.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * 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 | 4 | */ |
---|
13 | 5 | |
---|
14 | 6 | #include <linux/acpi.h> |
---|
.. | .. |
---|
18 | 10 | #include <linux/iio/iio.h> |
---|
19 | 11 | #include <linux/module.h> |
---|
20 | 12 | #include <linux/of_device.h> |
---|
| 13 | +#include <linux/property.h> |
---|
21 | 14 | #include "inv_mpu_iio.h" |
---|
22 | 15 | |
---|
23 | 16 | static const struct regmap_config inv_mpu_regmap_config = { |
---|
.. | .. |
---|
27 | 20 | |
---|
28 | 21 | static int inv_mpu6050_select_bypass(struct i2c_mux_core *muxc, u32 chan_id) |
---|
29 | 22 | { |
---|
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 | 23 | return 0; |
---|
63 | 24 | } |
---|
64 | 25 | |
---|
65 | | -static const char *inv_mpu_match_acpi_device(struct device *dev, |
---|
66 | | - enum inv_devices *chip_id) |
---|
| 26 | +static bool inv_mpu_i2c_aux_bus(struct device *dev) |
---|
67 | 27 | { |
---|
68 | | - const struct acpi_device_id *id; |
---|
| 28 | + struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev)); |
---|
69 | 29 | |
---|
70 | | - id = acpi_match_device(dev->driver->acpi_match_table, dev); |
---|
71 | | - if (!id) |
---|
72 | | - return NULL; |
---|
| 30 | + switch (st->chip_type) { |
---|
| 31 | + case INV_ICM20608: |
---|
| 32 | + case INV_ICM20609: |
---|
| 33 | + case INV_ICM20689: |
---|
| 34 | + case INV_ICM20602: |
---|
| 35 | + case INV_IAM20680: |
---|
| 36 | + /* no i2c auxiliary bus on the chip */ |
---|
| 37 | + return false; |
---|
| 38 | + case INV_MPU9150: |
---|
| 39 | + case INV_MPU9250: |
---|
| 40 | + case INV_MPU9255: |
---|
| 41 | + if (st->magn_disabled) |
---|
| 42 | + return true; |
---|
| 43 | + else |
---|
| 44 | + return false; |
---|
| 45 | + default: |
---|
| 46 | + return true; |
---|
| 47 | + } |
---|
| 48 | +} |
---|
73 | 49 | |
---|
74 | | - *chip_id = (int)id->driver_data; |
---|
| 50 | +static int inv_mpu_i2c_aux_setup(struct iio_dev *indio_dev) |
---|
| 51 | +{ |
---|
| 52 | + struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
| 53 | + struct device *dev = indio_dev->dev.parent; |
---|
| 54 | + struct device_node *mux_node; |
---|
| 55 | + int ret; |
---|
75 | 56 | |
---|
76 | | - return dev_name(dev); |
---|
| 57 | + /* |
---|
| 58 | + * MPU9xxx magnetometer support requires to disable i2c auxiliary bus. |
---|
| 59 | + * To ensure backward compatibility with existing setups, do not disable |
---|
| 60 | + * i2c auxiliary bus if it used. |
---|
| 61 | + * Check for i2c-gate node in devicetree and set magnetometer disabled. |
---|
| 62 | + * Only MPU6500 is supported by ACPI, no need to check. |
---|
| 63 | + */ |
---|
| 64 | + switch (st->chip_type) { |
---|
| 65 | + case INV_MPU9150: |
---|
| 66 | + case INV_MPU9250: |
---|
| 67 | + case INV_MPU9255: |
---|
| 68 | + mux_node = of_get_child_by_name(dev->of_node, "i2c-gate"); |
---|
| 69 | + if (mux_node != NULL) { |
---|
| 70 | + st->magn_disabled = true; |
---|
| 71 | + dev_warn(dev, "disable internal use of magnetometer\n"); |
---|
| 72 | + } |
---|
| 73 | + of_node_put(mux_node); |
---|
| 74 | + break; |
---|
| 75 | + default: |
---|
| 76 | + break; |
---|
| 77 | + } |
---|
| 78 | + |
---|
| 79 | + /* enable i2c bypass when using i2c auxiliary bus */ |
---|
| 80 | + if (inv_mpu_i2c_aux_bus(dev)) { |
---|
| 81 | + ret = regmap_write(st->map, st->reg->int_pin_cfg, |
---|
| 82 | + st->irq_mask | INV_MPU6050_BIT_BYPASS_EN); |
---|
| 83 | + if (ret) |
---|
| 84 | + return ret; |
---|
| 85 | + } |
---|
| 86 | + |
---|
| 87 | + return 0; |
---|
77 | 88 | } |
---|
78 | 89 | |
---|
79 | 90 | /** |
---|
.. | .. |
---|
86 | 97 | static int inv_mpu_probe(struct i2c_client *client, |
---|
87 | 98 | const struct i2c_device_id *id) |
---|
88 | 99 | { |
---|
| 100 | + const void *match; |
---|
89 | 101 | struct inv_mpu6050_state *st; |
---|
90 | 102 | int result; |
---|
91 | 103 | enum inv_devices chip_type; |
---|
.. | .. |
---|
96 | 108 | I2C_FUNC_SMBUS_I2C_BLOCK)) |
---|
97 | 109 | return -EOPNOTSUPP; |
---|
98 | 110 | |
---|
99 | | - if (client->dev.of_node) { |
---|
100 | | - chip_type = (enum inv_devices) |
---|
101 | | - of_device_get_match_data(&client->dev); |
---|
| 111 | + match = device_get_match_data(&client->dev); |
---|
| 112 | + if (match) { |
---|
| 113 | + chip_type = (enum inv_devices)match; |
---|
102 | 114 | name = client->name; |
---|
103 | 115 | } else if (id) { |
---|
104 | 116 | chip_type = (enum inv_devices) |
---|
105 | 117 | id->driver_data; |
---|
106 | 118 | 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 | 119 | } else { |
---|
112 | 120 | return -ENOSYS; |
---|
113 | 121 | } |
---|
114 | 122 | |
---|
115 | 123 | regmap = devm_regmap_init_i2c(client, &inv_mpu_regmap_config); |
---|
116 | 124 | if (IS_ERR(regmap)) { |
---|
117 | | - dev_err(&client->dev, "Failed to register i2c regmap %d\n", |
---|
118 | | - (int)PTR_ERR(regmap)); |
---|
| 125 | + dev_err(&client->dev, "Failed to register i2c regmap: %pe\n", |
---|
| 126 | + regmap); |
---|
119 | 127 | return PTR_ERR(regmap); |
---|
120 | 128 | } |
---|
121 | 129 | |
---|
122 | 130 | result = inv_mpu_core_probe(regmap, client->irq, name, |
---|
123 | | - NULL, chip_type); |
---|
| 131 | + inv_mpu_i2c_aux_setup, chip_type); |
---|
124 | 132 | if (result < 0) |
---|
125 | 133 | return result; |
---|
126 | 134 | |
---|
127 | 135 | 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: |
---|
| 136 | + if (inv_mpu_i2c_aux_bus(&client->dev)) { |
---|
134 | 137 | /* declare i2c auxiliary bus */ |
---|
135 | 138 | st->muxc = i2c_mux_alloc(client->adapter, &client->dev, |
---|
136 | 139 | 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, |
---|
137 | | - inv_mpu6050_select_bypass, |
---|
138 | | - inv_mpu6050_deselect_bypass); |
---|
| 140 | + inv_mpu6050_select_bypass, NULL); |
---|
139 | 141 | if (!st->muxc) |
---|
140 | 142 | return -ENOMEM; |
---|
141 | 143 | st->muxc->priv = dev_get_drvdata(&client->dev); |
---|
.. | .. |
---|
145 | 147 | result = inv_mpu_acpi_create_mux_client(client); |
---|
146 | 148 | if (result) |
---|
147 | 149 | goto out_del_mux; |
---|
148 | | - break; |
---|
149 | 150 | } |
---|
150 | 151 | |
---|
151 | 152 | return 0; |
---|
.. | .. |
---|
180 | 181 | {"mpu9250", INV_MPU9250}, |
---|
181 | 182 | {"mpu9255", INV_MPU9255}, |
---|
182 | 183 | {"icm20608", INV_ICM20608}, |
---|
| 184 | + {"icm20609", INV_ICM20609}, |
---|
| 185 | + {"icm20689", INV_ICM20689}, |
---|
183 | 186 | {"icm20602", INV_ICM20602}, |
---|
| 187 | + {"icm20690", INV_ICM20690}, |
---|
| 188 | + {"iam20680", INV_IAM20680}, |
---|
184 | 189 | {} |
---|
185 | 190 | }; |
---|
186 | 191 | |
---|
.. | .. |
---|
216 | 221 | .data = (void *)INV_ICM20608 |
---|
217 | 222 | }, |
---|
218 | 223 | { |
---|
| 224 | + .compatible = "invensense,icm20609", |
---|
| 225 | + .data = (void *)INV_ICM20609 |
---|
| 226 | + }, |
---|
| 227 | + { |
---|
| 228 | + .compatible = "invensense,icm20689", |
---|
| 229 | + .data = (void *)INV_ICM20689 |
---|
| 230 | + }, |
---|
| 231 | + { |
---|
219 | 232 | .compatible = "invensense,icm20602", |
---|
220 | 233 | .data = (void *)INV_ICM20602 |
---|
221 | 234 | }, |
---|
| 235 | + { |
---|
| 236 | + .compatible = "invensense,icm20690", |
---|
| 237 | + .data = (void *)INV_ICM20690 |
---|
| 238 | + }, |
---|
| 239 | + { |
---|
| 240 | + .compatible = "invensense,iam20680", |
---|
| 241 | + .data = (void *)INV_IAM20680 |
---|
| 242 | + }, |
---|
222 | 243 | { } |
---|
223 | 244 | }; |
---|
224 | 245 | MODULE_DEVICE_TABLE(of, inv_of_match); |
---|