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; 29492baeb9SGustavo A. R. Silva DECLARE_FLEX_ARRAY(u8, data); 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 140b38f2d5dSRaul E Rangel struct i2c_acpi_irq_context { 141b38f2d5dSRaul E Rangel int irq; 142b38f2d5dSRaul E Rangel bool wake_capable; 143b38f2d5dSRaul E Rangel }; 144b38f2d5dSRaul E Rangel 14553f8f7c5SWolfram Sang static int i2c_acpi_do_lookup(struct acpi_device *adev, 14653f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup) 14753f8f7c5SWolfram Sang { 14853f8f7c5SWolfram Sang struct i2c_board_info *info = lookup->info; 14953f8f7c5SWolfram Sang struct list_head resource_list; 15053f8f7c5SWolfram Sang int ret; 15153f8f7c5SWolfram Sang 152fb90e58fSHans de Goede if (acpi_bus_get_status(adev)) 15353f8f7c5SWolfram Sang return -EINVAL; 15453f8f7c5SWolfram Sang 155fb90e58fSHans de Goede if (!acpi_dev_ready_for_enumeration(adev)) 156fb90e58fSHans de Goede return -ENODEV; 157fb90e58fSHans de Goede 1583a4991a9SHans de Goede if (acpi_match_device_ids(adev, i2c_acpi_ignored_device_ids) == 0) 1593a4991a9SHans de Goede return -ENODEV; 1603a4991a9SHans de Goede 16153f8f7c5SWolfram Sang memset(info, 0, sizeof(*info)); 16253f8f7c5SWolfram Sang lookup->device_handle = acpi_device_handle(adev); 16353f8f7c5SWolfram Sang 16453f8f7c5SWolfram Sang /* Look up for I2cSerialBus resource */ 16553f8f7c5SWolfram Sang INIT_LIST_HEAD(&resource_list); 16653f8f7c5SWolfram Sang ret = acpi_dev_get_resources(adev, &resource_list, 16753f8f7c5SWolfram Sang i2c_acpi_fill_info, lookup); 16853f8f7c5SWolfram Sang acpi_dev_free_resource_list(&resource_list); 16953f8f7c5SWolfram Sang 17053f8f7c5SWolfram Sang if (ret < 0 || !info->addr) 17153f8f7c5SWolfram Sang return -EINVAL; 17253f8f7c5SWolfram Sang 17353f8f7c5SWolfram Sang return 0; 17453f8f7c5SWolfram Sang } 17553f8f7c5SWolfram Sang 176b38f2d5dSRaul E Rangel static int i2c_acpi_add_irq_resource(struct acpi_resource *ares, void *data) 177c2223ddcSCharles Keepax { 178b38f2d5dSRaul E Rangel struct i2c_acpi_irq_context *irq_ctx = data; 179c2223ddcSCharles Keepax struct resource r; 180c2223ddcSCharles Keepax 181b38f2d5dSRaul E Rangel if (irq_ctx->irq > 0) 182b38f2d5dSRaul E Rangel return 1; 183b38f2d5dSRaul E Rangel 184b38f2d5dSRaul E Rangel if (!acpi_dev_resource_interrupt(ares, 0, &r)) 185b38f2d5dSRaul E Rangel return 1; 186b38f2d5dSRaul E Rangel 187b38f2d5dSRaul E Rangel irq_ctx->irq = i2c_dev_irq_from_resources(&r, 1); 188b38f2d5dSRaul E Rangel irq_ctx->wake_capable = r.flags & IORESOURCE_IRQ_WAKECAPABLE; 189c2223ddcSCharles Keepax 190c2223ddcSCharles Keepax return 1; /* No need to add resource to the list */ 191c2223ddcSCharles Keepax } 192c2223ddcSCharles Keepax 19316c9db1dSCharles Keepax /** 19416c9db1dSCharles Keepax * i2c_acpi_get_irq - get device IRQ number from ACPI 19516c9db1dSCharles Keepax * @client: Pointer to the I2C client device 196b38f2d5dSRaul E Rangel * @wake_capable: Set to true if the IRQ is wake capable 19716c9db1dSCharles Keepax * 19816c9db1dSCharles Keepax * Find the IRQ number used by a specific client device. 19916c9db1dSCharles Keepax * 20016c9db1dSCharles Keepax * Return: The IRQ number or an error code. 20116c9db1dSCharles Keepax */ 202b38f2d5dSRaul E Rangel int i2c_acpi_get_irq(struct i2c_client *client, bool *wake_capable) 203a52e3b37SCharles Keepax { 20416c9db1dSCharles Keepax struct acpi_device *adev = ACPI_COMPANION(&client->dev); 205a52e3b37SCharles Keepax struct list_head resource_list; 206b38f2d5dSRaul E Rangel struct i2c_acpi_irq_context irq_ctx = { 207b38f2d5dSRaul E Rangel .irq = -ENOENT, 208b38f2d5dSRaul E Rangel }; 209a52e3b37SCharles Keepax int ret; 210a52e3b37SCharles Keepax 211a52e3b37SCharles Keepax INIT_LIST_HEAD(&resource_list); 212a52e3b37SCharles Keepax 213a52e3b37SCharles Keepax ret = acpi_dev_get_resources(adev, &resource_list, 214b38f2d5dSRaul E Rangel i2c_acpi_add_irq_resource, &irq_ctx); 215a52e3b37SCharles Keepax if (ret < 0) 216a52e3b37SCharles Keepax return ret; 217a52e3b37SCharles Keepax 218a52e3b37SCharles Keepax acpi_dev_free_resource_list(&resource_list); 219a52e3b37SCharles Keepax 220b38f2d5dSRaul E Rangel if (irq_ctx.irq == -ENOENT) 221b38f2d5dSRaul E Rangel irq_ctx.irq = acpi_dev_gpio_irq_wake_get(adev, 0, &irq_ctx.wake_capable); 2228466b616SCharles Keepax 223b38f2d5dSRaul E Rangel if (irq_ctx.irq < 0) 224b38f2d5dSRaul E Rangel return irq_ctx.irq; 225b38f2d5dSRaul E Rangel 226b38f2d5dSRaul E Rangel if (wake_capable) 227b38f2d5dSRaul E Rangel *wake_capable = irq_ctx.wake_capable; 228b38f2d5dSRaul E Rangel 229b38f2d5dSRaul E Rangel return irq_ctx.irq; 230a52e3b37SCharles Keepax } 231a52e3b37SCharles Keepax 23253f8f7c5SWolfram Sang static int i2c_acpi_get_info(struct acpi_device *adev, 23353f8f7c5SWolfram Sang struct i2c_board_info *info, 23453f8f7c5SWolfram Sang struct i2c_adapter *adapter, 23553f8f7c5SWolfram Sang acpi_handle *adapter_handle) 23653f8f7c5SWolfram Sang { 23753f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 23853f8f7c5SWolfram Sang int ret; 23953f8f7c5SWolfram Sang 24053f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 24153f8f7c5SWolfram Sang lookup.info = info; 24253f8f7c5SWolfram Sang lookup.index = -1; 24353f8f7c5SWolfram Sang 2444befedc0SArd Biesheuvel if (acpi_device_enumerated(adev)) 2454befedc0SArd Biesheuvel return -EINVAL; 2464befedc0SArd Biesheuvel 24753f8f7c5SWolfram Sang ret = i2c_acpi_do_lookup(adev, &lookup); 24853f8f7c5SWolfram Sang if (ret) 24953f8f7c5SWolfram Sang return ret; 25053f8f7c5SWolfram Sang 25153f8f7c5SWolfram Sang if (adapter) { 25253f8f7c5SWolfram Sang /* The adapter must match the one in I2cSerialBus() connector */ 25353f8f7c5SWolfram Sang if (ACPI_HANDLE(&adapter->dev) != lookup.adapter_handle) 25453f8f7c5SWolfram Sang return -ENODEV; 25553f8f7c5SWolfram Sang } else { 25653f8f7c5SWolfram Sang struct acpi_device *adapter_adev; 25753f8f7c5SWolfram Sang 25853f8f7c5SWolfram Sang /* The adapter must be present */ 2590bc4978aSRafael J. Wysocki adapter_adev = acpi_fetch_acpi_dev(lookup.adapter_handle); 2600bc4978aSRafael J. Wysocki if (!adapter_adev) 26153f8f7c5SWolfram Sang return -ENODEV; 26253f8f7c5SWolfram Sang if (acpi_bus_get_status(adapter_adev) || 26353f8f7c5SWolfram Sang !adapter_adev->status.present) 26453f8f7c5SWolfram Sang return -ENODEV; 26553f8f7c5SWolfram Sang } 26653f8f7c5SWolfram Sang 26753f8f7c5SWolfram Sang info->fwnode = acpi_fwnode_handle(adev); 26853f8f7c5SWolfram Sang if (adapter_handle) 26953f8f7c5SWolfram Sang *adapter_handle = lookup.adapter_handle; 27053f8f7c5SWolfram Sang 27153f8f7c5SWolfram Sang acpi_set_modalias(adev, dev_name(&adev->dev), info->type, 27253f8f7c5SWolfram Sang sizeof(info->type)); 27353f8f7c5SWolfram Sang 27453f8f7c5SWolfram Sang return 0; 27553f8f7c5SWolfram Sang } 27653f8f7c5SWolfram Sang 27753f8f7c5SWolfram Sang static void i2c_acpi_register_device(struct i2c_adapter *adapter, 27853f8f7c5SWolfram Sang struct acpi_device *adev, 27953f8f7c5SWolfram Sang struct i2c_board_info *info) 28053f8f7c5SWolfram Sang { 281a6e1445cSHans de Goede /* 282a6e1445cSHans de Goede * Skip registration on boards where the ACPI tables are 283a6e1445cSHans de Goede * known to contain bogus I2C devices. 284a6e1445cSHans de Goede */ 285a6e1445cSHans de Goede if (acpi_quirk_skip_i2c_client_enumeration(adev)) 286a6e1445cSHans de Goede return; 287a6e1445cSHans de Goede 28853f8f7c5SWolfram Sang adev->power.flags.ignore_parent = true; 28953f8f7c5SWolfram Sang acpi_device_set_enumerated(adev); 29053f8f7c5SWolfram Sang 291785e21cfSHans de Goede if (IS_ERR(i2c_new_client_device(adapter, info))) 29253f8f7c5SWolfram Sang adev->power.flags.ignore_parent = false; 29353f8f7c5SWolfram Sang } 29453f8f7c5SWolfram Sang 29553f8f7c5SWolfram Sang static acpi_status i2c_acpi_add_device(acpi_handle handle, u32 level, 29653f8f7c5SWolfram Sang void *data, void **return_value) 29753f8f7c5SWolfram Sang { 29853f8f7c5SWolfram Sang struct i2c_adapter *adapter = data; 2990bc4978aSRafael J. Wysocki struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 30053f8f7c5SWolfram Sang struct i2c_board_info info; 30153f8f7c5SWolfram Sang 3020bc4978aSRafael J. Wysocki if (!adev || i2c_acpi_get_info(adev, &info, adapter, NULL)) 30353f8f7c5SWolfram Sang return AE_OK; 30453f8f7c5SWolfram Sang 30553f8f7c5SWolfram Sang i2c_acpi_register_device(adapter, adev, &info); 30653f8f7c5SWolfram Sang 30753f8f7c5SWolfram Sang return AE_OK; 30853f8f7c5SWolfram Sang } 30953f8f7c5SWolfram Sang 31053f8f7c5SWolfram Sang #define I2C_ACPI_MAX_SCAN_DEPTH 32 31153f8f7c5SWolfram Sang 31253f8f7c5SWolfram Sang /** 31353f8f7c5SWolfram Sang * i2c_acpi_register_devices - enumerate I2C slave devices behind adapter 31453f8f7c5SWolfram Sang * @adap: pointer to adapter 31553f8f7c5SWolfram Sang * 31653f8f7c5SWolfram Sang * Enumerate all I2C slave devices behind this adapter by walking the ACPI 31753f8f7c5SWolfram Sang * namespace. When a device is found it will be added to the Linux device 31853f8f7c5SWolfram Sang * model and bound to the corresponding ACPI handle. 31953f8f7c5SWolfram Sang */ 32053f8f7c5SWolfram Sang void i2c_acpi_register_devices(struct i2c_adapter *adap) 32153f8f7c5SWolfram Sang { 322a9e10e58SDaniel Scally struct acpi_device *adev; 32353f8f7c5SWolfram Sang acpi_status status; 32453f8f7c5SWolfram Sang 32553f8f7c5SWolfram Sang if (!has_acpi_companion(&adap->dev)) 32653f8f7c5SWolfram Sang return; 32753f8f7c5SWolfram Sang 32853f8f7c5SWolfram Sang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 32953f8f7c5SWolfram Sang I2C_ACPI_MAX_SCAN_DEPTH, 33053f8f7c5SWolfram Sang i2c_acpi_add_device, NULL, 33153f8f7c5SWolfram Sang adap, NULL); 33253f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) 33353f8f7c5SWolfram Sang dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); 3348058d699SHans de Goede 3358058d699SHans de Goede if (!adap->dev.parent) 3368058d699SHans de Goede return; 3378058d699SHans de Goede 338a9e10e58SDaniel Scally adev = ACPI_COMPANION(adap->dev.parent); 339a9e10e58SDaniel Scally if (!adev) 3408058d699SHans de Goede return; 3418058d699SHans de Goede 342a9e10e58SDaniel Scally acpi_dev_clear_dependencies(adev); 34353f8f7c5SWolfram Sang } 34453f8f7c5SWolfram Sang 3457574c0dbSHans de Goede static const struct acpi_device_id i2c_acpi_force_400khz_device_ids[] = { 3467574c0dbSHans de Goede /* 3477574c0dbSHans de Goede * These Silead touchscreen controllers only work at 400KHz, for 3487574c0dbSHans de Goede * some reason they do not work at 100KHz. On some devices the ACPI 3497574c0dbSHans de Goede * tables list another device at their bus as only being capable 3507574c0dbSHans de Goede * of 100KHz, testing has shown that these other devices work fine 3517574c0dbSHans de Goede * at 400KHz (as can be expected of any recent i2c hw) so we force 3527574c0dbSHans de Goede * the speed of the bus to 400 KHz if a Silead device is present. 3537574c0dbSHans de Goede */ 3547574c0dbSHans de Goede { "MSSL1680", 0 }, 3557574c0dbSHans de Goede {} 3567574c0dbSHans de Goede }; 3577574c0dbSHans de Goede 35853f8f7c5SWolfram Sang static acpi_status i2c_acpi_lookup_speed(acpi_handle handle, u32 level, 35953f8f7c5SWolfram Sang void *data, void **return_value) 36053f8f7c5SWolfram Sang { 36153f8f7c5SWolfram Sang struct i2c_acpi_lookup *lookup = data; 3620bc4978aSRafael J. Wysocki struct acpi_device *adev = acpi_fetch_acpi_dev(handle); 36353f8f7c5SWolfram Sang 3640bc4978aSRafael J. Wysocki if (!adev || i2c_acpi_do_lookup(adev, lookup)) 36553f8f7c5SWolfram Sang return AE_OK; 36653f8f7c5SWolfram Sang 36753f8f7c5SWolfram Sang if (lookup->search_handle != lookup->adapter_handle) 36853f8f7c5SWolfram Sang return AE_OK; 36953f8f7c5SWolfram Sang 37053f8f7c5SWolfram Sang if (lookup->speed <= lookup->min_speed) 37153f8f7c5SWolfram Sang lookup->min_speed = lookup->speed; 37253f8f7c5SWolfram Sang 3737574c0dbSHans de Goede if (acpi_match_device_ids(adev, i2c_acpi_force_400khz_device_ids) == 0) 374e6282fc6SAndy Shevchenko lookup->force_speed = I2C_MAX_FAST_MODE_FREQ; 3757574c0dbSHans de Goede 37653f8f7c5SWolfram Sang return AE_OK; 37753f8f7c5SWolfram Sang } 37853f8f7c5SWolfram Sang 37953f8f7c5SWolfram Sang /** 38053f8f7c5SWolfram Sang * i2c_acpi_find_bus_speed - find I2C bus speed from ACPI 38153f8f7c5SWolfram Sang * @dev: The device owning the bus 38253f8f7c5SWolfram Sang * 38353f8f7c5SWolfram Sang * Find the I2C bus speed by walking the ACPI namespace for all I2C slaves 38453f8f7c5SWolfram Sang * devices connected to this bus and use the speed of slowest device. 38553f8f7c5SWolfram Sang * 38653f8f7c5SWolfram Sang * Returns the speed in Hz or zero 38753f8f7c5SWolfram Sang */ 38853f8f7c5SWolfram Sang u32 i2c_acpi_find_bus_speed(struct device *dev) 38953f8f7c5SWolfram Sang { 39053f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 39153f8f7c5SWolfram Sang struct i2c_board_info dummy; 39253f8f7c5SWolfram Sang acpi_status status; 39353f8f7c5SWolfram Sang 39453f8f7c5SWolfram Sang if (!has_acpi_companion(dev)) 39553f8f7c5SWolfram Sang return 0; 39653f8f7c5SWolfram Sang 39753f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 39853f8f7c5SWolfram Sang lookup.search_handle = ACPI_HANDLE(dev); 39953f8f7c5SWolfram Sang lookup.min_speed = UINT_MAX; 40053f8f7c5SWolfram Sang lookup.info = &dummy; 40153f8f7c5SWolfram Sang lookup.index = -1; 40253f8f7c5SWolfram Sang 40353f8f7c5SWolfram Sang status = acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, 40453f8f7c5SWolfram Sang I2C_ACPI_MAX_SCAN_DEPTH, 40553f8f7c5SWolfram Sang i2c_acpi_lookup_speed, NULL, 40653f8f7c5SWolfram Sang &lookup, NULL); 40753f8f7c5SWolfram Sang 40853f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 40953f8f7c5SWolfram Sang dev_warn(dev, "unable to find I2C bus speed from ACPI\n"); 41053f8f7c5SWolfram Sang return 0; 41153f8f7c5SWolfram Sang } 41253f8f7c5SWolfram Sang 4137574c0dbSHans de Goede if (lookup.force_speed) { 4147574c0dbSHans de Goede if (lookup.force_speed != lookup.min_speed) 4157574c0dbSHans de Goede dev_warn(dev, FW_BUG "DSDT uses known not-working I2C bus speed %d, forcing it to %d\n", 4167574c0dbSHans de Goede lookup.min_speed, lookup.force_speed); 4177574c0dbSHans de Goede return lookup.force_speed; 4187574c0dbSHans de Goede } else if (lookup.min_speed != UINT_MAX) { 4197574c0dbSHans de Goede return lookup.min_speed; 4207574c0dbSHans de Goede } else { 4217574c0dbSHans de Goede return 0; 4227574c0dbSHans de Goede } 42353f8f7c5SWolfram Sang } 42453f8f7c5SWolfram Sang EXPORT_SYMBOL_GPL(i2c_acpi_find_bus_speed); 42553f8f7c5SWolfram Sang 4261e91a2e5SRuslan Babayev struct i2c_adapter *i2c_acpi_find_adapter_by_handle(acpi_handle handle) 42753f8f7c5SWolfram Sang { 4280a2d47aaSAndy Shevchenko struct i2c_adapter *adapter; 429644bf600SSuzuki K Poulose struct device *dev; 430644bf600SSuzuki K Poulose 4310a2d47aaSAndy Shevchenko dev = bus_find_device(&i2c_bus_type, NULL, handle, device_match_acpi_handle); 4320a2d47aaSAndy Shevchenko if (!dev) 4330a2d47aaSAndy Shevchenko return NULL; 43453f8f7c5SWolfram Sang 4350a2d47aaSAndy Shevchenko adapter = i2c_verify_adapter(dev); 4360a2d47aaSAndy Shevchenko if (!adapter) 4370a2d47aaSAndy Shevchenko put_device(dev); 4380a2d47aaSAndy Shevchenko 4390a2d47aaSAndy Shevchenko return adapter; 44053f8f7c5SWolfram Sang } 4411e91a2e5SRuslan Babayev EXPORT_SYMBOL_GPL(i2c_acpi_find_adapter_by_handle); 44253f8f7c5SWolfram Sang 44353f8f7c5SWolfram Sang static struct i2c_client *i2c_acpi_find_client_by_adev(struct acpi_device *adev) 44453f8f7c5SWolfram Sang { 445373c612dSRussell King (Oracle) return i2c_find_device_by_fwnode(acpi_fwnode_handle(adev)); 44653f8f7c5SWolfram Sang } 44753f8f7c5SWolfram Sang 448*3f858bbfSHamish Martin static struct i2c_adapter *i2c_acpi_find_adapter_by_adev(struct acpi_device *adev) 449*3f858bbfSHamish Martin { 450*3f858bbfSHamish Martin return i2c_find_adapter_by_fwnode(acpi_fwnode_handle(adev)); 451*3f858bbfSHamish Martin } 452*3f858bbfSHamish Martin 45353f8f7c5SWolfram Sang static int i2c_acpi_notify(struct notifier_block *nb, unsigned long value, 45453f8f7c5SWolfram Sang void *arg) 45553f8f7c5SWolfram Sang { 45653f8f7c5SWolfram Sang struct acpi_device *adev = arg; 45753f8f7c5SWolfram Sang struct i2c_board_info info; 45853f8f7c5SWolfram Sang acpi_handle adapter_handle; 45953f8f7c5SWolfram Sang struct i2c_adapter *adapter; 46053f8f7c5SWolfram Sang struct i2c_client *client; 46153f8f7c5SWolfram Sang 46253f8f7c5SWolfram Sang switch (value) { 46353f8f7c5SWolfram Sang case ACPI_RECONFIG_DEVICE_ADD: 46453f8f7c5SWolfram Sang if (i2c_acpi_get_info(adev, &info, NULL, &adapter_handle)) 46553f8f7c5SWolfram Sang break; 46653f8f7c5SWolfram Sang 46753f8f7c5SWolfram Sang adapter = i2c_acpi_find_adapter_by_handle(adapter_handle); 46853f8f7c5SWolfram Sang if (!adapter) 46953f8f7c5SWolfram Sang break; 47053f8f7c5SWolfram Sang 47153f8f7c5SWolfram Sang i2c_acpi_register_device(adapter, adev, &info); 4726558b646SJamie Iles put_device(&adapter->dev); 47353f8f7c5SWolfram Sang break; 47453f8f7c5SWolfram Sang case ACPI_RECONFIG_DEVICE_REMOVE: 47553f8f7c5SWolfram Sang if (!acpi_device_enumerated(adev)) 47653f8f7c5SWolfram Sang break; 47753f8f7c5SWolfram Sang 47853f8f7c5SWolfram Sang client = i2c_acpi_find_client_by_adev(adev); 479*3f858bbfSHamish Martin if (client) { 48053f8f7c5SWolfram Sang i2c_unregister_device(client); 48153f8f7c5SWolfram Sang put_device(&client->dev); 482*3f858bbfSHamish Martin } 483*3f858bbfSHamish Martin 484*3f858bbfSHamish Martin adapter = i2c_acpi_find_adapter_by_adev(adev); 485*3f858bbfSHamish Martin if (adapter) { 486*3f858bbfSHamish Martin acpi_unbind_one(&adapter->dev); 487*3f858bbfSHamish Martin put_device(&adapter->dev); 488*3f858bbfSHamish Martin } 489*3f858bbfSHamish Martin 49053f8f7c5SWolfram Sang break; 49153f8f7c5SWolfram Sang } 49253f8f7c5SWolfram Sang 49353f8f7c5SWolfram Sang return NOTIFY_OK; 49453f8f7c5SWolfram Sang } 49553f8f7c5SWolfram Sang 49653f8f7c5SWolfram Sang struct notifier_block i2c_acpi_notifier = { 49753f8f7c5SWolfram Sang .notifier_call = i2c_acpi_notify, 49853f8f7c5SWolfram Sang }; 49953f8f7c5SWolfram Sang 50053f8f7c5SWolfram Sang /** 501c537be0bSHans de Goede * i2c_acpi_new_device_by_fwnode - Create i2c-client for the Nth I2cSerialBus resource 502c537be0bSHans de Goede * @fwnode: fwnode with the ACPI resources to get the client from 50353f8f7c5SWolfram Sang * @index: Index of ACPI resource to get 50453f8f7c5SWolfram Sang * @info: describes the I2C device; note this is modified (addr gets set) 50553f8f7c5SWolfram Sang * Context: can sleep 50653f8f7c5SWolfram Sang * 50753f8f7c5SWolfram Sang * By default the i2c subsys creates an i2c-client for the first I2cSerialBus 50853f8f7c5SWolfram Sang * resource of an acpi_device, but some acpi_devices have multiple I2cSerialBus 50953f8f7c5SWolfram Sang * resources, in that case this function can be used to create an i2c-client 51053f8f7c5SWolfram Sang * for other I2cSerialBus resources in the Current Resource Settings table. 51153f8f7c5SWolfram Sang * 51290a3be9bSWolfram Sang * Also see i2c_new_client_device, which this function calls to create the 51390a3be9bSWolfram Sang * i2c-client. 51453f8f7c5SWolfram Sang * 5152dea645fSAndy Shevchenko * Returns a pointer to the new i2c-client, or error pointer in case of failure. 5162dea645fSAndy Shevchenko * Specifically, -EPROBE_DEFER is returned if the adapter is not found. 51753f8f7c5SWolfram Sang */ 518c537be0bSHans de Goede struct i2c_client *i2c_acpi_new_device_by_fwnode(struct fwnode_handle *fwnode, 519c537be0bSHans de Goede int index, 52053f8f7c5SWolfram Sang struct i2c_board_info *info) 52153f8f7c5SWolfram Sang { 52253f8f7c5SWolfram Sang struct i2c_acpi_lookup lookup; 52353f8f7c5SWolfram Sang struct i2c_adapter *adapter; 524c537be0bSHans de Goede struct acpi_device *adev; 52553f8f7c5SWolfram Sang LIST_HEAD(resource_list); 52653f8f7c5SWolfram Sang int ret; 52753f8f7c5SWolfram Sang 528c537be0bSHans de Goede adev = to_acpi_device_node(fwnode); 529c537be0bSHans de Goede if (!adev) 530c537be0bSHans de Goede return ERR_PTR(-ENODEV); 531c537be0bSHans de Goede 53253f8f7c5SWolfram Sang memset(&lookup, 0, sizeof(lookup)); 53353f8f7c5SWolfram Sang lookup.info = info; 53453f8f7c5SWolfram Sang lookup.device_handle = acpi_device_handle(adev); 53553f8f7c5SWolfram Sang lookup.index = index; 53653f8f7c5SWolfram Sang 53753f8f7c5SWolfram Sang ret = acpi_dev_get_resources(adev, &resource_list, 53853f8f7c5SWolfram Sang i2c_acpi_fill_info, &lookup); 5392dea645fSAndy Shevchenko if (ret < 0) 5402dea645fSAndy Shevchenko return ERR_PTR(ret); 5412dea645fSAndy Shevchenko 54253f8f7c5SWolfram Sang acpi_dev_free_resource_list(&resource_list); 54353f8f7c5SWolfram Sang 5442dea645fSAndy Shevchenko if (!info->addr) 5452dea645fSAndy Shevchenko return ERR_PTR(-EADDRNOTAVAIL); 54653f8f7c5SWolfram Sang 54753f8f7c5SWolfram Sang adapter = i2c_acpi_find_adapter_by_handle(lookup.adapter_handle); 54853f8f7c5SWolfram Sang if (!adapter) 5492dea645fSAndy Shevchenko return ERR_PTR(-EPROBE_DEFER); 55053f8f7c5SWolfram Sang 55190a3be9bSWolfram Sang return i2c_new_client_device(adapter, info); 55253f8f7c5SWolfram Sang } 553c537be0bSHans de Goede EXPORT_SYMBOL_GPL(i2c_acpi_new_device_by_fwnode); 55453f8f7c5SWolfram Sang 555b18c1ad6SSakari Ailus bool i2c_acpi_waive_d0_probe(struct device *dev) 556b18c1ad6SSakari Ailus { 557b18c1ad6SSakari Ailus struct i2c_driver *driver = to_i2c_driver(dev->driver); 558b18c1ad6SSakari Ailus struct acpi_device *adev = ACPI_COMPANION(dev); 559b18c1ad6SSakari Ailus 560b18c1ad6SSakari Ailus return driver->flags & I2C_DRV_ACPI_WAIVE_D0_PROBE && 561b18c1ad6SSakari Ailus adev && adev->power.state_for_enumeration >= adev->power.state; 562b18c1ad6SSakari Ailus } 563b18c1ad6SSakari Ailus EXPORT_SYMBOL_GPL(i2c_acpi_waive_d0_probe); 564b18c1ad6SSakari Ailus 56553f8f7c5SWolfram Sang #ifdef CONFIG_ACPI_I2C_OPREGION 56653f8f7c5SWolfram Sang static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, 56753f8f7c5SWolfram Sang u8 cmd, u8 *data, u8 data_len) 56853f8f7c5SWolfram Sang { 56953f8f7c5SWolfram Sang 57053f8f7c5SWolfram Sang struct i2c_msg msgs[2]; 57153f8f7c5SWolfram Sang int ret; 57253f8f7c5SWolfram Sang u8 *buffer; 57353f8f7c5SWolfram Sang 57453f8f7c5SWolfram Sang buffer = kzalloc(data_len, GFP_KERNEL); 57553f8f7c5SWolfram Sang if (!buffer) 57653f8f7c5SWolfram Sang return AE_NO_MEMORY; 57753f8f7c5SWolfram Sang 57853f8f7c5SWolfram Sang msgs[0].addr = client->addr; 57953f8f7c5SWolfram Sang msgs[0].flags = client->flags; 58053f8f7c5SWolfram Sang msgs[0].len = 1; 58153f8f7c5SWolfram Sang msgs[0].buf = &cmd; 58253f8f7c5SWolfram Sang 58353f8f7c5SWolfram Sang msgs[1].addr = client->addr; 58453f8f7c5SWolfram Sang msgs[1].flags = client->flags | I2C_M_RD; 58553f8f7c5SWolfram Sang msgs[1].len = data_len; 58653f8f7c5SWolfram Sang msgs[1].buf = buffer; 58753f8f7c5SWolfram Sang 58853f8f7c5SWolfram Sang ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 5897781edaeSHans de Goede if (ret < 0) { 5907781edaeSHans de Goede /* Getting a NACK is unfortunately normal with some DSTDs */ 5917781edaeSHans de Goede if (ret == -EREMOTEIO) 5927781edaeSHans de Goede dev_dbg(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", 593c8016fa2SHans de Goede data_len, client->addr, cmd, ret); 59453f8f7c5SWolfram Sang else 5957781edaeSHans de Goede dev_err(&client->adapter->dev, "i2c read %d bytes from client@%#x starting at reg %#x failed, error: %d\n", 5967781edaeSHans de Goede data_len, client->addr, cmd, ret); 5970a30446cSHans de Goede /* 2 transfers must have completed successfully */ 5980a30446cSHans de Goede } else if (ret == 2) { 59953f8f7c5SWolfram Sang memcpy(data, buffer, data_len); 6000a30446cSHans de Goede ret = 0; 6010a30446cSHans de Goede } else { 6020a30446cSHans de Goede ret = -EIO; 6037781edaeSHans de Goede } 60453f8f7c5SWolfram Sang 60553f8f7c5SWolfram Sang kfree(buffer); 60653f8f7c5SWolfram Sang return ret; 60753f8f7c5SWolfram Sang } 60853f8f7c5SWolfram Sang 60953f8f7c5SWolfram Sang static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, 61053f8f7c5SWolfram Sang u8 cmd, u8 *data, u8 data_len) 61153f8f7c5SWolfram Sang { 61253f8f7c5SWolfram Sang 61353f8f7c5SWolfram Sang struct i2c_msg msgs[1]; 61453f8f7c5SWolfram Sang u8 *buffer; 61553f8f7c5SWolfram Sang int ret = AE_OK; 61653f8f7c5SWolfram Sang 61753f8f7c5SWolfram Sang buffer = kzalloc(data_len + 1, GFP_KERNEL); 61853f8f7c5SWolfram Sang if (!buffer) 61953f8f7c5SWolfram Sang return AE_NO_MEMORY; 62053f8f7c5SWolfram Sang 62153f8f7c5SWolfram Sang buffer[0] = cmd; 62253f8f7c5SWolfram Sang memcpy(buffer + 1, data, data_len); 62353f8f7c5SWolfram Sang 62453f8f7c5SWolfram Sang msgs[0].addr = client->addr; 62553f8f7c5SWolfram Sang msgs[0].flags = client->flags; 62653f8f7c5SWolfram Sang msgs[0].len = data_len + 1; 62753f8f7c5SWolfram Sang msgs[0].buf = buffer; 62853f8f7c5SWolfram Sang 62953f8f7c5SWolfram Sang ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); 63053f8f7c5SWolfram Sang 63153f8f7c5SWolfram Sang kfree(buffer); 632c463a158SHans de Goede 633c463a158SHans de Goede if (ret < 0) { 634c463a158SHans de Goede dev_err(&client->adapter->dev, "i2c write failed: %d\n", ret); 63553f8f7c5SWolfram Sang return ret; 63653f8f7c5SWolfram Sang } 63753f8f7c5SWolfram Sang 638c463a158SHans de Goede /* 1 transfer must have completed successfully */ 639c463a158SHans de Goede return (ret == 1) ? 0 : -EIO; 640c463a158SHans de Goede } 641c463a158SHans de Goede 64253f8f7c5SWolfram Sang static acpi_status 64353f8f7c5SWolfram Sang i2c_acpi_space_handler(u32 function, acpi_physical_address command, 64453f8f7c5SWolfram Sang u32 bits, u64 *value64, 64553f8f7c5SWolfram Sang void *handler_context, void *region_context) 64653f8f7c5SWolfram Sang { 64753f8f7c5SWolfram Sang struct gsb_buffer *gsb = (struct gsb_buffer *)value64; 64853f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data = handler_context; 64953f8f7c5SWolfram Sang struct acpi_connection_info *info = &data->info; 65053f8f7c5SWolfram Sang struct acpi_resource_i2c_serialbus *sb; 65153f8f7c5SWolfram Sang struct i2c_adapter *adapter = data->adapter; 65253f8f7c5SWolfram Sang struct i2c_client *client; 65353f8f7c5SWolfram Sang struct acpi_resource *ares; 65453f8f7c5SWolfram Sang u32 accessor_type = function >> 16; 65553f8f7c5SWolfram Sang u8 action = function & ACPI_IO_MASK; 65653f8f7c5SWolfram Sang acpi_status ret; 65753f8f7c5SWolfram Sang int status; 65853f8f7c5SWolfram Sang 65953f8f7c5SWolfram Sang ret = acpi_buffer_to_resource(info->connection, info->length, &ares); 66053f8f7c5SWolfram Sang if (ACPI_FAILURE(ret)) 66153f8f7c5SWolfram Sang return ret; 66253f8f7c5SWolfram Sang 66353f8f7c5SWolfram Sang client = kzalloc(sizeof(*client), GFP_KERNEL); 66453f8f7c5SWolfram Sang if (!client) { 66553f8f7c5SWolfram Sang ret = AE_NO_MEMORY; 66653f8f7c5SWolfram Sang goto err; 66753f8f7c5SWolfram Sang } 66853f8f7c5SWolfram Sang 6690d5102feSAndy Shevchenko if (!value64 || !i2c_acpi_get_i2c_resource(ares, &sb)) { 67053f8f7c5SWolfram Sang ret = AE_BAD_PARAMETER; 67153f8f7c5SWolfram Sang goto err; 67253f8f7c5SWolfram Sang } 67353f8f7c5SWolfram Sang 67453f8f7c5SWolfram Sang client->adapter = adapter; 67553f8f7c5SWolfram Sang client->addr = sb->slave_address; 67653f8f7c5SWolfram Sang 67753f8f7c5SWolfram Sang if (sb->access_mode == ACPI_I2C_10BIT_MODE) 67853f8f7c5SWolfram Sang client->flags |= I2C_CLIENT_TEN; 67953f8f7c5SWolfram Sang 68053f8f7c5SWolfram Sang switch (accessor_type) { 68153f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: 68253f8f7c5SWolfram Sang if (action == ACPI_READ) { 68353f8f7c5SWolfram Sang status = i2c_smbus_read_byte(client); 68453f8f7c5SWolfram Sang if (status >= 0) { 68553f8f7c5SWolfram Sang gsb->bdata = status; 68653f8f7c5SWolfram Sang status = 0; 68753f8f7c5SWolfram Sang } 68853f8f7c5SWolfram Sang } else { 68953f8f7c5SWolfram Sang status = i2c_smbus_write_byte(client, gsb->bdata); 69053f8f7c5SWolfram Sang } 69153f8f7c5SWolfram Sang break; 69253f8f7c5SWolfram Sang 69353f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_BYTE: 69453f8f7c5SWolfram Sang if (action == ACPI_READ) { 69553f8f7c5SWolfram Sang status = i2c_smbus_read_byte_data(client, command); 69653f8f7c5SWolfram Sang if (status >= 0) { 69753f8f7c5SWolfram Sang gsb->bdata = status; 69853f8f7c5SWolfram Sang status = 0; 69953f8f7c5SWolfram Sang } 70053f8f7c5SWolfram Sang } else { 70153f8f7c5SWolfram Sang status = i2c_smbus_write_byte_data(client, command, 70253f8f7c5SWolfram Sang gsb->bdata); 70353f8f7c5SWolfram Sang } 70453f8f7c5SWolfram Sang break; 70553f8f7c5SWolfram Sang 70653f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_WORD: 70753f8f7c5SWolfram Sang if (action == ACPI_READ) { 70853f8f7c5SWolfram Sang status = i2c_smbus_read_word_data(client, command); 70953f8f7c5SWolfram Sang if (status >= 0) { 71053f8f7c5SWolfram Sang gsb->wdata = status; 71153f8f7c5SWolfram Sang status = 0; 71253f8f7c5SWolfram Sang } 71353f8f7c5SWolfram Sang } else { 71453f8f7c5SWolfram Sang status = i2c_smbus_write_word_data(client, command, 71553f8f7c5SWolfram Sang gsb->wdata); 71653f8f7c5SWolfram Sang } 71753f8f7c5SWolfram Sang break; 71853f8f7c5SWolfram Sang 71953f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_BLOCK: 72053f8f7c5SWolfram Sang if (action == ACPI_READ) { 72153f8f7c5SWolfram Sang status = i2c_smbus_read_block_data(client, command, 72253f8f7c5SWolfram Sang gsb->data); 72353f8f7c5SWolfram Sang if (status >= 0) { 72453f8f7c5SWolfram Sang gsb->len = status; 72553f8f7c5SWolfram Sang status = 0; 72653f8f7c5SWolfram Sang } 72753f8f7c5SWolfram Sang } else { 72853f8f7c5SWolfram Sang status = i2c_smbus_write_block_data(client, command, 72953f8f7c5SWolfram Sang gsb->len, gsb->data); 73053f8f7c5SWolfram Sang } 73153f8f7c5SWolfram Sang break; 73253f8f7c5SWolfram Sang 73353f8f7c5SWolfram Sang case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: 73453f8f7c5SWolfram Sang if (action == ACPI_READ) { 73553f8f7c5SWolfram Sang status = acpi_gsb_i2c_read_bytes(client, command, 73653f8f7c5SWolfram Sang gsb->data, info->access_length); 73753f8f7c5SWolfram Sang } else { 73853f8f7c5SWolfram Sang status = acpi_gsb_i2c_write_bytes(client, command, 73953f8f7c5SWolfram Sang gsb->data, info->access_length); 74053f8f7c5SWolfram Sang } 74153f8f7c5SWolfram Sang break; 74253f8f7c5SWolfram Sang 74353f8f7c5SWolfram Sang default: 74453f8f7c5SWolfram Sang dev_warn(&adapter->dev, "protocol 0x%02x not supported for client 0x%02x\n", 74553f8f7c5SWolfram Sang accessor_type, client->addr); 74653f8f7c5SWolfram Sang ret = AE_BAD_PARAMETER; 74753f8f7c5SWolfram Sang goto err; 74853f8f7c5SWolfram Sang } 74953f8f7c5SWolfram Sang 75053f8f7c5SWolfram Sang gsb->status = status; 75153f8f7c5SWolfram Sang 75253f8f7c5SWolfram Sang err: 75353f8f7c5SWolfram Sang kfree(client); 75453f8f7c5SWolfram Sang ACPI_FREE(ares); 75553f8f7c5SWolfram Sang return ret; 75653f8f7c5SWolfram Sang } 75753f8f7c5SWolfram Sang 75853f8f7c5SWolfram Sang 75953f8f7c5SWolfram Sang int i2c_acpi_install_space_handler(struct i2c_adapter *adapter) 76053f8f7c5SWolfram Sang { 76153f8f7c5SWolfram Sang acpi_handle handle; 76253f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data; 76353f8f7c5SWolfram Sang acpi_status status; 76453f8f7c5SWolfram Sang 76553f8f7c5SWolfram Sang if (!adapter->dev.parent) 76653f8f7c5SWolfram Sang return -ENODEV; 76753f8f7c5SWolfram Sang 76853f8f7c5SWolfram Sang handle = ACPI_HANDLE(adapter->dev.parent); 76953f8f7c5SWolfram Sang 77053f8f7c5SWolfram Sang if (!handle) 77153f8f7c5SWolfram Sang return -ENODEV; 77253f8f7c5SWolfram Sang 77353f8f7c5SWolfram Sang data = kzalloc(sizeof(struct i2c_acpi_handler_data), 77453f8f7c5SWolfram Sang GFP_KERNEL); 77553f8f7c5SWolfram Sang if (!data) 77653f8f7c5SWolfram Sang return -ENOMEM; 77753f8f7c5SWolfram Sang 77853f8f7c5SWolfram Sang data->adapter = adapter; 77953f8f7c5SWolfram Sang status = acpi_bus_attach_private_data(handle, (void *)data); 78053f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 78153f8f7c5SWolfram Sang kfree(data); 78253f8f7c5SWolfram Sang return -ENOMEM; 78353f8f7c5SWolfram Sang } 78453f8f7c5SWolfram Sang 78553f8f7c5SWolfram Sang status = acpi_install_address_space_handler(handle, 78653f8f7c5SWolfram Sang ACPI_ADR_SPACE_GSBUS, 78753f8f7c5SWolfram Sang &i2c_acpi_space_handler, 78853f8f7c5SWolfram Sang NULL, 78953f8f7c5SWolfram Sang data); 79053f8f7c5SWolfram Sang if (ACPI_FAILURE(status)) { 79153f8f7c5SWolfram Sang dev_err(&adapter->dev, "Error installing i2c space handler\n"); 79253f8f7c5SWolfram Sang acpi_bus_detach_private_data(handle); 79353f8f7c5SWolfram Sang kfree(data); 79453f8f7c5SWolfram Sang return -ENOMEM; 79553f8f7c5SWolfram Sang } 79653f8f7c5SWolfram Sang 79753f8f7c5SWolfram Sang return 0; 79853f8f7c5SWolfram Sang } 79953f8f7c5SWolfram Sang 80053f8f7c5SWolfram Sang void i2c_acpi_remove_space_handler(struct i2c_adapter *adapter) 80153f8f7c5SWolfram Sang { 80253f8f7c5SWolfram Sang acpi_handle handle; 80353f8f7c5SWolfram Sang struct i2c_acpi_handler_data *data; 80453f8f7c5SWolfram Sang acpi_status status; 80553f8f7c5SWolfram Sang 80653f8f7c5SWolfram Sang if (!adapter->dev.parent) 80753f8f7c5SWolfram Sang return; 80853f8f7c5SWolfram Sang 80953f8f7c5SWolfram Sang handle = ACPI_HANDLE(adapter->dev.parent); 81053f8f7c5SWolfram Sang 81153f8f7c5SWolfram Sang if (!handle) 81253f8f7c5SWolfram Sang return; 81353f8f7c5SWolfram Sang 81453f8f7c5SWolfram Sang acpi_remove_address_space_handler(handle, 81553f8f7c5SWolfram Sang ACPI_ADR_SPACE_GSBUS, 81653f8f7c5SWolfram Sang &i2c_acpi_space_handler); 81753f8f7c5SWolfram Sang 81853f8f7c5SWolfram Sang status = acpi_bus_get_private_data(handle, (void **)&data); 81953f8f7c5SWolfram Sang if (ACPI_SUCCESS(status)) 82053f8f7c5SWolfram Sang kfree(data); 82153f8f7c5SWolfram Sang 82253f8f7c5SWolfram Sang acpi_bus_detach_private_data(handle); 82353f8f7c5SWolfram Sang } 82453f8f7c5SWolfram Sang #endif /* CONFIG_ACPI_I2C_OPREGION */ 825