From b97a325b336542365bcb20c8936e16d51c3c23b9 Mon Sep 17 00:00:00 2001 From: zah Date: Tue, 8 Aug 2017 07:03:29 +0000 Subject: [PATCH] i2c: Devices which have some i2c addr can work in same i2c bus If i2c slave devices don't work at the same time, which have the same i2c addr, this patch can make them working. Change-Id: I1bfb7783924b08bdc6e12bf47c2de01bdac7c2e2 Signed-off-by: Zhang aihui --- drivers/i2c/i2c-core-base.c | 43 ++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 9200e349f29e..eddec3860359 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -67,6 +67,7 @@ static DEFINE_MUTEX(core_lock); static DEFINE_IDR(i2c_adapter_idr); +static int i2c_check_addr_ex(struct i2c_adapter *adapter, int addr); static int i2c_detect(struct i2c_adapter *adapter, struct i2c_driver *driver); static DEFINE_STATIC_KEY_FALSE(i2c_trace_msg_key); @@ -666,7 +667,8 @@ static void i2c_adapter_unlock_bus(struct i2c_adapter *adapter, static void i2c_dev_set_name(struct i2c_adapter *adap, struct i2c_client *client, - struct i2c_board_info const *info) + struct i2c_board_info const *info, + int status) { struct acpi_device *adev = ACPI_COMPANION(&client->dev); @@ -680,8 +682,12 @@ static void i2c_dev_set_name(struct i2c_adapter *adap, return; } - dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), - i2c_encode_flags_to_addr(client)); + if (status == 0) + dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), + i2c_encode_flags_to_addr(client)); + else + dev_set_name(&client->dev, "%d-%04x-%01x", i2c_adapter_id(adap), + i2c_encode_flags_to_addr(client), status); } static int i2c_dev_irq_from_resources(const struct resource *resources, @@ -757,7 +763,7 @@ 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)); + status = i2c_check_addr_ex(adap, i2c_encode_flags_to_addr(client)); if (status) goto out_err; @@ -767,7 +773,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.of_node = of_node_get(info->of_node); client->dev.fwnode = info->fwnode; - i2c_dev_set_name(adap, client, info); + i2c_dev_set_name(adap, client, info, status); if (info->properties) { status = device_add_properties(&client->dev, info->properties); @@ -1650,6 +1656,33 @@ EXPORT_SYMBOL(i2c_del_driver); /* ------------------------------------------------------------------------- */ +struct i2c_addr_cnt { + int addr; + int cnt; +}; + +static int __i2c_check_addr_ex(struct device *dev, void *addrp) +{ + struct i2c_client *client = i2c_verify_client(dev); + struct i2c_addr_cnt *addrinfo = (struct i2c_addr_cnt *)addrp; + int addr = addrinfo->addr; + + if (client && client->addr == addr) + addrinfo->cnt++; + + return 0; +} + +static int i2c_check_addr_ex(struct i2c_adapter *adapter, int addr) +{ + struct i2c_addr_cnt addrinfo; + + addrinfo.addr = addr; + addrinfo.cnt = 0; + device_for_each_child(&adapter->dev, &addrinfo, __i2c_check_addr_ex); + return addrinfo.cnt; +} + /** * i2c_use_client - increments the reference count of the i2c client structure * @client: the client being referenced