1 // SPDX-License-Identifier: GPL-2.0-only
3 * inv_mpu_acpi: ACPI processing for creating client devices
4 * Copyright (c) 2015, Intel Corporation.
9 #include <linux/kernel.h>
10 #include <linux/i2c.h>
11 #include <linux/dmi.h>
12 #include <linux/acpi.h>
13 #include "inv_mpu_iio.h"
15 enum inv_mpu_product_name
{
20 static enum inv_mpu_product_name matched_product_name
;
22 static int __init
asus_t100_matched(const struct dmi_system_id
*d
)
24 matched_product_name
= INV_MPU_ASUS_T100TA
;
29 static const struct dmi_system_id inv_mpu_dev_list
[] = {
31 .callback
= asus_t100_matched
,
32 .ident
= "Asus Transformer Book T100",
34 DMI_MATCH(DMI_SYS_VENDOR
, "ASUSTeK COMPUTER INC"),
35 DMI_MATCH(DMI_PRODUCT_NAME
, "T100TA"),
36 DMI_MATCH(DMI_PRODUCT_VERSION
, "1.0"),
39 /* Add more matching tables here..*/
43 static int asus_acpi_get_sensor_info(struct acpi_device
*adev
,
44 struct i2c_client
*client
,
45 struct i2c_board_info
*info
)
47 struct acpi_buffer buffer
= {ACPI_ALLOCATE_BUFFER
, NULL
};
50 union acpi_object
*cpm
;
53 status
= acpi_evaluate_object(adev
->handle
, "CNF0", NULL
, &buffer
);
54 if (ACPI_FAILURE(status
))
58 for (i
= 0; i
< cpm
->package
.count
; ++i
) {
59 union acpi_object
*elem
;
62 elem
= &cpm
->package
.elements
[i
];
63 for (j
= 0; j
< elem
->package
.count
; ++j
) {
64 union acpi_object
*sub_elem
;
66 sub_elem
= &elem
->package
.elements
[j
];
67 if (sub_elem
->type
== ACPI_TYPE_STRING
)
68 strlcpy(info
->type
, sub_elem
->string
.pointer
,
70 else if (sub_elem
->type
== ACPI_TYPE_INTEGER
) {
71 if (sub_elem
->integer
.value
!= client
->addr
) {
72 info
->addr
= sub_elem
->integer
.value
;
73 break; /* Not a MPU6500 primary */
78 ret
= cpm
->package
.count
;
79 kfree(buffer
.pointer
);
84 static int acpi_i2c_check_resource(struct acpi_resource
*ares
, void *data
)
86 struct acpi_resource_i2c_serialbus
*sb
;
89 if (i2c_acpi_get_i2c_resource(ares
, &sb
)) {
91 *addr
|= (sb
->slave_address
<< 16);
93 *addr
= sb
->slave_address
;
96 /* Tell the ACPI core that we already copied this address */
100 static int inv_mpu_process_acpi_config(struct i2c_client
*client
,
101 unsigned short *primary_addr
,
102 unsigned short *secondary_addr
)
104 const struct acpi_device_id
*id
;
105 struct acpi_device
*adev
;
107 LIST_HEAD(resources
);
110 id
= acpi_match_device(client
->dev
.driver
->acpi_match_table
,
115 adev
= ACPI_COMPANION(&client
->dev
);
119 ret
= acpi_dev_get_resources(adev
, &resources
,
120 acpi_i2c_check_resource
, &i2c_addr
);
124 acpi_dev_free_resource_list(&resources
);
125 *primary_addr
= i2c_addr
& 0x0000ffff;
126 *secondary_addr
= (i2c_addr
& 0xffff0000) >> 16;
131 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
133 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
135 st
->mux_client
= NULL
;
136 if (ACPI_HANDLE(&client
->dev
)) {
137 struct i2c_board_info info
;
138 struct acpi_device
*adev
;
141 adev
= ACPI_COMPANION(&client
->dev
);
142 memset(&info
, 0, sizeof(info
));
144 dmi_check_system(inv_mpu_dev_list
);
145 switch (matched_product_name
) {
146 case INV_MPU_ASUS_T100TA
:
147 ret
= asus_acpi_get_sensor_info(adev
, client
,
150 /* Add more matched product processing here */
156 /* No matching DMI, so create device on INV6XX type */
157 unsigned short primary
, secondary
;
159 ret
= inv_mpu_process_acpi_config(client
, &primary
,
161 if (!ret
&& secondary
) {
164 info
.addr
= secondary
;
165 strlcpy(info
.type
, dev_name(&adev
->dev
),
167 name
= strchr(info
.type
, ':');
170 strlcat(info
.type
, "-client",
173 return 0; /* no secondary addr, which is OK */
175 st
->mux_client
= i2c_new_device(st
->muxc
->adapter
[0], &info
);
183 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)
185 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
187 i2c_unregister_device(st
->mux_client
);
191 #include "inv_mpu_iio.h"
193 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
198 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)