1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#ifdef CONFIG_ACPI
16
17#include <linux/kernel.h>
18#include <linux/i2c.h>
19#include <linux/dmi.h>
20#include <linux/acpi.h>
21#include "inv_mpu_iio.h"
22
23enum inv_mpu_product_name {
24 INV_MPU_NOT_MATCHED,
25 INV_MPU_ASUS_T100TA,
26};
27
28static enum inv_mpu_product_name matched_product_name;
29
30static int __init asus_t100_matched(const struct dmi_system_id *d)
31{
32 matched_product_name = INV_MPU_ASUS_T100TA;
33
34 return 0;
35}
36
37static const struct dmi_system_id inv_mpu_dev_list[] = {
38 {
39 .callback = asus_t100_matched,
40 .ident = "Asus Transformer Book T100",
41 .matches = {
42 DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC"),
43 DMI_MATCH(DMI_PRODUCT_NAME, "T100TA"),
44 DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
45 },
46 },
47
48 {}
49};
50
51static int asus_acpi_get_sensor_info(struct acpi_device *adev,
52 struct i2c_client *client,
53 struct i2c_board_info *info)
54{
55 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
56 int i;
57 acpi_status status;
58 union acpi_object *cpm;
59
60 status = acpi_evaluate_object(adev->handle, "CNF0", NULL, &buffer);
61 if (ACPI_FAILURE(status))
62 return -ENODEV;
63
64 cpm = buffer.pointer;
65 for (i = 0; i < cpm->package.count; ++i) {
66 union acpi_object *elem;
67 int j;
68
69 elem = &cpm->package.elements[i];
70 for (j = 0; j < elem->package.count; ++j) {
71 union acpi_object *sub_elem;
72
73 sub_elem = &elem->package.elements[j];
74 if (sub_elem->type == ACPI_TYPE_STRING)
75 strlcpy(info->type, sub_elem->string.pointer,
76 sizeof(info->type));
77 else if (sub_elem->type == ACPI_TYPE_INTEGER) {
78 if (sub_elem->integer.value != client->addr) {
79 info->addr = sub_elem->integer.value;
80 break;
81 }
82 }
83 }
84 }
85
86 kfree(buffer.pointer);
87
88 return cpm->package.count;
89}
90
91static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data)
92{
93 u32 *addr = data;
94
95 if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS) {
96 struct acpi_resource_i2c_serialbus *sb;
97
98 sb = &ares->data.i2c_serial_bus;
99 if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
100 if (*addr)
101 *addr |= (sb->slave_address << 16);
102 else
103 *addr = sb->slave_address;
104 }
105 }
106
107
108 return 1;
109}
110
111static int inv_mpu_process_acpi_config(struct i2c_client *client,
112 unsigned short *primary_addr,
113 unsigned short *secondary_addr)
114{
115 const struct acpi_device_id *id;
116 struct acpi_device *adev;
117 u32 i2c_addr = 0;
118 LIST_HEAD(resources);
119 int ret;
120
121 id = acpi_match_device(client->dev.driver->acpi_match_table,
122 &client->dev);
123 if (!id)
124 return -ENODEV;
125
126 adev = ACPI_COMPANION(&client->dev);
127 if (!adev)
128 return -ENODEV;
129
130 ret = acpi_dev_get_resources(adev, &resources,
131 acpi_i2c_check_resource, &i2c_addr);
132 if (ret < 0)
133 return ret;
134
135 acpi_dev_free_resource_list(&resources);
136 *primary_addr = i2c_addr & 0x0000ffff;
137 *secondary_addr = (i2c_addr & 0xffff0000) >> 16;
138
139 return 0;
140}
141
142int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
143{
144 struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
145
146 st->mux_client = NULL;
147 if (ACPI_HANDLE(&client->dev)) {
148 struct i2c_board_info info;
149 struct acpi_device *adev;
150 int ret = -1;
151
152 adev = ACPI_COMPANION(&client->dev);
153 memset(&info, 0, sizeof(info));
154
155 dmi_check_system(inv_mpu_dev_list);
156 switch (matched_product_name) {
157 case INV_MPU_ASUS_T100TA:
158 ret = asus_acpi_get_sensor_info(adev, client,
159 &info);
160 break;
161
162 default:
163 break;
164 }
165
166 if (ret < 0) {
167
168 unsigned short primary, secondary;
169
170 ret = inv_mpu_process_acpi_config(client, &primary,
171 &secondary);
172 if (!ret && secondary) {
173 char *name;
174
175 info.addr = secondary;
176 strlcpy(info.type, dev_name(&adev->dev),
177 sizeof(info.type));
178 name = strchr(info.type, ':');
179 if (name)
180 *name = '\0';
181 strlcat(info.type, "-client",
182 sizeof(info.type));
183 } else
184 return 0;
185 }
186 st->mux_client = i2c_new_device(st->mux_adapter, &info);
187 if (!st->mux_client)
188 return -ENODEV;
189 }
190
191 return 0;
192}
193
194void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
195{
196 struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(&client->dev));
197
198 if (st->mux_client)
199 i2c_unregister_device(st->mux_client);
200}
201#else
202
203#include "inv_mpu_iio.h"
204
205int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
206{
207 return 0;
208}
209
210void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
211{
212}
213#endif
214