mirror of https://gitee.com/openkylin/linux.git
i2c: move ACPI helpers into the core
This follows what has already been done for the DeviceTree helpers. Move the ACPI helpers from drivers/acpi/acpi_i2c.c to the I2C core and update documentation accordingly. This also solves a problem reported by Jerry Snitselaar that we can't build the ACPI I2C helpers as a module. Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com> Acked-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Wolfram Sang <wsa@the-dreams.de>
This commit is contained in:
parent
687b81d083
commit
55e71edb81
|
@ -228,18 +228,9 @@ ACPI handle like:
|
||||||
I2C serial bus support
|
I2C serial bus support
|
||||||
~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~
|
||||||
The slaves behind I2C bus controller only need to add the ACPI IDs like
|
The slaves behind I2C bus controller only need to add the ACPI IDs like
|
||||||
with the platform and SPI drivers. However the I2C bus controller driver
|
with the platform and SPI drivers. The I2C core automatically enumerates
|
||||||
needs to call acpi_i2c_register_devices() after it has added the adapter.
|
any slave devices behind the controller device once the adapter is
|
||||||
|
registered.
|
||||||
An I2C bus (controller) driver does:
|
|
||||||
|
|
||||||
...
|
|
||||||
ret = i2c_add_numbered_adapter(adapter);
|
|
||||||
if (ret)
|
|
||||||
/* handle error */
|
|
||||||
|
|
||||||
/* Enumerate the slave devices behind this bus via ACPI */
|
|
||||||
acpi_i2c_register_devices(adapter);
|
|
||||||
|
|
||||||
Below is an example of how to add ACPI support to the existing mpu3050
|
Below is an example of how to add ACPI support to the existing mpu3050
|
||||||
input driver:
|
input driver:
|
||||||
|
|
|
@ -180,12 +180,6 @@ config ACPI_DOCK
|
||||||
This driver supports ACPI-controlled docking stations and removable
|
This driver supports ACPI-controlled docking stations and removable
|
||||||
drive bays such as the IBM Ultrabay and the Dell Module Bay.
|
drive bays such as the IBM Ultrabay and the Dell Module Bay.
|
||||||
|
|
||||||
config ACPI_I2C
|
|
||||||
def_tristate I2C
|
|
||||||
depends on I2C
|
|
||||||
help
|
|
||||||
ACPI I2C enumeration support.
|
|
||||||
|
|
||||||
config ACPI_PROCESSOR
|
config ACPI_PROCESSOR
|
||||||
tristate "Processor"
|
tristate "Processor"
|
||||||
select THERMAL
|
select THERMAL
|
||||||
|
|
|
@ -73,7 +73,6 @@ obj-$(CONFIG_ACPI_HED) += hed.o
|
||||||
obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
|
obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
|
||||||
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
|
obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
|
||||||
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
|
obj-$(CONFIG_ACPI_BGRT) += bgrt.o
|
||||||
obj-$(CONFIG_ACPI_I2C) += acpi_i2c.o
|
|
||||||
|
|
||||||
# processor has its own "processor." module_param namespace
|
# processor has its own "processor." module_param namespace
|
||||||
processor-y := processor_driver.o processor_throttling.o
|
processor-y := processor_driver.o processor_throttling.o
|
||||||
|
|
|
@ -1,103 +0,0 @@
|
||||||
/*
|
|
||||||
* ACPI I2C enumeration support
|
|
||||||
*
|
|
||||||
* Copyright (C) 2012, Intel Corporation
|
|
||||||
* Author: Mika Westerberg <mika.westerberg@linux.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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <linux/acpi.h>
|
|
||||||
#include <linux/device.h>
|
|
||||||
#include <linux/export.h>
|
|
||||||
#include <linux/i2c.h>
|
|
||||||
#include <linux/ioport.h>
|
|
||||||
|
|
||||||
ACPI_MODULE_NAME("i2c");
|
|
||||||
|
|
||||||
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.handle = handle;
|
|
||||||
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;
|
|
||||||
|
|
||||||
strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
|
|
||||||
if (!i2c_new_device(adapter, &info)) {
|
|
||||||
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
|
|
||||||
* @adapter: 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 *adapter)
|
|
||||||
{
|
|
||||||
acpi_handle handle;
|
|
||||||
acpi_status status;
|
|
||||||
|
|
||||||
handle = ACPI_HANDLE(adapter->dev.parent);
|
|
||||||
if (!handle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
|
|
||||||
acpi_i2c_add_device, NULL,
|
|
||||||
adapter, NULL);
|
|
||||||
if (ACPI_FAILURE(status))
|
|
||||||
dev_warn(&adapter->dev, "failed to enumerate I2C slaves\n");
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(acpi_i2c_register_devices);
|
|
|
@ -171,7 +171,6 @@ static int dw_i2c_probe(struct platform_device *pdev)
|
||||||
dev_err(&pdev->dev, "failure adding adapter\n");
|
dev_err(&pdev->dev, "failure adding adapter\n");
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
acpi_i2c_register_devices(adap);
|
|
||||||
|
|
||||||
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
|
pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
|
||||||
pm_runtime_use_autosuspend(&pdev->dev);
|
pm_runtime_use_autosuspend(&pdev->dev);
|
||||||
|
|
|
@ -1058,6 +1058,96 @@ EXPORT_SYMBOL(of_find_i2c_adapter_by_node);
|
||||||
static void of_i2c_register_devices(struct i2c_adapter *adap) { }
|
static void of_i2c_register_devices(struct i2c_adapter *adap) { }
|
||||||
#endif /* CONFIG_OF */
|
#endif /* CONFIG_OF */
|
||||||
|
|
||||||
|
/* ACPI support code */
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_ACPI)
|
||||||
|
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.handle = handle;
|
||||||
|
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;
|
||||||
|
|
||||||
|
strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
|
||||||
|
if (!i2c_new_device(adapter, &info)) {
|
||||||
|
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.
|
||||||
|
*/
|
||||||
|
static void acpi_i2c_register_devices(struct i2c_adapter *adap)
|
||||||
|
{
|
||||||
|
acpi_handle handle;
|
||||||
|
acpi_status status;
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
|
||||||
|
#endif /* CONFIG_ACPI */
|
||||||
|
|
||||||
static int i2c_do_add_adapter(struct i2c_driver *driver,
|
static int i2c_do_add_adapter(struct i2c_driver *driver,
|
||||||
struct i2c_adapter *adap)
|
struct i2c_adapter *adap)
|
||||||
{
|
{
|
||||||
|
@ -1163,6 +1253,7 @@ static int i2c_register_adapter(struct i2c_adapter *adap)
|
||||||
exit_recovery:
|
exit_recovery:
|
||||||
/* create pre-declared device nodes */
|
/* create pre-declared device nodes */
|
||||||
of_i2c_register_devices(adap);
|
of_i2c_register_devices(adap);
|
||||||
|
acpi_i2c_register_devices(adap);
|
||||||
|
|
||||||
if (adap->nr < __i2c_first_dynamic_bus_num)
|
if (adap->nr < __i2c_first_dynamic_bus_num)
|
||||||
i2c_scan_static_board_info(adap);
|
i2c_scan_static_board_info(adap);
|
||||||
|
|
|
@ -564,10 +564,4 @@ static inline struct i2c_adapter *of_find_i2c_adapter_by_node(struct device_node
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_OF */
|
#endif /* CONFIG_OF */
|
||||||
|
|
||||||
#if IS_ENABLED(CONFIG_ACPI_I2C)
|
|
||||||
extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
|
|
||||||
#else
|
|
||||||
static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* _LINUX_I2C_H */
|
#endif /* _LINUX_I2C_H */
|
||||||
|
|
Loading…
Reference in New Issue