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