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
;
60 status
= acpi_evaluate_object(adev
->handle
, "CNF0", NULL
, &buffer
);
61 if (ACPI_FAILURE(status
))
65 for (i
= 0; i
< cpm
->package
.count
; ++i
) {
66 union acpi_object
*elem
;
69 elem
= &(cpm
->package
.elements
[i
]);
70 for (j
= 0; j
< elem
->package
.count
; ++j
) {
71 union acpi_object
*sub_elem
;
73 sub_elem
= &(elem
->package
.elements
[j
]);
74 if (sub_elem
->type
== ACPI_TYPE_STRING
)
75 strlcpy(info
->type
, sub_elem
->string
.pointer
,
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; /* Not a MPU6500 primary */
86 kfree(buffer
.pointer
);
88 return cpm
->package
.count
;
91 static int acpi_i2c_check_resource(struct acpi_resource
*ares
, void *data
)
95 if (ares
->type
== ACPI_RESOURCE_TYPE_SERIAL_BUS
) {
96 struct acpi_resource_i2c_serialbus
*sb
;
98 sb
= &ares
->data
.i2c_serial_bus
;
99 if (sb
->type
== ACPI_RESOURCE_SERIAL_TYPE_I2C
) {
101 *addr
|= (sb
->slave_address
<< 16);
103 *addr
= sb
->slave_address
;
107 /* Tell the ACPI core that we already copied this address */
111 static int inv_mpu_process_acpi_config(struct i2c_client
*client
,
112 unsigned short *primary_addr
,
113 unsigned short *secondary_addr
)
115 const struct acpi_device_id
*id
;
116 struct acpi_device
*adev
;
118 LIST_HEAD(resources
);
121 id
= acpi_match_device(client
->dev
.driver
->acpi_match_table
,
126 adev
= ACPI_COMPANION(&client
->dev
);
130 ret
= acpi_dev_get_resources(adev
, &resources
,
131 acpi_i2c_check_resource
, &i2c_addr
);
135 acpi_dev_free_resource_list(&resources
);
136 *primary_addr
= i2c_addr
& 0x0000ffff;
137 *secondary_addr
= (i2c_addr
& 0xffff0000) >> 16;
142 int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state
*st
)
145 st
->mux_client
= NULL
;
146 if (ACPI_HANDLE(&st
->client
->dev
)) {
147 struct i2c_board_info info
;
148 struct acpi_device
*adev
;
151 adev
= ACPI_COMPANION(&st
->client
->dev
);
152 memset(&info
, 0, sizeof(info
));
154 dmi_check_system(inv_mpu_dev_list
);
155 switch (matched_product_name
) {
156 case INV_MPU_ASUS_T100TA
:
157 ret
= asus_acpi_get_sensor_info(adev
, st
->client
,
160 /* Add more matched product processing here */
166 /* No matching DMI, so create device on INV6XX type */
167 unsigned short primary
, secondary
;
169 ret
= inv_mpu_process_acpi_config(st
->client
, &primary
,
171 if (!ret
&& secondary
) {
174 info
.addr
= secondary
;
175 strlcpy(info
.type
, dev_name(&adev
->dev
),
177 name
= strchr(info
.type
, ':');
180 strlcat(info
.type
, "-client",
183 return 0; /* no secondary addr, which is OK */
185 st
->mux_client
= i2c_new_device(st
->mux_adapter
, &info
);
194 void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state
*st
)
197 i2c_unregister_device(st
->mux_client
);
201 #include "inv_mpu_iio.h"
203 int inv_mpu_acpi_create_mux_client(struct inv_mpu6050_state
*st
)
208 void inv_mpu_acpi_delete_mux_client(struct inv_mpu6050_state
*st
)