1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2020 Invensense, Inc. 4 */ 5 6 #include <linux/kernel.h> 7 #include <linux/device.h> 8 #include <linux/mutex.h> 9 #include <linux/pm_runtime.h> 10 #include <linux/regmap.h> 11 #include <linux/delay.h> 12 #include <linux/math64.h> 13 #include <linux/minmax.h> 14 #include <linux/units.h> 15 16 #include <linux/iio/buffer.h> 17 #include <linux/iio/common/inv_sensors_timestamp.h> 18 #include <linux/iio/events.h> 19 #include <linux/iio/iio.h> 20 #include <linux/iio/kfifo_buf.h> 21 22 #include "inv_icm42600.h" 23 #include "inv_icm42600_temp.h" 24 #include "inv_icm42600_buffer.h" 25 26 #define INV_ICM42600_ACCEL_CHAN(_modifier, _index, _ext_info) \ 27 { \ 28 .type = IIO_ACCEL, \ 29 .modified = 1, \ 30 .channel2 = _modifier, \ 31 .info_mask_separate = \ 32 BIT(IIO_CHAN_INFO_RAW) | \ 33 BIT(IIO_CHAN_INFO_CALIBBIAS), \ 34 .info_mask_shared_by_type = \ 35 BIT(IIO_CHAN_INFO_SCALE), \ 36 .info_mask_shared_by_type_available = \ 37 BIT(IIO_CHAN_INFO_SCALE) | \ 38 BIT(IIO_CHAN_INFO_CALIBBIAS), \ 39 .info_mask_shared_by_all = \ 40 BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 41 .info_mask_shared_by_all_available = \ 42 BIT(IIO_CHAN_INFO_SAMP_FREQ), \ 43 .scan_index = _index, \ 44 .scan_type = { \ 45 .sign = 's', \ 46 .realbits = 16, \ 47 .storagebits = 16, \ 48 .endianness = IIO_BE, \ 49 }, \ 50 .ext_info = _ext_info, \ 51 } 52 53 #define INV_ICM42600_ACCEL_EVENT_CHAN(_modifier, _events, _events_nb) \ 54 { \ 55 .type = IIO_ACCEL, \ 56 .modified = 1, \ 57 .channel2 = _modifier, \ 58 .event_spec = _events, \ 59 .num_event_specs = _events_nb, \ 60 .scan_index = -1, \ 61 } 62 63 enum inv_icm42600_accel_scan { 64 INV_ICM42600_ACCEL_SCAN_X, 65 INV_ICM42600_ACCEL_SCAN_Y, 66 INV_ICM42600_ACCEL_SCAN_Z, 67 INV_ICM42600_ACCEL_SCAN_TEMP, 68 INV_ICM42600_ACCEL_SCAN_TIMESTAMP, 69 }; 70 71 static const char * const inv_icm42600_accel_power_mode_items[] = { 72 "low-noise", 73 "low-power", 74 }; 75 static const int inv_icm42600_accel_power_mode_values[] = { 76 INV_ICM42600_SENSOR_MODE_LOW_NOISE, 77 INV_ICM42600_SENSOR_MODE_LOW_POWER, 78 }; 79 static const int inv_icm42600_accel_filter_values[] = { 80 INV_ICM42600_FILTER_BW_ODR_DIV_2, 81 INV_ICM42600_FILTER_AVG_16X, 82 }; 83 84 static int inv_icm42600_accel_power_mode_set(struct iio_dev *indio_dev, 85 const struct iio_chan_spec *chan, 86 unsigned int idx) 87 { 88 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 89 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 90 int power_mode, filter; 91 92 if (chan->type != IIO_ACCEL) 93 return -EINVAL; 94 95 if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values)) 96 return -EINVAL; 97 98 power_mode = inv_icm42600_accel_power_mode_values[idx]; 99 filter = inv_icm42600_accel_filter_values[idx]; 100 101 guard(mutex)(&st->lock); 102 103 /* cannot change if accel sensor is on */ 104 if (st->conf.accel.mode != INV_ICM42600_SENSOR_MODE_OFF) 105 return -EBUSY; 106 107 /* prevent change if power mode is not supported by the ODR */ 108 switch (power_mode) { 109 case INV_ICM42600_SENSOR_MODE_LOW_NOISE: 110 if (st->conf.accel.odr >= INV_ICM42600_ODR_6_25HZ_LP && 111 st->conf.accel.odr <= INV_ICM42600_ODR_1_5625HZ_LP) 112 return -EPERM; 113 break; 114 case INV_ICM42600_SENSOR_MODE_LOW_POWER: 115 default: 116 if (st->conf.accel.odr <= INV_ICM42600_ODR_1KHZ_LN) 117 return -EPERM; 118 break; 119 } 120 121 accel_st->power_mode = power_mode; 122 accel_st->filter = filter; 123 124 return 0; 125 } 126 127 static int inv_icm42600_accel_power_mode_get(struct iio_dev *indio_dev, 128 const struct iio_chan_spec *chan) 129 { 130 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 131 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 132 unsigned int idx; 133 int power_mode; 134 135 if (chan->type != IIO_ACCEL) 136 return -EINVAL; 137 138 guard(mutex)(&st->lock); 139 140 /* if sensor is on, returns actual power mode and not configured one */ 141 switch (st->conf.accel.mode) { 142 case INV_ICM42600_SENSOR_MODE_LOW_POWER: 143 case INV_ICM42600_SENSOR_MODE_LOW_NOISE: 144 power_mode = st->conf.accel.mode; 145 break; 146 default: 147 power_mode = accel_st->power_mode; 148 break; 149 } 150 151 for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_power_mode_values); ++idx) { 152 if (power_mode == inv_icm42600_accel_power_mode_values[idx]) 153 break; 154 } 155 if (idx >= ARRAY_SIZE(inv_icm42600_accel_power_mode_values)) 156 return -EINVAL; 157 158 return idx; 159 } 160 161 static const struct iio_enum inv_icm42600_accel_power_mode_enum = { 162 .items = inv_icm42600_accel_power_mode_items, 163 .num_items = ARRAY_SIZE(inv_icm42600_accel_power_mode_items), 164 .set = inv_icm42600_accel_power_mode_set, 165 .get = inv_icm42600_accel_power_mode_get, 166 }; 167 168 static const struct iio_chan_spec_ext_info inv_icm42600_accel_ext_infos[] = { 169 IIO_MOUNT_MATRIX(IIO_SHARED_BY_ALL, inv_icm42600_get_mount_matrix), 170 IIO_ENUM_AVAILABLE("power_mode", IIO_SHARED_BY_TYPE, 171 &inv_icm42600_accel_power_mode_enum), 172 IIO_ENUM("power_mode", IIO_SHARED_BY_TYPE, 173 &inv_icm42600_accel_power_mode_enum), 174 { } 175 }; 176 177 /* WoM event: rising ROC */ 178 static const struct iio_event_spec inv_icm42600_wom_events[] = { 179 { 180 .type = IIO_EV_TYPE_ROC, 181 .dir = IIO_EV_DIR_RISING, 182 .mask_separate = BIT(IIO_EV_INFO_ENABLE) | 183 BIT(IIO_EV_INFO_VALUE), 184 }, 185 }; 186 187 static const struct iio_chan_spec inv_icm42600_accel_channels[] = { 188 INV_ICM42600_ACCEL_CHAN(IIO_MOD_X, INV_ICM42600_ACCEL_SCAN_X, 189 inv_icm42600_accel_ext_infos), 190 INV_ICM42600_ACCEL_CHAN(IIO_MOD_Y, INV_ICM42600_ACCEL_SCAN_Y, 191 inv_icm42600_accel_ext_infos), 192 INV_ICM42600_ACCEL_CHAN(IIO_MOD_Z, INV_ICM42600_ACCEL_SCAN_Z, 193 inv_icm42600_accel_ext_infos), 194 INV_ICM42600_TEMP_CHAN(INV_ICM42600_ACCEL_SCAN_TEMP), 195 IIO_CHAN_SOFT_TIMESTAMP(INV_ICM42600_ACCEL_SCAN_TIMESTAMP), 196 INV_ICM42600_ACCEL_EVENT_CHAN(IIO_MOD_X_OR_Y_OR_Z, inv_icm42600_wom_events, 197 ARRAY_SIZE(inv_icm42600_wom_events)), 198 }; 199 200 /* 201 * IIO buffer data: size must be a power of 2 and timestamp aligned 202 * 16 bytes: 6 bytes acceleration, 2 bytes temperature, 8 bytes timestamp 203 */ 204 struct inv_icm42600_accel_buffer { 205 struct inv_icm42600_fifo_sensor_data accel; 206 s16 temp; 207 aligned_s64 timestamp; 208 }; 209 210 #define INV_ICM42600_SCAN_MASK_ACCEL_3AXIS \ 211 (BIT(INV_ICM42600_ACCEL_SCAN_X) | \ 212 BIT(INV_ICM42600_ACCEL_SCAN_Y) | \ 213 BIT(INV_ICM42600_ACCEL_SCAN_Z)) 214 215 #define INV_ICM42600_SCAN_MASK_TEMP BIT(INV_ICM42600_ACCEL_SCAN_TEMP) 216 217 static const unsigned long inv_icm42600_accel_scan_masks[] = { 218 /* 3-axis accel + temperature */ 219 INV_ICM42600_SCAN_MASK_ACCEL_3AXIS | INV_ICM42600_SCAN_MASK_TEMP, 220 0, 221 }; 222 223 /* enable accelerometer sensor and FIFO write */ 224 static int inv_icm42600_accel_update_scan_mode(struct iio_dev *indio_dev, 225 const unsigned long *scan_mask) 226 { 227 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 228 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 229 struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; 230 unsigned int fifo_en = 0; 231 unsigned int sleep_temp = 0; 232 unsigned int sleep_accel = 0; 233 unsigned int sleep; 234 int ret; 235 236 mutex_lock(&st->lock); 237 238 if (*scan_mask & INV_ICM42600_SCAN_MASK_TEMP) { 239 /* enable temp sensor */ 240 ret = inv_icm42600_set_temp_conf(st, true, &sleep_temp); 241 if (ret) 242 goto out_unlock; 243 fifo_en |= INV_ICM42600_SENSOR_TEMP; 244 } 245 246 if (*scan_mask & INV_ICM42600_SCAN_MASK_ACCEL_3AXIS) { 247 /* enable accel sensor */ 248 conf.mode = accel_st->power_mode; 249 conf.filter = accel_st->filter; 250 ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_accel); 251 if (ret) 252 goto out_unlock; 253 fifo_en |= INV_ICM42600_SENSOR_ACCEL; 254 } 255 256 /* update data FIFO write */ 257 ret = inv_icm42600_buffer_set_fifo_en(st, fifo_en | st->fifo.en); 258 259 out_unlock: 260 mutex_unlock(&st->lock); 261 /* sleep maximum required time */ 262 sleep = max(sleep_accel, sleep_temp); 263 if (sleep) 264 msleep(sleep); 265 return ret; 266 } 267 268 static int inv_icm42600_accel_read_sensor(struct iio_dev *indio_dev, 269 struct iio_chan_spec const *chan, 270 s16 *val) 271 { 272 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 273 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 274 struct device *dev = regmap_get_device(st->map); 275 struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; 276 unsigned int reg; 277 __be16 *data; 278 int ret; 279 280 if (chan->type != IIO_ACCEL) 281 return -EINVAL; 282 283 switch (chan->channel2) { 284 case IIO_MOD_X: 285 reg = INV_ICM42600_REG_ACCEL_DATA_X; 286 break; 287 case IIO_MOD_Y: 288 reg = INV_ICM42600_REG_ACCEL_DATA_Y; 289 break; 290 case IIO_MOD_Z: 291 reg = INV_ICM42600_REG_ACCEL_DATA_Z; 292 break; 293 default: 294 return -EINVAL; 295 } 296 297 pm_runtime_get_sync(dev); 298 mutex_lock(&st->lock); 299 300 /* enable accel sensor */ 301 conf.mode = accel_st->power_mode; 302 conf.filter = accel_st->filter; 303 ret = inv_icm42600_set_accel_conf(st, &conf, NULL); 304 if (ret) 305 goto exit; 306 307 /* read accel register data */ 308 data = (__be16 *)&st->buffer[0]; 309 ret = regmap_bulk_read(st->map, reg, data, sizeof(*data)); 310 if (ret) 311 goto exit; 312 313 *val = (s16)be16_to_cpup(data); 314 if (*val == INV_ICM42600_DATA_INVALID) 315 ret = -EINVAL; 316 exit: 317 mutex_unlock(&st->lock); 318 pm_runtime_put_autosuspend(dev); 319 return ret; 320 } 321 322 static unsigned int inv_icm42600_accel_convert_roc_to_wom(u64 roc, 323 int accel_hz, int accel_uhz) 324 { 325 /* 1000/256mg per LSB converted in µm/s² */ 326 const unsigned int convert = (9807U * (MICRO / MILLI)) / 256U; 327 u64 value; 328 u64 freq_uhz; 329 330 /* return 0 only if roc is 0 */ 331 if (roc == 0) 332 return 0; 333 334 freq_uhz = (u64)accel_hz * MICRO + (u64)accel_uhz; 335 value = div64_u64(roc * MICRO, freq_uhz * (u64)convert); 336 337 /* limit value to 8 bits and prevent 0 */ 338 return clamp(value, 1, 255); 339 } 340 341 static u64 inv_icm42600_accel_convert_wom_to_roc(unsigned int threshold, 342 int accel_hz, int accel_uhz) 343 { 344 /* 1000/256mg per LSB converted in µm/s² */ 345 const unsigned int convert = (9807U * (MICRO / MILLI)) / 256U; 346 u64 value; 347 u64 freq_uhz; 348 349 value = threshold * convert; 350 freq_uhz = (u64)accel_hz * MICRO + (u64)accel_uhz; 351 352 /* compute the differential by multiplying by the frequency */ 353 return div_u64(value * freq_uhz, MICRO); 354 } 355 356 static int inv_icm42600_accel_set_wom_threshold(struct inv_icm42600_state *st, 357 u64 value, 358 int accel_hz, int accel_uhz) 359 { 360 unsigned int threshold; 361 int ret; 362 363 /* convert roc to wom threshold and convert back to handle clipping */ 364 threshold = inv_icm42600_accel_convert_roc_to_wom(value, accel_hz, accel_uhz); 365 value = inv_icm42600_accel_convert_wom_to_roc(threshold, accel_hz, accel_uhz); 366 367 dev_dbg(regmap_get_device(st->map), "wom_threshold: 0x%x\n", threshold); 368 369 /* set accel WoM threshold for the 3 axes */ 370 st->buffer[0] = threshold; 371 st->buffer[1] = threshold; 372 st->buffer[2] = threshold; 373 ret = regmap_bulk_write(st->map, INV_ICM42600_REG_ACCEL_WOM_X_THR, st->buffer, 3); 374 if (ret) 375 return ret; 376 377 st->apex.wom.value = value; 378 379 return 0; 380 } 381 382 static int _inv_icm42600_accel_enable_wom(struct iio_dev *indio_dev) 383 { 384 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 385 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 386 struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; 387 unsigned int sleep_ms = 0; 388 int ret; 389 390 scoped_guard(mutex, &st->lock) { 391 /* turn on accel sensor */ 392 conf.mode = accel_st->power_mode; 393 conf.filter = accel_st->filter; 394 ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_ms); 395 if (ret) 396 return ret; 397 } 398 399 if (sleep_ms) 400 msleep(sleep_ms); 401 402 scoped_guard(mutex, &st->lock) { 403 ret = inv_icm42600_enable_wom(st); 404 if (ret) 405 return ret; 406 st->apex.on++; 407 st->apex.wom.enable = true; 408 } 409 410 return 0; 411 } 412 413 static int inv_icm42600_accel_enable_wom(struct iio_dev *indio_dev) 414 { 415 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 416 struct device *pdev = regmap_get_device(st->map); 417 int ret; 418 419 ret = pm_runtime_resume_and_get(pdev); 420 if (ret) 421 return ret; 422 423 ret = _inv_icm42600_accel_enable_wom(indio_dev); 424 if (ret) { 425 pm_runtime_mark_last_busy(pdev); 426 pm_runtime_put_autosuspend(pdev); 427 return ret; 428 } 429 430 return 0; 431 } 432 433 static int _inv_icm42600_accel_disable_wom(struct iio_dev *indio_dev) 434 { 435 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 436 struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; 437 unsigned int sleep_ms = 0; 438 int ret; 439 440 scoped_guard(mutex, &st->lock) { 441 /* 442 * Consider that turning off WoM is always working to avoid 443 * blocking the chip in on mode and prevent going back to sleep. 444 * If there is an error, the chip will anyway go back to sleep 445 * and the feature will not work anymore. 446 */ 447 st->apex.wom.enable = false; 448 st->apex.on--; 449 ret = inv_icm42600_disable_wom(st); 450 if (ret) 451 return ret; 452 /* turn off accel sensor if not used */ 453 if (!st->apex.on && !iio_buffer_enabled(indio_dev)) { 454 conf.mode = INV_ICM42600_SENSOR_MODE_OFF; 455 ret = inv_icm42600_set_accel_conf(st, &conf, &sleep_ms); 456 if (ret) 457 return ret; 458 } 459 } 460 461 if (sleep_ms) 462 msleep(sleep_ms); 463 464 return 0; 465 } 466 467 static int inv_icm42600_accel_disable_wom(struct iio_dev *indio_dev) 468 { 469 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 470 struct device *pdev = regmap_get_device(st->map); 471 int ret; 472 473 ret = _inv_icm42600_accel_disable_wom(indio_dev); 474 475 pm_runtime_mark_last_busy(pdev); 476 pm_runtime_put_autosuspend(pdev); 477 478 return ret; 479 } 480 481 void inv_icm42600_accel_handle_events(struct iio_dev *indio_dev, 482 unsigned int status2, unsigned int status3, 483 s64 timestamp) 484 { 485 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 486 u64 ev_code; 487 488 /* handle WoM event */ 489 if (st->apex.wom.enable && (status2 & INV_ICM42600_INT_STATUS2_WOM_INT)) { 490 ev_code = IIO_MOD_EVENT_CODE(IIO_ACCEL, 0, IIO_MOD_X_OR_Y_OR_Z, 491 IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING); 492 iio_push_event(indio_dev, ev_code, timestamp); 493 } 494 } 495 496 /* IIO format int + nano */ 497 static const int inv_icm42600_accel_scale[] = { 498 /* +/- 16G => 0.004788403 m/s-2 */ 499 [2 * INV_ICM42600_ACCEL_FS_16G] = 0, 500 [2 * INV_ICM42600_ACCEL_FS_16G + 1] = 4788403, 501 /* +/- 8G => 0.002394202 m/s-2 */ 502 [2 * INV_ICM42600_ACCEL_FS_8G] = 0, 503 [2 * INV_ICM42600_ACCEL_FS_8G + 1] = 2394202, 504 /* +/- 4G => 0.001197101 m/s-2 */ 505 [2 * INV_ICM42600_ACCEL_FS_4G] = 0, 506 [2 * INV_ICM42600_ACCEL_FS_4G + 1] = 1197101, 507 /* +/- 2G => 0.000598550 m/s-2 */ 508 [2 * INV_ICM42600_ACCEL_FS_2G] = 0, 509 [2 * INV_ICM42600_ACCEL_FS_2G + 1] = 598550, 510 }; 511 static const int inv_icm42686_accel_scale[] = { 512 /* +/- 32G => 0.009576807 m/s-2 */ 513 [2 * INV_ICM42686_ACCEL_FS_32G] = 0, 514 [2 * INV_ICM42686_ACCEL_FS_32G + 1] = 9576807, 515 /* +/- 16G => 0.004788403 m/s-2 */ 516 [2 * INV_ICM42686_ACCEL_FS_16G] = 0, 517 [2 * INV_ICM42686_ACCEL_FS_16G + 1] = 4788403, 518 /* +/- 8G => 0.002394202 m/s-2 */ 519 [2 * INV_ICM42686_ACCEL_FS_8G] = 0, 520 [2 * INV_ICM42686_ACCEL_FS_8G + 1] = 2394202, 521 /* +/- 4G => 0.001197101 m/s-2 */ 522 [2 * INV_ICM42686_ACCEL_FS_4G] = 0, 523 [2 * INV_ICM42686_ACCEL_FS_4G + 1] = 1197101, 524 /* +/- 2G => 0.000598550 m/s-2 */ 525 [2 * INV_ICM42686_ACCEL_FS_2G] = 0, 526 [2 * INV_ICM42686_ACCEL_FS_2G + 1] = 598550, 527 }; 528 529 static int inv_icm42600_accel_read_scale(struct iio_dev *indio_dev, 530 int *val, int *val2) 531 { 532 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 533 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 534 unsigned int idx; 535 536 idx = st->conf.accel.fs; 537 538 *val = accel_st->scales[2 * idx]; 539 *val2 = accel_st->scales[2 * idx + 1]; 540 return IIO_VAL_INT_PLUS_NANO; 541 } 542 543 static int inv_icm42600_accel_write_scale(struct iio_dev *indio_dev, 544 int val, int val2) 545 { 546 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 547 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 548 struct device *dev = regmap_get_device(st->map); 549 unsigned int idx; 550 struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; 551 int ret; 552 553 for (idx = 0; idx < accel_st->scales_len; idx += 2) { 554 if (val == accel_st->scales[idx] && 555 val2 == accel_st->scales[idx + 1]) 556 break; 557 } 558 if (idx >= accel_st->scales_len) 559 return -EINVAL; 560 561 conf.fs = idx / 2; 562 563 pm_runtime_get_sync(dev); 564 565 scoped_guard(mutex, &st->lock) 566 ret = inv_icm42600_set_accel_conf(st, &conf, NULL); 567 568 pm_runtime_put_autosuspend(dev); 569 570 return ret; 571 } 572 573 /* IIO format int + micro */ 574 static const int inv_icm42600_accel_odr[] = { 575 /* 1.5625Hz */ 576 1, 562500, 577 /* 3.125Hz */ 578 3, 125000, 579 /* 6.25Hz */ 580 6, 250000, 581 /* 12.5Hz */ 582 12, 500000, 583 /* 25Hz */ 584 25, 0, 585 /* 50Hz */ 586 50, 0, 587 /* 100Hz */ 588 100, 0, 589 /* 200Hz */ 590 200, 0, 591 /* 1kHz */ 592 1000, 0, 593 /* 2kHz */ 594 2000, 0, 595 /* 4kHz */ 596 4000, 0, 597 }; 598 599 static const int inv_icm42600_accel_odr_conv[] = { 600 INV_ICM42600_ODR_1_5625HZ_LP, 601 INV_ICM42600_ODR_3_125HZ_LP, 602 INV_ICM42600_ODR_6_25HZ_LP, 603 INV_ICM42600_ODR_12_5HZ, 604 INV_ICM42600_ODR_25HZ, 605 INV_ICM42600_ODR_50HZ, 606 INV_ICM42600_ODR_100HZ, 607 INV_ICM42600_ODR_200HZ, 608 INV_ICM42600_ODR_1KHZ_LN, 609 INV_ICM42600_ODR_2KHZ_LN, 610 INV_ICM42600_ODR_4KHZ_LN, 611 }; 612 613 static int inv_icm42600_accel_read_odr(struct inv_icm42600_state *st, 614 int *val, int *val2) 615 { 616 unsigned int odr; 617 unsigned int i; 618 619 odr = st->conf.accel.odr; 620 621 for (i = 0; i < ARRAY_SIZE(inv_icm42600_accel_odr_conv); ++i) { 622 if (inv_icm42600_accel_odr_conv[i] == odr) 623 break; 624 } 625 if (i >= ARRAY_SIZE(inv_icm42600_accel_odr_conv)) 626 return -EINVAL; 627 628 *val = inv_icm42600_accel_odr[2 * i]; 629 *val2 = inv_icm42600_accel_odr[2 * i + 1]; 630 631 return IIO_VAL_INT_PLUS_MICRO; 632 } 633 634 static int inv_icm42600_accel_write_odr(struct iio_dev *indio_dev, 635 int val, int val2) 636 { 637 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 638 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 639 struct inv_sensors_timestamp *ts = &accel_st->ts; 640 struct device *dev = regmap_get_device(st->map); 641 unsigned int idx; 642 struct inv_icm42600_sensor_conf conf = INV_ICM42600_SENSOR_CONF_INIT; 643 int ret; 644 645 for (idx = 0; idx < ARRAY_SIZE(inv_icm42600_accel_odr); idx += 2) { 646 if (val == inv_icm42600_accel_odr[idx] && 647 val2 == inv_icm42600_accel_odr[idx + 1]) 648 break; 649 } 650 if (idx >= ARRAY_SIZE(inv_icm42600_accel_odr)) 651 return -EINVAL; 652 653 conf.odr = inv_icm42600_accel_odr_conv[idx / 2]; 654 655 pm_runtime_get_sync(dev); 656 mutex_lock(&st->lock); 657 658 ret = inv_sensors_timestamp_update_odr(ts, inv_icm42600_odr_to_period(conf.odr), 659 iio_buffer_enabled(indio_dev)); 660 if (ret) 661 goto out_unlock; 662 663 ret = inv_icm42600_set_accel_conf(st, &conf, NULL); 664 if (ret) 665 goto out_unlock; 666 /* update wom threshold since roc is dependent on sampling frequency */ 667 ret = inv_icm42600_accel_set_wom_threshold(st, st->apex.wom.value, val, val2); 668 if (ret) 669 goto out_unlock; 670 inv_icm42600_buffer_update_fifo_period(st); 671 inv_icm42600_buffer_update_watermark(st); 672 673 out_unlock: 674 mutex_unlock(&st->lock); 675 pm_runtime_put_autosuspend(dev); 676 677 return ret; 678 } 679 680 /* 681 * Calibration bias values, IIO range format int + micro. 682 * Value is limited to +/-1g coded on 12 bits signed. Step is 0.5mg. 683 */ 684 static int inv_icm42600_accel_calibbias[] = { 685 -10, 42010, /* min: -10.042010 m/s² */ 686 0, 4903, /* step: 0.004903 m/s² */ 687 10, 37106, /* max: 10.037106 m/s² */ 688 }; 689 690 static int inv_icm42600_accel_read_offset(struct inv_icm42600_state *st, 691 struct iio_chan_spec const *chan, 692 int *val, int *val2) 693 { 694 struct device *dev = regmap_get_device(st->map); 695 s64 val64; 696 s32 bias; 697 unsigned int reg; 698 s16 offset; 699 u8 data[2]; 700 int ret; 701 702 if (chan->type != IIO_ACCEL) 703 return -EINVAL; 704 705 switch (chan->channel2) { 706 case IIO_MOD_X: 707 reg = INV_ICM42600_REG_OFFSET_USER4; 708 break; 709 case IIO_MOD_Y: 710 reg = INV_ICM42600_REG_OFFSET_USER6; 711 break; 712 case IIO_MOD_Z: 713 reg = INV_ICM42600_REG_OFFSET_USER7; 714 break; 715 default: 716 return -EINVAL; 717 } 718 719 pm_runtime_get_sync(dev); 720 mutex_lock(&st->lock); 721 722 ret = regmap_bulk_read(st->map, reg, st->buffer, sizeof(data)); 723 memcpy(data, st->buffer, sizeof(data)); 724 725 mutex_unlock(&st->lock); 726 pm_runtime_put_autosuspend(dev); 727 if (ret) 728 return ret; 729 730 /* 12 bits signed value */ 731 switch (chan->channel2) { 732 case IIO_MOD_X: 733 offset = sign_extend32(((data[0] & 0xF0) << 4) | data[1], 11); 734 break; 735 case IIO_MOD_Y: 736 offset = sign_extend32(((data[1] & 0x0F) << 8) | data[0], 11); 737 break; 738 case IIO_MOD_Z: 739 offset = sign_extend32(((data[0] & 0xF0) << 4) | data[1], 11); 740 break; 741 default: 742 return -EINVAL; 743 } 744 745 /* 746 * convert raw offset to g then to m/s² 747 * 12 bits signed raw step 0.5mg to g: 5 / 10000 748 * g to m/s²: 9.806650 749 * result in micro (1000000) 750 * (offset * 5 * 9.806650 * 1000000) / 10000 751 */ 752 val64 = (s64)offset * 5LL * 9806650LL; 753 /* for rounding, add + or - divisor (10000) divided by 2 */ 754 if (val64 >= 0) 755 val64 += 10000LL / 2LL; 756 else 757 val64 -= 10000LL / 2LL; 758 bias = div_s64(val64, 10000L); 759 *val = bias / 1000000L; 760 *val2 = bias % 1000000L; 761 762 return IIO_VAL_INT_PLUS_MICRO; 763 } 764 765 static int inv_icm42600_accel_write_offset(struct inv_icm42600_state *st, 766 struct iio_chan_spec const *chan, 767 int val, int val2) 768 { 769 struct device *dev = regmap_get_device(st->map); 770 s64 val64; 771 s32 min, max; 772 unsigned int reg, regval; 773 s16 offset; 774 int ret; 775 776 if (chan->type != IIO_ACCEL) 777 return -EINVAL; 778 779 switch (chan->channel2) { 780 case IIO_MOD_X: 781 reg = INV_ICM42600_REG_OFFSET_USER4; 782 break; 783 case IIO_MOD_Y: 784 reg = INV_ICM42600_REG_OFFSET_USER6; 785 break; 786 case IIO_MOD_Z: 787 reg = INV_ICM42600_REG_OFFSET_USER7; 788 break; 789 default: 790 return -EINVAL; 791 } 792 793 /* inv_icm42600_accel_calibbias: min - step - max in micro */ 794 min = inv_icm42600_accel_calibbias[0] * 1000000L + 795 inv_icm42600_accel_calibbias[1]; 796 max = inv_icm42600_accel_calibbias[4] * 1000000L + 797 inv_icm42600_accel_calibbias[5]; 798 val64 = (s64)val * 1000000LL + (s64)val2; 799 if (val64 < min || val64 > max) 800 return -EINVAL; 801 802 /* 803 * convert m/s² to g then to raw value 804 * m/s² to g: 1 / 9.806650 805 * g to raw 12 bits signed, step 0.5mg: 10000 / 5 806 * val in micro (1000000) 807 * val * 10000 / (9.806650 * 1000000 * 5) 808 */ 809 val64 = val64 * 10000LL; 810 /* for rounding, add + or - divisor (9806650 * 5) divided by 2 */ 811 if (val64 >= 0) 812 val64 += 9806650 * 5 / 2; 813 else 814 val64 -= 9806650 * 5 / 2; 815 offset = div_s64(val64, 9806650 * 5); 816 817 /* clamp value limited to 12 bits signed */ 818 if (offset < -2048) 819 offset = -2048; 820 else if (offset > 2047) 821 offset = 2047; 822 823 pm_runtime_get_sync(dev); 824 mutex_lock(&st->lock); 825 826 switch (chan->channel2) { 827 case IIO_MOD_X: 828 /* OFFSET_USER4 register is shared */ 829 ret = regmap_read(st->map, INV_ICM42600_REG_OFFSET_USER4, 830 ®val); 831 if (ret) 832 goto out_unlock; 833 st->buffer[0] = ((offset & 0xF00) >> 4) | (regval & 0x0F); 834 st->buffer[1] = offset & 0xFF; 835 break; 836 case IIO_MOD_Y: 837 /* OFFSET_USER7 register is shared */ 838 ret = regmap_read(st->map, INV_ICM42600_REG_OFFSET_USER7, 839 ®val); 840 if (ret) 841 goto out_unlock; 842 st->buffer[0] = offset & 0xFF; 843 st->buffer[1] = ((offset & 0xF00) >> 8) | (regval & 0xF0); 844 break; 845 case IIO_MOD_Z: 846 /* OFFSET_USER7 register is shared */ 847 ret = regmap_read(st->map, INV_ICM42600_REG_OFFSET_USER7, 848 ®val); 849 if (ret) 850 goto out_unlock; 851 st->buffer[0] = ((offset & 0xF00) >> 4) | (regval & 0x0F); 852 st->buffer[1] = offset & 0xFF; 853 break; 854 default: 855 ret = -EINVAL; 856 goto out_unlock; 857 } 858 859 ret = regmap_bulk_write(st->map, reg, st->buffer, 2); 860 861 out_unlock: 862 mutex_unlock(&st->lock); 863 pm_runtime_put_autosuspend(dev); 864 return ret; 865 } 866 867 static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, 868 struct iio_chan_spec const *chan, 869 int *val, int *val2, long mask) 870 { 871 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 872 s16 data; 873 int ret; 874 875 switch (chan->type) { 876 case IIO_ACCEL: 877 break; 878 case IIO_TEMP: 879 return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); 880 default: 881 return -EINVAL; 882 } 883 884 switch (mask) { 885 case IIO_CHAN_INFO_RAW: 886 if (!iio_device_claim_direct(indio_dev)) 887 return -EBUSY; 888 ret = inv_icm42600_accel_read_sensor(indio_dev, chan, &data); 889 iio_device_release_direct(indio_dev); 890 if (ret) 891 return ret; 892 *val = data; 893 return IIO_VAL_INT; 894 case IIO_CHAN_INFO_SCALE: 895 return inv_icm42600_accel_read_scale(indio_dev, val, val2); 896 case IIO_CHAN_INFO_SAMP_FREQ: 897 return inv_icm42600_accel_read_odr(st, val, val2); 898 case IIO_CHAN_INFO_CALIBBIAS: 899 return inv_icm42600_accel_read_offset(st, chan, val, val2); 900 default: 901 return -EINVAL; 902 } 903 } 904 905 static int inv_icm42600_accel_read_avail(struct iio_dev *indio_dev, 906 struct iio_chan_spec const *chan, 907 const int **vals, 908 int *type, int *length, long mask) 909 { 910 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 911 912 if (chan->type != IIO_ACCEL) 913 return -EINVAL; 914 915 switch (mask) { 916 case IIO_CHAN_INFO_SCALE: 917 *vals = accel_st->scales; 918 *type = IIO_VAL_INT_PLUS_NANO; 919 *length = accel_st->scales_len; 920 return IIO_AVAIL_LIST; 921 case IIO_CHAN_INFO_SAMP_FREQ: 922 *vals = inv_icm42600_accel_odr; 923 *type = IIO_VAL_INT_PLUS_MICRO; 924 *length = ARRAY_SIZE(inv_icm42600_accel_odr); 925 return IIO_AVAIL_LIST; 926 case IIO_CHAN_INFO_CALIBBIAS: 927 *vals = inv_icm42600_accel_calibbias; 928 *type = IIO_VAL_INT_PLUS_MICRO; 929 return IIO_AVAIL_RANGE; 930 default: 931 return -EINVAL; 932 } 933 } 934 935 static int inv_icm42600_accel_write_raw(struct iio_dev *indio_dev, 936 struct iio_chan_spec const *chan, 937 int val, int val2, long mask) 938 { 939 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 940 int ret; 941 942 if (chan->type != IIO_ACCEL) 943 return -EINVAL; 944 945 switch (mask) { 946 case IIO_CHAN_INFO_SCALE: 947 if (!iio_device_claim_direct(indio_dev)) 948 return -EBUSY; 949 ret = inv_icm42600_accel_write_scale(indio_dev, val, val2); 950 iio_device_release_direct(indio_dev); 951 return ret; 952 case IIO_CHAN_INFO_SAMP_FREQ: 953 return inv_icm42600_accel_write_odr(indio_dev, val, val2); 954 case IIO_CHAN_INFO_CALIBBIAS: 955 if (!iio_device_claim_direct(indio_dev)) 956 return -EBUSY; 957 ret = inv_icm42600_accel_write_offset(st, chan, val, val2); 958 iio_device_release_direct(indio_dev); 959 return ret; 960 default: 961 return -EINVAL; 962 } 963 } 964 965 static int inv_icm42600_accel_write_raw_get_fmt(struct iio_dev *indio_dev, 966 struct iio_chan_spec const *chan, 967 long mask) 968 { 969 if (chan->type != IIO_ACCEL) 970 return -EINVAL; 971 972 switch (mask) { 973 case IIO_CHAN_INFO_SCALE: 974 return IIO_VAL_INT_PLUS_NANO; 975 case IIO_CHAN_INFO_SAMP_FREQ: 976 return IIO_VAL_INT_PLUS_MICRO; 977 case IIO_CHAN_INFO_CALIBBIAS: 978 return IIO_VAL_INT_PLUS_MICRO; 979 default: 980 return -EINVAL; 981 } 982 } 983 984 static int inv_icm42600_accel_hwfifo_set_watermark(struct iio_dev *indio_dev, 985 unsigned int val) 986 { 987 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 988 989 guard(mutex)(&st->lock); 990 991 st->fifo.watermark.accel = val; 992 return inv_icm42600_buffer_update_watermark(st); 993 } 994 995 static int inv_icm42600_accel_hwfifo_flush(struct iio_dev *indio_dev, 996 unsigned int count) 997 { 998 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 999 int ret; 1000 1001 if (count == 0) 1002 return 0; 1003 1004 guard(mutex)(&st->lock); 1005 1006 ret = inv_icm42600_buffer_hwfifo_flush(st, count); 1007 if (ret) 1008 return ret; 1009 1010 return st->fifo.nb.accel; 1011 } 1012 1013 static int inv_icm42600_accel_read_event_config(struct iio_dev *indio_dev, 1014 const struct iio_chan_spec *chan, 1015 enum iio_event_type type, 1016 enum iio_event_direction dir) 1017 { 1018 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1019 1020 /* handle only WoM (roc rising) event */ 1021 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1022 return -EINVAL; 1023 1024 guard(mutex)(&st->lock); 1025 1026 return st->apex.wom.enable ? 1 : 0; 1027 } 1028 1029 static int inv_icm42600_accel_write_event_config(struct iio_dev *indio_dev, 1030 const struct iio_chan_spec *chan, 1031 enum iio_event_type type, 1032 enum iio_event_direction dir, 1033 bool state) 1034 { 1035 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1036 1037 /* handle only WoM (roc rising) event */ 1038 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1039 return -EINVAL; 1040 1041 scoped_guard(mutex, &st->lock) { 1042 if (st->apex.wom.enable == state) 1043 return 0; 1044 } 1045 1046 if (state) 1047 return inv_icm42600_accel_enable_wom(indio_dev); 1048 1049 return inv_icm42600_accel_disable_wom(indio_dev); 1050 } 1051 1052 static int inv_icm42600_accel_read_event_value(struct iio_dev *indio_dev, 1053 const struct iio_chan_spec *chan, 1054 enum iio_event_type type, 1055 enum iio_event_direction dir, 1056 enum iio_event_info info, 1057 int *val, int *val2) 1058 { 1059 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1060 u32 rem; 1061 1062 /* handle only WoM (roc rising) event value */ 1063 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1064 return -EINVAL; 1065 1066 guard(mutex)(&st->lock); 1067 1068 /* return value in micro */ 1069 *val = div_u64_rem(st->apex.wom.value, MICRO, &rem); 1070 *val2 = rem; 1071 return IIO_VAL_INT_PLUS_MICRO; 1072 } 1073 1074 static int _inv_icm42600_accel_wom_value(struct inv_icm42600_state *st, 1075 int val, int val2) 1076 { 1077 u64 value; 1078 unsigned int accel_hz, accel_uhz; 1079 int ret; 1080 1081 guard(mutex)(&st->lock); 1082 1083 ret = inv_icm42600_accel_read_odr(st, &accel_hz, &accel_uhz); 1084 if (ret < 0) 1085 return ret; 1086 1087 value = (u64)val * MICRO + (u64)val2; 1088 1089 return inv_icm42600_accel_set_wom_threshold(st, value, 1090 accel_hz, accel_uhz); 1091 } 1092 1093 static int inv_icm42600_accel_write_event_value(struct iio_dev *indio_dev, 1094 const struct iio_chan_spec *chan, 1095 enum iio_event_type type, 1096 enum iio_event_direction dir, 1097 enum iio_event_info info, 1098 int val, int val2) 1099 { 1100 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1101 struct device *dev = regmap_get_device(st->map); 1102 int ret; 1103 1104 /* handle only WoM (roc rising) event value */ 1105 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1106 return -EINVAL; 1107 1108 if (val < 0 || val2 < 0) 1109 return -EINVAL; 1110 1111 ret = pm_runtime_resume_and_get(dev); 1112 if (ret) 1113 return ret; 1114 1115 ret = _inv_icm42600_accel_wom_value(st, val, val2); 1116 1117 pm_runtime_mark_last_busy(dev); 1118 pm_runtime_put_autosuspend(dev); 1119 1120 return ret; 1121 } 1122 1123 static const struct iio_info inv_icm42600_accel_info = { 1124 .read_raw = inv_icm42600_accel_read_raw, 1125 .read_avail = inv_icm42600_accel_read_avail, 1126 .write_raw = inv_icm42600_accel_write_raw, 1127 .write_raw_get_fmt = inv_icm42600_accel_write_raw_get_fmt, 1128 .debugfs_reg_access = inv_icm42600_debugfs_reg, 1129 .update_scan_mode = inv_icm42600_accel_update_scan_mode, 1130 .hwfifo_set_watermark = inv_icm42600_accel_hwfifo_set_watermark, 1131 .hwfifo_flush_to_buffer = inv_icm42600_accel_hwfifo_flush, 1132 .read_event_config = inv_icm42600_accel_read_event_config, 1133 .write_event_config = inv_icm42600_accel_write_event_config, 1134 .read_event_value = inv_icm42600_accel_read_event_value, 1135 .write_event_value = inv_icm42600_accel_write_event_value, 1136 }; 1137 1138 struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) 1139 { 1140 struct device *dev = regmap_get_device(st->map); 1141 const char *name; 1142 struct inv_icm42600_sensor_state *accel_st; 1143 struct inv_sensors_timestamp_chip ts_chip; 1144 struct iio_dev *indio_dev; 1145 int ret; 1146 1147 name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name); 1148 if (!name) 1149 return ERR_PTR(-ENOMEM); 1150 1151 indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st)); 1152 if (!indio_dev) 1153 return ERR_PTR(-ENOMEM); 1154 accel_st = iio_priv(indio_dev); 1155 1156 switch (st->chip) { 1157 case INV_CHIP_ICM42686: 1158 accel_st->scales = inv_icm42686_accel_scale; 1159 accel_st->scales_len = ARRAY_SIZE(inv_icm42686_accel_scale); 1160 break; 1161 default: 1162 accel_st->scales = inv_icm42600_accel_scale; 1163 accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale); 1164 break; 1165 } 1166 /* low-power by default at init */ 1167 accel_st->power_mode = INV_ICM42600_SENSOR_MODE_LOW_POWER; 1168 accel_st->filter = INV_ICM42600_FILTER_AVG_16X; 1169 1170 /* 1171 * clock period is 32kHz (31250ns) 1172 * jitter is +/- 2% (20 per mille) 1173 */ 1174 ts_chip.clock_period = 31250; 1175 ts_chip.jitter = 20; 1176 ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr); 1177 inv_sensors_timestamp_init(&accel_st->ts, &ts_chip); 1178 1179 iio_device_set_drvdata(indio_dev, st); 1180 indio_dev->name = name; 1181 indio_dev->info = &inv_icm42600_accel_info; 1182 indio_dev->modes = INDIO_DIRECT_MODE; 1183 indio_dev->channels = inv_icm42600_accel_channels; 1184 indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels); 1185 indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks; 1186 1187 ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, 1188 &inv_icm42600_buffer_ops); 1189 if (ret) 1190 return ERR_PTR(ret); 1191 1192 ret = devm_iio_device_register(dev, indio_dev); 1193 if (ret) 1194 return ERR_PTR(ret); 1195 1196 /* accel events are wakeup capable */ 1197 ret = devm_device_init_wakeup(&indio_dev->dev); 1198 if (ret) 1199 return ERR_PTR(ret); 1200 1201 return indio_dev; 1202 } 1203 1204 int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) 1205 { 1206 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1207 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 1208 struct inv_sensors_timestamp *ts = &accel_st->ts; 1209 ssize_t i, size; 1210 unsigned int no; 1211 const void *accel, *gyro, *timestamp; 1212 const int8_t *temp; 1213 unsigned int odr; 1214 int64_t ts_val; 1215 /* buffer is copied to userspace, zeroing it to avoid any data leak */ 1216 struct inv_icm42600_accel_buffer buffer = { }; 1217 1218 /* parse all fifo packets */ 1219 for (i = 0, no = 0; i < st->fifo.count; i += size, ++no) { 1220 size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i], 1221 &accel, &gyro, &temp, ×tamp, &odr); 1222 /* quit if error or FIFO is empty */ 1223 if (size <= 0) 1224 return size; 1225 1226 /* skip packet if no accel data or data is invalid */ 1227 if (accel == NULL || !inv_icm42600_fifo_is_data_valid(accel)) 1228 continue; 1229 1230 /* update odr */ 1231 if (odr & INV_ICM42600_SENSOR_ACCEL) 1232 inv_sensors_timestamp_apply_odr(ts, st->fifo.period, 1233 st->fifo.nb.total, no); 1234 1235 memcpy(&buffer.accel, accel, sizeof(buffer.accel)); 1236 /* convert 8 bits FIFO temperature in high resolution format */ 1237 buffer.temp = temp ? (*temp * 64) : 0; 1238 ts_val = inv_sensors_timestamp_pop(ts); 1239 iio_push_to_buffers_with_timestamp(indio_dev, &buffer, ts_val); 1240 } 1241 1242 return 0; 1243 } 1244