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; 427574c0dbSHans de Goede u32 force_speed; 4353f8f7c5SWolfram Sang }; 4453f8f7c5SWolfram Sang 450d5102feSAndy Shevchenko /** 460d5102feSAndy Shevchenko * i2c_acpi_get_i2c_resource - Gets I2cSerialBus resource if type matches 470d5102feSAndy Shevchenko * @ares: ACPI resource 480d5102feSAndy Shevchenko * @i2c: Pointer to I2cSerialBus resource will be returned here 490d5102feSAndy Shevchenko * 500d5102feSAndy Shevchenko * Checks if the given ACPI resource is of type I2cSerialBus. 510d5102feSAndy Shevchenko * In this case, returns a pointer to it to the caller. 520d5102feSAndy Shevchenko * 530d5102feSAndy Shevchenko * Returns true if resource type is of I2cSerialBus, otherwise false. 540d5102feSAndy Shevchenko */ 550d5102feSAndy Shevchenko bool i2c_acpi_get_i2c_resource(struct acpi_resource *ares, 560d5102feSAndy Shevchenko struct acpi_resource_i2c_serialbus **i2c) 570d5102feSAndy Shevchenko { 580d5102feSAndy Shevchenko struct acpi_resource_i2c_serialbus *sb; 590d5102feSAndy Shevchenko 600d5102feSAndy Shevchenko if (ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) 610d5102feSAndy Shevchenko return false; 620d5102feSAndy Shevchenko 630d5102feSAndy Shevchenko sb = &ares->data.i2c_serial_bus; 640d5102feSAndy Shevchenko if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) 650d5102feSAndy Shevchenko return false; 660d5102feSAndy Shevchenko 670d5102feSAndy Shevchenko *i2c = sb; 680d5102feSAndy Shevchenko return true; 690d5102feSAndy Shevchenko } 700d5102feSAndy Shevchenko EXPORT_SYMBOL_GPL(i2c_acpi_get_i2c_resource); 710d5102feSAndy Shevchenko 7220a1b3acSHans de Goede static int i2c_acpi_resource_count(struct acpi_resource *ares, void *data) 7320a1b3acSHans de Goede { 7420a1b3acSHans de Goede struct acpi_resource_i2c_serialbus *sb; 7520a1b3acSHans de Goede int *count = data; 7620a1b3acSHans de Goede 7720a1b3acSHans de Goede if (i2c_acpi_get_i2c_resource(ares, &sb)) 7820a1b3acSHans de Goede *count = *count + 1; 7920a1b3acSHans de Goede 8020a1b3acSHans de Goede return 1; 8120a1b3acSHans de Goede } 8220a1b3acSHans de Goede 8320a1b3acSHans de Goede /** 8420a1b3acSHans de Goede * i2c_acpi_client_count - Count the number of I2cSerialBus resources 8520a1b3acSHans de Goede * @adev: ACPI device 8620a1b3acSHans de Goede * 8720a1b3acSHans de Goede * Returns the number of I2cSerialBus resources in the ACPI-device's 8820a1b3acSHans de Goede * resource-list; or a negative error code. 8920a1b3acSHans de Goede */ 9020a1b3acSHans de Goede int i2c_acpi_client_count(struct acpi_device *adev) 9120a1b3acSHans de Goede { 9220a1b3acSHans de Goede int ret, count = 0; 9320a1b3acSHans de Goede LIST_HEAD(r); 9420a1b3acSHans de Goede 9520a1b3acSHans de Goede ret = acpi_dev_get_resources(adev, &r, i2c_acpi_resource_count, &count); 9620a1b3acSHans de Goede if (ret < 0) 9720a1b3acSHans de Goede return ret; 9820a1b3acSHans de Goede 9920a1b3acSHans de Goede acpi_dev_free_resource_list(&r); 10020a1b3acSHans de Goede return count; 10120a1b3acSHans de Goede } 10220a1b3acSHans de Goede EXPORT_SYMBOL_GPL(i2c_acpi_client_count); 10320a1b3acSHans de Goede 10453f8f7c5SWolfram Sang static int i2c_acpi_fill_info(struct acpi_resource *ares, void *data) 10553f8f7c5SWolfram Sang { 10653f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup = data; 10753f8f7c5SWolfram Sang struct i2c_board_info *info = lookup->info; 10853f8f7c5SWolfram Sang struct acpi_resource_i2c_serialbus *sb; 10953f8f7c5SWolfram Sang acpi_status status; 11053f8f7c5SWolfram Sang 1110d5102feSAndy Shevchenko if (info->addr || !i2c_acpi_get_i2c_resource(ares, &sb)) 11253f8f7c5SWolfram Sang return 1; 11353f8f7c5SWolfram Sang 11453f8f7c5SWolfram Sang if (lookup->index != -1 && lookup->n++ != lookup->index) 11553f8f7c5SWolfram Sang return 1; 11653f8f7c5SWolfram Sang 11753f8f7c5SWolfram Sang status = acpi_get_handle(lookup->device_handle, 11853f8f7c5SWolfram Sang sb->resource_source.string_ptr, 11953f8f7c5SWolfram Sang &lookup->adapter_handle); 1205f59d6a1SAndy Shevchenko if (ACPI_FAILURE(status)) 12153f8f7c5SWolfram Sang return 1; 12253f8f7c5SWolfram Sang 12353f8f7c5SWolfram Sang info->addr = sb->slave_address; 12453f8f7c5SWolfram Sang lookup->speed = sb->connection_speed; 12553f8f7c5SWolfram Sang if (sb->access_mode == ACPI_I2C_10BIT_MODE) 12653f8f7c5SWolfram Sang info->flags |= I2C_CLIENT_TEN; 12753f8f7c5SWolfram Sang 12853f8f7c5SWolfram Sang return 1; 12953f8f7c5SWolfram Sang } 13053f8f7c5SWolfram Sang 1313a4991a9SHans de Goede static const struct acpi_device_id i2c_acpi_ignored_device_ids[] = { 1323a4991a9SHans de Goede /* 1333a4991a9SHans de Goede * ACPI video acpi_devices, which are handled by the acpi-video driver 1343a4991a9SHans de Goede * sometimes contain a SERIAL_TYPE_I2C ACPI resource, ignore these. 1353a4991a9SHans de Goede */ 1363a4991a9SHans de Goede { ACPI_VIDEO_HID, 0 }, 1373a4991a9SHans de Goede {} 1383a4991a9SHans de Goede }; 1393a4991a9SHans de Goede 14053f8f7c5SWolfram Sang static int i2c_acpi_do_lookup(struct acpi_device *adev, 14153f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup) 14253f8f7c5SWolfram Sang { 14353f8f7c5SWolfram Sang struct i2c_board_info *info = lookup->info; 14453f8f7c5SWolfram Sang struct list_head resource_list; 14553f8f7c5SWolfram Sang int ret; 14653f8f7c5SWolfram Sang 147fb90e58fSHans de Goede if (acpi_bus_get_status(adev)) 14853f8f7c5SWolfram Sang return -EINVAL; 14953f8f7c5SWolfram Sang 150fb90e58fSHans de Goede if (!acpi_dev_ready_for_enumeration(adev)) 151fb90e58fSHans de Goede return -ENODEV; 152fb90e58fSHans de Goede 1533a4991a9SHans de Goede if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) 1543a4991a9SHans de Goede return -ENODEV; 1553a4991a9SHans de Goede 15653f8f7c5SWolfram Sang memset(info, 0, sizeof(*info)); 15753f8f7c5SWolfram Sang lookup->device_handle = acpi_device_handle(adev); 15853f8f7c5SWolfram Sang 15953f8f7c5SWolfram Sang /* Look up for I2cSerialBus resource */ 16053f8f7c5SWolfram Sang INIT_LIST_HEAD(&resource_list); 16153f8f7c5SWolfram Sang ret = acpi_dev_get_resources(adev, &resource_list, 16253f8f7c5SWolfram Sang i2c_acpi_fill_info, lookup); 16353f8f7c5SWolfram Sang acpi_dev_free_resource_list(&resource_list); 16453f8f7c5SWolfram Sang 16553f8f7c5SWolfram Sang if (ret < 0 || !info->addr) 16653f8f7c5SWolfram Sang return -EINVAL; 16753f8f7c5SWolfram Sang 16853f8f7c5SWolfram Sang return 0; 16953f8f7c5SWolfram Sang } 17053f8f7c5SWolfram Sang 171c2223ddcSCharles Keepax static int i2c_acpi_add_resource(struct acpi_resource *ares, void *data) 172c2223ddcSCharles Keepax { 173c2223ddcSCharles Keepax int *irq = data; 174c2223ddcSCharles Keepax struct resource r; 175c2223ddcSCharles Keepax 176c2223ddcSCharles Keepax if (*irq <= 0 && acpi_dev_resource_interrupt(ares, 0, &r)) 177c2223ddcSCharles Keepax *irq = i2c_dev_irq_from_resources(&r, 1); 178c2223ddcSCharles Keepax 179c2223ddcSCharles Keepax return 1; /* No need to add resource to the list */ 180c2223ddcSCharles Keepax } 181c2223ddcSCharles Keepax 18216c9db1dSCharles Keepax /** 18316c9db1dSCharles Keepax * i2c_acpi_get_irq - get device IRQ number from ACPI 18416c9db1dSCharles Keepax * @client: Pointer to the I2C client device 18516c9db1dSCharles Keepax * 18616c9db1dSCharles Keepax * Find the IRQ number used by a specific client device. 18716c9db1dSCharles Keepax * 18816c9db1dSCharles Keepax * Return: The IRQ number or an error code. 18916c9db1dSCharles Keepax */ 19016c9db1dSCharles Keepax int i2c_acpi_get_irq(struct i2c_client *client) 191a52e3b37SCharles Keepax { 19216c9db1dSCharles Keepax struct acpi_device *adev = ACPI_COMPANION(&client->dev); 193a52e3b37SCharles Keepax struct list_head resource_list; 194a52e3b37SCharles Keepax int irq = -ENOENT; 195a52e3b37SCharles Keepax int ret; 196a52e3b37SCharles Keepax 197a52e3b37SCharles Keepax INIT_LIST_HEAD(&resource_list); 198a52e3b37SCharles Keepax 199a52e3b37SCharles Keepax ret = acpi_dev_get_resources(adev, &resource_list, 200a52e3b37SCharles Keepax i2c_acpi_add_resource, &irq); 201a52e3b37SCharles Keepax if (ret < 0) 202a52e3b37SCharles Keepax return ret; 203a52e3b37SCharles Keepax 204a52e3b37SCharles Keepax acpi_dev_free_resource_list(&resource_list); 205a52e3b37SCharles Keepax 2068466b616SCharles Keepax if (irq == -ENOENT) 2078466b616SCharles Keepax irq = acpi_dev_gpio_irq_get(adev, 0); 2088466b616SCharles Keepax 209a52e3b37SCharles Keepax return irq; 210a52e3b37SCharles Keepax } 211a52e3b37SCharles Keepax 21253f8f7c5SWolfram Sang static int i2c_acpi_get_info(struct acpi_device *adev, 21353f8f7c5SWolfram Sang struct i2c_board_info *info, 21453f8f7c5SWolfram Sang struct i2c_adapter *adapter, 21553f8f7c5SWolfram Sang acpi_handle *adapter_handle) 21653f8f7c5SWolfram Sang { 21753f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 21853f8f7c5SWolfram Sang int ret; 21953f8f7c5SWolfram Sang 22053f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 22153f8f7c5SWolfram Sang lookup.info = info; 22253f8f7c5SWolfram Sang lookup.index = -1; 22353f8f7c5SWolfram Sang 2244befedc0SArd Biesheuvel if (acpi_device_enumerated(adev)) 2254befedc0SArd Biesheuvel return -EINVAL; 2264befedc0SArd Biesheuvel 22753f8f7c5SWolfram Sang ret = i2c_acpi_do_lookup(adev, &lookup); 22853f8f7c5SWolfram Sang if (ret) 22953f8f7c5SWolfram Sang return ret; 23053f8f7c5SWolfram Sang 23153f8f7c5SWolfram Sang if (adapter) { 23253f8f7c5SWolfram Sang /* The adapter must match the one in I2cSerialBus() connector */ 23353f8f7c5SWolfram Sang if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle) 23453f8f7c5SWolfram Sang return -ENODEV; 23553f8f7c5SWolfram Sang } else { 23653f8f7c5SWolfram Sang struct acpi_device *adapter_adev; 23753f8f7c5SWolfram Sang 23853f8f7c5SWolfram Sang /* The adapter must be present */ 239*0bc4978aSRafael J. Wysocki adapter_adev = acpi_fetch_acpi_dev(lookup.adapter_handle); 240*0bc4978aSRafael J. Wysocki if (!adapter_adev) 24153f8f7c5SWolfram Sang return -ENODEV; 24253f8f7c5SWolfram Sang if (acpi_bus_get_status(adapter_adev) || 24353f8f7c5SWolfram Sang !adapter_adev->status.present) 24453f8f7c5SWolfram Sang return -ENODEV; 24553f8f7c5SWolfram Sang } 24653f8f7c5SWolfram Sang 24753f8f7c5SWolfram Sang info->fwnode = acpi_fwnode_handle(adev); 24853f8f7c5SWolfram Sang if (adapter_handle) 24953f8f7c5SWolfram Sang *adapter_handle = lookup.adapter_handle; 25053f8f7c5SWolfram Sang 25153f8f7c5SWolfram Sang acpi_set_modalias(adev, dev_name(&adev->dev), info->type, 25253f8f7c5SWolfram Sang sizeof(info->type)); 25353f8f7c5SWolfram Sang 25453f8f7c5SWolfram Sang return 0; 25553f8f7c5SWolfram Sang } 25653f8f7c5SWolfram Sang 25753f8f7c5SWolfram Sang static void i2c_acpi_register_device(struct i2c_adapter *adapter, 25853f8f7c5SWolfram Sang struct acpi_device *adev, 25953f8f7c5SWolfram Sang struct i2c_board_info *info) 26053f8f7c5SWolfram Sang { 261a6e1445cSHans de Goede /* 262a6e1445cSHans de Goede * Skip registration on boards where the ACPI tables are 263a6e1445cSHans de Goede * known to contain bogus I2C devices. 264a6e1445cSHans de Goede */ 265a6e1445cSHans de Goede if (acpi_quirk_skip_i2c_client_enumeration(adev)) 266a6e1445cSHans de Goede return; 267a6e1445cSHans de Goede 26853f8f7c5SWolfram Sang adev->power.flags.ignore_parent = true; 26953f8f7c5SWolfram Sang acpi_device_set_enumerated(adev); 27053f8f7c5SWolfram Sang 271785e21cfSHans de Goede if (IS_ERR(i2c_new_client_device(adapter, info))) 27253f8f7c5SWolfram Sang adev->power.flags.ignore_parent = false; 27353f8f7c5SWolfram Sang } 27453f8f7c5SWolfram Sang 27553f8f7c5SWolfram Sang static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, 27653f8f7c5SWolfram Sang void *data, void **return_value) 27753f8f7c5SWolfram Sang { 27853f8f7c5SWolfram Sang struct i2c_adapter *adapter = data; 279*0bc4978aSRafael J. Wysocki struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 28053f8f7c5SWolfram Sang struct i2c_board_info info; 28153f8f7c5SWolfram Sang 282*0bc4978aSRafael J. Wysocki if (!adev || i2c_acpi_get_info(adev, &info, adapter, NULL)) 28353f8f7c5SWolfram Sang return AE_OK; 28453f8f7c5SWolfram Sang 28553f8f7c5SWolfram Sang i2c_acpi_register_device(adapter, adev, &info); 28653f8f7c5SWolfram Sang 28753f8f7c5SWolfram Sang return AE_OK; 28853f8f7c5SWolfram Sang } 28953f8f7c5SWolfram Sang 29053f8f7c5SWolfram Sang #define I2C_ACPI_MAX_SCAN_DEPTH 32 29153f8f7c5SWolfram Sang 29253f8f7c5SWolfram Sang /** 29353f8f7c5SWolfram Sang * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter 29453f8f7c5SWolfram Sang * @adap: pointer to adapter 29553f8f7c5SWolfram Sang * 29653f8f7c5SWolfram Sang * Enumerate all I2C slave devices behind this adapter by walking the ACPI 29753f8f7c5SWolfram Sang * namespace. When a device is found it will be added to the Linux device 29853f8f7c5SWolfram Sang * model and bound to the corresponding ACPI handle. 29953f8f7c5SWolfram Sang */ 30053f8f7c5SWolfram Sang void i2c_acpi_register_devices(struct i2c_adapter *adap) 30153f8f7c5SWolfram Sang { 302a9e10e58SDaniel Scally struct acpi_device *adev; 30353f8f7c5SWolfram Sang acpi_status status; 30453f8f7c5SWolfram Sang 30553f8f7c5SWolfram Sang if (!has_acpi_companion(&adap->dev)) 30653f8f7c5SWolfram Sang return; 30753f8f7c5SWolfram Sang 30853f8f7c5SWolfram Sang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 30953f8f7c5SWolfram Sang I2C_ACPI_MAX_SCAN_DEPTH, 31053f8f7c5SWolfram Sang i2c_acpi_add_device, NULL, 31153f8f7c5SWolfram Sang adap, NULL); 31253f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) 31353f8f7c5SWolfram Sang dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); 3148058d699SHans de Goede 3158058d699SHans de Goede if (!adap->dev.parent) 3168058d699SHans de Goede return; 3178058d699SHans de Goede 318a9e10e58SDaniel Scally adev = ACPI_COMPANION(adap->dev.parent); 319a9e10e58SDaniel Scally if (!adev) 3208058d699SHans de Goede return; 3218058d699SHans de Goede 322a9e10e58SDaniel Scally acpi_dev_clear_dependencies(adev); 32353f8f7c5SWolfram Sang } 32453f8f7c5SWolfram Sang 3257574c0dbSHans de Goede static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = { 3267574c0dbSHans de Goede /* 3277574c0dbSHans de Goede * These Silead touchscreen controllers only work at 400KHz, for 3287574c0dbSHans de Goede * some reason they do not work at 100KHz. On some devices the ACPI 3297574c0dbSHans de Goede * tables list another device at their bus as only being capable 3307574c0dbSHans de Goede * of 100KHz, testing has shown that these other devices work fine 3317574c0dbSHans de Goede * at 400KHz (as can be expected of any recent i2c hw) so we force 3327574c0dbSHans de Goede * the speed of the bus to 400 KHz if a Silead device is present. 3337574c0dbSHans de Goede */ 3347574c0dbSHans de Goede { "MSSL1680", 0 }, 3357574c0dbSHans de Goede {} 3367574c0dbSHans de Goede }; 3377574c0dbSHans de Goede 33853f8f7c5SWolfram Sang static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, 33953f8f7c5SWolfram Sang void *data, void **return_value) 34053f8f7c5SWolfram Sang { 34153f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup = data; 342*0bc4978aSRafael J. Wysocki struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 34353f8f7c5SWolfram Sang 344*0bc4978aSRafael J. Wysocki if (!adev || i2c_acpi_do_lookup(adev, lookup)) 34553f8f7c5SWolfram Sang return AE_OK; 34653f8f7c5SWolfram Sang 34753f8f7c5SWolfram Sang if (lookup->search_handle != lookup->adapter_handle) 34853f8f7c5SWolfram Sang return AE_OK; 34953f8f7c5SWolfram Sang 35053f8f7c5SWolfram Sang if (lookup->speed <= lookup->min_speed) 35153f8f7c5SWolfram Sang lookup->min_speed = lookup->speed; 35253f8f7c5SWolfram Sang 3537574c0dbSHans de Goede if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0) 354e6282fc6SAndy Shevchenko lookup->force_speed = I2C_MAX_FAST_MODE_FREQ; 3557574c0dbSHans de Goede 35653f8f7c5SWolfram Sang return AE_OK; 35753f8f7c5SWolfram Sang } 35853f8f7c5SWolfram Sang 35953f8f7c5SWolfram Sang /** 36053f8f7c5SWolfram Sang * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI 36153f8f7c5SWolfram Sang * @dev: The device owning the bus 36253f8f7c5SWolfram Sang * 36353f8f7c5SWolfram Sang * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves 36453f8f7c5SWolfram Sang * devices connected to this bus and use the speed of slowest device. 36553f8f7c5SWolfram Sang * 36653f8f7c5SWolfram Sang * Returns the speed in Hz or zero 36753f8f7c5SWolfram Sang */ 36853f8f7c5SWolfram Sang u32 i2c_acpi_find_bus_speed(struct device *dev) 36953f8f7c5SWolfram Sang { 37053f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 37153f8f7c5SWolfram Sang struct i2c_board_info dummy; 37253f8f7c5SWolfram Sang acpi_status status; 37353f8f7c5SWolfram Sang 37453f8f7c5SWolfram Sang if (!has_acpi_companion(dev)) 37553f8f7c5SWolfram Sang return 0; 37653f8f7c5SWolfram Sang 37753f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 37853f8f7c5SWolfram Sang lookup.search_handle = ACPI_HANDLE(dev); 37953f8f7c5SWolfram Sang lookup.min_speed = UINT_MAX; 38053f8f7c5SWolfram Sang lookup.info = &dummy; 38153f8f7c5SWolfram Sang lookup.index = -1; 38253f8f7c5SWolfram Sang 38353f8f7c5SWolfram Sang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 38453f8f7c5SWolfram Sang I2C_ACPI_MAX_SCAN_DEPTH, 38553f8f7c5SWolfram Sang i2c_acpi_lookup_speed, NULL, 38653f8f7c5SWolfram Sang &lookup, NULL); 38753f8f7c5SWolfram Sang 38853f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 38953f8f7c5SWolfram Sang dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); 39053f8f7c5SWolfram Sang return 0; 39153f8f7c5SWolfram Sang } 39253f8f7c5SWolfram Sang 3937574c0dbSHans de Goede if (lookup.force_speed) { 3947574c0dbSHans de Goede if (lookup.force_speed != lookup.min_speed) 3957574c0dbSHans de Goede dev_warn(dev, FW_BUG "DSDT uses known not-working I2C bus speed %d, forcing it to %d\n", 3967574c0dbSHans de Goede lookup.min_speed, lookup.force_speed); 3977574c0dbSHans de Goede return lookup.force_speed; 3987574c0dbSHans de Goede } else if (lookup.min_speed != UINT_MAX) { 3997574c0dbSHans de Goede return lookup.min_speed; 4007574c0dbSHans de Goede } else { 4017574c0dbSHans de Goede return 0; 4027574c0dbSHans de Goede } 40353f8f7c5SWolfram Sang } 40453f8f7c5SWolfram Sang EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); 40553f8f7c5SWolfram Sang 4061e91a2e5SRuslan Babayev struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) 40753f8f7c5SWolfram Sang { 4080a2d47aaSAndy Shevchenko struct i2c_adapter *adapter; 409644bf600SSuzuki K Poulose struct device *dev; 410644bf600SSuzuki K Poulose 4110a2d47aaSAndy Shevchenko dev = bus_find_device(&i2c_bus_type, NULL, handle, device_match_acpi_handle); 4120a2d47aaSAndy Shevchenko if (!dev) 4130a2d47aaSAndy Shevchenko return NULL; 41453f8f7c5SWolfram Sang 4150a2d47aaSAndy Shevchenko adapter = i2c_verify_adapter(dev); 4160a2d47aaSAndy Shevchenko if (!adapter) 4170a2d47aaSAndy Shevchenko put_device(dev); 4180a2d47aaSAndy Shevchenko 4190a2d47aaSAndy Shevchenko return adapter; 42053f8f7c5SWolfram Sang } 4211e91a2e5SRuslan Babayev EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); 42253f8f7c5SWolfram Sang 42353f8f7c5SWolfram Sang static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) 42453f8f7c5SWolfram Sang { 42553f8f7c5SWolfram Sang struct device *dev; 4268daee952SWolfram Sang struct i2c_client *client; 42753f8f7c5SWolfram Sang 42800500147SSuzuki K Poulose dev = bus_find_device_by_acpi_dev(&i2c_bus_type, adev); 4298daee952SWolfram Sang if (!dev) 4308daee952SWolfram Sang return NULL; 4318daee952SWolfram Sang 4328daee952SWolfram Sang client = i2c_verify_client(dev); 4338daee952SWolfram Sang if (!client) 4348daee952SWolfram Sang put_device(dev); 4358daee952SWolfram Sang 4368daee952SWolfram Sang return client; 43753f8f7c5SWolfram Sang } 43853f8f7c5SWolfram Sang 43953f8f7c5SWolfram Sang static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, 44053f8f7c5SWolfram Sang void *arg) 44153f8f7c5SWolfram Sang { 44253f8f7c5SWolfram Sang struct acpi_device *adev = arg; 44353f8f7c5SWolfram Sang struct i2c_board_info info; 44453f8f7c5SWolfram Sang acpi_handle adapter_handle; 44553f8f7c5SWolfram Sang struct i2c_adapter *adapter; 44653f8f7c5SWolfram Sang struct i2c_client *client; 44753f8f7c5SWolfram Sang 44853f8f7c5SWolfram Sang switch (value) { 44953f8f7c5SWolfram Sang case ACPI_RECONFIG_DEVICE_ADD: 45053f8f7c5SWolfram Sang if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle)) 45153f8f7c5SWolfram Sang break; 45253f8f7c5SWolfram Sang 45353f8f7c5SWolfram Sang adapter = i2c_acpi_find_adapter_by_handle(adapter_handle); 45453f8f7c5SWolfram Sang if (!adapter) 45553f8f7c5SWolfram Sang break; 45653f8f7c5SWolfram Sang 45753f8f7c5SWolfram Sang i2c_acpi_register_device(adapter, adev, &info); 4586558b646SJamie Iles put_device(&adapter->dev); 45953f8f7c5SWolfram Sang break; 46053f8f7c5SWolfram Sang case ACPI_RECONFIG_DEVICE_REMOVE: 46153f8f7c5SWolfram Sang if (!acpi_device_enumerated(adev)) 46253f8f7c5SWolfram Sang break; 46353f8f7c5SWolfram Sang 46453f8f7c5SWolfram Sang client = i2c_acpi_find_client_by_adev(adev); 46553f8f7c5SWolfram Sang if (!client) 46653f8f7c5SWolfram Sang break; 46753f8f7c5SWolfram Sang 46853f8f7c5SWolfram Sang i2c_unregister_device(client); 46953f8f7c5SWolfram Sang put_device(&client->dev); 47053f8f7c5SWolfram Sang break; 47153f8f7c5SWolfram Sang } 47253f8f7c5SWolfram Sang 47353f8f7c5SWolfram Sang return NOTIFY_OK; 47453f8f7c5SWolfram Sang } 47553f8f7c5SWolfram Sang 47653f8f7c5SWolfram Sang struct notifier_block i2c_acpi_notifier = { 47753f8f7c5SWolfram Sang .notifier_call = i2c_acpi_notify, 47853f8f7c5SWolfram Sang }; 47953f8f7c5SWolfram Sang 48053f8f7c5SWolfram Sang /** 481c537be0bSHans de Goede * i2c_acpi_new_device_by_fwnode - Create i2c-client for the Nth I2cSerialBus resource 482c537be0bSHans de Goede * @fwnode: fwnode with the ACPI resources to get the client from 48353f8f7c5SWolfram Sang * @index: Index of ACPI resource to get 48453f8f7c5SWolfram Sang * @info: describes the I2C device; note this is modified (addr gets set) 48553f8f7c5SWolfram Sang * Context: can sleep 48653f8f7c5SWolfram Sang * 48753f8f7c5SWolfram Sang * By default the i2c subsys creates an i2c-client for the first I2cSerialBus 48853f8f7c5SWolfram Sang * resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus 48953f8f7c5SWolfram Sang * resources, in that case this function can be used to create an i2c-client 49053f8f7c5SWolfram Sang * for other I2cSerialBus resources in the Current Resource Settings table. 49153f8f7c5SWolfram Sang * 49290a3be9bSWolfram Sang * Also see i2c_new_client_device, which this function calls to create the 49390a3be9bSWolfram Sang * i2c-client. 49453f8f7c5SWolfram Sang * 4952dea645fSAndy Shevchenko * Returns a pointer to the new i2c-client, or error pointer in case of failure. 4962dea645fSAndy Shevchenko * Specifically, -EPROBE_DEFER is returned if the adapter is not found. 49753f8f7c5SWolfram Sang */ 498c537be0bSHans de Goede struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode, 499c537be0bSHans de Goede int index, 50053f8f7c5SWolfram Sang struct i2c_board_info *info) 50153f8f7c5SWolfram Sang { 50253f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 50353f8f7c5SWolfram Sang struct i2c_adapter *adapter; 504c537be0bSHans de Goede struct acpi_device *adev; 50553f8f7c5SWolfram Sang LIST_HEAD(resource_list); 50653f8f7c5SWolfram Sang int ret; 50753f8f7c5SWolfram Sang 508c537be0bSHans de Goede adev = to_acpi_device_node(fwnode); 509c537be0bSHans de Goede if (!adev) 510c537be0bSHans de Goede return ERR_PTR(-ENODEV); 511c537be0bSHans de Goede 51253f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 51353f8f7c5SWolfram Sang lookup.info = info; 51453f8f7c5SWolfram Sang lookup.device_handle = acpi_device_handle(adev); 51553f8f7c5SWolfram Sang lookup.index = index; 51653f8f7c5SWolfram Sang 51753f8f7c5SWolfram Sang ret = acpi_dev_get_resources(adev, &resource_list, 51853f8f7c5SWolfram Sang i2c_acpi_fill_info, &lookup); 5192dea645fSAndy Shevchenko if (ret < 0) 5202dea645fSAndy Shevchenko return ERR_PTR(ret); 5212dea645fSAndy Shevchenko 52253f8f7c5SWolfram Sang acpi_dev_free_resource_list(&resource_list); 52353f8f7c5SWolfram Sang 5242dea645fSAndy Shevchenko if (!info->addr) 5252dea645fSAndy Shevchenko return ERR_PTR(-EADDRNOTAVAIL); 52653f8f7c5SWolfram Sang 52753f8f7c5SWolfram Sang adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle); 52853f8f7c5SWolfram Sang if (!adapter) 5292dea645fSAndy Shevchenko return ERR_PTR(-EPROBE_DEFER); 53053f8f7c5SWolfram Sang 53190a3be9bSWolfram Sang return i2c_new_client_device(adapter, info); 53253f8f7c5SWolfram Sang } 533c537be0bSHans de Goede EXPORT_SYMBOL_GPL(i2c_acpi_new_device_by_fwnode); 53453f8f7c5SWolfram Sang 535b18c1ad6SSakari Ailus bool i2c_acpi_waive_d0_probe(struct device *dev) 536b18c1ad6SSakari Ailus { 537b18c1ad6SSakari Ailus struct i2c_driver *driver = to_i2c_driver(dev->driver); 538b18c1ad6SSakari Ailus struct acpi_device *adev = ACPI_COMPANION(dev); 539b18c1ad6SSakari Ailus 540b18c1ad6SSakari Ailus return driver->flags & I2C_DRV_ACPI_WAIVE_D0_PROBE && 541b18c1ad6SSakari Ailus adev && adev->power.state_for_enumeration >= adev->power.state; 542b18c1ad6SSakari Ailus } 543b18c1ad6SSakari Ailus EXPORT_SYMBOL_GPL(i2c_acpi_waive_d0_probe); 544b18c1ad6SSakari Ailus 54553f8f7c5SWolfram Sang #ifdef CONFIG_ACPI_I2C_OPREGION 54653f8f7c5SWolfram Sang static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, 54753f8f7c5SWolfram Sang u8 cmd, u8 *data, u8 data_len) 54853f8f7c5SWolfram Sang { 54953f8f7c5SWolfram Sang 55053f8f7c5SWolfram Sang struct i2c_msg msgs[2]; 55153f8f7c5SWolfram Sang int ret; 55253f8f7c5SWolfram Sang u8 *buffer; 55353f8f7c5SWolfram Sang 55453f8f7c5SWolfram Sang buffer = kzalloc(data_len, GFP_KERNEL); 55553f8f7c5SWolfram Sang if (!buffer) 55653f8f7c5SWolfram Sang return AE_NO_MEMORY; 55753f8f7c5SWolfram Sang 55853f8f7c5SWolfram Sang msgs[0].addr = client->addr; 55953f8f7c5SWolfram Sang msgs[0].flags = client->flags; 56053f8f7c5SWolfram Sang msgs[0].len = 1; 56153f8f7c5SWolfram Sang msgs[0].buf = &cmd; 56253f8f7c5SWolfram Sang 56353f8f7c5SWolfram Sang msgs[1].addr = client->addr; 56453f8f7c5SWolfram Sang msgs[1].flags = client->flags | I2C_M_RD; 56553f8f7c5SWolfram Sang msgs[1].len = data_len; 56653f8f7c5SWolfram Sang msgs[1].buf = buffer; 56753f8f7c5SWolfram Sang 56853f8f7c5SWolfram Sang ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 5697781edaeSHans de Goede if (ret < 0) { 5707781edaeSHans de Goede /* Getting a NACK is unfortunately normal with some DSTDs */ 5717781edaeSHans de Goede if (ret == -EREMOTEIO) 5727781edaeSHans de Goede dev_dbg(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", 573c8016fa2SHans de Goede data_len, client->addr, cmd, ret); 57453f8f7c5SWolfram Sang else 5757781edaeSHans de Goede dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", 5767781edaeSHans de Goede data_len, client->addr, cmd, ret); 5770a30446cSHans de Goede /* 2 transfers must have completed successfully */ 5780a30446cSHans de Goede } else if (ret == 2) { 57953f8f7c5SWolfram Sang memcpy(data, buffer, data_len); 5800a30446cSHans de Goede ret = 0; 5810a30446cSHans de Goede } else { 5820a30446cSHans de Goede ret = -EIO; 5837781edaeSHans de Goede } 58453f8f7c5SWolfram Sang 58553f8f7c5SWolfram Sang kfree(buffer); 58653f8f7c5SWolfram Sang return ret; 58753f8f7c5SWolfram Sang } 58853f8f7c5SWolfram Sang 58953f8f7c5SWolfram Sang static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, 59053f8f7c5SWolfram Sang u8 cmd, u8 *data, u8 data_len) 59153f8f7c5SWolfram Sang { 59253f8f7c5SWolfram Sang 59353f8f7c5SWolfram Sang struct i2c_msg msgs[1]; 59453f8f7c5SWolfram Sang u8 *buffer; 59553f8f7c5SWolfram Sang int ret = AE_OK; 59653f8f7c5SWolfram Sang 59753f8f7c5SWolfram Sang buffer = kzalloc(data_len + 1, GFP_KERNEL); 59853f8f7c5SWolfram Sang if (!buffer) 59953f8f7c5SWolfram Sang return AE_NO_MEMORY; 60053f8f7c5SWolfram Sang 60153f8f7c5SWolfram Sang buffer[0] = cmd; 60253f8f7c5SWolfram Sang memcpy(buffer + 1, data, data_len); 60353f8f7c5SWolfram Sang 60453f8f7c5SWolfram Sang msgs[0].addr = client->addr; 60553f8f7c5SWolfram Sang msgs[0].flags = client->flags; 60653f8f7c5SWolfram Sang msgs[0].len = data_len + 1; 60753f8f7c5SWolfram Sang msgs[0].buf = buffer; 60853f8f7c5SWolfram Sang 60953f8f7c5SWolfram Sang ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 61053f8f7c5SWolfram Sang 61153f8f7c5SWolfram Sang kfree(buffer); 612c463a158SHans de Goede 613c463a158SHans de Goede if (ret < 0) { 614c463a158SHans de Goede dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); 61553f8f7c5SWolfram Sang return ret; 61653f8f7c5SWolfram Sang } 61753f8f7c5SWolfram Sang 618c463a158SHans de Goede /* 1 transfer must have completed successfully */ 619c463a158SHans de Goede return (ret == 1) ? 0 : -EIO; 620c463a158SHans de Goede } 621c463a158SHans de Goede 62253f8f7c5SWolfram Sang static acpi_status 62353f8f7c5SWolfram Sang i2c_acpi_space_handler(u32 function, acpi_physical_address command, 62453f8f7c5SWolfram Sang u32 bits, u64 *value64, 62553f8f7c5SWolfram Sang void *handler_context, void *region_context) 62653f8f7c5SWolfram Sang { 62753f8f7c5SWolfram Sang struct gsb_buffer *gsb = (struct gsb_buffer *)value64; 62853f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data = handler_context; 62953f8f7c5SWolfram Sang struct acpi_connection_info *info = &data->info; 63053f8f7c5SWolfram Sang struct acpi_resource_i2c_serialbus *sb; 63153f8f7c5SWolfram Sang struct i2c_adapter *adapter = data->adapter; 63253f8f7c5SWolfram Sang struct i2c_client *client; 63353f8f7c5SWolfram Sang struct acpi_resource *ares; 63453f8f7c5SWolfram Sang u32 accessor_type = function >> 16; 63553f8f7c5SWolfram Sang u8 action = function & ACPI_IO_MASK; 63653f8f7c5SWolfram Sang acpi_status ret; 63753f8f7c5SWolfram Sang int status; 63853f8f7c5SWolfram Sang 63953f8f7c5SWolfram Sang ret = acpi_buffer_to_resource(info->connection, info->length, &ares); 64053f8f7c5SWolfram Sang if (ACPI_FAILURE(ret)) 64153f8f7c5SWolfram Sang return ret; 64253f8f7c5SWolfram Sang 64353f8f7c5SWolfram Sang client = kzalloc(sizeof(*client), GFP_KERNEL); 64453f8f7c5SWolfram Sang if (!client) { 64553f8f7c5SWolfram Sang ret = AE_NO_MEMORY; 64653f8f7c5SWolfram Sang goto err; 64753f8f7c5SWolfram Sang } 64853f8f7c5SWolfram Sang 6490d5102feSAndy Shevchenko if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) { 65053f8f7c5SWolfram Sang ret = AE_BAD_PARAMETER; 65153f8f7c5SWolfram Sang goto err; 65253f8f7c5SWolfram Sang } 65353f8f7c5SWolfram Sang 65453f8f7c5SWolfram Sang client->adapter = adapter; 65553f8f7c5SWolfram Sang client->addr = sb->slave_address; 65653f8f7c5SWolfram Sang 65753f8f7c5SWolfram Sang if (sb->access_mode == ACPI_I2C_10BIT_MODE) 65853f8f7c5SWolfram Sang client->flags |= I2C_CLIENT_TEN; 65953f8f7c5SWolfram Sang 66053f8f7c5SWolfram Sang switch (accessor_type) { 66153f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: 66253f8f7c5SWolfram Sang if (action == ACPI_READ) { 66353f8f7c5SWolfram Sang status = i2c_smbus_read_byte(client); 66453f8f7c5SWolfram Sang if (status >= 0) { 66553f8f7c5SWolfram Sang gsb->bdata = status; 66653f8f7c5SWolfram Sang status = 0; 66753f8f7c5SWolfram Sang } 66853f8f7c5SWolfram Sang } else { 66953f8f7c5SWolfram Sang status = i2c_smbus_write_byte(client, gsb->bdata); 67053f8f7c5SWolfram Sang } 67153f8f7c5SWolfram Sang break; 67253f8f7c5SWolfram Sang 67353f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_BYTE: 67453f8f7c5SWolfram Sang if (action == ACPI_READ) { 67553f8f7c5SWolfram Sang status = i2c_smbus_read_byte_data(client, command); 67653f8f7c5SWolfram Sang if (status >= 0) { 67753f8f7c5SWolfram Sang gsb->bdata = status; 67853f8f7c5SWolfram Sang status = 0; 67953f8f7c5SWolfram Sang } 68053f8f7c5SWolfram Sang } else { 68153f8f7c5SWolfram Sang status = i2c_smbus_write_byte_data(client, command, 68253f8f7c5SWolfram Sang gsb->bdata); 68353f8f7c5SWolfram Sang } 68453f8f7c5SWolfram Sang break; 68553f8f7c5SWolfram Sang 68653f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_WORD: 68753f8f7c5SWolfram Sang if (action == ACPI_READ) { 68853f8f7c5SWolfram Sang status = i2c_smbus_read_word_data(client, command); 68953f8f7c5SWolfram Sang if (status >= 0) { 69053f8f7c5SWolfram Sang gsb->wdata = status; 69153f8f7c5SWolfram Sang status = 0; 69253f8f7c5SWolfram Sang } 69353f8f7c5SWolfram Sang } else { 69453f8f7c5SWolfram Sang status = i2c_smbus_write_word_data(client, command, 69553f8f7c5SWolfram Sang gsb->wdata); 69653f8f7c5SWolfram Sang } 69753f8f7c5SWolfram Sang break; 69853f8f7c5SWolfram Sang 69953f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_BLOCK: 70053f8f7c5SWolfram Sang if (action == ACPI_READ) { 70153f8f7c5SWolfram Sang status = i2c_smbus_read_block_data(client, command, 70253f8f7c5SWolfram Sang gsb->data); 70353f8f7c5SWolfram Sang if (status >= 0) { 70453f8f7c5SWolfram Sang gsb->len = status; 70553f8f7c5SWolfram Sang status = 0; 70653f8f7c5SWolfram Sang } 70753f8f7c5SWolfram Sang } else { 70853f8f7c5SWolfram Sang status = i2c_smbus_write_block_data(client, command, 70953f8f7c5SWolfram Sang gsb->len, gsb->data); 71053f8f7c5SWolfram Sang } 71153f8f7c5SWolfram Sang break; 71253f8f7c5SWolfram Sang 71353f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: 71453f8f7c5SWolfram Sang if (action == ACPI_READ) { 71553f8f7c5SWolfram Sang status = acpi_gsb_i2c_read_bytes(client, command, 71653f8f7c5SWolfram Sang gsb->data, info->access_length); 71753f8f7c5SWolfram Sang } else { 71853f8f7c5SWolfram Sang status = acpi_gsb_i2c_write_bytes(client, command, 71953f8f7c5SWolfram Sang gsb->data, info->access_length); 72053f8f7c5SWolfram Sang } 72153f8f7c5SWolfram Sang break; 72253f8f7c5SWolfram Sang 72353f8f7c5SWolfram Sang default: 72453f8f7c5SWolfram Sang dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", 72553f8f7c5SWolfram Sang accessor_type, client->addr); 72653f8f7c5SWolfram Sang ret = AE_BAD_PARAMETER; 72753f8f7c5SWolfram Sang goto err; 72853f8f7c5SWolfram Sang } 72953f8f7c5SWolfram Sang 73053f8f7c5SWolfram Sang gsb->status = status; 73153f8f7c5SWolfram Sang 73253f8f7c5SWolfram Sang err: 73353f8f7c5SWolfram Sang kfree(client); 73453f8f7c5SWolfram Sang ACPI_FREE(ares); 73553f8f7c5SWolfram Sang return ret; 73653f8f7c5SWolfram Sang } 73753f8f7c5SWolfram Sang 73853f8f7c5SWolfram Sang 73953f8f7c5SWolfram Sang int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) 74053f8f7c5SWolfram Sang { 74153f8f7c5SWolfram Sang acpi_handle handle; 74253f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data; 74353f8f7c5SWolfram Sang acpi_status status; 74453f8f7c5SWolfram Sang 74553f8f7c5SWolfram Sang if (!adapter->dev.parent) 74653f8f7c5SWolfram Sang return -ENODEV; 74753f8f7c5SWolfram Sang 74853f8f7c5SWolfram Sang handle = ACPI_HANDLE(adapter->dev.parent); 74953f8f7c5SWolfram Sang 75053f8f7c5SWolfram Sang if (!handle) 75153f8f7c5SWolfram Sang return -ENODEV; 75253f8f7c5SWolfram Sang 75353f8f7c5SWolfram Sang data = kzalloc(sizeof(struct i2c_acpi_handler_data), 75453f8f7c5SWolfram Sang GFP_KERNEL); 75553f8f7c5SWolfram Sang if (!data) 75653f8f7c5SWolfram Sang return -ENOMEM; 75753f8f7c5SWolfram Sang 75853f8f7c5SWolfram Sang data->adapter = adapter; 75953f8f7c5SWolfram Sang status = acpi_bus_attach_private_data(handle, (void *)data); 76053f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 76153f8f7c5SWolfram Sang kfree(data); 76253f8f7c5SWolfram Sang return -ENOMEM; 76353f8f7c5SWolfram Sang } 76453f8f7c5SWolfram Sang 76553f8f7c5SWolfram Sang status = acpi_install_address_space_handler(handle, 76653f8f7c5SWolfram Sang ACPI_ADR_SPACE_GSBUS, 76753f8f7c5SWolfram Sang &i2c_acpi_space_handler, 76853f8f7c5SWolfram Sang NULL, 76953f8f7c5SWolfram Sang data); 77053f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 77153f8f7c5SWolfram Sang dev_err(&adapter->dev, "Error installing i2c space handler\n"); 77253f8f7c5SWolfram Sang acpi_bus_detach_private_data(handle); 77353f8f7c5SWolfram Sang kfree(data); 77453f8f7c5SWolfram Sang return -ENOMEM; 77553f8f7c5SWolfram Sang } 77653f8f7c5SWolfram Sang 77753f8f7c5SWolfram Sang return 0; 77853f8f7c5SWolfram Sang } 77953f8f7c5SWolfram Sang 78053f8f7c5SWolfram Sang void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) 78153f8f7c5SWolfram Sang { 78253f8f7c5SWolfram Sang acpi_handle handle; 78353f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data; 78453f8f7c5SWolfram Sang acpi_status status; 78553f8f7c5SWolfram Sang 78653f8f7c5SWolfram Sang if (!adapter->dev.parent) 78753f8f7c5SWolfram Sang return; 78853f8f7c5SWolfram Sang 78953f8f7c5SWolfram Sang handle = ACPI_HANDLE(adapter->dev.parent); 79053f8f7c5SWolfram Sang 79153f8f7c5SWolfram Sang if (!handle) 79253f8f7c5SWolfram Sang return; 79353f8f7c5SWolfram Sang 79453f8f7c5SWolfram Sang acpi_remove_address_space_handler(handle, 79553f8f7c5SWolfram Sang ACPI_ADR_SPACE_GSBUS, 79653f8f7c5SWolfram Sang &i2c_acpi_space_handler); 79753f8f7c5SWolfram Sang 79853f8f7c5SWolfram Sang status = acpi_bus_get_private_data(handle, (void **)&data); 79953f8f7c5SWolfram Sang if (ACPI_SUCCESS(status)) 80053f8f7c5SWolfram Sang kfree(data); 80153f8f7c5SWolfram Sang 80253f8f7c5SWolfram Sang acpi_bus_detach_private_data(handle); 80353f8f7c5SWolfram Sang } 80453f8f7c5SWolfram Sang #endif /* CONFIG_ACPI_I2C_OPREGION */ 805