Linux IIO development
 help / color / mirror / Atom feed
From: Rupesh Majhi <zoone.rupert@gmail.com>
To: "David Lechner" <dlechner@baylibre.com>,
	"Nuno Sá" <nuno.sa@analog.com>,
	"Andy Shevchenko" <andy@kernel.org>,
	"Jonathan Cameron" <Jonathan.Cameron@huawei.com>,
	"Petre Rodan" <petre.rodan@subdimension.ro>,
	"Marcelo Schmitt" <marcelo.schmitt1@gmail.com>,
	"Rupesh Majhi" <zoone.rupert@gmail.com>,
	"Akhilesh Patil" <akhilesh@ee.iitb.ac.in>,
	linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org
Cc: Jonathan Cameron <jic23@kernel.org>, Eddie James <eajames@linux.ibm.com>
Subject: [PATCH v3] iio: pressure: dps310: add triggered buffer support
Date: Sun, 19 Jul 2026 02:51:58 +0300	[thread overview]
Message-ID: <20260718235203.73699-1-zoone.rupert@gmail.com> (raw)
In-Reply-To: <20260718224455.38acd927@jic23-huawei>

Add triggered buffer support so pressure and temperature can be captured
into a buffer instead of only through one-shot sysfs reads.

Pressure is a processed value in kPa computed from a non-linear
calibration polynomial. To keep full resolution in the buffer without
disagreeing with the sysfs unit, add raw and scale attributes for
pressure (raw in Pa, scale 1/1000 to kPa), following bme680; the existing
processed attribute is kept for ABI compatibility. Temperature is already
a full-resolution value in its base unit (millidegrees Celsius) and stays
a processed channel.

Pressure compensation depends on a temperature reading, so both channels
are always captured together. The device already runs in continuous
background mode, so no buffer setup ops are needed. Sysfs reads and
reconfiguration return -EBUSY while the buffer is enabled, as they share
the capture path's raw values and configuration.

Signed-off-by: Rupesh Majhi <zoone.rupert@gmail.com>
---
Changes in v3:
 - Rework from just enabling the FIFO into proper IIO triggered buffer
   support, as suggested by Jonathan.
 - Buffer the pressure and temperature values; add raw + scale for
   pressure (bme680-style) so buffered pressure keeps full resolution
   and stays consistent with the sysfs unit.
 - Drop the unused FIFO enable/flush/read helpers.

v2 was a resend that still contained the v1 FIFO-enable code.

Note: this touches dps310_probe() near the separately-sent fix "iio:
pressure: dps310: fix NULL pointer deref on ACPI probe". It was generated
on a plain base tree, so applying it after that fix needs a trivial
3-way merge/rebase - happy to resend in whatever order or branch you
prefer.

 drivers/iio/pressure/Kconfig  |   2 +
 drivers/iio/pressure/dps310.c | 141 ++++++++++++++++++++++++++++++++--
 2 files changed, 136 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 838a8340c4c0..cef8b90b9ae7 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -112,6 +112,8 @@ config DPS310
 	tristate "Infineon DPS310 pressure and temperature sensor"
 	depends on I2C
 	select REGMAP_I2C
+	select IIO_BUFFER
+	select IIO_TRIGGERED_BUFFER
 	help
 	  Support for the Infineon DPS310 digital barometric pressure sensor.
 	  It can be accessed over I2C bus.
diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c
index f45af72a0554..967a2043550b 100644
--- a/drivers/iio/pressure/dps310.c
+++ b/drivers/iio/pressure/dps310.c
@@ -20,8 +20,11 @@
 #include <linux/module.h>
 #include <linux/regmap.h>
 
+#include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #define DPS310_DEV_NAME		"dps310"
 
@@ -90,6 +93,12 @@ struct dps310_data {
 	s32 pressure_raw;
 	s32 temp_raw;
 	bool timeout_recovery_failed;
+
+	/* Buffer to hold a scan; timestamp is naturally aligned */
+	struct {
+		s32 chan[2];
+		aligned_s64 timestamp;
+	} scan __aligned(8);
 };
 
 static const struct iio_chan_spec dps310_channels[] = {
@@ -98,15 +107,38 @@ static const struct iio_chan_spec dps310_channels[] = {
 		.info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
 			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
 			BIT(IIO_CHAN_INFO_PROCESSED),
+		.scan_index = 0,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 32,
+			.storagebits = 32,
+			.endianness = IIO_CPU,
+		},
 	},
 	{
 		.type = IIO_PRESSURE,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) |
 			BIT(IIO_CHAN_INFO_SAMP_FREQ) |
-			BIT(IIO_CHAN_INFO_PROCESSED),
+			BIT(IIO_CHAN_INFO_PROCESSED) |
+			BIT(IIO_CHAN_INFO_RAW) |
+			BIT(IIO_CHAN_INFO_SCALE),
+		.scan_index = 1,
+		.scan_type = {
+			.sign = 's',
+			.realbits = 32,
+			.storagebits = 32,
+			.endianness = IIO_CPU,
+		},
 	},
+	IIO_CHAN_SOFT_TIMESTAMP(2),
 };
 
+/*
+ * Pressure compensation needs a temperature reading, so the trigger
+ * handler always captures both channels; keep them enabled together.
+ */
+static const unsigned long dps310_scan_masks[] = { GENMASK(1, 0), 0 };
+
 /* To be called after checking the COEF_RDY bit in MEAS_CFG */
 static int dps310_get_coefs(struct dps310_data *data)
 {
@@ -583,8 +615,14 @@ static int dps310_write_raw(struct iio_dev *iio,
 	int rc;
 	struct dps310_data *data = iio_priv(iio);
 
-	if (mutex_lock_interruptible(&data->lock))
+	/* Don't reconfigure the sensor while a buffered capture is running */
+	if (!iio_device_claim_direct(iio))
+		return -EBUSY;
+
+	if (mutex_lock_interruptible(&data->lock)) {
+		iio_device_release_direct(iio);
 		return -EINTR;
+	}
 
 	switch (mask) {
 	case IIO_CHAN_INFO_SAMP_FREQ:
@@ -625,6 +663,7 @@ static int dps310_write_raw(struct iio_dev *iio,
 	}
 
 	mutex_unlock(&data->lock);
+	iio_device_release_direct(iio);
 	return rc;
 }
 
@@ -735,6 +774,23 @@ static int dps310_read_pressure(struct dps310_data *data, int *val, int *val2,
 		*val2 = 1000; /* Convert Pa to KPa per IIO ABI */
 		return IIO_VAL_FRACTIONAL;
 
+	case IIO_CHAN_INFO_RAW:
+		rc = dps310_read_pres_raw(data);
+		if (rc)
+			return rc;
+
+		rc = dps310_calculate_pressure(data, val);
+		if (rc)
+			return rc;
+
+		return IIO_VAL_INT;
+
+	case IIO_CHAN_INFO_SCALE:
+		/* Raw pressure is in Pa; scale to kPa per IIO ABI */
+		*val = 1;
+		*val2 = 1000;
+		return IIO_VAL_FRACTIONAL;
+
 	case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
 		rc = dps310_get_pres_precision(data, val);
 		if (rc)
@@ -804,12 +860,10 @@ static int dps310_read_temp(struct dps310_data *data, int *val, int *val2,
 	}
 }
 
-static int dps310_read_raw(struct iio_dev *iio,
-			   struct iio_chan_spec const *chan,
-			   int *val, int *val2, long mask)
+static int dps310_read_channel(struct dps310_data *data,
+			       struct iio_chan_spec const *chan,
+			       int *val, int *val2, long mask)
 {
-	struct dps310_data *data = iio_priv(iio);
-
 	switch (chan->type) {
 	case IIO_PRESSURE:
 		return dps310_read_pressure(data, val, val2, mask);
@@ -822,6 +876,32 @@ static int dps310_read_raw(struct iio_dev *iio,
 	}
 }
 
+static int dps310_read_raw(struct iio_dev *iio,
+			   struct iio_chan_spec const *chan,
+			   int *val, int *val2, long mask)
+{
+	struct dps310_data *data = iio_priv(iio);
+	int rc;
+
+	switch (mask) {
+	case IIO_CHAN_INFO_RAW:
+	case IIO_CHAN_INFO_PROCESSED:
+		/*
+		 * Reading a sample uses the same raw values as the buffered
+		 * capture path, so only allow it outside of buffered mode.
+		 */
+		if (!iio_device_claim_direct(iio))
+			return -EBUSY;
+
+		rc = dps310_read_channel(data, chan, val, val2, mask);
+		iio_device_release_direct(iio);
+		return rc;
+
+	default:
+		return dps310_read_channel(data, chan, val, val2, mask);
+	}
+}
+
 static void dps310_reset(void *action_data)
 {
 	struct dps310_data *data = action_data;
@@ -843,6 +923,46 @@ static const struct iio_info dps310_info = {
 	.write_raw = dps310_write_raw,
 };
 
+static irqreturn_t dps310_trigger_handler(int irq, void *p)
+{
+	struct iio_poll_func *pf = p;
+	struct iio_dev *iio = pf->indio_dev;
+	struct dps310_data *data = iio_priv(iio);
+	int rc, pressure, temp;
+
+	/*
+	 * Don't hold data->lock across these calls: the read helpers take it
+	 * themselves and the mutex is not recursive (dps310_calculate_pressure
+	 * also grabs it with mutex_trylock to refresh the temperature).
+	 */
+	rc = dps310_read_pres_raw(data);
+	if (rc)
+		goto out;
+
+	rc = dps310_read_temp_raw(data);
+	if (rc)
+		goto out;
+
+	rc = dps310_calculate_pressure(data, &pressure);
+	if (rc)
+		goto out;
+
+	rc = dps310_calculate_temp(data, &temp);
+	if (rc)
+		goto out;
+
+	data->scan.chan[0] = temp;	/* millidegrees Celsius */
+	data->scan.chan[1] = pressure;	/* Pascals */
+
+	iio_push_to_buffers_with_ts(iio, &data->scan, sizeof(data->scan),
+				    pf->timestamp);
+
+out:
+	iio_trigger_notify_done(iio->trig);
+
+	return IRQ_HANDLED;
+}
+
 static int dps310_probe(struct i2c_client *client)
 {
 	const struct i2c_device_id *id = i2c_client_get_device_id(client);
@@ -863,6 +983,7 @@ static int dps310_probe(struct i2c_client *client)
 	iio->num_channels = ARRAY_SIZE(dps310_channels);
 	iio->info = &dps310_info;
 	iio->modes = INDIO_DIRECT_MODE;
+	iio->available_scan_masks = dps310_scan_masks;
 
 	data->regmap = devm_regmap_init_i2c(client, &dps310_regmap_config);
 	if (IS_ERR(data->regmap))
@@ -877,6 +998,12 @@ static int dps310_probe(struct i2c_client *client)
 	if (rc)
 		return rc;
 
+	rc = devm_iio_triggered_buffer_setup(&client->dev, iio,
+					     iio_pollfunc_store_time,
+					     dps310_trigger_handler, NULL);
+	if (rc)
+		return rc;
+
 	rc = devm_iio_device_register(&client->dev, iio);
 	if (rc)
 		return rc;
-- 
2.43.0


  reply	other threads:[~2026-07-18 23:54 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-18 21:17 [PATCH] iio: pressure: dps310: add FIFO support Rupesh Majhi
2026-07-18 21:44 ` Jonathan Cameron
2026-07-18 23:51   ` Rupesh Majhi [this message]
2026-07-19  8:47     ` [PATCH v3] iio: pressure: dps310: add triggered buffer support Andy Shevchenko
2026-07-19  8:48       ` Andy Shevchenko
2026-07-19 21:48       ` Jonathan Cameron
2026-07-19 22:11     ` Jonathan Cameron
2026-07-20  5:56       ` Rupert Zoone
2026-07-23 23:42         ` Jonathan Cameron

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260718235203.73699-1-zoone.rupert@gmail.com \
    --to=zoone.rupert@gmail.com \
    --cc=Jonathan.Cameron@huawei.com \
    --cc=akhilesh@ee.iitb.ac.in \
    --cc=andy@kernel.org \
    --cc=dlechner@baylibre.com \
    --cc=eajames@linux.ibm.com \
    --cc=jic23@kernel.org \
    --cc=linux-iio@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=marcelo.schmitt1@gmail.com \
    --cc=nuno.sa@analog.com \
    --cc=petre.rodan@subdimension.ro \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox