提交 55e71edb 编写于 作者: M Mika Westerberg 提交者: Wolfram Sang

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: NMika Westerberg <mika.westerberg@linux.intel.com>
Acked-by: NRafael J. Wysocki <rafael.j.wysocki@intel.com>
Signed-off-by: NWolfram Sang <wsa@the-dreams.de>
上级 687b81d0
...@@ -228,18 +228,9 @@ ACPI handle like: ...@@ -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 ...@@ -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 ...@@ -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
......
/*
* 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) ...@@ -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); ...@@ -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) ...@@ -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 ...@@ -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 */
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册