1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2012 Invensense, Inc.
4 */
5
6 #include <linux/delay.h>
7 #include <linux/err.h>
8 #include <linux/i2c.h>
9 #include <linux/iio/iio.h>
10 #include <linux/mod_devicetable.h>
11 #include <linux/module.h>
12 #include <linux/property.h>
13
14 #include "inv_mpu_iio.h"
15
16 static const struct regmap_config inv_mpu_regmap_config = {
17 .reg_bits = 8,
18 .val_bits = 8,
19 };
20
inv_mpu6050_select_bypass(struct i2c_mux_core * muxc,u32 chan_id)21 static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
22 {
23 return 0;
24 }
25
inv_mpu_i2c_aux_bus(struct device * dev)26 static bool inv_mpu_i2c_aux_bus(struct device *dev)
27 {
28 struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev));
29
30 switch (st->chip_type) {
31 case INV_ICM20608:
32 case INV_ICM20608D:
33 case INV_ICM20609:
34 case INV_ICM20689:
35 case INV_ICM20600:
36 case INV_ICM20602:
37 case INV_IAM20380:
38 case INV_IAM20680:
39 /* no i2c auxiliary bus on the chip */
40 return false;
41 case INV_MPU9150:
42 case INV_MPU9250:
43 case INV_MPU9255:
44 if (st->magn_disabled)
45 return true;
46 else
47 return false;
48 default:
49 return true;
50 }
51 }
52
inv_mpu_i2c_aux_setup(struct iio_dev * indio_dev)53 static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev)
54 {
55 struct inv_mpu6050_state *st = iio_priv(indio_dev);
56 struct device *dev = indio_dev->dev.parent;
57 struct fwnode_handle *mux_node;
58 int ret;
59
60 /*
61 * MPU9xxx magnetometer support requires to disable i2c auxiliary bus.
62 * To ensure backward compatibility with existing setups, do not disable
63 * i2c auxiliary bus if it used.
64 * Check for i2c-gate node in devicetree and set magnetometer disabled.
65 * Only MPU6500 is supported by ACPI, no need to check.
66 */
67 switch (st->chip_type) {
68 case INV_MPU9150:
69 case INV_MPU9250:
70 case INV_MPU9255:
71 mux_node = device_get_named_child_node(dev, "i2c-gate");
72 if (mux_node != NULL) {
73 st->magn_disabled = true;
74 dev_warn(dev, "disable internal use of magnetometer\n");
75 }
76 fwnode_handle_put(mux_node);
77 break;
78 default:
79 break;
80 }
81
82 /* enable i2c bypass when using i2c auxiliary bus */
83 if (inv_mpu_i2c_aux_bus(dev)) {
84 ret = regmap_write(st->map, st->reg->int_pin_cfg,
85 st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);
86 if (ret)
87 return ret;
88 }
89
90 return 0;
91 }
92
93 /**
94 * inv_mpu_probe() - probe function.
95 * @client: i2c client.
96 *
97 * Returns 0 on success, a negative error code otherwise.
98 */
inv_mpu_probe(struct i2c_client * client)99 static int inv_mpu_probe(struct i2c_client *client)
100 {
101 const struct i2c_device_id *id = i2c_client_get_device_id(client);
102 const void *match;
103 struct inv_mpu6050_state *st;
104 int result;
105 enum inv_devices chip_type;
106 struct regmap *regmap;
107 const char *name;
108
109 if (!i2c_check_functionality(client->adapter,
110 I2C_FUNC_SMBUS_I2C_BLOCK))
111 return -EOPNOTSUPP;
112
113 match = device_get_match_data(&client->dev);
114 if (match) {
115 chip_type = (uintptr_t)match;
116 name = client->name;
117 } else if (id) {
118 chip_type = (enum inv_devices)
119 id->driver_data;
120 name = id->name;
121 } else {
122 return -ENOSYS;
123 }
124
125 regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config);
126 if (IS_ERR(regmap)) {
127 dev_err(&client->dev, "Failed to register i2c regmap: %pe\n",
128 regmap);
129 return PTR_ERR(regmap);
130 }
131
132 result = inv_mpu_core_probe(regmap, client->irq, name,
133 inv_mpu_i2c_aux_setup, chip_type);
134 if (result < 0)
135 return result;
136
137 st = iio_priv(dev_get_drvdata(&client->dev));
138 if (inv_mpu_i2c_aux_bus(&client->dev)) {
139 /* declare i2c auxiliary bus */
140 st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
141 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
142 inv_mpu6050_select_bypass, NULL);
143 if (!st->muxc)
144 return -ENOMEM;
145 st->muxc->priv = dev_get_drvdata(&client->dev);
146 result = i2c_mux_add_adapter(st->muxc, 0, 0);
147 if (result)
148 return result;
149 result = inv_mpu_acpi_create_mux_client(client);
150 if (result)
151 goto out_del_mux;
152 }
153
154 return 0;
155
156 out_del_mux:
157 i2c_mux_del_adapters(st->muxc);
158 return result;
159 }
160
inv_mpu_remove(struct i2c_client * client)161 static void inv_mpu_remove(struct i2c_client *client)
162 {
163 struct iio_dev *indio_dev = i2c_get_clientdata(client);
164 struct inv_mpu6050_state *st = iio_priv(indio_dev);
165
166 if (st->muxc) {
167 inv_mpu_acpi_delete_mux_client(client);
168 i2c_mux_del_adapters(st->muxc);
169 }
170 }
171
172 /*
173 * device id table is used to identify what device can be
174 * supported by this driver
175 */
176 static const struct i2c_device_id inv_mpu_id[] = {
177 {"mpu6050", INV_MPU6050},
178 {"mpu6500", INV_MPU6500},
179 {"mpu6515", INV_MPU6515},
180 {"mpu6880", INV_MPU6880},
181 {"mpu9150", INV_MPU9150},
182 {"mpu9250", INV_MPU9250},
183 {"mpu9255", INV_MPU9255},
184 {"icm20608", INV_ICM20608},
185 {"icm20608d", INV_ICM20608D},
186 {"icm20609", INV_ICM20609},
187 {"icm20689", INV_ICM20689},
188 {"icm20600", INV_ICM20600},
189 {"icm20602", INV_ICM20602},
190 {"icm20690", INV_ICM20690},
191 {"iam20380", INV_IAM20380},
192 {"iam20680", INV_IAM20680},
193 {"iam20680hp", INV_IAM20680HP},
194 {"iam20680ht", INV_IAM20680HT},
195 {}
196 };
197
198 MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
199
200 static const struct of_device_id inv_of_match[] = {
201 {
202 .compatible = "invensense,mpu6050",
203 .data = (void *)INV_MPU6050
204 },
205 {
206 .compatible = "invensense,mpu6500",
207 .data = (void *)INV_MPU6500
208 },
209 {
210 .compatible = "invensense,mpu6515",
211 .data = (void *)INV_MPU6515
212 },
213 {
214 .compatible = "invensense,mpu6880",
215 .data = (void *)INV_MPU6880
216 },
217 {
218 .compatible = "invensense,mpu9150",
219 .data = (void *)INV_MPU9150
220 },
221 {
222 .compatible = "invensense,mpu9250",
223 .data = (void *)INV_MPU9250
224 },
225 {
226 .compatible = "invensense,mpu9255",
227 .data = (void *)INV_MPU9255
228 },
229 {
230 .compatible = "invensense,icm20608",
231 .data = (void *)INV_ICM20608
232 },
233 {
234 .compatible = "invensense,icm20608d",
235 .data = (void *)INV_ICM20608D
236 },
237 {
238 .compatible = "invensense,icm20609",
239 .data = (void *)INV_ICM20609
240 },
241 {
242 .compatible = "invensense,icm20689",
243 .data = (void *)INV_ICM20689
244 },
245 {
246 .compatible = "invensense,icm20600",
247 .data = (void *)INV_ICM20600
248 },
249 {
250 .compatible = "invensense,icm20602",
251 .data = (void *)INV_ICM20602
252 },
253 {
254 .compatible = "invensense,icm20690",
255 .data = (void *)INV_ICM20690
256 },
257 {
258 .compatible = "invensense,iam20380",
259 .data = (void *)INV_IAM20380
260 },
261 {
262 .compatible = "invensense,iam20680",
263 .data = (void *)INV_IAM20680
264 },
265 {
266 .compatible = "invensense,iam20680hp",
267 .data = (void *)INV_IAM20680HP
268 },
269 {
270 .compatible = "invensense,iam20680ht",
271 .data = (void *)INV_IAM20680HT
272 },
273 { }
274 };
275 MODULE_DEVICE_TABLE(of, inv_of_match);
276
277 static const struct acpi_device_id inv_acpi_match[] = {
278 {"INVN6500", INV_MPU6500},
279 { },
280 };
281 MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
282
283 static struct i2c_driver inv_mpu_driver = {
284 .probe = inv_mpu_probe,
285 .remove = inv_mpu_remove,
286 .id_table = inv_mpu_id,
287 .driver = {
288 .of_match_table = inv_of_match,
289 .acpi_match_table = inv_acpi_match,
290 .name = "inv-mpu6050-i2c",
291 .pm = pm_ptr(&inv_mpu_pmops),
292 },
293 };
294
295 module_i2c_driver(inv_mpu_driver);
296
297 MODULE_AUTHOR("Invensense Corporation");
298 MODULE_DESCRIPTION("Invensense device MPU6050 driver");
299 MODULE_LICENSE("GPL");
300 MODULE_IMPORT_NS("IIO_MPU6050");
301