[PATCH] iio: pressure: dps310: wait for a new sample after a ratio change

From: Rupesh Majhi

Date: Mon Oct 19 2026 - 13:43:17 EST


After an oversampling ratio change, the sample waiting in the result
registers and the one being measured are both from the old ratio, but
are scaled with the new one. Pressure ratio 2 to 16 reads 192 kPa instead
of 103 kPa, and temperature is off by hundreds of degrees. Pressure is
also wrong after a temperature ratio change, as it is compensated with
the cached temperature.

Discard those two samples on a ratio change, and for temperature cache
the one after. The ratio write now blocks until then.

That wait can be longer than the 1/rate timeout, after which the driver
resets the chip and the ratio silently goes back to 1. Allow two periods.

Fixes: ba6ec48e76bc ("iio: Add driver for Infineon DPS310")
Fixes: d711a3c7dc82 ("iio: dps310: Add pressure sensing capability")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: LLM
Signed-off-by: Rupesh Majhi <zoone.rupert@xxxxxxxxx>
---
Tested on a DPS310 on a BeagleBone Black. Applies with or without the
ZTS8032 series.

drivers/iio/pressure/dps310.c | 51 +++++++++++++++++++++++++++++------
1 file changed, 43 insertions(+), 8 deletions(-)

diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index 00f6be126326..e6b27cf26cec 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -78,8 +78,8 @@

/* Make sure sleep time is <= 30ms for usleep_range */
#define DPS310_POLL_SLEEP_US(t) min(30000, (t) / 8)
-/* Silently handle error in rate value here */
-#define DPS310_POLL_TIMEOUT_US(rc) ((rc) <= 0 ? 1000000 : 1000000 / (rc))
+/* A period plus a measurement time; silently handle error in rate value */
+#define DPS310_POLL_TIMEOUT_US(rc) (2 * USEC_PER_SEC / max(rc, 1))

#define DPS310_PRS_BASE DPS310_PRS_B0
#define DPS310_TMP_BASE DPS310_TMP_B0
@@ -354,6 +354,18 @@ static int dps310_get_temp_precision(struct dps310_data *data, int *val)
return 0;
}

+/*
+ * A sample measured before a ratio change would be scaled with the new one.
+ * Reading it clears its ready bit, so the next read waits for a new sample.
+ */
+static int dps310_drop_sample(struct dps310_data *data, unsigned int reg)
+ __must_hold(&data->lock)
+{
+ u8 val[3];
+
+ return regmap_bulk_read(data->regmap, reg, val, sizeof(val));
+}
+
static int dps310_set_pres_precision(struct dps310_data *data, int val)
__must_hold(&data->lock)
{
@@ -369,8 +381,12 @@ static int dps310_set_pres_precision(struct dps310_data *data, int val)
if (rc)
return rc;

- return regmap_update_bits(data->regmap, DPS310_PRS_CFG,
- DPS310_PRS_PRC_BITS, ilog2(val));
+ rc = regmap_update_bits(data->regmap, DPS310_PRS_CFG,
+ DPS310_PRS_PRC_BITS, ilog2(val));
+ if (rc)
+ return rc;
+
+ return dps310_drop_sample(data, DPS310_PRS_BASE);
}

static int dps310_set_temp_precision(struct dps310_data *data, int val)
@@ -388,8 +404,12 @@ static int dps310_set_temp_precision(struct dps310_data *data, int val)
if (rc)
return rc;

- return regmap_update_bits(data->regmap, DPS310_TMP_CFG,
- DPS310_TMP_PRC_BITS, ilog2(val));
+ rc = regmap_update_bits(data->regmap, DPS310_TMP_CFG,
+ DPS310_TMP_PRC_BITS, ilog2(val));
+ if (rc)
+ return rc;
+
+ return dps310_drop_sample(data, DPS310_TMP_BASE);
}

static int dps310_set_pres_samp_freq(struct dps310_data *data, int freq)
@@ -651,6 +671,7 @@ static int dps310_write_raw(struct iio_dev *iio,
int val2, long mask)
{
struct dps310_data *data = iio_priv(iio);
+ int rc;

/* Reconfiguring mid-capture would change the values being captured */
IIO_DEV_ACQUIRE_DIRECT_MODE(iio, claim);
@@ -677,10 +698,24 @@ static int dps310_write_raw(struct iio_dev *iio,
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_PRESSURE:
- return dps310_set_pres_precision(data, val);
+ rc = dps310_set_pres_precision(data, val);
+ if (rc)
+ return rc;
+
+ /* A measurement already running finishes at the old ratio */
+ return dps310_read_pres_raw_locked(data);

case IIO_TEMP:
- return dps310_set_temp_precision(data, val);
+ rc = dps310_set_temp_precision(data, val);
+ if (rc)
+ return rc;
+
+ /* The next sample is the one cached for pressure compensation */
+ rc = dps310_read_temp_raw_locked(data);
+ if (rc)
+ return rc;
+
+ return dps310_read_temp_raw_locked(data);

default:
return -EINVAL;

base-commit: 43ffda3c7f8456bbe641ae8249a077a361b97880
--
2.43.0