FILE
inv_icm42600_accel.c
File preview with syntax highlighting.
linux-6.19.14/drivers/iio/imu/inv_icm42600/inv_icm42600_accel.c
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 63enum 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 71static const char * const inv_icm42600_accel_power_mode_items[] = { 72 "low-noise", 73 "low-power", 74}; 75static const int inv_icm42600_accel_power_mode_values[] = { 76 INV_ICM42600_SENSOR_MODE_LOW_NOISE, 77 INV_ICM42600_SENSOR_MODE_LOW_POWER, 78}; 79static const int inv_icm42600_accel_filter_values[] = { 80 INV_ICM42600_FILTER_BW_ODR_DIV_2, 81 INV_ICM42600_FILTER_AVG_16X, 82}; 83 84static 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 127static 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 161static 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 168static 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 */ 178static 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 187static 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 */ 204struct 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 217static 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 */ 224static 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 259out_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 268static 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; 316exit: 317 mutex_unlock(&st->lock); 318 pm_runtime_put_autosuspend(dev); 319 return ret; 320} 321 322static 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 341static 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 356static 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 382static 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 413static 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 433static 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 467static 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 481void 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 */ 497static 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}; 511static 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 529static 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 543static 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 */ 574static 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 599static 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 613static 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 634static 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 if (conf.odr == st->conf.accel.odr) 655 return 0; 656 657 pm_runtime_get_sync(dev); 658 mutex_lock(&st->lock); 659 660 ret = inv_sensors_timestamp_update_odr(ts, inv_icm42600_odr_to_period(conf.odr), 661 iio_buffer_enabled(indio_dev)); 662 if (ret) 663 goto out_unlock; 664 665 ret = inv_icm42600_set_accel_conf(st, &conf, NULL); 666 if (ret) 667 goto out_unlock; 668 /* update wom threshold since roc is dependent on sampling frequency */ 669 ret = inv_icm42600_accel_set_wom_threshold(st, st->apex.wom.value, val, val2); 670 if (ret) 671 goto out_unlock; 672 inv_icm42600_buffer_update_fifo_period(st); 673 inv_icm42600_buffer_update_watermark(st); 674 675out_unlock: 676 mutex_unlock(&st->lock); 677 pm_runtime_put_autosuspend(dev); 678 679 return ret; 680} 681 682/* 683 * Calibration bias values, IIO range format int + micro. 684 * Value is limited to +/-1g coded on 12 bits signed. Step is 0.5mg. 685 */ 686static int inv_icm42600_accel_calibbias[] = { 687 -10, 42010, /* min: -10.042010 m/s² */ 688 0, 4903, /* step: 0.004903 m/s² */ 689 10, 37106, /* max: 10.037106 m/s² */ 690}; 691 692static int inv_icm42600_accel_read_offset(struct inv_icm42600_state *st, 693 struct iio_chan_spec const *chan, 694 int *val, int *val2) 695{ 696 struct device *dev = regmap_get_device(st->map); 697 s64 val64; 698 s32 bias; 699 unsigned int reg; 700 s16 offset; 701 u8 data[2]; 702 int ret; 703 704 if (chan->type != IIO_ACCEL) 705 return -EINVAL; 706 707 switch (chan->channel2) { 708 case IIO_MOD_X: 709 reg = INV_ICM42600_REG_OFFSET_USER4; 710 break; 711 case IIO_MOD_Y: 712 reg = INV_ICM42600_REG_OFFSET_USER6; 713 break; 714 case IIO_MOD_Z: 715 reg = INV_ICM42600_REG_OFFSET_USER7; 716 break; 717 default: 718 return -EINVAL; 719 } 720 721 pm_runtime_get_sync(dev); 722 mutex_lock(&st->lock); 723 724 ret = regmap_bulk_read(st->map, reg, st->buffer, sizeof(data)); 725 memcpy(data, st->buffer, sizeof(data)); 726 727 mutex_unlock(&st->lock); 728 pm_runtime_put_autosuspend(dev); 729 if (ret) 730 return ret; 731 732 /* 12 bits signed value */ 733 switch (chan->channel2) { 734 case IIO_MOD_X: 735 offset = sign_extend32(((data[0] & 0xF0) << 4) | data[1], 11); 736 break; 737 case IIO_MOD_Y: 738 offset = sign_extend32(((data[1] & 0x0F) << 8) | data[0], 11); 739 break; 740 case IIO_MOD_Z: 741 offset = sign_extend32(((data[0] & 0xF0) << 4) | data[1], 11); 742 break; 743 default: 744 return -EINVAL; 745 } 746 747 /* 748 * convert raw offset to g then to m/s² 749 * 12 bits signed raw step 0.5mg to g: 5 / 10000 750 * g to m/s²: 9.806650 751 * result in micro (1000000) 752 * (offset * 5 * 9.806650 * 1000000) / 10000 753 */ 754 val64 = (s64)offset * 5LL * 9806650LL; 755 /* for rounding, add + or - divisor (10000) divided by 2 */ 756 if (val64 >= 0) 757 val64 += 10000LL / 2LL; 758 else 759 val64 -= 10000LL / 2LL; 760 bias = div_s64(val64, 10000L); 761 *val = bias / 1000000L; 762 *val2 = bias % 1000000L; 763 764 return IIO_VAL_INT_PLUS_MICRO; 765} 766 767static int inv_icm42600_accel_write_offset(struct inv_icm42600_state *st, 768 struct iio_chan_spec const *chan, 769 int val, int val2) 770{ 771 struct device *dev = regmap_get_device(st->map); 772 s64 val64; 773 s32 min, max; 774 unsigned int reg, regval; 775 s16 offset; 776 int ret; 777 778 if (chan->type != IIO_ACCEL) 779 return -EINVAL; 780 781 switch (chan->channel2) { 782 case IIO_MOD_X: 783 reg = INV_ICM42600_REG_OFFSET_USER4; 784 break; 785 case IIO_MOD_Y: 786 reg = INV_ICM42600_REG_OFFSET_USER6; 787 break; 788 case IIO_MOD_Z: 789 reg = INV_ICM42600_REG_OFFSET_USER7; 790 break; 791 default: 792 return -EINVAL; 793 } 794 795 /* inv_icm42600_accel_calibbias: min - step - max in micro */ 796 min = inv_icm42600_accel_calibbias[0] * 1000000L + 797 inv_icm42600_accel_calibbias[1]; 798 max = inv_icm42600_accel_calibbias[4] * 1000000L + 799 inv_icm42600_accel_calibbias[5]; 800 val64 = (s64)val * 1000000LL + (s64)val2; 801 if (val64 < min || val64 > max) 802 return -EINVAL; 803 804 /* 805 * convert m/s² to g then to raw value 806 * m/s² to g: 1 / 9.806650 807 * g to raw 12 bits signed, step 0.5mg: 10000 / 5 808 * val in micro (1000000) 809 * val * 10000 / (9.806650 * 1000000 * 5) 810 */ 811 val64 = val64 * 10000LL; 812 /* for rounding, add + or - divisor (9806650 * 5) divided by 2 */ 813 if (val64 >= 0) 814 val64 += 9806650 * 5 / 2; 815 else 816 val64 -= 9806650 * 5 / 2; 817 offset = div_s64(val64, 9806650 * 5); 818 819 /* clamp value limited to 12 bits signed */ 820 if (offset < -2048) 821 offset = -2048; 822 else if (offset > 2047) 823 offset = 2047; 824 825 pm_runtime_get_sync(dev); 826 mutex_lock(&st->lock); 827 828 switch (chan->channel2) { 829 case IIO_MOD_X: 830 /* OFFSET_USER4 register is shared */ 831 ret = regmap_read(st->map, INV_ICM42600_REG_OFFSET_USER4, 832 ®val); 833 if (ret) 834 goto out_unlock; 835 st->buffer[0] = ((offset & 0xF00) >> 4) | (regval & 0x0F); 836 st->buffer[1] = offset & 0xFF; 837 break; 838 case IIO_MOD_Y: 839 /* OFFSET_USER7 register is shared */ 840 ret = regmap_read(st->map, INV_ICM42600_REG_OFFSET_USER7, 841 ®val); 842 if (ret) 843 goto out_unlock; 844 st->buffer[0] = offset & 0xFF; 845 st->buffer[1] = ((offset & 0xF00) >> 8) | (regval & 0xF0); 846 break; 847 case IIO_MOD_Z: 848 /* OFFSET_USER7 register is shared */ 849 ret = regmap_read(st->map, INV_ICM42600_REG_OFFSET_USER7, 850 ®val); 851 if (ret) 852 goto out_unlock; 853 st->buffer[0] = ((offset & 0xF00) >> 4) | (regval & 0x0F); 854 st->buffer[1] = offset & 0xFF; 855 break; 856 default: 857 ret = -EINVAL; 858 goto out_unlock; 859 } 860 861 ret = regmap_bulk_write(st->map, reg, st->buffer, 2); 862 863out_unlock: 864 mutex_unlock(&st->lock); 865 pm_runtime_put_autosuspend(dev); 866 return ret; 867} 868 869static int inv_icm42600_accel_read_raw(struct iio_dev *indio_dev, 870 struct iio_chan_spec const *chan, 871 int *val, int *val2, long mask) 872{ 873 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 874 s16 data; 875 int ret; 876 877 switch (chan->type) { 878 case IIO_ACCEL: 879 break; 880 case IIO_TEMP: 881 return inv_icm42600_temp_read_raw(indio_dev, chan, val, val2, mask); 882 default: 883 return -EINVAL; 884 } 885 886 switch (mask) { 887 case IIO_CHAN_INFO_RAW: 888 if (!iio_device_claim_direct(indio_dev)) 889 return -EBUSY; 890 ret = inv_icm42600_accel_read_sensor(indio_dev, chan, &data); 891 iio_device_release_direct(indio_dev); 892 if (ret) 893 return ret; 894 *val = data; 895 return IIO_VAL_INT; 896 case IIO_CHAN_INFO_SCALE: 897 return inv_icm42600_accel_read_scale(indio_dev, val, val2); 898 case IIO_CHAN_INFO_SAMP_FREQ: 899 return inv_icm42600_accel_read_odr(st, val, val2); 900 case IIO_CHAN_INFO_CALIBBIAS: 901 return inv_icm42600_accel_read_offset(st, chan, val, val2); 902 default: 903 return -EINVAL; 904 } 905} 906 907static int inv_icm42600_accel_read_avail(struct iio_dev *indio_dev, 908 struct iio_chan_spec const *chan, 909 const int **vals, 910 int *type, int *length, long mask) 911{ 912 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 913 914 if (chan->type != IIO_ACCEL) 915 return -EINVAL; 916 917 switch (mask) { 918 case IIO_CHAN_INFO_SCALE: 919 *vals = accel_st->scales; 920 *type = IIO_VAL_INT_PLUS_NANO; 921 *length = accel_st->scales_len; 922 return IIO_AVAIL_LIST; 923 case IIO_CHAN_INFO_SAMP_FREQ: 924 *vals = inv_icm42600_accel_odr; 925 *type = IIO_VAL_INT_PLUS_MICRO; 926 *length = ARRAY_SIZE(inv_icm42600_accel_odr); 927 return IIO_AVAIL_LIST; 928 case IIO_CHAN_INFO_CALIBBIAS: 929 *vals = inv_icm42600_accel_calibbias; 930 *type = IIO_VAL_INT_PLUS_MICRO; 931 return IIO_AVAIL_RANGE; 932 default: 933 return -EINVAL; 934 } 935} 936 937static int inv_icm42600_accel_write_raw(struct iio_dev *indio_dev, 938 struct iio_chan_spec const *chan, 939 int val, int val2, long mask) 940{ 941 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 942 int ret; 943 944 if (chan->type != IIO_ACCEL) 945 return -EINVAL; 946 947 switch (mask) { 948 case IIO_CHAN_INFO_SCALE: 949 if (!iio_device_claim_direct(indio_dev)) 950 return -EBUSY; 951 ret = inv_icm42600_accel_write_scale(indio_dev, val, val2); 952 iio_device_release_direct(indio_dev); 953 return ret; 954 case IIO_CHAN_INFO_SAMP_FREQ: 955 return inv_icm42600_accel_write_odr(indio_dev, val, val2); 956 case IIO_CHAN_INFO_CALIBBIAS: 957 if (!iio_device_claim_direct(indio_dev)) 958 return -EBUSY; 959 ret = inv_icm42600_accel_write_offset(st, chan, val, val2); 960 iio_device_release_direct(indio_dev); 961 return ret; 962 default: 963 return -EINVAL; 964 } 965} 966 967static int inv_icm42600_accel_write_raw_get_fmt(struct iio_dev *indio_dev, 968 struct iio_chan_spec const *chan, 969 long mask) 970{ 971 if (chan->type != IIO_ACCEL) 972 return -EINVAL; 973 974 switch (mask) { 975 case IIO_CHAN_INFO_SCALE: 976 return IIO_VAL_INT_PLUS_NANO; 977 case IIO_CHAN_INFO_SAMP_FREQ: 978 return IIO_VAL_INT_PLUS_MICRO; 979 case IIO_CHAN_INFO_CALIBBIAS: 980 return IIO_VAL_INT_PLUS_MICRO; 981 default: 982 return -EINVAL; 983 } 984} 985 986static int inv_icm42600_accel_hwfifo_set_watermark(struct iio_dev *indio_dev, 987 unsigned int val) 988{ 989 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 990 991 guard(mutex)(&st->lock); 992 993 st->fifo.watermark.accel = val; 994 return inv_icm42600_buffer_update_watermark(st); 995} 996 997static int inv_icm42600_accel_hwfifo_flush(struct iio_dev *indio_dev, 998 unsigned int count) 999{ 1000 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1001 int ret; 1002 1003 if (count == 0) 1004 return 0; 1005 1006 guard(mutex)(&st->lock); 1007 1008 ret = inv_icm42600_buffer_hwfifo_flush(st, count); 1009 if (ret) 1010 return ret; 1011 1012 return st->fifo.nb.accel; 1013} 1014 1015static int inv_icm42600_accel_read_event_config(struct iio_dev *indio_dev, 1016 const struct iio_chan_spec *chan, 1017 enum iio_event_type type, 1018 enum iio_event_direction dir) 1019{ 1020 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1021 1022 /* handle only WoM (roc rising) event */ 1023 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1024 return -EINVAL; 1025 1026 guard(mutex)(&st->lock); 1027 1028 return st->apex.wom.enable ? 1 : 0; 1029} 1030 1031static int inv_icm42600_accel_write_event_config(struct iio_dev *indio_dev, 1032 const struct iio_chan_spec *chan, 1033 enum iio_event_type type, 1034 enum iio_event_direction dir, 1035 bool state) 1036{ 1037 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1038 1039 /* handle only WoM (roc rising) event */ 1040 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1041 return -EINVAL; 1042 1043 scoped_guard(mutex, &st->lock) { 1044 if (st->apex.wom.enable == state) 1045 return 0; 1046 } 1047 1048 if (state) 1049 return inv_icm42600_accel_enable_wom(indio_dev); 1050 1051 return inv_icm42600_accel_disable_wom(indio_dev); 1052} 1053 1054static int inv_icm42600_accel_read_event_value(struct iio_dev *indio_dev, 1055 const struct iio_chan_spec *chan, 1056 enum iio_event_type type, 1057 enum iio_event_direction dir, 1058 enum iio_event_info info, 1059 int *val, int *val2) 1060{ 1061 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1062 u32 rem; 1063 1064 /* handle only WoM (roc rising) event value */ 1065 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1066 return -EINVAL; 1067 1068 guard(mutex)(&st->lock); 1069 1070 /* return value in micro */ 1071 *val = div_u64_rem(st->apex.wom.value, MICRO, &rem); 1072 *val2 = rem; 1073 return IIO_VAL_INT_PLUS_MICRO; 1074} 1075 1076static int _inv_icm42600_accel_wom_value(struct inv_icm42600_state *st, 1077 int val, int val2) 1078{ 1079 u64 value; 1080 unsigned int accel_hz, accel_uhz; 1081 int ret; 1082 1083 guard(mutex)(&st->lock); 1084 1085 ret = inv_icm42600_accel_read_odr(st, &accel_hz, &accel_uhz); 1086 if (ret < 0) 1087 return ret; 1088 1089 value = (u64)val * MICRO + (u64)val2; 1090 1091 return inv_icm42600_accel_set_wom_threshold(st, value, 1092 accel_hz, accel_uhz); 1093} 1094 1095static int inv_icm42600_accel_write_event_value(struct iio_dev *indio_dev, 1096 const struct iio_chan_spec *chan, 1097 enum iio_event_type type, 1098 enum iio_event_direction dir, 1099 enum iio_event_info info, 1100 int val, int val2) 1101{ 1102 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1103 struct device *dev = regmap_get_device(st->map); 1104 int ret; 1105 1106 /* handle only WoM (roc rising) event value */ 1107 if (type != IIO_EV_TYPE_ROC || dir != IIO_EV_DIR_RISING) 1108 return -EINVAL; 1109 1110 if (val < 0 || val2 < 0) 1111 return -EINVAL; 1112 1113 ret = pm_runtime_resume_and_get(dev); 1114 if (ret) 1115 return ret; 1116 1117 ret = _inv_icm42600_accel_wom_value(st, val, val2); 1118 1119 pm_runtime_mark_last_busy(dev); 1120 pm_runtime_put_autosuspend(dev); 1121 1122 return ret; 1123} 1124 1125static const struct iio_info inv_icm42600_accel_info = { 1126 .read_raw = inv_icm42600_accel_read_raw, 1127 .read_avail = inv_icm42600_accel_read_avail, 1128 .write_raw = inv_icm42600_accel_write_raw, 1129 .write_raw_get_fmt = inv_icm42600_accel_write_raw_get_fmt, 1130 .debugfs_reg_access = inv_icm42600_debugfs_reg, 1131 .update_scan_mode = inv_icm42600_accel_update_scan_mode, 1132 .hwfifo_set_watermark = inv_icm42600_accel_hwfifo_set_watermark, 1133 .hwfifo_flush_to_buffer = inv_icm42600_accel_hwfifo_flush, 1134 .read_event_config = inv_icm42600_accel_read_event_config, 1135 .write_event_config = inv_icm42600_accel_write_event_config, 1136 .read_event_value = inv_icm42600_accel_read_event_value, 1137 .write_event_value = inv_icm42600_accel_write_event_value, 1138}; 1139 1140struct iio_dev *inv_icm42600_accel_init(struct inv_icm42600_state *st) 1141{ 1142 struct device *dev = regmap_get_device(st->map); 1143 const char *name; 1144 struct inv_icm42600_sensor_state *accel_st; 1145 struct inv_sensors_timestamp_chip ts_chip; 1146 struct iio_dev *indio_dev; 1147 int ret; 1148 1149 name = devm_kasprintf(dev, GFP_KERNEL, "%s-accel", st->name); 1150 if (!name) 1151 return ERR_PTR(-ENOMEM); 1152 1153 indio_dev = devm_iio_device_alloc(dev, sizeof(*accel_st)); 1154 if (!indio_dev) 1155 return ERR_PTR(-ENOMEM); 1156 accel_st = iio_priv(indio_dev); 1157 1158 switch (st->chip) { 1159 case INV_CHIP_ICM42686: 1160 accel_st->scales = inv_icm42686_accel_scale; 1161 accel_st->scales_len = ARRAY_SIZE(inv_icm42686_accel_scale); 1162 break; 1163 default: 1164 accel_st->scales = inv_icm42600_accel_scale; 1165 accel_st->scales_len = ARRAY_SIZE(inv_icm42600_accel_scale); 1166 break; 1167 } 1168 /* low-power by default at init */ 1169 accel_st->power_mode = INV_ICM42600_SENSOR_MODE_LOW_POWER; 1170 accel_st->filter = INV_ICM42600_FILTER_AVG_16X; 1171 1172 /* 1173 * clock period is 32kHz (31250ns) 1174 * jitter is +/- 2% (20 per mille) 1175 */ 1176 ts_chip.clock_period = 31250; 1177 ts_chip.jitter = 20; 1178 ts_chip.init_period = inv_icm42600_odr_to_period(st->conf.accel.odr); 1179 inv_sensors_timestamp_init(&accel_st->ts, &ts_chip); 1180 1181 iio_device_set_drvdata(indio_dev, st); 1182 indio_dev->name = name; 1183 indio_dev->info = &inv_icm42600_accel_info; 1184 indio_dev->modes = INDIO_DIRECT_MODE; 1185 indio_dev->channels = inv_icm42600_accel_channels; 1186 indio_dev->num_channels = ARRAY_SIZE(inv_icm42600_accel_channels); 1187 indio_dev->available_scan_masks = inv_icm42600_accel_scan_masks; 1188 1189 ret = devm_iio_kfifo_buffer_setup(dev, indio_dev, 1190 &inv_icm42600_buffer_ops); 1191 if (ret) 1192 return ERR_PTR(ret); 1193 1194 ret = devm_iio_device_register(dev, indio_dev); 1195 if (ret) 1196 return ERR_PTR(ret); 1197 1198 /* accel events are wakeup capable */ 1199 ret = devm_device_init_wakeup(&indio_dev->dev); 1200 if (ret) 1201 return ERR_PTR(ret); 1202 1203 return indio_dev; 1204} 1205 1206int inv_icm42600_accel_parse_fifo(struct iio_dev *indio_dev) 1207{ 1208 struct inv_icm42600_state *st = iio_device_get_drvdata(indio_dev); 1209 struct inv_icm42600_sensor_state *accel_st = iio_priv(indio_dev); 1210 struct inv_sensors_timestamp *ts = &accel_st->ts; 1211 ssize_t i, size; 1212 unsigned int no; 1213 const void *accel, *gyro, *timestamp; 1214 const int8_t *temp; 1215 unsigned int odr; 1216 int64_t ts_val; 1217 /* buffer is copied to userspace, zeroing it to avoid any data leak */ 1218 struct inv_icm42600_accel_buffer buffer = { }; 1219 1220 /* parse all fifo packets */ 1221 for (i = 0, no = 0; i < st->fifo.count; i += size, ++no) { 1222 size = inv_icm42600_fifo_decode_packet(&st->fifo.data[i], 1223 &accel, &gyro, &temp, ×tamp, &odr); 1224 /* quit if error or FIFO is empty */ 1225 if (size <= 0) 1226 return size; 1227 1228 /* skip packet if no accel data or data is invalid */ 1229 if (accel == NULL || !inv_icm42600_fifo_is_data_valid(accel)) 1230 continue; 1231 1232 /* update odr */ 1233 if (odr & INV_ICM42600_SENSOR_ACCEL) 1234 inv_sensors_timestamp_apply_odr(ts, st->fifo.period, 1235 st->fifo.nb.total, no); 1236 1237 memcpy(&buffer.accel, accel, sizeof(buffer.accel)); 1238 /* convert 8 bits FIFO temperature in high resolution format */ 1239 buffer.temp = temp ? (*temp * 64) : 0; 1240 ts_val = inv_sensors_timestamp_pop(ts); 1241 iio_push_to_buffers_with_timestamp(indio_dev, &buffer, ts_val); 1242 } 1243 1244 return 0; 1245}
~/
Read-only file preview.