[PATCH 4/4] iio: pressure: Add triggered buffer support for BMP280 driver

From: Vasileios Amoiridis
Date: Sun Mar 03 2024 - 11:54:12 EST


Add a buffer struct that will hold the values of the measurements
and will be pushed to userspace. Modify all read_* functions in order
to just read and compensate the data without though converting to the
required IIO measurement units which are used for the oneshot captures.

Signed-off-by: Vasileios Amoiridis <vassilisamir@xxxxxxxxx>
---
drivers/iio/pressure/Kconfig | 2 +
drivers/iio/pressure/bmp280-core.c | 155 +++++++++++++++++++++++------
drivers/iio/pressure/bmp280.h | 7 ++
3 files changed, 134 insertions(+), 30 deletions(-)

diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig
index 79adfd059c3a..5145b94b4679 100644
--- a/drivers/iio/pressure/Kconfig
+++ b/drivers/iio/pressure/Kconfig
@@ -31,6 +31,8 @@ config BMP280
select REGMAP
select BMP280_I2C if (I2C)
select BMP280_SPI if (SPI_MASTER)
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
help
Say yes here to build support for Bosch Sensortec BMP180, BMP280, BMP380
and BMP580 pressure and temperature sensors. Also supports the BME280 with
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 3bdf6002983f..3b1a159e57ea 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -31,8 +31,12 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
+#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
#include <linux/interrupt.h>
#include <linux/irq.h> /* For irq_get_irq_data() */
#include <linux/module.h>
@@ -457,13 +461,16 @@ static int bmp280_read_temp(struct bmp280_data *data,

/*
* val might be NULL if we're called by the read_press routine,
- * who only cares about the carry over t_fine value.
+ * who only cares about the carry over t_fine value or if we're called
+ * by the buffer handler function.
*/
if (val) {
*val = comp_temp * 10;
return IIO_VAL_INT;
}

+ data->iio_buffer.temperature = comp_temp;
+
return 0;
}

@@ -494,10 +501,16 @@ static int bmp280_read_press(struct bmp280_data *data,
}
comp_press = bmp280_compensate_press(data, adc_press);

- *val = comp_press;
- *val2 = 256000;
+ /* val might be NULL if we're called by the buffer handler */
+ if (val) {
+ *val = comp_press;
+ *val2 = 256000;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ data->iio_buffer.pressure = comp_press;

- return IIO_VAL_FRACTIONAL;
+ return 0;
}

static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2)
@@ -526,9 +539,15 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2)
}
comp_humidity = bmp280_compensate_humidity(data, adc_humidity);

- *val = comp_humidity * 1000 / 1024;
+ /* val might be NULL if we're called by the buffer handler */
+ if (val) {
+ *val = comp_humidity * 1000 / 1024;
+ return IIO_VAL_INT;
+ }

- return IIO_VAL_INT;
+ data->iio_buffer.humidity = comp_humidity;
+
+ return 0;
}

static int bmp280_read_raw(struct iio_dev *indio_dev,
@@ -1170,7 +1189,8 @@ static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2)

/*
* Val might be NULL if we're called by the read_press routine,
- * who only cares about the carry over t_fine value.
+ * who only cares about the carry over t_fine value or if we're called
+ * by the buffer handler.
*/
if (val) {
/* IIO reports temperatures in milli Celsius */
@@ -1178,6 +1198,8 @@ static int bmp380_read_temp(struct bmp280_data *data, int *val, int *val2)
return IIO_VAL_INT;
}

+ data->iio_buffer.temperature = comp_temp;
+
return 0;
}

@@ -1206,11 +1228,17 @@ static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2)
}
comp_press = bmp380_compensate_press(data, adc_press);

- *val = comp_press;
- /* Compensated pressure is in cPa (centipascals) */
- *val2 = 100000;
+ /* val might be NULL if we're called by the buffer handler */
+ if (val) {
+ *val = comp_press;
+ /* Compensated pressure is in cPa (centipascals) */
+ *val2 = 100000;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ data->iio_buffer.pressure = comp_press;

- return IIO_VAL_FRACTIONAL;
+ return 0;
}

static int bmp380_read_calib(struct bmp280_data *data)
@@ -1543,14 +1571,21 @@ static int bmp580_read_temp(struct bmp280_data *data, int *val, int *val2)
return -EIO;
}

- /*
- * Temperature is returned in Celsius degrees in fractional
- * form down 2^16. We rescale by x1000 to return milli Celsius
- * to respect IIO ABI.
- */
- *val = raw_temp * 1000;
- *val2 = 16;
- return IIO_VAL_FRACTIONAL_LOG2;
+ /* val might be NULL if we're called by the buffer handler */
+ if (val) {
+ /*
+ * Temperature is returned in Celsius degrees in fractional
+ * form down 2^16. We rescale by x1000 to return milli Celsius
+ * to respect IIO ABI.
+ */
+ *val = raw_temp * 1000;
+ *val2 = 16;
+ return IIO_VAL_FRACTIONAL_LOG2;
+ }
+
+ data->iio_buffer.temperature = raw_temp;
+
+ return 0;
}

static int bmp580_read_press(struct bmp280_data *data, int *val, int *val2)
@@ -1570,13 +1605,21 @@ static int bmp580_read_press(struct bmp280_data *data, int *val, int *val2)
dev_err(data->dev, "reading pressure skipped\n");
return -EIO;
}
- /*
- * Pressure is returned in Pascals in fractional form down 2^16.
- * We rescale /1000 to convert to kilopascal to respect IIO ABI.
- */
- *val = raw_press;
- *val2 = 64000; /* 2^6 * 1000 */
- return IIO_VAL_FRACTIONAL;
+
+ /* val might be NULL if we're called by the buffer handler */
+ if (val) {
+ /*
+ * Pressure is returned in Pascals in fractional form down 2^16.
+ * We rescale /1000 to convert to kilopascal to respect IIO ABI.
+ */
+ *val = raw_press;
+ *val2 = 64000; /* 2^6 * 1000 */
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ data->iio_buffer.pressure = raw_press;
+
+ return 0;
}

static const int bmp580_odr_table[][2] = {
@@ -2048,13 +2091,16 @@ static int bmp180_read_temp(struct bmp280_data *data, int *val, int *val2)

/*
* val might be NULL if we're called by the read_press routine,
- * who only cares about the carry over t_fine value.
+ * who only cares about the carry over t_fine value or if we're called
+ * by the buffer handler.
*/
if (val) {
*val = comp_temp * 100;
return IIO_VAL_INT;
}

+ data->iio_buffer.temperature = comp_temp;
+
return 0;
}

@@ -2133,10 +2179,16 @@ static int bmp180_read_press(struct bmp280_data *data,

comp_press = bmp180_compensate_press(data, adc_press);

- *val = comp_press;
- *val2 = 1000;
+ /* val might be NULL if we're called by the buffer handler */
+ if (val) {
+ *val = comp_press;
+ *val2 = 1000;
+ return IIO_VAL_FRACTIONAL;
+ }
+
+ data->iio_buffer.pressure = comp_press;

- return IIO_VAL_FRACTIONAL;
+ return 0;
}

static int bmp180_chip_config(struct bmp280_data *data)
@@ -2217,6 +2269,43 @@ static int bmp085_fetch_eoc_irq(struct device *dev,
return 0;
}

+static irqreturn_t bmp280_buffer_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct bmp280_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ if (test_bit(BMP280_TEMP, indio_dev->active_scan_mask)) {
+ ret = data->chip_info->read_temp(data, NULL, NULL);
+ if (ret < 0)
+ goto done;
+ }
+
+ if (test_bit(BMP280_PRESS, indio_dev->active_scan_mask)) {
+ ret = data->chip_info->read_press(data, NULL, NULL);
+ if (ret < 0)
+ goto done;
+ }
+
+ if (test_bit(BME280_HUMID, indio_dev->active_scan_mask)) {
+ ret = data->chip_info->read_humid(data, NULL, NULL);
+ if (ret < 0)
+ goto done;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, &data->iio_buffer,
+ pf->timestamp);
+
+done:
+ mutex_unlock(&data->lock);
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+
+}
static void bmp280_pm_disable(void *data)
{
struct device *dev = data;
@@ -2358,6 +2447,12 @@ int bmp280_common_probe(struct device *dev,
return ret;
}

+ ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
+ iio_pollfunc_store_time,
+ &bmp280_buffer_handler, NULL);
+ if (ret)
+ return dev_err_probe(data->dev, ret,
+ "iio triggered buffer setup failed\n");
/* Enable runtime PM */
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index d77402cb3121..d5c0451ebf68 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -400,6 +400,13 @@ struct bmp280_data {
*/
s32 t_fine;

+ /* IIO sysfs buffer */
+ struct {
+ s32 temperature;
+ u32 pressure;
+ u32 humidity;
+ s64 timestamp;
+ } iio_buffer;
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
--
2.25.1