WIP FPC-III support
[linux/fpc-iii.git] / drivers / iio / imu / inv_mpu6050 / inv_mpu_acpi.c
blobf8f0cf716bc6b233004892dd2891e5be9e88de51
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * inv_mpu_acpi: ACPI processing for creating client devices
4 * Copyright (c) 2015, Intel Corporation.
5 */
7 #ifdef CONFIG_ACPI
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 {
16 INV_MPU_NOT_MATCHED,
17 INV_MPU_ASUS_T100TA,
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;
26 return 0;
29 static const struct dmi_system_id inv_mpu_dev_list[] = {
31 .callback = asus_t100_matched,
32 .ident = "Asus Transformer Book T100",
33 .matches = {
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};
48 int i;
49 acpi_status status;
50 union acpi_object *cpm;
51 int ret;
53 status = acpi_evaluate_object(adev->handle, "CNF0", NULL, &buffer);
54 if (ACPI_FAILURE(status))
55 return -ENODEV;
57 cpm = buffer.pointer;
58 for (i = 0; i < cpm->package.count; ++i) {
59 union acpi_object *elem;
60 int j;
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,
69 sizeof(info->type));
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);
81 return ret;
84 static int acpi_i2c_check_resource(struct acpi_resource *ares, void *data)
86 struct acpi_resource_i2c_serialbus *sb;
87 u32 *addr = data;
89 if (i2c_acpi_get_i2c_resource(ares, &sb)) {
90 if (*addr)
91 *addr |= (sb->slave_address << 16);
92 else
93 *addr = sb->slave_address;
96 /* Tell the ACPI core that we already copied this address */
97 return 1;
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;
106 u32 i2c_addr = 0;
107 LIST_HEAD(resources);
108 int ret;
110 id = acpi_match_device(client->dev.driver->acpi_match_table,
111 &client->dev);
112 if (!id)
113 return -ENODEV;
115 ret = acpi_dev_get_resources(adev, &resources,
116 acpi_i2c_check_resource, &i2c_addr);
117 if (ret < 0)
118 return ret;
120 acpi_dev_free_resource_list(&resources);
121 *primary_addr = i2c_addr & 0x0000ffff;
122 *secondary_addr = (i2c_addr & 0xffff0000) >> 16;
124 return 0;
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;
136 int ret = -1;
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,
145 &info);
146 break;
147 /* Add more matched product processing here */
148 default:
149 break;
152 if (ret < 0) {
153 /* No matching DMI, so create device on INV6XX type */
154 unsigned short primary, secondary;
156 ret = inv_mpu_process_acpi_config(client, &primary,
157 &secondary);
158 if (!ret && secondary) {
159 char *name;
161 info.addr = secondary;
162 strlcpy(info.type, dev_name(&adev->dev),
163 sizeof(info.type));
164 name = strchr(info.type, ':');
165 if (name)
166 *name = '\0';
167 strlcat(info.type, "-client",
168 sizeof(info.type));
169 } else
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;
178 return 0;
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);
187 #else
189 #include "inv_mpu_iio.h"
191 int inv_mpu_acpi_create_mux_client(struct i2c_client *client)
193 return 0;
196 void inv_mpu_acpi_delete_mux_client(struct i2c_client *client)
199 #endif