12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later 253f8f7c5SWolfram Sang /* 353f8f7c5SWolfram Sang * Linux I2C core ACPI support code 453f8f7c5SWolfram Sang * 553f8f7c5SWolfram Sang * Copyright (C) 2014 Intel Corp, Author: Lan Tianyu <tianyu.lan@intel.com> 653f8f7c5SWolfram Sang */ 753f8f7c5SWolfram Sang 853f8f7c5SWolfram Sang #include <linux/acpi.h> 953f8f7c5SWolfram Sang #include <linux/device.h> 1053f8f7c5SWolfram Sang #include <linux/err.h> 1153f8f7c5SWolfram Sang #include <linux/i2c.h> 1253f8f7c5SWolfram Sang #include <linux/list.h> 1353f8f7c5SWolfram Sang #include <linux/module.h> 1453f8f7c5SWolfram Sang #include <linux/slab.h> 1553f8f7c5SWolfram Sang 1653f8f7c5SWolfram Sang #include "i2c-core.h" 1753f8f7c5SWolfram Sang 1853f8f7c5SWolfram Sang struct i2c_acpi_handler_data { 1953f8f7c5SWolfram Sang struct acpi_connection_info info; 2053f8f7c5SWolfram Sang struct i2c_adapter *adapter; 2153f8f7c5SWolfram Sang }; 2253f8f7c5SWolfram Sang 2353f8f7c5SWolfram Sang struct gsb_buffer { 2453f8f7c5SWolfram Sang u8 status; 2553f8f7c5SWolfram Sang u8 len; 2653f8f7c5SWolfram Sang union { 2753f8f7c5SWolfram Sang u16 wdata; 2853f8f7c5SWolfram Sang u8 bdata; 2953f8f7c5SWolfram Sang u8 data[0]; 3053f8f7c5SWolfram Sang }; 3153f8f7c5SWolfram Sang } __packed; 3253f8f7c5SWolfram Sang 3353f8f7c5SWolfram Sang struct i2c_acpi_lookup { 3453f8f7c5SWolfram Sang struct i2c_board_info *info; 3553f8f7c5SWolfram Sang acpi_handle adapter_handle; 3653f8f7c5SWolfram Sang acpi_handle device_handle; 3753f8f7c5SWolfram Sang acpi_handle search_handle; 3853f8f7c5SWolfram Sang int n; 3953f8f7c5SWolfram Sang int index; 4053f8f7c5SWolfram Sang u32 speed; 4153f8f7c5SWolfram Sang u32 min_speed; 4253f8f7c5SWolfram Sang }; 4353f8f7c5SWolfram Sang 440d5102feSAndy Shevchenko /** 450d5102feSAndy Shevchenko * i2c_acpi_get_i2c_resource - Gets I2cSerialBus resource if type matches 460d5102feSAndy Shevchenko * @ares: ACPI resource 470d5102feSAndy Shevchenko * @i2c: Pointer to I2cSerialBus resource will be returned here 480d5102feSAndy Shevchenko * 490d5102feSAndy Shevchenko * Checks if the given ACPI resource is of type I2cSerialBus. 500d5102feSAndy Shevchenko * In this case, returns a pointer to it to the caller. 510d5102feSAndy Shevchenko * 520d5102feSAndy Shevchenko * Returns true if resource type is of I2cSerialBus, otherwise false. 530d5102feSAndy Shevchenko */ 540d5102feSAndy Shevchenko bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares, 550d5102feSAndy Shevchenko struct acpi_resource_i2c_serialbus **i2c) 560d5102feSAndy Shevchenko { 570d5102feSAndy Shevchenko struct acpi_resource_i2c_serialbus *sb; 580d5102feSAndy Shevchenko 590d5102feSAndy Shevchenko if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) 600d5102feSAndy Shevchenko return false; 610d5102feSAndy Shevchenko 620d5102feSAndy Shevchenko sb = &ares->data.i2c_serial_bus; 630d5102feSAndy Shevchenko if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) 640d5102feSAndy Shevchenko return false; 650d5102feSAndy Shevchenko 660d5102feSAndy Shevchenko *i2c = sb; 670d5102feSAndy Shevchenko return true; 680d5102feSAndy Shevchenko } 690d5102feSAndy Shevchenko EXPORT_SYMBOL_GPL(i2c_acpi_get_i2c_resource); 700d5102feSAndy Shevchenko 7153f8f7c5SWolfram Sang static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) 7253f8f7c5SWolfram Sang { 7353f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup = data; 7453f8f7c5SWolfram Sang struct i2c_board_info *info = lookup->info; 7553f8f7c5SWolfram Sang struct acpi_resource_i2c_serialbus *sb; 7653f8f7c5SWolfram Sang acpi_status status; 7753f8f7c5SWolfram Sang 780d5102feSAndy Shevchenko if (info->addr || !i2c_acpi_get_i2c_resource(ares, &sb)) 7953f8f7c5SWolfram Sang return 1; 8053f8f7c5SWolfram Sang 8153f8f7c5SWolfram Sang if (lookup->index != -1 && lookup->n++ != lookup->index) 8253f8f7c5SWolfram Sang return 1; 8353f8f7c5SWolfram Sang 8453f8f7c5SWolfram Sang status = acpi_get_handle(lookup->device_handle, 8553f8f7c5SWolfram Sang sb->resource_source.string_ptr, 8653f8f7c5SWolfram Sang &lookup->adapter_handle); 875f59d6a1SAndy Shevchenko if (ACPI_FAILURE(status)) 8853f8f7c5SWolfram Sang return 1; 8953f8f7c5SWolfram Sang 9053f8f7c5SWolfram Sang info->addr = sb->slave_address; 9153f8f7c5SWolfram Sang lookup->speed = sb->connection_speed; 9253f8f7c5SWolfram Sang if (sb->access_mode == ACPI_I2C_10BIT_MODE) 9353f8f7c5SWolfram Sang info->flags |= I2C_CLIENT_TEN; 9453f8f7c5SWolfram Sang 9553f8f7c5SWolfram Sang return 1; 9653f8f7c5SWolfram Sang } 9753f8f7c5SWolfram Sang 983a4991a9SHans de Goede static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = { 993a4991a9SHans de Goede /* 1003a4991a9SHans de Goede * ACPI video acpi_devices, which are handled by the acpi-video driver 1013a4991a9SHans de Goede * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these. 1023a4991a9SHans de Goede */ 1033a4991a9SHans de Goede { ACPI_VIDEO_HID, 0 }, 1043a4991a9SHans de Goede {} 1053a4991a9SHans de Goede }; 1063a4991a9SHans de Goede 10753f8f7c5SWolfram Sang static int i2c_acpi_do_lookup(struct acpi_device *adev, 10853f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup) 10953f8f7c5SWolfram Sang { 11053f8f7c5SWolfram Sang struct i2c_board_info *info = lookup->info; 11153f8f7c5SWolfram Sang struct list_head resource_list; 11253f8f7c5SWolfram Sang int ret; 11353f8f7c5SWolfram Sang 1144befedc0SArd Biesheuvel if (acpi_bus_get_status(adev) || !adev->status.present) 11553f8f7c5SWolfram Sang return -EINVAL; 11653f8f7c5SWolfram Sang 1173a4991a9SHans de Goede if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) 1183a4991a9SHans de Goede return -ENODEV; 1193a4991a9SHans de Goede 12053f8f7c5SWolfram Sang memset(info, 0, sizeof(*info)); 12153f8f7c5SWolfram Sang lookup->device_handle = acpi_device_handle(adev); 12253f8f7c5SWolfram Sang 12353f8f7c5SWolfram Sang /* Look up for I2cSerialBus resource */ 12453f8f7c5SWolfram Sang INIT_LIST_HEAD(&resource_list); 12553f8f7c5SWolfram Sang ret = acpi_dev_get_resources(adev, &resource_list, 12653f8f7c5SWolfram Sang i2c_acpi_fill_info, lookup); 12753f8f7c5SWolfram Sang acpi_dev_free_resource_list(&resource_list); 12853f8f7c5SWolfram Sang 12953f8f7c5SWolfram Sang if (ret < 0 || !info->addr) 13053f8f7c5SWolfram Sang return -EINVAL; 13153f8f7c5SWolfram Sang 13253f8f7c5SWolfram Sang return 0; 13353f8f7c5SWolfram Sang } 13453f8f7c5SWolfram Sang 135c2223ddcSCharles Keepax static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) 136c2223ddcSCharles Keepax { 137c2223ddcSCharles Keepax int *irq = data; 138c2223ddcSCharles Keepax struct resource r; 139c2223ddcSCharles Keepax 140c2223ddcSCharles Keepax if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r)) 141c2223ddcSCharles Keepax *irq = i2c_dev_irq_from_resources(&r, 1); 142c2223ddcSCharles Keepax 143c2223ddcSCharles Keepax return 1; /* No need to add resource to the list */ 144c2223ddcSCharles Keepax } 145c2223ddcSCharles Keepax 14616c9db1dSCharles Keepax /** 14716c9db1dSCharles Keepax * i2c_acpi_get_irq - get device IRQ number from ACPI 14816c9db1dSCharles Keepax * @client: Pointer to the I2C client device 14916c9db1dSCharles Keepax * 15016c9db1dSCharles Keepax * Find the IRQ number used by a specific client device. 15116c9db1dSCharles Keepax * 15216c9db1dSCharles Keepax * Return: The IRQ number or an error code. 15316c9db1dSCharles Keepax */ 15416c9db1dSCharles Keepax int i2c_acpi_get_irq(struct i2c_client *client) 155a52e3b37SCharles Keepax { 15616c9db1dSCharles Keepax struct acpi_device *adev = ACPI_COMPANION(&client->dev); 157a52e3b37SCharles Keepax struct list_head resource_list; 158a52e3b37SCharles Keepax int irq = -ENOENT; 159a52e3b37SCharles Keepax int ret; 160a52e3b37SCharles Keepax 161a52e3b37SCharles Keepax INIT_LIST_HEAD(&resource_list); 162a52e3b37SCharles Keepax 163a52e3b37SCharles Keepax ret = acpi_dev_get_resources(adev, &resource_list, 164a52e3b37SCharles Keepax i2c_acpi_add_resource, &irq); 165a52e3b37SCharles Keepax if (ret < 0) 166a52e3b37SCharles Keepax return ret; 167a52e3b37SCharles Keepax 168a52e3b37SCharles Keepax acpi_dev_free_resource_list(&resource_list); 169a52e3b37SCharles Keepax 1708466b616SCharles Keepax if (irq == -ENOENT) 1718466b616SCharles Keepax irq = acpi_dev_gpio_irq_get(adev, 0); 1728466b616SCharles Keepax 173a52e3b37SCharles Keepax return irq; 174a52e3b37SCharles Keepax } 175a52e3b37SCharles Keepax 17653f8f7c5SWolfram Sang static int i2c_acpi_get_info(struct acpi_device *adev, 17753f8f7c5SWolfram Sang struct i2c_board_info *info, 17853f8f7c5SWolfram Sang struct i2c_adapter *adapter, 17953f8f7c5SWolfram Sang acpi_handle *adapter_handle) 18053f8f7c5SWolfram Sang { 18153f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 18253f8f7c5SWolfram Sang int ret; 18353f8f7c5SWolfram Sang 18453f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 18553f8f7c5SWolfram Sang lookup.info = info; 18653f8f7c5SWolfram Sang lookup.index = -1; 18753f8f7c5SWolfram Sang 1884befedc0SArd Biesheuvel if (acpi_device_enumerated(adev)) 1894befedc0SArd Biesheuvel return -EINVAL; 1904befedc0SArd Biesheuvel 19153f8f7c5SWolfram Sang ret = i2c_acpi_do_lookup(adev, &lookup); 19253f8f7c5SWolfram Sang if (ret) 19353f8f7c5SWolfram Sang return ret; 19453f8f7c5SWolfram Sang 19553f8f7c5SWolfram Sang if (adapter) { 19653f8f7c5SWolfram Sang /* The adapter must match the one in I2cSerialBus() connector */ 19753f8f7c5SWolfram Sang if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle) 19853f8f7c5SWolfram Sang return -ENODEV; 19953f8f7c5SWolfram Sang } else { 20053f8f7c5SWolfram Sang struct acpi_device *adapter_adev; 20153f8f7c5SWolfram Sang 20253f8f7c5SWolfram Sang /* The adapter must be present */ 20353f8f7c5SWolfram Sang if (acpi_bus_get_device(lookup.adapter_handle, &adapter_adev)) 20453f8f7c5SWolfram Sang return -ENODEV; 20553f8f7c5SWolfram Sang if (acpi_bus_get_status(adapter_adev) || 20653f8f7c5SWolfram Sang !adapter_adev->status.present) 20753f8f7c5SWolfram Sang return -ENODEV; 20853f8f7c5SWolfram Sang } 20953f8f7c5SWolfram Sang 21053f8f7c5SWolfram Sang info->fwnode = acpi_fwnode_handle(adev); 21153f8f7c5SWolfram Sang if (adapter_handle) 21253f8f7c5SWolfram Sang *adapter_handle = lookup.adapter_handle; 21353f8f7c5SWolfram Sang 21453f8f7c5SWolfram Sang acpi_set_modalias(adev, dev_name(&adev->dev), info->type, 21553f8f7c5SWolfram Sang sizeof(info->type)); 21653f8f7c5SWolfram Sang 21753f8f7c5SWolfram Sang return 0; 21853f8f7c5SWolfram Sang } 21953f8f7c5SWolfram Sang 22053f8f7c5SWolfram Sang static void i2c_acpi_register_device(struct i2c_adapter *adapter, 22153f8f7c5SWolfram Sang struct acpi_device *adev, 22253f8f7c5SWolfram Sang struct i2c_board_info *info) 22353f8f7c5SWolfram Sang { 22453f8f7c5SWolfram Sang adev->power.flags.ignore_parent = true; 22553f8f7c5SWolfram Sang acpi_device_set_enumerated(adev); 22653f8f7c5SWolfram Sang 22753f8f7c5SWolfram Sang if (!i2c_new_device(adapter, info)) { 22853f8f7c5SWolfram Sang adev->power.flags.ignore_parent = false; 22953f8f7c5SWolfram Sang dev_err(&adapter->dev, 23053f8f7c5SWolfram Sang "failed to add I2C device %s from ACPI\n", 23153f8f7c5SWolfram Sang dev_name(&adev->dev)); 23253f8f7c5SWolfram Sang } 23353f8f7c5SWolfram Sang } 23453f8f7c5SWolfram Sang 23553f8f7c5SWolfram Sang static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, 23653f8f7c5SWolfram Sang void *data, void **return_value) 23753f8f7c5SWolfram Sang { 23853f8f7c5SWolfram Sang struct i2c_adapter *adapter = data; 23953f8f7c5SWolfram Sang struct acpi_device *adev; 24053f8f7c5SWolfram Sang struct i2c_board_info info; 24153f8f7c5SWolfram Sang 24253f8f7c5SWolfram Sang if (acpi_bus_get_device(handle, &adev)) 24353f8f7c5SWolfram Sang return AE_OK; 24453f8f7c5SWolfram Sang 24553f8f7c5SWolfram Sang if (i2c_acpi_get_info(adev, &info, adapter, NULL)) 24653f8f7c5SWolfram Sang return AE_OK; 24753f8f7c5SWolfram Sang 24853f8f7c5SWolfram Sang i2c_acpi_register_device(adapter, adev, &info); 24953f8f7c5SWolfram Sang 25053f8f7c5SWolfram Sang return AE_OK; 25153f8f7c5SWolfram Sang } 25253f8f7c5SWolfram Sang 25353f8f7c5SWolfram Sang #define I2C_ACPI_MAX_SCAN_DEPTH 32 25453f8f7c5SWolfram Sang 25553f8f7c5SWolfram Sang /** 25653f8f7c5SWolfram Sang * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter 25753f8f7c5SWolfram Sang * @adap: pointer to adapter 25853f8f7c5SWolfram Sang * 25953f8f7c5SWolfram Sang * Enumerate all I2C slave devices behind this adapter by walking the ACPI 26053f8f7c5SWolfram Sang * namespace. When a device is found it will be added to the Linux device 26153f8f7c5SWolfram Sang * model and bound to the corresponding ACPI handle. 26253f8f7c5SWolfram Sang */ 26353f8f7c5SWolfram Sang void i2c_acpi_register_devices(struct i2c_adapter *adap) 26453f8f7c5SWolfram Sang { 26553f8f7c5SWolfram Sang acpi_status status; 26653f8f7c5SWolfram Sang 26753f8f7c5SWolfram Sang if (!has_acpi_companion(&adap->dev)) 26853f8f7c5SWolfram Sang return; 26953f8f7c5SWolfram Sang 27053f8f7c5SWolfram Sang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 27153f8f7c5SWolfram Sang I2C_ACPI_MAX_SCAN_DEPTH, 27253f8f7c5SWolfram Sang i2c_acpi_add_device, NULL, 27353f8f7c5SWolfram Sang adap, NULL); 27453f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) 27553f8f7c5SWolfram Sang dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); 27653f8f7c5SWolfram Sang } 27753f8f7c5SWolfram Sang 278c64ffff7SAndy Shevchenko const struct acpi_device_id * 279c64ffff7SAndy Shevchenko i2c_acpi_match_device(const struct acpi_device_id *matches, 280c64ffff7SAndy Shevchenko struct i2c_client *client) 281c64ffff7SAndy Shevchenko { 282c64ffff7SAndy Shevchenko if (!(client && matches)) 283c64ffff7SAndy Shevchenko return NULL; 284c64ffff7SAndy Shevchenko 285c64ffff7SAndy Shevchenko return acpi_match_device(matches, &client->dev); 286c64ffff7SAndy Shevchenko } 287c64ffff7SAndy Shevchenko 28853f8f7c5SWolfram Sang static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, 28953f8f7c5SWolfram Sang void *data, void **return_value) 29053f8f7c5SWolfram Sang { 29153f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup = data; 29253f8f7c5SWolfram Sang struct acpi_device *adev; 29353f8f7c5SWolfram Sang 29453f8f7c5SWolfram Sang if (acpi_bus_get_device(handle, &adev)) 29553f8f7c5SWolfram Sang return AE_OK; 29653f8f7c5SWolfram Sang 29753f8f7c5SWolfram Sang if (i2c_acpi_do_lookup(adev, lookup)) 29853f8f7c5SWolfram Sang return AE_OK; 29953f8f7c5SWolfram Sang 30053f8f7c5SWolfram Sang if (lookup->search_handle != lookup->adapter_handle) 30153f8f7c5SWolfram Sang return AE_OK; 30253f8f7c5SWolfram Sang 30353f8f7c5SWolfram Sang if (lookup->speed <= lookup->min_speed) 30453f8f7c5SWolfram Sang lookup->min_speed = lookup->speed; 30553f8f7c5SWolfram Sang 30653f8f7c5SWolfram Sang return AE_OK; 30753f8f7c5SWolfram Sang } 30853f8f7c5SWolfram Sang 30953f8f7c5SWolfram Sang /** 31053f8f7c5SWolfram Sang * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI 31153f8f7c5SWolfram Sang * @dev: The device owning the bus 31253f8f7c5SWolfram Sang * 31353f8f7c5SWolfram Sang * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves 31453f8f7c5SWolfram Sang * devices connected to this bus and use the speed of slowest device. 31553f8f7c5SWolfram Sang * 31653f8f7c5SWolfram Sang * Returns the speed in Hz or zero 31753f8f7c5SWolfram Sang */ 31853f8f7c5SWolfram Sang u32 i2c_acpi_find_bus_speed(struct device *dev) 31953f8f7c5SWolfram Sang { 32053f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 32153f8f7c5SWolfram Sang struct i2c_board_info dummy; 32253f8f7c5SWolfram Sang acpi_status status; 32353f8f7c5SWolfram Sang 32453f8f7c5SWolfram Sang if (!has_acpi_companion(dev)) 32553f8f7c5SWolfram Sang return 0; 32653f8f7c5SWolfram Sang 32753f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 32853f8f7c5SWolfram Sang lookup.search_handle = ACPI_HANDLE(dev); 32953f8f7c5SWolfram Sang lookup.min_speed = UINT_MAX; 33053f8f7c5SWolfram Sang lookup.info = &dummy; 33153f8f7c5SWolfram Sang lookup.index = -1; 33253f8f7c5SWolfram Sang 33353f8f7c5SWolfram Sang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 33453f8f7c5SWolfram Sang I2C_ACPI_MAX_SCAN_DEPTH, 33553f8f7c5SWolfram Sang i2c_acpi_lookup_speed, NULL, 33653f8f7c5SWolfram Sang &lookup, NULL); 33753f8f7c5SWolfram Sang 33853f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 33953f8f7c5SWolfram Sang dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); 34053f8f7c5SWolfram Sang return 0; 34153f8f7c5SWolfram Sang } 34253f8f7c5SWolfram Sang 34353f8f7c5SWolfram Sang return lookup.min_speed != UINT_MAX ? lookup.min_speed : 0; 34453f8f7c5SWolfram Sang } 34553f8f7c5SWolfram Sang EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); 34653f8f7c5SWolfram Sang 347418e3ea1SSuzuki K Poulose static int i2c_acpi_find_match_adapter(struct device *dev, const void *data) 34853f8f7c5SWolfram Sang { 34953f8f7c5SWolfram Sang struct i2c_adapter *adapter = i2c_verify_adapter(dev); 35053f8f7c5SWolfram Sang 35153f8f7c5SWolfram Sang if (!adapter) 35253f8f7c5SWolfram Sang return 0; 35353f8f7c5SWolfram Sang 35453f8f7c5SWolfram Sang return ACPI_HANDLE(dev) == (acpi_handle)data; 35553f8f7c5SWolfram Sang } 35653f8f7c5SWolfram Sang 35753f8f7c5SWolfram Sang 3581e91a2e5SRuslan Babayev struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) 35953f8f7c5SWolfram Sang { 360*644bf600SSuzuki K Poulose struct device *dev; 361*644bf600SSuzuki K Poulose 362*644bf600SSuzuki K Poulose dev = bus_find_device(&i2c_bus_type, NULL, handle, 363*644bf600SSuzuki K Poulose i2c_acpi_find_match_adapter); 36453f8f7c5SWolfram Sang 36553f8f7c5SWolfram Sang return dev ? i2c_verify_adapter(dev) : NULL; 36653f8f7c5SWolfram Sang } 3671e91a2e5SRuslan Babayev EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); 36853f8f7c5SWolfram Sang 36953f8f7c5SWolfram Sang static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) 37053f8f7c5SWolfram Sang { 37153f8f7c5SWolfram Sang struct device *dev; 37253f8f7c5SWolfram Sang 37300500147SSuzuki K Poulose dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); 37453f8f7c5SWolfram Sang return dev ? i2c_verify_client(dev) : NULL; 37553f8f7c5SWolfram Sang } 37653f8f7c5SWolfram Sang 37753f8f7c5SWolfram Sang static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, 37853f8f7c5SWolfram Sang void *arg) 37953f8f7c5SWolfram Sang { 38053f8f7c5SWolfram Sang struct acpi_device *adev = arg; 38153f8f7c5SWolfram Sang struct i2c_board_info info; 38253f8f7c5SWolfram Sang acpi_handle adapter_handle; 38353f8f7c5SWolfram Sang struct i2c_adapter *adapter; 38453f8f7c5SWolfram Sang struct i2c_client *client; 38553f8f7c5SWolfram Sang 38653f8f7c5SWolfram Sang switch (value) { 38753f8f7c5SWolfram Sang case ACPI_RECONFIG_DEVICE_ADD: 38853f8f7c5SWolfram Sang if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle)) 38953f8f7c5SWolfram Sang break; 39053f8f7c5SWolfram Sang 39153f8f7c5SWolfram Sang adapter = i2c_acpi_find_adapter_by_handle(adapter_handle); 39253f8f7c5SWolfram Sang if (!adapter) 39353f8f7c5SWolfram Sang break; 39453f8f7c5SWolfram Sang 39553f8f7c5SWolfram Sang i2c_acpi_register_device(adapter, adev, &info); 39653f8f7c5SWolfram Sang break; 39753f8f7c5SWolfram Sang case ACPI_RECONFIG_DEVICE_REMOVE: 39853f8f7c5SWolfram Sang if (!acpi_device_enumerated(adev)) 39953f8f7c5SWolfram Sang break; 40053f8f7c5SWolfram Sang 40153f8f7c5SWolfram Sang client = i2c_acpi_find_client_by_adev(adev); 40253f8f7c5SWolfram Sang if (!client) 40353f8f7c5SWolfram Sang break; 40453f8f7c5SWolfram Sang 40553f8f7c5SWolfram Sang i2c_unregister_device(client); 40653f8f7c5SWolfram Sang put_device(&client->dev); 40753f8f7c5SWolfram Sang break; 40853f8f7c5SWolfram Sang } 40953f8f7c5SWolfram Sang 41053f8f7c5SWolfram Sang return NOTIFY_OK; 41153f8f7c5SWolfram Sang } 41253f8f7c5SWolfram Sang 41353f8f7c5SWolfram Sang struct notifier_block i2c_acpi_notifier = { 41453f8f7c5SWolfram Sang .notifier_call = i2c_acpi_notify, 41553f8f7c5SWolfram Sang }; 41653f8f7c5SWolfram Sang 41753f8f7c5SWolfram Sang /** 41853f8f7c5SWolfram Sang * i2c_acpi_new_device - Create i2c-client for the Nth I2cSerialBus resource 41953f8f7c5SWolfram Sang * @dev: Device owning the ACPI resources to get the client from 42053f8f7c5SWolfram Sang * @index: Index of ACPI resource to get 42153f8f7c5SWolfram Sang * @info: describes the I2C device; note this is modified (addr gets set) 42253f8f7c5SWolfram Sang * Context: can sleep 42353f8f7c5SWolfram Sang * 42453f8f7c5SWolfram Sang * By default the i2c subsys creates an i2c-client for the first I2cSerialBus 42553f8f7c5SWolfram Sang * resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus 42653f8f7c5SWolfram Sang * resources, in that case this function can be used to create an i2c-client 42753f8f7c5SWolfram Sang * for other I2cSerialBus resources in the Current Resource Settings table. 42853f8f7c5SWolfram Sang * 42953f8f7c5SWolfram Sang * Also see i2c_new_device, which this function calls to create the i2c-client. 43053f8f7c5SWolfram Sang * 4312dea645fSAndy Shevchenko * Returns a pointer to the new i2c-client, or error pointer in case of failure. 4322dea645fSAndy Shevchenko * Specifically, -EPROBE_DEFER is returned if the adapter is not found. 43353f8f7c5SWolfram Sang */ 43453f8f7c5SWolfram Sang struct i2c_client *i2c_acpi_new_device(struct device *dev, int index, 43553f8f7c5SWolfram Sang struct i2c_board_info *info) 43653f8f7c5SWolfram Sang { 43753f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 43853f8f7c5SWolfram Sang struct i2c_adapter *adapter; 4392dea645fSAndy Shevchenko struct i2c_client *client; 44053f8f7c5SWolfram Sang struct acpi_device *adev; 44153f8f7c5SWolfram Sang LIST_HEAD(resource_list); 44253f8f7c5SWolfram Sang int ret; 44353f8f7c5SWolfram Sang 44453f8f7c5SWolfram Sang adev = ACPI_COMPANION(dev); 44553f8f7c5SWolfram Sang if (!adev) 4462dea645fSAndy Shevchenko return ERR_PTR(-EINVAL); 44753f8f7c5SWolfram Sang 44853f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 44953f8f7c5SWolfram Sang lookup.info = info; 45053f8f7c5SWolfram Sang lookup.device_handle = acpi_device_handle(adev); 45153f8f7c5SWolfram Sang lookup.index = index; 45253f8f7c5SWolfram Sang 45353f8f7c5SWolfram Sang ret = acpi_dev_get_resources(adev, &resource_list, 45453f8f7c5SWolfram Sang i2c_acpi_fill_info, &lookup); 4552dea645fSAndy Shevchenko if (ret < 0) 4562dea645fSAndy Shevchenko return ERR_PTR(ret); 4572dea645fSAndy Shevchenko 45853f8f7c5SWolfram Sang acpi_dev_free_resource_list(&resource_list); 45953f8f7c5SWolfram Sang 4602dea645fSAndy Shevchenko if (!info->addr) 4612dea645fSAndy Shevchenko return ERR_PTR(-EADDRNOTAVAIL); 46253f8f7c5SWolfram Sang 46353f8f7c5SWolfram Sang adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle); 46453f8f7c5SWolfram Sang if (!adapter) 4652dea645fSAndy Shevchenko return ERR_PTR(-EPROBE_DEFER); 46653f8f7c5SWolfram Sang 4672dea645fSAndy Shevchenko client = i2c_new_device(adapter, info); 4682dea645fSAndy Shevchenko if (!client) 4692dea645fSAndy Shevchenko return ERR_PTR(-ENODEV); 4702dea645fSAndy Shevchenko 4712dea645fSAndy Shevchenko return client; 47253f8f7c5SWolfram Sang } 47353f8f7c5SWolfram Sang EXPORT_SYMBOL_GPL(i2c_acpi_new_device); 47453f8f7c5SWolfram Sang 47553f8f7c5SWolfram Sang #ifdef CONFIG_ACPI_I2C_OPREGION 47653f8f7c5SWolfram Sang static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, 47753f8f7c5SWolfram Sang u8 cmd, u8 *data, u8 data_len) 47853f8f7c5SWolfram Sang { 47953f8f7c5SWolfram Sang 48053f8f7c5SWolfram Sang struct i2c_msg msgs[2]; 48153f8f7c5SWolfram Sang int ret; 48253f8f7c5SWolfram Sang u8 *buffer; 48353f8f7c5SWolfram Sang 48453f8f7c5SWolfram Sang buffer = kzalloc(data_len, GFP_KERNEL); 48553f8f7c5SWolfram Sang if (!buffer) 48653f8f7c5SWolfram Sang return AE_NO_MEMORY; 48753f8f7c5SWolfram Sang 48853f8f7c5SWolfram Sang msgs[0].addr = client->addr; 48953f8f7c5SWolfram Sang msgs[0].flags = client->flags; 49053f8f7c5SWolfram Sang msgs[0].len = 1; 49153f8f7c5SWolfram Sang msgs[0].buf = &cmd; 49253f8f7c5SWolfram Sang 49353f8f7c5SWolfram Sang msgs[1].addr = client->addr; 49453f8f7c5SWolfram Sang msgs[1].flags = client->flags | I2C_M_RD; 49553f8f7c5SWolfram Sang msgs[1].len = data_len; 49653f8f7c5SWolfram Sang msgs[1].buf = buffer; 49753f8f7c5SWolfram Sang 49853f8f7c5SWolfram Sang ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 4997781edaeSHans de Goede if (ret < 0) { 5007781edaeSHans de Goede /* Getting a NACK is unfortunately normal with some DSTDs */ 5017781edaeSHans de Goede if (ret == -EREMOTEIO) 5027781edaeSHans de Goede dev_dbg(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", 503c8016fa2SHans de Goede data_len, client->addr, cmd, ret); 50453f8f7c5SWolfram Sang else 5057781edaeSHans de Goede dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", 5067781edaeSHans de Goede data_len, client->addr, cmd, ret); 5070a30446cSHans de Goede /* 2 transfers must have completed successfully */ 5080a30446cSHans de Goede } else if (ret == 2) { 50953f8f7c5SWolfram Sang memcpy(data, buffer, data_len); 5100a30446cSHans de Goede ret = 0; 5110a30446cSHans de Goede } else { 5120a30446cSHans de Goede ret = -EIO; 5137781edaeSHans de Goede } 51453f8f7c5SWolfram Sang 51553f8f7c5SWolfram Sang kfree(buffer); 51653f8f7c5SWolfram Sang return ret; 51753f8f7c5SWolfram Sang } 51853f8f7c5SWolfram Sang 51953f8f7c5SWolfram Sang static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, 52053f8f7c5SWolfram Sang u8 cmd, u8 *data, u8 data_len) 52153f8f7c5SWolfram Sang { 52253f8f7c5SWolfram Sang 52353f8f7c5SWolfram Sang struct i2c_msg msgs[1]; 52453f8f7c5SWolfram Sang u8 *buffer; 52553f8f7c5SWolfram Sang int ret = AE_OK; 52653f8f7c5SWolfram Sang 52753f8f7c5SWolfram Sang buffer = kzalloc(data_len + 1, GFP_KERNEL); 52853f8f7c5SWolfram Sang if (!buffer) 52953f8f7c5SWolfram Sang return AE_NO_MEMORY; 53053f8f7c5SWolfram Sang 53153f8f7c5SWolfram Sang buffer[0] = cmd; 53253f8f7c5SWolfram Sang memcpy(buffer + 1, data, data_len); 53353f8f7c5SWolfram Sang 53453f8f7c5SWolfram Sang msgs[0].addr = client->addr; 53553f8f7c5SWolfram Sang msgs[0].flags = client->flags; 53653f8f7c5SWolfram Sang msgs[0].len = data_len + 1; 53753f8f7c5SWolfram Sang msgs[0].buf = buffer; 53853f8f7c5SWolfram Sang 53953f8f7c5SWolfram Sang ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 54053f8f7c5SWolfram Sang 54153f8f7c5SWolfram Sang kfree(buffer); 542c463a158SHans de Goede 543c463a158SHans de Goede if (ret < 0) { 544c463a158SHans de Goede dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); 54553f8f7c5SWolfram Sang return ret; 54653f8f7c5SWolfram Sang } 54753f8f7c5SWolfram Sang 548c463a158SHans de Goede /* 1 transfer must have completed successfully */ 549c463a158SHans de Goede return (ret == 1) ? 0 : -EIO; 550c463a158SHans de Goede } 551c463a158SHans de Goede 55253f8f7c5SWolfram Sang static acpi_status 55353f8f7c5SWolfram Sang i2c_acpi_space_handler(u32 function, acpi_physical_address command, 55453f8f7c5SWolfram Sang u32 bits, u64 *value64, 55553f8f7c5SWolfram Sang void *handler_context, void *region_context) 55653f8f7c5SWolfram Sang { 55753f8f7c5SWolfram Sang struct gsb_buffer *gsb = (struct gsb_buffer *)value64; 55853f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data = handler_context; 55953f8f7c5SWolfram Sang struct acpi_connection_info *info = &data->info; 56053f8f7c5SWolfram Sang struct acpi_resource_i2c_serialbus *sb; 56153f8f7c5SWolfram Sang struct i2c_adapter *adapter = data->adapter; 56253f8f7c5SWolfram Sang struct i2c_client *client; 56353f8f7c5SWolfram Sang struct acpi_resource *ares; 56453f8f7c5SWolfram Sang u32 accessor_type = function >> 16; 56553f8f7c5SWolfram Sang u8 action = function & ACPI_IO_MASK; 56653f8f7c5SWolfram Sang acpi_status ret; 56753f8f7c5SWolfram Sang int status; 56853f8f7c5SWolfram Sang 56953f8f7c5SWolfram Sang ret = acpi_buffer_to_resource(info->connection, info->length, &ares); 57053f8f7c5SWolfram Sang if (ACPI_FAILURE(ret)) 57153f8f7c5SWolfram Sang return ret; 57253f8f7c5SWolfram Sang 57353f8f7c5SWolfram Sang client = kzalloc(sizeof(*client), GFP_KERNEL); 57453f8f7c5SWolfram Sang if (!client) { 57553f8f7c5SWolfram Sang ret = AE_NO_MEMORY; 57653f8f7c5SWolfram Sang goto err; 57753f8f7c5SWolfram Sang } 57853f8f7c5SWolfram Sang 5790d5102feSAndy Shevchenko if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) { 58053f8f7c5SWolfram Sang ret = AE_BAD_PARAMETER; 58153f8f7c5SWolfram Sang goto err; 58253f8f7c5SWolfram Sang } 58353f8f7c5SWolfram Sang 58453f8f7c5SWolfram Sang client->adapter = adapter; 58553f8f7c5SWolfram Sang client->addr = sb->slave_address; 58653f8f7c5SWolfram Sang 58753f8f7c5SWolfram Sang if (sb->access_mode == ACPI_I2C_10BIT_MODE) 58853f8f7c5SWolfram Sang client->flags |= I2C_CLIENT_TEN; 58953f8f7c5SWolfram Sang 59053f8f7c5SWolfram Sang switch (accessor_type) { 59153f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: 59253f8f7c5SWolfram Sang if (action == ACPI_READ) { 59353f8f7c5SWolfram Sang status = i2c_smbus_read_byte(client); 59453f8f7c5SWolfram Sang if (status >= 0) { 59553f8f7c5SWolfram Sang gsb->bdata = status; 59653f8f7c5SWolfram Sang status = 0; 59753f8f7c5SWolfram Sang } 59853f8f7c5SWolfram Sang } else { 59953f8f7c5SWolfram Sang status = i2c_smbus_write_byte(client, gsb->bdata); 60053f8f7c5SWolfram Sang } 60153f8f7c5SWolfram Sang break; 60253f8f7c5SWolfram Sang 60353f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_BYTE: 60453f8f7c5SWolfram Sang if (action == ACPI_READ) { 60553f8f7c5SWolfram Sang status = i2c_smbus_read_byte_data(client, command); 60653f8f7c5SWolfram Sang if (status >= 0) { 60753f8f7c5SWolfram Sang gsb->bdata = status; 60853f8f7c5SWolfram Sang status = 0; 60953f8f7c5SWolfram Sang } 61053f8f7c5SWolfram Sang } else { 61153f8f7c5SWolfram Sang status = i2c_smbus_write_byte_data(client, command, 61253f8f7c5SWolfram Sang gsb->bdata); 61353f8f7c5SWolfram Sang } 61453f8f7c5SWolfram Sang break; 61553f8f7c5SWolfram Sang 61653f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_WORD: 61753f8f7c5SWolfram Sang if (action == ACPI_READ) { 61853f8f7c5SWolfram Sang status = i2c_smbus_read_word_data(client, command); 61953f8f7c5SWolfram Sang if (status >= 0) { 62053f8f7c5SWolfram Sang gsb->wdata = status; 62153f8f7c5SWolfram Sang status = 0; 62253f8f7c5SWolfram Sang } 62353f8f7c5SWolfram Sang } else { 62453f8f7c5SWolfram Sang status = i2c_smbus_write_word_data(client, command, 62553f8f7c5SWolfram Sang gsb->wdata); 62653f8f7c5SWolfram Sang } 62753f8f7c5SWolfram Sang break; 62853f8f7c5SWolfram Sang 62953f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_BLOCK: 63053f8f7c5SWolfram Sang if (action == ACPI_READ) { 63153f8f7c5SWolfram Sang status = i2c_smbus_read_block_data(client, command, 63253f8f7c5SWolfram Sang gsb->data); 63353f8f7c5SWolfram Sang if (status >= 0) { 63453f8f7c5SWolfram Sang gsb->len = status; 63553f8f7c5SWolfram Sang status = 0; 63653f8f7c5SWolfram Sang } 63753f8f7c5SWolfram Sang } else { 63853f8f7c5SWolfram Sang status = i2c_smbus_write_block_data(client, command, 63953f8f7c5SWolfram Sang gsb->len, gsb->data); 64053f8f7c5SWolfram Sang } 64153f8f7c5SWolfram Sang break; 64253f8f7c5SWolfram Sang 64353f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: 64453f8f7c5SWolfram Sang if (action == ACPI_READ) { 64553f8f7c5SWolfram Sang status = acpi_gsb_i2c_read_bytes(client, command, 64653f8f7c5SWolfram Sang gsb->data, info->access_length); 64753f8f7c5SWolfram Sang } else { 64853f8f7c5SWolfram Sang status = acpi_gsb_i2c_write_bytes(client, command, 64953f8f7c5SWolfram Sang gsb->data, info->access_length); 65053f8f7c5SWolfram Sang } 65153f8f7c5SWolfram Sang break; 65253f8f7c5SWolfram Sang 65353f8f7c5SWolfram Sang default: 65453f8f7c5SWolfram Sang dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", 65553f8f7c5SWolfram Sang accessor_type, client->addr); 65653f8f7c5SWolfram Sang ret = AE_BAD_PARAMETER; 65753f8f7c5SWolfram Sang goto err; 65853f8f7c5SWolfram Sang } 65953f8f7c5SWolfram Sang 66053f8f7c5SWolfram Sang gsb->status = status; 66153f8f7c5SWolfram Sang 66253f8f7c5SWolfram Sang err: 66353f8f7c5SWolfram Sang kfree(client); 66453f8f7c5SWolfram Sang ACPI_FREE(ares); 66553f8f7c5SWolfram Sang return ret; 66653f8f7c5SWolfram Sang } 66753f8f7c5SWolfram Sang 66853f8f7c5SWolfram Sang 66953f8f7c5SWolfram Sang int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) 67053f8f7c5SWolfram Sang { 67153f8f7c5SWolfram Sang acpi_handle handle; 67253f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data; 67353f8f7c5SWolfram Sang acpi_status status; 67453f8f7c5SWolfram Sang 67553f8f7c5SWolfram Sang if (!adapter->dev.parent) 67653f8f7c5SWolfram Sang return -ENODEV; 67753f8f7c5SWolfram Sang 67853f8f7c5SWolfram Sang handle = ACPI_HANDLE(adapter->dev.parent); 67953f8f7c5SWolfram Sang 68053f8f7c5SWolfram Sang if (!handle) 68153f8f7c5SWolfram Sang return -ENODEV; 68253f8f7c5SWolfram Sang 68353f8f7c5SWolfram Sang data = kzalloc(sizeof(struct i2c_acpi_handler_data), 68453f8f7c5SWolfram Sang GFP_KERNEL); 68553f8f7c5SWolfram Sang if (!data) 68653f8f7c5SWolfram Sang return -ENOMEM; 68753f8f7c5SWolfram Sang 68853f8f7c5SWolfram Sang data->adapter = adapter; 68953f8f7c5SWolfram Sang status = acpi_bus_attach_private_data(handle, (void *)data); 69053f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 69153f8f7c5SWolfram Sang kfree(data); 69253f8f7c5SWolfram Sang return -ENOMEM; 69353f8f7c5SWolfram Sang } 69453f8f7c5SWolfram Sang 69553f8f7c5SWolfram Sang status = acpi_install_address_space_handler(handle, 69653f8f7c5SWolfram Sang ACPI_ADR_SPACE_GSBUS, 69753f8f7c5SWolfram Sang &i2c_acpi_space_handler, 69853f8f7c5SWolfram Sang NULL, 69953f8f7c5SWolfram Sang data); 70053f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 70153f8f7c5SWolfram Sang dev_err(&adapter->dev, "Error installing i2c space handler\n"); 70253f8f7c5SWolfram Sang acpi_bus_detach_private_data(handle); 70353f8f7c5SWolfram Sang kfree(data); 70453f8f7c5SWolfram Sang return -ENOMEM; 70553f8f7c5SWolfram Sang } 70653f8f7c5SWolfram Sang 70753f8f7c5SWolfram Sang acpi_walk_dep_device_list(handle); 70853f8f7c5SWolfram Sang return 0; 70953f8f7c5SWolfram Sang } 71053f8f7c5SWolfram Sang 71153f8f7c5SWolfram Sang void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) 71253f8f7c5SWolfram Sang { 71353f8f7c5SWolfram Sang acpi_handle handle; 71453f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data; 71553f8f7c5SWolfram Sang acpi_status status; 71653f8f7c5SWolfram Sang 71753f8f7c5SWolfram Sang if (!adapter->dev.parent) 71853f8f7c5SWolfram Sang return; 71953f8f7c5SWolfram Sang 72053f8f7c5SWolfram Sang handle = ACPI_HANDLE(adapter->dev.parent); 72153f8f7c5SWolfram Sang 72253f8f7c5SWolfram Sang if (!handle) 72353f8f7c5SWolfram Sang return; 72453f8f7c5SWolfram Sang 72553f8f7c5SWolfram Sang acpi_remove_address_space_handler(handle, 72653f8f7c5SWolfram Sang ACPI_ADR_SPACE_GSBUS, 72753f8f7c5SWolfram Sang &i2c_acpi_space_handler); 72853f8f7c5SWolfram Sang 72953f8f7c5SWolfram Sang status = acpi_bus_get_private_data(handle, (void **)&data); 73053f8f7c5SWolfram Sang if (ACPI_SUCCESS(status)) 73153f8f7c5SWolfram Sang kfree(data); 73253f8f7c5SWolfram Sang 73353f8f7c5SWolfram Sang acpi_bus_detach_private_data(handle); 73453f8f7c5SWolfram Sang } 73553f8f7c5SWolfram Sang #endif /* CONFIG_ACPI_I2C_OPREGION */ 736