| .. | .. |
|---|
| 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 | } |
|---|