On 04/16/2014 09:24 PM, Lan Tianyu wrote:
ACPI 5.0 spec(5.5.2.4.5) defines GenericSerialBus(i2c, spi, uart) operation region. It allows ACPI aml code able to access such kind of devices to implement some ACPI standard method. On the Asus T100TA, Bios use GenericSerialBus operation region to access i2c device to get battery info. So battery function depends on the I2C operation region support. Here is the bug link. https://bugzilla.kernel.org/show_bug.cgi?id=69011
Completely fixing battery issue on the Asus T100TA also needs ACPI _DEP support. The feature is under developing. Attach a temporary patch for test.
This patchset is to add I2C ACPI operation region handler support. [PATCH 1/9] ACPICA: Executer: Fix buffer allocation issue for [PATCH 2/9] ACPICA: Export acpi_buffer_to_resource symbol [PATCH 3/9] ACPI: Add acpi_bus_attach_private_data() to facilitate to [PATCH 4/9] ACPI/Thermal: Use acpi_bus_attach_private_data() to [PATCH 5/9] I2C: Add smbus quick read/write helper function [PATCH 6/9] I2C: Add smbus word/block process call helper function [PATCH 7/9] I2C/ACPI: Add i2c ACPI operation region support [PATCH 8/9] I2C/ACPI: Move ACPI related code to i2c-acpi.c [PATCH 9/9] I2C/ACPI: Add CONFIG_I2C_ACPI config
>From bbadbc67de278123e28dd6f9ee7e88b6ada56ce4 Mon Sep 17 00:00:00 2001 From: Lan Tianyu <tianyu.lan@xxxxxxxxx> Date: Fri, 21 Mar 2014 16:42:12 +0800 Subject: [PATCH] ACPI: temporary dep solution for battery support This is a dep workaround for battery support on Asus T100TA and the formal dep solution is under developing. This patch is just for test and will not be upstreamed. --- drivers/acpi/scan.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++--- drivers/i2c/i2c-acpi.c | 1 + include/linux/acpi.h | 1 + 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 7efe546..254afb7 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -36,6 +36,7 @@ bool acpi_force_hot_remove; static const char *dummy_hid = "device"; +static LIST_HEAD(acpi_bus_dep_device_list); static LIST_HEAD(acpi_bus_id_list); static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); @@ -43,6 +44,12 @@ DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); static DEFINE_MUTEX(acpi_hp_context_lock); + +struct acpi_dep_handle { + struct list_head node; + acpi_handle handle; +}; + struct acpi_device_bus_id{ char bus_id[15]; unsigned int instance_no; @@ -2027,10 +2034,22 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) } } + +static int acpi_dep_device_check(acpi_handle handle) +{ + struct acpi_dep_handle *dep; + + list_for_each_entry(dep, &acpi_bus_dep_device_list, node) + if (dep->handle == handle) + return -EEXIST; + return 0; +} + static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { struct acpi_device *device = NULL; + struct acpi_dep_handle *dep = NULL; int type; unsigned long long sta; int result; @@ -2048,9 +2067,24 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_OK; } - acpi_add_single_object(&device, handle, type, sta); - if (!device) - return AE_CTRL_DEPTH; + if (!acpi_dep_device_check(handle) + && acpi_has_method(handle, "_BIX") + && acpi_has_method(handle, "_DEP")) { + dep = kmalloc(sizeof(struct acpi_dep_handle), GFP_KERNEL); + if (!dep) + return AE_CTRL_DEPTH; + dep->handle = handle; + list_add_tail(&dep->node , &acpi_bus_dep_device_list); + + acpi_handle_info(dep->handle, + "is added to dep device list.\n"); + + return AE_OK; + } else { + acpi_add_single_object(&device, handle, type, sta); + if (!device) + return AE_CTRL_DEPTH; + } acpi_scan_init_hotplug(device); @@ -2061,6 +2095,30 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_OK; } +int acpi_walk_dep_device_list(void) +{ + struct acpi_dep_handle *dep, *tmp; + acpi_status status; + unsigned long long sta; + + list_for_each_entry_safe(dep, tmp, &acpi_bus_dep_device_list, node) { + status = acpi_evaluate_integer(dep->handle, "_STA", NULL, &sta); + + if (ACPI_FAILURE(status)) { + acpi_handle_warn(dep->handle, + "Status check failed (0x%x)\n", status); + } else if (sta & ACPI_STA_DEVICE_ENABLED) { + acpi_bus_scan(dep->handle); + acpi_handle_info(dep->handle, + "Device is readly\n"); + list_del(&dep->node); + kfree(dep); + } + } + return 0; +} +EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list); + static int acpi_scan_attach_handler(struct acpi_device *device) { struct acpi_hardware_id *hwid; diff --git a/drivers/i2c/i2c-acpi.c b/drivers/i2c/i2c-acpi.c index a0ae867..471490a 100644 --- a/drivers/i2c/i2c-acpi.c +++ b/drivers/i2c/i2c-acpi.c @@ -349,6 +349,7 @@ int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) return -ENOMEM; } + acpi_walk_dep_device_list(); return 0; } diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 667204c..66ad0dd 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -115,6 +115,7 @@ int acpi_boot_init (void); void acpi_boot_table_init (void); int acpi_mps_check (void); int acpi_numa_init (void); +int acpi_walk_dep_device_list(void); int acpi_table_init (void); int acpi_table_parse(char *id, acpi_tbl_table_handler handler); -- 1.8.3.1