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
)
94 struct acpi_resource_i2c_serialbus
*sb
;
97 if (i2c_acpi_get_i2c_resource(ares
, &sb
)) {
99 *addr
|= (sb
->slave_address
<< 16);
101 *addr
= sb
->slave_address
;
104 /* Tell the ACPI core that we already copied this address */
108 static int inv_mpu_process_acpi_config(struct i2c_client
*client
,
109 unsigned short *primary_addr
,
110 unsigned short *secondary_addr
)
112 const struct acpi_device_id
*id
;
113 struct acpi_device
*adev
;
115 LIST_HEAD(resources
);
118 id
= acpi_match_device(client
->dev
.driver
->acpi_match_table
,
123 adev
= ACPI_COMPANION(&client
->dev
);
127 ret
= acpi_dev_get_resources(adev
, &resources
,
128 acpi_i2c_check_resource
, &i2c_addr
);
132 acpi_dev_free_resource_list(&resources
);
133 *primary_addr
= i2c_addr
& 0x0000ffff;
134 *secondary_addr
= (i2c_addr
& 0xffff0000) >> 16;
139 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
141 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
143 st
->mux_client
= NULL
;
144 if (ACPI_HANDLE(&client
->dev
)) {
145 struct i2c_board_info info
;
146 struct acpi_device
*adev
;
149 adev
= ACPI_COMPANION(&client
->dev
);
150 memset(&info
, 0, sizeof(info
));
152 dmi_check_system(inv_mpu_dev_list
);
153 switch (matched_product_name
) {
154 case INV_MPU_ASUS_T100TA
:
155 ret
= asus_acpi_get_sensor_info(adev
, client
,
158 /* Add more matched product processing here */
164 /* No matching DMI, so create device on INV6XX type */
165 unsigned short primary
, secondary
;
167 ret
= inv_mpu_process_acpi_config(client
, &primary
,
169 if (!ret
&& secondary
) {
172 info
.addr
= secondary
;
173 strlcpy(info
.type
, dev_name(&adev
->dev
),
175 name
= strchr(info
.type
, ':');
178 strlcat(info
.type
, "-client",
181 return 0; /* no secondary addr, which is OK */
183 st
->mux_client
= i2c_new_device(st
->muxc
->adapter
[0], &info
);
191 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)
193 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
195 i2c_unregister_device(st
->mux_client
);
199 #include "inv_mpu_iio.h"
201 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
206 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)