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 struct acpi_device
*adev
= ACPI_COMPANION(&client
->dev
);
105 const struct acpi_device_id
*id
;
107 LIST_HEAD(resources
);
110 id
= acpi_match_device(client
->dev
.driver
->acpi_match_table
,
115 ret
= acpi_dev_get_resources(adev
, &resources
,
116 acpi_i2c_check_resource
, &i2c_addr
);
120 acpi_dev_free_resource_list(&resources
);
121 *primary_addr
= i2c_addr
& 0x0000ffff;
122 *secondary_addr
= (i2c_addr
& 0xffff0000) >> 16;
127 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
129 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
131 st
->mux_client
= NULL
;
132 if (ACPI_HANDLE(&client
->dev
)) {
133 struct i2c_board_info info
;
134 struct i2c_client
*mux_client
;
135 struct acpi_device
*adev
;
138 adev
= ACPI_COMPANION(&client
->dev
);
139 memset(&info
, 0, sizeof(info
));
141 dmi_check_system(inv_mpu_dev_list
);
142 switch (matched_product_name
) {
143 case INV_MPU_ASUS_T100TA
:
144 ret
= asus_acpi_get_sensor_info(adev
, client
,
147 /* Add more matched product processing here */
153 /* No matching DMI, so create device on INV6XX type */
154 unsigned short primary
, secondary
;
156 ret
= inv_mpu_process_acpi_config(client
, &primary
,
158 if (!ret
&& secondary
) {
161 info
.addr
= secondary
;
162 strlcpy(info
.type
, dev_name(&adev
->dev
),
164 name
= strchr(info
.type
, ':');
167 strlcat(info
.type
, "-client",
170 return 0; /* no secondary addr, which is OK */
172 mux_client
= i2c_new_client_device(st
->muxc
->adapter
[0], &info
);
173 if (IS_ERR(mux_client
))
174 return PTR_ERR(mux_client
);
175 st
->mux_client
= mux_client
;
181 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)
183 struct inv_mpu6050_state
*st
= iio_priv(dev_get_drvdata(&client
->dev
));
185 i2c_unregister_device(st
->mux_client
);
189 #include "inv_mpu_iio.h"
191 int inv_mpu_acpi_create_mux_client(struct i2c_client
*client
)
196 void inv_mpu_acpi_delete_mux_client(struct i2c_client
*client
)