Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

iio: invensense: fix timestamp glitches when switching frequency

When a sensor is running and there is a FIFO frequency change due to
another sensor turned on/off, there are glitches on timestamp. Fix that
by using only interrupt timestamp when there is the corresponding sensor
data in the FIFO.

Delete FIFO period handling and simplify internal functions.

Update integration inside inv_mpu6050 and inv_icm42600 drivers.

Fixes: 0ecc363ccea7 ("iio: make invensense timestamp module generic")
Cc: Stable@vger.kernel.org
Signed-off-by: Jean-Baptiste Maneyrol <jean-baptiste.maneyrol@tdk.com>
Link: https://lore.kernel.org/r/20240426094835.138389-1-inv.git-commit@tdk.com
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>

authored by

Jean-Baptiste Maneyrol and committed by
Jonathan Cameron
bf8367b0 0340dc4c

+21 -28
+11 -13
drivers/iio/common/inv_sensors/inv_sensors_timestamp.c
··· 70 70 } 71 71 EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, IIO_INV_SENSORS_TIMESTAMP); 72 72 73 - static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period, uint32_t mult) 73 + static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period) 74 74 { 75 75 uint32_t period_min, period_max; 76 76 77 77 /* check that period is acceptable */ 78 - period_min = ts->min_period * mult; 79 - period_max = ts->max_period * mult; 78 + period_min = ts->min_period * ts->mult; 79 + period_max = ts->max_period * ts->mult; 80 80 if (period > period_min && period < period_max) 81 81 return true; 82 82 else ··· 84 84 } 85 85 86 86 static bool inv_update_chip_period(struct inv_sensors_timestamp *ts, 87 - uint32_t mult, uint32_t period) 87 + uint32_t period) 88 88 { 89 89 uint32_t new_chip_period; 90 90 91 - if (!inv_validate_period(ts, period, mult)) 91 + if (!inv_validate_period(ts, period)) 92 92 return false; 93 93 94 94 /* update chip internal period estimation */ 95 - new_chip_period = period / mult; 95 + new_chip_period = period / ts->mult; 96 96 inv_update_acc(&ts->chip_period, new_chip_period); 97 97 ts->period = ts->mult * ts->chip_period.val; 98 98 ··· 125 125 } 126 126 127 127 void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, 128 - uint32_t fifo_period, size_t fifo_nb, 129 - size_t sensor_nb, int64_t timestamp) 128 + size_t sample_nb, int64_t timestamp) 130 129 { 131 130 struct inv_sensors_timestamp_interval *it; 132 131 int64_t delta, interval; 133 - const uint32_t fifo_mult = fifo_period / ts->chip.clock_period; 134 132 uint32_t period; 135 133 bool valid = false; 136 134 137 - if (fifo_nb == 0) 135 + if (sample_nb == 0) 138 136 return; 139 137 140 138 /* update interrupt timestamp and compute chip and sensor periods */ ··· 142 144 delta = it->up - it->lo; 143 145 if (it->lo != 0) { 144 146 /* compute period: delta time divided by number of samples */ 145 - period = div_s64(delta, fifo_nb); 146 - valid = inv_update_chip_period(ts, fifo_mult, period); 147 + period = div_s64(delta, sample_nb); 148 + valid = inv_update_chip_period(ts, period); 147 149 } 148 150 149 151 /* no previous data, compute theoritical value from interrupt */ 150 152 if (ts->timestamp == 0) { 151 153 /* elapsed time: sensor period * sensor samples number */ 152 - interval = (int64_t)ts->period * (int64_t)sensor_nb; 154 + interval = (int64_t)ts->period * (int64_t)sample_nb; 153 155 ts->timestamp = it->up - interval; 154 156 return; 155 157 }
+8 -12
drivers/iio/imu/inv_icm42600/inv_icm42600_buffer.c
··· 512 512 return 0; 513 513 514 514 /* handle gyroscope timestamp and FIFO data parsing */ 515 - ts = &gyro_st->ts; 516 - inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, 517 - st->fifo.nb.gyro, st->timestamp.gyro); 518 515 if (st->fifo.nb.gyro > 0) { 516 + ts = &gyro_st->ts; 517 + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro, 518 + st->timestamp.gyro); 519 519 ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro); 520 520 if (ret) 521 521 return ret; 522 522 } 523 523 524 524 /* handle accelerometer timestamp and FIFO data parsing */ 525 - ts = &accel_st->ts; 526 - inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total, 527 - st->fifo.nb.accel, st->timestamp.accel); 528 525 if (st->fifo.nb.accel > 0) { 526 + ts = &accel_st->ts; 527 + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel, 528 + st->timestamp.accel); 529 529 ret = inv_icm42600_accel_parse_fifo(st->indio_accel); 530 530 if (ret) 531 531 return ret; ··· 555 555 556 556 if (st->fifo.nb.gyro > 0) { 557 557 ts = &gyro_st->ts; 558 - inv_sensors_timestamp_interrupt(ts, st->fifo.period, 559 - st->fifo.nb.total, st->fifo.nb.gyro, 560 - gyro_ts); 558 + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro, gyro_ts); 561 559 ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro); 562 560 if (ret) 563 561 return ret; ··· 563 565 564 566 if (st->fifo.nb.accel > 0) { 565 567 ts = &accel_st->ts; 566 - inv_sensors_timestamp_interrupt(ts, st->fifo.period, 567 - st->fifo.nb.total, st->fifo.nb.accel, 568 - accel_ts); 568 + inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel, accel_ts); 569 569 ret = inv_icm42600_accel_parse_fifo(st->indio_accel); 570 570 if (ret) 571 571 return ret;
+1 -1
drivers/iio/imu/inv_mpu6050/inv_mpu_ring.c
··· 100 100 goto end_session; 101 101 /* Each FIFO data contains all sensors, so same number for FIFO and sensor data */ 102 102 fifo_period = NSEC_PER_SEC / INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider); 103 - inv_sensors_timestamp_interrupt(&st->timestamp, fifo_period, nb, nb, pf->timestamp); 103 + inv_sensors_timestamp_interrupt(&st->timestamp, nb, pf->timestamp); 104 104 inv_sensors_timestamp_apply_odr(&st->timestamp, fifo_period, nb, 0); 105 105 106 106 /* clear internal data buffer for avoiding kernel data leak */
+1 -2
include/linux/iio/common/inv_sensors_timestamp.h
··· 71 71 uint32_t period, bool fifo); 72 72 73 73 void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts, 74 - uint32_t fifo_period, size_t fifo_nb, 75 - size_t sensor_nb, int64_t timestamp); 74 + size_t sample_nb, int64_t timestamp); 76 75 77 76 static inline int64_t inv_sensors_timestamp_pop(struct inv_sensors_timestamp *ts) 78 77 {