aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/Kconfig6
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_i2c.c103
-rw-r--r--drivers/i2c/i2c-core.c6
-rw-r--r--include/linux/i2c.h9
5 files changed, 125 insertions, 0 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 119d58db8342..0300bf612946 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -181,6 +181,12 @@ config ACPI_DOCK
181 This driver supports ACPI-controlled docking stations and removable 181 This driver supports ACPI-controlled docking stations and removable
182 drive bays such as the IBM Ultrabay and the Dell Module Bay. 182 drive bays such as the IBM Ultrabay and the Dell Module Bay.
183 183
184config ACPI_I2C
185 def_tristate I2C
186 depends on I2C
187 help
188 ACPI I2C enumeration support.
189
184config ACPI_PROCESSOR 190config ACPI_PROCESSOR
185 tristate "Processor" 191 tristate "Processor"
186 select THERMAL 192 select THERMAL
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 3223edfb23b6..7198b6d6b763 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_ACPI_HED) += hed.o
69obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o 69obj-$(CONFIG_ACPI_EC_DEBUGFS) += ec_sys.o
70obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o 70obj-$(CONFIG_ACPI_CUSTOM_METHOD)+= custom_method.o
71obj-$(CONFIG_ACPI_BGRT) += bgrt.o 71obj-$(CONFIG_ACPI_BGRT) += bgrt.o
72obj-$(CONFIG_ACPI_I2C) += acpi_i2c.o
72 73
73# processor has its own "processor." module_param namespace 74# processor has its own "processor." module_param namespace
74processor-y := processor_driver.o processor_throttling.o 75processor-y := processor_driver.o processor_throttling.o
diff --git a/drivers/acpi/acpi_i2c.c b/drivers/acpi/acpi_i2c.c
new file mode 100644
index 000000000000..82045e3f5cac
--- /dev/null
+++ b/drivers/acpi/acpi_i2c.c
@@ -0,0 +1,103 @@
1/*
2 * ACPI I2C enumeration support
3 *
4 * Copyright (C) 2012, Intel Corporation
5 * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/acpi.h>
13#include <linux/device.h>
14#include <linux/export.h>
15#include <linux/i2c.h>
16#include <linux/ioport.h>
17
18ACPI_MODULE_NAME("i2c");
19
20static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
21{
22 struct i2c_board_info *info = data;
23
24 if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
25 struct acpi_resource_i2c_serialbus *sb;
26
27 sb = &ares->data.i2c_serial_bus;
28 if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
29 info->addr = sb->slave_address;
30 if (sb->access_mode == ACPI_I2C_10BIT_MODE)
31 info->flags |= I2C_CLIENT_TEN;
32 }
33 } else if (info->irq < 0) {
34 struct resource r;
35
36 if (acpi_dev_resource_interrupt(ares, 0, &r))
37 info->irq = r.start;
38 }
39
40 /* Tell the ACPI core to skip this resource */
41 return 1;
42}
43
44static acpi_status acpi_i2c_add_device(acpi_handle handle, u32 level,
45 void *data, void **return_value)
46{
47 struct i2c_adapter *adapter = data;
48 struct list_head resource_list;
49 struct i2c_board_info info;
50 struct acpi_device *adev;
51 int ret;
52
53 if (acpi_bus_get_device(handle, &adev))
54 return AE_OK;
55 if (acpi_bus_get_status(adev) || !adev->status.present)
56 return AE_OK;
57
58 memset(&info, 0, sizeof(info));
59 info.acpi_node.handle = handle;
60 info.irq = -1;
61
62 INIT_LIST_HEAD(&resource_list);
63 ret = acpi_dev_get_resources(adev, &resource_list,
64 acpi_i2c_add_resource, &info);
65 acpi_dev_free_resource_list(&resource_list);
66
67 if (ret < 0 || !info.addr)
68 return AE_OK;
69
70 strlcpy(info.type, dev_name(&adev->dev), sizeof(info.type));
71 if (!i2c_new_device(adapter, &info)) {
72 dev_err(&adapter->dev,
73 "failed to add I2C device %s from ACPI\n",
74 dev_name(&adev->dev));
75 }
76
77 return AE_OK;
78}
79
80/**
81 * acpi_i2c_register_devices - enumerate I2C slave devices behind adapter
82 * @adapter: pointer to adapter
83 *
84 * Enumerate all I2C slave devices behind this adapter by walking the ACPI
85 * namespace. When a device is found it will be added to the Linux device
86 * model and bound to the corresponding ACPI handle.
87 */
88void acpi_i2c_register_devices(struct i2c_adapter *adapter)
89{
90 acpi_handle handle;
91 acpi_status status;
92
93 handle = ACPI_HANDLE(&adapter->dev);
94 if (!handle)
95 return;
96
97 status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1,
98 acpi_i2c_add_device, NULL,
99 adapter, NULL);
100 if (ACPI_FAILURE(status))
101 dev_warn(&adapter->dev, "failed to enumerate I2C slaves\n");
102}
103EXPORT_SYMBOL_GPL(acpi_i2c_register_devices);
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index a7edf987a339..e388590b44ab 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -39,6 +39,7 @@
39#include <linux/irqflags.h> 39#include <linux/irqflags.h>
40#include <linux/rwsem.h> 40#include <linux/rwsem.h>
41#include <linux/pm_runtime.h> 41#include <linux/pm_runtime.h>
42#include <linux/acpi.h>
42#include <asm/uaccess.h> 43#include <asm/uaccess.h>
43 44
44#include "i2c-core.h" 45#include "i2c-core.h"
@@ -78,6 +79,10 @@ static int i2c_device_match(struct device *dev, struct device_driver *drv)
78 if (of_driver_match_device(dev, drv)) 79 if (of_driver_match_device(dev, drv))
79 return 1; 80 return 1;
80 81
82 /* Then ACPI style match */
83 if (acpi_driver_match_device(dev, drv))
84 return 1;
85
81 driver = to_i2c_driver(drv); 86 driver = to_i2c_driver(drv);
82 /* match on an id table if there is one */ 87 /* match on an id table if there is one */
83 if (driver->id_table) 88 if (driver->id_table)
@@ -539,6 +544,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info)
539 client->dev.bus = &i2c_bus_type; 544 client->dev.bus = &i2c_bus_type;
540 client->dev.type = &i2c_client_type; 545 client->dev.type = &i2c_client_type;
541 client->dev.of_node = info->of_node; 546 client->dev.of_node = info->of_node;
547 ACPI_HANDLE_SET(&client->dev, info->acpi_node.handle);
542 548
543 /* For 10-bit clients, add an arbitrary offset to avoid collisions */ 549 /* For 10-bit clients, add an arbitrary offset to avoid collisions */
544 dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), 550 dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap),
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index 800de224336b..d0c4db7b4872 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -259,6 +259,7 @@ static inline void i2c_set_clientdata(struct i2c_client *dev, void *data)
259 * @platform_data: stored in i2c_client.dev.platform_data 259 * @platform_data: stored in i2c_client.dev.platform_data
260 * @archdata: copied into i2c_client.dev.archdata 260 * @archdata: copied into i2c_client.dev.archdata
261 * @of_node: pointer to OpenFirmware device node 261 * @of_node: pointer to OpenFirmware device node
262 * @acpi_node: ACPI device node
262 * @irq: stored in i2c_client.irq 263 * @irq: stored in i2c_client.irq
263 * 264 *
264 * I2C doesn't actually support hardware probing, although controllers and 265 * I2C doesn't actually support hardware probing, although controllers and
@@ -279,6 +280,7 @@ struct i2c_board_info {
279 void *platform_data; 280 void *platform_data;
280 struct dev_archdata *archdata; 281 struct dev_archdata *archdata;
281 struct device_node *of_node; 282 struct device_node *of_node;
283 struct acpi_dev_node acpi_node;
282 int irq; 284 int irq;
283}; 285};
284 286
@@ -501,4 +503,11 @@ static inline int i2c_adapter_id(struct i2c_adapter *adap)
501 i2c_del_driver) 503 i2c_del_driver)
502 504
503#endif /* I2C */ 505#endif /* I2C */
506
507#if IS_ENABLED(CONFIG_ACPI_I2C)
508extern void acpi_i2c_register_devices(struct i2c_adapter *adap);
509#else
510static inline void acpi_i2c_register_devices(struct i2c_adapter *adap) {}
511#endif
512
504#endif /* _LINUX_I2C_H */ 513#endif /* _LINUX_I2C_H */