2 * inv_mpu_acpi: ACPI processing for creating client devices
3 * Copyright (c) 2015, Intel Corporation.
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
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"
23 enum inv_mpu_product_name
{
28 static enum inv_mpu_product_name matched_product_name
;
30 static int __init
asus_t100_matched(const struct dmi_system_id
*d
)
32 matched_product_name
= INV_MPU_ASUS_T100TA
;
37 static const struct dmi_system_id inv_mpu_dev_list
[] = {
39 .callback
= asus_t100_matched
,
40 .ident
= "Asus Transformer Book T100",
42 DMI_MATCH(DMI_SYS_VENDOR
, "ASUSTeK COMPUTER INC"),
43 DMI_MATCH(DMI_PRODUCT_NAME
, "T100TA"),
44 DMI_MATCH(DMI_PRODUCT_VERSION
, "1.0"),
47 /* Add more matching tables here..*/
51 static int asus_acpi_get_sensor_info(struct acpi_device
*adev
,
52 struct i2c_client
*client
,
53 struct i2c_board_info
*info
)
55 struct acpi_buffer buffer
= {ACPI_ALLOCATE_BUFFER
, NULL
};
58 union acpi_object
*cpm
;
61 status
= acpi_evaluate_object(adev
->handle
, "CNF0", NULL
, &buffer
);
62 if (ACPI_FAILURE(status
))
66 for (i
= 0; i
< cpm
->package
.count
; ++i
) {
67 union acpi_object
*elem
;
70 elem
= &cpm
->package
.elements
[i
];
71 for (j
= 0; j
< elem
->package
.count
; ++j
) {
72 union acpi_object
*sub_elem
;
74 sub_elem
= &elem
->package
.elements
[j
];
75 if (sub_elem
->type
== ACPI_TYPE_STRING
)
76 strlcpy(info
->type
, sub_elem
->string
.pointer
,
78 else if (sub_elem
->type
== ACPI_TYPE_INTEGER
) {
79 if (sub_elem
->integer
.value
!= client
->addr
) {
80 info
->addr
= sub_elem
->integer
.value
;
81 break; /* Not a MPU6500 primary */
86 ret
= cpm
->package
.count
;
87 kfree(buffer
.pointer
);
92 static int acpi_i2c_check_resource(struct acpi_resource
*ares
, void *data
)
96 if (ares
->type
== ACPI_RESOURCE_TYPE_SERIAL_BUS
) {
97 struct acpi_resource_i2c_serialbus
*sb
;
99 sb
= &ares
->data
.i2c_serial_bus
;
100 if (sb
->type
== ACPI_RESOURCE_SERIAL_TYPE_I2C
) {
102 *addr
|= (sb
->slave_address
<< 16);
104 *addr
= sb
->slave_address
;
108 /* Tell the ACPI core that we already copied this address */
112 static int inv_mpu_process_acpi_config(struct i2c_client
*client
,
113 unsigned short *primary_addr
,
114 unsigned short *secondary_addr
)
116 const struct acpi_device_id
*id
;
117 struct acpi_device
*adev
;
119 LIST_HEAD(resources
);
122 id
= acpi_match_device(client
->dev
.driver
->acpi_match_table
,
127 adev
= ACPI_COMPANION(&client
->dev
);
131 ret
= acpi_dev_get_resources(adev
, &resources
,
132 acpi_i2c_check_resource
, &i2c_addr
);
136 acpi_dev_free_resource_list(&resources
);
137 *primary_addr
= i2c_addr
& 0x0000ffff;
138 *secondary_addr
= (i2c_addr
& 0xffff0000) >> 16;
143 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
145 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
147 st
->mux_client
= NULL
;
148 if (ACPI_HANDLE(&client
->dev
)) {
149 struct i2c_board_info info
;
150 struct acpi_device
*adev
;
153 adev
= ACPI_COMPANION(&client
->dev
);
154 memset(&info
, 0, sizeof(info
));
156 dmi_check_system(inv_mpu_dev_list
);
157 switch (matched_product_name
) {
158 case INV_MPU_ASUS_T100TA
:
159 ret
= asus_acpi_get_sensor_info(adev
, client
,
162 /* Add more matched product processing here */
168 /* No matching DMI, so create device on INV6XX type */
169 unsigned short primary
, secondary
;
171 ret
= inv_mpu_process_acpi_config(client
, &primary
,
173 if (!ret
&& secondary
) {
176 info
.addr
= secondary
;
177 strlcpy(info
.type
, dev_name(&adev
->dev
),
179 name
= strchr(info
.type
, ':');
182 strlcat(info
.type
, "-client",
185 return 0; /* no secondary addr, which is OK */
187 st
->mux_client
= i2c_new_device(st
->muxc
->adapter
[0], &info
);
195 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)
197 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
199 i2c_unregister_device(st
->mux_client
);
203 #include "inv_mpu_iio.h"
205 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
210 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)