[v2,1/2] i2c: Add new I2C_CLIENT_IGNORE_BUSY flag

Message ID 20180701122343.27194-2-hdegoede@redhat.com
State New
Headers show
  • i2c: ACPI: Add multi-instantiate pseudo driver
Related show

Commit Message

Hans de Goede July 1, 2018, 12:23 p.m.
Normally i2c_new_device will check that a client at the same address does
not already exists.

On systems with ACPI instantiated i2c-clients, normally there is 1 fw_node
per i2c-device and that fw-node contains 1 I2cSerialBus resource for that 1

But in some rare cases the manufacturer has decided to describe multiple
i2c-devices in a single ACPI fwnode with multiple I2cSerialBus resources.

After an earlier attempt to fix this in the i2c-core which resulted in a
lot of extra code to support this corner-case it was decided to go for a
different approach. The next patch in this series introduces a new special
i2c-multi-instantiate driver which can be build as a module and which will
bind to the i2c-client which gets instantiated by the core for the first
I2cSerialBus resource in the fwnode.

This driver will instantiate a new i2c-client per I2cSerialBus resource,
using the driver_data from the acpi_device_id it is binding to to tell it
which chip-type (and optional irq-resource) to use when instantiating.

Since it binds to the core instantiated i2c-client and claims the
acpi_device_id of the fwnode, it also needs to instantiate a new i2c-client
for the first I2cSerialBus resource uses the chip-id for the real driver,
so that that can bind to the i2c-device described by the first I2cSerialBus
resource, this requires the new I2C_CLIENT_IGNORE_BUSY flag.

Note this means that we will be instantiating 2 i2c_client-s for the first
I2cSerialBus resource, this is not pretty, but since the multi-instantiate
driver does exactly 0 i2c-transfers this is not a problem.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
 drivers/i2c/i2c-core-base.c | 11 +++++++----
 include/linux/i2c.h         |  3 +++
 2 files changed, 10 insertions(+), 4 deletions(-)


diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index 31d16ada6e7d..1806ad6ffa95 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -717,7 +717,7 @@  i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
 	client->adapter = adap;
 	client->dev.platform_data = info->platform_data;
-	client->flags = info->flags;
+	client->flags = info->flags & ~I2C_CLIENT_IGNORE_BUSY;
 	client->addr = info->addr;
 	client->irq = info->irq;
@@ -735,9 +735,12 @@  i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
 	/* Check for address business */
-	status = i2c_check_addr_busy(adap, i2c_encode_flags_to_addr(client));
-	if (status)
-		goto out_err;
+	if (!(info->flags & I2C_CLIENT_IGNORE_BUSY)) {
+		status = i2c_check_addr_busy(adap,
+					     i2c_encode_flags_to_addr(client));
+		if (status)
+			goto out_err;
+	}
 	client->dev.parent = &client->adapter->dev;
 	client->dev.bus = &i2c_bus_type;
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 254cd34eeae2..82280d1c8e7b 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -773,6 +773,9 @@  i2c_unlock_adapter(struct i2c_adapter *adapter)
 #define I2C_CLIENT_SLAVE	0x20	/* we are the slave */
 #define I2C_CLIENT_HOST_NOTIFY	0x40	/* We want to use I2C host notify */
 #define I2C_CLIENT_WAKE		0x80	/* for board_info; true iff can wake */
+#define I2C_CLIENT_IGNORE_BUSY	0x100	/* For board_info; skip busy check */
+					/* Do NOT use, reserved for use by */
+					/* drv/i2c/i2c-multi-instantiate.c */
 #define I2C_CLIENT_SCCB		0x9000	/* Use Omnivision SCCB protocol */
 					/* Must match I2C_M_STOP|IGNORE_NAK */