.. | .. |
---|
| 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/module.h> |
---|
.. | .. |
---|
23 | 15 | #include <linux/iio/iio.h> |
---|
24 | 16 | #include <linux/acpi.h> |
---|
25 | 17 | #include <linux/platform_device.h> |
---|
| 18 | +#include <linux/regulator/consumer.h> |
---|
| 19 | +#include <linux/pm.h> |
---|
| 20 | +#include <linux/pm_runtime.h> |
---|
26 | 21 | #include "inv_mpu_iio.h" |
---|
| 22 | +#include "inv_mpu_magn.h" |
---|
27 | 23 | |
---|
28 | 24 | /* |
---|
29 | 25 | * this is the gyro scale translated from dynamic range plus/minus |
---|
.. | .. |
---|
105 | 101 | }; |
---|
106 | 102 | |
---|
107 | 103 | static const struct inv_mpu6050_chip_config chip_config_6050 = { |
---|
| 104 | + .clk = INV_CLK_INTERNAL, |
---|
108 | 105 | .fsr = INV_MPU6050_FSR_2000DPS, |
---|
109 | 106 | .lpf = INV_MPU6050_FILTER_20HZ, |
---|
110 | | - .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE), |
---|
| 107 | + .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(50), |
---|
| 108 | + .gyro_en = true, |
---|
| 109 | + .accl_en = true, |
---|
| 110 | + .temp_en = true, |
---|
| 111 | + .magn_en = false, |
---|
111 | 112 | .gyro_fifo_enable = false, |
---|
112 | 113 | .accl_fifo_enable = false, |
---|
| 114 | + .temp_fifo_enable = false, |
---|
| 115 | + .magn_fifo_enable = false, |
---|
| 116 | + .accl_fs = INV_MPU6050_FS_02G, |
---|
| 117 | + .user_ctrl = 0, |
---|
| 118 | +}; |
---|
| 119 | + |
---|
| 120 | +static const struct inv_mpu6050_chip_config chip_config_6500 = { |
---|
| 121 | + .clk = INV_CLK_PLL, |
---|
| 122 | + .fsr = INV_MPU6050_FSR_2000DPS, |
---|
| 123 | + .lpf = INV_MPU6050_FILTER_20HZ, |
---|
| 124 | + .divider = INV_MPU6050_FIFO_RATE_TO_DIVIDER(50), |
---|
| 125 | + .gyro_en = true, |
---|
| 126 | + .accl_en = true, |
---|
| 127 | + .temp_en = true, |
---|
| 128 | + .magn_en = false, |
---|
| 129 | + .gyro_fifo_enable = false, |
---|
| 130 | + .accl_fifo_enable = false, |
---|
| 131 | + .temp_fifo_enable = false, |
---|
| 132 | + .magn_fifo_enable = false, |
---|
113 | 133 | .accl_fs = INV_MPU6050_FS_02G, |
---|
114 | 134 | .user_ctrl = 0, |
---|
115 | 135 | }; |
---|
.. | .. |
---|
128 | 148 | .whoami = INV_MPU6500_WHOAMI_VALUE, |
---|
129 | 149 | .name = "MPU6500", |
---|
130 | 150 | .reg = ®_set_6500, |
---|
131 | | - .config = &chip_config_6050, |
---|
| 151 | + .config = &chip_config_6500, |
---|
132 | 152 | .fifo_size = 512, |
---|
133 | 153 | .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, |
---|
134 | 154 | }, |
---|
.. | .. |
---|
136 | 156 | .whoami = INV_MPU6515_WHOAMI_VALUE, |
---|
137 | 157 | .name = "MPU6515", |
---|
138 | 158 | .reg = ®_set_6500, |
---|
139 | | - .config = &chip_config_6050, |
---|
| 159 | + .config = &chip_config_6500, |
---|
140 | 160 | .fifo_size = 512, |
---|
141 | 161 | .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, |
---|
142 | 162 | }, |
---|
.. | .. |
---|
160 | 180 | .whoami = INV_MPU9250_WHOAMI_VALUE, |
---|
161 | 181 | .name = "MPU9250", |
---|
162 | 182 | .reg = ®_set_6500, |
---|
163 | | - .config = &chip_config_6050, |
---|
| 183 | + .config = &chip_config_6500, |
---|
164 | 184 | .fifo_size = 512, |
---|
165 | 185 | .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, |
---|
166 | 186 | }, |
---|
.. | .. |
---|
168 | 188 | .whoami = INV_MPU9255_WHOAMI_VALUE, |
---|
169 | 189 | .name = "MPU9255", |
---|
170 | 190 | .reg = ®_set_6500, |
---|
171 | | - .config = &chip_config_6050, |
---|
| 191 | + .config = &chip_config_6500, |
---|
172 | 192 | .fifo_size = 512, |
---|
173 | 193 | .temp = {INV_MPU6500_TEMP_OFFSET, INV_MPU6500_TEMP_SCALE}, |
---|
174 | 194 | }, |
---|
.. | .. |
---|
176 | 196 | .whoami = INV_ICM20608_WHOAMI_VALUE, |
---|
177 | 197 | .name = "ICM20608", |
---|
178 | 198 | .reg = ®_set_6500, |
---|
179 | | - .config = &chip_config_6050, |
---|
| 199 | + .config = &chip_config_6500, |
---|
180 | 200 | .fifo_size = 512, |
---|
| 201 | + .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, |
---|
| 202 | + }, |
---|
| 203 | + { |
---|
| 204 | + .whoami = INV_ICM20609_WHOAMI_VALUE, |
---|
| 205 | + .name = "ICM20609", |
---|
| 206 | + .reg = ®_set_6500, |
---|
| 207 | + .config = &chip_config_6500, |
---|
| 208 | + .fifo_size = 4 * 1024, |
---|
| 209 | + .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, |
---|
| 210 | + }, |
---|
| 211 | + { |
---|
| 212 | + .whoami = INV_ICM20689_WHOAMI_VALUE, |
---|
| 213 | + .name = "ICM20689", |
---|
| 214 | + .reg = ®_set_6500, |
---|
| 215 | + .config = &chip_config_6500, |
---|
| 216 | + .fifo_size = 4 * 1024, |
---|
181 | 217 | .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, |
---|
182 | 218 | }, |
---|
183 | 219 | { |
---|
184 | 220 | .whoami = INV_ICM20602_WHOAMI_VALUE, |
---|
185 | 221 | .name = "ICM20602", |
---|
186 | 222 | .reg = ®_set_icm20602, |
---|
187 | | - .config = &chip_config_6050, |
---|
| 223 | + .config = &chip_config_6500, |
---|
188 | 224 | .fifo_size = 1008, |
---|
| 225 | + .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, |
---|
| 226 | + }, |
---|
| 227 | + { |
---|
| 228 | + .whoami = INV_ICM20690_WHOAMI_VALUE, |
---|
| 229 | + .name = "ICM20690", |
---|
| 230 | + .reg = ®_set_6500, |
---|
| 231 | + .config = &chip_config_6500, |
---|
| 232 | + .fifo_size = 1024, |
---|
| 233 | + .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, |
---|
| 234 | + }, |
---|
| 235 | + { |
---|
| 236 | + .whoami = INV_IAM20680_WHOAMI_VALUE, |
---|
| 237 | + .name = "IAM20680", |
---|
| 238 | + .reg = ®_set_6500, |
---|
| 239 | + .config = &chip_config_6500, |
---|
| 240 | + .fifo_size = 512, |
---|
189 | 241 | .temp = {INV_ICM20608_TEMP_OFFSET, INV_ICM20608_TEMP_SCALE}, |
---|
190 | 242 | }, |
---|
191 | 243 | }; |
---|
192 | 244 | |
---|
193 | | -int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask) |
---|
| 245 | +static int inv_mpu6050_pwr_mgmt_1_write(struct inv_mpu6050_state *st, bool sleep, |
---|
| 246 | + int clock, int temp_dis) |
---|
194 | 247 | { |
---|
195 | | - unsigned int d, mgmt_1; |
---|
196 | | - int result; |
---|
197 | | - /* |
---|
198 | | - * switch clock needs to be careful. Only when gyro is on, can |
---|
199 | | - * clock source be switched to gyro. Otherwise, it must be set to |
---|
200 | | - * internal clock |
---|
201 | | - */ |
---|
202 | | - if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) { |
---|
203 | | - result = regmap_read(st->map, st->reg->pwr_mgmt_1, &mgmt_1); |
---|
204 | | - if (result) |
---|
205 | | - return result; |
---|
| 248 | + u8 val; |
---|
206 | 249 | |
---|
207 | | - mgmt_1 &= ~INV_MPU6050_BIT_CLK_MASK; |
---|
| 250 | + if (clock < 0) |
---|
| 251 | + clock = st->chip_config.clk; |
---|
| 252 | + if (temp_dis < 0) |
---|
| 253 | + temp_dis = !st->chip_config.temp_en; |
---|
| 254 | + |
---|
| 255 | + val = clock & INV_MPU6050_BIT_CLK_MASK; |
---|
| 256 | + if (temp_dis) |
---|
| 257 | + val |= INV_MPU6050_BIT_TEMP_DIS; |
---|
| 258 | + if (sleep) |
---|
| 259 | + val |= INV_MPU6050_BIT_SLEEP; |
---|
| 260 | + |
---|
| 261 | + dev_dbg(regmap_get_device(st->map), "pwr_mgmt_1: 0x%x\n", val); |
---|
| 262 | + return regmap_write(st->map, st->reg->pwr_mgmt_1, val); |
---|
| 263 | +} |
---|
| 264 | + |
---|
| 265 | +static int inv_mpu6050_clock_switch(struct inv_mpu6050_state *st, |
---|
| 266 | + unsigned int clock) |
---|
| 267 | +{ |
---|
| 268 | + int ret; |
---|
| 269 | + |
---|
| 270 | + switch (st->chip_type) { |
---|
| 271 | + case INV_MPU6050: |
---|
| 272 | + case INV_MPU6000: |
---|
| 273 | + case INV_MPU9150: |
---|
| 274 | + /* old chips: switch clock manually */ |
---|
| 275 | + ret = inv_mpu6050_pwr_mgmt_1_write(st, false, clock, -1); |
---|
| 276 | + if (ret) |
---|
| 277 | + return ret; |
---|
| 278 | + st->chip_config.clk = clock; |
---|
| 279 | + break; |
---|
| 280 | + default: |
---|
| 281 | + /* automatic clock switching, nothing to do */ |
---|
| 282 | + break; |
---|
208 | 283 | } |
---|
209 | 284 | |
---|
210 | | - if ((mask == INV_MPU6050_BIT_PWR_GYRO_STBY) && (!en)) { |
---|
211 | | - /* |
---|
212 | | - * turning off gyro requires switch to internal clock first. |
---|
213 | | - * Then turn off gyro engine |
---|
214 | | - */ |
---|
215 | | - mgmt_1 |= INV_CLK_INTERNAL; |
---|
216 | | - result = regmap_write(st->map, st->reg->pwr_mgmt_1, mgmt_1); |
---|
217 | | - if (result) |
---|
218 | | - return result; |
---|
| 285 | + return 0; |
---|
| 286 | +} |
---|
| 287 | + |
---|
| 288 | +int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, |
---|
| 289 | + unsigned int mask) |
---|
| 290 | +{ |
---|
| 291 | + unsigned int sleep; |
---|
| 292 | + u8 pwr_mgmt2, user_ctrl; |
---|
| 293 | + int ret; |
---|
| 294 | + |
---|
| 295 | + /* delete useless requests */ |
---|
| 296 | + if (mask & INV_MPU6050_SENSOR_ACCL && en == st->chip_config.accl_en) |
---|
| 297 | + mask &= ~INV_MPU6050_SENSOR_ACCL; |
---|
| 298 | + if (mask & INV_MPU6050_SENSOR_GYRO && en == st->chip_config.gyro_en) |
---|
| 299 | + mask &= ~INV_MPU6050_SENSOR_GYRO; |
---|
| 300 | + if (mask & INV_MPU6050_SENSOR_TEMP && en == st->chip_config.temp_en) |
---|
| 301 | + mask &= ~INV_MPU6050_SENSOR_TEMP; |
---|
| 302 | + if (mask & INV_MPU6050_SENSOR_MAGN && en == st->chip_config.magn_en) |
---|
| 303 | + mask &= ~INV_MPU6050_SENSOR_MAGN; |
---|
| 304 | + if (mask == 0) |
---|
| 305 | + return 0; |
---|
| 306 | + |
---|
| 307 | + /* turn on/off temperature sensor */ |
---|
| 308 | + if (mask & INV_MPU6050_SENSOR_TEMP) { |
---|
| 309 | + ret = inv_mpu6050_pwr_mgmt_1_write(st, false, -1, !en); |
---|
| 310 | + if (ret) |
---|
| 311 | + return ret; |
---|
| 312 | + st->chip_config.temp_en = en; |
---|
219 | 313 | } |
---|
220 | 314 | |
---|
221 | | - result = regmap_read(st->map, st->reg->pwr_mgmt_2, &d); |
---|
222 | | - if (result) |
---|
223 | | - return result; |
---|
224 | | - if (en) |
---|
225 | | - d &= ~mask; |
---|
226 | | - else |
---|
227 | | - d |= mask; |
---|
228 | | - result = regmap_write(st->map, st->reg->pwr_mgmt_2, d); |
---|
229 | | - if (result) |
---|
230 | | - return result; |
---|
| 315 | + /* update user_crtl for driving magnetometer */ |
---|
| 316 | + if (mask & INV_MPU6050_SENSOR_MAGN) { |
---|
| 317 | + user_ctrl = st->chip_config.user_ctrl; |
---|
| 318 | + if (en) |
---|
| 319 | + user_ctrl |= INV_MPU6050_BIT_I2C_MST_EN; |
---|
| 320 | + else |
---|
| 321 | + user_ctrl &= ~INV_MPU6050_BIT_I2C_MST_EN; |
---|
| 322 | + ret = regmap_write(st->map, st->reg->user_ctrl, user_ctrl); |
---|
| 323 | + if (ret) |
---|
| 324 | + return ret; |
---|
| 325 | + st->chip_config.user_ctrl = user_ctrl; |
---|
| 326 | + st->chip_config.magn_en = en; |
---|
| 327 | + } |
---|
231 | 328 | |
---|
232 | | - if (en) { |
---|
233 | | - /* Wait for output to stabilize */ |
---|
234 | | - msleep(INV_MPU6050_TEMP_UP_TIME); |
---|
235 | | - if (mask == INV_MPU6050_BIT_PWR_GYRO_STBY) { |
---|
236 | | - /* switch internal clock to PLL */ |
---|
237 | | - mgmt_1 |= INV_CLK_PLL; |
---|
238 | | - result = regmap_write(st->map, |
---|
239 | | - st->reg->pwr_mgmt_1, mgmt_1); |
---|
240 | | - if (result) |
---|
241 | | - return result; |
---|
| 329 | + /* manage accel & gyro engines */ |
---|
| 330 | + if (mask & (INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO)) { |
---|
| 331 | + /* compute power management 2 current value */ |
---|
| 332 | + pwr_mgmt2 = 0; |
---|
| 333 | + if (!st->chip_config.accl_en) |
---|
| 334 | + pwr_mgmt2 |= INV_MPU6050_BIT_PWR_ACCL_STBY; |
---|
| 335 | + if (!st->chip_config.gyro_en) |
---|
| 336 | + pwr_mgmt2 |= INV_MPU6050_BIT_PWR_GYRO_STBY; |
---|
| 337 | + |
---|
| 338 | + /* update to new requested value */ |
---|
| 339 | + if (mask & INV_MPU6050_SENSOR_ACCL) { |
---|
| 340 | + if (en) |
---|
| 341 | + pwr_mgmt2 &= ~INV_MPU6050_BIT_PWR_ACCL_STBY; |
---|
| 342 | + else |
---|
| 343 | + pwr_mgmt2 |= INV_MPU6050_BIT_PWR_ACCL_STBY; |
---|
| 344 | + } |
---|
| 345 | + if (mask & INV_MPU6050_SENSOR_GYRO) { |
---|
| 346 | + if (en) |
---|
| 347 | + pwr_mgmt2 &= ~INV_MPU6050_BIT_PWR_GYRO_STBY; |
---|
| 348 | + else |
---|
| 349 | + pwr_mgmt2 |= INV_MPU6050_BIT_PWR_GYRO_STBY; |
---|
| 350 | + } |
---|
| 351 | + |
---|
| 352 | + /* switch clock to internal when turning gyro off */ |
---|
| 353 | + if (mask & INV_MPU6050_SENSOR_GYRO && !en) { |
---|
| 354 | + ret = inv_mpu6050_clock_switch(st, INV_CLK_INTERNAL); |
---|
| 355 | + if (ret) |
---|
| 356 | + return ret; |
---|
| 357 | + } |
---|
| 358 | + |
---|
| 359 | + /* update sensors engine */ |
---|
| 360 | + dev_dbg(regmap_get_device(st->map), "pwr_mgmt_2: 0x%x\n", |
---|
| 361 | + pwr_mgmt2); |
---|
| 362 | + ret = regmap_write(st->map, st->reg->pwr_mgmt_2, pwr_mgmt2); |
---|
| 363 | + if (ret) |
---|
| 364 | + return ret; |
---|
| 365 | + if (mask & INV_MPU6050_SENSOR_ACCL) |
---|
| 366 | + st->chip_config.accl_en = en; |
---|
| 367 | + if (mask & INV_MPU6050_SENSOR_GYRO) |
---|
| 368 | + st->chip_config.gyro_en = en; |
---|
| 369 | + |
---|
| 370 | + /* compute required time to have sensors stabilized */ |
---|
| 371 | + sleep = 0; |
---|
| 372 | + if (en) { |
---|
| 373 | + if (mask & INV_MPU6050_SENSOR_ACCL) { |
---|
| 374 | + if (sleep < INV_MPU6050_ACCEL_UP_TIME) |
---|
| 375 | + sleep = INV_MPU6050_ACCEL_UP_TIME; |
---|
| 376 | + } |
---|
| 377 | + if (mask & INV_MPU6050_SENSOR_GYRO) { |
---|
| 378 | + if (sleep < INV_MPU6050_GYRO_UP_TIME) |
---|
| 379 | + sleep = INV_MPU6050_GYRO_UP_TIME; |
---|
| 380 | + } |
---|
| 381 | + } else { |
---|
| 382 | + if (mask & INV_MPU6050_SENSOR_GYRO) { |
---|
| 383 | + if (sleep < INV_MPU6050_GYRO_DOWN_TIME) |
---|
| 384 | + sleep = INV_MPU6050_GYRO_DOWN_TIME; |
---|
| 385 | + } |
---|
| 386 | + } |
---|
| 387 | + if (sleep) |
---|
| 388 | + msleep(sleep); |
---|
| 389 | + |
---|
| 390 | + /* switch clock to PLL when turning gyro on */ |
---|
| 391 | + if (mask & INV_MPU6050_SENSOR_GYRO && en) { |
---|
| 392 | + ret = inv_mpu6050_clock_switch(st, INV_CLK_PLL); |
---|
| 393 | + if (ret) |
---|
| 394 | + return ret; |
---|
242 | 395 | } |
---|
243 | 396 | } |
---|
244 | 397 | |
---|
245 | 398 | return 0; |
---|
246 | 399 | } |
---|
247 | 400 | |
---|
248 | | -int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on) |
---|
| 401 | +static int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, |
---|
| 402 | + bool power_on) |
---|
249 | 403 | { |
---|
250 | 404 | int result; |
---|
251 | 405 | |
---|
252 | | - if (power_on) { |
---|
253 | | - if (!st->powerup_count) { |
---|
254 | | - result = regmap_write(st->map, st->reg->pwr_mgmt_1, 0); |
---|
255 | | - if (result) |
---|
256 | | - return result; |
---|
257 | | - usleep_range(INV_MPU6050_REG_UP_TIME_MIN, |
---|
258 | | - INV_MPU6050_REG_UP_TIME_MAX); |
---|
259 | | - } |
---|
260 | | - st->powerup_count++; |
---|
261 | | - } else { |
---|
262 | | - if (st->powerup_count == 1) { |
---|
263 | | - result = regmap_write(st->map, st->reg->pwr_mgmt_1, |
---|
264 | | - INV_MPU6050_BIT_SLEEP); |
---|
265 | | - if (result) |
---|
266 | | - return result; |
---|
267 | | - } |
---|
268 | | - st->powerup_count--; |
---|
269 | | - } |
---|
| 406 | + result = inv_mpu6050_pwr_mgmt_1_write(st, !power_on, -1, -1); |
---|
| 407 | + if (result) |
---|
| 408 | + return result; |
---|
270 | 409 | |
---|
271 | | - dev_dbg(regmap_get_device(st->map), "set power %d, count=%u\n", |
---|
272 | | - power_on, st->powerup_count); |
---|
| 410 | + if (power_on) |
---|
| 411 | + usleep_range(INV_MPU6050_REG_UP_TIME_MIN, |
---|
| 412 | + INV_MPU6050_REG_UP_TIME_MAX); |
---|
273 | 413 | |
---|
274 | 414 | return 0; |
---|
275 | 415 | } |
---|
276 | | -EXPORT_SYMBOL_GPL(inv_mpu6050_set_power_itg); |
---|
277 | 416 | |
---|
278 | | -/** |
---|
| 417 | +static int inv_mpu6050_set_gyro_fsr(struct inv_mpu6050_state *st, |
---|
| 418 | + enum inv_mpu6050_fsr_e val) |
---|
| 419 | +{ |
---|
| 420 | + unsigned int gyro_shift; |
---|
| 421 | + u8 data; |
---|
| 422 | + |
---|
| 423 | + switch (st->chip_type) { |
---|
| 424 | + case INV_ICM20690: |
---|
| 425 | + gyro_shift = INV_ICM20690_GYRO_CONFIG_FSR_SHIFT; |
---|
| 426 | + break; |
---|
| 427 | + default: |
---|
| 428 | + gyro_shift = INV_MPU6050_GYRO_CONFIG_FSR_SHIFT; |
---|
| 429 | + break; |
---|
| 430 | + } |
---|
| 431 | + |
---|
| 432 | + data = val << gyro_shift; |
---|
| 433 | + return regmap_write(st->map, st->reg->gyro_config, data); |
---|
| 434 | +} |
---|
| 435 | + |
---|
| 436 | +/* |
---|
279 | 437 | * inv_mpu6050_set_lpf_regs() - set low pass filter registers, chip dependent |
---|
280 | 438 | * |
---|
281 | 439 | * MPU60xx/MPU9150 use only 1 register for accelerometer + gyroscope |
---|
.. | .. |
---|
290 | 448 | if (result) |
---|
291 | 449 | return result; |
---|
292 | 450 | |
---|
| 451 | + /* set accel lpf */ |
---|
293 | 452 | switch (st->chip_type) { |
---|
294 | 453 | case INV_MPU6050: |
---|
295 | 454 | case INV_MPU6000: |
---|
296 | 455 | case INV_MPU9150: |
---|
297 | 456 | /* old chips, nothing to do */ |
---|
298 | | - result = 0; |
---|
| 457 | + return 0; |
---|
| 458 | + case INV_ICM20689: |
---|
| 459 | + case INV_ICM20690: |
---|
| 460 | + /* set FIFO size to maximum value */ |
---|
| 461 | + val |= INV_ICM20689_BITS_FIFO_SIZE_MAX; |
---|
299 | 462 | break; |
---|
300 | 463 | default: |
---|
301 | | - /* set accel lpf */ |
---|
302 | | - result = regmap_write(st->map, st->reg->accel_lpf, val); |
---|
303 | 464 | break; |
---|
304 | 465 | } |
---|
305 | 466 | |
---|
306 | | - return result; |
---|
| 467 | + return regmap_write(st->map, st->reg->accel_lpf, val); |
---|
307 | 468 | } |
---|
308 | 469 | |
---|
309 | | -/** |
---|
| 470 | +/* |
---|
310 | 471 | * inv_mpu6050_init_config() - Initialize hardware, disable FIFO. |
---|
311 | 472 | * |
---|
312 | 473 | * Initial configuration: |
---|
.. | .. |
---|
321 | 482 | u8 d; |
---|
322 | 483 | struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
323 | 484 | |
---|
324 | | - result = inv_mpu6050_set_power_itg(st, true); |
---|
| 485 | + result = inv_mpu6050_set_gyro_fsr(st, st->chip_config.fsr); |
---|
325 | 486 | if (result) |
---|
326 | 487 | return result; |
---|
327 | | - d = (INV_MPU6050_FSR_2000DPS << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); |
---|
328 | | - result = regmap_write(st->map, st->reg->gyro_config, d); |
---|
329 | | - if (result) |
---|
330 | | - goto error_power_off; |
---|
331 | 488 | |
---|
332 | | - result = inv_mpu6050_set_lpf_regs(st, INV_MPU6050_FILTER_20HZ); |
---|
| 489 | + result = inv_mpu6050_set_lpf_regs(st, st->chip_config.lpf); |
---|
333 | 490 | if (result) |
---|
334 | | - goto error_power_off; |
---|
| 491 | + return result; |
---|
335 | 492 | |
---|
336 | | - d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(INV_MPU6050_INIT_FIFO_RATE); |
---|
| 493 | + d = st->chip_config.divider; |
---|
337 | 494 | result = regmap_write(st->map, st->reg->sample_rate_div, d); |
---|
338 | 495 | if (result) |
---|
339 | | - goto error_power_off; |
---|
| 496 | + return result; |
---|
340 | 497 | |
---|
341 | | - d = (INV_MPU6050_FS_02G << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); |
---|
| 498 | + d = (st->chip_config.accl_fs << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); |
---|
342 | 499 | result = regmap_write(st->map, st->reg->accl_config, d); |
---|
343 | 500 | if (result) |
---|
344 | | - goto error_power_off; |
---|
| 501 | + return result; |
---|
345 | 502 | |
---|
346 | 503 | result = regmap_write(st->map, st->reg->int_pin_cfg, st->irq_mask); |
---|
347 | 504 | if (result) |
---|
348 | 505 | return result; |
---|
349 | | - |
---|
350 | | - memcpy(&st->chip_config, hw_info[st->chip_type].config, |
---|
351 | | - sizeof(struct inv_mpu6050_chip_config)); |
---|
352 | 506 | |
---|
353 | 507 | /* |
---|
354 | 508 | * Internal chip period is 1ms (1kHz). |
---|
.. | .. |
---|
357 | 511 | */ |
---|
358 | 512 | st->chip_period = NSEC_PER_MSEC; |
---|
359 | 513 | |
---|
360 | | - return inv_mpu6050_set_power_itg(st, false); |
---|
| 514 | + /* magn chip init, noop if not present in the chip */ |
---|
| 515 | + result = inv_mpu_magn_probe(st); |
---|
| 516 | + if (result) |
---|
| 517 | + return result; |
---|
361 | 518 | |
---|
362 | | -error_power_off: |
---|
363 | | - inv_mpu6050_set_power_itg(st, false); |
---|
364 | | - return result; |
---|
| 519 | + return 0; |
---|
365 | 520 | } |
---|
366 | 521 | |
---|
367 | 522 | static int inv_mpu6050_sensor_set(struct inv_mpu6050_state *st, int reg, |
---|
.. | .. |
---|
371 | 526 | __be16 d = cpu_to_be16(val); |
---|
372 | 527 | |
---|
373 | 528 | ind = (axis - IIO_MOD_X) * 2; |
---|
374 | | - result = regmap_bulk_write(st->map, reg + ind, (u8 *)&d, 2); |
---|
| 529 | + result = regmap_bulk_write(st->map, reg + ind, &d, sizeof(d)); |
---|
375 | 530 | if (result) |
---|
376 | 531 | return -EINVAL; |
---|
377 | 532 | |
---|
.. | .. |
---|
385 | 540 | __be16 d; |
---|
386 | 541 | |
---|
387 | 542 | ind = (axis - IIO_MOD_X) * 2; |
---|
388 | | - result = regmap_bulk_read(st->map, reg + ind, (u8 *)&d, 2); |
---|
| 543 | + result = regmap_bulk_read(st->map, reg + ind, &d, sizeof(d)); |
---|
389 | 544 | if (result) |
---|
390 | 545 | return -EINVAL; |
---|
391 | 546 | *val = (short)be16_to_cpup(&d); |
---|
.. | .. |
---|
398 | 553 | int *val) |
---|
399 | 554 | { |
---|
400 | 555 | struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
| 556 | + struct device *pdev = regmap_get_device(st->map); |
---|
| 557 | + unsigned int freq_hz, period_us, min_sleep_us, max_sleep_us; |
---|
401 | 558 | int result; |
---|
402 | 559 | int ret; |
---|
403 | 560 | |
---|
404 | | - result = inv_mpu6050_set_power_itg(st, true); |
---|
405 | | - if (result) |
---|
| 561 | + /* compute sample period */ |
---|
| 562 | + freq_hz = INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider); |
---|
| 563 | + period_us = 1000000 / freq_hz; |
---|
| 564 | + |
---|
| 565 | + result = pm_runtime_get_sync(pdev); |
---|
| 566 | + if (result < 0) { |
---|
| 567 | + pm_runtime_put_noidle(pdev); |
---|
406 | 568 | return result; |
---|
| 569 | + } |
---|
407 | 570 | |
---|
408 | 571 | switch (chan->type) { |
---|
409 | 572 | case IIO_ANGL_VEL: |
---|
410 | | - result = inv_mpu6050_switch_engine(st, true, |
---|
411 | | - INV_MPU6050_BIT_PWR_GYRO_STBY); |
---|
412 | | - if (result) |
---|
413 | | - goto error_power_off; |
---|
| 573 | + if (!st->chip_config.gyro_en) { |
---|
| 574 | + result = inv_mpu6050_switch_engine(st, true, |
---|
| 575 | + INV_MPU6050_SENSOR_GYRO); |
---|
| 576 | + if (result) |
---|
| 577 | + goto error_power_off; |
---|
| 578 | + /* need to wait 2 periods to have first valid sample */ |
---|
| 579 | + min_sleep_us = 2 * period_us; |
---|
| 580 | + max_sleep_us = 2 * (period_us + period_us / 2); |
---|
| 581 | + usleep_range(min_sleep_us, max_sleep_us); |
---|
| 582 | + } |
---|
414 | 583 | ret = inv_mpu6050_sensor_show(st, st->reg->raw_gyro, |
---|
415 | 584 | chan->channel2, val); |
---|
416 | | - result = inv_mpu6050_switch_engine(st, false, |
---|
417 | | - INV_MPU6050_BIT_PWR_GYRO_STBY); |
---|
418 | | - if (result) |
---|
419 | | - goto error_power_off; |
---|
420 | 585 | break; |
---|
421 | 586 | case IIO_ACCEL: |
---|
422 | | - result = inv_mpu6050_switch_engine(st, true, |
---|
423 | | - INV_MPU6050_BIT_PWR_ACCL_STBY); |
---|
424 | | - if (result) |
---|
425 | | - goto error_power_off; |
---|
| 587 | + if (!st->chip_config.accl_en) { |
---|
| 588 | + result = inv_mpu6050_switch_engine(st, true, |
---|
| 589 | + INV_MPU6050_SENSOR_ACCL); |
---|
| 590 | + if (result) |
---|
| 591 | + goto error_power_off; |
---|
| 592 | + /* wait 1 period for first sample availability */ |
---|
| 593 | + min_sleep_us = period_us; |
---|
| 594 | + max_sleep_us = period_us + period_us / 2; |
---|
| 595 | + usleep_range(min_sleep_us, max_sleep_us); |
---|
| 596 | + } |
---|
426 | 597 | ret = inv_mpu6050_sensor_show(st, st->reg->raw_accl, |
---|
427 | 598 | chan->channel2, val); |
---|
428 | | - result = inv_mpu6050_switch_engine(st, false, |
---|
429 | | - INV_MPU6050_BIT_PWR_ACCL_STBY); |
---|
430 | | - if (result) |
---|
431 | | - goto error_power_off; |
---|
432 | 599 | break; |
---|
433 | 600 | case IIO_TEMP: |
---|
434 | | - /* wait for stablization */ |
---|
435 | | - msleep(INV_MPU6050_SENSOR_UP_TIME); |
---|
| 601 | + /* temperature sensor work only with accel and/or gyro */ |
---|
| 602 | + if (!st->chip_config.accl_en && !st->chip_config.gyro_en) { |
---|
| 603 | + result = -EBUSY; |
---|
| 604 | + goto error_power_off; |
---|
| 605 | + } |
---|
| 606 | + if (!st->chip_config.temp_en) { |
---|
| 607 | + result = inv_mpu6050_switch_engine(st, true, |
---|
| 608 | + INV_MPU6050_SENSOR_TEMP); |
---|
| 609 | + if (result) |
---|
| 610 | + goto error_power_off; |
---|
| 611 | + /* wait 1 period for first sample availability */ |
---|
| 612 | + min_sleep_us = period_us; |
---|
| 613 | + max_sleep_us = period_us + period_us / 2; |
---|
| 614 | + usleep_range(min_sleep_us, max_sleep_us); |
---|
| 615 | + } |
---|
436 | 616 | ret = inv_mpu6050_sensor_show(st, st->reg->temperature, |
---|
437 | 617 | IIO_MOD_X, val); |
---|
| 618 | + break; |
---|
| 619 | + case IIO_MAGN: |
---|
| 620 | + if (!st->chip_config.magn_en) { |
---|
| 621 | + result = inv_mpu6050_switch_engine(st, true, |
---|
| 622 | + INV_MPU6050_SENSOR_MAGN); |
---|
| 623 | + if (result) |
---|
| 624 | + goto error_power_off; |
---|
| 625 | + /* frequency is limited for magnetometer */ |
---|
| 626 | + if (freq_hz > INV_MPU_MAGN_FREQ_HZ_MAX) { |
---|
| 627 | + freq_hz = INV_MPU_MAGN_FREQ_HZ_MAX; |
---|
| 628 | + period_us = 1000000 / freq_hz; |
---|
| 629 | + } |
---|
| 630 | + /* need to wait 2 periods to have first valid sample */ |
---|
| 631 | + min_sleep_us = 2 * period_us; |
---|
| 632 | + max_sleep_us = 2 * (period_us + period_us / 2); |
---|
| 633 | + usleep_range(min_sleep_us, max_sleep_us); |
---|
| 634 | + } |
---|
| 635 | + ret = inv_mpu_magn_read(st, chan->channel2, val); |
---|
438 | 636 | break; |
---|
439 | 637 | default: |
---|
440 | 638 | ret = -EINVAL; |
---|
441 | 639 | break; |
---|
442 | 640 | } |
---|
443 | 641 | |
---|
444 | | - result = inv_mpu6050_set_power_itg(st, false); |
---|
445 | | - if (result) |
---|
446 | | - goto error_power_off; |
---|
| 642 | + pm_runtime_mark_last_busy(pdev); |
---|
| 643 | + pm_runtime_put_autosuspend(pdev); |
---|
447 | 644 | |
---|
448 | 645 | return ret; |
---|
449 | 646 | |
---|
450 | 647 | error_power_off: |
---|
451 | | - inv_mpu6050_set_power_itg(st, false); |
---|
| 648 | + pm_runtime_put_autosuspend(pdev); |
---|
452 | 649 | return result; |
---|
453 | 650 | } |
---|
454 | 651 | |
---|
.. | .. |
---|
490 | 687 | *val = st->hw->temp.scale / 1000000; |
---|
491 | 688 | *val2 = st->hw->temp.scale % 1000000; |
---|
492 | 689 | return IIO_VAL_INT_PLUS_MICRO; |
---|
| 690 | + case IIO_MAGN: |
---|
| 691 | + return inv_mpu_magn_get_scale(st, chan, val, val2); |
---|
493 | 692 | default: |
---|
494 | 693 | return -EINVAL; |
---|
495 | 694 | } |
---|
.. | .. |
---|
524 | 723 | } |
---|
525 | 724 | } |
---|
526 | 725 | |
---|
527 | | -static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val) |
---|
| 726 | +static int inv_mpu6050_write_gyro_scale(struct inv_mpu6050_state *st, int val, |
---|
| 727 | + int val2) |
---|
528 | 728 | { |
---|
529 | 729 | int result, i; |
---|
530 | | - u8 d; |
---|
| 730 | + |
---|
| 731 | + if (val != 0) |
---|
| 732 | + return -EINVAL; |
---|
531 | 733 | |
---|
532 | 734 | for (i = 0; i < ARRAY_SIZE(gyro_scale_6050); ++i) { |
---|
533 | | - if (gyro_scale_6050[i] == val) { |
---|
534 | | - d = (i << INV_MPU6050_GYRO_CONFIG_FSR_SHIFT); |
---|
535 | | - result = regmap_write(st->map, st->reg->gyro_config, d); |
---|
| 735 | + if (gyro_scale_6050[i] == val2) { |
---|
| 736 | + result = inv_mpu6050_set_gyro_fsr(st, i); |
---|
536 | 737 | if (result) |
---|
537 | 738 | return result; |
---|
538 | 739 | |
---|
.. | .. |
---|
562 | 763 | return -EINVAL; |
---|
563 | 764 | } |
---|
564 | 765 | |
---|
565 | | -static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val) |
---|
| 766 | +static int inv_mpu6050_write_accel_scale(struct inv_mpu6050_state *st, int val, |
---|
| 767 | + int val2) |
---|
566 | 768 | { |
---|
567 | 769 | int result, i; |
---|
568 | 770 | u8 d; |
---|
569 | 771 | |
---|
| 772 | + if (val != 0) |
---|
| 773 | + return -EINVAL; |
---|
| 774 | + |
---|
570 | 775 | for (i = 0; i < ARRAY_SIZE(accel_scale); ++i) { |
---|
571 | | - if (accel_scale[i] == val) { |
---|
| 776 | + if (accel_scale[i] == val2) { |
---|
572 | 777 | d = (i << INV_MPU6050_ACCL_CONFIG_FSR_SHIFT); |
---|
573 | 778 | result = regmap_write(st->map, st->reg->accl_config, d); |
---|
574 | 779 | if (result) |
---|
.. | .. |
---|
587 | 792 | int val, int val2, long mask) |
---|
588 | 793 | { |
---|
589 | 794 | struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
| 795 | + struct device *pdev = regmap_get_device(st->map); |
---|
590 | 796 | int result; |
---|
591 | 797 | |
---|
592 | 798 | /* |
---|
.. | .. |
---|
598 | 804 | return result; |
---|
599 | 805 | |
---|
600 | 806 | mutex_lock(&st->lock); |
---|
601 | | - result = inv_mpu6050_set_power_itg(st, true); |
---|
602 | | - if (result) |
---|
| 807 | + result = pm_runtime_get_sync(pdev); |
---|
| 808 | + if (result < 0) { |
---|
| 809 | + pm_runtime_put_noidle(pdev); |
---|
603 | 810 | goto error_write_raw_unlock; |
---|
| 811 | + } |
---|
604 | 812 | |
---|
605 | 813 | switch (mask) { |
---|
606 | 814 | case IIO_CHAN_INFO_SCALE: |
---|
607 | 815 | switch (chan->type) { |
---|
608 | 816 | case IIO_ANGL_VEL: |
---|
609 | | - result = inv_mpu6050_write_gyro_scale(st, val2); |
---|
| 817 | + result = inv_mpu6050_write_gyro_scale(st, val, val2); |
---|
610 | 818 | break; |
---|
611 | 819 | case IIO_ACCEL: |
---|
612 | | - result = inv_mpu6050_write_accel_scale(st, val2); |
---|
| 820 | + result = inv_mpu6050_write_accel_scale(st, val, val2); |
---|
613 | 821 | break; |
---|
614 | 822 | default: |
---|
615 | 823 | result = -EINVAL; |
---|
.. | .. |
---|
638 | 846 | break; |
---|
639 | 847 | } |
---|
640 | 848 | |
---|
641 | | - result |= inv_mpu6050_set_power_itg(st, false); |
---|
| 849 | + pm_runtime_mark_last_busy(pdev); |
---|
| 850 | + pm_runtime_put_autosuspend(pdev); |
---|
642 | 851 | error_write_raw_unlock: |
---|
643 | 852 | mutex_unlock(&st->lock); |
---|
644 | 853 | iio_device_release_direct_mode(indio_dev); |
---|
.. | .. |
---|
646 | 855 | return result; |
---|
647 | 856 | } |
---|
648 | 857 | |
---|
649 | | -/** |
---|
| 858 | +/* |
---|
650 | 859 | * inv_mpu6050_set_lpf() - set low pass filer based on fifo rate. |
---|
651 | 860 | * |
---|
652 | | - * Based on the Nyquist principle, the sampling rate must |
---|
653 | | - * exceed twice of the bandwidth of the signal, or there |
---|
654 | | - * would be alising. This function basically search for the |
---|
655 | | - * correct low pass parameters based on the fifo rate, e.g, |
---|
656 | | - * sampling frequency. |
---|
| 861 | + * Based on the Nyquist principle, the bandwidth of the low |
---|
| 862 | + * pass filter must not exceed the signal sampling rate divided |
---|
| 863 | + * by 2, or there would be aliasing. |
---|
| 864 | + * This function basically search for the correct low pass |
---|
| 865 | + * parameters based on the fifo rate, e.g, sampling frequency. |
---|
657 | 866 | * |
---|
658 | 867 | * lpf is set automatically when setting sampling rate to avoid any aliases. |
---|
659 | 868 | */ |
---|
660 | 869 | static int inv_mpu6050_set_lpf(struct inv_mpu6050_state *st, int rate) |
---|
661 | 870 | { |
---|
662 | | - static const int hz[] = {188, 98, 42, 20, 10, 5}; |
---|
| 871 | + static const int hz[] = {400, 200, 90, 40, 20, 10}; |
---|
663 | 872 | static const int d[] = { |
---|
664 | | - INV_MPU6050_FILTER_188HZ, INV_MPU6050_FILTER_98HZ, |
---|
665 | | - INV_MPU6050_FILTER_42HZ, INV_MPU6050_FILTER_20HZ, |
---|
| 873 | + INV_MPU6050_FILTER_200HZ, INV_MPU6050_FILTER_100HZ, |
---|
| 874 | + INV_MPU6050_FILTER_45HZ, INV_MPU6050_FILTER_20HZ, |
---|
666 | 875 | INV_MPU6050_FILTER_10HZ, INV_MPU6050_FILTER_5HZ |
---|
667 | 876 | }; |
---|
668 | | - int i, h, result; |
---|
| 877 | + int i, result; |
---|
669 | 878 | u8 data; |
---|
670 | 879 | |
---|
671 | | - h = (rate >> 1); |
---|
672 | | - i = 0; |
---|
673 | | - while ((h < hz[i]) && (i < ARRAY_SIZE(d) - 1)) |
---|
674 | | - i++; |
---|
675 | | - data = d[i]; |
---|
| 880 | + data = INV_MPU6050_FILTER_5HZ; |
---|
| 881 | + for (i = 0; i < ARRAY_SIZE(hz); ++i) { |
---|
| 882 | + if (rate >= hz[i]) { |
---|
| 883 | + data = d[i]; |
---|
| 884 | + break; |
---|
| 885 | + } |
---|
| 886 | + } |
---|
676 | 887 | result = inv_mpu6050_set_lpf_regs(st, data); |
---|
677 | 888 | if (result) |
---|
678 | 889 | return result; |
---|
.. | .. |
---|
681 | 892 | return 0; |
---|
682 | 893 | } |
---|
683 | 894 | |
---|
684 | | -/** |
---|
| 895 | +/* |
---|
685 | 896 | * inv_mpu6050_fifo_rate_store() - Set fifo rate. |
---|
686 | 897 | */ |
---|
687 | 898 | static ssize_t |
---|
.. | .. |
---|
693 | 904 | int result; |
---|
694 | 905 | struct iio_dev *indio_dev = dev_to_iio_dev(dev); |
---|
695 | 906 | struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
| 907 | + struct device *pdev = regmap_get_device(st->map); |
---|
696 | 908 | |
---|
697 | 909 | if (kstrtoint(buf, 10, &fifo_rate)) |
---|
698 | 910 | return -EINVAL; |
---|
699 | 911 | if (fifo_rate < INV_MPU6050_MIN_FIFO_RATE || |
---|
700 | 912 | fifo_rate > INV_MPU6050_MAX_FIFO_RATE) |
---|
701 | 913 | return -EINVAL; |
---|
702 | | - |
---|
703 | | - result = iio_device_claim_direct_mode(indio_dev); |
---|
704 | | - if (result) |
---|
705 | | - return result; |
---|
706 | 914 | |
---|
707 | 915 | /* compute the chip sample rate divider */ |
---|
708 | 916 | d = INV_MPU6050_FIFO_RATE_TO_DIVIDER(fifo_rate); |
---|
.. | .. |
---|
714 | 922 | result = 0; |
---|
715 | 923 | goto fifo_rate_fail_unlock; |
---|
716 | 924 | } |
---|
717 | | - result = inv_mpu6050_set_power_itg(st, true); |
---|
718 | | - if (result) |
---|
| 925 | + result = pm_runtime_get_sync(pdev); |
---|
| 926 | + if (result < 0) { |
---|
| 927 | + pm_runtime_put_noidle(pdev); |
---|
719 | 928 | goto fifo_rate_fail_unlock; |
---|
| 929 | + } |
---|
720 | 930 | |
---|
721 | 931 | result = regmap_write(st->map, st->reg->sample_rate_div, d); |
---|
722 | 932 | if (result) |
---|
.. | .. |
---|
727 | 937 | if (result) |
---|
728 | 938 | goto fifo_rate_fail_power_off; |
---|
729 | 939 | |
---|
| 940 | + /* update rate for magn, noop if not present in chip */ |
---|
| 941 | + result = inv_mpu_magn_set_rate(st, fifo_rate); |
---|
| 942 | + if (result) |
---|
| 943 | + goto fifo_rate_fail_power_off; |
---|
| 944 | + |
---|
| 945 | + pm_runtime_mark_last_busy(pdev); |
---|
730 | 946 | fifo_rate_fail_power_off: |
---|
731 | | - result |= inv_mpu6050_set_power_itg(st, false); |
---|
| 947 | + pm_runtime_put_autosuspend(pdev); |
---|
732 | 948 | fifo_rate_fail_unlock: |
---|
733 | 949 | mutex_unlock(&st->lock); |
---|
734 | | - iio_device_release_direct_mode(indio_dev); |
---|
735 | 950 | if (result) |
---|
736 | 951 | return result; |
---|
737 | 952 | |
---|
738 | 953 | return count; |
---|
739 | 954 | } |
---|
740 | 955 | |
---|
741 | | -/** |
---|
| 956 | +/* |
---|
742 | 957 | * inv_fifo_rate_show() - Get the current sampling rate. |
---|
743 | 958 | */ |
---|
744 | 959 | static ssize_t |
---|
.. | .. |
---|
755 | 970 | return scnprintf(buf, PAGE_SIZE, "%u\n", fifo_rate); |
---|
756 | 971 | } |
---|
757 | 972 | |
---|
758 | | -/** |
---|
| 973 | +/* |
---|
759 | 974 | * inv_attr_show() - calling this function will show current |
---|
760 | 975 | * parameters. |
---|
761 | 976 | * |
---|
.. | .. |
---|
811 | 1026 | inv_get_mount_matrix(const struct iio_dev *indio_dev, |
---|
812 | 1027 | const struct iio_chan_spec *chan) |
---|
813 | 1028 | { |
---|
814 | | - return &((struct inv_mpu6050_state *)iio_priv(indio_dev))->orientation; |
---|
| 1029 | + struct inv_mpu6050_state *data = iio_priv(indio_dev); |
---|
| 1030 | + const struct iio_mount_matrix *matrix; |
---|
| 1031 | + |
---|
| 1032 | + if (chan->type == IIO_MAGN) |
---|
| 1033 | + matrix = &data->magn_orient; |
---|
| 1034 | + else |
---|
| 1035 | + matrix = &data->orientation; |
---|
| 1036 | + |
---|
| 1037 | + return matrix; |
---|
815 | 1038 | } |
---|
816 | 1039 | |
---|
817 | 1040 | static const struct iio_chan_spec_ext_info inv_ext_info[] = { |
---|
818 | 1041 | IIO_MOUNT_MATRIX(IIO_SHARED_BY_TYPE, inv_get_mount_matrix), |
---|
819 | | - { }, |
---|
| 1042 | + { } |
---|
820 | 1043 | }; |
---|
821 | 1044 | |
---|
822 | 1045 | #define INV_MPU6050_CHAN(_type, _channel2, _index) \ |
---|
.. | .. |
---|
838 | 1061 | .ext_info = inv_ext_info, \ |
---|
839 | 1062 | } |
---|
840 | 1063 | |
---|
| 1064 | +#define INV_MPU6050_TEMP_CHAN(_index) \ |
---|
| 1065 | + { \ |
---|
| 1066 | + .type = IIO_TEMP, \ |
---|
| 1067 | + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) \ |
---|
| 1068 | + | BIT(IIO_CHAN_INFO_OFFSET) \ |
---|
| 1069 | + | BIT(IIO_CHAN_INFO_SCALE), \ |
---|
| 1070 | + .scan_index = _index, \ |
---|
| 1071 | + .scan_type = { \ |
---|
| 1072 | + .sign = 's', \ |
---|
| 1073 | + .realbits = 16, \ |
---|
| 1074 | + .storagebits = 16, \ |
---|
| 1075 | + .shift = 0, \ |
---|
| 1076 | + .endianness = IIO_BE, \ |
---|
| 1077 | + }, \ |
---|
| 1078 | + } |
---|
| 1079 | + |
---|
841 | 1080 | static const struct iio_chan_spec inv_mpu_channels[] = { |
---|
842 | 1081 | IIO_CHAN_SOFT_TIMESTAMP(INV_MPU6050_SCAN_TIMESTAMP), |
---|
843 | | - /* |
---|
844 | | - * Note that temperature should only be via polled reading only, |
---|
845 | | - * not the final scan elements output. |
---|
846 | | - */ |
---|
847 | | - { |
---|
848 | | - .type = IIO_TEMP, |
---|
849 | | - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
---|
850 | | - | BIT(IIO_CHAN_INFO_OFFSET) |
---|
851 | | - | BIT(IIO_CHAN_INFO_SCALE), |
---|
852 | | - .scan_index = -1, |
---|
853 | | - }, |
---|
| 1082 | + |
---|
| 1083 | + INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP), |
---|
| 1084 | + |
---|
854 | 1085 | INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), |
---|
855 | 1086 | INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), |
---|
856 | 1087 | INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), |
---|
.. | .. |
---|
860 | 1091 | INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), |
---|
861 | 1092 | }; |
---|
862 | 1093 | |
---|
| 1094 | +#define INV_MPU6050_SCAN_MASK_3AXIS_ACCEL \ |
---|
| 1095 | + (BIT(INV_MPU6050_SCAN_ACCL_X) \ |
---|
| 1096 | + | BIT(INV_MPU6050_SCAN_ACCL_Y) \ |
---|
| 1097 | + | BIT(INV_MPU6050_SCAN_ACCL_Z)) |
---|
| 1098 | + |
---|
| 1099 | +#define INV_MPU6050_SCAN_MASK_3AXIS_GYRO \ |
---|
| 1100 | + (BIT(INV_MPU6050_SCAN_GYRO_X) \ |
---|
| 1101 | + | BIT(INV_MPU6050_SCAN_GYRO_Y) \ |
---|
| 1102 | + | BIT(INV_MPU6050_SCAN_GYRO_Z)) |
---|
| 1103 | + |
---|
| 1104 | +#define INV_MPU6050_SCAN_MASK_TEMP (BIT(INV_MPU6050_SCAN_TEMP)) |
---|
| 1105 | + |
---|
863 | 1106 | static const unsigned long inv_mpu_scan_masks[] = { |
---|
864 | 1107 | /* 3-axis accel */ |
---|
865 | | - BIT(INV_MPU6050_SCAN_ACCL_X) |
---|
866 | | - | BIT(INV_MPU6050_SCAN_ACCL_Y) |
---|
867 | | - | BIT(INV_MPU6050_SCAN_ACCL_Z), |
---|
| 1108 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL, |
---|
| 1109 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_TEMP, |
---|
868 | 1110 | /* 3-axis gyro */ |
---|
869 | | - BIT(INV_MPU6050_SCAN_GYRO_X) |
---|
870 | | - | BIT(INV_MPU6050_SCAN_GYRO_Y) |
---|
871 | | - | BIT(INV_MPU6050_SCAN_GYRO_Z), |
---|
| 1111 | + INV_MPU6050_SCAN_MASK_3AXIS_GYRO, |
---|
| 1112 | + INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU6050_SCAN_MASK_TEMP, |
---|
872 | 1113 | /* 6-axis accel + gyro */ |
---|
873 | | - BIT(INV_MPU6050_SCAN_ACCL_X) |
---|
874 | | - | BIT(INV_MPU6050_SCAN_ACCL_Y) |
---|
875 | | - | BIT(INV_MPU6050_SCAN_ACCL_Z) |
---|
876 | | - | BIT(INV_MPU6050_SCAN_GYRO_X) |
---|
877 | | - | BIT(INV_MPU6050_SCAN_GYRO_Y) |
---|
878 | | - | BIT(INV_MPU6050_SCAN_GYRO_Z), |
---|
| 1114 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO, |
---|
| 1115 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO |
---|
| 1116 | + | INV_MPU6050_SCAN_MASK_TEMP, |
---|
879 | 1117 | 0, |
---|
880 | 1118 | }; |
---|
881 | 1119 | |
---|
882 | | -static const struct iio_chan_spec inv_icm20602_channels[] = { |
---|
883 | | - IIO_CHAN_SOFT_TIMESTAMP(INV_ICM20602_SCAN_TIMESTAMP), |
---|
884 | | - { |
---|
885 | | - .type = IIO_TEMP, |
---|
886 | | - .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
---|
887 | | - | BIT(IIO_CHAN_INFO_OFFSET) |
---|
888 | | - | BIT(IIO_CHAN_INFO_SCALE), |
---|
889 | | - .scan_index = INV_ICM20602_SCAN_TEMP, |
---|
890 | | - .scan_type = { |
---|
891 | | - .sign = 's', |
---|
892 | | - .realbits = 16, |
---|
893 | | - .storagebits = 16, |
---|
894 | | - .shift = 0, |
---|
895 | | - .endianness = IIO_BE, |
---|
896 | | - }, |
---|
897 | | - }, |
---|
| 1120 | +#define INV_MPU9X50_MAGN_CHAN(_chan2, _bits, _index) \ |
---|
| 1121 | + { \ |
---|
| 1122 | + .type = IIO_MAGN, \ |
---|
| 1123 | + .modified = 1, \ |
---|
| 1124 | + .channel2 = _chan2, \ |
---|
| 1125 | + .info_mask_separate = BIT(IIO_CHAN_INFO_SCALE) | \ |
---|
| 1126 | + BIT(IIO_CHAN_INFO_RAW), \ |
---|
| 1127 | + .scan_index = _index, \ |
---|
| 1128 | + .scan_type = { \ |
---|
| 1129 | + .sign = 's', \ |
---|
| 1130 | + .realbits = _bits, \ |
---|
| 1131 | + .storagebits = 16, \ |
---|
| 1132 | + .shift = 0, \ |
---|
| 1133 | + .endianness = IIO_BE, \ |
---|
| 1134 | + }, \ |
---|
| 1135 | + .ext_info = inv_ext_info, \ |
---|
| 1136 | + } |
---|
898 | 1137 | |
---|
899 | | - INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_ICM20602_SCAN_GYRO_X), |
---|
900 | | - INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_ICM20602_SCAN_GYRO_Y), |
---|
901 | | - INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_ICM20602_SCAN_GYRO_Z), |
---|
| 1138 | +static const struct iio_chan_spec inv_mpu9150_channels[] = { |
---|
| 1139 | + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP), |
---|
902 | 1140 | |
---|
903 | | - INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_ICM20602_SCAN_ACCL_Y), |
---|
904 | | - INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_ICM20602_SCAN_ACCL_X), |
---|
905 | | - INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_ICM20602_SCAN_ACCL_Z), |
---|
| 1141 | + INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP), |
---|
| 1142 | + |
---|
| 1143 | + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), |
---|
| 1144 | + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), |
---|
| 1145 | + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), |
---|
| 1146 | + |
---|
| 1147 | + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), |
---|
| 1148 | + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), |
---|
| 1149 | + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), |
---|
| 1150 | + |
---|
| 1151 | + /* Magnetometer resolution is 13 bits */ |
---|
| 1152 | + INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 13, INV_MPU9X50_SCAN_MAGN_X), |
---|
| 1153 | + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 13, INV_MPU9X50_SCAN_MAGN_Y), |
---|
| 1154 | + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 13, INV_MPU9X50_SCAN_MAGN_Z), |
---|
| 1155 | +}; |
---|
| 1156 | + |
---|
| 1157 | +static const struct iio_chan_spec inv_mpu9250_channels[] = { |
---|
| 1158 | + IIO_CHAN_SOFT_TIMESTAMP(INV_MPU9X50_SCAN_TIMESTAMP), |
---|
| 1159 | + |
---|
| 1160 | + INV_MPU6050_TEMP_CHAN(INV_MPU6050_SCAN_TEMP), |
---|
| 1161 | + |
---|
| 1162 | + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_X, INV_MPU6050_SCAN_GYRO_X), |
---|
| 1163 | + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Y, INV_MPU6050_SCAN_GYRO_Y), |
---|
| 1164 | + INV_MPU6050_CHAN(IIO_ANGL_VEL, IIO_MOD_Z, INV_MPU6050_SCAN_GYRO_Z), |
---|
| 1165 | + |
---|
| 1166 | + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_X, INV_MPU6050_SCAN_ACCL_X), |
---|
| 1167 | + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Y, INV_MPU6050_SCAN_ACCL_Y), |
---|
| 1168 | + INV_MPU6050_CHAN(IIO_ACCEL, IIO_MOD_Z, INV_MPU6050_SCAN_ACCL_Z), |
---|
| 1169 | + |
---|
| 1170 | + /* Magnetometer resolution is 16 bits */ |
---|
| 1171 | + INV_MPU9X50_MAGN_CHAN(IIO_MOD_X, 16, INV_MPU9X50_SCAN_MAGN_X), |
---|
| 1172 | + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Y, 16, INV_MPU9X50_SCAN_MAGN_Y), |
---|
| 1173 | + INV_MPU9X50_MAGN_CHAN(IIO_MOD_Z, 16, INV_MPU9X50_SCAN_MAGN_Z), |
---|
| 1174 | +}; |
---|
| 1175 | + |
---|
| 1176 | +#define INV_MPU9X50_SCAN_MASK_3AXIS_MAGN \ |
---|
| 1177 | + (BIT(INV_MPU9X50_SCAN_MAGN_X) \ |
---|
| 1178 | + | BIT(INV_MPU9X50_SCAN_MAGN_Y) \ |
---|
| 1179 | + | BIT(INV_MPU9X50_SCAN_MAGN_Z)) |
---|
| 1180 | + |
---|
| 1181 | +static const unsigned long inv_mpu9x50_scan_masks[] = { |
---|
| 1182 | + /* 3-axis accel */ |
---|
| 1183 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL, |
---|
| 1184 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_TEMP, |
---|
| 1185 | + /* 3-axis gyro */ |
---|
| 1186 | + INV_MPU6050_SCAN_MASK_3AXIS_GYRO, |
---|
| 1187 | + INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU6050_SCAN_MASK_TEMP, |
---|
| 1188 | + /* 3-axis magn */ |
---|
| 1189 | + INV_MPU9X50_SCAN_MASK_3AXIS_MAGN, |
---|
| 1190 | + INV_MPU9X50_SCAN_MASK_3AXIS_MAGN | INV_MPU6050_SCAN_MASK_TEMP, |
---|
| 1191 | + /* 6-axis accel + gyro */ |
---|
| 1192 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO, |
---|
| 1193 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO |
---|
| 1194 | + | INV_MPU6050_SCAN_MASK_TEMP, |
---|
| 1195 | + /* 6-axis accel + magn */ |
---|
| 1196 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN, |
---|
| 1197 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN |
---|
| 1198 | + | INV_MPU6050_SCAN_MASK_TEMP, |
---|
| 1199 | + /* 6-axis gyro + magn */ |
---|
| 1200 | + INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN, |
---|
| 1201 | + INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN |
---|
| 1202 | + | INV_MPU6050_SCAN_MASK_TEMP, |
---|
| 1203 | + /* 9-axis accel + gyro + magn */ |
---|
| 1204 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO |
---|
| 1205 | + | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN, |
---|
| 1206 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO |
---|
| 1207 | + | INV_MPU9X50_SCAN_MASK_3AXIS_MAGN |
---|
| 1208 | + | INV_MPU6050_SCAN_MASK_TEMP, |
---|
| 1209 | + 0, |
---|
906 | 1210 | }; |
---|
907 | 1211 | |
---|
908 | 1212 | static const unsigned long inv_icm20602_scan_masks[] = { |
---|
909 | 1213 | /* 3-axis accel + temp (mandatory) */ |
---|
910 | | - BIT(INV_ICM20602_SCAN_ACCL_X) |
---|
911 | | - | BIT(INV_ICM20602_SCAN_ACCL_Y) |
---|
912 | | - | BIT(INV_ICM20602_SCAN_ACCL_Z) |
---|
913 | | - | BIT(INV_ICM20602_SCAN_TEMP), |
---|
| 1214 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_TEMP, |
---|
914 | 1215 | /* 3-axis gyro + temp (mandatory) */ |
---|
915 | | - BIT(INV_ICM20602_SCAN_GYRO_X) |
---|
916 | | - | BIT(INV_ICM20602_SCAN_GYRO_Y) |
---|
917 | | - | BIT(INV_ICM20602_SCAN_GYRO_Z) |
---|
918 | | - | BIT(INV_ICM20602_SCAN_TEMP), |
---|
| 1216 | + INV_MPU6050_SCAN_MASK_3AXIS_GYRO | INV_MPU6050_SCAN_MASK_TEMP, |
---|
919 | 1217 | /* 6-axis accel + gyro + temp (mandatory) */ |
---|
920 | | - BIT(INV_ICM20602_SCAN_ACCL_X) |
---|
921 | | - | BIT(INV_ICM20602_SCAN_ACCL_Y) |
---|
922 | | - | BIT(INV_ICM20602_SCAN_ACCL_Z) |
---|
923 | | - | BIT(INV_ICM20602_SCAN_GYRO_X) |
---|
924 | | - | BIT(INV_ICM20602_SCAN_GYRO_Y) |
---|
925 | | - | BIT(INV_ICM20602_SCAN_GYRO_Z) |
---|
926 | | - | BIT(INV_ICM20602_SCAN_TEMP), |
---|
| 1218 | + INV_MPU6050_SCAN_MASK_3AXIS_ACCEL | INV_MPU6050_SCAN_MASK_3AXIS_GYRO |
---|
| 1219 | + | INV_MPU6050_SCAN_MASK_TEMP, |
---|
927 | 1220 | 0, |
---|
928 | 1221 | }; |
---|
929 | 1222 | |
---|
.. | .. |
---|
963 | 1256 | .attrs = inv_attributes |
---|
964 | 1257 | }; |
---|
965 | 1258 | |
---|
| 1259 | +static int inv_mpu6050_reg_access(struct iio_dev *indio_dev, |
---|
| 1260 | + unsigned int reg, |
---|
| 1261 | + unsigned int writeval, |
---|
| 1262 | + unsigned int *readval) |
---|
| 1263 | +{ |
---|
| 1264 | + struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
| 1265 | + int ret; |
---|
| 1266 | + |
---|
| 1267 | + mutex_lock(&st->lock); |
---|
| 1268 | + if (readval) |
---|
| 1269 | + ret = regmap_read(st->map, reg, readval); |
---|
| 1270 | + else |
---|
| 1271 | + ret = regmap_write(st->map, reg, writeval); |
---|
| 1272 | + mutex_unlock(&st->lock); |
---|
| 1273 | + |
---|
| 1274 | + return ret; |
---|
| 1275 | +} |
---|
| 1276 | + |
---|
966 | 1277 | static const struct iio_info mpu_info = { |
---|
967 | 1278 | .read_raw = &inv_mpu6050_read_raw, |
---|
968 | 1279 | .write_raw = &inv_mpu6050_write_raw, |
---|
969 | 1280 | .write_raw_get_fmt = &inv_write_raw_get_fmt, |
---|
970 | 1281 | .attrs = &inv_attribute_group, |
---|
971 | 1282 | .validate_trigger = inv_mpu6050_validate_trigger, |
---|
| 1283 | + .debugfs_reg_access = &inv_mpu6050_reg_access, |
---|
972 | 1284 | }; |
---|
973 | 1285 | |
---|
974 | | -/** |
---|
| 1286 | +/* |
---|
975 | 1287 | * inv_check_and_setup_chip() - check and setup chip. |
---|
976 | 1288 | */ |
---|
977 | 1289 | static int inv_check_and_setup_chip(struct inv_mpu6050_state *st) |
---|
978 | 1290 | { |
---|
979 | 1291 | int result; |
---|
980 | | - unsigned int regval; |
---|
| 1292 | + unsigned int regval, mask; |
---|
981 | 1293 | int i; |
---|
982 | 1294 | |
---|
983 | 1295 | st->hw = &hw_info[st->chip_type]; |
---|
984 | 1296 | st->reg = hw_info[st->chip_type].reg; |
---|
| 1297 | + memcpy(&st->chip_config, hw_info[st->chip_type].config, |
---|
| 1298 | + sizeof(st->chip_config)); |
---|
985 | 1299 | |
---|
986 | 1300 | /* check chip self-identification */ |
---|
987 | 1301 | result = regmap_read(st->map, INV_MPU6050_REG_WHOAMI, ®val); |
---|
.. | .. |
---|
1013 | 1327 | if (result) |
---|
1014 | 1328 | return result; |
---|
1015 | 1329 | msleep(INV_MPU6050_POWER_UP_TIME); |
---|
| 1330 | + switch (st->chip_type) { |
---|
| 1331 | + case INV_MPU6000: |
---|
| 1332 | + case INV_MPU6500: |
---|
| 1333 | + case INV_MPU6515: |
---|
| 1334 | + case INV_MPU9250: |
---|
| 1335 | + case INV_MPU9255: |
---|
| 1336 | + /* reset signal path (required for spi connection) */ |
---|
| 1337 | + regval = INV_MPU6050_BIT_TEMP_RST | INV_MPU6050_BIT_ACCEL_RST | |
---|
| 1338 | + INV_MPU6050_BIT_GYRO_RST; |
---|
| 1339 | + result = regmap_write(st->map, INV_MPU6050_REG_SIGNAL_PATH_RESET, |
---|
| 1340 | + regval); |
---|
| 1341 | + if (result) |
---|
| 1342 | + return result; |
---|
| 1343 | + msleep(INV_MPU6050_POWER_UP_TIME); |
---|
| 1344 | + break; |
---|
| 1345 | + default: |
---|
| 1346 | + break; |
---|
| 1347 | + } |
---|
1016 | 1348 | |
---|
1017 | 1349 | /* |
---|
1018 | 1350 | * Turn power on. After reset, the sleep bit could be on |
---|
.. | .. |
---|
1023 | 1355 | result = inv_mpu6050_set_power_itg(st, true); |
---|
1024 | 1356 | if (result) |
---|
1025 | 1357 | return result; |
---|
1026 | | - |
---|
1027 | | - result = inv_mpu6050_switch_engine(st, false, |
---|
1028 | | - INV_MPU6050_BIT_PWR_ACCL_STBY); |
---|
1029 | | - if (result) |
---|
1030 | | - goto error_power_off; |
---|
1031 | | - result = inv_mpu6050_switch_engine(st, false, |
---|
1032 | | - INV_MPU6050_BIT_PWR_GYRO_STBY); |
---|
| 1358 | + mask = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO | |
---|
| 1359 | + INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN; |
---|
| 1360 | + result = inv_mpu6050_switch_engine(st, false, mask); |
---|
1033 | 1361 | if (result) |
---|
1034 | 1362 | goto error_power_off; |
---|
1035 | 1363 | |
---|
1036 | | - return inv_mpu6050_set_power_itg(st, false); |
---|
| 1364 | + return 0; |
---|
1037 | 1365 | |
---|
1038 | 1366 | error_power_off: |
---|
1039 | 1367 | inv_mpu6050_set_power_itg(st, false); |
---|
1040 | 1368 | return result; |
---|
| 1369 | +} |
---|
| 1370 | + |
---|
| 1371 | +static int inv_mpu_core_enable_regulator_vddio(struct inv_mpu6050_state *st) |
---|
| 1372 | +{ |
---|
| 1373 | + int result; |
---|
| 1374 | + |
---|
| 1375 | + result = regulator_enable(st->vddio_supply); |
---|
| 1376 | + if (result) { |
---|
| 1377 | + dev_err(regmap_get_device(st->map), |
---|
| 1378 | + "Failed to enable vddio regulator: %d\n", result); |
---|
| 1379 | + } else { |
---|
| 1380 | + /* Give the device a little bit of time to start up. */ |
---|
| 1381 | + usleep_range(3000, 5000); |
---|
| 1382 | + } |
---|
| 1383 | + |
---|
| 1384 | + return result; |
---|
| 1385 | +} |
---|
| 1386 | + |
---|
| 1387 | +static int inv_mpu_core_disable_regulator_vddio(struct inv_mpu6050_state *st) |
---|
| 1388 | +{ |
---|
| 1389 | + int result; |
---|
| 1390 | + |
---|
| 1391 | + result = regulator_disable(st->vddio_supply); |
---|
| 1392 | + if (result) |
---|
| 1393 | + dev_err(regmap_get_device(st->map), |
---|
| 1394 | + "Failed to disable vddio regulator: %d\n", result); |
---|
| 1395 | + |
---|
| 1396 | + return result; |
---|
| 1397 | +} |
---|
| 1398 | + |
---|
| 1399 | +static void inv_mpu_core_disable_regulator_action(void *_data) |
---|
| 1400 | +{ |
---|
| 1401 | + struct inv_mpu6050_state *st = _data; |
---|
| 1402 | + int result; |
---|
| 1403 | + |
---|
| 1404 | + result = regulator_disable(st->vdd_supply); |
---|
| 1405 | + if (result) |
---|
| 1406 | + dev_err(regmap_get_device(st->map), |
---|
| 1407 | + "Failed to disable vdd regulator: %d\n", result); |
---|
| 1408 | + |
---|
| 1409 | + inv_mpu_core_disable_regulator_vddio(st); |
---|
| 1410 | +} |
---|
| 1411 | + |
---|
| 1412 | +static void inv_mpu_pm_disable(void *data) |
---|
| 1413 | +{ |
---|
| 1414 | + struct device *dev = data; |
---|
| 1415 | + |
---|
| 1416 | + pm_runtime_put_sync_suspend(dev); |
---|
| 1417 | + pm_runtime_disable(dev); |
---|
1041 | 1418 | } |
---|
1042 | 1419 | |
---|
1043 | 1420 | int inv_mpu_core_probe(struct regmap *regmap, int irq, const char *name, |
---|
.. | .. |
---|
1064 | 1441 | st = iio_priv(indio_dev); |
---|
1065 | 1442 | mutex_init(&st->lock); |
---|
1066 | 1443 | st->chip_type = chip_type; |
---|
1067 | | - st->powerup_count = 0; |
---|
1068 | 1444 | st->irq = irq; |
---|
1069 | 1445 | st->map = regmap; |
---|
1070 | 1446 | |
---|
1071 | 1447 | pdata = dev_get_platdata(dev); |
---|
1072 | 1448 | if (!pdata) { |
---|
1073 | | - result = of_iio_read_mount_matrix(dev, "mount-matrix", |
---|
1074 | | - &st->orientation); |
---|
| 1449 | + result = iio_read_mount_matrix(dev, "mount-matrix", |
---|
| 1450 | + &st->orientation); |
---|
1075 | 1451 | if (result) { |
---|
1076 | 1452 | dev_err(dev, "Failed to retrieve mounting matrix %d\n", |
---|
1077 | 1453 | result); |
---|
.. | .. |
---|
1090 | 1466 | irq_type = irqd_get_trigger_type(desc); |
---|
1091 | 1467 | if (!irq_type) |
---|
1092 | 1468 | irq_type = IRQF_TRIGGER_RISING; |
---|
1093 | | - if (irq_type == IRQF_TRIGGER_RISING) |
---|
| 1469 | + if (irq_type & IRQF_TRIGGER_RISING) // rising or both-edge |
---|
1094 | 1470 | st->irq_mask = INV_MPU6050_ACTIVE_HIGH; |
---|
1095 | 1471 | else if (irq_type == IRQF_TRIGGER_FALLING) |
---|
1096 | 1472 | st->irq_mask = INV_MPU6050_ACTIVE_LOW; |
---|
.. | .. |
---|
1106 | 1482 | return -EINVAL; |
---|
1107 | 1483 | } |
---|
1108 | 1484 | |
---|
| 1485 | + st->vdd_supply = devm_regulator_get(dev, "vdd"); |
---|
| 1486 | + if (IS_ERR(st->vdd_supply)) |
---|
| 1487 | + return dev_err_probe(dev, PTR_ERR(st->vdd_supply), |
---|
| 1488 | + "Failed to get vdd regulator\n"); |
---|
| 1489 | + |
---|
| 1490 | + st->vddio_supply = devm_regulator_get(dev, "vddio"); |
---|
| 1491 | + if (IS_ERR(st->vddio_supply)) |
---|
| 1492 | + return dev_err_probe(dev, PTR_ERR(st->vddio_supply), |
---|
| 1493 | + "Failed to get vddio regulator\n"); |
---|
| 1494 | + |
---|
| 1495 | + result = regulator_enable(st->vdd_supply); |
---|
| 1496 | + if (result) { |
---|
| 1497 | + dev_err(dev, "Failed to enable vdd regulator: %d\n", result); |
---|
| 1498 | + return result; |
---|
| 1499 | + } |
---|
| 1500 | + msleep(INV_MPU6050_POWER_UP_TIME); |
---|
| 1501 | + |
---|
| 1502 | + result = inv_mpu_core_enable_regulator_vddio(st); |
---|
| 1503 | + if (result) { |
---|
| 1504 | + regulator_disable(st->vdd_supply); |
---|
| 1505 | + return result; |
---|
| 1506 | + } |
---|
| 1507 | + |
---|
| 1508 | + result = devm_add_action_or_reset(dev, inv_mpu_core_disable_regulator_action, |
---|
| 1509 | + st); |
---|
| 1510 | + if (result) { |
---|
| 1511 | + dev_err(dev, "Failed to setup regulator cleanup action %d\n", |
---|
| 1512 | + result); |
---|
| 1513 | + return result; |
---|
| 1514 | + } |
---|
| 1515 | + |
---|
| 1516 | + /* fill magnetometer orientation */ |
---|
| 1517 | + result = inv_mpu_magn_set_orient(st); |
---|
| 1518 | + if (result) |
---|
| 1519 | + return result; |
---|
| 1520 | + |
---|
1109 | 1521 | /* power is turned on inside check chip type*/ |
---|
1110 | 1522 | result = inv_check_and_setup_chip(st); |
---|
1111 | 1523 | if (result) |
---|
.. | .. |
---|
1114 | 1526 | result = inv_mpu6050_init_config(indio_dev); |
---|
1115 | 1527 | if (result) { |
---|
1116 | 1528 | dev_err(dev, "Could not initialize device.\n"); |
---|
1117 | | - return result; |
---|
| 1529 | + goto error_power_off; |
---|
1118 | 1530 | } |
---|
1119 | 1531 | |
---|
1120 | | - if (inv_mpu_bus_setup) |
---|
1121 | | - inv_mpu_bus_setup(indio_dev); |
---|
1122 | | - |
---|
1123 | 1532 | dev_set_drvdata(dev, indio_dev); |
---|
1124 | | - indio_dev->dev.parent = dev; |
---|
1125 | 1533 | /* name will be NULL when enumerated via ACPI */ |
---|
1126 | 1534 | if (name) |
---|
1127 | 1535 | indio_dev->name = name; |
---|
1128 | 1536 | else |
---|
1129 | 1537 | indio_dev->name = dev_name(dev); |
---|
1130 | 1538 | |
---|
1131 | | - if (chip_type == INV_ICM20602) { |
---|
1132 | | - indio_dev->channels = inv_icm20602_channels; |
---|
1133 | | - indio_dev->num_channels = ARRAY_SIZE(inv_icm20602_channels); |
---|
| 1539 | + /* requires parent device set in indio_dev */ |
---|
| 1540 | + if (inv_mpu_bus_setup) { |
---|
| 1541 | + result = inv_mpu_bus_setup(indio_dev); |
---|
| 1542 | + if (result) |
---|
| 1543 | + goto error_power_off; |
---|
| 1544 | + } |
---|
| 1545 | + |
---|
| 1546 | + /* chip init is done, turning on runtime power management */ |
---|
| 1547 | + result = pm_runtime_set_active(dev); |
---|
| 1548 | + if (result) |
---|
| 1549 | + goto error_power_off; |
---|
| 1550 | + pm_runtime_get_noresume(dev); |
---|
| 1551 | + pm_runtime_enable(dev); |
---|
| 1552 | + pm_runtime_set_autosuspend_delay(dev, INV_MPU6050_SUSPEND_DELAY_MS); |
---|
| 1553 | + pm_runtime_use_autosuspend(dev); |
---|
| 1554 | + pm_runtime_put(dev); |
---|
| 1555 | + result = devm_add_action_or_reset(dev, inv_mpu_pm_disable, dev); |
---|
| 1556 | + if (result) |
---|
| 1557 | + return result; |
---|
| 1558 | + |
---|
| 1559 | + switch (chip_type) { |
---|
| 1560 | + case INV_MPU9150: |
---|
| 1561 | + indio_dev->channels = inv_mpu9150_channels; |
---|
| 1562 | + indio_dev->num_channels = ARRAY_SIZE(inv_mpu9150_channels); |
---|
| 1563 | + indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; |
---|
| 1564 | + break; |
---|
| 1565 | + case INV_MPU9250: |
---|
| 1566 | + case INV_MPU9255: |
---|
| 1567 | + indio_dev->channels = inv_mpu9250_channels; |
---|
| 1568 | + indio_dev->num_channels = ARRAY_SIZE(inv_mpu9250_channels); |
---|
| 1569 | + indio_dev->available_scan_masks = inv_mpu9x50_scan_masks; |
---|
| 1570 | + break; |
---|
| 1571 | + case INV_ICM20602: |
---|
| 1572 | + indio_dev->channels = inv_mpu_channels; |
---|
| 1573 | + indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); |
---|
1134 | 1574 | indio_dev->available_scan_masks = inv_icm20602_scan_masks; |
---|
1135 | | - } else { |
---|
| 1575 | + break; |
---|
| 1576 | + default: |
---|
| 1577 | + indio_dev->channels = inv_mpu_channels; |
---|
| 1578 | + indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); |
---|
| 1579 | + indio_dev->available_scan_masks = inv_mpu_scan_masks; |
---|
| 1580 | + break; |
---|
| 1581 | + } |
---|
| 1582 | + /* |
---|
| 1583 | + * Use magnetometer inside the chip only if there is no i2c |
---|
| 1584 | + * auxiliary device in use. Otherwise Going back to 6-axis only. |
---|
| 1585 | + */ |
---|
| 1586 | + if (st->magn_disabled) { |
---|
1136 | 1587 | indio_dev->channels = inv_mpu_channels; |
---|
1137 | 1588 | indio_dev->num_channels = ARRAY_SIZE(inv_mpu_channels); |
---|
1138 | 1589 | indio_dev->available_scan_masks = inv_mpu_scan_masks; |
---|
.. | .. |
---|
1162 | 1613 | } |
---|
1163 | 1614 | |
---|
1164 | 1615 | return 0; |
---|
| 1616 | + |
---|
| 1617 | +error_power_off: |
---|
| 1618 | + inv_mpu6050_set_power_itg(st, false); |
---|
| 1619 | + return result; |
---|
1165 | 1620 | } |
---|
1166 | 1621 | EXPORT_SYMBOL_GPL(inv_mpu_core_probe); |
---|
1167 | 1622 | |
---|
1168 | | -#ifdef CONFIG_PM_SLEEP |
---|
1169 | | - |
---|
1170 | | -static int inv_mpu_resume(struct device *dev) |
---|
| 1623 | +static int __maybe_unused inv_mpu_resume(struct device *dev) |
---|
1171 | 1624 | { |
---|
1172 | | - struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev)); |
---|
| 1625 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); |
---|
| 1626 | + struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
1173 | 1627 | int result; |
---|
1174 | 1628 | |
---|
1175 | 1629 | mutex_lock(&st->lock); |
---|
| 1630 | + result = inv_mpu_core_enable_regulator_vddio(st); |
---|
| 1631 | + if (result) |
---|
| 1632 | + goto out_unlock; |
---|
| 1633 | + |
---|
1176 | 1634 | result = inv_mpu6050_set_power_itg(st, true); |
---|
| 1635 | + if (result) |
---|
| 1636 | + goto out_unlock; |
---|
| 1637 | + |
---|
| 1638 | + pm_runtime_disable(dev); |
---|
| 1639 | + pm_runtime_set_active(dev); |
---|
| 1640 | + pm_runtime_enable(dev); |
---|
| 1641 | + |
---|
| 1642 | + result = inv_mpu6050_switch_engine(st, true, st->suspended_sensors); |
---|
| 1643 | + if (result) |
---|
| 1644 | + goto out_unlock; |
---|
| 1645 | + |
---|
| 1646 | + if (iio_buffer_enabled(indio_dev)) |
---|
| 1647 | + result = inv_mpu6050_prepare_fifo(st, true); |
---|
| 1648 | + |
---|
| 1649 | +out_unlock: |
---|
1177 | 1650 | mutex_unlock(&st->lock); |
---|
1178 | 1651 | |
---|
1179 | 1652 | return result; |
---|
1180 | 1653 | } |
---|
1181 | 1654 | |
---|
1182 | | -static int inv_mpu_suspend(struct device *dev) |
---|
| 1655 | +static int __maybe_unused inv_mpu_suspend(struct device *dev) |
---|
1183 | 1656 | { |
---|
1184 | | - struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev)); |
---|
| 1657 | + struct iio_dev *indio_dev = dev_get_drvdata(dev); |
---|
| 1658 | + struct inv_mpu6050_state *st = iio_priv(indio_dev); |
---|
1185 | 1659 | int result; |
---|
1186 | 1660 | |
---|
1187 | 1661 | mutex_lock(&st->lock); |
---|
| 1662 | + |
---|
| 1663 | + st->suspended_sensors = 0; |
---|
| 1664 | + if (pm_runtime_suspended(dev)) { |
---|
| 1665 | + result = 0; |
---|
| 1666 | + goto out_unlock; |
---|
| 1667 | + } |
---|
| 1668 | + |
---|
| 1669 | + if (iio_buffer_enabled(indio_dev)) { |
---|
| 1670 | + result = inv_mpu6050_prepare_fifo(st, false); |
---|
| 1671 | + if (result) |
---|
| 1672 | + goto out_unlock; |
---|
| 1673 | + } |
---|
| 1674 | + |
---|
| 1675 | + if (st->chip_config.accl_en) |
---|
| 1676 | + st->suspended_sensors |= INV_MPU6050_SENSOR_ACCL; |
---|
| 1677 | + if (st->chip_config.gyro_en) |
---|
| 1678 | + st->suspended_sensors |= INV_MPU6050_SENSOR_GYRO; |
---|
| 1679 | + if (st->chip_config.temp_en) |
---|
| 1680 | + st->suspended_sensors |= INV_MPU6050_SENSOR_TEMP; |
---|
| 1681 | + if (st->chip_config.magn_en) |
---|
| 1682 | + st->suspended_sensors |= INV_MPU6050_SENSOR_MAGN; |
---|
| 1683 | + result = inv_mpu6050_switch_engine(st, false, st->suspended_sensors); |
---|
| 1684 | + if (result) |
---|
| 1685 | + goto out_unlock; |
---|
| 1686 | + |
---|
1188 | 1687 | result = inv_mpu6050_set_power_itg(st, false); |
---|
| 1688 | + if (result) |
---|
| 1689 | + goto out_unlock; |
---|
| 1690 | + |
---|
| 1691 | + inv_mpu_core_disable_regulator_vddio(st); |
---|
| 1692 | +out_unlock: |
---|
1189 | 1693 | mutex_unlock(&st->lock); |
---|
1190 | 1694 | |
---|
1191 | 1695 | return result; |
---|
1192 | 1696 | } |
---|
1193 | | -#endif /* CONFIG_PM_SLEEP */ |
---|
1194 | 1697 | |
---|
1195 | | -SIMPLE_DEV_PM_OPS(inv_mpu_pmops, inv_mpu_suspend, inv_mpu_resume); |
---|
| 1698 | +static int __maybe_unused inv_mpu_runtime_suspend(struct device *dev) |
---|
| 1699 | +{ |
---|
| 1700 | + struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev)); |
---|
| 1701 | + unsigned int sensors; |
---|
| 1702 | + int ret; |
---|
| 1703 | + |
---|
| 1704 | + mutex_lock(&st->lock); |
---|
| 1705 | + |
---|
| 1706 | + sensors = INV_MPU6050_SENSOR_ACCL | INV_MPU6050_SENSOR_GYRO | |
---|
| 1707 | + INV_MPU6050_SENSOR_TEMP | INV_MPU6050_SENSOR_MAGN; |
---|
| 1708 | + ret = inv_mpu6050_switch_engine(st, false, sensors); |
---|
| 1709 | + if (ret) |
---|
| 1710 | + goto out_unlock; |
---|
| 1711 | + |
---|
| 1712 | + ret = inv_mpu6050_set_power_itg(st, false); |
---|
| 1713 | + if (ret) |
---|
| 1714 | + goto out_unlock; |
---|
| 1715 | + |
---|
| 1716 | + inv_mpu_core_disable_regulator_vddio(st); |
---|
| 1717 | + |
---|
| 1718 | +out_unlock: |
---|
| 1719 | + mutex_unlock(&st->lock); |
---|
| 1720 | + return ret; |
---|
| 1721 | +} |
---|
| 1722 | + |
---|
| 1723 | +static int __maybe_unused inv_mpu_runtime_resume(struct device *dev) |
---|
| 1724 | +{ |
---|
| 1725 | + struct inv_mpu6050_state *st = iio_priv(dev_get_drvdata(dev)); |
---|
| 1726 | + int ret; |
---|
| 1727 | + |
---|
| 1728 | + ret = inv_mpu_core_enable_regulator_vddio(st); |
---|
| 1729 | + if (ret) |
---|
| 1730 | + return ret; |
---|
| 1731 | + |
---|
| 1732 | + return inv_mpu6050_set_power_itg(st, true); |
---|
| 1733 | +} |
---|
| 1734 | + |
---|
| 1735 | +const struct dev_pm_ops inv_mpu_pmops = { |
---|
| 1736 | + SET_SYSTEM_SLEEP_PM_OPS(inv_mpu_suspend, inv_mpu_resume) |
---|
| 1737 | + SET_RUNTIME_PM_OPS(inv_mpu_runtime_suspend, inv_mpu_runtime_resume, NULL) |
---|
| 1738 | +}; |
---|
1196 | 1739 | EXPORT_SYMBOL_GPL(inv_mpu_pmops); |
---|
1197 | 1740 | |
---|
1198 | 1741 | MODULE_AUTHOR("Invensense Corporation"); |
---|