aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/i2c
diff options
context:
space:
mode:
authorMika Westerberg <mika.westerberg@linux.intel.com>2015-10-07 06:18:44 -0400
committerWolfram Sang <wsa@the-dreams.de>2015-10-20 10:51:14 -0400
commit166c2ba398640278ae6037be4aa5562c03cf3d24 (patch)
tree7227b55c3f29e90f26d4b6f7daf279cf65a0389a /drivers/i2c
parentd80d134182ba536ececab8d5fca50d779befc9a6 (diff)
i2c / ACPI: Rework I2C device scanning
The way we currently scan I2C devices behind an I2C host controller does not work in cases where the I2C device in question is not declared directly below the host controller ACPI node. This is perfectly legal according the ACPI 6.0 specification and some existing systems are doing this. To be able to enumerate all devices which are connected to a certain I2C host controller we need to rework the current I2C scanning routine a bit. Instead of scanning directly below the host controller we scan the whole ACPI namespace for present devices with valid I2cSerialBus() connection pointing to the host controller in question. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Tested-by: Dustin Byford <dustin@cumulusnetworks.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/i2c-core.c82
1 files changed, 59 insertions, 23 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 5f89f1e3c2f2..3a4c54ef290d 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -99,27 +99,40 @@ struct gsb_buffer {
99 }; 99 };
100} __packed; 100} __packed;
101 101
102static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) 102struct acpi_i2c_lookup {
103 struct i2c_board_info *info;
104 acpi_handle adapter_handle;
105 acpi_handle device_handle;
106};
107
108static int acpi_i2c_find_address(struct acpi_resource *ares, void *data)
103{ 109{
104 struct i2c_board_info *info = data; 110 struct acpi_i2c_lookup *lookup = data;
111 struct i2c_board_info *info = lookup->info;
112 struct acpi_resource_i2c_serialbus *sb;
113 acpi_handle adapter_handle;
114 acpi_status status;
105 115
106 if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { 116 if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS)
107 struct acpi_resource_i2c_serialbus *sb; 117 return 1;
108 118
109 sb = &ares->data.i2c_serial_bus; 119 sb = &ares->data.i2c_serial_bus;
110 if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { 120 if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C)
111 info->addr = sb->slave_address; 121 return 1;
112 if (sb->access_mode == ACPI_I2C_10BIT_MODE)
113 info->flags |= I2C_CLIENT_TEN;
114 }
115 } else if (!info->irq) {
116 struct resource r;
117 122
118 if (acpi_dev_resource_interrupt(ares, 0, &r)) 123 /*
119 info->irq = r.start; 124 * Extract the ResourceSource and make sure that the handle matches
125 * with the I2C adapter handle.
126 */
127 status = acpi_get_handle(lookup->device_handle,
128 sb->resource_source.string_ptr,
129 &adapter_handle);
130 if (ACPI_SUCCESS(status) && adapter_handle == lookup->adapter_handle) {
131 info->addr = sb->slave_address;
132 if (sb->access_mode == ACPI_I2C_10BIT_MODE)
133 info->flags |= I2C_CLIENT_TEN;
120 } 134 }
121 135
122 /* Tell the ACPI core to skip this resource */
123 return 1; 136 return 1;
124} 137}
125 138
@@ -128,6 +141,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
128{ 141{
129 struct i2c_adapter *adapter = data; 142 struct i2c_adapter *adapter = data;
130 struct list_head resource_list; 143 struct list_head resource_list;
144 struct acpi_i2c_lookup lookup;
145 struct resource_entry *entry;
131 struct i2c_board_info info; 146 struct i2c_board_info info;
132 struct acpi_device *adev; 147 struct acpi_device *adev;
133 int ret; 148 int ret;
@@ -140,14 +155,37 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
140 memset(&info, 0, sizeof(info)); 155 memset(&info, 0, sizeof(info));
141 info.fwnode = acpi_fwnode_handle(adev); 156 info.fwnode = acpi_fwnode_handle(adev);
142 157
158 memset(&lookup, 0, sizeof(lookup));
159 lookup.adapter_handle = ACPI_HANDLE(adapter->dev.parent);
160 lookup.device_handle = handle;
161 lookup.info = &info;
162
163 /*
164 * Look up for I2cSerialBus resource with ResourceSource that
165 * matches with this adapter.
166 */
143 INIT_LIST_HEAD(&resource_list); 167 INIT_LIST_HEAD(&resource_list);
144 ret = acpi_dev_get_resources(adev, &resource_list, 168 ret = acpi_dev_get_resources(adev, &resource_list,
145 acpi_i2c_add_resource, &info); 169 acpi_i2c_find_address, &lookup);
146 acpi_dev_free_resource_list(&resource_list); 170 acpi_dev_free_resource_list(&resource_list);
147 171
148 if (ret < 0 || !info.addr) 172 if (ret < 0 || !info.addr)
149 return AE_OK; 173 return AE_OK;
150 174
175 /* Then fill IRQ number if any */
176 ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
177 if (ret < 0)
178 return AE_OK;
179
180 resource_list_for_each_entry(entry, &resource_list) {
181 if (resource_type(entry->res) == IORESOURCE_IRQ) {
182 info.irq = entry->res->start;
183 break;
184 }
185 }
186
187 acpi_dev_free_resource_list(&resource_list);
188
151 adev->power.flags.ignore_parent = true; 189 adev->power.flags.ignore_parent = true;
152 strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); 190 strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
153 if (!i2c_new_device(adapter, &info)) { 191 if (!i2c_new_device(adapter, &info)) {
@@ -160,6 +198,8 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
160 return AE_OK; 198 return AE_OK;
161} 199}
162 200
201#define ACPI_I2C_MAX_SCAN_DEPTH 32
202
163/** 203/**
164 * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter 204 * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
165 * @adap: pointer to adapter 205 * @adap: pointer to adapter
@@ -170,17 +210,13 @@ static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
170 */ 210 */
171static void acpi_i2c_register_devices(struct i2c_adapter *adap) 211static void acpi_i2c_register_devices(struct i2c_adapter *adap)
172{ 212{
173 acpi_handle handle;
174 acpi_status status; 213 acpi_status status;
175 214
176 if (!adap->dev.parent) 215 if (!adap->dev.parent || !has_acpi_companion(adap->dev.parent))
177 return;
178
179 handle = ACPI_HANDLE(adap->dev.parent);
180 if (!handle)
181 return; 216 return;
182 217
183 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, 218 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
219 ACPI_I2C_MAX_SCAN_DEPTH,
184 acpi_i2c_add_device, NULL, 220 acpi_i2c_add_device, NULL,
185 adap, NULL); 221 adap, NULL);
186 if (ACPI_FAILURE(status)) 222 if (ACPI_FAILURE(status))