.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Linux I2C core ACPI support code |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (C) 2014 Intel Corp, Author: Lan Tianyu <tianyu.lan@intel.com> |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or modify it |
---|
7 | | - * under the terms of the GNU General Public License as published by the Free |
---|
8 | | - * Software Foundation; either version 2 of the License, or (at your option) |
---|
9 | | - * any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/acpi.h> |
---|
.. | .. |
---|
46 | 42 | u32 force_speed; |
---|
47 | 43 | }; |
---|
48 | 44 | |
---|
| 45 | +/** |
---|
| 46 | + * i2c_acpi_get_i2c_resource - Gets I2cSerialBus resource if type matches |
---|
| 47 | + * @ares: ACPI resource |
---|
| 48 | + * @i2c: Pointer to I2cSerialBus resource will be returned here |
---|
| 49 | + * |
---|
| 50 | + * Checks if the given ACPI resource is of type I2cSerialBus. |
---|
| 51 | + * In this case, returns a pointer to it to the caller. |
---|
| 52 | + * |
---|
| 53 | + * Returns true if resource type is of I2cSerialBus, otherwise false. |
---|
| 54 | + */ |
---|
| 55 | +bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares, |
---|
| 56 | + struct acpi_resource_i2c_serialbus **i2c) |
---|
| 57 | +{ |
---|
| 58 | + struct acpi_resource_i2c_serialbus *sb; |
---|
| 59 | + |
---|
| 60 | + if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) |
---|
| 61 | + return false; |
---|
| 62 | + |
---|
| 63 | + sb = &ares->data.i2c_serial_bus; |
---|
| 64 | + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) |
---|
| 65 | + return false; |
---|
| 66 | + |
---|
| 67 | + *i2c = sb; |
---|
| 68 | + return true; |
---|
| 69 | +} |
---|
| 70 | +EXPORT_SYMBOL_GPL(i2c_acpi_get_i2c_resource); |
---|
| 71 | + |
---|
49 | 72 | static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) |
---|
50 | 73 | { |
---|
51 | 74 | struct i2c_acpi_lookup *lookup = data; |
---|
.. | .. |
---|
53 | 76 | struct acpi_resource_i2c_serialbus *sb; |
---|
54 | 77 | acpi_status status; |
---|
55 | 78 | |
---|
56 | | - if (info->addr || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) |
---|
57 | | - return 1; |
---|
58 | | - |
---|
59 | | - sb = &ares->data.i2c_serial_bus; |
---|
60 | | - if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) |
---|
| 79 | + if (info->addr || !i2c_acpi_get_i2c_resource(ares, &sb)) |
---|
61 | 80 | return 1; |
---|
62 | 81 | |
---|
63 | 82 | if (lookup->index != -1 && lookup->n++ != lookup->index) |
---|
.. | .. |
---|
66 | 85 | status = acpi_get_handle(lookup->device_handle, |
---|
67 | 86 | sb->resource_source.string_ptr, |
---|
68 | 87 | &lookup->adapter_handle); |
---|
69 | | - if (!ACPI_SUCCESS(status)) |
---|
| 88 | + if (ACPI_FAILURE(status)) |
---|
70 | 89 | return 1; |
---|
71 | 90 | |
---|
72 | 91 | info->addr = sb->slave_address; |
---|
.. | .. |
---|
93 | 112 | struct list_head resource_list; |
---|
94 | 113 | int ret; |
---|
95 | 114 | |
---|
96 | | - if (acpi_bus_get_status(adev) || !adev->status.present || |
---|
97 | | - acpi_device_enumerated(adev)) |
---|
| 115 | + if (acpi_bus_get_status(adev) || !adev->status.present) |
---|
98 | 116 | return -EINVAL; |
---|
99 | 117 | |
---|
100 | 118 | if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) |
---|
.. | .. |
---|
115 | 133 | return 0; |
---|
116 | 134 | } |
---|
117 | 135 | |
---|
| 136 | +static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) |
---|
| 137 | +{ |
---|
| 138 | + int *irq = data; |
---|
| 139 | + struct resource r; |
---|
| 140 | + |
---|
| 141 | + if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r)) |
---|
| 142 | + *irq = i2c_dev_irq_from_resources(&r, 1); |
---|
| 143 | + |
---|
| 144 | + return 1; /* No need to add resource to the list */ |
---|
| 145 | +} |
---|
| 146 | + |
---|
| 147 | +/** |
---|
| 148 | + * i2c_acpi_get_irq - get device IRQ number from ACPI |
---|
| 149 | + * @client: Pointer to the I2C client device |
---|
| 150 | + * |
---|
| 151 | + * Find the IRQ number used by a specific client device. |
---|
| 152 | + * |
---|
| 153 | + * Return: The IRQ number or an error code. |
---|
| 154 | + */ |
---|
| 155 | +int i2c_acpi_get_irq(struct i2c_client *client) |
---|
| 156 | +{ |
---|
| 157 | + struct acpi_device *adev = ACPI_COMPANION(&client->dev); |
---|
| 158 | + struct list_head resource_list; |
---|
| 159 | + int irq = -ENOENT; |
---|
| 160 | + int ret; |
---|
| 161 | + |
---|
| 162 | + INIT_LIST_HEAD(&resource_list); |
---|
| 163 | + |
---|
| 164 | + ret = acpi_dev_get_resources(adev, &resource_list, |
---|
| 165 | + i2c_acpi_add_resource, &irq); |
---|
| 166 | + if (ret < 0) |
---|
| 167 | + return ret; |
---|
| 168 | + |
---|
| 169 | + acpi_dev_free_resource_list(&resource_list); |
---|
| 170 | + |
---|
| 171 | + if (irq == -ENOENT) |
---|
| 172 | + irq = acpi_dev_gpio_irq_get(adev, 0); |
---|
| 173 | + |
---|
| 174 | + return irq; |
---|
| 175 | +} |
---|
| 176 | + |
---|
118 | 177 | static int i2c_acpi_get_info(struct acpi_device *adev, |
---|
119 | 178 | struct i2c_board_info *info, |
---|
120 | 179 | struct i2c_adapter *adapter, |
---|
121 | 180 | acpi_handle *adapter_handle) |
---|
122 | 181 | { |
---|
123 | | - struct list_head resource_list; |
---|
124 | | - struct resource_entry *entry; |
---|
125 | 182 | struct i2c_acpi_lookup lookup; |
---|
126 | 183 | int ret; |
---|
127 | 184 | |
---|
128 | 185 | memset(&lookup, 0, sizeof(lookup)); |
---|
129 | 186 | lookup.info = info; |
---|
130 | 187 | lookup.index = -1; |
---|
| 188 | + |
---|
| 189 | + if (acpi_device_enumerated(adev)) |
---|
| 190 | + return -EINVAL; |
---|
131 | 191 | |
---|
132 | 192 | ret = i2c_acpi_do_lookup(adev, &lookup); |
---|
133 | 193 | if (ret) |
---|
.. | .. |
---|
152 | 212 | if (adapter_handle) |
---|
153 | 213 | *adapter_handle = lookup.adapter_handle; |
---|
154 | 214 | |
---|
155 | | - /* Then fill IRQ number if any */ |
---|
156 | | - INIT_LIST_HEAD(&resource_list); |
---|
157 | | - ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL); |
---|
158 | | - if (ret < 0) |
---|
159 | | - return -EINVAL; |
---|
160 | | - |
---|
161 | | - resource_list_for_each_entry(entry, &resource_list) { |
---|
162 | | - if (resource_type(entry->res) == IORESOURCE_IRQ) { |
---|
163 | | - info->irq = entry->res->start; |
---|
164 | | - break; |
---|
165 | | - } |
---|
166 | | - } |
---|
167 | | - |
---|
168 | | - acpi_dev_free_resource_list(&resource_list); |
---|
169 | | - |
---|
170 | 215 | acpi_set_modalias(adev, dev_name(&adev->dev), info->type, |
---|
171 | 216 | sizeof(info->type)); |
---|
172 | 217 | |
---|
.. | .. |
---|
180 | 225 | adev->power.flags.ignore_parent = true; |
---|
181 | 226 | acpi_device_set_enumerated(adev); |
---|
182 | 227 | |
---|
183 | | - if (!i2c_new_device(adapter, info)) { |
---|
| 228 | + if (IS_ERR(i2c_new_client_device(adapter, info))) { |
---|
184 | 229 | adev->power.flags.ignore_parent = false; |
---|
185 | 230 | dev_err(&adapter->dev, |
---|
186 | 231 | "failed to add I2C device %s from ACPI\n", |
---|
.. | .. |
---|
241 | 286 | acpi_walk_dep_device_list(handle); |
---|
242 | 287 | } |
---|
243 | 288 | |
---|
244 | | -const struct acpi_device_id * |
---|
245 | | -i2c_acpi_match_device(const struct acpi_device_id *matches, |
---|
246 | | - struct i2c_client *client) |
---|
247 | | -{ |
---|
248 | | - if (!(client && matches)) |
---|
249 | | - return NULL; |
---|
250 | | - |
---|
251 | | - return acpi_match_device(matches, &client->dev); |
---|
252 | | -} |
---|
253 | | - |
---|
254 | 289 | static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = { |
---|
255 | 290 | /* |
---|
256 | 291 | * These Silead touchscreen controllers only work at 400KHz, for |
---|
.. | .. |
---|
283 | 318 | lookup->min_speed = lookup->speed; |
---|
284 | 319 | |
---|
285 | 320 | if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0) |
---|
286 | | - lookup->force_speed = 400000; |
---|
| 321 | + lookup->force_speed = I2C_MAX_FAST_MODE_FREQ; |
---|
287 | 322 | |
---|
288 | 323 | return AE_OK; |
---|
289 | 324 | } |
---|
.. | .. |
---|
335 | 370 | } |
---|
336 | 371 | EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); |
---|
337 | 372 | |
---|
338 | | -static int i2c_acpi_find_match_adapter(struct device *dev, void *data) |
---|
| 373 | +static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) |
---|
339 | 374 | { |
---|
340 | 375 | struct i2c_adapter *adapter = i2c_verify_adapter(dev); |
---|
341 | 376 | |
---|
.. | .. |
---|
345 | 380 | return ACPI_HANDLE(dev) == (acpi_handle)data; |
---|
346 | 381 | } |
---|
347 | 382 | |
---|
348 | | -static int i2c_acpi_find_match_device(struct device *dev, void *data) |
---|
349 | | -{ |
---|
350 | | - return ACPI_COMPANION(dev) == data; |
---|
351 | | -} |
---|
352 | | - |
---|
353 | | -static struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) |
---|
| 383 | +struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) |
---|
354 | 384 | { |
---|
355 | 385 | struct device *dev; |
---|
356 | 386 | |
---|
357 | 387 | dev = bus_find_device(&i2c_bus_type, NULL, handle, |
---|
358 | 388 | i2c_acpi_find_match_adapter); |
---|
| 389 | + |
---|
359 | 390 | return dev ? i2c_verify_adapter(dev) : NULL; |
---|
360 | 391 | } |
---|
| 392 | +EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); |
---|
361 | 393 | |
---|
362 | 394 | static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) |
---|
363 | 395 | { |
---|
364 | 396 | struct device *dev; |
---|
365 | 397 | struct i2c_client *client; |
---|
366 | 398 | |
---|
367 | | - dev = bus_find_device(&i2c_bus_type, NULL, adev, |
---|
368 | | - i2c_acpi_find_match_device); |
---|
| 399 | + dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); |
---|
369 | 400 | if (!dev) |
---|
370 | 401 | return NULL; |
---|
371 | 402 | |
---|
.. | .. |
---|
429 | 460 | * resources, in that case this function can be used to create an i2c-client |
---|
430 | 461 | * for other I2cSerialBus resources in the Current Resource Settings table. |
---|
431 | 462 | * |
---|
432 | | - * Also see i2c_new_device, which this function calls to create the i2c-client. |
---|
| 463 | + * Also see i2c_new_client_device, which this function calls to create the |
---|
| 464 | + * i2c-client. |
---|
433 | 465 | * |
---|
434 | | - * Returns a pointer to the new i2c-client, or NULL if the adapter is not found. |
---|
| 466 | + * Returns a pointer to the new i2c-client, or error pointer in case of failure. |
---|
| 467 | + * Specifically, -EPROBE_DEFER is returned if the adapter is not found. |
---|
435 | 468 | */ |
---|
436 | 469 | struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, |
---|
437 | 470 | struct i2c_board_info *info) |
---|
438 | 471 | { |
---|
| 472 | + struct acpi_device *adev = ACPI_COMPANION(dev); |
---|
439 | 473 | struct i2c_acpi_lookup lookup; |
---|
440 | 474 | struct i2c_adapter *adapter; |
---|
441 | | - struct acpi_device *adev; |
---|
442 | 475 | LIST_HEAD(resource_list); |
---|
443 | 476 | int ret; |
---|
444 | | - |
---|
445 | | - adev = ACPI_COMPANION(dev); |
---|
446 | | - if (!adev) |
---|
447 | | - return NULL; |
---|
448 | 477 | |
---|
449 | 478 | memset(&lookup, 0, sizeof(lookup)); |
---|
450 | 479 | lookup.info = info; |
---|
.. | .. |
---|
453 | 482 | |
---|
454 | 483 | ret = acpi_dev_get_resources(adev, &resource_list, |
---|
455 | 484 | i2c_acpi_fill_info, &lookup); |
---|
| 485 | + if (ret < 0) |
---|
| 486 | + return ERR_PTR(ret); |
---|
| 487 | + |
---|
456 | 488 | acpi_dev_free_resource_list(&resource_list); |
---|
457 | 489 | |
---|
458 | | - if (ret < 0 || !info->addr) |
---|
459 | | - return NULL; |
---|
| 490 | + if (!info->addr) |
---|
| 491 | + return ERR_PTR(-EADDRNOTAVAIL); |
---|
460 | 492 | |
---|
461 | 493 | adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle); |
---|
462 | 494 | if (!adapter) |
---|
463 | | - return NULL; |
---|
| 495 | + return ERR_PTR(-EPROBE_DEFER); |
---|
464 | 496 | |
---|
465 | | - return i2c_new_device(adapter, info); |
---|
| 497 | + return i2c_new_client_device(adapter, info); |
---|
466 | 498 | } |
---|
467 | 499 | EXPORT_SYMBOL_GPL(i2c_acpi_new_device); |
---|
468 | 500 | |
---|
.. | .. |
---|
570 | 602 | goto err; |
---|
571 | 603 | } |
---|
572 | 604 | |
---|
573 | | - if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { |
---|
574 | | - ret = AE_BAD_PARAMETER; |
---|
575 | | - goto err; |
---|
576 | | - } |
---|
577 | | - |
---|
578 | | - sb = &ares->data.i2c_serial_bus; |
---|
579 | | - if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { |
---|
| 605 | + if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) { |
---|
580 | 606 | ret = AE_BAD_PARAMETER; |
---|
581 | 607 | goto err; |
---|
582 | 608 | } |
---|