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: 0ecc363cce ("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>
This commit is contained in:
Jean-Baptiste Maneyrol 2024-04-26 09:48:35 +00:00 committed by Jonathan Cameron
parent 0340dc4c82
commit bf8367b00c
4 changed files with 21 additions and 28 deletions

View file

@ -70,13 +70,13 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts,
}
EXPORT_SYMBOL_NS_GPL(inv_sensors_timestamp_update_odr, IIO_INV_SENSORS_TIMESTAMP);
static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period, uint32_t mult)
static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t period)
{
uint32_t period_min, period_max;
/* check that period is acceptable */
period_min = ts->min_period * mult;
period_max = ts->max_period * mult;
period_min = ts->min_period * ts->mult;
period_max = ts->max_period * ts->mult;
if (period > period_min && period < period_max)
return true;
else
@ -84,15 +84,15 @@ static bool inv_validate_period(struct inv_sensors_timestamp *ts, uint32_t perio
}
static bool inv_update_chip_period(struct inv_sensors_timestamp *ts,
uint32_t mult, uint32_t period)
uint32_t period)
{
uint32_t new_chip_period;
if (!inv_validate_period(ts, period, mult))
if (!inv_validate_period(ts, period))
return false;
/* update chip internal period estimation */
new_chip_period = period / mult;
new_chip_period = period / ts->mult;
inv_update_acc(&ts->chip_period, new_chip_period);
ts->period = ts->mult * ts->chip_period.val;
@ -125,16 +125,14 @@ static void inv_align_timestamp_it(struct inv_sensors_timestamp *ts)
}
void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
uint32_t fifo_period, size_t fifo_nb,
size_t sensor_nb, int64_t timestamp)
size_t sample_nb, int64_t timestamp)
{
struct inv_sensors_timestamp_interval *it;
int64_t delta, interval;
const uint32_t fifo_mult = fifo_period / ts->chip.clock_period;
uint32_t period;
bool valid = false;
if (fifo_nb == 0)
if (sample_nb == 0)
return;
/* update interrupt timestamp and compute chip and sensor periods */
@ -144,14 +142,14 @@ void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
delta = it->up - it->lo;
if (it->lo != 0) {
/* compute period: delta time divided by number of samples */
period = div_s64(delta, fifo_nb);
valid = inv_update_chip_period(ts, fifo_mult, period);
period = div_s64(delta, sample_nb);
valid = inv_update_chip_period(ts, period);
}
/* no previous data, compute theoritical value from interrupt */
if (ts->timestamp == 0) {
/* elapsed time: sensor period * sensor samples number */
interval = (int64_t)ts->period * (int64_t)sensor_nb;
interval = (int64_t)ts->period * (int64_t)sample_nb;
ts->timestamp = it->up - interval;
return;
}

View file

@ -512,20 +512,20 @@ int inv_icm42600_buffer_fifo_parse(struct inv_icm42600_state *st)
return 0;
/* handle gyroscope timestamp and FIFO data parsing */
ts = &gyro_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total,
st->fifo.nb.gyro, st->timestamp.gyro);
if (st->fifo.nb.gyro > 0) {
ts = &gyro_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro,
st->timestamp.gyro);
ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
if (ret)
return ret;
}
/* handle accelerometer timestamp and FIFO data parsing */
ts = &accel_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.period, st->fifo.nb.total,
st->fifo.nb.accel, st->timestamp.accel);
if (st->fifo.nb.accel > 0) {
ts = &accel_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel,
st->timestamp.accel);
ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
if (ret)
return ret;
@ -555,9 +555,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
if (st->fifo.nb.gyro > 0) {
ts = &gyro_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.period,
st->fifo.nb.total, st->fifo.nb.gyro,
gyro_ts);
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.gyro, gyro_ts);
ret = inv_icm42600_gyro_parse_fifo(st->indio_gyro);
if (ret)
return ret;
@ -565,9 +563,7 @@ int inv_icm42600_buffer_hwfifo_flush(struct inv_icm42600_state *st,
if (st->fifo.nb.accel > 0) {
ts = &accel_st->ts;
inv_sensors_timestamp_interrupt(ts, st->fifo.period,
st->fifo.nb.total, st->fifo.nb.accel,
accel_ts);
inv_sensors_timestamp_interrupt(ts, st->fifo.nb.accel, accel_ts);
ret = inv_icm42600_accel_parse_fifo(st->indio_accel);
if (ret)
return ret;

View file

@ -100,7 +100,7 @@ irqreturn_t inv_mpu6050_read_fifo(int irq, void *p)
goto end_session;
/* Each FIFO data contains all sensors, so same number for FIFO and sensor data */
fifo_period = NSEC_PER_SEC / INV_MPU6050_DIVIDER_TO_FIFO_RATE(st->chip_config.divider);
inv_sensors_timestamp_interrupt(&st->timestamp, fifo_period, nb, nb, pf->timestamp);
inv_sensors_timestamp_interrupt(&st->timestamp, nb, pf->timestamp);
inv_sensors_timestamp_apply_odr(&st->timestamp, fifo_period, nb, 0);
/* clear internal data buffer for avoiding kernel data leak */

View file

@ -71,8 +71,7 @@ int inv_sensors_timestamp_update_odr(struct inv_sensors_timestamp *ts,
uint32_t period, bool fifo);
void inv_sensors_timestamp_interrupt(struct inv_sensors_timestamp *ts,
uint32_t fifo_period, size_t fifo_nb,
size_t sensor_nb, int64_t timestamp);
size_t sample_nb, int64_t timestamp);
static inline int64_t inv_sensors_timestamp_pop(struct inv_sensors_timestamp *ts)
{