Message ID | 1411420006-4713-1-git-send-email-wsa@the-dreams.de (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
On 2014?09?23? 05:06, Wolfram Sang wrote: > Commit 5d98e61d337c ("I2C/ACPI: Add i2c ACPI operation region support") renamed > the i2c-core module. This may cause regressions for distributions, so put the > ACPI code back into the core. No code was changed. > > Reported-by: Jean Delvare <jdelvare@suse.de> > Signed-off-by: Wolfram Sang <wsa@the-dreams.de> > Cc: Mika Westerberg <mika.westerberg@linux.intel.com> > Cc: Lan Tianyu <tianyu.lan@intel.com> > Cc: Jean Delvare <jdelvare@suse.de> > --- > > Lan Tianyi, this is a patch I expected to get from you, fully tested. Since we > are approaching the final release soon, I did it now. Please do test this > patch. All I can do is build test (it works for me, build robots are still > running). If nobody tests this, I have to revert the ACPI changes of this > cycle. Hi Wolfram: Sorry for later response due to sickness. I can't write this patch in time. Sorry again. I will test it soon. > > Jean, can you have a look, too? > > We can think of something better for the next release, but for now, this should be it. > > MAINTAINERS | 1 - > drivers/i2c/Makefile | 5 +- > drivers/i2c/i2c-acpi.c | 364 ------------------------------------------------- > drivers/i2c/i2c-core.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 346 insertions(+), 369 deletions(-) > delete mode 100644 drivers/i2c/i2c-acpi.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 809ecd680d88..e3682d0dea1e 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -4477,7 +4477,6 @@ M: Mika Westerberg <mika.westerberg@linux.intel.com> > L: linux-i2c@vger.kernel.org > L: linux-acpi@vger.kernel.org > S: Maintained > -F: drivers/i2c/i2c-acpi.c > > I2C-TAOS-EVM DRIVER > M: Jean Delvare <jdelvare@suse.de> > diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile > index e0228b228256..1722f50f2473 100644 > --- a/drivers/i2c/Makefile > +++ b/drivers/i2c/Makefile > @@ -2,11 +2,8 @@ > # Makefile for the i2c core. > # > > -i2ccore-y := i2c-core.o > -i2ccore-$(CONFIG_ACPI) += i2c-acpi.o > - > obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o > -obj-$(CONFIG_I2C) += i2ccore.o > +obj-$(CONFIG_I2C) += i2c-core.o > obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o > obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o > obj-$(CONFIG_I2C_MUX) += i2c-mux.o > diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c > deleted file mode 100644 > index 0dbc18c15c43..000000000000 > --- a/drivers/i2c/i2c-acpi.c > +++ /dev/null > @@ -1,364 +0,0 @@ > -/* > - * I2C ACPI code > - * > - * Copyright (C) 2014 Intel Corp > - * > - * Author: Lan Tianyu <tianyu.lan@intel.com> > - * > - * This program is free software; you can redistribute it and/or modify > - * it under the terms of the GNU General Public License version 2 as > - * published by the Free Software Foundation. > - * > - * This program is distributed in the hope that it will be useful, but > - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY > - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License > - * for more details. > - */ > -#define pr_fmt(fmt) "I2C/ACPI : " fmt > - > -#include <linux/kernel.h> > -#include <linux/errno.h> > -#include <linux/err.h> > -#include <linux/i2c.h> > -#include <linux/acpi.h> > - > -struct acpi_i2c_handler_data { > - struct acpi_connection_info info; > - struct i2c_adapter *adapter; > -}; > - > -struct gsb_buffer { > - u8 status; > - u8 len; > - union { > - u16 wdata; > - u8 bdata; > - u8 data[0]; > - }; > -} __packed; > - > -static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) > -{ > - struct i2c_board_info *info = data; > - > - if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { > - struct acpi_resource_i2c_serialbus *sb; > - > - sb = &ares->data.i2c_serial_bus; > - if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { > - info->addr = sb->slave_address; > - if (sb->access_mode == ACPI_I2C_10BIT_MODE) > - info->flags |= I2C_CLIENT_TEN; > - } > - } else if (info->irq < 0) { > - struct resource r; > - > - if (acpi_dev_resource_interrupt(ares, 0, &r)) > - info->irq = r.start; > - } > - > - /* Tell the ACPI core to skip this resource */ > - return 1; > -} > - > -static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, > - void *data, void **return_value) > -{ > - struct i2c_adapter *adapter = data; > - struct list_head resource_list; > - struct i2c_board_info info; > - struct acpi_device *adev; > - int ret; > - > - if (acpi_bus_get_device(handle, &adev)) > - return AE_OK; > - if (acpi_bus_get_status(adev) || !adev->status.present) > - return AE_OK; > - > - memset(&info, 0, sizeof(info)); > - info.acpi_node.companion = adev; > - info.irq = -1; > - > - INIT_LIST_HEAD(&resource_list); > - ret = acpi_dev_get_resources(adev, &resource_list, > - acpi_i2c_add_resource, &info); > - acpi_dev_free_resource_list(&resource_list); > - > - if (ret < 0 || !info.addr) > - return AE_OK; > - > - adev->power.flags.ignore_parent = true; > - strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); > - if (!i2c_new_device(adapter, &info)) { > - adev->power.flags.ignore_parent = false; > - dev_err(&adapter->dev, > - "failed to add I2C device %s from ACPI\n", > - dev_name(&adev->dev)); > - } > - > - return AE_OK; > -} > - > -/** > - * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter > - * @adap: pointer to adapter > - * > - * Enumerate all I2C slave devices behind this adapter by walking the ACPI > - * namespace. When a device is found it will be added to the Linux device > - * model and bound to the corresponding ACPI handle. > - */ > -void acpi_i2c_register_devices(struct i2c_adapter *adap) > -{ > - acpi_handle handle; > - acpi_status status; > - > - if (!adap->dev.parent) > - return; > - > - handle = ACPI_HANDLE(adap->dev.parent); > - if (!handle) > - return; > - > - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, > - acpi_i2c_add_device, NULL, > - adap, NULL); > - if (ACPI_FAILURE(status)) > - dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); > -} > - > -#ifdef CONFIG_ACPI_I2C_OPREGION > -static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, > - u8 cmd, u8 *data, u8 data_len) > -{ > - > - struct i2c_msg msgs[2]; > - int ret; > - u8 *buffer; > - > - buffer = kzalloc(data_len, GFP_KERNEL); > - if (!buffer) > - return AE_NO_MEMORY; > - > - msgs[0].addr = client->addr; > - msgs[0].flags = client->flags; > - msgs[0].len = 1; > - msgs[0].buf = &cmd; > - > - msgs[1].addr = client->addr; > - msgs[1].flags = client->flags | I2C_M_RD; > - msgs[1].len = data_len; > - msgs[1].buf = buffer; > - > - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); > - if (ret < 0) > - dev_err(&client->adapter->dev, "i2c read failed\n"); > - else > - memcpy(data, buffer, data_len); > - > - kfree(buffer); > - return ret; > -} > - > -static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, > - u8 cmd, u8 *data, u8 data_len) > -{ > - > - struct i2c_msg msgs[1]; > - u8 *buffer; > - int ret = AE_OK; > - > - buffer = kzalloc(data_len + 1, GFP_KERNEL); > - if (!buffer) > - return AE_NO_MEMORY; > - > - buffer[0] = cmd; > - memcpy(buffer + 1, data, data_len); > - > - msgs[0].addr = client->addr; > - msgs[0].flags = client->flags; > - msgs[0].len = data_len + 1; > - msgs[0].buf = buffer; > - > - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); > - if (ret < 0) > - dev_err(&client->adapter->dev, "i2c write failed\n"); > - > - kfree(buffer); > - return ret; > -} > - > -static acpi_status > -acpi_i2c_space_handler(u32 function, acpi_physical_address command, > - u32 bits, u64 *value64, > - void *handler_context, void *region_context) > -{ > - struct gsb_buffer *gsb = (struct gsb_buffer *)value64; > - struct acpi_i2c_handler_data *data = handler_context; > - struct acpi_connection_info *info = &data->info; > - struct acpi_resource_i2c_serialbus *sb; > - struct i2c_adapter *adapter = data->adapter; > - struct i2c_client client; > - struct acpi_resource *ares; > - u32 accessor_type = function >> 16; > - u8 action = function & ACPI_IO_MASK; > - acpi_status ret = AE_OK; > - int status; > - > - ret = acpi_buffer_to_resource(info->connection, info->length, &ares); > - if (ACPI_FAILURE(ret)) > - return ret; > - > - if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { > - ret = AE_BAD_PARAMETER; > - goto err; > - } > - > - sb = &ares->data.i2c_serial_bus; > - if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { > - ret = AE_BAD_PARAMETER; > - goto err; > - } > - > - memset(&client, 0, sizeof(client)); > - client.adapter = adapter; > - client.addr = sb->slave_address; > - client.flags = 0; > - > - if (sb->access_mode == ACPI_I2C_10BIT_MODE) > - client.flags |= I2C_CLIENT_TEN; > - > - switch (accessor_type) { > - case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: > - if (action == ACPI_READ) { > - status = i2c_smbus_read_byte(&client); > - if (status >= 0) { > - gsb->bdata = status; > - status = 0; > - } > - } else { > - status = i2c_smbus_write_byte(&client, gsb->bdata); > - } > - break; > - > - case ACPI_GSB_ACCESS_ATTRIB_BYTE: > - if (action == ACPI_READ) { > - status = i2c_smbus_read_byte_data(&client, command); > - if (status >= 0) { > - gsb->bdata = status; > - status = 0; > - } > - } else { > - status = i2c_smbus_write_byte_data(&client, command, > - gsb->bdata); > - } > - break; > - > - case ACPI_GSB_ACCESS_ATTRIB_WORD: > - if (action == ACPI_READ) { > - status = i2c_smbus_read_word_data(&client, command); > - if (status >= 0) { > - gsb->wdata = status; > - status = 0; > - } > - } else { > - status = i2c_smbus_write_word_data(&client, command, > - gsb->wdata); > - } > - break; > - > - case ACPI_GSB_ACCESS_ATTRIB_BLOCK: > - if (action == ACPI_READ) { > - status = i2c_smbus_read_block_data(&client, command, > - gsb->data); > - if (status >= 0) { > - gsb->len = status; > - status = 0; > - } > - } else { > - status = i2c_smbus_write_block_data(&client, command, > - gsb->len, gsb->data); > - } > - break; > - > - case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: > - if (action == ACPI_READ) { > - status = acpi_gsb_i2c_read_bytes(&client, command, > - gsb->data, info->access_length); > - if (status > 0) > - status = 0; > - } else { > - status = acpi_gsb_i2c_write_bytes(&client, command, > - gsb->data, info->access_length); > - } > - break; > - > - default: > - pr_info("protocol(0x%02x) is not supported.\n", accessor_type); > - ret = AE_BAD_PARAMETER; > - goto err; > - } > - > - gsb->status = status; > - > - err: > - ACPI_FREE(ares); > - return ret; > -} > - > - > -int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) > -{ > - acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); > - struct acpi_i2c_handler_data *data; > - acpi_status status; > - > - if (!handle) > - return -ENODEV; > - > - data = kzalloc(sizeof(struct acpi_i2c_handler_data), > - GFP_KERNEL); > - if (!data) > - return -ENOMEM; > - > - data->adapter = adapter; > - status = acpi_bus_attach_private_data(handle, (void *)data); > - if (ACPI_FAILURE(status)) { > - kfree(data); > - return -ENOMEM; > - } > - > - status = acpi_install_address_space_handler(handle, > - ACPI_ADR_SPACE_GSBUS, > - &acpi_i2c_space_handler, > - NULL, > - data); > - if (ACPI_FAILURE(status)) { > - dev_err(&adapter->dev, "Error installing i2c space handler\n"); > - acpi_bus_detach_private_data(handle); > - kfree(data); > - return -ENOMEM; > - } > - > - return 0; > -} > - > -void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) > -{ > - acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); > - struct acpi_i2c_handler_data *data; > - acpi_status status; > - > - if (!handle) > - return; > - > - acpi_remove_address_space_handler(handle, > - ACPI_ADR_SPACE_GSBUS, > - &acpi_i2c_space_handler); > - > - status = acpi_bus_get_private_data(handle, (void **)&data); > - if (ACPI_SUCCESS(status)) > - kfree(data); > - > - acpi_bus_detach_private_data(handle); > -} > -#endif > diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c > index 632057a44615..3fbd5d5c38bf 100644 > --- a/drivers/i2c/i2c-core.c > +++ b/drivers/i2c/i2c-core.c > @@ -27,6 +27,8 @@ > OF support is copyright (c) 2008 Jochen Friedrich <jochen@scram.de> > (based on a previous patch from Jon Smirl <jonsmirl@gmail.com>) and > (c) 2013 Wolfram Sang <wsa@the-dreams.de> > + I2C ACPI code Copyright (C) 2014 Intel Corp > + Author: Lan Tianyu <tianyu.lan@intel.com> > */ > > #include <linux/module.h> > @@ -78,6 +80,349 @@ void i2c_transfer_trace_unreg(void) > static_key_slow_dec(&i2c_trace_msg); > } > > +#if defined(CONFIG_ACPI) > +struct acpi_i2c_handler_data { > + struct acpi_connection_info info; > + struct i2c_adapter *adapter; > +}; > + > +struct gsb_buffer { > + u8 status; > + u8 len; > + union { > + u16 wdata; > + u8 bdata; > + u8 data[0]; > + }; > +} __packed; > + > +static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) > +{ > + struct i2c_board_info *info = data; > + > + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { > + struct acpi_resource_i2c_serialbus *sb; > + > + sb = &ares->data.i2c_serial_bus; > + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { > + info->addr = sb->slave_address; > + if (sb->access_mode == ACPI_I2C_10BIT_MODE) > + info->flags |= I2C_CLIENT_TEN; > + } > + } else if (info->irq < 0) { > + struct resource r; > + > + if (acpi_dev_resource_interrupt(ares, 0, &r)) > + info->irq = r.start; > + } > + > + /* Tell the ACPI core to skip this resource */ > + return 1; > +} > + > +static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, > + void *data, void **return_value) > +{ > + struct i2c_adapter *adapter = data; > + struct list_head resource_list; > + struct i2c_board_info info; > + struct acpi_device *adev; > + int ret; > + > + if (acpi_bus_get_device(handle, &adev)) > + return AE_OK; > + if (acpi_bus_get_status(adev) || !adev->status.present) > + return AE_OK; > + > + memset(&info, 0, sizeof(info)); > + info.acpi_node.companion = adev; > + info.irq = -1; > + > + INIT_LIST_HEAD(&resource_list); > + ret = acpi_dev_get_resources(adev, &resource_list, > + acpi_i2c_add_resource, &info); > + acpi_dev_free_resource_list(&resource_list); > + > + if (ret < 0 || !info.addr) > + return AE_OK; > + > + adev->power.flags.ignore_parent = true; > + strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); > + if (!i2c_new_device(adapter, &info)) { > + adev->power.flags.ignore_parent = false; > + dev_err(&adapter->dev, > + "failed to add I2C device %s from ACPI\n", > + dev_name(&adev->dev)); > + } > + > + return AE_OK; > +} > + > +/** > + * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter > + * @adap: pointer to adapter > + * > + * Enumerate all I2C slave devices behind this adapter by walking the ACPI > + * namespace. When a device is found it will be added to the Linux device > + * model and bound to the corresponding ACPI handle. > + */ > +void acpi_i2c_register_devices(struct i2c_adapter *adap) > +{ > + acpi_handle handle; > + acpi_status status; > + > + if (!adap->dev.parent) > + return; > + > + handle = ACPI_HANDLE(adap->dev.parent); > + if (!handle) > + return; > + > + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, > + acpi_i2c_add_device, NULL, > + adap, NULL); > + if (ACPI_FAILURE(status)) > + dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); > +} > + > +#ifdef CONFIG_ACPI_I2C_OPREGION > +static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, > + u8 cmd, u8 *data, u8 data_len) > +{ > + > + struct i2c_msg msgs[2]; > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(data_len, GFP_KERNEL); > + if (!buffer) > + return AE_NO_MEMORY; > + > + msgs[0].addr = client->addr; > + msgs[0].flags = client->flags; > + msgs[0].len = 1; > + msgs[0].buf = &cmd; > + > + msgs[1].addr = client->addr; > + msgs[1].flags = client->flags | I2C_M_RD; > + msgs[1].len = data_len; > + msgs[1].buf = buffer; > + > + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); > + if (ret < 0) > + dev_err(&client->adapter->dev, "i2c read failed\n"); > + else > + memcpy(data, buffer, data_len); > + > + kfree(buffer); > + return ret; > +} > + > +static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, > + u8 cmd, u8 *data, u8 data_len) > +{ > + > + struct i2c_msg msgs[1]; > + u8 *buffer; > + int ret = AE_OK; > + > + buffer = kzalloc(data_len + 1, GFP_KERNEL); > + if (!buffer) > + return AE_NO_MEMORY; > + > + buffer[0] = cmd; > + memcpy(buffer + 1, data, data_len); > + > + msgs[0].addr = client->addr; > + msgs[0].flags = client->flags; > + msgs[0].len = data_len + 1; > + msgs[0].buf = buffer; > + > + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); > + if (ret < 0) > + dev_err(&client->adapter->dev, "i2c write failed\n"); > + > + kfree(buffer); > + return ret; > +} > + > +static acpi_status > +acpi_i2c_space_handler(u32 function, acpi_physical_address command, > + u32 bits, u64 *value64, > + void *handler_context, void *region_context) > +{ > + struct gsb_buffer *gsb = (struct gsb_buffer *)value64; > + struct acpi_i2c_handler_data *data = handler_context; > + struct acpi_connection_info *info = &data->info; > + struct acpi_resource_i2c_serialbus *sb; > + struct i2c_adapter *adapter = data->adapter; > + struct i2c_client client; > + struct acpi_resource *ares; > + u32 accessor_type = function >> 16; > + u8 action = function & ACPI_IO_MASK; > + acpi_status ret = AE_OK; > + int status; > + > + ret = acpi_buffer_to_resource(info->connection, info->length, &ares); > + if (ACPI_FAILURE(ret)) > + return ret; > + > + if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { > + ret = AE_BAD_PARAMETER; > + goto err; > + } > + > + sb = &ares->data.i2c_serial_bus; > + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { > + ret = AE_BAD_PARAMETER; > + goto err; > + } > + > + memset(&client, 0, sizeof(client)); > + client.adapter = adapter; > + client.addr = sb->slave_address; > + client.flags = 0; > + > + if (sb->access_mode == ACPI_I2C_10BIT_MODE) > + client.flags |= I2C_CLIENT_TEN; > + > + switch (accessor_type) { > + case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: > + if (action == ACPI_READ) { > + status = i2c_smbus_read_byte(&client); > + if (status >= 0) { > + gsb->bdata = status; > + status = 0; > + } > + } else { > + status = i2c_smbus_write_byte(&client, gsb->bdata); > + } > + break; > + > + case ACPI_GSB_ACCESS_ATTRIB_BYTE: > + if (action == ACPI_READ) { > + status = i2c_smbus_read_byte_data(&client, command); > + if (status >= 0) { > + gsb->bdata = status; > + status = 0; > + } > + } else { > + status = i2c_smbus_write_byte_data(&client, command, > + gsb->bdata); > + } > + break; > + > + case ACPI_GSB_ACCESS_ATTRIB_WORD: > + if (action == ACPI_READ) { > + status = i2c_smbus_read_word_data(&client, command); > + if (status >= 0) { > + gsb->wdata = status; > + status = 0; > + } > + } else { > + status = i2c_smbus_write_word_data(&client, command, > + gsb->wdata); > + } > + break; > + > + case ACPI_GSB_ACCESS_ATTRIB_BLOCK: > + if (action == ACPI_READ) { > + status = i2c_smbus_read_block_data(&client, command, > + gsb->data); > + if (status >= 0) { > + gsb->len = status; > + status = 0; > + } > + } else { > + status = i2c_smbus_write_block_data(&client, command, > + gsb->len, gsb->data); > + } > + break; > + > + case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: > + if (action == ACPI_READ) { > + status = acpi_gsb_i2c_read_bytes(&client, command, > + gsb->data, info->access_length); > + if (status > 0) > + status = 0; > + } else { > + status = acpi_gsb_i2c_write_bytes(&client, command, > + gsb->data, info->access_length); > + } > + break; > + > + default: > + pr_info("protocol(0x%02x) is not supported.\n", accessor_type); > + ret = AE_BAD_PARAMETER; > + goto err; > + } > + > + gsb->status = status; > + > + err: > + ACPI_FREE(ares); > + return ret; > +} > + > + > +int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) > +{ > + acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); > + struct acpi_i2c_handler_data *data; > + acpi_status status; > + > + if (!handle) > + return -ENODEV; > + > + data = kzalloc(sizeof(struct acpi_i2c_handler_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + data->adapter = adapter; > + status = acpi_bus_attach_private_data(handle, (void *)data); > + if (ACPI_FAILURE(status)) { > + kfree(data); > + return -ENOMEM; > + } > + > + status = acpi_install_address_space_handler(handle, > + ACPI_ADR_SPACE_GSBUS, > + &acpi_i2c_space_handler, > + NULL, > + data); > + if (ACPI_FAILURE(status)) { > + dev_err(&adapter->dev, "Error installing i2c space handler\n"); > + acpi_bus_detach_private_data(handle); > + kfree(data); > + return -ENOMEM; > + } > + > + return 0; > +} > + > +void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) > +{ > + acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); > + struct acpi_i2c_handler_data *data; > + acpi_status status; > + > + if (!handle) > + return; > + > + acpi_remove_address_space_handler(handle, > + ACPI_ADR_SPACE_GSBUS, > + &acpi_i2c_space_handler); > + > + status = acpi_bus_get_private_data(handle, (void **)&data); > + if (ACPI_SUCCESS(status)) > + kfree(data); > + > + acpi_bus_detach_private_data(handle); > +} > +#endif > +#endif /* CONFIG_ACPI */ > + > /* ------------------------------------------------------------------------- */ > > static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, >
> Sorry for later response due to sickness. I can't write this patch in > time. Sorry again. I will test it soon. Oh, get well soon! Please say so next time, so I know.
On 2014?09?23? 13:39, Wolfram Sang wrote: > >> Sorry for later response due to sickness. I can't write this patch in >> time. Sorry again. I will test it soon. > > Oh, get well soon! Please say so next time, so I know. > Thanks. OK. I have put the patch into test system and need to wait some time.
On 2014?09?23? 15:09, Lan Tianyu wrote: > On 2014?09?23? 13:39, Wolfram Sang wrote: >> >>> Sorry for later response due to sickness. I can't write this patch in >>> time. Sorry again. I will test it soon. >> >> Oh, get well soon! Please say so next time, so I know. >> > > Thanks. OK. > I have put the patch into test system and need to wait some time. > Hi Wolfram: The patch passed through the following 110 configure build test in the 0-day build test system. configs tested: 110 mips allmodconfig mips jz4740 mips allnoconfig mips fuloong2e_defconfig mips txx9 x86_64 allnoconfig sh titan_defconfig sh rsk7269_defconfig sh sh7785lcr_32bit_defconfig sh allnoconfig x86_64 randconfig-c3-0923 x86_64 randconfig-c1-0923 x86_64 randconfig-c2-0923 x86_64 randconfig-c0-0923 arm omap2plus_defconfig arm sa1100 arm allmodconfig arm prima2_defconfig arm at91_dt_defconfig arm allnoconfig arm samsung arm spear13xx_defconfig arm s3c2410_defconfig arm iop-adma arm imx_v6_v7_defconfig arm mmp arm tegra_defconfig arm arm5 arm marzen_defconfig arm at_hdmac arm ep93xx arm sh arm arm67 parisc c3000_defconfig parisc b180_defconfig parisc defconfig alpha defconfig parisc allnoconfig powerpc iss476-smp_defconfig powerpc mpc8315_rdb_defconfig mips ath79_defconfig arm bcm_defconfig powerpc gef_ppc9a_defconfig i386 randconfig-ha0-0923 i386 randconfig-ha1-0923 i386 randconfig-ha2-0923 i386 randconfig-ha3-0923 ia64 allmodconfig ia64 allnoconfig ia64 defconfig ia64 alldefconfig microblaze mmu_defconfig microblaze nommu_defconfig microblaze allyesconfig s390 allmodconfig s390 allnoconfig s390 defconfig x86_64 randconfig-ha1-0923 x86_64 randconfig-ha3-0923 x86_64 randconfig-ha0-0923 x86_64 randconfig-ha2-0923 xtensa common_defconfig m32r m32104ut_defconfig xtensa iss_defconfig m32r opsput_defconfig m32r usrv_defconfig m32r mappi3.smp_defconfig sparc defconfig sparc64 allnoconfig sparc64 defconfig i386 allyesconfig cris etrax-100lx_v2_defconfig blackfin TCM-BF537_defconfig blackfin BF561-EZKIT-SMP_defconfig blackfin BF533-EZKIT_defconfig blackfin BF526-EZBRD_defconfig i386 randconfig-r0-0923 i386 randconfig-r2-0923 i386 randconfig-r3-0923 i386 randconfig-r1-0923 x86_64 randconfig-s0-09231616 x86_64 randconfig Hi Wolfram: The patch passed through the following 110 configure build test in the 0-day build test system.-s1-09231616 x86_64 allmodconfig i386 alldefconfig i386 allmodconfig i386 allnoconfig i386 defconfig i386 randconfig-x009-0922 x86_64 randconfig-x003-0922 x86_64 randconfig-x004-0922 i386 randconfig-x006-0922 x86_64 randconfig-x001-0922 i386 randconfig-x005-0922 x86_64 randconfig-x006-0922 i386 randconfig-x001-0922 i386 randconfig-x004-0922 i386 randconfig-x003-0922 i386 randconfig-x000-0922 x86_64 randconfig-x002-0922 x86_64 randconfig-x008-0922 i386 randconfig-x008-0922 i386 randconfig-x007-0922 x86_64 randconfig-x009-0922 x86_64 randconfig-x000-0922 x86_64 randconfig-x007-0922 i386 randconfig-x002-0922 x86_64 randconfig-x005-0922 x86_64 acpi-redef x86_64 allyesdebian x86_64 nfsroot
On Mon, Sep 22, 2014 at 11:06:46PM +0200, Wolfram Sang wrote: > Commit 5d98e61d337c ("I2C/ACPI: Add i2c ACPI operation region support") renamed > the i2c-core module. This may cause regressions for distributions, so put the > ACPI code back into the core. No code was changed. Thanks Wolfram for doing this! I tested this already and it of course works but there are few things that you are missing so this probably needs an additional iteration. > Reported-by: Jean Delvare <jdelvare@suse.de> > Signed-off-by: Wolfram Sang <wsa@the-dreams.de> > Cc: Mika Westerberg <mika.westerberg@linux.intel.com> > Cc: Lan Tianyu <tianyu.lan@intel.com> > Cc: Jean Delvare <jdelvare@suse.de> > --- > > Lan Tianyi, this is a patch I expected to get from you, fully tested. Since we > are approaching the final release soon, I did it now. Please do test this > patch. All I can do is build test (it works for me, build robots are still > running). If nobody tests this, I have to revert the ACPI changes of this > cycle. > > Jean, can you have a look, too? > > We can think of something better for the next release, but for now, this should be it. > > MAINTAINERS | 1 - > drivers/i2c/Makefile | 5 +- > drivers/i2c/i2c-acpi.c | 364 ------------------------------------------------- > drivers/i2c/i2c-core.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++ > 4 files changed, 346 insertions(+), 369 deletions(-) > delete mode 100644 drivers/i2c/i2c-acpi.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 809ecd680d88..e3682d0dea1e 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -4477,7 +4477,6 @@ M: Mika Westerberg <mika.westerberg@linux.intel.com> > L: linux-i2c@vger.kernel.org > L: linux-acpi@vger.kernel.org > S: Maintained > -F: drivers/i2c/i2c-acpi.c You can remove my name from MAINTANERS as well. I'm not I2C subsystem maintainer :) Of course I will still assist reviewing ACPI related changes in i2c-core.c. > I2C-TAOS-EVM DRIVER > M: Jean Delvare <jdelvare@suse.de> ... > +/** > + * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter > + * @adap: pointer to adapter > + * > + * Enumerate all I2C slave devices behind this adapter by walking the ACPI > + * namespace. When a device is found it will be added to the Linux device > + * model and bound to the corresponding ACPI handle. > + */ > +void acpi_i2c_register_devices(struct i2c_adapter *adap) static > +{ > + acpi_handle handle; > + acpi_status status; > + > + if (!adap->dev.parent) > + return; > + > + handle = ACPI_HANDLE(adap->dev.parent); > + if (!handle) > + return; > + > + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, > + acpi_i2c_add_device, NULL, > + adap, NULL); > + if (ACPI_FAILURE(status)) > + dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); > +} > + ... > +int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) static > +{ > + acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); > + struct acpi_i2c_handler_data *data; > + acpi_status status; > + > + if (!handle) > + return -ENODEV; > + > + data = kzalloc(sizeof(struct acpi_i2c_handler_data), > + GFP_KERNEL); > + if (!data) > + return -ENOMEM; > + > + data->adapter = adapter; > + status = acpi_bus_attach_private_data(handle, (void *)data); > + if (ACPI_FAILURE(status)) { > + kfree(data); > + return -ENOMEM; > + } > + > + status = acpi_install_address_space_handler(handle, > + ACPI_ADR_SPACE_GSBUS, > + &acpi_i2c_space_handler, > + NULL, > + data); > + if (ACPI_FAILURE(status)) { > + dev_err(&adapter->dev, "Error installing i2c space handler\n"); > + acpi_bus_detach_private_data(handle); > + kfree(data); > + return -ENOMEM; > + } > + > + return 0; > +} > + > +void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) static > +{ > + acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); > + struct acpi_i2c_handler_data *data; > + acpi_status status; > + > + if (!handle) > + return; > + > + acpi_remove_address_space_handler(handle, > + ACPI_ADR_SPACE_GSBUS, > + &acpi_i2c_space_handler); > + > + status = acpi_bus_get_private_data(handle, (void **)&data); > + if (ACPI_SUCCESS(status)) > + kfree(data); > + > + acpi_bus_detach_private_data(handle); > +} > +#endif I would put there #endif /* CONFIG_ACPI_I2C_OPREGION */ > +#endif /* CONFIG_ACPI */ Also please remove all ACPI related stuff in include/linux/i2c.h. That is not needed anymore. -- To unsubscribe from this list: send the line "unsubscribe linux-acpi" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
> > diff --git a/MAINTAINERS b/MAINTAINERS > > index 809ecd680d88..e3682d0dea1e 100644 > > --- a/MAINTAINERS > > +++ b/MAINTAINERS > > @@ -4477,7 +4477,6 @@ M: Mika Westerberg <mika.westerberg@linux.intel.com> > > L: linux-i2c@vger.kernel.org > > L: linux-acpi@vger.kernel.org > > S: Maintained > > -F: drivers/i2c/i2c-acpi.c > > You can remove my name from MAINTANERS as well. I'm not I2C subsystem > maintainer :) Of course I will still assist reviewing ACPI related > changes in i2c-core.c. I'd like to keep this since the header says I2C/ACPI. I am thinking of adding something like 'K: i2c_.*acpi_' but that can wait. For now, we need a working solution _very_ soon. > > +#endif > > I would put there > > #endif /* CONFIG_ACPI_I2C_OPREGION */ I didn't want to change lines not written by me, but well yeah... > Also please remove all ACPI related stuff in include/linux/i2c.h. That > is not needed anymore. Yup, thanks!
> Hi Wolfram: > The patch passed through the following 110 configure build test in the > 0-day build test system. Thanks, but my tree gets checked automatically anyhow. What I'd need is functional tests because I don't have hardware to test.
diff --git a/MAINTAINERS b/MAINTAINERS index 809ecd680d88..e3682d0dea1e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4477,7 +4477,6 @@ M: Mika Westerberg <mika.westerberg@linux.intel.com> L: linux-i2c@vger.kernel.org L: linux-acpi@vger.kernel.org S: Maintained -F: drivers/i2c/i2c-acpi.c I2C-TAOS-EVM DRIVER M: Jean Delvare <jdelvare@suse.de> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile index e0228b228256..1722f50f2473 100644 --- a/drivers/i2c/Makefile +++ b/drivers/i2c/Makefile @@ -2,11 +2,8 @@ # Makefile for the i2c core. # -i2ccore-y := i2c-core.o -i2ccore-$(CONFIG_ACPI) += i2c-acpi.o - obj-$(CONFIG_I2C_BOARDINFO) += i2c-boardinfo.o -obj-$(CONFIG_I2C) += i2ccore.o +obj-$(CONFIG_I2C) += i2c-core.o obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o obj-$(CONFIG_I2C_MUX) += i2c-mux.o diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c deleted file mode 100644 index 0dbc18c15c43..000000000000 --- a/drivers/i2c/i2c-acpi.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * I2C ACPI code - * - * Copyright (C) 2014 Intel Corp - * - * Author: Lan Tianyu <tianyu.lan@intel.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * for more details. - */ -#define pr_fmt(fmt) "I2C/ACPI : " fmt - -#include <linux/kernel.h> -#include <linux/errno.h> -#include <linux/err.h> -#include <linux/i2c.h> -#include <linux/acpi.h> - -struct acpi_i2c_handler_data { - struct acpi_connection_info info; - struct i2c_adapter *adapter; -}; - -struct gsb_buffer { - u8 status; - u8 len; - union { - u16 wdata; - u8 bdata; - u8 data[0]; - }; -} __packed; - -static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) -{ - struct i2c_board_info *info = data; - - if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { - struct acpi_resource_i2c_serialbus *sb; - - sb = &ares->data.i2c_serial_bus; - if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { - info->addr = sb->slave_address; - if (sb->access_mode == ACPI_I2C_10BIT_MODE) - info->flags |= I2C_CLIENT_TEN; - } - } else if (info->irq < 0) { - struct resource r; - - if (acpi_dev_resource_interrupt(ares, 0, &r)) - info->irq = r.start; - } - - /* Tell the ACPI core to skip this resource */ - return 1; -} - -static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, - void *data, void **return_value) -{ - struct i2c_adapter *adapter = data; - struct list_head resource_list; - struct i2c_board_info info; - struct acpi_device *adev; - int ret; - - if (acpi_bus_get_device(handle, &adev)) - return AE_OK; - if (acpi_bus_get_status(adev) || !adev->status.present) - return AE_OK; - - memset(&info, 0, sizeof(info)); - info.acpi_node.companion = adev; - info.irq = -1; - - INIT_LIST_HEAD(&resource_list); - ret = acpi_dev_get_resources(adev, &resource_list, - acpi_i2c_add_resource, &info); - acpi_dev_free_resource_list(&resource_list); - - if (ret < 0 || !info.addr) - return AE_OK; - - adev->power.flags.ignore_parent = true; - strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); - if (!i2c_new_device(adapter, &info)) { - adev->power.flags.ignore_parent = false; - dev_err(&adapter->dev, - "failed to add I2C device %s from ACPI\n", - dev_name(&adev->dev)); - } - - return AE_OK; -} - -/** - * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter - * @adap: pointer to adapter - * - * Enumerate all I2C slave devices behind this adapter by walking the ACPI - * namespace. When a device is found it will be added to the Linux device - * model and bound to the corresponding ACPI handle. - */ -void acpi_i2c_register_devices(struct i2c_adapter *adap) -{ - acpi_handle handle; - acpi_status status; - - if (!adap->dev.parent) - return; - - handle = ACPI_HANDLE(adap->dev.parent); - if (!handle) - return; - - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - acpi_i2c_add_device, NULL, - adap, NULL); - if (ACPI_FAILURE(status)) - dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); -} - -#ifdef CONFIG_ACPI_I2C_OPREGION -static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, - u8 cmd, u8 *data, u8 data_len) -{ - - struct i2c_msg msgs[2]; - int ret; - u8 *buffer; - - buffer = kzalloc(data_len, GFP_KERNEL); - if (!buffer) - return AE_NO_MEMORY; - - msgs[0].addr = client->addr; - msgs[0].flags = client->flags; - msgs[0].len = 1; - msgs[0].buf = &cmd; - - msgs[1].addr = client->addr; - msgs[1].flags = client->flags | I2C_M_RD; - msgs[1].len = data_len; - msgs[1].buf = buffer; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - dev_err(&client->adapter->dev, "i2c read failed\n"); - else - memcpy(data, buffer, data_len); - - kfree(buffer); - return ret; -} - -static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, - u8 cmd, u8 *data, u8 data_len) -{ - - struct i2c_msg msgs[1]; - u8 *buffer; - int ret = AE_OK; - - buffer = kzalloc(data_len + 1, GFP_KERNEL); - if (!buffer) - return AE_NO_MEMORY; - - buffer[0] = cmd; - memcpy(buffer + 1, data, data_len); - - msgs[0].addr = client->addr; - msgs[0].flags = client->flags; - msgs[0].len = data_len + 1; - msgs[0].buf = buffer; - - ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); - if (ret < 0) - dev_err(&client->adapter->dev, "i2c write failed\n"); - - kfree(buffer); - return ret; -} - -static acpi_status -acpi_i2c_space_handler(u32 function, acpi_physical_address command, - u32 bits, u64 *value64, - void *handler_context, void *region_context) -{ - struct gsb_buffer *gsb = (struct gsb_buffer *)value64; - struct acpi_i2c_handler_data *data = handler_context; - struct acpi_connection_info *info = &data->info; - struct acpi_resource_i2c_serialbus *sb; - struct i2c_adapter *adapter = data->adapter; - struct i2c_client client; - struct acpi_resource *ares; - u32 accessor_type = function >> 16; - u8 action = function & ACPI_IO_MASK; - acpi_status ret = AE_OK; - int status; - - ret = acpi_buffer_to_resource(info->connection, info->length, &ares); - if (ACPI_FAILURE(ret)) - return ret; - - if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { - ret = AE_BAD_PARAMETER; - goto err; - } - - sb = &ares->data.i2c_serial_bus; - if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { - ret = AE_BAD_PARAMETER; - goto err; - } - - memset(&client, 0, sizeof(client)); - client.adapter = adapter; - client.addr = sb->slave_address; - client.flags = 0; - - if (sb->access_mode == ACPI_I2C_10BIT_MODE) - client.flags |= I2C_CLIENT_TEN; - - switch (accessor_type) { - case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: - if (action == ACPI_READ) { - status = i2c_smbus_read_byte(&client); - if (status >= 0) { - gsb->bdata = status; - status = 0; - } - } else { - status = i2c_smbus_write_byte(&client, gsb->bdata); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_BYTE: - if (action == ACPI_READ) { - status = i2c_smbus_read_byte_data(&client, command); - if (status >= 0) { - gsb->bdata = status; - status = 0; - } - } else { - status = i2c_smbus_write_byte_data(&client, command, - gsb->bdata); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_WORD: - if (action == ACPI_READ) { - status = i2c_smbus_read_word_data(&client, command); - if (status >= 0) { - gsb->wdata = status; - status = 0; - } - } else { - status = i2c_smbus_write_word_data(&client, command, - gsb->wdata); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_BLOCK: - if (action == ACPI_READ) { - status = i2c_smbus_read_block_data(&client, command, - gsb->data); - if (status >= 0) { - gsb->len = status; - status = 0; - } - } else { - status = i2c_smbus_write_block_data(&client, command, - gsb->len, gsb->data); - } - break; - - case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: - if (action == ACPI_READ) { - status = acpi_gsb_i2c_read_bytes(&client, command, - gsb->data, info->access_length); - if (status > 0) - status = 0; - } else { - status = acpi_gsb_i2c_write_bytes(&client, command, - gsb->data, info->access_length); - } - break; - - default: - pr_info("protocol(0x%02x) is not supported.\n", accessor_type); - ret = AE_BAD_PARAMETER; - goto err; - } - - gsb->status = status; - - err: - ACPI_FREE(ares); - return ret; -} - - -int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) -{ - acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); - struct acpi_i2c_handler_data *data; - acpi_status status; - - if (!handle) - return -ENODEV; - - data = kzalloc(sizeof(struct acpi_i2c_handler_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - data->adapter = adapter; - status = acpi_bus_attach_private_data(handle, (void *)data); - if (ACPI_FAILURE(status)) { - kfree(data); - return -ENOMEM; - } - - status = acpi_install_address_space_handler(handle, - ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler, - NULL, - data); - if (ACPI_FAILURE(status)) { - dev_err(&adapter->dev, "Error installing i2c space handler\n"); - acpi_bus_detach_private_data(handle); - kfree(data); - return -ENOMEM; - } - - return 0; -} - -void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) -{ - acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); - struct acpi_i2c_handler_data *data; - acpi_status status; - - if (!handle) - return; - - acpi_remove_address_space_handler(handle, - ACPI_ADR_SPACE_GSBUS, - &acpi_i2c_space_handler); - - status = acpi_bus_get_private_data(handle, (void **)&data); - if (ACPI_SUCCESS(status)) - kfree(data); - - acpi_bus_detach_private_data(handle); -} -#endif diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 632057a44615..3fbd5d5c38bf 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -27,6 +27,8 @@ OF support is copyright (c) 2008 Jochen Friedrich <jochen@scram.de> (based on a previous patch from Jon Smirl <jonsmirl@gmail.com>) and (c) 2013 Wolfram Sang <wsa@the-dreams.de> + I2C ACPI code Copyright (C) 2014 Intel Corp + Author: Lan Tianyu <tianyu.lan@intel.com> */ #include <linux/module.h> @@ -78,6 +80,349 @@ void i2c_transfer_trace_unreg(void) static_key_slow_dec(&i2c_trace_msg); } +#if defined(CONFIG_ACPI) +struct acpi_i2c_handler_data { + struct acpi_connection_info info; + struct i2c_adapter *adapter; +}; + +struct gsb_buffer { + u8 status; + u8 len; + union { + u16 wdata; + u8 bdata; + u8 data[0]; + }; +} __packed; + +static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data) +{ + struct i2c_board_info *info = data; + + if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) { + struct acpi_resource_i2c_serialbus *sb; + + sb = &ares->data.i2c_serial_bus; + if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) { + info->addr = sb->slave_address; + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + info->flags |= I2C_CLIENT_TEN; + } + } else if (info->irq < 0) { + struct resource r; + + if (acpi_dev_resource_interrupt(ares, 0, &r)) + info->irq = r.start; + } + + /* Tell the ACPI core to skip this resource */ + return 1; +} + +static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level, + void *data, void **return_value) +{ + struct i2c_adapter *adapter = data; + struct list_head resource_list; + struct i2c_board_info info; + struct acpi_device *adev; + int ret; + + if (acpi_bus_get_device(handle, &adev)) + return AE_OK; + if (acpi_bus_get_status(adev) || !adev->status.present) + return AE_OK; + + memset(&info, 0, sizeof(info)); + info.acpi_node.companion = adev; + info.irq = -1; + + INIT_LIST_HEAD(&resource_list); + ret = acpi_dev_get_resources(adev, &resource_list, + acpi_i2c_add_resource, &info); + acpi_dev_free_resource_list(&resource_list); + + if (ret < 0 || !info.addr) + return AE_OK; + + adev->power.flags.ignore_parent = true; + strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type)); + if (!i2c_new_device(adapter, &info)) { + adev->power.flags.ignore_parent = false; + dev_err(&adapter->dev, + "failed to add I2C device %s from ACPI\n", + dev_name(&adev->dev)); + } + + return AE_OK; +} + +/** + * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter + * @adap: pointer to adapter + * + * Enumerate all I2C slave devices behind this adapter by walking the ACPI + * namespace. When a device is found it will be added to the Linux device + * model and bound to the corresponding ACPI handle. + */ +void acpi_i2c_register_devices(struct i2c_adapter *adap) +{ + acpi_handle handle; + acpi_status status; + + if (!adap->dev.parent) + return; + + handle = ACPI_HANDLE(adap->dev.parent); + if (!handle) + return; + + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, + acpi_i2c_add_device, NULL, + adap, NULL); + if (ACPI_FAILURE(status)) + dev_warn(&adap->dev, "failed to enumerate I2C slaves\n"); +} + +#ifdef CONFIG_ACPI_I2C_OPREGION +static int acpi_gsb_i2c_read_bytes(struct i2c_client *client, + u8 cmd, u8 *data, u8 data_len) +{ + + struct i2c_msg msgs[2]; + int ret; + u8 *buffer; + + buffer = kzalloc(data_len, GFP_KERNEL); + if (!buffer) + return AE_NO_MEMORY; + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; + msgs[0].len = 1; + msgs[0].buf = &cmd; + + msgs[1].addr = client->addr; + msgs[1].flags = client->flags | I2C_M_RD; + msgs[1].len = data_len; + msgs[1].buf = buffer; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + dev_err(&client->adapter->dev, "i2c read failed\n"); + else + memcpy(data, buffer, data_len); + + kfree(buffer); + return ret; +} + +static int acpi_gsb_i2c_write_bytes(struct i2c_client *client, + u8 cmd, u8 *data, u8 data_len) +{ + + struct i2c_msg msgs[1]; + u8 *buffer; + int ret = AE_OK; + + buffer = kzalloc(data_len + 1, GFP_KERNEL); + if (!buffer) + return AE_NO_MEMORY; + + buffer[0] = cmd; + memcpy(buffer + 1, data, data_len); + + msgs[0].addr = client->addr; + msgs[0].flags = client->flags; + msgs[0].len = data_len + 1; + msgs[0].buf = buffer; + + ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); + if (ret < 0) + dev_err(&client->adapter->dev, "i2c write failed\n"); + + kfree(buffer); + return ret; +} + +static acpi_status +acpi_i2c_space_handler(u32 function, acpi_physical_address command, + u32 bits, u64 *value64, + void *handler_context, void *region_context) +{ + struct gsb_buffer *gsb = (struct gsb_buffer *)value64; + struct acpi_i2c_handler_data *data = handler_context; + struct acpi_connection_info *info = &data->info; + struct acpi_resource_i2c_serialbus *sb; + struct i2c_adapter *adapter = data->adapter; + struct i2c_client client; + struct acpi_resource *ares; + u32 accessor_type = function >> 16; + u8 action = function & ACPI_IO_MASK; + acpi_status ret = AE_OK; + int status; + + ret = acpi_buffer_to_resource(info->connection, info->length, &ares); + if (ACPI_FAILURE(ret)) + return ret; + + if (!value64 || ares->type != ACPI_RESOURCE_TYPE_SERIAL_BUS) { + ret = AE_BAD_PARAMETER; + goto err; + } + + sb = &ares->data.i2c_serial_bus; + if (sb->type != ACPI_RESOURCE_SERIAL_TYPE_I2C) { + ret = AE_BAD_PARAMETER; + goto err; + } + + memset(&client, 0, sizeof(client)); + client.adapter = adapter; + client.addr = sb->slave_address; + client.flags = 0; + + if (sb->access_mode == ACPI_I2C_10BIT_MODE) + client.flags |= I2C_CLIENT_TEN; + + switch (accessor_type) { + case ACPI_GSB_ACCESS_ATTRIB_SEND_RCV: + if (action == ACPI_READ) { + status = i2c_smbus_read_byte(&client); + if (status >= 0) { + gsb->bdata = status; + status = 0; + } + } else { + status = i2c_smbus_write_byte(&client, gsb->bdata); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_BYTE: + if (action == ACPI_READ) { + status = i2c_smbus_read_byte_data(&client, command); + if (status >= 0) { + gsb->bdata = status; + status = 0; + } + } else { + status = i2c_smbus_write_byte_data(&client, command, + gsb->bdata); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_WORD: + if (action == ACPI_READ) { + status = i2c_smbus_read_word_data(&client, command); + if (status >= 0) { + gsb->wdata = status; + status = 0; + } + } else { + status = i2c_smbus_write_word_data(&client, command, + gsb->wdata); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_BLOCK: + if (action == ACPI_READ) { + status = i2c_smbus_read_block_data(&client, command, + gsb->data); + if (status >= 0) { + gsb->len = status; + status = 0; + } + } else { + status = i2c_smbus_write_block_data(&client, command, + gsb->len, gsb->data); + } + break; + + case ACPI_GSB_ACCESS_ATTRIB_MULTIBYTE: + if (action == ACPI_READ) { + status = acpi_gsb_i2c_read_bytes(&client, command, + gsb->data, info->access_length); + if (status > 0) + status = 0; + } else { + status = acpi_gsb_i2c_write_bytes(&client, command, + gsb->data, info->access_length); + } + break; + + default: + pr_info("protocol(0x%02x) is not supported.\n", accessor_type); + ret = AE_BAD_PARAMETER; + goto err; + } + + gsb->status = status; + + err: + ACPI_FREE(ares); + return ret; +} + + +int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) +{ + acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); + struct acpi_i2c_handler_data *data; + acpi_status status; + + if (!handle) + return -ENODEV; + + data = kzalloc(sizeof(struct acpi_i2c_handler_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + data->adapter = adapter; + status = acpi_bus_attach_private_data(handle, (void *)data); + if (ACPI_FAILURE(status)) { + kfree(data); + return -ENOMEM; + } + + status = acpi_install_address_space_handler(handle, + ACPI_ADR_SPACE_GSBUS, + &acpi_i2c_space_handler, + NULL, + data); + if (ACPI_FAILURE(status)) { + dev_err(&adapter->dev, "Error installing i2c space handler\n"); + acpi_bus_detach_private_data(handle); + kfree(data); + return -ENOMEM; + } + + return 0; +} + +void acpi_i2c_remove_space_handler(struct i2c_adapter *adapter) +{ + acpi_handle handle = ACPI_HANDLE(adapter->dev.parent); + struct acpi_i2c_handler_data *data; + acpi_status status; + + if (!handle) + return; + + acpi_remove_address_space_handler(handle, + ACPI_ADR_SPACE_GSBUS, + &acpi_i2c_space_handler); + + status = acpi_bus_get_private_data(handle, (void **)&data); + if (ACPI_SUCCESS(status)) + kfree(data); + + acpi_bus_detach_private_data(handle); +} +#endif +#endif /* CONFIG_ACPI */ + /* ------------------------------------------------------------------------- */ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id,
Commit 5d98e61d337c ("I2C/ACPI: Add i2c ACPI operation region support") renamed the i2c-core module. This may cause regressions for distributions, so put the ACPI code back into the core. No code was changed. Reported-by: Jean Delvare <jdelvare@suse.de> Signed-off-by: Wolfram Sang <wsa@the-dreams.de> Cc: Mika Westerberg <mika.westerberg@linux.intel.com> Cc: Lan Tianyu <tianyu.lan@intel.com> Cc: Jean Delvare <jdelvare@suse.de> --- Lan Tianyi, this is a patch I expected to get from you, fully tested. Since we are approaching the final release soon, I did it now. Please do test this patch. All I can do is build test (it works for me, build robots are still running). If nobody tests this, I have to revert the ACPI changes of this cycle. Jean, can you have a look, too? We can think of something better for the next release, but for now, this should be it. MAINTAINERS | 1 - drivers/i2c/Makefile | 5 +- drivers/i2c/i2c-acpi.c | 364 ------------------------------------------------- drivers/i2c/i2c-core.c | 345 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 346 insertions(+), 369 deletions(-) delete mode 100644 drivers/i2c/i2c-acpi.c