GNU Linux-libre 4.19.245-gnu1
[releases.git] / drivers / iio / imu / inv_mpu6050 / inv_mpu_i2c.c
1 /*
2 * Copyright (C) 2012 Invensense, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * GNU General Public License for more details.
12 */
13
14 #include <linux/acpi.h>
15 #include <linux/delay.h>
16 #include <linux/err.h>
17 #include <linux/i2c.h>
18 #include <linux/iio/iio.h>
19 #include <linux/module.h>
20 #include <linux/of_device.h>
21 #include "inv_mpu_iio.h"
22
23 static const struct regmap_config inv_mpu_regmap_config = {
24         .reg_bits = 8,
25         .val_bits = 8,
26 };
27
28 static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id)
29 {
30         struct iio_dev *indio_dev = i2c_mux_priv(muxc);
31         struct inv_mpu6050_state *st = iio_priv(indio_dev);
32         int ret;
33
34         mutex_lock(&st->lock);
35
36         ret = inv_mpu6050_set_power_itg(st, true);
37         if (ret)
38                 goto error_unlock;
39
40         ret = regmap_write(st->map, st->reg->int_pin_cfg,
41                            st->irq_mask | INV_MPU6050_BIT_BYPASS_EN);
42
43 error_unlock:
44         mutex_unlock(&st->lock);
45
46         return ret;
47 }
48
49 static int inv_mpu6050_deselect_bypass(struct i2c_mux_core *muxc, u32 chan_id)
50 {
51         struct iio_dev *indio_dev = i2c_mux_priv(muxc);
52         struct inv_mpu6050_state *st = iio_priv(indio_dev);
53
54         mutex_lock(&st->lock);
55
56         /* It doesn't really matter if any of the calls fail */
57         regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask);
58         inv_mpu6050_set_power_itg(st, false);
59
60         mutex_unlock(&st->lock);
61
62         return 0;
63 }
64
65 static const char *inv_mpu_match_acpi_device(struct device *dev,
66                                              enum inv_devices *chip_id)
67 {
68         const struct acpi_device_id *id;
69
70         id = acpi_match_device(dev->driver->acpi_match_table, dev);
71         if (!id)
72                 return NULL;
73
74         *chip_id = (int)id->driver_data;
75
76         return dev_name(dev);
77 }
78
79 /**
80  *  inv_mpu_probe() - probe function.
81  *  @client:          i2c client.
82  *  @id:              i2c device id.
83  *
84  *  Returns 0 on success, a negative error code otherwise.
85  */
86 static int inv_mpu_probe(struct i2c_client *client,
87                          const struct i2c_device_id *id)
88 {
89         struct inv_mpu6050_state *st;
90         int result;
91         enum inv_devices chip_type;
92         struct regmap *regmap;
93         const char *name;
94
95         if (!i2c_check_functionality(client->adapter,
96                                      I2C_FUNC_SMBUS_I2C_BLOCK))
97                 return -EOPNOTSUPP;
98
99         if (client->dev.of_node) {
100                 chip_type = (enum inv_devices)
101                         of_device_get_match_data(&client->dev);
102                 name = client->name;
103         } else if (id) {
104                 chip_type = (enum inv_devices)
105                         id->driver_data;
106                 name = id->name;
107         } else if (ACPI_HANDLE(&client->dev)) {
108                 name = inv_mpu_match_acpi_device(&client->dev, &chip_type);
109                 if (!name)
110                         return -ENODEV;
111         } else {
112                 return -ENOSYS;
113         }
114
115         regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config);
116         if (IS_ERR(regmap)) {
117                 dev_err(&client->dev, "Failed to register i2c regmap %d\n",
118                         (int)PTR_ERR(regmap));
119                 return PTR_ERR(regmap);
120         }
121
122         result = inv_mpu_core_probe(regmap, client->irq, name,
123                                     NULL, chip_type);
124         if (result < 0)
125                 return result;
126
127         st = iio_priv(dev_get_drvdata(&client->dev));
128         switch (st->chip_type) {
129         case INV_ICM20608:
130         case INV_ICM20602:
131                 /* no i2c auxiliary bus on the chip */
132                 break;
133         default:
134                 /* declare i2c auxiliary bus */
135                 st->muxc = i2c_mux_alloc(client->adapter, &client->dev,
136                                          1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
137                                          inv_mpu6050_select_bypass,
138                                          inv_mpu6050_deselect_bypass);
139                 if (!st->muxc)
140                         return -ENOMEM;
141                 st->muxc->priv = dev_get_drvdata(&client->dev);
142                 result = i2c_mux_add_adapter(st->muxc, 0, 0, 0);
143                 if (result)
144                         return result;
145                 result = inv_mpu_acpi_create_mux_client(client);
146                 if (result)
147                         goto out_del_mux;
148                 break;
149         }
150
151         return 0;
152
153 out_del_mux:
154         i2c_mux_del_adapters(st->muxc);
155         return result;
156 }
157
158 static int inv_mpu_remove(struct i2c_client *client)
159 {
160         struct iio_dev *indio_dev = i2c_get_clientdata(client);
161         struct inv_mpu6050_state *st = iio_priv(indio_dev);
162
163         if (st->muxc) {
164                 inv_mpu_acpi_delete_mux_client(client);
165                 i2c_mux_del_adapters(st->muxc);
166         }
167
168         return 0;
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},
178         {"mpu6515", INV_MPU6515},
179         {"mpu9150", INV_MPU9150},
180         {"mpu9250", INV_MPU9250},
181         {"mpu9255", INV_MPU9255},
182         {"icm20608", INV_ICM20608},
183         {"icm20602", INV_ICM20602},
184         {}
185 };
186
187 MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
188
189 static const struct of_device_id inv_of_match[] = {
190         {
191                 .compatible = "invensense,mpu6050",
192                 .data = (void *)INV_MPU6050
193         },
194         {
195                 .compatible = "invensense,mpu6500",
196                 .data = (void *)INV_MPU6500
197         },
198         {
199                 .compatible = "invensense,mpu6515",
200                 .data = (void *)INV_MPU6515
201         },
202         {
203                 .compatible = "invensense,mpu9150",
204                 .data = (void *)INV_MPU9150
205         },
206         {
207                 .compatible = "invensense,mpu9250",
208                 .data = (void *)INV_MPU9250
209         },
210         {
211                 .compatible = "invensense,mpu9255",
212                 .data = (void *)INV_MPU9255
213         },
214         {
215                 .compatible = "invensense,icm20608",
216                 .data = (void *)INV_ICM20608
217         },
218         {
219                 .compatible = "invensense,icm20602",
220                 .data = (void *)INV_ICM20602
221         },
222         { }
223 };
224 MODULE_DEVICE_TABLE(of, inv_of_match);
225
226 static const struct acpi_device_id inv_acpi_match[] = {
227         {"INVN6500", INV_MPU6500},
228         { },
229 };
230
231 MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
232
233 static struct i2c_driver inv_mpu_driver = {
234         .probe          =       inv_mpu_probe,
235         .remove         =       inv_mpu_remove,
236         .id_table       =       inv_mpu_id,
237         .driver = {
238                 .of_match_table = inv_of_match,
239                 .acpi_match_table = ACPI_PTR(inv_acpi_match),
240                 .name   =       "inv-mpu6050-i2c",
241                 .pm     =       &inv_mpu_pmops,
242         },
243 };
244
245 module_i2c_driver(inv_mpu_driver);
246
247 MODULE_AUTHOR("Invensense Corporation");
248 MODULE_DESCRIPTION("Invensense device MPU6050 driver");
249 MODULE_LICENSE("GPL");