* [PATCH v9 0/3] iio: pressure: dps310: hardware FIFO support
@ 2026-09-28 21:11 Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 1/3] iio: pressure: dps310: read buffered samples from the hardware FIFO Rupesh Majhi
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Rupesh Majhi @ 2026-09-28 21:11 UTC (permalink / raw)
To: Andy Shevchenko, David Lechner, Eddie James, Jonathan Cameron,
Nuno Sá
Cc: linux-iio, linux-kernel, Rupesh Majhi
Rest of v8, rebased on iio/testing where 1-6 and 10 now are.
Since v8, both in patch 1:
- a held entry that fails to compensate is dropped. v8 kept it and
retried it at every temperature entry, failing that drain and losing
rest of its batch. With one bad entry injected on hardware, v8 lost
20 to 45% of samples and v9 only that entry
- postenable takes the lock by hand instead of mixing guard() and goto
On your question about out-of-range values in the FIFO: none seen from
real data at any oversampling ratio. Checking turned up an s64 overflow in
pressure compensation, fixed on its own:
https://lore.kernel.org/linux-iio/20260928101803.547005-1-zoone.rupert@gmail.com/
Retested on a DPS310 on a BeagleBone Black: six of six buffer enables
produce data, flush race test clean. Built with clang 23 and
CONFIG_WARN_CONTEXT_ANALYSIS, no warnings.
Clang annotation for the mode claim helpers, from Andy's question on v7
9/10, comes as its own series, with at_least for dps310_fill_channels().
Cleanup series after that.
Rupesh Majhi (3):
iio: pressure: dps310: read buffered samples from the hardware FIFO
iio: pressure: dps310: derive the drain interval from the watermark
iio: pressure: dps310: implement .hwfifo_flush_to_buffer()
drivers/iio/pressure/dps310.c | 410 +++++++++++++++++++++++++++++++++-
1 file changed, 400 insertions(+), 10 deletions(-)
base-commit: a3b3580713f3ac5a32dc2874ee546828977a1d68
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v9 1/3] iio: pressure: dps310: read buffered samples from the hardware FIFO
2026-09-28 21:11 [PATCH v9 0/3] iio: pressure: dps310: hardware FIFO support Rupesh Majhi
@ 2026-09-28 21:11 ` Rupesh Majhi
2026-09-28 21:55 ` Andy Shevchenko
2026-09-28 21:11 ` [PATCH v9 2/3] iio: pressure: dps310: derive the drain interval from the watermark Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 3/3] iio: pressure: dps310: implement .hwfifo_flush_to_buffer() Rupesh Majhi
2 siblings, 1 reply; 5+ messages in thread
From: Rupesh Majhi @ 2026-09-28 21:11 UTC (permalink / raw)
To: Andy Shevchenko, David Lechner, Eddie James, Jonathan Cameron,
Nuno Sá
Cc: linux-iio, linux-kernel, Rupesh Majhi
The DPS310 has a 32-entry FIFO shared by both measurements. Drain it from
a work item and push what it held, so a buffered capture needs no
trigger. Nothing in tree wires the interrupt pin, so the work rearms
itself at half the time the FIFO takes to fill.
Entries carry one measurement each, so a pressure entry is compensated
with the temperature ahead of it. Pressure read before the first
temperature of a session is held until one arrives rather than dropped,
so the first push can wait a temperature period.
FIFO entries are not timestamped, so postenable refuses the timestamp
channel unless a trigger is attached.
Tested on a DPS310 on a BeagleBone Black.
Assisted-by: LLM
Signed-off-by: Rupesh Majhi <zoone.rupert@gmail.com>
---
drivers/iio/pressure/dps310.c | 353 +++++++++++++++++++++++++++++++++-
1 file changed, 343 insertions(+), 10 deletions(-)
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index 85df58ac1809..c199fc734084 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -2,16 +2,11 @@
// Copyright IBM Corp 2019
/*
* The DPS310 is a barometric pressure and temperature sensor.
- * Currently only reading a single temperature is supported by
- * this driver.
*
* https://www.infineon.com/dgdl/?fileId=5546d462576f34750157750826c42242
*
* Temperature calculation:
* c0 * 0.5 + c1 * T_raw / kT °C
- *
- * TODO:
- * - Optionally support the FIFO
*/
#include <linux/cleanup.h>
@@ -20,7 +15,10 @@
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/regmap.h>
+#include <linux/slab.h>
#include <linux/unaligned.h>
+#include <linux/units.h>
+#include <linux/workqueue.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
@@ -59,9 +57,22 @@
#define DPS310_FIFO_EN BIT(1)
#define DPS310_SPI_EN BIT(0)
#define DPS310_RESET 0x0c
+#define DPS310_FIFO_FLUSH BIT(7)
#define DPS310_RESET_MAGIC 0x09
#define DPS310_COEF_BASE 0x10
+/* Section 4.8: 32 shared entries. Stops when full, so late drains lose data */
+#define DPS310_FIFO_DEPTH 32
+
+/* Read back once the FIFO is empty */
+#define DPS310_FIFO_EMPTY_VAL 0x800000
+
+/* LSB tags which measurement produced the entry */
+#define DPS310_FIFO_TAG_PRS BIT(0)
+
+#define DPS310_DRAIN_MIN_MS 20
+#define DPS310_DRAIN_MAX_MS (2 * MSEC_PER_SEC)
+
/* 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 */
@@ -95,6 +106,22 @@ struct dps310_data {
s32 pressure_raw;
s32 temp_raw;
bool timeout_recovery_failed;
+ bool fifo_temp_valid;
+
+ /* Used only while the FIFO is enabled */
+ struct iio_dev *iio;
+ struct delayed_work fifo_work;
+ s32 *fifo_hold;
+ unsigned int fifo_hold_max;
+ unsigned int fifo_held;
+ unsigned int drain_interval_ms;
+ s32 fifo_temp_raw;
+};
+
+enum dps310_fifo_entry {
+ DPS310_FIFO_EMPTY,
+ DPS310_FIFO_TEMP,
+ DPS310_FIFO_PRESSURE,
};
enum dps310_scan_index {
@@ -937,6 +964,291 @@ static int dps310_fill_channels(struct dps310_data *data,
return 0;
}
+static int dps310_fifo_hw_flush(struct dps310_data *data)
+ __must_hold(&data->lock)
+{
+ return regmap_write(data->regmap, DPS310_RESET, DPS310_FIFO_FLUSH);
+}
+
+static int dps310_fifo_set_enable(struct dps310_data *data, bool enable)
+ __must_hold(&data->lock)
+{
+ return regmap_assign_bits(data->regmap, DPS310_CFG_REG, DPS310_FIFO_EN,
+ enable);
+}
+
+/*
+ * No interrupt pin is wired in tree, so drain on a timer. Both measurements
+ * share the entries, so they fill it together.
+ */
+static unsigned int dps310_fifo_interval(int prs_rate, int tmp_rate)
+{
+ unsigned int fill_ms;
+
+ fill_ms = MSEC_PER_SEC * DPS310_FIFO_DEPTH / (prs_rate + tmp_rate);
+
+ return clamp(fill_ms / 2, DPS310_DRAIN_MIN_MS, DPS310_DRAIN_MAX_MS);
+}
+
+/* Returns which measurement the entry came from, or a negative error */
+static int dps310_fifo_read_entry(struct dps310_data *data, s32 *value)
+ __must_hold(&data->lock)
+{
+ u8 val[3];
+ s32 raw;
+ int rc;
+
+ /* Entries come out of the pressure registers whichever made them */
+ rc = regmap_bulk_read(data->regmap, DPS310_PRS_BASE, val, sizeof(val));
+ if (rc < 0)
+ return rc;
+
+ raw = get_unaligned_be24(val);
+ if (raw == DPS310_FIFO_EMPTY_VAL)
+ return DPS310_FIFO_EMPTY;
+
+ *value = sign_extend32(raw, 23);
+
+ return raw & DPS310_FIFO_TAG_PRS ? DPS310_FIFO_PRESSURE :
+ DPS310_FIFO_TEMP;
+}
+
+static int dps310_fifo_push_scan(struct dps310_data *data, s32 temp_raw,
+ s32 pressure_raw)
+ __must_hold(&data->lock)
+{
+ struct iio_dev *iio = data->iio;
+ s32 channels[2] = { };
+ unsigned int i;
+ int rc;
+
+ /* Direct-mode claim keeps sysfs reads off these */
+ data->temp_raw = temp_raw;
+ data->pressure_raw = pressure_raw;
+
+ i = 0;
+ if (test_bit(DPS310_SCAN_TEMP, iio->active_scan_mask)) {
+ rc = dps310_calculate_temp(data, &channels[i++]);
+ if (rc)
+ return rc;
+ }
+
+ if (test_bit(DPS310_SCAN_PRESSURE, iio->active_scan_mask)) {
+ rc = dps310_calculate_pressure(data, &channels[i++]);
+ if (rc)
+ return rc;
+ }
+
+ iio_push_to_buffers(iio, channels);
+
+ return 0;
+}
+
+/* Pressure seen before any temperature, kept until one turns up */
+static void dps310_fifo_hold(struct dps310_data *data, s32 pressure_raw)
+ __must_hold(&data->lock)
+{
+ if (data->fifo_held < data->fifo_hold_max)
+ data->fifo_hold[data->fifo_held++] = pressure_raw;
+}
+
+/* Returns scans pushed. One that fails to compensate is dropped. */
+static unsigned int dps310_fifo_push_held(struct dps310_data *data)
+ __must_hold(&data->lock)
+{
+ unsigned int pushed = 0;
+ unsigned int i;
+
+ for (i = 0; i < data->fifo_held; i++) {
+ if (!dps310_fifo_push_scan(data, data->fifo_temp_raw,
+ data->fifo_hold[i]))
+ pushed++;
+ }
+
+ data->fifo_held = 0;
+
+ return pushed;
+}
+
+/*
+ * Read the batch out before compensating it, so a pressure entry pairs with
+ * the temperature preceding it rather than the last one in the batch.
+ *
+ * Returns scans pushed.
+ */
+static int dps310_fifo_drain(struct dps310_data *data)
+ __must_hold(&data->lock)
+{
+ bool pressure_enabled = test_bit(DPS310_SCAN_PRESSURE,
+ data->iio->active_scan_mask);
+ u8 kind[DPS310_FIFO_DEPTH];
+ s32 raw[DPS310_FIFO_DEPTH];
+ unsigned int pushed = 0;
+ unsigned int cnt, i;
+ int rc;
+
+ for (cnt = 0; cnt < DPS310_FIFO_DEPTH; cnt++) {
+ rc = dps310_fifo_read_entry(data, &raw[cnt]);
+ if (rc < 0)
+ return rc;
+
+ if (rc == DPS310_FIFO_EMPTY)
+ break;
+
+ kind[cnt] = rc;
+ }
+
+ for (i = 0; i < cnt; i++) {
+ if (kind[i] == DPS310_FIFO_TEMP) {
+ data->fifo_temp_raw = raw[i];
+ data->fifo_temp_valid = true;
+
+ if (!pressure_enabled) {
+ if (!dps310_fifo_push_scan(data, raw[i], 0))
+ pushed++;
+ continue;
+ }
+
+ pushed += dps310_fifo_push_held(data);
+ continue;
+ }
+
+ if (!pressure_enabled)
+ continue;
+
+ if (!data->fifo_temp_valid) {
+ dps310_fifo_hold(data, raw[i]);
+ continue;
+ }
+
+ if (!dps310_fifo_push_scan(data, data->fifo_temp_raw, raw[i]))
+ pushed++;
+ }
+
+ return pushed;
+}
+
+static void dps310_fifo_work(struct work_struct *work)
+{
+ struct dps310_data *data = container_of(to_delayed_work(work),
+ struct dps310_data, fifo_work);
+ int rc;
+
+ mutex_lock(&data->lock);
+ rc = dps310_fifo_drain(data);
+ mutex_unlock(&data->lock);
+
+ if (rc < 0)
+ dev_dbg(&data->client->dev, "FIFO drain failed: %d\n", rc);
+
+ schedule_delayed_work(&data->fifo_work,
+ msecs_to_jiffies(data->drain_interval_ms));
+}
+
+/*
+ * First temperature is one temperature period away at most, which bounds the
+ * pressure before it. Rates cannot change while the buffer runs.
+ */
+static int dps310_fifo_hold_alloc(struct dps310_data *data, int prs_rate,
+ int tmp_rate)
+ __must_hold(&data->lock)
+{
+ data->fifo_temp_valid = false;
+ data->fifo_held = 0;
+ data->fifo_hold = NULL;
+ data->fifo_hold_max = 0;
+
+ if (!test_bit(DPS310_SCAN_PRESSURE, data->iio->active_scan_mask))
+ return 0;
+
+ data->fifo_hold_max = prs_rate / tmp_rate + 2;
+ data->fifo_hold = kcalloc(data->fifo_hold_max, sizeof(*data->fifo_hold),
+ GFP_KERNEL);
+ if (!data->fifo_hold)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int dps310_buffer_postenable(struct iio_dev *iio)
+{
+ struct dps310_data *data = iio_priv(iio);
+ int rc, prs_rate, tmp_rate;
+
+ /* An attached trigger drives the capture instead, FIFO stays off */
+ if (iio_device_get_current_mode(iio) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ /* Entries are not timestamped and the drain timer is no substitute */
+ if (iio_scan_timestamp_enabled(iio))
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+
+ rc = dps310_get_pres_samp_freq(data, &prs_rate);
+ if (rc)
+ goto err_unlock;
+
+ rc = dps310_get_temp_samp_freq(data, &tmp_rate);
+ if (rc)
+ goto err_unlock;
+
+ data->drain_interval_ms = dps310_fifo_interval(prs_rate, tmp_rate);
+
+ rc = dps310_fifo_hold_alloc(data, prs_rate, tmp_rate);
+ if (rc)
+ goto err_unlock;
+
+ /* Drop whatever accumulated before enable */
+ rc = dps310_fifo_hw_flush(data);
+ if (rc)
+ goto err_hold;
+
+ rc = dps310_fifo_set_enable(data, true);
+ if (rc)
+ goto err_hold;
+
+ schedule_delayed_work(&data->fifo_work,
+ msecs_to_jiffies(data->drain_interval_ms));
+
+ mutex_unlock(&data->lock);
+
+ return 0;
+
+err_hold:
+ kfree(data->fifo_hold);
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return rc;
+}
+
+static int dps310_buffer_predisable(struct iio_dev *iio)
+{
+ struct dps310_data *data = iio_priv(iio);
+ int rc;
+
+ if (iio_device_get_current_mode(iio) == INDIO_BUFFER_TRIGGERED)
+ return 0;
+
+ cancel_delayed_work_sync(&data->fifo_work);
+
+ guard(mutex)(&data->lock);
+
+ kfree(data->fifo_hold);
+
+ rc = dps310_fifo_set_enable(data, false);
+ if (rc)
+ return rc;
+
+ return dps310_fifo_hw_flush(data);
+}
+
+static const struct iio_buffer_setup_ops dps310_buffer_setup_ops = {
+ .postenable = dps310_buffer_postenable,
+ .predisable = dps310_buffer_predisable,
+};
+
static irqreturn_t dps310_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -969,6 +1281,14 @@ static void dps310_reset(void *action_data)
dps310_reset_wait(data);
}
+/* The drain rearms itself, so stop it even if the buffer never disabled */
+static void dps310_cancel_fifo_work(void *action_data)
+{
+ struct dps310_data *data = action_data;
+
+ cancel_delayed_work_sync(&data->fifo_work);
+}
+
static const struct regmap_config dps310_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -996,13 +1316,20 @@ static int dps310_probe(struct i2c_client *client)
data = iio_priv(iio);
data->client = client;
+ data->iio = iio;
mutex_init(&data->lock);
+ INIT_DELAYED_WORK(&data->fifo_work, dps310_fifo_work);
iio->name = DPS310_DEV_NAME;
iio->channels = dps310_channels;
iio->num_channels = ARRAY_SIZE(dps310_channels);
iio->info = &dps310_info;
- iio->modes = INDIO_DIRECT_MODE;
+ /*
+ * Both modes advertised: the core picks TRIGGERED with a trigger
+ * attached and falls back to SOFTWARE, which the FIFO path uses.
+ */
+ iio->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_TRIGGERED |
+ INDIO_BUFFER_SOFTWARE;
data->regmap = devm_regmap_init_i2c(client, &dps310_regmap_config);
if (IS_ERR(data->regmap))
@@ -1018,12 +1345,18 @@ static int dps310_probe(struct i2c_client *client)
return rc;
/*
- * The device measures continuously in background mode, so a capture is
- * just a read of the latest results. The trigger is not aligned with
- * the measurements, so the timestamp is taken in the handler.
+ * The device measures continuously in background mode, so a triggered
+ * capture is just a read of the latest results. The setup ops run the
+ * FIFO drain when no trigger is attached. The trigger is not aligned
+ * with the measurements, so the timestamp is taken in the handler.
*/
rc = devm_iio_triggered_buffer_setup(dev, iio, NULL,
- dps310_trigger_handler, NULL);
+ dps310_trigger_handler,
+ &dps310_buffer_setup_ops);
+ if (rc)
+ return rc;
+
+ rc = devm_add_action_or_reset(dev, dps310_cancel_fifo_work, data);
if (rc)
return rc;
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v9 2/3] iio: pressure: dps310: derive the drain interval from the watermark
2026-09-28 21:11 [PATCH v9 0/3] iio: pressure: dps310: hardware FIFO support Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 1/3] iio: pressure: dps310: read buffered samples from the hardware FIFO Rupesh Majhi
@ 2026-09-28 21:11 ` Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 3/3] iio: pressure: dps310: implement .hwfifo_flush_to_buffer() Rupesh Majhi
2 siblings, 0 replies; 5+ messages in thread
From: Rupesh Majhi @ 2026-09-28 21:11 UTC (permalink / raw)
To: Andy Shevchenko, David Lechner, Eddie James, Jonathan Cameron,
Nuno Sá
Cc: linux-iio, linux-kernel, Rupesh Majhi
The drain interval only tracked how fast the FIFO fills, so a small
watermark still waited half a FIFO for its samples. Take the watermark
as the number of scans to wait for, but never drain slower than half a
fill.
Assisted-by: LLM
Signed-off-by: Rupesh Majhi <zoone.rupert@gmail.com>
---
drivers/iio/pressure/dps310.c | 35 +++++++++++++++++++++++++++++++----
1 file changed, 31 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index c199fc734084..66f24adc8df7 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -114,6 +114,7 @@ struct dps310_data {
s32 *fifo_hold;
unsigned int fifo_hold_max;
unsigned int fifo_held;
+ unsigned int watermark;
unsigned int drain_interval_ms;
s32 fifo_temp_raw;
};
@@ -981,13 +982,28 @@ static int dps310_fifo_set_enable(struct dps310_data *data, bool enable)
* No interrupt pin is wired in tree, so drain on a timer. Both measurements
* share the entries, so they fill it together.
*/
-static unsigned int dps310_fifo_interval(int prs_rate, int tmp_rate)
+static unsigned int dps310_fifo_interval(struct dps310_data *data, int prs_rate,
+ int tmp_rate)
{
- unsigned int fill_ms;
+ unsigned int fill_ms, want_ms;
+ int scan_rate;
fill_ms = MSEC_PER_SEC * DPS310_FIFO_DEPTH / (prs_rate + tmp_rate);
- return clamp(fill_ms / 2, DPS310_DRAIN_MIN_MS, DPS310_DRAIN_MAX_MS);
+ /*
+ * There is no hardware watermark, so take it as the number of scans
+ * the user will wait for and drain at that rate. Scans come from
+ * whichever measurement drives them.
+ */
+ if (test_bit(DPS310_SCAN_PRESSURE, data->iio->active_scan_mask))
+ scan_rate = prs_rate;
+ else
+ scan_rate = tmp_rate;
+
+ want_ms = data->watermark * MSEC_PER_SEC / scan_rate;
+
+ return clamp(min(want_ms, fill_ms / 2), DPS310_DRAIN_MIN_MS,
+ DPS310_DRAIN_MAX_MS);
}
/* Returns which measurement the entry came from, or a negative error */
@@ -1170,6 +1186,15 @@ static int dps310_fifo_hold_alloc(struct dps310_data *data, int prs_rate,
return 0;
}
+static int dps310_hwfifo_set_watermark(struct iio_dev *iio, unsigned int val)
+{
+ struct dps310_data *data = iio_priv(iio);
+
+ data->watermark = clamp(val, 1, DPS310_FIFO_DEPTH);
+
+ return 0;
+}
+
static int dps310_buffer_postenable(struct iio_dev *iio)
{
struct dps310_data *data = iio_priv(iio);
@@ -1193,7 +1218,7 @@ static int dps310_buffer_postenable(struct iio_dev *iio)
if (rc)
goto err_unlock;
- data->drain_interval_ms = dps310_fifo_interval(prs_rate, tmp_rate);
+ data->drain_interval_ms = dps310_fifo_interval(data, prs_rate, tmp_rate);
rc = dps310_fifo_hold_alloc(data, prs_rate, tmp_rate);
if (rc)
@@ -1301,6 +1326,7 @@ static const struct regmap_config dps310_regmap_config = {
static const struct iio_info dps310_info = {
.read_raw = dps310_read_raw,
.write_raw = dps310_write_raw,
+ .hwfifo_set_watermark = dps310_hwfifo_set_watermark,
};
static int dps310_probe(struct i2c_client *client)
@@ -1317,6 +1343,7 @@ static int dps310_probe(struct i2c_client *client)
data = iio_priv(iio);
data->client = client;
data->iio = iio;
+ data->watermark = 1;
mutex_init(&data->lock);
INIT_DELAYED_WORK(&data->fifo_work, dps310_fifo_work);
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v9 3/3] iio: pressure: dps310: implement .hwfifo_flush_to_buffer()
2026-09-28 21:11 [PATCH v9 0/3] iio: pressure: dps310: hardware FIFO support Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 1/3] iio: pressure: dps310: read buffered samples from the hardware FIFO Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 2/3] iio: pressure: dps310: derive the drain interval from the watermark Rupesh Majhi
@ 2026-09-28 21:11 ` Rupesh Majhi
2 siblings, 0 replies; 5+ messages in thread
From: Rupesh Majhi @ 2026-09-28 21:11 UTC (permalink / raw)
To: Andy Shevchenko, David Lechner, Eddie James, Jonathan Cameron,
Nuno Sá
Cc: linux-iio, linux-kernel, Rupesh Majhi
Let userspace drain the FIFO on demand rather than only from the
periodic drain.
With a trigger attached the FIFO is not running, so there is nothing to
flush and the hook returns 0.
Hold the mode across the drain, so a concurrent buffer disable cannot
free active_scan_mask while it runs.
Assisted-by: LLM
Signed-off-by: Rupesh Majhi <zoone.rupert@gmail.com>
---
drivers/iio/pressure/dps310.c | 36 ++++++++++++++++++++++++++++++++---
1 file changed, 33 insertions(+), 3 deletions(-)
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index 66f24adc8df7..2af2971de970 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -1088,22 +1088,30 @@ static unsigned int dps310_fifo_push_held(struct dps310_data *data)
/*
* Read the batch out before compensating it, so a pressure entry pairs with
- * the temperature preceding it rather than the last one in the batch.
+ * the temperature preceding it rather than the last one in the batch. Stop
+ * reading at max_scans rather than after it, since entries leave the hardware
+ * as they are read and any extra would have to be thrown away. max_scans of
+ * zero drains everything.
*
* Returns scans pushed.
*/
-static int dps310_fifo_drain(struct dps310_data *data)
+static int dps310_fifo_drain(struct dps310_data *data, unsigned int max_scans)
__must_hold(&data->lock)
{
bool pressure_enabled = test_bit(DPS310_SCAN_PRESSURE,
data->iio->active_scan_mask);
u8 kind[DPS310_FIFO_DEPTH];
s32 raw[DPS310_FIFO_DEPTH];
+ unsigned int scans = 0;
unsigned int pushed = 0;
unsigned int cnt, i;
+ bool is_pressure;
int rc;
for (cnt = 0; cnt < DPS310_FIFO_DEPTH; cnt++) {
+ if (max_scans && scans >= max_scans)
+ break;
+
rc = dps310_fifo_read_entry(data, &raw[cnt]);
if (rc < 0)
return rc;
@@ -1111,7 +1119,12 @@ static int dps310_fifo_drain(struct dps310_data *data)
if (rc == DPS310_FIFO_EMPTY)
break;
+ is_pressure = rc == DPS310_FIFO_PRESSURE;
kind[cnt] = rc;
+
+ /* Only the measurement that drives the scans counts */
+ if (is_pressure == pressure_enabled)
+ scans++;
}
for (i = 0; i < cnt; i++) {
@@ -1151,7 +1164,7 @@ static void dps310_fifo_work(struct work_struct *work)
int rc;
mutex_lock(&data->lock);
- rc = dps310_fifo_drain(data);
+ rc = dps310_fifo_drain(data, 0);
mutex_unlock(&data->lock);
if (rc < 0)
@@ -1186,6 +1199,22 @@ static int dps310_fifo_hold_alloc(struct dps310_data *data, int prs_rate,
return 0;
}
+static int dps310_hwfifo_flush(struct iio_dev *iio, unsigned int count)
+{
+ struct dps310_data *data = iio_priv(iio);
+
+ /* Holding the mode keeps active_scan_mask alive across the drain */
+ IIO_DEV_GUARD_CURRENT_MODE(iio);
+
+ /* A trigger drives the capture instead and leaves the FIFO empty */
+ if (iio_device_get_current_mode(iio) != INDIO_BUFFER_SOFTWARE)
+ return 0;
+
+ guard(mutex)(&data->lock);
+
+ return dps310_fifo_drain(data, count);
+}
+
static int dps310_hwfifo_set_watermark(struct iio_dev *iio, unsigned int val)
{
struct dps310_data *data = iio_priv(iio);
@@ -1327,6 +1356,7 @@ static const struct iio_info dps310_info = {
.read_raw = dps310_read_raw,
.write_raw = dps310_write_raw,
.hwfifo_set_watermark = dps310_hwfifo_set_watermark,
+ .hwfifo_flush_to_buffer = dps310_hwfifo_flush,
};
static int dps310_probe(struct i2c_client *client)
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH v9 1/3] iio: pressure: dps310: read buffered samples from the hardware FIFO
2026-09-28 21:11 ` [PATCH v9 1/3] iio: pressure: dps310: read buffered samples from the hardware FIFO Rupesh Majhi
@ 2026-09-28 21:55 ` Andy Shevchenko
0 siblings, 0 replies; 5+ messages in thread
From: Andy Shevchenko @ 2026-09-28 21:55 UTC (permalink / raw)
To: Rupesh Majhi
Cc: Andy Shevchenko, David Lechner, Eddie James, Jonathan Cameron,
Nuno Sá,
linux-iio, linux-kernel
On Tue, Sep 29, 2026 at 12:11:25AM +0300, Rupesh Majhi wrote:
> The DPS310 has a 32-entry FIFO shared by both measurements. Drain it from
> a work item and push what it held, so a buffered capture needs no
> trigger. Nothing in tree wires the interrupt pin, so the work rearms
> itself at half the time the FIFO takes to fill.
>
> Entries carry one measurement each, so a pressure entry is compensated
> with the temperature ahead of it. Pressure read before the first
> temperature of a session is held until one arrives rather than dropped,
> so the first push can wait a temperature period.
>
> FIFO entries are not timestamped, so postenable refuses the timestamp
> channel unless a trigger is attached.
>
> Tested on a DPS310 on a BeagleBone Black.
...
> +#define DPS310_DRAIN_MAX_MS (2 * MSEC_PER_SEC)
+ time.h
...
> +/* Returns which measurement the entry came from, or a negative error */
> +static int dps310_fifo_read_entry(struct dps310_data *data, s32 *value)
> + __must_hold(&data->lock)
Hmm... Don't you want to also add lockdep annotations?
...
> + if (kind[i] == DPS310_FIFO_TEMP) {
> + data->fifo_temp_raw = raw[i];
> + data->fifo_temp_valid = true;
> +
> + if (!pressure_enabled) {
> + if (!dps310_fifo_push_scan(data, raw[i], 0))
> + pushed++;
> + continue;
> + }
> +
> + pushed += dps310_fifo_push_held(data);
> + continue;
You may deduplicate 'continue'.
> + }
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-09-28 21:55 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-28 21:11 [PATCH v9 0/3] iio: pressure: dps310: hardware FIFO support Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 1/3] iio: pressure: dps310: read buffered samples from the hardware FIFO Rupesh Majhi
2026-09-28 21:55 ` Andy Shevchenko
2026-09-28 21:11 ` [PATCH v9 2/3] iio: pressure: dps310: derive the drain interval from the watermark Rupesh Majhi
2026-09-28 21:11 ` [PATCH v9 3/3] iio: pressure: dps310: implement .hwfifo_flush_to_buffer() Rupesh Majhi
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®