* [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support
@ 2024-10-17 23:30 Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures Vasileios Amoiridis
` (6 more replies)
0 siblings, 7 replies; 71+ messages in thread
From: Vasileios Amoiridis @ 2024-10-17 23:30 UTC (permalink / raw)
To: jic23, lars, robh, krzk+dt, conor+dt, andriy.shevchenko
Cc: vassilisamir, ang.iglesiasg, ajarizzo, biju.das.jz, linus.walleij,
semen.protsenko, 579lpy, ak, linux-iio, devicetree, linux-kernel
Changes in v9:
PATCH 1/4:
- fixed warning of uninitialized variable that was generated by
the kernel test robot in v8.
PATCH 4/4:
- Remove extra lock and unneeded reenable function since the irq is
being reset on the first read in the irq handler.
---
v8: https://lore.kernel.org/linux-iio/20241007194945.66192-1-vassilisamir@gmail.com
v7: https://lore.kernel.org/linux-iio/20240914002900.45158-1-vassilisamir@gmail.com
v6: https://lore.kernel.org/linux-iio/20240912233234.45519-1-vassilisamir@gmail.com
v5: https://lore.kernel.org/linux-iio/20240902184222.24874-1-vassilisamir@gmail.com
v4: https://lore.kernel.org/linux-iio/20240828205128.92145-1-vassilisamir@gmail.com
v3: https://lore.kernel.org/linux-iio/20240823181714.64545-1-vassilisamir@gmail.com
v2: https://lore.kernel.org/linux-iio/20240725231039.614536-1-vassilisamir@gmail.com
v1: https://lore.kernel.org/linux-iio/20240711211558.106327-1-vassilisamir@gmail.com
Vasileios Amoiridis (4):
iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
dt-bindings: iio: pressure: bmp085: Add interrupts for BMP3xx and
BMP5xx devices
iio: pressure: bmp280: Add data ready trigger support
iio: pressure: bmp280: Move bmp085 interrupt to new configuration
.../bindings/iio/pressure/bmp085.yaml | 22 +-
drivers/iio/pressure/bmp280-core.c | 536 ++++++++++++++++--
drivers/iio/pressure/bmp280-i2c.c | 4 +-
drivers/iio/pressure/bmp280-spi.c | 4 +-
drivers/iio/pressure/bmp280.h | 43 ++
5 files changed, 568 insertions(+), 41 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 71+ messages in thread
* [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
@ 2024-10-17 23:30 ` Vasileios Amoiridis
2025-06-28 18:45 ` ASSI
2024-10-17 23:30 ` [PATCH v9 2/4] dt-bindings: iio: pressure: bmp085: Add interrupts for BMP3xx and BMP5xx devices Vasileios Amoiridis
` (5 subsequent siblings)
6 siblings, 1 reply; 71+ messages in thread
From: Vasileios Amoiridis @ 2024-10-17 23:30 UTC (permalink / raw)
To: jic23, lars, robh, krzk+dt, conor+dt, andriy.shevchenko
Cc: vassilisamir, ang.iglesiasg, ajarizzo, biju.das.jz, linus.walleij,
semen.protsenko, 579lpy, ak, linux-iio, devicetree, linux-kernel
Add forced mode support in sensors BMP28x, BME28x, BMP3xx and BMP58x.
Sensors BMP18x and BMP085 are old and do not support this feature so
their operation is not affected at all.
Essentially, up to now, the rest of the sensors were used in normal mode
all the time. This means that they are continuously doing measurements
even though these measurements are not used. Even though the sensor does
provide PM support, to cover all the possible use cases, the sensor needs
to go into sleep mode and wake up whenever necessary.
The idea is that the sensor is by default in sleep mode, wakes up in
forced mode when a oneshot capture is requested, or in normal mode
when the buffer is enabled. The difference lays in the fact that in
forced mode, the sensor does only one conversion and goes back to sleep
while in normal mode, the sensor does continuous measurements with the
frequency that was set in the ODR registers.
The bmpX_chip_config() functions which are responsible for applying
the requested configuration to the sensor, are modified accordingly
in order to set the sensor by default in sleep mode.
DEEP STANDBY, Low Power NORMAL and CONTINUOUS modes, supported only by
the BMP58x version, are not added.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Vasileios Amoiridis <vassilisamir@gmail.com>
---
drivers/iio/pressure/bmp280-core.c | 280 ++++++++++++++++++++++++++---
drivers/iio/pressure/bmp280.h | 21 +++
2 files changed, 280 insertions(+), 21 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 682329f81886..70abaff08646 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -16,6 +16,11 @@
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp390-ds002.pdf
* https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp581-ds004.pdf
*
+ * Sensor API:
+ * https://github.com/boschsensortec/BME280_SensorAPI
+ * https://github.com/boschsensortec/BMP3_SensorAPI
+ * https://github.com/boschsensortec/BMP5_SensorAPI
+ *
* Notice:
* The link to the bmp180 datasheet points to an outdated version missing these changes:
* - Changed document referral from ANP015 to BST-MPS-AN004-00 on page 26
@@ -616,6 +621,14 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
+ ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ if (ret)
+ return ret;
+
+ ret = data->chip_info->wait_conv(data);
+ if (ret)
+ return ret;
+
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
ret = data->chip_info->read_humid(data, &chan_value);
@@ -645,6 +658,14 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
+ ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ if (ret)
+ return ret;
+
+ ret = data->chip_info->wait_conv(data);
+ if (ret)
+ return ret;
+
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
ret = data->chip_info->read_humid(data, &chan_value);
@@ -991,6 +1012,65 @@ static int bmp280_preinit(struct bmp280_data *data)
return 0;
}
+static const u8 bmp280_operation_mode[] = {
+ [BMP280_SLEEP] = BMP280_MODE_SLEEP,
+ [BMP280_FORCED] = BMP280_MODE_FORCED,
+ [BMP280_NORMAL] = BMP280_MODE_NORMAL,
+};
+
+static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
+{
+ int ret;
+
+ ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
+ BMP280_MODE_MASK, bmp280_operation_mode[mode]);
+ if (ret) {
+ dev_err(data->dev, "failed to write ctrl_meas register.\n");
+ return ret;
+ }
+
+ data->op_mode = mode;
+
+ return 0;
+}
+
+static int bmp280_wait_conv(struct bmp280_data *data)
+{
+ unsigned int reg, meas_time_us;
+ int ret;
+
+ /* Check if we are using a BME280 device */
+ if (data->oversampling_humid)
+ meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
+ BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
+
+ else
+ meas_time_us = 0;
+
+ /* Pressure measurement time */
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
+ BIT(data->oversampling_press) * BMP280_MEAS_DUR;
+
+ /* Temperature measurement time */
+ meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
+
+ /* Waiting time according to the BM(P/E)2 Sensor API */
+ fsleep(meas_time_us);
+
+ ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
+ if (ret) {
+ dev_err(data->dev, "failed to read status register.\n");
+ return ret;
+ }
+
+ if (reg & BMP280_REG_STATUS_MEAS_BIT) {
+ dev_err(data->dev, "Measurement cycle didn't complete.\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
static int bmp280_chip_config(struct bmp280_data *data)
{
u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
@@ -1001,7 +1081,7 @@ static int bmp280_chip_config(struct bmp280_data *data)
BMP280_OSRS_TEMP_MASK |
BMP280_OSRS_PRESS_MASK |
BMP280_MODE_MASK,
- osrs | BMP280_MODE_NORMAL);
+ osrs | BMP280_MODE_SLEEP);
if (ret) {
dev_err(data->dev, "failed to write ctrl_meas register\n");
return ret;
@@ -1111,6 +1191,8 @@ const struct bmp280_chip_info bmp280_chip_info = {
.read_temp = bmp280_read_temp,
.read_press = bmp280_read_press,
.read_calib = bmp280_read_calib,
+ .set_mode = bmp280_set_mode,
+ .wait_conv = bmp280_wait_conv,
.preinit = bmp280_preinit,
.trigger_handler = bmp280_trigger_handler,
@@ -1235,6 +1317,8 @@ const struct bmp280_chip_info bme280_chip_info = {
.read_press = bmp280_read_press,
.read_humid = bme280_read_humid,
.read_calib = bme280_read_calib,
+ .set_mode = bmp280_set_mode,
+ .wait_conv = bmp280_wait_conv,
.preinit = bmp280_preinit,
.trigger_handler = bme280_trigger_handler,
@@ -1522,6 +1606,64 @@ static int bmp380_preinit(struct bmp280_data *data)
return bmp380_cmd(data, BMP380_CMD_SOFT_RESET);
}
+static const u8 bmp380_operation_mode[] = {
+ [BMP280_SLEEP] = BMP380_MODE_SLEEP,
+ [BMP280_FORCED] = BMP380_MODE_FORCED,
+ [BMP280_NORMAL] = BMP380_MODE_NORMAL,
+};
+
+static int bmp380_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
+{
+ int ret;
+
+ ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL,
+ BMP380_MODE_MASK,
+ FIELD_PREP(BMP380_MODE_MASK,
+ bmp380_operation_mode[mode]));
+ if (ret) {
+ dev_err(data->dev, "failed to write power control register.\n");
+ return ret;
+ }
+
+ data->op_mode = mode;
+
+ return 0;
+}
+
+static int bmp380_wait_conv(struct bmp280_data *data)
+{
+ unsigned int reg;
+ int ret, meas_time_us;
+
+ /* Offset measurement time */
+ meas_time_us = BMP380_MEAS_OFFSET;
+
+ /* Pressure measurement time */
+ meas_time_us += BMP380_PRESS_MEAS_OFFSET +
+ BIT(data->oversampling_press) * BMP380_MEAS_DUR;
+
+ /* Temperature measurement time */
+ meas_time_us += BMP380_TEMP_MEAS_OFFSET +
+ BIT(data->oversampling_temp) * BMP380_MEAS_DUR;
+
+ /* Measurement time defined in Datasheet Section 3.9.2 */
+ fsleep(meas_time_us);
+
+ ret = regmap_read(data->regmap, BMP380_REG_STATUS, ®);
+ if (ret) {
+ dev_err(data->dev, "failed to read status register.\n");
+ return ret;
+ }
+
+ if (!((reg & BMP380_STATUS_DRDY_PRESS_MASK) &&
+ (reg & BMP380_STATUS_DRDY_TEMP_MASK))) {
+ dev_err(data->dev, "Measurement cycle didn't complete.\n");
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
static int bmp380_chip_config(struct bmp280_data *data)
{
bool change = false, aux;
@@ -1582,17 +1724,19 @@ static int bmp380_chip_config(struct bmp280_data *data)
* Resets sensor measurement loop toggling between sleep and
* normal operating modes.
*/
- ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL,
- BMP380_MODE_MASK,
- FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_SLEEP));
+ ret = bmp380_set_mode(data, BMP280_SLEEP);
if (ret) {
dev_err(data->dev, "failed to set sleep mode\n");
return ret;
}
- usleep_range(2000, 2500);
- ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL,
- BMP380_MODE_MASK,
- FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_NORMAL));
+
+ /*
+ * According to the BMP3 Sensor API, the sensor needs 5ms
+ * in order to go to the sleep mode.
+ */
+ fsleep(5 * USEC_PER_MSEC);
+
+ ret = bmp380_set_mode(data, BMP280_NORMAL);
if (ret) {
dev_err(data->dev, "failed to set normal mode\n");
return ret;
@@ -1618,7 +1762,16 @@ static int bmp380_chip_config(struct bmp280_data *data)
}
}
- return 0;
+ /* Dummy read to empty data registers. */
+ ret = bmp380_read_press(data, &tmp);
+ if (ret)
+ return ret;
+
+ ret = bmp380_set_mode(data, BMP280_SLEEP);
+ if (ret)
+ dev_err(data->dev, "failed to set sleep mode.\n");
+
+ return ret;
}
static irqreturn_t bmp380_trigger_handler(int irq, void *p)
@@ -1714,6 +1867,8 @@ const struct bmp280_chip_info bmp380_chip_info = {
.read_temp = bmp380_read_temp,
.read_press = bmp380_read_press,
.read_calib = bmp380_read_calib,
+ .set_mode = bmp380_set_mode,
+ .wait_conv = bmp380_wait_conv,
.preinit = bmp380_preinit,
.trigger_handler = bmp380_trigger_handler,
@@ -2101,6 +2256,70 @@ static int bmp580_preinit(struct bmp280_data *data)
return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config));
}
+static const u8 bmp580_operation_mode[] = {
+ [BMP280_SLEEP] = BMP580_MODE_SLEEP,
+ [BMP280_FORCED] = BMP580_MODE_FORCED,
+ [BMP280_NORMAL] = BMP580_MODE_NORMAL,
+};
+
+static int bmp580_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
+{
+ struct device *dev = data->dev;
+ int ret;
+
+ if (mode == BMP280_FORCED) {
+ ret = regmap_set_bits(data->regmap, BMP580_REG_DSP_CONFIG,
+ BMP580_DSP_IIR_FORCED_FLUSH);
+ if (ret) {
+ dev_err(dev, "Could not flush IIR filter constants.\n");
+ return ret;
+ }
+ }
+
+ ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG,
+ BMP580_MODE_MASK,
+ FIELD_PREP(BMP580_MODE_MASK,
+ bmp580_operation_mode[mode]));
+ if (ret) {
+ dev_err(dev, "failed to write power control register.\n");
+ return ret;
+ }
+
+ data->op_mode = mode;
+
+ return 0;
+}
+
+static int bmp580_wait_conv(struct bmp280_data *data)
+{
+ /*
+ * Taken from datasheet, Section 2 "Specification, Table 3 "Electrical
+ * characteristics.
+ */
+ static const int time_conv_press[] = {
+ 0, 1050, 1785, 3045, 5670, 10920, 21420, 42420,
+ 84420,
+ };
+ static const int time_conv_temp[] = {
+ 0, 1050, 1105, 1575, 2205, 3465, 6090, 11340,
+ 21840,
+ };
+ int meas_time_us;
+
+ meas_time_us = 4 * USEC_PER_MSEC +
+ time_conv_temp[data->oversampling_temp] +
+ time_conv_press[data->oversampling_press];
+
+ /*
+ * Measurement time mentioned in Chapter 2, Table 4 of the datasheet.
+ * The extra 4ms is the required mode change to start of measurement
+ * time.
+ */
+ fsleep(meas_time_us);
+
+ return 0;
+}
+
static int bmp580_chip_config(struct bmp280_data *data)
{
bool change = false, aux;
@@ -2171,17 +2390,6 @@ static int bmp580_chip_config(struct bmp280_data *data)
return ret;
}
- /* Restore sensor to normal operation mode */
- ret = regmap_write_bits(data->regmap, BMP580_REG_ODR_CONFIG,
- BMP580_MODE_MASK,
- FIELD_PREP(BMP580_MODE_MASK, BMP580_MODE_NORMAL));
- if (ret) {
- dev_err(data->dev, "failed to set normal mode\n");
- return ret;
- }
- /* From datasheet's table 4: electrical characteristics */
- usleep_range(3000, 3500);
-
if (change) {
/*
* Check if ODR and OSR settings are valid or we are
@@ -2281,6 +2489,8 @@ const struct bmp280_chip_info bmp580_chip_info = {
.chip_config = bmp580_chip_config,
.read_temp = bmp580_read_temp,
.read_press = bmp580_read_press,
+ .set_mode = bmp580_set_mode,
+ .wait_conv = bmp580_wait_conv,
.preinit = bmp580_preinit,
.trigger_handler = bmp580_trigger_handler,
@@ -2528,6 +2738,19 @@ static int bmp180_read_press(struct bmp280_data *data, u32 *comp_press)
return 0;
}
+/* Keep compatibility with newer generations of the sensor */
+static int bmp180_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
+{
+ return 0;
+}
+
+/* Keep compatibility with newer generations of the sensor */
+static int bmp180_wait_conv(struct bmp280_data *data)
+{
+ return 0;
+}
+
+/* Keep compatibility with newer generations of the sensor */
static int bmp180_chip_config(struct bmp280_data *data)
{
return 0;
@@ -2599,6 +2822,8 @@ const struct bmp280_chip_info bmp180_chip_info = {
.read_temp = bmp180_read_temp,
.read_press = bmp180_read_press,
.read_calib = bmp180_read_calib,
+ .set_mode = bmp180_set_mode,
+ .wait_conv = bmp180_wait_conv,
.trigger_handler = bmp180_trigger_handler,
};
@@ -2651,6 +2876,7 @@ static int bmp280_buffer_preenable(struct iio_dev *indio_dev)
struct bmp280_data *data = iio_priv(indio_dev);
pm_runtime_get_sync(data->dev);
+ data->chip_info->set_mode(data, BMP280_NORMAL);
return 0;
}
@@ -2821,6 +3047,10 @@ int bmp280_common_probe(struct device *dev,
return ret;
}
+ ret = data->chip_info->set_mode(data, BMP280_SLEEP);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to set sleep mode\n");
+
/* Enable runtime PM */
pm_runtime_get_noresume(dev);
pm_runtime_set_active(dev);
@@ -2846,6 +3076,9 @@ static int bmp280_runtime_suspend(struct device *dev)
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmp280_data *data = iio_priv(indio_dev);
+ data->chip_info->set_mode(data, BMP280_SLEEP);
+
+ fsleep(data->start_up_time);
return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies);
}
@@ -2860,7 +3093,12 @@ static int bmp280_runtime_resume(struct device *dev)
return ret;
usleep_range(data->start_up_time, data->start_up_time + 100);
- return data->chip_info->chip_config(data);
+
+ ret = data->chip_info->chip_config(data);
+ if (ret)
+ return ret;
+
+ return data->chip_info->set_mode(data, data->op_mode);
}
EXPORT_RUNTIME_DEV_PM_OPS(bmp280_dev_pm_ops, bmp280_runtime_suspend,
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index dc1bf04cb0b5..3babf90ce73c 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -170,6 +170,11 @@
#define BMP380_MODE_FORCED 1
#define BMP380_MODE_NORMAL 3
+#define BMP380_MEAS_OFFSET 234
+#define BMP380_MEAS_DUR 2020
+#define BMP380_TEMP_MEAS_OFFSET 163
+#define BMP380_PRESS_MEAS_OFFSET 392
+
#define BMP380_MIN_TEMP -4000
#define BMP380_MAX_TEMP 8500
#define BMP380_MIN_PRES 3000000
@@ -206,6 +211,7 @@
#define BMP280_REG_CTRL_MEAS 0xF4
#define BMP280_REG_STATUS 0xF3
#define BMP280_REG_STATUS_IM_UPDATE BIT(0)
+#define BMP280_REG_STATUS_MEAS_BIT BIT(3)
#define BMP280_REG_RESET 0xE0
#define BMP280_RST_SOFT_CMD 0xB6
@@ -246,6 +252,10 @@
#define BMP280_MODE_FORCED 1
#define BMP280_MODE_NORMAL 3
+#define BMP280_MEAS_OFFSET 1250
+#define BMP280_MEAS_DUR 2300
+#define BMP280_PRESS_HUMID_MEAS_OFFSET 575
+
/* BME280 specific registers */
#define BME280_REG_HUMIDITY_LSB 0xFE
#define BME280_REG_HUMIDITY_MSB 0xFD
@@ -385,6 +395,12 @@ struct bmp380_calib {
s8 P11;
};
+enum bmp280_op_mode {
+ BMP280_SLEEP,
+ BMP280_FORCED,
+ BMP280_NORMAL,
+};
+
struct bmp280_data {
struct device *dev;
struct mutex lock;
@@ -423,6 +439,9 @@ struct bmp280_data {
u8 sensor_data[ALIGN(sizeof(s32) * BME280_NUM_MAX_CHANNELS, sizeof(s64))
+ sizeof(s64)] __aligned(sizeof(s64));
+ /* Value to hold the current operation mode of the device */
+ enum bmp280_op_mode op_mode;
+
/*
* DMA (thus cache coherency maintenance) may require the
* transfer buffers to live in their own cache lines.
@@ -487,6 +506,8 @@ struct bmp280_chip_info {
int (*read_humid)(struct bmp280_data *data, u32 *adc_humidity);
int (*read_calib)(struct bmp280_data *data);
int (*preinit)(struct bmp280_data *data);
+ int (*set_mode)(struct bmp280_data *data, enum bmp280_op_mode mode);
+ int (*wait_conv)(struct bmp280_data *data);
irqreturn_t (*trigger_handler)(int irq, void *p);
};
--
2.43.0
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH v9 2/4] dt-bindings: iio: pressure: bmp085: Add interrupts for BMP3xx and BMP5xx devices
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures Vasileios Amoiridis
@ 2024-10-17 23:30 ` Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 3/4] iio: pressure: bmp280: Add data ready trigger support Vasileios Amoiridis
` (4 subsequent siblings)
6 siblings, 0 replies; 71+ messages in thread
From: Vasileios Amoiridis @ 2024-10-17 23:30 UTC (permalink / raw)
To: jic23, lars, robh, krzk+dt, conor+dt, andriy.shevchenko
Cc: vassilisamir, ang.iglesiasg, ajarizzo, biju.das.jz, linus.walleij,
semen.protsenko, 579lpy, ak, linux-iio, devicetree, linux-kernel,
Conor Dooley
Add interrupt options for BMP3xx and BMP5xx devices as well.
Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Vasileios Amoiridis <vassilisamir@gmail.com>
---
.../bindings/iio/pressure/bmp085.yaml | 22 +++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml
index 6fda887ee9d4..cb201cecfa1a 100644
--- a/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml
+++ b/Documentation/devicetree/bindings/iio/pressure/bmp085.yaml
@@ -47,15 +47,33 @@ properties:
maxItems: 1
interrupts:
- description:
- interrupt mapping for IRQ (BMP085 only)
maxItems: 1
+ drive-open-drain:
+ description:
+ set if the interrupt pin should be configured as open drain.
+ If not set, defaults to push-pull configuration.
+ type: boolean
+
required:
- compatible
- vddd-supply
- vdda-supply
+allOf:
+ - if:
+ properties:
+ compatible:
+ not:
+ contains:
+ enum:
+ - bosch,bmp085
+ - bosch,bmp380
+ - bosch,bmp580
+ then:
+ properties:
+ interrupts: false
+
additionalProperties: false
examples:
--
2.43.0
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH v9 3/4] iio: pressure: bmp280: Add data ready trigger support
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 2/4] dt-bindings: iio: pressure: bmp085: Add interrupts for BMP3xx and BMP5xx devices Vasileios Amoiridis
@ 2024-10-17 23:30 ` Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 4/4] iio: pressure: bmp280: Move bmp085 interrupt to new configuration Vasileios Amoiridis
` (3 subsequent siblings)
6 siblings, 0 replies; 71+ messages in thread
From: Vasileios Amoiridis @ 2024-10-17 23:30 UTC (permalink / raw)
To: jic23, lars, robh, krzk+dt, conor+dt, andriy.shevchenko
Cc: vassilisamir, ang.iglesiasg, ajarizzo, biju.das.jz, linus.walleij,
semen.protsenko, 579lpy, ak, linux-iio, devicetree, linux-kernel
The BMP3xx and BMP5xx sensors have an interrupt pin which can be used as
a trigger for when there are data ready in the sensor for pick up.
This use case is used along with NORMAL_MODE in the sensor, which allows
the sensor to do consecutive measurements depending on the ODR rate value.
The trigger pin can be configured to be open-drain or push-pull and either
rising or falling edge.
No support is added yet for interrupts for FIFO, WATERMARK and out of range
values.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Vasileios Amoiridis <vassilisamir@gmail.com>
---
drivers/iio/pressure/bmp280-core.c | 197 ++++++++++++++++++++++++++++-
drivers/iio/pressure/bmp280.h | 21 +++
2 files changed, 216 insertions(+), 2 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 70abaff08646..a941423a899a 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -42,12 +42,14 @@
#include <linux/module.h>
#include <linux/nvmem-provider.h>
#include <linux/pm_runtime.h>
+#include <linux/property.h>
#include <linux/random.h>
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/iio/buffer.h>
#include <linux/iio/iio.h>
+#include <linux/iio/trigger.h>
#include <linux/iio/trigger_consumer.h>
#include <linux/iio/triggered_buffer.h>
@@ -1280,6 +1282,63 @@ static irqreturn_t bme280_trigger_handler(int irq, void *p)
return IRQ_HANDLED;
}
+static int __bmp280_trigger_probe(struct iio_dev *indio_dev,
+ const struct iio_trigger_ops *trigger_ops,
+ int (*int_pin_config)(struct bmp280_data *data),
+ irq_handler_t irq_thread_handler)
+{
+ struct bmp280_data *data = iio_priv(indio_dev);
+ struct device *dev = data->dev;
+ u32 irq_type;
+ int ret, irq;
+
+ irq = fwnode_irq_get(dev_fwnode(dev), 0);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "No interrupt found.\n");
+
+ irq_type = irq_get_trigger_type(irq);
+ switch (irq_type) {
+ case IRQF_TRIGGER_RISING:
+ data->trig_active_high = true;
+ break;
+ case IRQF_TRIGGER_FALLING:
+ data->trig_active_high = false;
+ break;
+ default:
+ return dev_err_probe(dev, -EINVAL, "Invalid interrupt type specified.\n");
+ }
+
+ data->trig_open_drain =
+ fwnode_property_read_bool(dev_fwnode(dev), "int-open-drain");
+
+ ret = int_pin_config(data);
+ if (ret)
+ return ret;
+
+ data->trig = devm_iio_trigger_alloc(data->dev, "%s-dev%d",
+ indio_dev->name,
+ iio_device_id(indio_dev));
+ if (!data->trig)
+ return -ENOMEM;
+
+ data->trig->ops = trigger_ops;
+ iio_trigger_set_drvdata(data->trig, data);
+
+ ret = devm_request_threaded_irq(data->dev, irq, NULL,
+ irq_thread_handler, IRQF_ONESHOT,
+ indio_dev->name, indio_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "request IRQ failed.\n");
+
+ ret = devm_iio_trigger_register(data->dev, data->trig);
+ if (ret)
+ return dev_err_probe(dev, ret, "iio trigger register failed.\n");
+
+ indio_dev->trig = iio_trigger_get(data->trig);
+
+ return 0;
+}
+
static const u8 bme280_chip_ids[] = { BME280_CHIP_ID };
static const int bme280_humid_coeffs[] = { 1000, 1024 };
@@ -1774,6 +1833,67 @@ static int bmp380_chip_config(struct bmp280_data *data)
return ret;
}
+static int bmp380_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct bmp280_data *data = iio_trigger_get_drvdata(trig);
+ int ret;
+
+ guard(mutex)(&data->lock);
+
+ ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL,
+ BMP380_INT_CTRL_DRDY_EN,
+ FIELD_PREP(BMP380_INT_CTRL_DRDY_EN, !!state));
+ if (ret)
+ dev_err(data->dev,
+ "Could not %s interrupt.\n", str_enable_disable(state));
+ return ret;
+}
+
+static const struct iio_trigger_ops bmp380_trigger_ops = {
+ .set_trigger_state = &bmp380_data_rdy_trigger_set_state,
+};
+
+static int bmp380_int_pin_config(struct bmp280_data *data)
+{
+ int pin_drive_cfg = FIELD_PREP(BMP380_INT_CTRL_OPEN_DRAIN,
+ data->trig_open_drain);
+ int pin_level_cfg = FIELD_PREP(BMP380_INT_CTRL_LEVEL,
+ data->trig_active_high);
+ int ret, int_pin_cfg = pin_drive_cfg | pin_level_cfg;
+
+ ret = regmap_update_bits(data->regmap, BMP380_REG_INT_CONTROL,
+ BMP380_INT_CTRL_SETTINGS_MASK, int_pin_cfg);
+ if (ret)
+ dev_err(data->dev, "Could not set interrupt settings.\n");
+
+ return ret;
+}
+
+static irqreturn_t bmp380_irq_thread_handler(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct bmp280_data *data = iio_priv(indio_dev);
+ unsigned int int_ctrl;
+ int ret;
+
+ ret = regmap_read(data->regmap, BMP380_REG_INT_STATUS, &int_ctrl);
+ if (ret)
+ return IRQ_NONE;
+
+ if (FIELD_GET(BMP380_INT_STATUS_DRDY, int_ctrl))
+ iio_trigger_poll_nested(data->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int bmp380_trigger_probe(struct iio_dev *indio_dev)
+{
+ return __bmp280_trigger_probe(indio_dev, &bmp380_trigger_ops,
+ bmp380_int_pin_config,
+ bmp380_irq_thread_handler);
+}
+
static irqreturn_t bmp380_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -1871,6 +1991,7 @@ const struct bmp280_chip_info bmp380_chip_info = {
.wait_conv = bmp380_wait_conv,
.preinit = bmp380_preinit,
+ .trigger_probe = bmp380_trigger_probe,
.trigger_handler = bmp380_trigger_handler,
};
EXPORT_SYMBOL_NS(bmp380_chip_info, IIO_BMP280);
@@ -2413,6 +2534,74 @@ static int bmp580_chip_config(struct bmp280_data *data)
return 0;
}
+static int bmp580_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct bmp280_data *data = iio_trigger_get_drvdata(trig);
+ int ret;
+
+ guard(mutex)(&data->lock);
+
+ ret = regmap_update_bits(data->regmap, BMP580_REG_INT_CONFIG,
+ BMP580_INT_CONFIG_INT_EN,
+ FIELD_PREP(BMP580_INT_CONFIG_INT_EN, !!state));
+ if (ret)
+ dev_err(data->dev,
+ "Could not %s interrupt.\n", str_enable_disable(state));
+ return ret;
+}
+
+static const struct iio_trigger_ops bmp580_trigger_ops = {
+ .set_trigger_state = &bmp580_data_rdy_trigger_set_state,
+};
+
+static int bmp580_int_pin_config(struct bmp280_data *data)
+{
+ int pin_drive_cfg = FIELD_PREP(BMP580_INT_CONFIG_OPEN_DRAIN,
+ data->trig_open_drain);
+ int pin_level_cfg = FIELD_PREP(BMP580_INT_CONFIG_LEVEL,
+ data->trig_active_high);
+ int ret, int_pin_cfg = pin_drive_cfg | pin_level_cfg;
+
+ ret = regmap_update_bits(data->regmap, BMP580_REG_INT_CONFIG,
+ BMP580_INT_CONFIG_MASK, int_pin_cfg);
+ if (ret) {
+ dev_err(data->dev, "Could not set interrupt settings.\n");
+ return ret;
+ }
+
+ ret = regmap_set_bits(data->regmap, BMP580_REG_INT_SOURCE,
+ BMP580_INT_SOURCE_DRDY);
+ if (ret)
+ dev_err(data->dev, "Could not set interrupt source.\n");
+
+ return ret;
+}
+
+static irqreturn_t bmp580_irq_thread_handler(int irq, void *p)
+{
+ struct iio_dev *indio_dev = p;
+ struct bmp280_data *data = iio_priv(indio_dev);
+ unsigned int int_ctrl;
+ int ret;
+
+ ret = regmap_read(data->regmap, BMP580_REG_INT_STATUS, &int_ctrl);
+ if (ret)
+ return IRQ_NONE;
+
+ if (FIELD_GET(BMP580_INT_STATUS_DRDY_MASK, int_ctrl))
+ iio_trigger_poll_nested(data->trig);
+
+ return IRQ_HANDLED;
+}
+
+static int bmp580_trigger_probe(struct iio_dev *indio_dev)
+{
+ return __bmp280_trigger_probe(indio_dev, &bmp580_trigger_ops,
+ bmp580_int_pin_config,
+ bmp580_irq_thread_handler);
+}
+
static irqreturn_t bmp580_trigger_handler(int irq, void *p)
{
struct iio_poll_func *pf = p;
@@ -2493,6 +2682,7 @@ const struct bmp280_chip_info bmp580_chip_info = {
.wait_conv = bmp580_wait_conv,
.preinit = bmp580_preinit,
+ .trigger_probe = bmp580_trigger_probe,
.trigger_handler = bmp580_trigger_handler,
};
EXPORT_SYMBOL_NS(bmp580_chip_info, IIO_BMP280);
@@ -3041,8 +3231,11 @@ int bmp280_common_probe(struct device *dev,
* however as it happens, the BMP085 shares the chip ID of BMP180
* so we look for an IRQ if we have that.
*/
- if (irq > 0 && (chip_id == BMP180_CHIP_ID)) {
- ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
+ if (irq > 0) {
+ if (chip_id == BMP180_CHIP_ID)
+ ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
+ if (data->chip_info->trigger_probe)
+ ret = data->chip_info->trigger_probe(indio_dev);
if (ret)
return ret;
}
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 3babf90ce73c..12f6e90b3728 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -55,8 +55,17 @@
#define BMP580_CMD_NVM_WRITE_SEQ_1 0xA0
#define BMP580_CMD_SOFT_RESET 0xB6
+#define BMP580_INT_STATUS_DRDY_MASK BIT(0)
#define BMP580_INT_STATUS_POR_MASK BIT(4)
+#define BMP580_INT_SOURCE_DRDY BIT(0)
+
+#define BMP580_INT_CONFIG_MASK GENMASK(3, 0)
+#define BMP580_INT_CONFIG_LATCH BIT(0)
+#define BMP580_INT_CONFIG_LEVEL BIT(1)
+#define BMP580_INT_CONFIG_OPEN_DRAIN BIT(2)
+#define BMP580_INT_CONFIG_INT_EN BIT(3)
+
#define BMP580_STATUS_CORE_RDY_MASK BIT(0)
#define BMP580_STATUS_NVM_RDY_MASK BIT(1)
#define BMP580_STATUS_NVM_ERR_MASK BIT(2)
@@ -175,6 +184,14 @@
#define BMP380_TEMP_MEAS_OFFSET 163
#define BMP380_PRESS_MEAS_OFFSET 392
+#define BMP380_INT_STATUS_DRDY BIT(3)
+
+#define BMP380_INT_CTRL_SETTINGS_MASK GENMASK(2, 0)
+#define BMP380_INT_CTRL_OPEN_DRAIN BIT(0)
+#define BMP380_INT_CTRL_LEVEL BIT(1)
+#define BMP380_INT_CTRL_LATCH BIT(2)
+#define BMP380_INT_CTRL_DRDY_EN BIT(6)
+
#define BMP380_MIN_TEMP -4000
#define BMP380_MAX_TEMP 8500
#define BMP380_MIN_PRES 3000000
@@ -407,6 +424,9 @@ struct bmp280_data {
struct regmap *regmap;
struct completion done;
bool use_eoc;
+ bool trig_open_drain;
+ bool trig_active_high;
+ struct iio_trigger *trig;
const struct bmp280_chip_info *chip_info;
union {
struct bmp180_calib bmp180;
@@ -509,6 +529,7 @@ struct bmp280_chip_info {
int (*set_mode)(struct bmp280_data *data, enum bmp280_op_mode mode);
int (*wait_conv)(struct bmp280_data *data);
+ int (*trigger_probe)(struct iio_dev *indio_dev);
irqreturn_t (*trigger_handler)(int irq, void *p);
};
--
2.43.0
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [PATCH v9 4/4] iio: pressure: bmp280: Move bmp085 interrupt to new configuration
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
` (2 preceding siblings ...)
2024-10-17 23:30 ` [PATCH v9 3/4] iio: pressure: bmp280: Add data ready trigger support Vasileios Amoiridis
@ 2024-10-17 23:30 ` Vasileios Amoiridis
2024-10-19 13:55 ` [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Jonathan Cameron
` (2 subsequent siblings)
6 siblings, 0 replies; 71+ messages in thread
From: Vasileios Amoiridis @ 2024-10-17 23:30 UTC (permalink / raw)
To: jic23, lars, robh, krzk+dt, conor+dt, andriy.shevchenko
Cc: vassilisamir, ang.iglesiasg, ajarizzo, biju.das.jz, linus.walleij,
semen.protsenko, 579lpy, ak, linux-iio, devicetree, linux-kernel
This commit intends to add the old BMP085 sensor to the new IRQ interface
of the driver for consistence. No functional changes intended.
The BMP085 sensor is equivalent with the BMP180 with the only difference of
BMP085 having an extra interrupt pin to inform about an End of Conversion.
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Vasileios Amoiridis <vassilisamir@gmail.com>
---
drivers/iio/pressure/bmp280-core.c | 63 +++++++++++++++++++++++-------
drivers/iio/pressure/bmp280-i2c.c | 4 +-
drivers/iio/pressure/bmp280-spi.c | 4 +-
drivers/iio/pressure/bmp280.h | 1 +
4 files changed, 54 insertions(+), 18 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index a941423a899a..e5ec8137961f 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -3028,13 +3028,16 @@ static irqreturn_t bmp085_eoc_irq(int irq, void *d)
return IRQ_HANDLED;
}
-static int bmp085_fetch_eoc_irq(struct device *dev,
- const char *name,
- int irq,
- struct bmp280_data *data)
+static int bmp085_trigger_probe(struct iio_dev *indio_dev)
{
+ struct bmp280_data *data = iio_priv(indio_dev);
+ struct device *dev = data->dev;
unsigned long irq_trig;
- int ret;
+ int ret, irq;
+
+ irq = fwnode_irq_get(dev_fwnode(dev), 0);
+ if (irq < 0)
+ return dev_err_probe(dev, irq, "No interrupt found.\n");
irq_trig = irq_get_trigger_type(irq);
if (irq_trig != IRQF_TRIGGER_RISING) {
@@ -3044,13 +3047,8 @@ static int bmp085_fetch_eoc_irq(struct device *dev,
init_completion(&data->done);
- ret = devm_request_threaded_irq(dev,
- irq,
- bmp085_eoc_irq,
- NULL,
- irq_trig,
- name,
- data);
+ ret = devm_request_irq(dev, irq, bmp085_eoc_irq, irq_trig,
+ indio_dev->name, data);
if (ret) {
/* Bail out without IRQ but keep the driver in place */
dev_err(dev, "unable to request DRDY IRQ\n");
@@ -3058,9 +3056,48 @@ static int bmp085_fetch_eoc_irq(struct device *dev,
}
data->use_eoc = true;
+
return 0;
}
+/* Identical to bmp180_chip_info + bmp085_trigger_probe */
+const struct bmp280_chip_info bmp085_chip_info = {
+ .id_reg = BMP280_REG_ID,
+ .chip_id = bmp180_chip_ids,
+ .num_chip_id = ARRAY_SIZE(bmp180_chip_ids),
+ .regmap_config = &bmp180_regmap_config,
+ .start_up_time = 2000,
+ .channels = bmp280_channels,
+ .num_channels = ARRAY_SIZE(bmp280_channels),
+ .avail_scan_masks = bmp280_avail_scan_masks,
+
+ .oversampling_temp_avail = bmp180_oversampling_temp_avail,
+ .num_oversampling_temp_avail =
+ ARRAY_SIZE(bmp180_oversampling_temp_avail),
+ .oversampling_temp_default = 0,
+
+ .oversampling_press_avail = bmp180_oversampling_press_avail,
+ .num_oversampling_press_avail =
+ ARRAY_SIZE(bmp180_oversampling_press_avail),
+ .oversampling_press_default = BMP180_MEAS_PRESS_8X,
+
+ .temp_coeffs = bmp180_temp_coeffs,
+ .temp_coeffs_type = IIO_VAL_FRACTIONAL,
+ .press_coeffs = bmp180_press_coeffs,
+ .press_coeffs_type = IIO_VAL_FRACTIONAL,
+
+ .chip_config = bmp180_chip_config,
+ .read_temp = bmp180_read_temp,
+ .read_press = bmp180_read_press,
+ .read_calib = bmp180_read_calib,
+ .set_mode = bmp180_set_mode,
+ .wait_conv = bmp180_wait_conv,
+
+ .trigger_probe = bmp085_trigger_probe,
+ .trigger_handler = bmp180_trigger_handler,
+};
+EXPORT_SYMBOL_NS(bmp085_chip_info, IIO_BMP280);
+
static int bmp280_buffer_preenable(struct iio_dev *indio_dev)
{
struct bmp280_data *data = iio_priv(indio_dev);
@@ -3232,8 +3269,6 @@ int bmp280_common_probe(struct device *dev,
* so we look for an IRQ if we have that.
*/
if (irq > 0) {
- if (chip_id == BMP180_CHIP_ID)
- ret = bmp085_fetch_eoc_irq(dev, name, irq, data);
if (data->chip_info->trigger_probe)
ret = data->chip_info->trigger_probe(indio_dev);
if (ret)
diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c
index 5c3a63b4327c..2f7b25984c7b 100644
--- a/drivers/iio/pressure/bmp280-i2c.c
+++ b/drivers/iio/pressure/bmp280-i2c.c
@@ -27,7 +27,7 @@ static int bmp280_i2c_probe(struct i2c_client *client)
}
static const struct of_device_id bmp280_of_i2c_match[] = {
- { .compatible = "bosch,bmp085", .data = &bmp180_chip_info },
+ { .compatible = "bosch,bmp085", .data = &bmp085_chip_info },
{ .compatible = "bosch,bmp180", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp280", .data = &bmp280_chip_info },
{ .compatible = "bosch,bme280", .data = &bme280_chip_info },
@@ -38,7 +38,7 @@ static const struct of_device_id bmp280_of_i2c_match[] = {
MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match);
static const struct i2c_device_id bmp280_i2c_id[] = {
- {"bmp085", (kernel_ulong_t)&bmp180_chip_info },
+ {"bmp085", (kernel_ulong_t)&bmp085_chip_info },
{"bmp180", (kernel_ulong_t)&bmp180_chip_info },
{"bmp280", (kernel_ulong_t)&bmp280_chip_info },
{"bme280", (kernel_ulong_t)&bme280_chip_info },
diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c
index d18549d9bb64..49aa8c2cd85b 100644
--- a/drivers/iio/pressure/bmp280-spi.c
+++ b/drivers/iio/pressure/bmp280-spi.c
@@ -114,7 +114,7 @@ static int bmp280_spi_probe(struct spi_device *spi)
}
static const struct of_device_id bmp280_of_spi_match[] = {
- { .compatible = "bosch,bmp085", .data = &bmp180_chip_info },
+ { .compatible = "bosch,bmp085", .data = &bmp085_chip_info },
{ .compatible = "bosch,bmp180", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp181", .data = &bmp180_chip_info },
{ .compatible = "bosch,bmp280", .data = &bmp280_chip_info },
@@ -126,7 +126,7 @@ static const struct of_device_id bmp280_of_spi_match[] = {
MODULE_DEVICE_TABLE(of, bmp280_of_spi_match);
static const struct spi_device_id bmp280_spi_id[] = {
- { "bmp085", (kernel_ulong_t)&bmp180_chip_info },
+ { "bmp085", (kernel_ulong_t)&bmp085_chip_info },
{ "bmp180", (kernel_ulong_t)&bmp180_chip_info },
{ "bmp181", (kernel_ulong_t)&bmp180_chip_info },
{ "bmp280", (kernel_ulong_t)&bmp280_chip_info },
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 12f6e90b3728..2df1175b6b85 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -534,6 +534,7 @@ struct bmp280_chip_info {
};
/* Chip infos for each variant */
+extern const struct bmp280_chip_info bmp085_chip_info;
extern const struct bmp280_chip_info bmp180_chip_info;
extern const struct bmp280_chip_info bmp280_chip_info;
extern const struct bmp280_chip_info bme280_chip_info;
--
2.43.0
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
` (3 preceding siblings ...)
2024-10-17 23:30 ` [PATCH v9 4/4] iio: pressure: bmp280: Move bmp085 interrupt to new configuration Vasileios Amoiridis
@ 2024-10-19 13:55 ` Jonathan Cameron
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
6 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2024-10-19 13:55 UTC (permalink / raw)
To: Vasileios Amoiridis
Cc: lars, robh, krzk+dt, conor+dt, andriy.shevchenko, ang.iglesiasg,
ajarizzo, biju.das.jz, linus.walleij, semen.protsenko, 579lpy, ak,
linux-iio, devicetree, linux-kernel
On Fri, 18 Oct 2024 01:30:18 +0200
Vasileios Amoiridis <vassilisamir@gmail.com> wrote:
> Changes in v9:
>
> PATCH 1/4:
> - fixed warning of uninitialized variable that was generated by
> the kernel test robot in v8.
>
> PATCH 4/4:
> - Remove extra lock and unneeded reenable function since the irq is
> being reset on the first read in the irq handler.
Applied to the togreg branch of iio.git and pushed out as testing for the normal reasons.
Note I'll probably rebase that tree in a few days to pick up some precusor fixes needed
for another series.
Jonathan
>
> ---
> v8: https://lore.kernel.org/linux-iio/20241007194945.66192-1-vassilisamir@gmail.com
> v7: https://lore.kernel.org/linux-iio/20240914002900.45158-1-vassilisamir@gmail.com
> v6: https://lore.kernel.org/linux-iio/20240912233234.45519-1-vassilisamir@gmail.com
> v5: https://lore.kernel.org/linux-iio/20240902184222.24874-1-vassilisamir@gmail.com
> v4: https://lore.kernel.org/linux-iio/20240828205128.92145-1-vassilisamir@gmail.com
> v3: https://lore.kernel.org/linux-iio/20240823181714.64545-1-vassilisamir@gmail.com
> v2: https://lore.kernel.org/linux-iio/20240725231039.614536-1-vassilisamir@gmail.com
> v1: https://lore.kernel.org/linux-iio/20240711211558.106327-1-vassilisamir@gmail.com
>
> Vasileios Amoiridis (4):
> iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
> dt-bindings: iio: pressure: bmp085: Add interrupts for BMP3xx and
> BMP5xx devices
> iio: pressure: bmp280: Add data ready trigger support
> iio: pressure: bmp280: Move bmp085 interrupt to new configuration
>
> .../bindings/iio/pressure/bmp085.yaml | 22 +-
> drivers/iio/pressure/bmp280-core.c | 536 ++++++++++++++++--
> drivers/iio/pressure/bmp280-i2c.c | 4 +-
> drivers/iio/pressure/bmp280-spi.c | 4 +-
> drivers/iio/pressure/bmp280.h | 43 ++
> 5 files changed, 568 insertions(+), 41 deletions(-)
>
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2024-10-17 23:30 ` [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures Vasileios Amoiridis
@ 2025-06-28 18:45 ` ASSI
2025-06-28 20:57 ` David Lechner
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-06-28 18:45 UTC (permalink / raw)
To: linux-iio
Vasileios Amoiridis writes:
> The idea is that the sensor is by default in sleep mode, wakes up in
> forced mode when a oneshot capture is requested, or in normal mode
> when the buffer is enabled. The difference lays in the fact that in
> forced mode, the sensor does only one conversion and goes back to sleep
> while in normal mode, the sensor does continuous measurements with the
> frequency that was set in the ODR registers.
>
> The bmpX_chip_config() functions which are responsible for applying
> the requested configuration to the sensor, are modified accordingly
> in order to set the sensor by default in sleep mode.
Since this change went into 6.13, I've been unable to update the kernel
since it breaks usermode quite badly for me. I am using sysfs to read a
BME280 sensor every second (oversampling is set to 1, so there should be
no trouble at all to read at that rate) and most of the time the
measurement doesn't complete and I get back an error message instead of
the expected reading. The journal is full of these:
Jun 28 08:19:16 Otto kernel: bmp280 1-0076: Measurement cycle didn't complete.
Jun 28 08:19:16 Otto kernel: bmp280 1-0076: Measurement cycle didn't complete.
Jun 28 08:19:16 Otto kernel: bmp280 1-0076: Measurement cycle didn't complete.
The exact same thing happens if I stop the process that's reading the
sensor every second and do a manual read at much longer intervals, so
it's indeed not the read rate, but rather that the driver apparently
doesn't wait long enough for the measurement to complete. There is an
indication that the wait time is just slightly too short as I have a
somewhat higher success rate at reading every second when the load is
higher. Addtionally the read time for all three values from the sensor
went from ~7ms to ~28ms with much stronger tailing to longer read times
than before. This sensor is in daisy-chain with a DS3231M RTC and hangs
off the DDC of the unsused VGA port provided by an Intel IGP.
I've not found a way to switch the operations mode via sysfs and/or
enable the ring buffer, which may or may not solve the problem depending
on which mode is used when the trigger arrives. That's mainly because I
couldn't find a complete example of how to use this facility and I've
likely done some of the steps in the wrong order or missed one. I've
enabled the scan elements, but trying to enable the buffer tells me
"write error: Invalid argument". For starters, the system I'm on
(openSUSE Tumbleweed) doesn't seem to have IIO trigger support enabled
via either configfs or sysfs. But in any case I think oneshot capturing
from userland should still work, I just haven't found out how.
So is there some description of how to get the sysfs functionality as
before and/or switch the operations mode to avoid this failure? The
easiest would be if the BME280_MEAS_OFFSET value was configurable, but
it's a #DEFINE at the moment.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2025-06-28 18:45 ` ASSI
@ 2025-06-28 20:57 ` David Lechner
2025-06-29 7:43 ` ASSI
2025-07-11 19:17 ` ASSI
0 siblings, 2 replies; 71+ messages in thread
From: David Lechner @ 2025-06-28 20:57 UTC (permalink / raw)
To: ASSI, linux-iio, Vasileios Amoiridis
On 6/28/25 1:45 PM, ASSI wrote:
> Vasileios Amoiridis writes:
>> The idea is that the sensor is by default in sleep mode, wakes up in
>> forced mode when a oneshot capture is requested, or in normal mode
>> when the buffer is enabled. The difference lays in the fact that in
>> forced mode, the sensor does only one conversion and goes back to sleep
>> while in normal mode, the sensor does continuous measurements with the
>> frequency that was set in the ODR registers.
>>
>> The bmpX_chip_config() functions which are responsible for applying
>> the requested configuration to the sensor, are modified accordingly
>> in order to set the sensor by default in sleep mode.
>
> Since this change went into 6.13, I've been unable to update the kernel
> since it breaks usermode quite badly for me. I am using sysfs to read a
> BME280 sensor every second (oversampling is set to 1, so there should be
> no trouble at all to read at that rate) and most of the time the
> measurement doesn't complete and I get back an error message instead of
> the expected reading. The journal is full of these:
>
> Jun 28 08:19:16 Otto kernel: bmp280 1-0076: Measurement cycle didn't complete.
> Jun 28 08:19:16 Otto kernel: bmp280 1-0076: Measurement cycle didn't complete.
> Jun 28 08:19:16 Otto kernel: bmp280 1-0076: Measurement cycle didn't complete.
>
> The exact same thing happens if I stop the process that's reading the
> sensor every second and do a manual read at much longer intervals, so
> it's indeed not the read rate, but rather that the driver apparently
> doesn't wait long enough for the measurement to complete. There is an
> indication that the wait time is just slightly too short as I have a
> somewhat higher success rate at reading every second when the load is
> higher. Addtionally the read time for all three values from the sensor
> went from ~7ms to ~28ms with much stronger tailing to longer read times
> than before. This sensor is in daisy-chain with a DS3231M RTC and hangs
> off the DDC of the unsused VGA port provided by an Intel IGP.
>
> I've not found a way to switch the operations mode via sysfs and/or
> enable the ring buffer, which may or may not solve the problem depending
> on which mode is used when the trigger arrives. That's mainly because I
> couldn't find a complete example of how to use this facility and I've
> likely done some of the steps in the wrong order or missed one. I've
> enabled the scan elements, but trying to enable the buffer tells me
> "write error: Invalid argument". For starters, the system I'm on
> (openSUSE Tumbleweed) doesn't seem to have IIO trigger support enabled
> via either configfs or sysfs. But in any case I think oneshot capturing
> from userland should still work, I just haven't found out how.
>
> So is there some description of how to get the sysfs functionality as
> before and/or switch the operations mode to avoid this failure? The
> easiest would be if the BME280_MEAS_OFFSET value was configurable, but
> it's a #DEFINE at the moment.
>
>
> Regards,
> Achim.
If this change broke your code, we need to fix it in the kernel, so
thanks for reporting the regression.
It looks like the wait time calculations in bmp280_wait_conv() don't
match up with the datasheet [1] that I found.
[1]: https://cdn-shop.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf
There, table 13 says that if pressure and temperature oversampling
are bot set to x1, then it could take up to 6.4 ms to complete the
measurement.
However, in the code, we have:
```
#define BMP280_MEAS_OFFSET 1250
#define BMP280_MEAS_DUR 2300
#define BMP280_PRESS_HUMID_MEAS_OFFSET 575
```
and
```
/* Check if we are using a BME280 device */
if (data->oversampling_humid)
meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
else
meas_time_us = 0;
/* Pressure measurement time */
meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_press) * BMP280_MEAS_DUR;
/* Temperature measurement time */
meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
/* Waiting time according to the BM(P/E)2 Sensor API */
fsleep(meas_time_us);
```
Assuming BIT(*oversampling*) is 1 for x1 oversampling, we get
meas_time_us = (0) + (575 + 1 * 2300) + (1 * 2300) = 5175
^ ^ ^
| | |
| | temperature
| pressure
humidity
5175 microseconds is less than the 6.4 milliseconds max time, so
that would explain the error that is seen since the error is
triggered by the status bit that says the chip is still busy taking
the measurement.
BMP280_MEAS_OFFSET is unused in the code. But 6400 - 5175 is 1225
which is very close to 1250. So I think the intention was to include
that it the calculation like this:
---
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 74505c9ec1a0..50c869e3d5c9 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1042,14 +1042,13 @@ static int bmp280_wait_conv(struct bmp280_data *data)
unsigned int reg, meas_time_us;
int ret;
+ meas_time_us = BMP280_MEAS_OFFSET;
+
/* Check if we are using a BME280 device */
if (data->oversampling_humid)
- meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
- else
- meas_time_us = 0;
-
/* Pressure measurement time */
meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_press) * BMP280_MEAS_DUR;
---
Hopefully you can compile your own kernel and test this. If that fixes it
we can turn it into a proper patch.
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2025-06-28 20:57 ` David Lechner
@ 2025-06-29 7:43 ` ASSI
2025-07-11 19:17 ` ASSI
1 sibling, 0 replies; 71+ messages in thread
From: ASSI @ 2025-06-29 7:43 UTC (permalink / raw)
To: linux-iio
David Lechner writes:
> It looks like the wait time calculations in bmp280_wait_conv() don't
> match up with the datasheet [1] that I found.
>
> [1]: https://cdn-shop.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf
The canonical location for these is
https://www.bosch-sensortec.com/products/downloads/ and there is a later
version available (no changes w.r.t. the information discussed here,
though).
> There, table 13 says that if pressure and temperature oversampling
> are bot set to x1, then it could take up to 6.4 ms to complete the
> measurement.
The BME280 has a slightly different specification that matches up with
the numbers in the header file…
> However, in the code, we have:
>
> ```
> #define BMP280_MEAS_OFFSET 1250
> #define BMP280_MEAS_DUR 2300
> #define BMP280_PRESS_HUMID_MEAS_OFFSET 575
> ```
… with the proviso that BMP280_MEAS_OFFSET is applied to each
measurement independent of any other settings and
BMP280_PRESS_HUMID_MEAS_OFFSET to the humidity and pressure measurement
if these are activated.
> and
>
> ```
> /* Check if we are using a BME280 device */
> if (data->oversampling_humid)
> meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
> BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
>
> else
> meas_time_us = 0;
>
> /* Pressure measurement time */
> meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
> BIT(data->oversampling_press) * BMP280_MEAS_DUR;
>
> /* Temperature measurement time */
> meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
>
> /* Waiting time according to the BM(P/E)2 Sensor API */
> fsleep(meas_time_us);
> ```
>
> Assuming BIT(*oversampling*) is 1 for x1 oversampling, we get
>
> meas_time_us = (0) + (575 + 1 * 2300) + (1 * 2300) = 5175
> ^ ^ ^
> | | |
> | | temperature
> | pressure
> humidity
>
> 5175 microseconds is less than the 6.4 milliseconds max time, so
> that would explain the error that is seen since the error is
> triggered by the status bit that says the chip is still busy taking
> the measurement.
>
> BMP280_MEAS_OFFSET is unused in the code. But 6400 - 5175 is 1225
> which is very close to 1250. So I think the intention was to include
> that it the calculation like this:
Yes, I think that's where the trouble comes from.
> ---
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 74505c9ec1a0..50c869e3d5c9 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -1042,14 +1042,13 @@ static int bmp280_wait_conv(struct bmp280_data *data)
> unsigned int reg, meas_time_us;
> int ret;
>
> + meas_time_us = BMP280_MEAS_OFFSET;
> +
> /* Check if we are using a BME280 device */
> if (data->oversampling_humid)
> - meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
> + meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
> BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
>
> - else
> - meas_time_us = 0;
> -
> /* Pressure measurement time */
> meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
> BIT(data->oversampling_press) * BMP280_MEAS_DUR;
> ---
That looks correct to me. So in my case (all three measurements
performed) the measurement should take 8ms nominal / 9.3ms maximum, but
the current code waits just 8.05ms (which is still slightly above
nominal, but apparently not sufficiently long for my sensor).
Another area of concern is that now that each sysfs read triggers
another forced measurement instead of just looking at the values from
the last one that was produced automatically, should the oversampling
ratio of the unused measurements (as specified by chan->type) for that
read not be set to zero temporarily so that the measurements whose
values you don't get the result of are not performed? That would still
be at least 2.5ms or 12.5ms slower (2×1.25ms + 2×5ms entering sleep mode
and 2.3ms more for each increment of OSR settings) than before depending
on whether the device enters sleep mode inbetween readings (I haven't
figured that one out from the code, but my timing results suggest it
does) in normal mode when reading all three values in succession (which
suggests that there should probably be a separate sysfs interface for
doing a complete read), but not quite as much as currently seen.
Also, instead of waiting the maximum time (typical +15%) unconditionally
it might be preferrable to initially wait just the typical time followed
by a wait of (meas_time_us>>3) and then (meas_time_us>>5) if the busy
flag is still on before returning EBUSY. That of course depends on how
large the overhead is of that wait plus the register read, but it
probably still is a net win even if the actual sensor always requires
two reads.
> Hopefully you can compile your own kernel and test this. If that fixes it
> we can turn it into a proper patch.
I used to compile the driver myself, but Tumbleweed since switched to a
signed kernel, so I have to figure out how to load an unsigned driver and
then get up to speed again on how to compile and install it.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2025-06-28 20:57 ` David Lechner
2025-06-29 7:43 ` ASSI
@ 2025-07-11 19:17 ` ASSI
2025-07-12 14:49 ` ASSI
1 sibling, 1 reply; 71+ messages in thread
From: ASSI @ 2025-07-11 19:17 UTC (permalink / raw)
To: linux-iio
David Lechner writes:
> Hopefully you can compile your own kernel and test this. If that fixes it
> we can turn it into a proper patch.
I've out-of-tree re-compiled the module with the patch applied, booted
into the kernel with secure boot / validation switched off, removed the
compiled-in module and did an insmod for the patched one. It works and
I can read all values again most of the time at oversampling=1 and
consistently at oversampling=2 for all channels.
I'll try my suggestion of a tapered wait later, perhaps over the
weekend, now that I don't need to reboot to play around with the module
code.
Setting oversampling=1 on all three channels gets me a fuil acquisition
at ~33ms now (was ~28ms with the too short wait time), oversampling=2 is
at ~64ms. I'll need to figure out how to enable and use the triggered
buffer to get that back to more reasonable times.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2025-07-11 19:17 ` ASSI
@ 2025-07-12 14:49 ` ASSI
2025-07-21 19:15 ` ASSI
2025-07-26 18:34 ` ASSI
0 siblings, 2 replies; 71+ messages in thread
From: ASSI @ 2025-07-12 14:49 UTC (permalink / raw)
To: linux-iio
ASSI writes:
> I'll try my suggestion of a tapered wait later, perhaps over the
> weekend, now that I don't need to reboot to play around with the module
> code.
That works and indeed even slightly reduces the acquisition times with
my slow sensor specimen, so it does not always need the maximum time
(but very close). I've also implemented switching off unused channels
during the read through the simple sysfs interface, which does not
support to read all channels in a single measurement. The temperature
reading is required for both humidity and pressure compensation so it
can only be set to oversampling=1 but not switched off. For
oversampling=1 on all channels unfortunately the overhead of doing this
almost compensates for the savings made in measurement time, but any
other setting will be a net win:
| oversampling | max/full | max/skip | time/full | time/skip |
| | [ms] | [ms] | [ms] | [ms] |
|--------------+----------+----------+-----------+-----------|
| 16 | 339 | 120 | 315 | 127 |
| 8 | 174 | 65 | 166 | 76 |
| 4 | 90 | 38 | 94 | 53 |
| 2 | 49 | 24 | 59 | 41 |
| 1 | 28 | 17 | 36 | 33 |
I suspect the overhead at lower oversampling factors is significantly
lower for SPI interfaced sensors that I cannot currently test. I've
left a constant in the code to control the skip threshold if anybody
wants to play with it, but the final solution will probably be to either
skip always or make it even more configurable by exposing this facility
via sysfs. Getting the original channel config restored on all exit
paths is a bit stilted and calls for a bit of refactoring (or even a
goto) but for now this should suffice. Patch:
--8<---------------cut here---------------start------------->8---
--- /usr/src/linux-6.15.5-1//drivers/iio/pressure/bmp280-core.c
+++ bmp280-6.15.5-1/bmp280-core.c
@@ -618,19 +618,77 @@
struct bmp280_data *data = iio_priv(indio_dev);
int chan_value;
int ret;
+ int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
+ int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
+ int switch_off, switch_threshold = -1;
guard(mutex)(&data->lock);
+ prev_oversampling_humid = temp_oversampling_humid = data->oversampling_humid;
+ prev_oversampling_press = temp_oversampling_press = data->oversampling_press;
+ prev_oversampling_temp = temp_oversampling_temp = data->oversampling_temp;
+
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
+ /* switch off unused channels */
+ switch_off = 0;
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) | (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (switch_off) {
+ data->oversampling_humid = temp_oversampling_humid;
+ data->oversampling_press = temp_oversampling_press;
+ data->oversampling_temp = temp_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ return ret;
+ }
+ }
+
ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
+ if (ret) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
return ret;
+ }
ret = data->chip_info->wait_conv(data);
if (ret)
return ret;
+ /* restore channel configuration */
+ if (switch_off) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret) {
+ return ret;
+ }
+ }
+
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
ret = data->chip_info->read_humid(data, &chan_value);
@@ -660,13 +718,60 @@
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- return ret;
+ /* switch off unused channels */
+ switch_off = 0;
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) | (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (switch_off) {
+ data->oversampling_humid = temp_oversampling_humid;
+ data->oversampling_press = temp_oversampling_press;
+ data->oversampling_temp = temp_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ return ret;
+ }
+ }
ret = data->chip_info->wait_conv(data);
- if (ret)
+ if (ret) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
return ret;
+ }
+
+ /* restore channel configuration */
+ if (switch_off) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret) {
+ return ret;
+ }
+ }
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
@@ -1040,15 +1145,15 @@
{
unsigned int reg, meas_time_us;
int ret;
+ int meas_cycles = 4;
+
+ meas_time_us = BMP280_MEAS_OFFSET;
/* Check if we are using a BME280 device */
if (data->oversampling_humid)
- meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
- else
- meas_time_us = 0;
-
/* Pressure measurement time */
meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_press) * BMP280_MEAS_DUR;
@@ -1056,14 +1161,18 @@
/* Temperature measurement time */
meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
- /* Waiting time according to the BM(P/E)2 Sensor API */
- fsleep(meas_time_us);
+ do {
+ /* Waiting time according to the BM(P/E)2 Sensor API */
+ fsleep(meas_time_us);
+
+ ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
+ if (ret) {
+ dev_err(data->dev, "failed to read status register.\n");
+ return ret;
+ }
- ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
- if (ret) {
- dev_err(data->dev, "failed to read status register.\n");
- return ret;
- }
+ meas_time_us >>= 3;
+ } while ((reg & BMP280_REG_STATUS_MEAS_BIT) && --meas_cycles);
if (reg & BMP280_REG_STATUS_MEAS_BIT) {
dev_err(data->dev, "Measurement cycle didn't complete.\n");
--- /usr/src/linux-6.15.5-1//drivers/iio/pressure/bmp280.0
+++ bmp280-6.15.5-1/bmp280.h
@@ -269,9 +269,9 @@
#define BMP280_MODE_FORCED 1
#define BMP280_MODE_NORMAL 3
-#define BMP280_MEAS_OFFSET 1250
-#define BMP280_MEAS_DUR 2300
-#define BMP280_PRESS_HUMID_MEAS_OFFSET 575
+#define BMP280_MEAS_OFFSET 1095 /* ceil(1250/(1+2^-3+2^-6+2^-9) */
+#define BMP280_MEAS_DUR 2013 /* ceil(2300/(1+2^-3+2^-6+2^-9) */
+#define BMP280_PRESS_HUMID_MEAS_OFFSET 504 /* ceil( 575/(1+2^-3+2^-6+2^-9) */
/* BME280 specific registers */
#define BME280_REG_HUMIDITY_LSB 0xFE
--8<---------------cut here---------------end--------------->8---
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
Factory and User Sound Singles for Waldorf Q+, Q and microQ:
http://Synth.Stromeko.net/Downloads.html#WaldorfSounds
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2025-07-12 14:49 ` ASSI
@ 2025-07-21 19:15 ` ASSI
2025-07-26 18:34 ` ASSI
1 sibling, 0 replies; 71+ messages in thread
From: ASSI @ 2025-07-21 19:15 UTC (permalink / raw)
To: linux-iio
ASSI writes:
[…]
I've been running with this patch for two weeks now and even updated to
another kernel. Unfortunately Tumbleweed does not provide the sysfs
trigger device, but I could enable a HRT trigger device via configfs. I
did not get this to work however, for stzartes I have no diea if I need
to enable both the buffer and buffer0 provided via sysfs:
--8<---------------cut here---------------start------------->8---
/sys/bus/iio/devices/iio:device0/buffer:
data_available direction enable length watermark
/sys/bus/iio/devices/iio:device0/buffer0:
data_available enable in_humidityrelative_index in_pressure_en in_pressure_type in_temp_index in_timestamp_en in_timestamp_type watermark
direction in_humidityrelative_en in_humidityrelative_type in_pressure_index in_temp_en in_temp_type in_timestamp_index length
--8<---------------cut here---------------end--------------->8---
After setting up the trigger and enabling the channels in scan_elements
I ended up enabling both, which had the effect that the forced readings
via the processed endpoints stopped working for pressure and humidity
(which is probably because the channel config is left in that state
somehow), but no values were ever appearing at the /dev/iio0 endpoint
that got created. I also didn't manage to disable the buffers again and
got an EBUSY instead. I needed to remove the driver and re-insert it to
get out of this mode. Anyway it seems I should not mix triggered and
forced operation anyway as it seems that triggered operation requires
the device to stay in normal mode.
I have one other idea to get back at the short(er) aquisition times I
had previously: since triggered and forced operation can't be mixed, it
would be possible to use the timestamp fields to record the last
aquisition, always aquire all channels and only actually force a new
measurement if some time has elapsed after that, like another full
measurement cycle time based on the current oversampling configuration.
THe other option would be to actually enable the sampling frequency
parameter that must be converted into a t_standby setting for the BMx280
devices, as hinted at in the header file, but not actually implemented
yet (or mis-use that field directly for the standby time).
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2025-07-12 14:49 ` ASSI
2025-07-21 19:15 ` ASSI
@ 2025-07-26 18:34 ` ASSI
2025-07-27 19:08 ` ASSI
1 sibling, 1 reply; 71+ messages in thread
From: ASSI @ 2025-07-26 18:34 UTC (permalink / raw)
To: linux-iio
ASSI writes:
> That works and indeed even slightly reduces the acquisition times with
> my slow sensor specimen, so it does not always need the maximum time
> (but very close). I've also implemented switching off unused channels
> during the read through the simple sysfs interface, which does not
> support to read all channels in a single measurement. The temperature
> reading is required for both humidity and pressure compensation so it
> can only be set to oversampling=1 but not switched off. For
> oversampling=1 on all channels unfortunately the overhead of doing this
> almost compensates for the savings made in measurement time, but any
> other setting will be a net win:
>
> | oversampling | max/full | max/skip | time/full | time/skip |
> | | [ms] | [ms] | [ms] | [ms] |
> |--------------+----------+----------+-----------+-----------|
> | 16 | 339 | 120 | 315 | 127 |
> | 8 | 174 | 65 | 166 | 76 |
> | 4 | 90 | 38 | 94 | 53 |
> | 2 | 49 | 24 | 59 | 41 |
> | 1 | 28 | 17 | 36 | 33 |
>
> I suspect the overhead at lower oversampling factors is significantly
> lower for SPI interfaced sensors that I cannot currently test. I've
> left a constant in the code to control the skip threshold if anybody
> wants to play with it, but the final solution will probably be to either
> skip always or make it even more configurable by exposing this facility
> via sysfs. Getting the original channel config restored on all exit
> paths is a bit stilted and calls for a bit of refactoring (or even a
> goto) but for now this should suffice. Patch:
As the acquisition times were still more than four times higher than
before, I've implemented the sampling_frequency endpoint for the BMx280
devices and only use the forced measurement mode when it is set to zero
(which is the default to keep the userspace behaviour identical to the
previous version). That gets me back to ~9ms read of all three channels
since I no longer need to wait for the measurements, almost like it was
before the change to forced mode. The extra 2ms probably come from the
unconditional set_mode call, which I inserted since otherwise the chip
would sometimes get stuck in the wrong mode and not do any measurements
until I wrote to sampling_frequency again.
Since the BMx280 don't actually have a frequency setting and need to set
standby times between measurements instead (for which I haven't found an
easily usable parameter in the IIO framework), the permissible frequency
settings are calculated for the lowest possible measurement time
(oversampling=1 for all channels). The actual frequencies could be
caclulated from the current settings and made available on read, but I
haven't implemented that yet -- at the moment you'll get back the value
you have set independent of the actual oversampling ratios.
Another issue I found while perusing the sources is that the filter has
a fixed setting of 4 for these chips, which might be made changeable by
using the filter_coefficient. Not looked at what that entails, though.
I've got a sparse checkout of the kernel repo now, so if you think that
this may be acceptable I can work on getting that into the form you are
expecting (either a single commit or a series) and iron out any kinks
you see.
--8<---------------cut here---------------start------------->8---
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index f37f20776c89..79bd2bba22ca 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -64,7 +64,32 @@
*/
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
+enum bmp280_odr {
+ BMP280_ODR_0HZ, /* MODE_FORCED */
+ BMP280_ODR_110HZ, /* t_sb = 0.5ms */
+ BMP280_ODR_14HZ, /* t_sb = 62.5ms */
+ BMP280_ODR_7_5HZ, /* t_sb = 125ms */
+ BMP280_ODR_3_85HZ, /* t_sb = 250ms */
+ BMP280_ODR_1_96HZ, /* t_sb = 500ms */
+ BMP280_ODR_0_99HZ, /* t_sb = 1000ms */
+ BMP280_ODR_0_49HZ, /* t_sb = 2000ms */
+ BMP280_ODR_0_24HZ, /* t_sb = 4000ms */
+};
+
+enum bme280_odr {
+ BME280_ODR_0HZ, /* MODE_FORCED */
+ BME280_ODR_110HZ, /* t_sb = 0.5ms */
+ BME280_ODR_14HZ, /* t_sb = 62.5ms */
+ BME280_ODR_7_5HZ, /* t_sb = 125ms */
+ BME280_ODR_3_85HZ, /* t_sb = 250ms */
+ BME280_ODR_1_96HZ, /* t_sb = 500ms */
+ BME280_ODR_0_99HZ, /* t_sb = 1000ms */
+ BME280_ODR_51HZ, /* t_sb = 10ms */
+ BME280_ODR_34HZ, /* t_sb = 20ms */
+};
+
enum bmp380_odr {
+ BMP380_ODR_0HZ, /* MODE_FORCED */
BMP380_ODR_200HZ,
BMP380_ODR_100HZ,
BMP380_ODR_50HZ,
@@ -86,6 +111,7 @@ enum bmp380_odr {
};
enum bmp580_odr {
+ BMP580_ODR_0HZ, /* MODE_FORCED */
BMP580_ODR_240HZ,
BMP580_ODR_218HZ,
BMP580_ODR_199HZ,
@@ -159,6 +185,7 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -174,6 +201,7 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -193,6 +221,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -208,6 +237,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -223,6 +253,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 2,
.scan_type = {
.sign = 'u',
@@ -619,18 +650,65 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
struct bmp280_data *data = iio_priv(indio_dev);
int chan_value;
int ret;
+ int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
+ int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
+ int switch_off, switch_threshold = -1;
guard(mutex)(&data->lock);
+ prev_oversampling_humid = temp_oversampling_humid = data->oversampling_humid;
+ prev_oversampling_press = temp_oversampling_press = data->oversampling_press;
+ prev_oversampling_temp = temp_oversampling_temp = data->oversampling_temp;
+
+ data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
+
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- return ret;
+ switch_off = 0;
+ if (data->op_mode == BMP280_FORCED) {
+ /* switch off unused channels */
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) | (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ if (switch_off) {
+ data->oversampling_humid = temp_oversampling_humid;
+ data->oversampling_press = temp_oversampling_press;
+ data->oversampling_temp = temp_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret)
+ goto restore;
+ }
ret = data->chip_info->wait_conv(data);
if (ret)
- return ret;
+ goto restore;
+
+ if (switch_off) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ if (ret) {
+ return ret;
+ }
+ }
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
@@ -661,13 +739,51 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- return ret;
+ switch_off = 0;
+ if (data->op_mode == BMP280_FORCED) {
+ /* MODE_FORCED, switch off unused channels */
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) | (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ if (switch_off) {
+ data->oversampling_humid = temp_oversampling_humid;
+ data->oversampling_press = temp_oversampling_press;
+ data->oversampling_temp = temp_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret)
+ goto restore;
+ }
ret = data->chip_info->wait_conv(data);
if (ret)
- return ret;
+ goto restore;
+
+ if (switch_off) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ if (ret) {
+ return ret;
+ }
+ }
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
@@ -741,6 +857,15 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
+ restore:
+ if (switch_off) {
+ /* restore channel configuration */
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ }
+ return ret;
}
static int bmp280_read_raw(struct iio_dev *indio_dev,
@@ -852,6 +977,10 @@ static int bmp280_write_sampling_frequency(struct bmp280_data *data,
data->chip_info->chip_config(data);
return ret;
}
+ ret = data->chip_info->set_mode(data, (i ? BMP280_NORMAL : BMP280_FORCED));
+ if (ret)
+ return ret;
+
return 0;
}
}
@@ -988,6 +1117,30 @@ static const unsigned long bme280_avail_scan_masks[] = {
0
};
+static const int bmp280_odr_table[][2] = {
+ [BMP280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
+ [BMP280_ODR_110HZ] = {110, 0},
+ [BMP280_ODR_14HZ] = {14, 0},
+ [BMP280_ODR_7_5HZ] = {7, 500000},
+ [BMP280_ODR_3_85HZ] = {3, 850000},
+ [BMP280_ODR_1_96HZ] = {1, 960000},
+ [BMP280_ODR_0_99HZ] = {0, 990000},
+ [BMP280_ODR_0_49HZ] = {0, 490000},
+ [BMP280_ODR_0_24HZ] = {0, 240000},
+};
+
+static const int bme280_odr_table[][2] = {
+ [BME280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
+ [BME280_ODR_110HZ] = {110, 0},
+ [BME280_ODR_14HZ] = {14, 0},
+ [BME280_ODR_7_5HZ] = {7, 500000},
+ [BME280_ODR_3_85HZ] = {3, 850000},
+ [BME280_ODR_1_96HZ] = {1, 960000},
+ [BME280_ODR_0_99HZ] = {0, 990000},
+ [BME280_ODR_51HZ] = {51, 0},
+ [BME280_ODR_34HZ] = {34, 0},
+};
+
static int bmp280_preinit(struct bmp280_data *data)
{
struct device *dev = data->dev;
@@ -1037,19 +1190,15 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
return 0;
}
-static int bmp280_wait_conv(struct bmp280_data *data)
+static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
{
- unsigned int reg, meas_time_us;
- int ret;
+ unsigned int meas_time_us = BMP280_MEAS_OFFSET;
/* Check if we are using a BME280 device */
if (data->oversampling_humid)
- meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
- else
- meas_time_us = 0;
-
/* Pressure measurement time */
meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_press) * BMP280_MEAS_DUR;
@@ -1057,14 +1206,38 @@ static int bmp280_wait_conv(struct bmp280_data *data)
/* Temperature measurement time */
meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
- /* Waiting time according to the BM(P/E)2 Sensor API */
- fsleep(meas_time_us);
+ /* nominal value */
+ return meas_time_us;
+}
- ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
- if (ret) {
- dev_err(data->dev, "failed to read status register.\n");
+static int bmp280_wait_conv(struct bmp280_data *data)
+{
+ unsigned int reg, meas_time_us;
+ int ret;
+ int meas_cycles = 4;
+
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
return ret;
- }
+
+ if (data->op_mode == BMP280_NORMAL)
+ return 0;
+
+ meas_time_us = bmp280_calc_meas_time_us(data);
+
+ do {
+ /* Waiting time according to the BM(P/E)2 Sensor API */
+ fsleep(meas_time_us);
+
+ ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
+ if (ret) {
+ dev_err(data->dev, "failed to read status register.\n");
+ return ret;
+ }
+
+ meas_time_us >>= 3;
+ } while ((reg & BMP280_REG_STATUS_MEAS_BIT) && --meas_cycles);
if (reg & BMP280_REG_STATUS_MEAS_BIT) {
dev_err(data->dev, "Measurement cycle didn't complete.\n");
@@ -1078,6 +1251,7 @@ static int bmp280_chip_config(struct bmp280_data *data)
{
u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
+ u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK, (data->sampling_freq ? data->sampling_freq - 1 : 0));
int ret;
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
@@ -1091,8 +1265,9 @@ static int bmp280_chip_config(struct bmp280_data *data)
}
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
- BMP280_FILTER_MASK,
- BMP280_FILTER_4X);
+ BMP280_FILTER_MASK |
+ BMP280_TSTBY_MASK,
+ tstby | BMP280_FILTER_4X);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1186,6 +1361,10 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_press_default = BMP280_OSRS_PRESS_16X - 1,
+ .sampling_freq_avail = bmp280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
+ .sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1371,6 +1550,10 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1,
+ .sampling_freq_avail = bme280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
+ .sampling_freq_default = BME280_ODR_0HZ, /* MODE_FORCED */
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1701,6 +1884,11 @@ static int bmp380_wait_conv(struct bmp280_data *data)
unsigned int reg;
int ret, meas_time_us;
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
+
/* Offset measurement time */
meas_time_us = BMP380_MEAS_OFFSET;
@@ -2435,6 +2623,12 @@ static int bmp580_wait_conv(struct bmp280_data *data)
21840,
};
int meas_time_us;
+ int ret;
+
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
meas_time_us = 4 * USEC_PER_MSEC +
time_conv_temp[data->oversampling_temp] +
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 25bb9c743a05..0ec8a8e142f0 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -248,6 +248,16 @@
#define BMP280_FILTER_8X 3
#define BMP280_FILTER_16X 4
+#define BMP280_TSTBY_MASK GENMASK(7, 5)
+#define BMP280_TSTBY_0_5 0
+#define BMP280_TSTBY_62_5 1
+#define BMP280_TSTBY_125 2
+#define BMP280_TSTBY_250 3
+#define BMP280_TSTBY_500 4
+#define BMP280_TSTBY_1000 5
+#define BMP280_TSTBY_2000 6
+#define BMP280_TSTBY_4000 7
+
#define BMP280_OSRS_TEMP_MASK GENMASK(7, 5)
#define BMP280_OSRS_TEMP_SKIP 0
#define BMP280_OSRS_TEMP_1X 1
@@ -269,9 +279,9 @@
#define BMP280_MODE_FORCED 1
#define BMP280_MODE_NORMAL 3
-#define BMP280_MEAS_OFFSET 1250
-#define BMP280_MEAS_DUR 2300
-#define BMP280_PRESS_HUMID_MEAS_OFFSET 575
+#define BMP280_MEAS_OFFSET 1095 /* ceil(1250/(1+2^-3+2^-6+2^-9) */
+#define BMP280_MEAS_DUR 2013 /* ceil(2300/(1+2^-3+2^-6+2^-9) */
+#define BMP280_PRESS_HUMID_MEAS_OFFSET 504 /* ceil( 575/(1+2^-3+2^-6+2^-9) */
/* BME280 specific registers */
#define BME280_REG_HUMIDITY_LSB 0xFE
@@ -294,6 +304,16 @@
#define BME280_CONTIGUOUS_CALIB_REGS 7
+#define BME280_TSTBY_MASK GENMASK(7, 5)
+#define BME280_TSTBY_0_5 0
+#define BME280_TSTBY_62_5 1
+#define BME280_TSTBY_125 2
+#define BME280_TSTBY_250 3
+#define BME280_TSTBY_500 4
+#define BME280_TSTBY_1000 5
+#define BME280_TSTBY_1 6
+#define BME280_TSTBY_20 7
+
#define BME280_OSRS_HUMIDITY_MASK GENMASK(2, 0)
#define BME280_OSRS_HUMIDITY_SKIP 0
#define BME280_OSRS_HUMIDITY_1X 1
--8<---------------cut here---------------end--------------->8---
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures
2025-07-26 18:34 ` ASSI
@ 2025-07-27 19:08 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-07-27 19:08 UTC (permalink / raw)
To: linux-iio
ASSI writes:
> ASSI writes:
> Since the BMx280 don't actually have a frequency setting and need to set
> standby times between measurements instead (for which I haven't found an
> easily usable parameter in the IIO framework), the permissible frequency
> settings are calculated for the lowest possible measurement time
> (oversampling=1 for all channels). The actual frequencies could be
> caclulated from the current settings and made available on read, but I
> haven't implemented that yet -- at the moment you'll get back the value
> you have set independent of the actual oversampling ratios.
Implemented and that actually helped find another bug hiding in plain
sight in the original code…
> Another issue I found while perusing the sources is that the filter has
> a fixed setting of 4 for these chips, which might be made changeable by
> using the filter_coefficient. Not looked at what that entails,
> though.
Implemented.
> I've got a sparse checkout of the kernel repo now, so if you think that
> this may be acceptable I can work on getting that into the form you are
> expecting (either a single commit or a series) and iron out any kinks
> you see.
I have a patch series that checkpatch.pl no longer complains about, but
I'll probably go over it at least one more time before submission.
Full patch for anybody wanting to give it a try (BMx[135]80 need testing
since I don't have any):
--8<---------------cut here---------------start------------->8---
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index f37f20776c89..22a49356ca9c 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -64,7 +64,32 @@
*/
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
+enum bmp280_odr {
+ BMP280_ODR_0HZ, /* MODE_FORCED */
+ BMP280_ODR_110HZ, /* t_sb = 0.5ms */
+ BMP280_ODR_14HZ, /* t_sb = 62.5ms */
+ BMP280_ODR_7_5HZ, /* t_sb = 125ms */
+ BMP280_ODR_3_85HZ, /* t_sb = 250ms */
+ BMP280_ODR_1_96HZ, /* t_sb = 500ms */
+ BMP280_ODR_0_99HZ, /* t_sb = 1000ms */
+ BMP280_ODR_0_49HZ, /* t_sb = 2000ms */
+ BMP280_ODR_0_24HZ, /* t_sb = 4000ms */
+};
+
+enum bme280_odr {
+ BME280_ODR_0HZ, /* MODE_FORCED */
+ BME280_ODR_110HZ, /* t_sb = 0.5ms */
+ BME280_ODR_14HZ, /* t_sb = 62.5ms */
+ BME280_ODR_7_5HZ, /* t_sb = 125ms */
+ BME280_ODR_3_85HZ, /* t_sb = 250ms */
+ BME280_ODR_1_96HZ, /* t_sb = 500ms */
+ BME280_ODR_0_99HZ, /* t_sb = 1000ms */
+ BME280_ODR_51HZ, /* t_sb = 10ms */
+ BME280_ODR_34HZ, /* t_sb = 20ms */
+};
+
enum bmp380_odr {
+ BMP380_ODR_0HZ, /* MODE_FORCED */
BMP380_ODR_200HZ,
BMP380_ODR_100HZ,
BMP380_ODR_50HZ,
@@ -86,6 +111,7 @@ enum bmp380_odr {
};
enum bmp580_odr {
+ BMP580_ODR_0HZ, /* MODE_FORCED */
BMP580_ODR_240HZ,
BMP580_ODR_218HZ,
BMP580_ODR_199HZ,
@@ -159,6 +185,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -174,6 +202,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -193,6 +223,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -208,6 +240,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -223,6 +257,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 2,
.scan_type = {
.sign = 'u',
@@ -612,6 +648,45 @@ static int bme280_read_humid(struct bmp280_data *data, u32 *comp_humidity)
return 0;
}
+static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
+{
+ unsigned int meas_time_us = BMP280_MEAS_OFFSET;
+
+ meas_time_us = BMP280_MEAS_OFFSET;
+
+ /* Check if we are using a BME280 device */
+ if (data->chip_info->oversampling_humid_avail)
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
+ BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
+
+ /* Pressure measurement time */
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
+ BIT(data->oversampling_press) * BMP280_MEAS_DUR;
+
+ /* Temperature measurement time */
+ meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
+
+ /* nominal value */
+ return meas_time_us;
+}
+
+static void bmp280_calc_sampling_frequency(struct bmp280_data *data, int *val, int *val2)
+{
+ unsigned int cycle_time_us;
+ unsigned long freq_uHz;
+
+ if (data->chip_info->sampling_freq_tstby) {
+ cycle_time_us = bmp280_calc_meas_time_us(data);
+ cycle_time_us += data->chip_info->sampling_freq_tstby[data->sampling_freq];
+ freq_uHz = 1000000000000L / cycle_time_us;
+ *val = freq_uHz / 1000000L;
+ *val2 = freq_uHz % 1000000L;
+ } else {
+ *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
+ *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
+ }
+}
+
static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -619,55 +694,68 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
struct bmp280_data *data = iio_priv(indio_dev);
int chan_value;
int ret;
+ int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
+ int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
+ int switch_off, switch_threshold = -1;
+ int raw = 0;
guard(mutex)(&data->lock);
+ prev_oversampling_humid = temp_oversampling_humid = data->oversampling_humid;
+ prev_oversampling_press = temp_oversampling_press = data->oversampling_press;
+ prev_oversampling_temp = temp_oversampling_temp = data->oversampling_temp;
+
+ data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
+
switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ raw = 1;
+ fallthrough;
case IIO_CHAN_INFO_PROCESSED:
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- return ret;
+ switch_off = 0;
+ if (data->op_mode == BMP280_FORCED) {
+ /* switch off unused channels */
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ temp_oversampling_temp = 1-1; /* can't be switched off as it is needed for compensation */
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) | (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+ if (switch_off) {
+ data->oversampling_humid = temp_oversampling_humid;
+ data->oversampling_press = temp_oversampling_press;
+ data->oversampling_temp = temp_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret)
+ goto restore;
+ }
ret = data->chip_info->wait_conv(data);
if (ret)
- return ret;
+ goto restore;
- switch (chan->type) {
- case IIO_HUMIDITYRELATIVE:
- ret = data->chip_info->read_humid(data, &chan_value);
- if (ret)
- return ret;
-
- *val = data->chip_info->humid_coeffs[0] * chan_value;
- *val2 = data->chip_info->humid_coeffs[1];
- return data->chip_info->humid_coeffs_type;
- case IIO_PRESSURE:
- ret = data->chip_info->read_press(data, &chan_value);
- if (ret)
- return ret;
-
- *val = data->chip_info->press_coeffs[0] * chan_value;
- *val2 = data->chip_info->press_coeffs[1];
- return data->chip_info->press_coeffs_type;
- case IIO_TEMP:
- ret = data->chip_info->read_temp(data, &chan_value);
+ if (switch_off) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
if (ret)
return ret;
-
- *val = data->chip_info->temp_coeffs[0] * chan_value;
- *val2 = data->chip_info->temp_coeffs[1];
- return data->chip_info->temp_coeffs_type;
- default:
- return -EINVAL;
}
- case IIO_CHAN_INFO_RAW:
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- return ret;
-
- ret = data->chip_info->wait_conv(data);
- if (ret)
- return ret;
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
@@ -675,22 +763,40 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (ret)
return ret;
- *val = chan_value;
- return IIO_VAL_INT;
+ if (raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ } else {
+ *val = data->chip_info->humid_coeffs[0] * chan_value;
+ *val2 = data->chip_info->humid_coeffs[1];
+ return data->chip_info->humid_coeffs_type;
+ }
case IIO_PRESSURE:
ret = data->chip_info->read_press(data, &chan_value);
if (ret)
return ret;
- *val = chan_value;
- return IIO_VAL_INT;
+ if (raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ } else {
+ *val = data->chip_info->press_coeffs[0] * chan_value;
+ *val2 = data->chip_info->press_coeffs[1];
+ return data->chip_info->press_coeffs_type;
+ }
case IIO_TEMP:
ret = data->chip_info->read_temp(data, &chan_value);
if (ret)
return ret;
- *val = chan_value;
- return IIO_VAL_INT;
+ if (raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ } else {
+ *val = data->chip_info->temp_coeffs[0] * chan_value;
+ *val2 = data->chip_info->temp_coeffs[1];
+ return data->chip_info->temp_coeffs_type;
+ }
default:
return -EINVAL;
}
@@ -728,19 +834,26 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SAMP_FREQ:
if (!data->chip_info->sampling_freq_avail)
return -EINVAL;
-
- *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
- *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
+ bmp280_calc_sampling_frequency(data, val, val2);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
if (!data->chip_info->iir_filter_coeffs_avail)
return -EINVAL;
- *val = (1 << data->iir_filter_coeff) - 1;
+ *val = data->chip_info->iir_filter_coeffs_avail[data->iir_filter_coeff];
return IIO_VAL_INT;
default:
return -EINVAL;
}
+ restore:
+ if (switch_off) {
+ /* restore channel configuration */
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ }
+ return ret;
}
static int bmp280_read_raw(struct iio_dev *indio_dev,
@@ -852,6 +965,10 @@ static int bmp280_write_sampling_frequency(struct bmp280_data *data,
data->chip_info->chip_config(data);
return ret;
}
+ ret = data->chip_info->set_mode(data, (i ? BMP280_NORMAL : BMP280_FORCED));
+ if (ret)
+ return ret;
+
return 0;
}
}
@@ -866,7 +983,7 @@ static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val)
int i;
for (i = 0; i < n; i++) {
- if (avail[i] - 1 == val) {
+ if (avail[i] == val) {
prev = data->iir_filter_coeff;
data->iir_filter_coeff = i;
@@ -988,6 +1105,54 @@ static const unsigned long bme280_avail_scan_masks[] = {
0
};
+static const int bmp280_odr_table[][2] = {
+ [BMP280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
+ [BMP280_ODR_110HZ] = {110, 0},
+ [BMP280_ODR_14HZ] = {14, 0},
+ [BMP280_ODR_7_5HZ] = {7, 500000},
+ [BMP280_ODR_3_85HZ] = {3, 850000},
+ [BMP280_ODR_1_96HZ] = {1, 960000},
+ [BMP280_ODR_0_99HZ] = {0, 990000},
+ [BMP280_ODR_0_49HZ] = {0, 490000},
+ [BMP280_ODR_0_24HZ] = {0, 240000},
+};
+/* must be the same size as the ODR table */
+static const int bmp280_tstby_table[] = {
+ [BMP280_ODR_0HZ] = 0,
+ [BMP280_ODR_110HZ] = 500,
+ [BMP280_ODR_14HZ] = 62500,
+ [BMP280_ODR_7_5HZ] = 125000,
+ [BMP280_ODR_3_85HZ] = 250000,
+ [BMP280_ODR_1_96HZ] = 500000,
+ [BMP280_ODR_0_99HZ] = 1000000,
+ [BMP280_ODR_0_49HZ] = 2000000,
+ [BMP280_ODR_0_24HZ] = 4000000,
+};
+
+static const int bme280_odr_table[][2] = {
+ [BME280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
+ [BME280_ODR_110HZ] = {110, 0},
+ [BME280_ODR_14HZ] = {14, 0},
+ [BME280_ODR_7_5HZ] = {7, 500000},
+ [BME280_ODR_3_85HZ] = {3, 850000},
+ [BME280_ODR_1_96HZ] = {1, 960000},
+ [BME280_ODR_0_99HZ] = {0, 990000},
+ [BME280_ODR_51HZ] = {51, 0},
+ [BME280_ODR_34HZ] = {34, 0},
+};
+/* must be the same size as the ODR table */
+static const int bme280_tstby_table[] = {
+ [BME280_ODR_0HZ] = 0,
+ [BME280_ODR_110HZ] = 500,
+ [BME280_ODR_14HZ] = 62500,
+ [BME280_ODR_7_5HZ] = 125000,
+ [BME280_ODR_3_85HZ] = 250000,
+ [BME280_ODR_1_96HZ] = 500000,
+ [BME280_ODR_0_99HZ] = 1000000,
+ [BME280_ODR_51HZ] = 10000,
+ [BME280_ODR_34HZ] = 20000,
+};
+
static int bmp280_preinit(struct bmp280_data *data)
{
struct device *dev = data->dev;
@@ -1025,6 +1190,8 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
{
int ret;
+ data->op_mode = BMP280_SLEEP;
+
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
BMP280_MODE_MASK, bmp280_operation_mode[mode]);
if (ret) {
@@ -1041,30 +1208,32 @@ static int bmp280_wait_conv(struct bmp280_data *data)
{
unsigned int reg, meas_time_us;
int ret;
+ int meas_cycles = 4;
- /* Check if we are using a BME280 device */
- if (data->oversampling_humid)
- meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
- BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
- else
- meas_time_us = 0;
+ if (data->op_mode == BMP280_NORMAL)
+ return 0;
- /* Pressure measurement time */
- meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
- BIT(data->oversampling_press) * BMP280_MEAS_DUR;
+ meas_time_us = bmp280_calc_meas_time_us(data);
- /* Temperature measurement time */
- meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
+ do {
+ /* Waiting time according to the BM(P/E)2 Sensor API */
+ fsleep(meas_time_us);
- /* Waiting time according to the BM(P/E)2 Sensor API */
- fsleep(meas_time_us);
+ ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
+ if (ret) {
+ dev_err(data->dev, "failed to read status register.\n");
+ return ret;
+ }
- ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
- if (ret) {
- dev_err(data->dev, "failed to read status register.\n");
- return ret;
- }
+ meas_time_us >>= 3;
+ } while ((reg & BMP280_REG_STATUS_MEAS_BIT) && --meas_cycles);
+
+ data->op_mode = BMP280_SLEEP;
if (reg & BMP280_REG_STATUS_MEAS_BIT) {
dev_err(data->dev, "Measurement cycle didn't complete.\n");
@@ -1078,6 +1247,7 @@ static int bmp280_chip_config(struct bmp280_data *data)
{
u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
+ u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK, (data->sampling_freq ? data->sampling_freq - 1 : 0));
int ret;
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
@@ -1091,8 +1261,9 @@ static int bmp280_chip_config(struct bmp280_data *data)
}
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
+ BMP280_TSTBY_MASK |
BMP280_FILTER_MASK,
- BMP280_FILTER_4X);
+ tstby | data->iir_filter_coeff);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1157,6 +1328,7 @@ static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static const u8 bmp280_chip_ids[] = { BMP280_CHIP_ID };
static const int bmp280_temp_coeffs[] = { 10, 1 };
static const int bmp280_press_coeffs[] = { 1, 256000 };
+static const int bmp280_iir_filter_coeffs_avail[] = { 0, 2, 4, 8, 16 };
const struct bmp280_chip_info bmp280_chip_info = {
.id_reg = BMP280_REG_ID,
@@ -1186,6 +1358,15 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_press_default = BMP280_OSRS_PRESS_16X - 1,
+ .sampling_freq_tstby = bmp280_tstby_table,
+ .sampling_freq_avail = bmp280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
+ .sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
+
+ .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
+ .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
+ .iir_filter_coeff_default = 2,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1371,6 +1552,15 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1,
+ .sampling_freq_tstby = bme280_tstby_table,
+ .sampling_freq_avail = bme280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
+ .sampling_freq_default = BME280_ODR_0HZ, /* MODE_FORCED */
+
+ .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
+ .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
+ .iir_filter_coeff_default = 2,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1701,6 +1891,11 @@ static int bmp380_wait_conv(struct bmp280_data *data)
unsigned int reg;
int ret, meas_time_us;
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
+
/* Offset measurement time */
meas_time_us = BMP380_MEAS_OFFSET;
@@ -1954,7 +2149,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
}
static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 };
-static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128};
+static const int bmp380_iir_filter_coeffs_avail[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
static const u8 bmp380_chip_ids[] = { BMP380_CHIP_ID, BMP390_CHIP_ID };
static const int bmp380_temp_coeffs[] = { 10, 1 };
static const int bmp380_press_coeffs[] = { 1, 100000 };
@@ -2435,6 +2630,12 @@ static int bmp580_wait_conv(struct bmp280_data *data)
21840,
};
int meas_time_us;
+ int ret;
+
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
meas_time_us = 4 * USEC_PER_MSEC +
time_conv_temp[data->oversampling_temp] +
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 25bb9c743a05..990ccb38da13 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -248,6 +248,16 @@
#define BMP280_FILTER_8X 3
#define BMP280_FILTER_16X 4
+#define BMP280_TSTBY_MASK GENMASK(7, 5)
+#define BMP280_TSTBY_0_5 0
+#define BMP280_TSTBY_62_5 1
+#define BMP280_TSTBY_125 2
+#define BMP280_TSTBY_250 3
+#define BMP280_TSTBY_500 4
+#define BMP280_TSTBY_1000 5
+#define BMP280_TSTBY_2000 6
+#define BMP280_TSTBY_4000 7
+
#define BMP280_OSRS_TEMP_MASK GENMASK(7, 5)
#define BMP280_OSRS_TEMP_SKIP 0
#define BMP280_OSRS_TEMP_1X 1
@@ -269,9 +279,9 @@
#define BMP280_MODE_FORCED 1
#define BMP280_MODE_NORMAL 3
-#define BMP280_MEAS_OFFSET 1250
-#define BMP280_MEAS_DUR 2300
-#define BMP280_PRESS_HUMID_MEAS_OFFSET 575
+#define BMP280_MEAS_OFFSET 1095 /* ceil(1250/(1+2^-3+2^-6+2^-9) */
+#define BMP280_MEAS_DUR 2013 /* ceil(2300/(1+2^-3+2^-6+2^-9) */
+#define BMP280_PRESS_HUMID_MEAS_OFFSET 504 /* ceil( 575/(1+2^-3+2^-6+2^-9) */
/* BME280 specific registers */
#define BME280_REG_HUMIDITY_LSB 0xFE
@@ -294,6 +304,16 @@
#define BME280_CONTIGUOUS_CALIB_REGS 7
+#define BME280_TSTBY_MASK GENMASK(7, 5)
+#define BME280_TSTBY_0_5 0
+#define BME280_TSTBY_62_5 1
+#define BME280_TSTBY_125 2
+#define BME280_TSTBY_250 3
+#define BME280_TSTBY_500 4
+#define BME280_TSTBY_1000 5
+#define BME280_TSTBY_1 6
+#define BME280_TSTBY_20 7
+
#define BME280_OSRS_HUMIDITY_MASK GENMASK(2, 0)
#define BME280_OSRS_HUMIDITY_SKIP 0
#define BME280_OSRS_HUMIDITY_1X 1
@@ -501,6 +521,7 @@ struct bmp280_chip_info {
int num_iir_filter_coeffs_avail;
int iir_filter_coeff_default;
+ const int *sampling_freq_tstby;
const int (*sampling_freq_avail)[2];
int num_sampling_freq_avail;
int sampling_freq_default;
--8<---------------cut here---------------end--------------->8---
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
` (4 preceding siblings ...)
2024-10-19 13:55 ` [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Jonathan Cameron
@ 2025-08-03 14:07 ` Achim Gratz
2025-08-03 14:07 ` [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
` (6 more replies)
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
6 siblings, 7 replies; 71+ messages in thread
From: Achim Gratz @ 2025-08-03 14:07 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
With 6.13 a change was made to the bmp280 drivers to use MODE_FORCED
instead of MODE_NORMAL. This broke userspace functionality: reading
from sysfs interfaces no longer worked and an error was thrown
"Measurement cycle didn't complete". This series fixes the udnerlying
bugs affecting the measurement time calculation and implements
additional functionality not available for the BMx280 devices
previously to allow the use of the sysfs interface in MODE_NORMAL
again and control the corresponding parameters. The implementation
follows the already existing facilities for the BMx[35]80 devices even
though the actual functionality of the BMx280 devices is slightly
different.
Achim Gratz (6):
iio: pressure: bmp280: correct meas_time_us calculation
iio: pressure: bmp280: reduce overhead on read with MODE_FORCED
iio: pressure: bmp280: implement sampling_frequency for BMx280
iio: pressure: bmp280: enable filter settings for BMx280
iio: pressure: bmp280: remove code duplication
iio: pressure: bmp280: implement sampling_frequency calculation for
BMx280
drivers/iio/pressure/bmp280-core.c | 335 +++++++++++++++++++++++------
drivers/iio/pressure/bmp280.h | 28 ++-
2 files changed, 297 insertions(+), 66 deletions(-)
--
2.50.1
^ permalink raw reply [flat|nested] 71+ messages in thread
* [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
@ 2025-08-03 14:07 ` Achim Gratz
2025-08-06 15:46 ` Jonathan Cameron
2025-08-03 14:07 ` [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED Achim Gratz
` (5 subsequent siblings)
6 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-03 14:07 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Based on an observation and partial patch by David Lechner.
There was also a thinko in bmp280_wait_conv: data->oversampling_humid
can actually be 0 (for an oversampling_ratio of 1), so it can not be
used to detect the presence of the humidity measurement capability.
Use data->chip_info->oversampling_humid_avail instead, which is NULL
for chips that cannot measure humidity and therefore need to skip that
part of the calculation.
Note: Since the BMx280 device support was added, oversampling=0
actually is a valid setting (that channels measurement is off), but
allowing that setting by changing the data structure to hold the
actual value instead of its ilog2 would require more extensive changes
elsewhere in the code.
Suggested-by: David Lechner <dlechner@baylibre.com>
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 74505c9ec1a0..3213dcadba28 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1042,14 +1042,13 @@ static int bmp280_wait_conv(struct bmp280_data *data)
unsigned int reg, meas_time_us;
int ret;
+ meas_time_us = BMP280_MEAS_OFFSET;
+
/* Check if we are using a BME280 device */
- if (data->oversampling_humid)
- meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
+ if (data->chip_info->oversampling_humid_avail)
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
- else
- meas_time_us = 0;
-
/* Pressure measurement time */
meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
BIT(data->oversampling_press) * BMP280_MEAS_DUR;
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
2025-08-03 14:07 ` [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
@ 2025-08-03 14:07 ` Achim Gratz
2025-08-03 20:12 ` Andy Shevchenko
2025-08-06 15:58 ` Jonathan Cameron
2025-08-03 14:07 ` [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280 Achim Gratz
` (4 subsequent siblings)
6 siblings, 2 replies; 71+ messages in thread
From: Achim Gratz @ 2025-08-03 14:07 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
When measuring with MODE_FORCED, each read through sysfs triggers a
new measurement cycle through aLL channels with the current channel
configuration, even though we can only access a single channel.
Reduce the incurred overhead (especially for higher oversampling_ratio
settings) by temporarily switching off the unused channels. This
savea about a third of the acquisition time when reading all three
channels in succession:
| oversampling | max/full | max/skip | time/full | time/skip |
| | [ms] | [ms] | [ms] | [ms] |
|--------------+----------+----------+-----------+-----------|
| 16 | 339 | 120 | 315 | 127 |
| 8 | 174 | 65 | 166 | 76 |
| 4 | 90 | 38 | 94 | 53 |
| 2 | 49 | 24 | 59 | 41 |
| 1 | 28 | 17 | 36 | 33 |
The results are from an I²C connected sensor at 400kHz, so there is
considerable overhead from the changing the channel configuration,
most noticeably with low oversampling_ratio values. Faster
communication will reduce this overhead further; and since there is
still a net reduction in acquisition time even for
oversampling_ratio=1 switching off the channels is always done.
Note: The IIR filters will process a slightly noisier input signal.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 138 ++++++++++++++++++++++++++---
drivers/iio/pressure/bmp280.h | 7 +-
2 files changed, 129 insertions(+), 16 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 3213dcadba28..858974a64306 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -619,18 +619,66 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
struct bmp280_data *data = iio_priv(indio_dev);
int chan_value;
int ret;
+ int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
+ int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
+ int switch_off, switch_threshold = -1;
guard(mutex)(&data->lock);
+ prev_oversampling_humid = temp_oversampling_humid = data->oversampling_humid;
+ prev_oversampling_press = temp_oversampling_press = data->oversampling_press;
+ prev_oversampling_temp = temp_oversampling_temp = data->oversampling_temp;
+
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
+ /* switch off unused channels */
+ switch_off = 0;
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) |
+ (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (switch_off) {
+ data->oversampling_humid = temp_oversampling_humid;
+ data->oversampling_press = temp_oversampling_press;
+ data->oversampling_temp = temp_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret)
+ goto restore;
+ }
+
ret = data->chip_info->set_mode(data, BMP280_FORCED);
if (ret)
- return ret;
-
+ goto restore;
ret = data->chip_info->wait_conv(data);
if (ret)
- return ret;
+ goto restore;
+
+ if (switch_off) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret)
+ return ret;
+ }
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
@@ -661,13 +709,55 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
+ /* switch off unused channels */
+ switch_off = 0;
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) |
+ (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
+ if (switch_off) {
+ data->oversampling_humid = temp_oversampling_humid;
+ data->oversampling_press = temp_oversampling_press;
+ data->oversampling_temp = temp_oversampling_temp;
+ ret = data->chip_info->chip_config(data);
+ if (ret)
+ goto restore;
+ }
+
ret = data->chip_info->set_mode(data, BMP280_FORCED);
if (ret)
- return ret;
-
+ goto restore;
ret = data->chip_info->wait_conv(data);
if (ret)
- return ret;
+ goto restore;
+
+ if (switch_off) {
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ if (ret) {
+ return ret;
+ }
+ }
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
@@ -741,6 +831,15 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
+restore:
+ if (switch_off) {
+ /* restore channel configuration */
+ data->oversampling_humid = prev_oversampling_humid;
+ data->oversampling_press = prev_oversampling_press;
+ data->oversampling_temp = prev_oversampling_temp;
+ data->chip_info->chip_config(data);
+ }
+ return ret;
}
static int bmp280_read_raw(struct iio_dev *indio_dev,
@@ -1040,6 +1139,7 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
static int bmp280_wait_conv(struct bmp280_data *data)
{
unsigned int reg, meas_time_us;
+ int wait_cycles = BMP280_MEAS_WAITCYCLES;
int ret;
meas_time_us = BMP280_MEAS_OFFSET;
@@ -1056,14 +1156,26 @@ static int bmp280_wait_conv(struct bmp280_data *data)
/* Temperature measurement time */
meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
- /* Waiting time according to the BM(P/E)2 Sensor API */
- fsleep(meas_time_us);
+ do {
+ /*
+ * Waiting time according to the BM(P/E)2 Sensor API.
+ *
+ * First wait is for slightly longer than the typical measurement time, then
+ * each successive wait cycle will divide that time by 8. The number of wait
+ * cycles determines the overhead, this number and the measurement durations
+ * need to be chosen so that the total wait time meets or exceeds the maximum
+ * measurement time acccording to the datasheet.
+ */
+ fsleep(meas_time_us);
- ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
- if (ret) {
- dev_err(data->dev, "failed to read status register.\n");
- return ret;
- }
+ ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
+ if (ret) {
+ dev_err(data->dev, "failed to read status register.\n");
+ return ret;
+ }
+ } while ((reg & BMP280_REG_STATUS_MEAS_BIT) &&
+ --wait_cycles &&
+ (meas_time_us >>= 3));
if (reg & BMP280_REG_STATUS_MEAS_BIT) {
dev_err(data->dev, "Measurement cycle didn't complete.\n");
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 25bb9c743a05..88f5898282ec 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -269,9 +269,10 @@
#define BMP280_MODE_FORCED 1
#define BMP280_MODE_NORMAL 3
-#define BMP280_MEAS_OFFSET 1250
-#define BMP280_MEAS_DUR 2300
-#define BMP280_PRESS_HUMID_MEAS_OFFSET 575
+#define BMP280_MEAS_WAITCYCLES 2 /* minimize overhead */
+#define BMP280_MEAS_OFFSET 1112 /* ceil(1250 * 8/9) */
+#define BMP280_MEAS_DUR 2045 /* ceil(2300 * 8/9) */
+#define BMP280_PRESS_HUMID_MEAS_OFFSET 512 /* ceil( 575 * 8/9) */
/* BME280 specific registers */
#define BME280_REG_HUMIDITY_LSB 0xFE
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
2025-08-03 14:07 ` [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
2025-08-03 14:07 ` [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED Achim Gratz
@ 2025-08-03 14:07 ` Achim Gratz
2025-08-03 20:26 ` Andy Shevchenko
2025-08-03 14:08 ` [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings " Achim Gratz
` (3 subsequent siblings)
6 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-03 14:07 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
As was already commented in bm280.h:468, sampling_frequency can be
emulated on BMx280 devices indirectly via t_standby configuration.
Actually implement it to enable this useful feature. This allows to
switch between MODE_FORCED and MODE_NORMAL operation and use the same
sysfs reads for both modes.
The actual sampling frequency depends on the oversampling_ratio
settings. In order to not complicate the code too much, the available
sampling frequency values are fixed and have been calculated for
oversampling_ratio=1 on all three channels assuming maximum
measurement duration per the data sheet, corresponding to the minimum
achievable sampling frequency for the highest measurement speed
configuration.
THe ODR tables for the BM[35]80 devices have been extended to allow
for MODE_FORCED operation also and the handling of the table values
adapted accordingly.
Report of the actual sampling frequency via sysfs is possible, but not
yet implemented. In preparation for that implementation the
calculation of measurement time has been factored out from
bmp280_wait_conv into bmp280_calc_meas_time_us.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 219 +++++++++++++++++++++--------
drivers/iio/pressure/bmp280.h | 20 +++
2 files changed, 179 insertions(+), 60 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 858974a64306..4efdbfc3ac2c 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -64,7 +64,32 @@
*/
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
+enum bmp280_odr {
+ BMP280_ODR_0HZ, /* MODE_FORCED */
+ BMP280_ODR_110HZ, /* t_sb = 0.5ms */
+ BMP280_ODR_14HZ, /* t_sb = 62.5ms */
+ BMP280_ODR_7_5HZ, /* t_sb = 125ms */
+ BMP280_ODR_3_85HZ, /* t_sb = 250ms */
+ BMP280_ODR_1_96HZ, /* t_sb = 500ms */
+ BMP280_ODR_0_99HZ, /* t_sb = 1000ms */
+ BMP280_ODR_0_49HZ, /* t_sb = 2000ms */
+ BMP280_ODR_0_24HZ, /* t_sb = 4000ms */
+};
+
+enum bme280_odr {
+ BME280_ODR_0HZ, /* MODE_FORCED */
+ BME280_ODR_110HZ, /* t_sb = 0.5ms */
+ BME280_ODR_14HZ, /* t_sb = 62.5ms */
+ BME280_ODR_7_5HZ, /* t_sb = 125ms */
+ BME280_ODR_3_85HZ, /* t_sb = 250ms */
+ BME280_ODR_1_96HZ, /* t_sb = 500ms */
+ BME280_ODR_0_99HZ, /* t_sb = 1000ms */
+ BME280_ODR_51HZ, /* t_sb = 10ms */
+ BME280_ODR_34HZ, /* t_sb = 20ms */
+};
+
enum bmp380_odr {
+ BMP380_ODR_0HZ, /* MODE_FORCED */
BMP380_ODR_200HZ,
BMP380_ODR_100HZ,
BMP380_ODR_50HZ,
@@ -86,6 +111,7 @@ enum bmp380_odr {
};
enum bmp580_odr {
+ BMP580_ODR_0HZ, /* MODE_FORCED */
BMP580_ODR_240HZ,
BMP580_ODR_218HZ,
BMP580_ODR_199HZ,
@@ -159,6 +185,7 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -174,6 +201,7 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -193,6 +221,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -208,6 +237,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -223,6 +253,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
.scan_index = 2,
.scan_type = {
.sign = 'u',
@@ -629,31 +660,35 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
prev_oversampling_press = temp_oversampling_press = data->oversampling_press;
prev_oversampling_temp = temp_oversampling_temp = data->oversampling_temp;
+ data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
+
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
- /* switch off unused channels */
switch_off = 0;
- switch (chan->type) {
- case IIO_HUMIDITYRELATIVE:
- temp_oversampling_press = 0-1;
- switch_off |= (prev_oversampling_press > switch_threshold);
- /* can't be switched off as it is needed for compensation */
- temp_oversampling_temp = 1-1;
- break;
- case IIO_PRESSURE:
- temp_oversampling_humid = 0-1;
- switch_off |= (prev_oversampling_humid > switch_threshold);
- /* can't be switched off as it is needed for compensation */
- temp_oversampling_temp = 1-1;
- break;
- case IIO_TEMP:
- temp_oversampling_humid = 0-1;
- temp_oversampling_press = 0-1;
- switch_off = (prev_oversampling_humid > switch_threshold) |
- (prev_oversampling_press > switch_threshold);
- break;
- default:
- return -EINVAL;
+ if (data->op_mode == BMP280_FORCED) {
+ /* switch off unused channels */
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) |
+ (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
}
if (switch_off) {
data->oversampling_humid = temp_oversampling_humid;
@@ -664,9 +699,6 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
goto restore;
}
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- goto restore;
ret = data->chip_info->wait_conv(data);
if (ret)
goto restore;
@@ -709,29 +741,31 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
- /* switch off unused channels */
switch_off = 0;
- switch (chan->type) {
- case IIO_HUMIDITYRELATIVE:
- temp_oversampling_press = 0-1;
- switch_off |= (prev_oversampling_press > switch_threshold);
- /* can't be switched off as it is needed for compensation */
- temp_oversampling_temp = 1-1;
- break;
- case IIO_PRESSURE:
- temp_oversampling_humid = 0-1;
- switch_off |= (prev_oversampling_humid > switch_threshold);
- /* can't be switched off as it is needed for compensation */
- temp_oversampling_temp = 1-1;
- break;
- case IIO_TEMP:
- temp_oversampling_humid = 0-1;
- temp_oversampling_press = 0-1;
- switch_off = (prev_oversampling_humid > switch_threshold) |
- (prev_oversampling_press > switch_threshold);
- break;
- default:
- return -EINVAL;
+ if (data->op_mode == BMP280_FORCED) {
+ /* MODE_FORCED, switch off unused channels */
+ switch (chan->type) {
+ case IIO_HUMIDITYRELATIVE:
+ temp_oversampling_press = 0-1;
+ switch_off |= (prev_oversampling_press > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_PRESSURE:
+ temp_oversampling_humid = 0-1;
+ switch_off |= (prev_oversampling_humid > switch_threshold);
+ /* can't be switched off as it is needed for compensation */
+ temp_oversampling_temp = 1-1;
+ break;
+ case IIO_TEMP:
+ temp_oversampling_humid = 0-1;
+ temp_oversampling_press = 0-1;
+ switch_off = (prev_oversampling_humid > switch_threshold) |
+ (prev_oversampling_press > switch_threshold);
+ break;
+ default:
+ return -EINVAL;
+ }
}
if (switch_off) {
data->oversampling_humid = temp_oversampling_humid;
@@ -742,9 +776,6 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
goto restore;
}
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- goto restore;
ret = data->chip_info->wait_conv(data);
if (ret)
goto restore;
@@ -754,9 +785,8 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
data->oversampling_press = prev_oversampling_press;
data->oversampling_temp = prev_oversampling_temp;
data->chip_info->chip_config(data);
- if (ret) {
+ if (ret)
return ret;
- }
}
switch (chan->type) {
@@ -951,6 +981,10 @@ static int bmp280_write_sampling_frequency(struct bmp280_data *data,
data->chip_info->chip_config(data);
return ret;
}
+ ret = data->chip_info->set_mode(data, (i ? BMP280_NORMAL : BMP280_FORCED));
+ if (ret)
+ return ret;
+
return 0;
}
}
@@ -1087,6 +1121,30 @@ static const unsigned long bme280_avail_scan_masks[] = {
0
};
+static const int bmp280_odr_table[][2] = {
+ [BMP280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
+ [BMP280_ODR_110HZ] = {110, 0},
+ [BMP280_ODR_14HZ] = {14, 0},
+ [BMP280_ODR_7_5HZ] = {7, 500000},
+ [BMP280_ODR_3_85HZ] = {3, 850000},
+ [BMP280_ODR_1_96HZ] = {1, 960000},
+ [BMP280_ODR_0_99HZ] = {0, 990000},
+ [BMP280_ODR_0_49HZ] = {0, 490000},
+ [BMP280_ODR_0_24HZ] = {0, 240000},
+};
+
+static const int bme280_odr_table[][2] = {
+ [BME280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
+ [BME280_ODR_110HZ] = {110, 0},
+ [BME280_ODR_14HZ] = {14, 0},
+ [BME280_ODR_7_5HZ] = {7, 500000},
+ [BME280_ODR_3_85HZ] = {3, 850000},
+ [BME280_ODR_1_96HZ] = {1, 960000},
+ [BME280_ODR_0_99HZ] = {0, 990000},
+ [BME280_ODR_51HZ] = {51, 0},
+ [BME280_ODR_34HZ] = {34, 0},
+};
+
static int bmp280_preinit(struct bmp280_data *data)
{
struct device *dev = data->dev;
@@ -1124,6 +1182,8 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
{
int ret;
+ data->op_mode = BMP280_SLEEP;
+
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
BMP280_MODE_MASK, bmp280_operation_mode[mode]);
if (ret) {
@@ -1136,13 +1196,9 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
return 0;
}
-static int bmp280_wait_conv(struct bmp280_data *data)
+static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
{
- unsigned int reg, meas_time_us;
- int wait_cycles = BMP280_MEAS_WAITCYCLES;
- int ret;
-
- meas_time_us = BMP280_MEAS_OFFSET;
+ unsigned int meas_time_us = BMP280_MEAS_OFFSET;
/* Check if we are using a BME280 device */
if (data->chip_info->oversampling_humid_avail)
@@ -1156,6 +1212,25 @@ static int bmp280_wait_conv(struct bmp280_data *data)
/* Temperature measurement time */
meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
+ /* nominal value */
+ return meas_time_us;
+}
+
+static int bmp280_wait_conv(struct bmp280_data *data)
+{
+ unsigned int reg, meas_time_us;
+ int wait_cycles = BMP280_MEAS_WAITCYCLES;
+ int ret;
+
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
+
+ if (data->op_mode == BMP280_NORMAL)
+ return 0;
+
+ meas_time_us = bmp280_calc_meas_time_us(data);
+
do {
/*
* Waiting time according to the BM(P/E)2 Sensor API.
@@ -1177,6 +1252,8 @@ static int bmp280_wait_conv(struct bmp280_data *data)
--wait_cycles &&
(meas_time_us >>= 3));
+ data->op_mode = BMP280_SLEEP;
+
if (reg & BMP280_REG_STATUS_MEAS_BIT) {
dev_err(data->dev, "Measurement cycle didn't complete.\n");
return -EBUSY;
@@ -1189,6 +1266,8 @@ static int bmp280_chip_config(struct bmp280_data *data)
{
u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
+ u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK,
+ (data->sampling_freq ? data->sampling_freq - 1 : 0));
int ret;
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
@@ -1202,8 +1281,9 @@ static int bmp280_chip_config(struct bmp280_data *data)
}
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
- BMP280_FILTER_MASK,
- BMP280_FILTER_4X);
+ BMP280_FILTER_MASK |
+ BMP280_TSTBY_MASK,
+ tstby | BMP280_FILTER_4X);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1297,6 +1377,10 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_press_default = BMP280_OSRS_PRESS_16X - 1,
+ .sampling_freq_avail = bmp280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
+ .sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1479,6 +1563,10 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1,
+ .sampling_freq_avail = bme280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
+ .sampling_freq_default = BME280_ODR_0HZ, /* MODE_FORCED */
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1809,6 +1897,11 @@ static int bmp380_wait_conv(struct bmp280_data *data)
unsigned int reg;
int ret, meas_time_us;
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
+
/* Offset measurement time */
meas_time_us = BMP380_MEAS_OFFSET;
@@ -2543,6 +2636,12 @@ static int bmp580_wait_conv(struct bmp280_data *data)
21840,
};
int meas_time_us;
+ int ret;
+
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
+ if (ret)
+ return ret;
meas_time_us = 4 * USEC_PER_MSEC +
time_conv_temp[data->oversampling_temp] +
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 88f5898282ec..e5cb2a52126d 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -248,6 +248,16 @@
#define BMP280_FILTER_8X 3
#define BMP280_FILTER_16X 4
+#define BMP280_TSTBY_MASK GENMASK(7, 5)
+#define BMP280_TSTBY_0_5 0
+#define BMP280_TSTBY_62_5 1
+#define BMP280_TSTBY_125 2
+#define BMP280_TSTBY_250 3
+#define BMP280_TSTBY_500 4
+#define BMP280_TSTBY_1000 5
+#define BMP280_TSTBY_2000 6
+#define BMP280_TSTBY_4000 7
+
#define BMP280_OSRS_TEMP_MASK GENMASK(7, 5)
#define BMP280_OSRS_TEMP_SKIP 0
#define BMP280_OSRS_TEMP_1X 1
@@ -295,6 +305,16 @@
#define BME280_CONTIGUOUS_CALIB_REGS 7
+#define BME280_TSTBY_MASK GENMASK(7, 5)
+#define BME280_TSTBY_0_5 0
+#define BME280_TSTBY_62_5 1
+#define BME280_TSTBY_125 2
+#define BME280_TSTBY_250 3
+#define BME280_TSTBY_500 4
+#define BME280_TSTBY_1000 5
+#define BME280_TSTBY_1 6
+#define BME280_TSTBY_20 7
+
#define BME280_OSRS_HUMIDITY_MASK GENMASK(2, 0)
#define BME280_OSRS_HUMIDITY_SKIP 0
#define BME280_OSRS_HUMIDITY_1X 1
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
` (2 preceding siblings ...)
2025-08-03 14:07 ` [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280 Achim Gratz
@ 2025-08-03 14:08 ` Achim Gratz
2025-08-03 20:28 ` Andy Shevchenko
2025-08-10 18:13 ` Jonathan Cameron
2025-08-03 14:08 ` [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication Achim Gratz
` (2 subsequent siblings)
6 siblings, 2 replies; 71+ messages in thread
From: Achim Gratz @ 2025-08-03 14:08 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
These devices were using a hardcoded IIR filter of length 4. Enable
filter_low_pass_3db_frequency settings to control the filter length
settings of the device (as done already for the BMx380 and BMx580
devices, even though the 3dB corner has an inverse relation to the
filter length). Remove an offset of 1 from the internal handling of
the available values.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 36 +++++++++++++++++++++---------
1 file changed, 25 insertions(+), 11 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 4efdbfc3ac2c..b3dcee3fe9b3 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -185,7 +185,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -201,7 +202,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -221,7 +223,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -237,7 +240,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -253,7 +257,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 2,
.scan_type = {
.sign = 'u',
@@ -856,7 +861,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (!data->chip_info->iir_filter_coeffs_avail)
return -EINVAL;
- *val = (1 << data->iir_filter_coeff) - 1;
+ *val = data->chip_info->iir_filter_coeffs_avail[data->iir_filter_coeff];
return IIO_VAL_INT;
default:
return -EINVAL;
@@ -999,7 +1004,7 @@ static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val)
int i;
for (i = 0; i < n; i++) {
- if (avail[i] - 1 == val) {
+ if (avail[i] == val) {
prev = data->iir_filter_coeff;
data->iir_filter_coeff = i;
@@ -1281,9 +1286,9 @@ static int bmp280_chip_config(struct bmp280_data *data)
}
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
- BMP280_FILTER_MASK |
- BMP280_TSTBY_MASK,
- tstby | BMP280_FILTER_4X);
+ BMP280_TSTBY_MASK |
+ BMP280_FILTER_MASK,
+ tstby | data->iir_filter_coeff);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1348,6 +1353,7 @@ static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static const u8 bmp280_chip_ids[] = { BMP280_CHIP_ID };
static const int bmp280_temp_coeffs[] = { 10, 1 };
static const int bmp280_press_coeffs[] = { 1, 256000 };
+static const int bmp280_iir_filter_coeffs_avail[] = { 0, 2, 4, 8, 16 };
const struct bmp280_chip_info bmp280_chip_info = {
.id_reg = BMP280_REG_ID,
@@ -1381,6 +1387,10 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
.sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
+ .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
+ .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
+ .iir_filter_coeff_default = 2,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1567,6 +1577,10 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
.sampling_freq_default = BME280_ODR_0HZ, /* MODE_FORCED */
+ .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
+ .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
+ .iir_filter_coeff_default = 2,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -2155,7 +2169,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
}
static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 };
-static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128};
+static const int bmp380_iir_filter_coeffs_avail[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
static const u8 bmp380_chip_ids[] = { BMP380_CHIP_ID, BMP390_CHIP_ID };
static const int bmp380_temp_coeffs[] = { 10, 1 };
static const int bmp380_press_coeffs[] = { 1, 100000 };
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
` (3 preceding siblings ...)
2025-08-03 14:08 ` [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings " Achim Gratz
@ 2025-08-03 14:08 ` Achim Gratz
2025-08-03 20:30 ` Andy Shevchenko
2025-08-10 18:19 ` Jonathan Cameron
2025-08-03 14:08 ` [bmp280 v1 6/6] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280 Achim Gratz
2025-08-03 19:20 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Andy Shevchenko
6 siblings, 2 replies; 71+ messages in thread
From: Achim Gratz @ 2025-08-03 14:08 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Refactor to get rid of duplicated code.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 89 +++++-------------------------
1 file changed, 15 insertions(+), 74 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index b3dcee3fe9b3..5cdaf7516940 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -658,6 +658,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
int switch_off, switch_threshold = -1;
+ int raw = 0;
guard(mutex)(&data->lock);
@@ -668,6 +669,8 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ raw = 1;
case IIO_CHAN_INFO_PROCESSED:
switch_off = 0;
if (data->op_mode == BMP280_FORCED) {
@@ -723,6 +726,10 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (ret)
return ret;
+ if (raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ }
*val = data->chip_info->humid_coeffs[0] * chan_value;
*val2 = data->chip_info->humid_coeffs[1];
return data->chip_info->humid_coeffs_type;
@@ -731,6 +738,10 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (ret)
return ret;
+ if (raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ }
*val = data->chip_info->press_coeffs[0] * chan_value;
*val2 = data->chip_info->press_coeffs[1];
return data->chip_info->press_coeffs_type;
@@ -739,86 +750,16 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (ret)
return ret;
+ if (raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ }
*val = data->chip_info->temp_coeffs[0] * chan_value;
*val2 = data->chip_info->temp_coeffs[1];
return data->chip_info->temp_coeffs_type;
default:
return -EINVAL;
}
- case IIO_CHAN_INFO_RAW:
- switch_off = 0;
- if (data->op_mode == BMP280_FORCED) {
- /* MODE_FORCED, switch off unused channels */
- switch (chan->type) {
- case IIO_HUMIDITYRELATIVE:
- temp_oversampling_press = 0-1;
- switch_off |= (prev_oversampling_press > switch_threshold);
- /* can't be switched off as it is needed for compensation */
- temp_oversampling_temp = 1-1;
- break;
- case IIO_PRESSURE:
- temp_oversampling_humid = 0-1;
- switch_off |= (prev_oversampling_humid > switch_threshold);
- /* can't be switched off as it is needed for compensation */
- temp_oversampling_temp = 1-1;
- break;
- case IIO_TEMP:
- temp_oversampling_humid = 0-1;
- temp_oversampling_press = 0-1;
- switch_off = (prev_oversampling_humid > switch_threshold) |
- (prev_oversampling_press > switch_threshold);
- break;
- default:
- return -EINVAL;
- }
- }
- if (switch_off) {
- data->oversampling_humid = temp_oversampling_humid;
- data->oversampling_press = temp_oversampling_press;
- data->oversampling_temp = temp_oversampling_temp;
- ret = data->chip_info->chip_config(data);
- if (ret)
- goto restore;
- }
-
- ret = data->chip_info->wait_conv(data);
- if (ret)
- goto restore;
-
- if (switch_off) {
- data->oversampling_humid = prev_oversampling_humid;
- data->oversampling_press = prev_oversampling_press;
- data->oversampling_temp = prev_oversampling_temp;
- data->chip_info->chip_config(data);
- if (ret)
- return ret;
- }
-
- switch (chan->type) {
- case IIO_HUMIDITYRELATIVE:
- ret = data->chip_info->read_humid(data, &chan_value);
- if (ret)
- return ret;
-
- *val = chan_value;
- return IIO_VAL_INT;
- case IIO_PRESSURE:
- ret = data->chip_info->read_press(data, &chan_value);
- if (ret)
- return ret;
-
- *val = chan_value;
- return IIO_VAL_INT;
- case IIO_TEMP:
- ret = data->chip_info->read_temp(data, &chan_value);
- if (ret)
- return ret;
-
- *val = chan_value;
- return IIO_VAL_INT;
- default:
- return -EINVAL;
- }
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [bmp280 v1 6/6] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
` (4 preceding siblings ...)
2025-08-03 14:08 ` [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication Achim Gratz
@ 2025-08-03 14:08 ` Achim Gratz
2025-08-03 20:37 ` Andy Shevchenko
2025-08-03 19:20 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Andy Shevchenko
6 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-03 14:08 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Report of the actual sampling frequency via sysfs is implemented based
on the nominal measurement cycle time, depending on oversampling_ratio
and t_standby settings. If the device dependent table for the
t_standby values is missing, the reported value is taken from the ODR
table as before.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 90 ++++++++++++++++++++++--------
drivers/iio/pressure/bmp280.h | 1 +
2 files changed, 68 insertions(+), 23 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 5cdaf7516940..3be22e2b777a 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -648,6 +648,45 @@ static int bme280_read_humid(struct bmp280_data *data, u32 *comp_humidity)
return 0;
}
+static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
+{
+ unsigned int meas_time_us = BMP280_MEAS_OFFSET;
+
+ meas_time_us = BMP280_MEAS_OFFSET;
+
+ /* Check if we are using a BME280 device */
+ if (data->chip_info->oversampling_humid_avail)
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
+ BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
+
+ /* Pressure measurement time */
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
+ BIT(data->oversampling_press) * BMP280_MEAS_DUR;
+
+ /* Temperature measurement time */
+ meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
+
+ /* nominal value */
+ return meas_time_us;
+}
+
+static void bmp280_calc_sampling_frequency(struct bmp280_data *data, int *val, int *val2)
+{
+ unsigned int cycle_time_us;
+ unsigned long freq_uHz;
+
+ if (data->chip_info->sampling_freq_tstby) {
+ cycle_time_us = bmp280_calc_meas_time_us(data);
+ cycle_time_us += data->chip_info->sampling_freq_tstby[data->sampling_freq];
+ freq_uHz = 1000000000000L / cycle_time_us;
+ *val = freq_uHz / 1000000L;
+ *val2 = freq_uHz % 1000000L;
+ } else {
+ *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
+ *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
+ }
+}
+
static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
@@ -671,6 +710,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
raw = 1;
+ fallthrough;
case IIO_CHAN_INFO_PROCESSED:
switch_off = 0;
if (data->op_mode == BMP280_FORCED) {
@@ -794,9 +834,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SAMP_FREQ:
if (!data->chip_info->sampling_freq_avail)
return -EINVAL;
-
- *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
- *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
+ bmp280_calc_sampling_frequency(data, val, val2);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
if (!data->chip_info->iir_filter_coeffs_avail)
@@ -1078,6 +1116,18 @@ static const int bmp280_odr_table[][2] = {
[BMP280_ODR_0_49HZ] = {0, 490000},
[BMP280_ODR_0_24HZ] = {0, 240000},
};
+/* must be the same size as the ODR table */
+static const int bmp280_tstby_table[] = {
+ [BMP280_ODR_0HZ] = 0,
+ [BMP280_ODR_110HZ] = 500,
+ [BMP280_ODR_14HZ] = 62500,
+ [BMP280_ODR_7_5HZ] = 125000,
+ [BMP280_ODR_3_85HZ] = 250000,
+ [BMP280_ODR_1_96HZ] = 500000,
+ [BMP280_ODR_0_99HZ] = 1000000,
+ [BMP280_ODR_0_49HZ] = 2000000,
+ [BMP280_ODR_0_24HZ] = 4000000,
+};
static const int bme280_odr_table[][2] = {
[BME280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
@@ -1090,6 +1140,18 @@ static const int bme280_odr_table[][2] = {
[BME280_ODR_51HZ] = {51, 0},
[BME280_ODR_34HZ] = {34, 0},
};
+/* must be the same size as the ODR table */
+static const int bme280_tstby_table[] = {
+ [BME280_ODR_0HZ] = 0,
+ [BME280_ODR_110HZ] = 500,
+ [BME280_ODR_14HZ] = 62500,
+ [BME280_ODR_7_5HZ] = 125000,
+ [BME280_ODR_3_85HZ] = 250000,
+ [BME280_ODR_1_96HZ] = 500000,
+ [BME280_ODR_0_99HZ] = 1000000,
+ [BME280_ODR_51HZ] = 10000,
+ [BME280_ODR_34HZ] = 20000,
+};
static int bmp280_preinit(struct bmp280_data *data)
{
@@ -1142,26 +1204,6 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
return 0;
}
-static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
-{
- unsigned int meas_time_us = BMP280_MEAS_OFFSET;
-
- /* Check if we are using a BME280 device */
- if (data->chip_info->oversampling_humid_avail)
- meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
- BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
-
- /* Pressure measurement time */
- meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
- BIT(data->oversampling_press) * BMP280_MEAS_DUR;
-
- /* Temperature measurement time */
- meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
-
- /* nominal value */
- return meas_time_us;
-}
-
static int bmp280_wait_conv(struct bmp280_data *data)
{
unsigned int reg, meas_time_us;
@@ -1324,6 +1366,7 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_press_default = BMP280_OSRS_PRESS_16X - 1,
+ .sampling_freq_tstby = bmp280_tstby_table,
.sampling_freq_avail = bmp280_odr_table,
.num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
.sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
@@ -1514,6 +1557,7 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1,
+ .sampling_freq_tstby = bme280_tstby_table,
.sampling_freq_avail = bme280_odr_table,
.num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
.sampling_freq_default = BME280_ODR_0HZ, /* MODE_FORCED */
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index e5cb2a52126d..89dbf19c9ee9 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -522,6 +522,7 @@ struct bmp280_chip_info {
int num_iir_filter_coeffs_avail;
int iir_filter_coeff_default;
+ const int *sampling_freq_tstby;
const int (*sampling_freq_avail)[2];
int num_sampling_freq_avail;
int sampling_freq_default;
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
` (5 preceding siblings ...)
2025-08-03 14:08 ` [bmp280 v1 6/6] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280 Achim Gratz
@ 2025-08-03 19:20 ` Andy Shevchenko
6 siblings, 0 replies; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-03 19:20 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 3, 2025 at 4:09 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>
> With 6.13 a change was made to the bmp280 drivers to use MODE_FORCED
v6.13
> instead of MODE_NORMAL. This broke userspace functionality: reading
> from sysfs interfaces no longer worked and an error was thrown
> "Measurement cycle didn't complete". This series fixes the udnerlying
underlying
> bugs affecting the measurement time calculation and implements
> additional functionality not available for the BMx280 devices
> previously to allow the use of the sysfs interface in MODE_NORMAL
> again and control the corresponding parameters. The implementation
> follows the already existing facilities for the BMx[35]80 devices even
> though the actual functionality of the BMx280 devices is slightly
> different.
This is interesting how you prepared the series. Please, don't drop
PATCH from the Subject prefix.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED
2025-08-03 14:07 ` [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED Achim Gratz
@ 2025-08-03 20:12 ` Andy Shevchenko
2025-08-06 15:58 ` Jonathan Cameron
1 sibling, 0 replies; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-03 20:12 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 3, 2025 at 4:09 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>
> When measuring with MODE_FORCED, each read through sysfs triggers a
> new measurement cycle through aLL channels with the current channel
all
> configuration, even though we can only access a single channel.
> Reduce the incurred overhead (especially for higher oversampling_ratio
> settings) by temporarily switching off the unused channels. This
> savea about a third of the acquisition time when reading all three
savea??
> channels in succession:
>
> | oversampling | max/full | max/skip | time/full | time/skip |
> | | [ms] | [ms] | [ms] | [ms] |
> |--------------+----------+----------+-----------+-----------|
> | 16 | 339 | 120 | 315 | 127 |
> | 8 | 174 | 65 | 166 | 76 |
> | 4 | 90 | 38 | 94 | 53 |
> | 2 | 49 | 24 | 59 | 41 |
> | 1 | 28 | 17 | 36 | 33 |
>
> The results are from an I²C connected sensor at 400kHz, so there is
> considerable overhead from the changing the channel configuration,
> most noticeably with low oversampling_ratio values. Faster
> communication will reduce this overhead further; and since there is
> still a net reduction in acquisition time even for
> oversampling_ratio=1 switching off the channels is always done.
>
> Note: The IIR filters will process a slightly noisier input signal.
...
> + int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
> + int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
> + int switch_off, switch_threshold = -1;
Are you sure everything here needs to be a _signed_ integer and
moreover _used_ as a such?
AFAICS switch_off usage is boolean with definitely the wrong type here.
...
> + case IIO_HUMIDITYRELATIVE:
> + temp_oversampling_press = 0-1;
> + switch_off |= (prev_oversampling_press > switch_threshold);
What's the point of '|'? Ditto for every case.
> + /* can't be switched off as it is needed for compensation */
> + temp_oversampling_temp = 1-1;
> + break;
...
> ret = data->chip_info->set_mode(data, BMP280_FORCED);
> if (ret)
> - return ret;
> -
Stray change (blank line removal).
> + goto restore;
> ret = data->chip_info->wait_conv(data);
> if (ret)
> - return ret;
> + goto restore;
...
> case IIO_CHAN_INFO_RAW:
Same comments as per above.
...
> ret = data->chip_info->set_mode(data, BMP280_FORCED);
> if (ret)
> - return ret;
> -
> + goto restore;
> ret = data->chip_info->wait_conv(data);
> if (ret)
> - return ret;
> + goto restore;
Same comments as per above.
...
> +restore:
With the above switch that returns on every case, this makes code less
readable. Consider refactoring first the function and then having a
code flow without an additional label.
> + if (switch_off) {
> + /* restore channel configuration */
> + data->oversampling_humid = prev_oversampling_humid;
> + data->oversampling_press = prev_oversampling_press;
> + data->oversampling_temp = prev_oversampling_temp;
> + data->chip_info->chip_config(data);
> + }
> + return ret;
...
> + do {
> + /*
> + * Waiting time according to the BM(P/E)2 Sensor API.
> + *
> + * First wait is for slightly longer than the typical measurement time, then
> + * each successive wait cycle will divide that time by 8. The number of wait
> + * cycles determines the overhead, this number and the measurement durations
> + * need to be chosen so that the total wait time meets or exceeds the maximum
> + * measurement time acccording to the datasheet.
according
> + */
> + fsleep(meas_time_us);
Can the meas_time_us be 0? What will happen in that case?
> + ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
> + if (ret) {
> + dev_err(data->dev, "failed to read status register.\n");
> + return ret;
> + }
> + } while ((reg & BMP280_REG_STATUS_MEAS_BIT) &&
> + --wait_cycles &&
> + (meas_time_us >>= 3));
Why not regmap_read_poll_timeout()?
...
> +#define BMP280_MEAS_OFFSET 1112 /* ceil(1250 * 8/9) */
> +#define BMP280_MEAS_DUR 2045 /* ceil(2300 * 8/9) */
> +#define BMP280_PRESS_HUMID_MEAS_OFFSET 512 /* ceil( 575 * 8/9) */
Instead of the not properly used style for the comment and comments
themselves use the preprocessor to do this for you. This not only
makes review easier (no need to recalculate by ourselves each time we
look at the code) but also eliminates potential typos.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-03 14:07 ` [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280 Achim Gratz
@ 2025-08-03 20:26 ` Andy Shevchenko
2025-08-04 17:29 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-03 20:26 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 3, 2025 at 4:09 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>
> As was already commented in bm280.h:468, sampling_frequency can be
> emulated on BMx280 devices indirectly via t_standby configuration.
> Actually implement it to enable this useful feature. This allows to
> switch between MODE_FORCED and MODE_NORMAL operation and use the same
> sysfs reads for both modes.
>
> The actual sampling frequency depends on the oversampling_ratio
> settings. In order to not complicate the code too much, the available
> sampling frequency values are fixed and have been calculated for
> oversampling_ratio=1 on all three channels assuming maximum
> measurement duration per the data sheet, corresponding to the minimum
> achievable sampling frequency for the highest measurement speed
> configuration.
>
> THe ODR tables for the BM[35]80 devices have been extended to allow
> for MODE_FORCED operation also and the handling of the table values
> adapted accordingly.
>
> Report of the actual sampling frequency via sysfs is possible, but not
> yet implemented. In preparation for that implementation the
> calculation of measurement time has been factored out from
> bmp280_wait_conv into bmp280_calc_meas_time_us.
...
The comments below make my eyebrows rise. Can you add a comment on top
explaining the relation between ODR Hz and t_sb, because it's
obviously not an inverted proportion.
> +enum bmp280_odr {
> + BMP280_ODR_0HZ, /* MODE_FORCED */
> + BMP280_ODR_110HZ, /* t_sb = 0.5ms */
> + BMP280_ODR_14HZ, /* t_sb = 62.5ms */
> + BMP280_ODR_7_5HZ, /* t_sb = 125ms */
> + BMP280_ODR_3_85HZ, /* t_sb = 250ms */
> + BMP280_ODR_1_96HZ, /* t_sb = 500ms */
> + BMP280_ODR_0_99HZ, /* t_sb = 1000ms */
> + BMP280_ODR_0_49HZ, /* t_sb = 2000ms */
> + BMP280_ODR_0_24HZ, /* t_sb = 4000ms */
> +};
> +
> +enum bme280_odr {
> + BME280_ODR_0HZ, /* MODE_FORCED */
> + BME280_ODR_110HZ, /* t_sb = 0.5ms */
> + BME280_ODR_14HZ, /* t_sb = 62.5ms */
> + BME280_ODR_7_5HZ, /* t_sb = 125ms */
> + BME280_ODR_3_85HZ, /* t_sb = 250ms */
> + BME280_ODR_1_96HZ, /* t_sb = 500ms */
> + BME280_ODR_0_99HZ, /* t_sb = 1000ms */
> + BME280_ODR_51HZ, /* t_sb = 10ms */
> + BME280_ODR_34HZ, /* t_sb = 20ms */
> +};
...
> switch (mask) {
> case IIO_CHAN_INFO_PROCESSED:
> - /* switch off unused channels */
> switch_off = 0;
> - switch (chan->type) {
AFAIU this code piece was just invented by one of the previous
patches. Can we just go to the point from the first one, please, and
avoid this ping-pong style of patching?
> - case IIO_HUMIDITYRELATIVE:
> - temp_oversampling_press = 0-1;
> - switch_off |= (prev_oversampling_press > switch_threshold);
> - /* can't be switched off as it is needed for compensation */
> - temp_oversampling_temp = 1-1;
> - break;
> - case IIO_PRESSURE:
> - temp_oversampling_humid = 0-1;
> - switch_off |= (prev_oversampling_humid > switch_threshold);
> - /* can't be switched off as it is needed for compensation */
> - temp_oversampling_temp = 1-1;
> - break;
> - case IIO_TEMP:
> - temp_oversampling_humid = 0-1;
> - temp_oversampling_press = 0-1;
> - switch_off = (prev_oversampling_humid > switch_threshold) |
> - (prev_oversampling_press > switch_threshold);
> - break;
> - default:
> - return -EINVAL;
> + if (data->op_mode == BMP280_FORCED) {
> + /* switch off unused channels */
> + switch (chan->type) {
> + case IIO_HUMIDITYRELATIVE:
> + temp_oversampling_press = 0-1;
> + switch_off |= (prev_oversampling_press > switch_threshold);
> + /* can't be switched off as it is needed for compensation */
> + temp_oversampling_temp = 1-1;
> + break;
> + case IIO_PRESSURE:
> + temp_oversampling_humid = 0-1;
> + switch_off |= (prev_oversampling_humid > switch_threshold);
> + /* can't be switched off as it is needed for compensation */
> + temp_oversampling_temp = 1-1;
> + break;
> + case IIO_TEMP:
> + temp_oversampling_humid = 0-1;
> + temp_oversampling_press = 0-1;
> + switch_off = (prev_oversampling_humid > switch_threshold) |
> + (prev_oversampling_press > switch_threshold);
> + break;
> + default:
> + return -EINVAL;
> + }
> }
Oh, yeah, my recommendation to refactor will really help to address
the above comment. So, not just consider, but please indeed refactor
code first. Ditto for the other switch-case and related pieces.
...
> +static const int bmp280_odr_table[][2] = {
> + [BMP280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
Why is the comment repeated here?
> + [BMP280_ODR_110HZ] = {110, 0},
> + [BMP280_ODR_14HZ] = {14, 0},
> + [BMP280_ODR_7_5HZ] = {7, 500000},
> + [BMP280_ODR_3_85HZ] = {3, 850000},
> + [BMP280_ODR_1_96HZ] = {1, 960000},
> + [BMP280_ODR_0_99HZ] = {0, 990000},
> + [BMP280_ODR_0_49HZ] = {0, 490000},
> + [BMP280_ODR_0_24HZ] = {0, 240000},
> +};
> +
> +static const int bme280_odr_table[][2] = {
> + [BME280_ODR_0HZ] = {0, 0}, /* MODE_FORCED */
Ditto.
> + [BME280_ODR_110HZ] = {110, 0},
> + [BME280_ODR_14HZ] = {14, 0},
> + [BME280_ODR_7_5HZ] = {7, 500000},
> + [BME280_ODR_3_85HZ] = {3, 850000},
> + [BME280_ODR_1_96HZ] = {1, 960000},
> + [BME280_ODR_0_99HZ] = {0, 990000},
> + [BME280_ODR_51HZ] = {51, 0},
> + [BME280_ODR_34HZ] = {34, 0},
> +};
...
> +static int bmp280_wait_conv(struct bmp280_data *data)
> +{
> + unsigned int reg, meas_time_us;
> + int wait_cycles = BMP280_MEAS_WAITCYCLES;
Signed?
> + int ret;
...
> + u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK,
> + (data->sampling_freq ? data->sampling_freq - 1 : 0));
Redundant parentheses, also possible shorten this to
(data->sampling_freq ?: 1) - 1
...
> ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
> - BMP280_FILTER_MASK,
> - BMP280_FILTER_4X);
> + BMP280_FILTER_MASK |
> + BMP280_TSTBY_MASK,
> + tstby | BMP280_FILTER_4X);
Make this more consistent (same parameter on the same columns and
perhaps one line for each)
_FILTER_MASK | _TSTBY_MASK,
_FILTER_4X | tstby
...
> + .sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
Why is this comment repeated all over the code? Any justification why
it's so important, please?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-03 14:08 ` [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings " Achim Gratz
@ 2025-08-03 20:28 ` Andy Shevchenko
2025-08-04 17:14 ` ASSI
2025-08-10 18:13 ` Jonathan Cameron
1 sibling, 1 reply; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-03 20:28 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 3, 2025 at 4:09 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>
> These devices were using a hardcoded IIR filter of length 4. Enable
> filter_low_pass_3db_frequency settings to control the filter length
> settings of the device (as done already for the BMx380 and BMx580
> devices, even though the 3dB corner has an inverse relation to the
> filter length). Remove an offset of 1 from the internal handling of
> the available values.
...
> ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
> - BMP280_FILTER_MASK |
> - BMP280_TSTBY_MASK,
> + BMP280_TSTBY_MASK |
> + BMP280_FILTER_MASK,
What's the point of this change, please?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication
2025-08-03 14:08 ` [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication Achim Gratz
@ 2025-08-03 20:30 ` Andy Shevchenko
2025-08-10 18:19 ` Jonathan Cameron
1 sibling, 0 replies; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-03 20:30 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 3, 2025 at 4:09 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>
> Refactor to get rid of duplicated code.
Maybe this patch should be somewhere earlier in the series?
...
> + int raw = 0;
Why integer and especially why _signed_ integer?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 6/6] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-08-03 14:08 ` [bmp280 v1 6/6] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280 Achim Gratz
@ 2025-08-03 20:37 ` Andy Shevchenko
2025-08-04 17:20 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-03 20:37 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 3, 2025 at 4:09 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>
> Report of the actual sampling frequency via sysfs is implemented based
> on the nominal measurement cycle time, depending on oversampling_ratio
> and t_standby settings. If the device dependent table for the
> t_standby values is missing, the reported value is taken from the ODR
> table as before.
...
> +static void bmp280_calc_sampling_frequency(struct bmp280_data *data, int *val, int *val2)
> +{
> + unsigned int cycle_time_us;
> + unsigned long freq_uHz;
> +
> + if (data->chip_info->sampling_freq_tstby) {
> + cycle_time_us = bmp280_calc_meas_time_us(data);
> + cycle_time_us += data->chip_info->sampling_freq_tstby[data->sampling_freq];
> + freq_uHz = 1000000000000L / cycle_time_us;
> + *val = freq_uHz / 1000000L;
> + *val2 = freq_uHz % 1000000L;
units.h and other constant definitions are for a reason.
> + } else {
> + *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
> + *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
> + }
> +}
...
> case IIO_CHAN_INFO_RAW:
> raw = 1;
> + fallthrough;
Oh, first of all, why is it here in _this_ patch?! Second, this makes
code harder to maintain and change. Think how to refactor to avoid
this. Or justify in the comment field of the patch (after '---' line)
why this is the best with the reference to what has been tried and
becomes worse than this.
...
> +/* must be the same size as the ODR table */
Instead of the comment, use proper static_assert() here somewhere.
> +static const int bmp280_tstby_table[] = {
> + [BMP280_ODR_0HZ] = 0,
> + [BMP280_ODR_110HZ] = 500,
> + [BMP280_ODR_14HZ] = 62500,
> + [BMP280_ODR_7_5HZ] = 125000,
> + [BMP280_ODR_3_85HZ] = 250000,
> + [BMP280_ODR_1_96HZ] = 500000,
> + [BMP280_ODR_0_99HZ] = 1000000,
> + [BMP280_ODR_0_49HZ] = 2000000,
> + [BMP280_ODR_0_24HZ] = 4000000,
> +};
...
> +/* must be the same size as the ODR table */
As per above.
> +static const int bme280_tstby_table[] = {
> + [BME280_ODR_0HZ] = 0,
> + [BME280_ODR_110HZ] = 500,
> + [BME280_ODR_14HZ] = 62500,
> + [BME280_ODR_7_5HZ] = 125000,
> + [BME280_ODR_3_85HZ] = 250000,
> + [BME280_ODR_1_96HZ] = 500000,
> + [BME280_ODR_0_99HZ] = 1000000,
> + [BME280_ODR_51HZ] = 10000,
> + [BME280_ODR_34HZ] = 20000,
Why not order by value?
> +};
...
For both, can you also utilize multipliers like USEC_PER_MSEC or so?
Or is it a different unit?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-03 20:28 ` Andy Shevchenko
@ 2025-08-04 17:14 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-08-04 17:14 UTC (permalink / raw)
To: linux-iio
Andy Shevchenko writes:
> On Sun, Aug 3, 2025 at 4:09 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>> ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
>> - BMP280_FILTER_MASK |
>> - BMP280_TSTBY_MASK,
>
>
>> + BMP280_TSTBY_MASK |
>> + BMP280_FILTER_MASK,
>
> What's the point of this change, please?
Keeping the arguments in the order of the bitfields in the device, just
like the other occurences of this pattern in the surrounding code.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 6/6] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-08-03 20:37 ` Andy Shevchenko
@ 2025-08-04 17:20 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-08-04 17:20 UTC (permalink / raw)
To: linux-iio
Andy Shevchenko writes:
>> +static const int bme280_tstby_table[] = {
>> + [BME280_ODR_0HZ] = 0,
>> + [BME280_ODR_110HZ] = 500,
>> + [BME280_ODR_14HZ] = 62500,
>> + [BME280_ODR_7_5HZ] = 125000,
>> + [BME280_ODR_3_85HZ] = 250000,
>> + [BME280_ODR_1_96HZ] = 500000,
>> + [BME280_ODR_0_99HZ] = 1000000,
>> + [BME280_ODR_51HZ] = 10000,
>> + [BME280_ODR_34HZ] = 20000,
>
> Why not order by value?
Because I do not have the luxury to retroactively define how the values
are mapped to the bitfield? Besides, if you look at the other table
you'll see how these values actually were in sequence in the BMP280 and
then replaced with these two values that are perhaps more useful in
application, but out-of-order. Otherwise the code would have to do a
table lookup each time one was trying to use this, which seems wasteful
for little to no gain.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-03 20:26 ` Andy Shevchenko
@ 2025-08-04 17:29 ` ASSI
2025-08-10 18:11 ` Jonathan Cameron
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-08-04 17:29 UTC (permalink / raw)
To: linux-iio
Andy Shevchenko writes:
>> + .sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
>
> Why is this comment repeated all over the code? Any justification why
> it's so important, please?
It's just a reminder that this value isn't actually used by the driver
to do what it says in the datasheet, but instead for effecting the
switching between MODE_FORCED and MODE_NORMAL. If you'd really want to
run the sensor with no standby between measurements there'd need to be
an extra invalid value (like -1), that then would need to be guarded
everywhere against getting used as an array index.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
SD adaptation for Waldorf rackAttack V1.04R1:
http://Synth.Stromeko.net/Downloads.html#WaldorfSDada
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation
2025-08-03 14:07 ` [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
@ 2025-08-06 15:46 ` Jonathan Cameron
2025-08-06 17:53 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-06 15:46 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, 3 Aug 2025 16:07:57 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Based on an observation and partial patch by David Lechner.
>
> There was also a thinko in bmp280_wait_conv: data->oversampling_humid
> can actually be 0 (for an oversampling_ratio of 1), so it can not be
> used to detect the presence of the humidity measurement capability.
> Use data->chip_info->oversampling_humid_avail instead, which is NULL
> for chips that cannot measure humidity and therefore need to skip that
> part of the calculation.
>
> Note: Since the BMx280 device support was added, oversampling=0
> actually is a valid setting (that channels measurement is off), but
> allowing that setting by changing the data structure to hold the
> actual value instead of its ilog2 would require more extensive changes
> elsewhere in the code.
>
> Suggested-by: David Lechner <dlechner@baylibre.com>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Needs a fixes tag if it is correcting something.
> ---
> drivers/iio/pressure/bmp280-core.c | 9 ++++-----
> 1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 74505c9ec1a0..3213dcadba28 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -1042,14 +1042,13 @@ static int bmp280_wait_conv(struct bmp280_data *data)
> unsigned int reg, meas_time_us;
> int ret;
>
> + meas_time_us = BMP280_MEAS_OFFSET;
> +
I'm not following this. Why are we now effectively adding MP280_MEAS_OFFSET
that we weren't before whether or not oversampling is enabled?
> /* Check if we are using a BME280 device */
> - if (data->oversampling_humid)
> - meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
> + if (data->chip_info->oversampling_humid_avail)
> + meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
> BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
>
> - else
> - meas_time_us = 0;
> -
> /* Pressure measurement time */
> meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
> BIT(data->oversampling_press) * BMP280_MEAS_DUR;
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED
2025-08-03 14:07 ` [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED Achim Gratz
2025-08-03 20:12 ` Andy Shevchenko
@ 2025-08-06 15:58 ` Jonathan Cameron
2025-08-06 18:00 ` ASSI
1 sibling, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-06 15:58 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, 3 Aug 2025 16:07:58 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> When measuring with MODE_FORCED, each read through sysfs triggers a
> new measurement cycle through aLL channels with the current channel
> configuration, even though we can only access a single channel.
> Reduce the incurred overhead (especially for higher oversampling_ratio
> settings) by temporarily switching off the unused channels. This
> savea about a third of the acquisition time when reading all three
> channels in succession:
>
> | oversampling | max/full | max/skip | time/full | time/skip |
> | | [ms] | [ms] | [ms] | [ms] |
> |--------------+----------+----------+-----------+-----------|
> | 16 | 339 | 120 | 315 | 127 |
> | 8 | 174 | 65 | 166 | 76 |
> | 4 | 90 | 38 | 94 | 53 |
> | 2 | 49 | 24 | 59 | 41 |
> | 1 | 28 | 17 | 36 | 33 |
>
> The results are from an I²C connected sensor at 400kHz, so there is
> considerable overhead from the changing the channel configuration,
> most noticeably with low oversampling_ratio values. Faster
> communication will reduce this overhead further; and since there is
> still a net reduction in acquisition time even for
> oversampling_ratio=1 switching off the channels is always done.
>
> Note: The IIR filters will process a slightly noisier input signal.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Hi Achim.
I'm not really sure what the algorithm implemented here is and what the
various local variables actually mean as state. Please add some
more comments to the code.
> ---
> drivers/iio/pressure/bmp280-core.c | 138 ++++++++++++++++++++++++++---
> drivers/iio/pressure/bmp280.h | 7 +-
> 2 files changed, 129 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 3213dcadba28..858974a64306 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -619,18 +619,66 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> struct bmp280_data *data = iio_priv(indio_dev);
> int chan_value;
> int ret;
> + int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
> + int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
> + int switch_off, switch_threshold = -1;
>
> guard(mutex)(&data->lock);
>
> + prev_oversampling_humid = temp_oversampling_humid = data->oversampling_humid;
> + prev_oversampling_press = temp_oversampling_press = data->oversampling_press;
> + prev_oversampling_temp = temp_oversampling_temp = data->oversampling_temp;
> +
> switch (mask) {
> case IIO_CHAN_INFO_PROCESSED:
> + /* switch off unused channels */
> + switch_off = 0;
So this is saying if 'anything can be switched off'?
switch_off_something or some naming like that.
> + switch (chan->type) {
> + case IIO_HUMIDITYRELATIVE:
> + temp_oversampling_press = 0-1;
0 - 1
etc. So always spaces around operators.
I'm not at all sure on the logic behind this maths though.
Seems it ultimately gets store into a u8. Add some comments on what the algorithm
is doing.
> + switch_off |= (prev_oversampling_press > switch_threshold);
> + /* can't be switched off as it is needed for compensation */
What can't be switched off? The temperature I guess.
> + temp_oversampling_temp = 1-1;
1 - 1
> + break;
> + case IIO_PRESSURE:
> + temp_oversampling_humid = 0-1;
> + switch_off |= (prev_oversampling_humid > switch_threshold);
> + /* can't be switched off as it is needed for compensation */
> + temp_oversampling_temp = 1-1;
> + break;
> + case IIO_TEMP:
> + temp_oversampling_humid = 0-1;
> + temp_oversampling_press = 0-1;
> + switch_off = (prev_oversampling_humid > switch_threshold) |
> + (prev_oversampling_press > switch_threshold);
> + break;
> + default:
> + return -EINVAL;
> + }
> + if (switch_off) {
> + data->oversampling_humid = temp_oversampling_humid;
> + data->oversampling_press = temp_oversampling_press;
> + data->oversampling_temp = temp_oversampling_temp;
> + ret = data->chip_info->chip_config(data);
> + if (ret)
> + goto restore;
> + }
> +
> ret = data->chip_info->set_mode(data, BMP280_FORCED);
> if (ret)
> - return ret;
> -
> + goto restore;
> ret = data->chip_info->wait_conv(data);
> if (ret)
> - return ret;
> + goto restore;
> +
> + if (switch_off) {
> + data->oversampling_humid = prev_oversampling_humid;
> + data->oversampling_press = prev_oversampling_press;
> + data->oversampling_temp = prev_oversampling_temp;
> + ret = data->chip_info->chip_config(data);
> + if (ret)
> + return ret;
> + }
>
> switch (chan->type) {
> case IIO_HUMIDITYRELATIVE:
> @@ -661,13 +709,55 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> return -EINVAL;
> }
> case IIO_CHAN_INFO_RAW:
> + /* switch off unused channels */
> + switch_off = 0;
> + switch (chan->type) {
> + case IIO_HUMIDITYRELATIVE:
> + temp_oversampling_press = 0-1;
> + switch_off |= (prev_oversampling_press > switch_threshold);
> + /* can't be switched off as it is needed for compensation */
> + temp_oversampling_temp = 1-1;
> + break;
> + case IIO_PRESSURE:
> + temp_oversampling_humid = 0-1;
> + switch_off |= (prev_oversampling_humid > switch_threshold);
> + /* can't be switched off as it is needed for compensation */
> + temp_oversampling_temp = 1-1;
> + break;
> + case IIO_TEMP:
> + temp_oversampling_humid = 0-1;
> + temp_oversampling_press = 0-1;
> + switch_off = (prev_oversampling_humid > switch_threshold) |
> + (prev_oversampling_press > switch_threshold);
> + break;
> + default:
> + return -EINVAL;
> + }
> + if (switch_off) {
> + data->oversampling_humid = temp_oversampling_humid;
> + data->oversampling_press = temp_oversampling_press;
> + data->oversampling_temp = temp_oversampling_temp;
> + ret = data->chip_info->chip_config(data);
> + if (ret)
> + goto restore;
> + }
> +
> ret = data->chip_info->set_mode(data, BMP280_FORCED);
> if (ret)
> - return ret;
> -
> + goto restore;
> ret = data->chip_info->wait_conv(data);
> if (ret)
> - return ret;
> + goto restore;
> +
> + if (switch_off) {
> + data->oversampling_humid = prev_oversampling_humid;
> + data->oversampling_press = prev_oversampling_press;
> + data->oversampling_temp = prev_oversampling_temp;
> + data->chip_info->chip_config(data);
> + if (ret) {
> + return ret;
> + }
> + }
>
> switch (chan->type) {
> case IIO_HUMIDITYRELATIVE:
> @@ -741,6 +831,15 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> default:
> return -EINVAL;
> }
> +restore:
Maybe worth factoring out he contents of the switch case that has goto restore
into a separate function so that the scope of the restore is same as the code
that is calling it. (i.e. avoid a goto jumping out of a switch.
> + if (switch_off) {
> + /* restore channel configuration */
> + data->oversampling_humid = prev_oversampling_humid;
> + data->oversampling_press = prev_oversampling_press;
> + data->oversampling_temp = prev_oversampling_temp;
> + data->chip_info->chip_config(data);
> + }
> + return ret;
> }
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation
2025-08-06 15:46 ` Jonathan Cameron
@ 2025-08-06 17:53 ` ASSI
2025-08-10 18:04 ` Jonathan Cameron
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-08-06 17:53 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> I'm not following this. Why are we now effectively adding MP280_MEAS_OFFSET
> that we weren't before whether or not oversampling is enabled?
Because that is a constant part of the actual measurement cycle that
happens entirely independent of any later measurements (whose individual
durations depend on the oversampling settings for the respective
channel). The graphics early in the datasheet don't show explicitly
where in the cycle it happens (my conjecture is at the end when it has
to update the IIR filters and swap the registers), however section 9.1
in Appendix B is abundantly clear that it's there.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED
2025-08-06 15:58 ` Jonathan Cameron
@ 2025-08-06 18:00 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-08-06 18:00 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> On Sun, 3 Aug 2025 16:07:58 +0200
> Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
>
>> When measuring with MODE_FORCED, each read through sysfs triggers a
>> new measurement cycle through aLL channels with the current channel
>> configuration, even though we can only access a single channel.
>> Reduce the incurred overhead (especially for higher oversampling_ratio
>> settings) by temporarily switching off the unused channels. This
>> savea about a third of the acquisition time when reading all three
>> channels in succession:
>>
>> | oversampling | max/full | max/skip | time/full | time/skip |
>> | | [ms] | [ms] | [ms] | [ms] |
>> |--------------+----------+----------+-----------+-----------|
>> | 16 | 339 | 120 | 315 | 127 |
>> | 8 | 174 | 65 | 166 | 76 |
>> | 4 | 90 | 38 | 94 | 53 |
>> | 2 | 49 | 24 | 59 | 41 |
>> | 1 | 28 | 17 | 36 | 33 |
>>
>> The results are from an I²C connected sensor at 400kHz, so there is
>> considerable overhead from the changing the channel configuration,
>> most noticeably with low oversampling_ratio values. Faster
>> communication will reduce this overhead further; and since there is
>> still a net reduction in acquisition time even for
>> oversampling_ratio=1 switching off the channels is always done.
>>
>> Note: The IIR filters will process a slightly noisier input signal.
>>
>> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
> Hi Achim.
>
> I'm not really sure what the algorithm implemented here is and what the
> various local variables actually mean as state. Please add some
> more comments to the code.
Based on yours and Andys comment I'm currently inclined to abandon this
part of the series and just let anybody still using the MODE_FORCED
operation suffer from the overly long acquisition cycles when using the
sysfs interface.
> Maybe worth factoring out he contents of the switch case that has goto restore
> into a separate function so that the scope of the restore is same as the code
> that is calling it. (i.e. avoid a goto jumping out of a switch.
I'll think about that when I have decided whether to keep that
feature in the code.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation
2025-08-06 17:53 ` ASSI
@ 2025-08-10 18:04 ` Jonathan Cameron
0 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-10 18:04 UTC (permalink / raw)
To: ASSI; +Cc: linux-iio
On Wed, 06 Aug 2025 19:53:55 +0200
ASSI <Stromeko@nexgo.de> wrote:
> Jonathan Cameron writes:
> > I'm not following this. Why are we now effectively adding MP280_MEAS_OFFSET
> > that we weren't before whether or not oversampling is enabled?
>
> Because that is a constant part of the actual measurement cycle that
> happens entirely independent of any later measurements (whose individual
> durations depend on the oversampling settings for the respective
> channel). The graphics early in the datasheet don't show explicitly
> where in the cycle it happens (my conjecture is at the end when it has
> to update the IIR filters and swap the registers), however section 9.1
> in Appendix B is abundantly clear that it's there.
>
>
> Regards,
> Achim.
Hi Achim. I'm a bit behind on reviews this weekend after a garage door related
crisis (now resolved) so might be a few days before I fully catch up.
I have few mins now though so quick replies where I can!
For this, thanks for the description. Please add something on this either
as a comment alongside that constant referring to the datasheet stuff you
mention, and/or something in the patch description.
Thanks,
Jonathan
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-04 17:29 ` ASSI
@ 2025-08-10 18:11 ` Jonathan Cameron
2025-08-10 19:12 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-10 18:11 UTC (permalink / raw)
To: ASSI; +Cc: linux-iio
On Mon, 04 Aug 2025 19:29:48 +0200
ASSI <Stromeko@nexgo.de> wrote:
> Andy Shevchenko writes:
> >> + .sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
> >
> > Why is this comment repeated all over the code? Any justification why
> > it's so important, please?
>
> It's just a reminder that this value isn't actually used by the driver
> to do what it says in the datasheet, but instead for effecting the
> switching between MODE_FORCED and MODE_NORMAL. If you'd really want to
> run the sensor with no standby between measurements there'd need to be
> an extra invalid value (like -1), that then would need to be guarded
> everywhere against getting used as an array index.
Call it BMP280_ODR_MODE_FORCED rather than making it 0HZ related?
Using the value 0 for the sysfs interface doesn't make much sense though.
Even if it is a pain to work out, we should estimate what it means to
use force mode wrt to how fast a single sample can be obtain.
It may be that is such that we don't bother with the other slow sampling
frequency modes if they are slower as they aren't useful vs only reading
when we want to.
Jonathan
>
>
> Regards,
> Achim.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-03 14:08 ` [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings " Achim Gratz
2025-08-03 20:28 ` Andy Shevchenko
@ 2025-08-10 18:13 ` Jonathan Cameron
2025-08-10 19:01 ` ASSI
1 sibling, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-10 18:13 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 3 Aug 2025 16:08:00 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> These devices were using a hardcoded IIR filter of length 4. Enable
> filter_low_pass_3db_frequency settings to control the filter length
> settings of the device (as done already for the BMx380 and BMx580
> devices, even though the 3dB corner has an inverse relation to the
> filter length). Remove an offset of 1 from the internal handling of
> the available values.
This confuses me. Are we saying those other devices have a 3db frequency
control that is not obeying the ABI? If so that sneaked in past me but
please don't continue that (and we should fix that broken use of the ABI).
Jonathan
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
> ---
> drivers/iio/pressure/bmp280-core.c | 36 +++++++++++++++++++++---------
> 1 file changed, 25 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 4efdbfc3ac2c..b3dcee3fe9b3 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -185,7 +185,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
> BIT(IIO_CHAN_INFO_RAW) |
> BIT(IIO_CHAN_INFO_SCALE) |
> BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
> .scan_index = 0,
> .scan_type = {
> .sign = 'u',
> @@ -201,7 +202,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
> BIT(IIO_CHAN_INFO_RAW) |
> BIT(IIO_CHAN_INFO_SCALE) |
> BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
> .scan_index = 1,
> .scan_type = {
> .sign = 's',
> @@ -221,7 +223,8 @@ static const struct iio_chan_spec bme280_channels[] = {
> BIT(IIO_CHAN_INFO_RAW) |
> BIT(IIO_CHAN_INFO_SCALE) |
> BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
> .scan_index = 0,
> .scan_type = {
> .sign = 'u',
> @@ -237,7 +240,8 @@ static const struct iio_chan_spec bme280_channels[] = {
> BIT(IIO_CHAN_INFO_RAW) |
> BIT(IIO_CHAN_INFO_SCALE) |
> BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
> .scan_index = 1,
> .scan_type = {
> .sign = 's',
> @@ -253,7 +257,8 @@ static const struct iio_chan_spec bme280_channels[] = {
> BIT(IIO_CHAN_INFO_RAW) |
> BIT(IIO_CHAN_INFO_SCALE) |
> BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
> - .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ),
> + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
> + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
> .scan_index = 2,
> .scan_type = {
> .sign = 'u',
> @@ -856,7 +861,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> if (!data->chip_info->iir_filter_coeffs_avail)
> return -EINVAL;
>
> - *val = (1 << data->iir_filter_coeff) - 1;
> + *val = data->chip_info->iir_filter_coeffs_avail[data->iir_filter_coeff];
> return IIO_VAL_INT;
> default:
> return -EINVAL;
> @@ -999,7 +1004,7 @@ static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val)
> int i;
>
> for (i = 0; i < n; i++) {
> - if (avail[i] - 1 == val) {
> + if (avail[i] == val) {
> prev = data->iir_filter_coeff;
> data->iir_filter_coeff = i;
>
> @@ -1281,9 +1286,9 @@ static int bmp280_chip_config(struct bmp280_data *data)
> }
>
> ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
> - BMP280_FILTER_MASK |
> - BMP280_TSTBY_MASK,
> - tstby | BMP280_FILTER_4X);
> + BMP280_TSTBY_MASK |
> + BMP280_FILTER_MASK,
> + tstby | data->iir_filter_coeff);
> if (ret) {
> dev_err(data->dev, "failed to write config register\n");
> return ret;
> @@ -1348,6 +1353,7 @@ static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
> static const u8 bmp280_chip_ids[] = { BMP280_CHIP_ID };
> static const int bmp280_temp_coeffs[] = { 10, 1 };
> static const int bmp280_press_coeffs[] = { 1, 256000 };
> +static const int bmp280_iir_filter_coeffs_avail[] = { 0, 2, 4, 8, 16 };
>
> const struct bmp280_chip_info bmp280_chip_info = {
> .id_reg = BMP280_REG_ID,
> @@ -1381,6 +1387,10 @@ const struct bmp280_chip_info bmp280_chip_info = {
> .num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
> .sampling_freq_default = BMP280_ODR_0HZ, /* MODE_FORCED */
>
> + .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
> + .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
> + .iir_filter_coeff_default = 2,
> +
> .temp_coeffs = bmp280_temp_coeffs,
> .temp_coeffs_type = IIO_VAL_FRACTIONAL,
> .press_coeffs = bmp280_press_coeffs,
> @@ -1567,6 +1577,10 @@ const struct bmp280_chip_info bme280_chip_info = {
> .num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
> .sampling_freq_default = BME280_ODR_0HZ, /* MODE_FORCED */
>
> + .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
> + .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
> + .iir_filter_coeff_default = 2,
> +
> .temp_coeffs = bmp280_temp_coeffs,
> .temp_coeffs_type = IIO_VAL_FRACTIONAL,
> .press_coeffs = bmp280_press_coeffs,
> @@ -2155,7 +2169,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
> }
>
> static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 };
> -static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128};
> +static const int bmp380_iir_filter_coeffs_avail[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
> static const u8 bmp380_chip_ids[] = { BMP380_CHIP_ID, BMP390_CHIP_ID };
> static const int bmp380_temp_coeffs[] = { 10, 1 };
> static const int bmp380_press_coeffs[] = { 1, 100000 };
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication
2025-08-03 14:08 ` [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication Achim Gratz
2025-08-03 20:30 ` Andy Shevchenko
@ 2025-08-10 18:19 ` Jonathan Cameron
1 sibling, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-10 18:19 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 3 Aug 2025 16:08:01 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Refactor to get rid of duplicated code.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Hmm. I can't remember the history of this, but I guess this was a driver
that got in with a _PROCESSED interface when it shouldn't have done
(As we don't normally do raw and processed except when things are non linear
and there are events involved).
whilst it saves quite a bit of code I'm not sure it is worth while. Kind of
depends on what happens with the earlier patch.
One comment inline.
Thanks,
Jonathan
> ---
> drivers/iio/pressure/bmp280-core.c | 89 +++++-------------------------
> 1 file changed, 15 insertions(+), 74 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index b3dcee3fe9b3..5cdaf7516940 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -658,6 +658,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> int prev_oversampling_humid, prev_oversampling_press, prev_oversampling_temp;
> int temp_oversampling_humid, temp_oversampling_press, temp_oversampling_temp;
> int switch_off, switch_threshold = -1;
> + int raw = 0;
>
> guard(mutex)(&data->lock);
>
> @@ -668,6 +669,8 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
>
> switch (mask) {
> + case IIO_CHAN_INFO_RAW:
> + raw = 1;
Needs a fall through marking comment (see other code for what that looks like)
or the static anaylsis tools will send us lots of bug reports.
> case IIO_CHAN_INFO_PROCESSED:
> switch_off = 0;
> if (data->op_mode == BMP280_FORCED) {
> @@ -723,6 +726,10 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> if (ret)
> return ret;
>
> + if (raw) {
> + *val = chan_value;
> + return IIO_VAL_INT;
> + }
> *val = data->chip_info->humid_coeffs[0] * chan_value;
> *val2 = data->chip_info->humid_coeffs[1];
> return data->chip_info->humid_coeffs_type;
> @@ -731,6 +738,10 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> if (ret)
> return ret;
>
> + if (raw) {
> + *val = chan_value;
> + return IIO_VAL_INT;
> + }
> *val = data->chip_info->press_coeffs[0] * chan_value;
> *val2 = data->chip_info->press_coeffs[1];
> return data->chip_info->press_coeffs_type;
> @@ -739,86 +750,16 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> if (ret)
> return ret;
>
> + if (raw) {
> + *val = chan_value;
> + return IIO_VAL_INT;
> + }
> *val = data->chip_info->temp_coeffs[0] * chan_value;
> *val2 = data->chip_info->temp_coeffs[1];
> return data->chip_info->temp_coeffs_type;
> default:
> return -EINVAL;
> }
> - case IIO_CHAN_INFO_RAW:
> - switch_off = 0;
> - if (data->op_mode == BMP280_FORCED) {
> - /* MODE_FORCED, switch off unused channels */
> - switch (chan->type) {
> - case IIO_HUMIDITYRELATIVE:
> - temp_oversampling_press = 0-1;
> - switch_off |= (prev_oversampling_press > switch_threshold);
> - /* can't be switched off as it is needed for compensation */
> - temp_oversampling_temp = 1-1;
> - break;
> - case IIO_PRESSURE:
> - temp_oversampling_humid = 0-1;
> - switch_off |= (prev_oversampling_humid > switch_threshold);
> - /* can't be switched off as it is needed for compensation */
> - temp_oversampling_temp = 1-1;
> - break;
> - case IIO_TEMP:
> - temp_oversampling_humid = 0-1;
> - temp_oversampling_press = 0-1;
> - switch_off = (prev_oversampling_humid > switch_threshold) |
> - (prev_oversampling_press > switch_threshold);
> - break;
> - default:
> - return -EINVAL;
> - }
> - }
> - if (switch_off) {
> - data->oversampling_humid = temp_oversampling_humid;
> - data->oversampling_press = temp_oversampling_press;
> - data->oversampling_temp = temp_oversampling_temp;
> - ret = data->chip_info->chip_config(data);
> - if (ret)
> - goto restore;
> - }
> -
> - ret = data->chip_info->wait_conv(data);
> - if (ret)
> - goto restore;
> -
> - if (switch_off) {
> - data->oversampling_humid = prev_oversampling_humid;
> - data->oversampling_press = prev_oversampling_press;
> - data->oversampling_temp = prev_oversampling_temp;
> - data->chip_info->chip_config(data);
> - if (ret)
> - return ret;
> - }
> -
> - switch (chan->type) {
> - case IIO_HUMIDITYRELATIVE:
> - ret = data->chip_info->read_humid(data, &chan_value);
> - if (ret)
> - return ret;
> -
> - *val = chan_value;
> - return IIO_VAL_INT;
> - case IIO_PRESSURE:
> - ret = data->chip_info->read_press(data, &chan_value);
> - if (ret)
> - return ret;
> -
> - *val = chan_value;
> - return IIO_VAL_INT;
> - case IIO_TEMP:
> - ret = data->chip_info->read_temp(data, &chan_value);
> - if (ret)
> - return ret;
> -
> - *val = chan_value;
> - return IIO_VAL_INT;
> - default:
> - return -EINVAL;
> - }
> case IIO_CHAN_INFO_SCALE:
> switch (chan->type) {
> case IIO_HUMIDITYRELATIVE:
^ permalink raw reply [flat|nested] 71+ messages in thread
* [RFC PATCH v2 0/9] Fixes and enhancements for the bmp280 driver
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
` (5 preceding siblings ...)
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
` (10 more replies)
6 siblings, 11 replies; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Revision History:
=================
v1:
- initial proposal, incorrectly prefixed "bmp280" instead of "RFC PATCH"
- patch series presented in the order it was created
v1 -> v2:
- prefix as "RFC PATCH"
- drop channel switching
- rewrite to present patches in smaller units and in logical steps
With v6.13 a change was made to the bmp280 drivers to use MODE_FORCED
instead of MODE_NORMAL. This broke userspace functionality: reading
from sysfs interfaces no longer worked and an error was thrown
"Measurement cycle didn't complete". This series fixes the underlying
bugs affecting the measurement time calculation and implements
additional functionality not available for the BMx280 devices
previously to allow the use of the sysfs interface in MODE_NORMAL
again and control the corresponding parameters. The implementation
follows the already existing facilities for the BMx[35]80 devices even
though the actual functionality of the BMx280 devices is slightly
different.
Achim Gratz (9):
iio: pressure: bmp280: correct meas_time_us calculation
iio: pressure: bmp280: implement adaptive wait for BMx280 devices
iio: pressure: bmp280: implement adaptive wait for BMP380 devices
iio: pressure: bmp280: refactoring
iio: pressure: bmp280: remove code duplication
iio: pressure: bmp280: enable filter settings for BMx280
iio: pressure: bmp280: implement sampling_frequency for BMx280
iio: pressure: bmp280: implement sampling_frequency calculation for
BMx280
iio: pressure: bmp280: test longer autosuspend (WIP)
drivers/iio/pressure/bmp280-core.c | 350 +++++++++++++++++++++++------
drivers/iio/pressure/bmp280.h | 22 ++
2 files changed, 300 insertions(+), 72 deletions(-)
---
Comments:
Thanks for allo the comments on my v1 patch series. I have not seen
any reaction to my on-list replies however, so it appears y'all are
expecting to Cc: everyone involved?
I've just seen new responses from James, but these are not taken into
account for v2 obviously.
The dropped channel switching code may be revisited / resurrected at a
later time. However it can not fully achieve what I want anyway for
how I use the sensor and the later implemented controls for several
sensor parameters get the desired performance back.
The remaining sticky point is the control of the autosuspend delay.
If the sensor is suspended between measurements, then even when it is
operating in MODE_NORMAL, an additional latency of 12…15ms is incured
when the interval between measurements is long enough to trigger
autosuspend. I have set the hardcoded value to 2s as a test (see the
last patch in the series) and this additional latency vanishes,
interestingly also the tailing to long measurement times I have
observed otherwise is also much reduced. However so far I've not come
up with an idea of how to control the autosuspend delay from
userspace, to wit:
/sys/bus/iio/devices/iio:device0/power/async: disabled
/sys/bus/iio/devices/iio:device0/power/autosuspend_delay_ms:
'/sys/bus/iio/devices/iio:device0/power/autosuspend_delay_ms': Input/output error
/sys/bus/iio/devices/iio:device0/power/control: auto
/sys/bus/iio/devices/iio:device0/power/runtime_active_kids: 0
/sys/bus/iio/devices/iio:device0/power/runtime_active_time: 0
/sys/bus/iio/devices/iio:device0/power/runtime_enabled: disabled
/sys/bus/iio/devices/iio:device0/power/runtime_status: unsupported
/sys/bus/iio/devices/iio:device0/power/runtime_suspended_time: 0
/sys/bus/iio/devices/iio:device0/power/runtime_usage: 0
-rw-r--r-- 1 root root 4096 Aug 10 18:41 async
-rw-r--r-- 1 root root 4096 Aug 10 18:41 autosuspend_delay_ms
-rw-r--r-- 1 root root 4096 Aug 10 18:41 control
-r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_active_kids
-r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_active_time
-r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_enabled
-r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_status
-r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_suspended_time
-r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_usage
…which according to the kernel documentation is due to a lack of
unspecified support from the driver. Now, it appears I should be able
to switch off autosuspend altogether by changing control from "auto"
to "on", but that doesn't seem to take effect; also I'd rather
configure a sensible value in accordance to my measurement settings.
The other handful of IIO drivers I've looked at that set this
parameter don't do things differently, so I don't know if there's
anything that can be done about it.
--
2.50.1
^ permalink raw reply [flat|nested] 71+ messages in thread
* [RFC PATCH v2 1/9] iio: pressure: bmp280: correct meas_time_us calculation
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-17 15:16 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices Achim Gratz
` (9 subsequent siblings)
10 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Correction of meas_time_us initialization based on an observation and
partial patch by David Lechner.
There was also a thinko in bmp280_wait_conv: data->oversampling_humid
can actually be 0 (for an oversampling_ratio of 1), so it can not be
used to detect the presence of the humidity measurement capability.
Use data->chip_info->oversampling_humid_avail instead, which is NULL
for chips that cannot measure humidity and therefore need to skip that
part of the calculation.
Closes: https://lore.kernel.org/linux-iio/875xgfg0wz.fsf@Gerda.invalid/
Fixes: 26ccfaa9ddaa ("iio: pressure: bmp280: Use sleep and forced mode for oneshot captures")
Suggested-by: David Lechner <dlechner@baylibre.com>
Tested-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
Notes
=====
Since the BMx280 device support was added, oversampling=0
actually is a valid setting (meaning that measurement channel is off),
but actually allowing that setting to be used by changing the data
structure to hold the actual value instead of its ilog2 would require
more extensive changes elsewhere in the code.
Further changes would be necesary to avoid the awkward use of -1 as
the value that would currently be necessary to achieve a setting of 0
in the register.
Datasheet values and median actual measurement times through sysfs for
a single reading with my BME280 connected to a 400kHz I²C bus provided
by the i915 IGP VGA port:
|--------------+---------+---------+----------+----------|
| Oversampling | Typical | Maximum | Measured | Overhead |
| Ratio | [ms] | [ms] | [ms] | [ms] |
|--------------+---------+---------+----------+----------|
| 16 | 98.0 | 112.8 | 122.1 | 9.3 |
| 8 | 50.0 | 57.6 | 63.6 | 6.0 |
| 4 | 26.0 | 30.0 | 34.6 | 4.6 |
| 2 | 14.0 | 16.2 | 21.7 | 5.5 |
| 1 | 8.0 | 9.3 | 14.8 | 5.5 |
|--------------+---------+---------+----------+----------|
Reading all three channels via sysfs triples those times, including
the overhead of course.
It is also impossible to obtain all three values from
the same measurement with MODE_FORCED, which is in a way a limitation
of the sysfs interface AFAIU.
---
drivers/iio/pressure/bmp280-core.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index f37f20776c89..5bec63c1bc11 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1042,13 +1042,16 @@ static int bmp280_wait_conv(struct bmp280_data *data)
unsigned int reg, meas_time_us;
int ret;
- /* Check if we are using a BME280 device */
- if (data->oversampling_humid)
- meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
- BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
+ /* Constant part of the measurement time */
+ meas_time_us = BMP280_MEAS_OFFSET;
- else
- meas_time_us = 0;
+ /*
+ * Check if we are using a BME280 device,
+ * Humidity measurement time
+ */
+ if (data->chip_info->oversampling_humid_avail)
+ meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
+ BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
/* Pressure measurement time */
meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-10 19:49 ` Andy Shevchenko
2025-08-10 18:58 ` [RFC PATCH v2 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices Achim Gratz
` (8 subsequent siblings)
10 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Currently the measurement wait time is fixed at the maximum value
according to the datasheet, resulting in about 15% overhead compared
the typical values. Implement an adaptive wait that uses
regmap_read_poll_timeout() and optimize the polling parameters so that
the overhead is reduced.
Link: https://lore.kernel.org/linux-iio/CAHp75VfQxSgQwJQsym9X58G6o4UUgz6EQ4ouhhx82aOHv_if2g@mail.gmail.com/
Suggested-by: Andy Shevchenko <andy@kernel.org>
Tested-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
Notes
=====
Datasheet values and median actual measurement times through sysfs for
a single reading with my BME280 connected to a 400kHz I²C bus provided
by the i915 IGP VGA port:
|--------------+---------+---------+-----------+----------+---------+----------+--------+----------+--------+----------|
| Oversampling | Typical | Maximum | Wait Full | Overhead | 2x@20ms | Overhead | 2x@4ms | Overhead | 2x@2ms | Overhead |
| Ratio | [ms] | [ms] | [ms] | [ms] | [ms] | [ms] | [ms] | [ms] | [ms] | [ms] |
|--------------+---------+---------+-----------+----------+---------+----------+--------+----------+--------+----------|
| 16 | 98.0 | 112.8 | 122.1 | 9.3 | 106.2 | -6.6 | 102.8 | -10.0 | 103.0 | -9.8 |
| 8 | 50.0 | 57.6 | 63.6 | 6.0 | 58.7 | 1.1 | 55.8 | -1.8 | 54.0 | -3.6 |
| 4 | 26.0 | 30.0 | 34.6 | 4.6 | 31.8 | 1.8 | 30.8 | 0.8 | 30.6 | 0.6 |
| 2 | 14.0 | 16.2 | 21.7 | 5.5 | 19.3 | 3.1 | 18.9 | 2.7 | 18.7 | 2.5 |
| 1 | 8.0 | 9.3 | 14.8 | 5.5 | 12.9 | 3.6 | 13.3 | 4.0 | 12.9 | 3.6 |
|--------------+---------+---------+-----------+----------+---------+----------+--------+----------+--------+----------|
---
drivers/iio/pressure/bmp280-core.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 5bec63c1bc11..e09e6b396a6f 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1039,7 +1039,7 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
static int bmp280_wait_conv(struct bmp280_data *data)
{
- unsigned int reg, meas_time_us;
+ unsigned int reg, meas_time_us, initial_wait;
int ret;
/* Constant part of the measurement time */
@@ -1060,10 +1060,23 @@ static int bmp280_wait_conv(struct bmp280_data *data)
/* Temperature measurement time */
meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
- /* Waiting time according to the BM(P/E)2 Sensor API */
- fsleep(meas_time_us);
-
- ret = regmap_read(data->regmap, BMP280_REG_STATUS, ®);
+ /*
+ * Split the wait into an initial wait of ~94% of the typical
+ * measurement time (which is ~87% of the maximum measurement
+ * time we have calculated) and then use a polling wait until
+ * the measurement finishes. Provide 2ms extra slack in the
+ * timeout value to compensate for any error in accumulated
+ * actual wait time. Minimum two poll cycles, but maximum 2ms
+ * duration where found to be the best compromise in overhead
+ * over a range of oversampling settings.
+ */
+ initial_wait = (13 * meas_time_us) / 16;
+ fsleep(initial_wait);
+ meas_time_us -= initial_wait;
+ ret = regmap_read_poll_timeout(data->regmap, BMP280_REG_STATUS, reg,
+ !(reg & BMP280_REG_STATUS_MEAS_BIT),
+ MIN((2 * USEC_PER_MSEC), (meas_time_us >> 1)),
+ (2 * USEC_PER_MSEC + meas_time_us));
if (ret) {
dev_err(data->dev, "failed to read status register.\n");
return ret;
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 4/9] iio: pressure: bmp280: refactoring Achim Gratz
` (7 subsequent siblings)
10 siblings, 0 replies; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Use same solution as for BMx280 devices. The variable meas_time_us is
changed to unsigned int in all *_wait_conv() implementations.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 23 ++++++++++++++---------
1 file changed, 14 insertions(+), 9 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index e09e6b396a6f..7630c9d1265a 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1714,8 +1714,8 @@ static int bmp380_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
static int bmp380_wait_conv(struct bmp280_data *data)
{
- unsigned int reg;
- int ret, meas_time_us;
+ unsigned int reg, meas_time_us, initial_wait;
+ int ret;
/* Offset measurement time */
meas_time_us = BMP380_MEAS_OFFSET;
@@ -1728,10 +1728,15 @@ static int bmp380_wait_conv(struct bmp280_data *data)
meas_time_us += BMP380_TEMP_MEAS_OFFSET +
BIT(data->oversampling_temp) * BMP380_MEAS_DUR;
- /* Measurement time defined in Datasheet Section 3.9.2 */
- fsleep(meas_time_us);
-
- ret = regmap_read(data->regmap, BMP380_REG_STATUS, ®);
+ /* See bmp280_wait_conv() */
+ initial_wait = (13 * meas_time_us) / 16;
+ fsleep(initial_wait);
+ meas_time_us -= initial_wait;
+ ret = regmap_read_poll_timeout(data->regmap, BMP280_REG_STATUS, reg,
+ !((reg & BMP380_STATUS_DRDY_PRESS_MASK) &&
+ (reg & BMP380_STATUS_DRDY_TEMP_MASK)),
+ MIN((2 * USEC_PER_MSEC), (meas_time_us >> 1)),
+ (2 * USEC_PER_MSEC + meas_time_us));
if (ret) {
dev_err(data->dev, "failed to read status register.\n");
return ret;
@@ -2442,15 +2447,15 @@ static int bmp580_wait_conv(struct bmp280_data *data)
* Taken from datasheet, Section 2 "Specification, Table 3 "Electrical
* characteristics.
*/
- static const int time_conv_press[] = {
+ static const unsigned int time_conv_press[] = {
0, 1050, 1785, 3045, 5670, 10920, 21420, 42420,
84420,
};
- static const int time_conv_temp[] = {
+ static const unsigned int time_conv_temp[] = {
0, 1050, 1105, 1575, 2205, 3465, 6090, 11340,
21840,
};
- int meas_time_us;
+ unsigned int meas_time_us;
meas_time_us = 4 * USEC_PER_MSEC +
time_conv_temp[data->oversampling_temp] +
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 4/9] iio: pressure: bmp280: refactoring
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (2 preceding siblings ...)
2025-08-10 18:58 ` [RFC PATCH v2 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-17 15:23 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 5/9] iio: pressure: bmp280: remove code duplication Achim Gratz
` (6 subsequent siblings)
10 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Refactor the measurement time calculation into a new function
bmp280_calc_meas_time_us() and use it in bmp280_wait_conv(). This is
currently the only consumer of this value, however calculation of
output data rate values will also require it. As already commented in
bm280.h:468, but not actually implemented for the BMx280 devices,
sampling_frequency can be emulated indirectly via t_standby
configuration.
Also move the setting of BMP280_MODE_FORCED from
bmp280_read_raw_impl() into bmp[235]80_wait_conv(), as the measurement
cannot be started without having set the mode immediately before
starting the wait, so .wait_conv() should not have to rely on getting
called in the right context. No mode setting is required for BMP180,
which only has a dummy bmp180_wait_conv() implementation anyway.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 50 +++++++++++++++++++++++-------
1 file changed, 39 insertions(+), 11 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 7630c9d1265a..4f5982a36200 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -624,10 +624,6 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- return ret;
-
ret = data->chip_info->wait_conv(data);
if (ret)
return ret;
@@ -661,10 +657,6 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_RAW:
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
- if (ret)
- return ret;
-
ret = data->chip_info->wait_conv(data);
if (ret)
return ret;
@@ -1037,10 +1029,9 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
return 0;
}
-static int bmp280_wait_conv(struct bmp280_data *data)
+static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
{
- unsigned int reg, meas_time_us, initial_wait;
- int ret;
+ unsigned int meas_time_us;
/* Constant part of the measurement time */
meas_time_us = BMP280_MEAS_OFFSET;
@@ -1060,6 +1051,24 @@ static int bmp280_wait_conv(struct bmp280_data *data)
/* Temperature measurement time */
meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
+ /* Waiting time according to the BM(P/E)2 Sensor API (maximum value) */
+ return meas_time_us;
+}
+
+static int bmp280_wait_conv(struct bmp280_data *data)
+{
+ unsigned int reg, meas_time_us, initial_wait;
+ int ret;
+
+ /*
+ * Each new measurement requires mode setting, as at the end
+ * of the measurement cycle the sensor enters MODE_SLEEP
+ * again.
+ */
+ ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ if (ret)
+ return ret;
+
/*
* Split the wait into an initial wait of ~94% of the typical
* measurement time (which is ~87% of the maximum measurement
@@ -1070,6 +1079,7 @@ static int bmp280_wait_conv(struct bmp280_data *data)
* duration where found to be the best compromise in overhead
* over a range of oversampling settings.
*/
+ meas_time_us = bmp280_calc_meas_time_us(data);
initial_wait = (13 * meas_time_us) / 16;
fsleep(initial_wait);
meas_time_us -= initial_wait;
@@ -1717,6 +1727,15 @@ static int bmp380_wait_conv(struct bmp280_data *data)
unsigned int reg, meas_time_us, initial_wait;
int ret;
+ /*
+ * Each new measurement requires mode setting, as at the end
+ * of the measurement cycle the sensor enters MODE_SLEEP
+ * again.
+ */
+ ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ if (ret)
+ return ret;
+
/* Offset measurement time */
meas_time_us = BMP380_MEAS_OFFSET;
@@ -2457,6 +2476,15 @@ static int bmp580_wait_conv(struct bmp280_data *data)
};
unsigned int meas_time_us;
+ /*
+ * Each new measurement requires mode setting, as at the end
+ * of the measurement cycle the sensor enters MODE_SLEEP
+ * again.
+ */
+ ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ if (ret)
+ return ret;
+
meas_time_us = 4 * USEC_PER_MSEC +
time_conv_temp[data->oversampling_temp] +
time_conv_press[data->oversampling_press];
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 5/9] iio: pressure: bmp280: remove code duplication
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (3 preceding siblings ...)
2025-08-10 18:58 ` [RFC PATCH v2 4/9] iio: pressure: bmp280: refactoring Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
` (5 subsequent siblings)
10 siblings, 0 replies; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Eliminate code duplication from bmp280_read_raw_impl() by handling raw
and processed channel reads together. The decision about which data format
to output is pre-computed in bool info_raw so that the switch
statement needs no fallthrough macro.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 46 +++++++++++-------------------
1 file changed, 16 insertions(+), 30 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 4f5982a36200..fbecee9928e8 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -619,10 +619,12 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
struct bmp280_data *data = iio_priv(indio_dev);
int chan_value;
int ret;
+ bool info_raw = mask & IIO_CHAN_INFO_RAW;
guard(mutex)(&data->lock);
switch (mask) {
+ case IIO_CHAN_INFO_RAW:
case IIO_CHAN_INFO_PROCESSED:
ret = data->chip_info->wait_conv(data);
if (ret)
@@ -634,6 +636,11 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (ret)
return ret;
+ if (info_raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ }
+
*val = data->chip_info->humid_coeffs[0] * chan_value;
*val2 = data->chip_info->humid_coeffs[1];
return data->chip_info->humid_coeffs_type;
@@ -642,6 +649,10 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (ret)
return ret;
+ if (info_raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ }
*val = data->chip_info->press_coeffs[0] * chan_value;
*val2 = data->chip_info->press_coeffs[1];
return data->chip_info->press_coeffs_type;
@@ -650,42 +661,17 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (ret)
return ret;
+ if (info_raw) {
+ *val = chan_value;
+ return IIO_VAL_INT;
+ }
+
*val = data->chip_info->temp_coeffs[0] * chan_value;
*val2 = data->chip_info->temp_coeffs[1];
return data->chip_info->temp_coeffs_type;
default:
return -EINVAL;
}
- case IIO_CHAN_INFO_RAW:
- ret = data->chip_info->wait_conv(data);
- if (ret)
- return ret;
-
- switch (chan->type) {
- case IIO_HUMIDITYRELATIVE:
- ret = data->chip_info->read_humid(data, &chan_value);
- if (ret)
- return ret;
-
- *val = chan_value;
- return IIO_VAL_INT;
- case IIO_PRESSURE:
- ret = data->chip_info->read_press(data, &chan_value);
- if (ret)
- return ret;
-
- *val = chan_value;
- return IIO_VAL_INT;
- case IIO_TEMP:
- ret = data->chip_info->read_temp(data, &chan_value);
- if (ret)
- return ret;
-
- *val = chan_value;
- return IIO_VAL_INT;
- default:
- return -EINVAL;
- }
case IIO_CHAN_INFO_SCALE:
switch (chan->type) {
case IIO_HUMIDITYRELATIVE:
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 6/9] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (4 preceding siblings ...)
2025-08-10 18:58 ` [RFC PATCH v2 5/9] iio: pressure: bmp280: remove code duplication Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-17 16:37 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
` (4 subsequent siblings)
10 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
These devices were using a hardcoded IIR filter of length 4. Enable
filter_low_pass_3db_frequency settings to control the filter length
settings of the device as done already for the BMx380 and BMx580
devices, even though the 3dB corner has an inverse relation to the
filter length. Remove a superfluous offset of -1 from the internal
handling of the available values and use the table entries directly.
Keep the default value at the previous hardcoded value to keep
identical device behaviour after module load.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 22 ++++++++++++++++++----
1 file changed, 18 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index fbecee9928e8..0ee40b6abb44 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -159,6 +159,7 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -174,6 +175,7 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -193,6 +195,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -208,6 +211,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -223,6 +227,7 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 2,
.scan_type = {
.sign = 'u',
@@ -714,7 +719,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
if (!data->chip_info->iir_filter_coeffs_avail)
return -EINVAL;
- *val = (1 << data->iir_filter_coeff) - 1;
+ *val = data->chip_info->iir_filter_coeffs_avail[data->iir_filter_coeff];
return IIO_VAL_INT;
default:
return -EINVAL;
@@ -844,7 +849,7 @@ static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val)
int i;
for (i = 0; i < n; i++) {
- if (avail[i] - 1 == val) {
+ if (avail[i] == val) {
prev = data->iir_filter_coeff;
data->iir_filter_coeff = i;
@@ -1104,7 +1109,7 @@ static int bmp280_chip_config(struct bmp280_data *data)
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
BMP280_FILTER_MASK,
- BMP280_FILTER_4X);
+ data->iir_filter_coeff);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1169,6 +1174,7 @@ static const int bmp280_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static const u8 bmp280_chip_ids[] = { BMP280_CHIP_ID };
static const int bmp280_temp_coeffs[] = { 10, 1 };
static const int bmp280_press_coeffs[] = { 1, 256000 };
+static const int bmp280_iir_filter_coeffs_avail[] = { 0, 2, 4, 8, 16 };
const struct bmp280_chip_info bmp280_chip_info = {
.id_reg = BMP280_REG_ID,
@@ -1198,6 +1204,10 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_press_default = BMP280_OSRS_PRESS_16X - 1,
+ .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
+ .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
+ .iir_filter_coeff_default = 2,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1383,6 +1393,10 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
.oversampling_humid_default = BME280_OSRS_HUMIDITY_16X - 1,
+ .iir_filter_coeffs_avail = bmp280_iir_filter_coeffs_avail,
+ .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
+ .iir_filter_coeff_default = 2,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1980,7 +1994,7 @@ static irqreturn_t bmp380_trigger_handler(int irq, void *p)
}
static const int bmp380_oversampling_avail[] = { 1, 2, 4, 8, 16, 32 };
-static const int bmp380_iir_filter_coeffs_avail[] = { 1, 2, 4, 8, 16, 32, 64, 128};
+static const int bmp380_iir_filter_coeffs_avail[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
static const u8 bmp380_chip_ids[] = { BMP380_CHIP_ID, BMP390_CHIP_ID };
static const int bmp380_temp_coeffs[] = { 10, 1 };
static const int bmp380_press_coeffs[] = { 1, 100000 };
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 7/9] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (5 preceding siblings ...)
2025-08-10 18:58 ` [RFC PATCH v2 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-17 16:53 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
` (3 subsequent siblings)
10 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
As was already commented in bm280.h:468, sampling_frequency can be
emulated on BMx280 devices indirectly via t_standby configuration.
Actually implement it to enable this useful feature. This allows to
switch between MODE_FORCED and MODE_NORMAL operation and use the same
sysfs read implementations for both modes.
the bmp[235]_wait_conv() functions check if the sensor already
operates in NORMAL_MODE and skips the wait for measurement complettion
unless a mode transition is required to save the overhead of
re-setting the same mode superfluously.
The actual sampling frequency depends on the oversampling_ratio
settings. In order to not complicate the code too much, the available
sampling frequency values are fixed and have been calculated for
oversampling_ratio=1 on all available channels assuming maximum
measurement duration per the data sheet, corresponding to the minimum
achievable sampling frequency for the highest measurement speed
configuration.
THe ODR tables for the BM[35]80 devices have been extended to allow
for MODE_FORCED operation also and the handling of the table values is
adapted accordingly.
Report of the actual sampling frequency via sysfs is possible, but not
yet implemented. In preparation for that implementation the
calculation of measurement time has previously been factored out from
bmp280_wait_conv into bmp280_calc_meas_time_us.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
Calculated ODR values:
|--------+---------+---------|
| t_sb | min ODR | min ODR |
| [ms] | BMP280 | BME280 |
|--------+---------+---------|
| 0 | 155.642 | 107.527 |
| 0.5 | 144.404 | 102.041 |
| 62.5 | 14.509 | 13.928 |
| 125.0 | 7.609 | 7.446 |
| 250.0 | 3.900 | 3.857 |
| 500.0 | 1.975 | 1.963 |
| 1000.0 | 0.994 | 0.991 |
| 2000.0 | 0.498 | 0.498 |
| 4000.0 | 0.250 | 0.249 |
| 10.0 | 60.883 | 51.813 |
| 20.0 | 37.843 | 34.130 |
|--------+---------+---------|
---
drivers/iio/pressure/bmp280-core.c | 165 +++++++++++++++++++++++------
drivers/iio/pressure/bmp280.h | 20 ++++
2 files changed, 155 insertions(+), 30 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 0ee40b6abb44..a66b90b3ddb8 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -64,7 +64,47 @@
*/
enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
+/*
+ * Output Data Rate of 0Hz is indicating operation in MODE_FORCED,
+ * otherwise ODR = 1/(t_meas + t_stby) (rounded down to three digits)
+ *
+ * t_meas is the maximum data sheet value calculated for an
+ * oversampling ratio of 1 for all available channels of the
+ * respective device
+ */
+enum bmp280_odr {
+ BMP280_ODR_0HZ,
+ BMP280_ODR_155HZ, /* t_meas_max = 6.425ms, t_sb = 0.0ms */
+ BMP280_ODR_144HZ, /* t_meas_max = 6.425ms, t_sb = 0.5ms */
+ BMP280_ODR_14_5HZ, /* t_meas_max = 6.425ms, t_sb = 62.5ms */
+ BMP280_ODR_7_60HZ, /* t_meas_max = 6.425ms, t_sb = 125ms */
+ BMP280_ODR_3_90HZ, /* t_meas_max = 6.425ms, t_sb = 250ms */
+ BMP280_ODR_1_97HZ, /* t_meas_max = 6.425ms, t_sb = 500ms */
+ BMP280_ODR_0_99HZ, /* t_meas_max = 6.425ms, t_sb = 1000ms */
+ BMP280_ODR_0_49HZ, /* t_meas_max = 6.425ms, t_sb = 2000ms */
+ BMP280_ODR_0_24HZ, /* t_meas_max = 6.425ms, t_sb = 4000ms */
+};
+
+/*
+ * BME280 redefines the meaning of the last two register settings
+ * vs. BMP280, which are now out of order with the other values but
+ * need to be in that exact position
+ */
+enum bme280_odr {
+ BME280_ODR_0HZ,
+ BME280_ODR_107HZ, /* t_meas_max = 9.300ms, t_sb = 0.5ms */
+ BME280_ODR_102HZ, /* t_meas_max = 9.300ms, t_sb = 0.5ms */
+ BME280_ODR_13_9HZ, /* t_meas_max = 9.300ms, t_sb = 62.5ms */
+ BME280_ODR_7_44HZ, /* t_meas_max = 9.300ms, t_sb = 125ms */
+ BME280_ODR_3_85HZ, /* t_meas_max = 9.300ms, t_sb = 250ms */
+ BME280_ODR_1_96HZ, /* t_meas_max = 9.300ms, t_sb = 500ms */
+ BME280_ODR_0_99HZ, /* t_meas_max = 9.300ms, t_sb = 1000ms */
+ BME280_ODR_51_8HZ, /* t_meas_max = 9.300ms, t_sb = 10ms */
+ BME280_ODR_34_1HZ, /* t_meas_max = 9.300ms, t_sb = 20ms */
+};
+
enum bmp380_odr {
+ BMP380_ODR_0HZ,
BMP380_ODR_200HZ,
BMP380_ODR_100HZ,
BMP380_ODR_50HZ,
@@ -86,6 +126,7 @@ enum bmp380_odr {
};
enum bmp580_odr {
+ BMP580_ODR_0HZ,
BMP580_ODR_240HZ,
BMP580_ODR_218HZ,
BMP580_ODR_199HZ,
@@ -159,7 +200,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -175,7 +217,8 @@ static const struct iio_chan_spec bmp280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -195,7 +238,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 0,
.scan_type = {
.sign = 'u',
@@ -211,7 +255,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 1,
.scan_type = {
.sign = 's',
@@ -227,7 +272,8 @@ static const struct iio_chan_spec bme280_channels[] = {
BIT(IIO_CHAN_INFO_RAW) |
BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
- .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) |
+ BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY),
.scan_index = 2,
.scan_type = {
.sign = 'u',
@@ -816,7 +862,7 @@ static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data,
return -EINVAL;
}
-static int bmp280_write_sampling_frequency(struct bmp280_data *data,
+static int bmp280_write_sampling_freq(struct bmp280_data *data,
int val, int val2)
{
const int (*avail)[2] = data->chip_info->sampling_freq_avail;
@@ -893,7 +939,7 @@ static int bmp280_write_raw_impl(struct iio_dev *indio_dev,
return -EINVAL;
}
case IIO_CHAN_INFO_SAMP_FREQ:
- return bmp280_write_sampling_frequency(data, val, val2);
+ return bmp280_write_sampling_freq(data, val, val2);
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
return bmp280_write_iir_filter_coeffs(data, val);
default:
@@ -971,6 +1017,32 @@ static const unsigned long bme280_avail_scan_masks[] = {
0
};
+static const int bmp280_odr_table[][2] = {
+ [BMP280_ODR_0HZ] = {0, 0},
+ [BMP280_ODR_155HZ] = {155, 0},
+ [BMP280_ODR_144HZ] = {144, 0},
+ [BMP280_ODR_14_5HZ] = {14, 500000},
+ [BMP280_ODR_7_60HZ] = {7, 600000},
+ [BMP280_ODR_3_90HZ] = {3, 900000},
+ [BMP280_ODR_1_97HZ] = {1, 970000},
+ [BMP280_ODR_0_99HZ] = {0, 990000},
+ [BMP280_ODR_0_49HZ] = {0, 490000},
+ [BMP280_ODR_0_24HZ] = {0, 240000},
+};
+
+static const int bme280_odr_table[][2] = {
+ [BME280_ODR_0HZ] = {0, 0},
+ [BME280_ODR_107HZ] = {107, 0},
+ [BME280_ODR_102HZ] = {102, 0},
+ [BME280_ODR_13_9HZ] = {13, 900000},
+ [BME280_ODR_7_44HZ] = {7, 440000},
+ [BME280_ODR_3_85HZ] = {3, 850000},
+ [BME280_ODR_1_96HZ] = {1, 960000},
+ [BME280_ODR_0_99HZ] = {0, 990000},
+ [BME280_ODR_51_8HZ] = {51, 800000},
+ [BME280_ODR_34_1HZ] = {34, 100000},
+};
+
static int bmp280_preinit(struct bmp280_data *data)
{
struct device *dev = data->dev;
@@ -1008,6 +1080,9 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
{
int ret;
+ /* Ensure a mode transition on next measurement if we take an error exit */
+ data->op_mode = BMP280_SLEEP;
+
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
BMP280_MODE_MASK, bmp280_operation_mode[mode]);
if (ret) {
@@ -1051,12 +1126,15 @@ static int bmp280_wait_conv(struct bmp280_data *data)
unsigned int reg, meas_time_us, initial_wait;
int ret;
- /*
- * Each new measurement requires mode setting, as at the end
- * of the measurement cycle the sensor enters MODE_SLEEP
- * again.
- */
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ /* No mode transition and already in NORMAL_MODE, skip wait */
+ if (data->sampling_freq && data->op_mode == BMP280_NORMAL)
+ return 0;
+
+ /* switch mode based on sampling_freq */
+ data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
+
+ /* Mode transition or measurement in MODE_FORCED */
+ ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED);
if (ret)
return ret;
@@ -1078,6 +1156,7 @@ static int bmp280_wait_conv(struct bmp280_data *data)
!(reg & BMP280_REG_STATUS_MEAS_BIT),
MIN((2 * USEC_PER_MSEC), (meas_time_us >> 1)),
(2 * USEC_PER_MSEC + meas_time_us));
+
if (ret) {
dev_err(data->dev, "failed to read status register.\n");
return ret;
@@ -1095,21 +1174,24 @@ static int bmp280_chip_config(struct bmp280_data *data)
{
u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
+ u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK, (data->sampling_freq ?: 1) - 1);
int ret;
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
BMP280_OSRS_TEMP_MASK |
BMP280_OSRS_PRESS_MASK |
BMP280_MODE_MASK,
- osrs | BMP280_MODE_SLEEP);
+ osrs | (data->sampling_freq ? BMP280_NORMAL : BMP280_SLEEP));
+ if (ret)
+ return ret;
if (ret) {
dev_err(data->dev, "failed to write ctrl_meas register\n");
return ret;
}
ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
- BMP280_FILTER_MASK,
- data->iir_filter_coeff);
+ BMP280_FILTER_MASK | BMP280_TSTBY_MASK,
+ tstby | BMP280_FILTER_4X);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1208,6 +1290,10 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
.iir_filter_coeff_default = 2,
+ .sampling_freq_avail = bmp280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
+ .sampling_freq_default = BMP280_ODR_0HZ,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1397,6 +1483,10 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
.iir_filter_coeff_default = 2,
+ .sampling_freq_avail = bme280_odr_table,
+ .num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
+ .sampling_freq_default = BME280_ODR_0HZ,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1727,12 +1817,20 @@ static int bmp380_wait_conv(struct bmp280_data *data)
unsigned int reg, meas_time_us, initial_wait;
int ret;
- /*
- * Each new measurement requires mode setting, as at the end
- * of the measurement cycle the sensor enters MODE_SLEEP
- * again.
- */
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ /* nothing to wait for, read already available data */
+ if (data->op_mode == BMP280_NORMAL)
+ return 0;
+
+ /* switch mode based on sampling_freq */
+ data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
+
+ /* Mode transition or measurement in MODE_FORCED */
+ ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED);
+ if (ret)
+ return ret;
+
+ /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
+ ret = data->chip_info->set_mode(data, data->op_mode);
if (ret)
return ret;
@@ -2475,13 +2573,17 @@ static int bmp580_wait_conv(struct bmp280_data *data)
21840,
};
unsigned int meas_time_us;
+ int ret;
- /*
- * Each new measurement requires mode setting, as at the end
- * of the measurement cycle the sensor enters MODE_SLEEP
- * again.
- */
- ret = data->chip_info->set_mode(data, BMP280_FORCED);
+ /* nothing to wait for, read already available data */
+ if (data->op_mode == BMP280_NORMAL)
+ return 0;
+
+ /* switch mode based on sammpling_freq */
+ data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
+
+ /* Mode transition or measurement in MODE_FORCED */
+ ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED);
if (ret)
return ret;
@@ -3363,10 +3465,13 @@ static int bmp280_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct bmp280_data *data = iio_priv(indio_dev);
-
- data->chip_info->set_mode(data, BMP280_SLEEP);
+ int ret;
fsleep(data->start_up_time_us);
+ ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_SLEEP);
+ if (ret)
+ return ret;
+
return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies);
}
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 25bb9c743a05..c15d0c74d4b6 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -248,6 +248,16 @@
#define BMP280_FILTER_8X 3
#define BMP280_FILTER_16X 4
+#define BMP280_TSTBY_MASK GENMASK(7, 5)
+#define BMP280_TSTBY_0_5 0
+#define BMP280_TSTBY_62_5 1
+#define BMP280_TSTBY_125 2
+#define BMP280_TSTBY_250 3
+#define BMP280_TSTBY_500 4
+#define BMP280_TSTBY_1000 5
+#define BMP280_TSTBY_2000 6
+#define BMP280_TSTBY_4000 7
+
#define BMP280_OSRS_TEMP_MASK GENMASK(7, 5)
#define BMP280_OSRS_TEMP_SKIP 0
#define BMP280_OSRS_TEMP_1X 1
@@ -294,6 +304,16 @@
#define BME280_CONTIGUOUS_CALIB_REGS 7
+#define BME280_TSTBY_MASK GENMASK(7, 5)
+#define BME280_TSTBY_0_5 0
+#define BME280_TSTBY_62_5 1
+#define BME280_TSTBY_125 2
+#define BME280_TSTBY_250 3
+#define BME280_TSTBY_500 4
+#define BME280_TSTBY_1000 5
+#define BME280_TSTBY_1 6
+#define BME280_TSTBY_20 7
+
#define BME280_OSRS_HUMIDITY_MASK GENMASK(2, 0)
#define BME280_OSRS_HUMIDITY_SKIP 0
#define BME280_OSRS_HUMIDITY_1X 1
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (6 preceding siblings ...)
2025-08-10 18:58 ` [RFC PATCH v2 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-17 17:04 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 9/9] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
` (2 subsequent siblings)
10 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Report of the actual sampling frequency via sysfs is implemented based
on the maximum measurement cycle time, depending on oversampling_ratio
and t_standby settings. If the device dependent table for the
t_standby values is missing, the reported value is taken from the ODR
table as before, which enables the support for the BMx[35]80 devices
to be unchanged.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 58 +++++++++++++++++++++++++++---
drivers/iio/pressure/bmp280.h | 2 ++
2 files changed, 56 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index a66b90b3ddb8..5c4126e4eccd 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -55,6 +55,7 @@
#include <linux/iio/triggered_buffer.h>
#include <linux/unaligned.h>
+#include <linux/units.h>
#include "bmp280.h"
@@ -757,9 +758,7 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_SAMP_FREQ:
if (!data->chip_info->sampling_freq_avail)
return -EINVAL;
-
- *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
- *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
+ data->chip_info->calc_sampling_freq(data, val, val2);
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
if (!data->chip_info->iir_filter_coeffs_avail)
@@ -1029,6 +1028,20 @@ static const int bmp280_odr_table[][2] = {
[BMP280_ODR_0_49HZ] = {0, 490000},
[BMP280_ODR_0_24HZ] = {0, 240000},
};
+static const int bmp280_tstby_table[] = {
+ [BMP280_ODR_0HZ] = 0,
+ [BMP280_ODR_155HZ] = 0,
+ [BMP280_ODR_144HZ] = 500,
+ [BMP280_ODR_14_5HZ] = 62500,
+ [BMP280_ODR_7_60HZ] = 125000,
+ [BMP280_ODR_3_90HZ] = 250000,
+ [BMP280_ODR_1_97HZ] = 500000,
+ [BMP280_ODR_0_99HZ] = 1000000,
+ [BMP280_ODR_0_49HZ] = 2000000,
+ [BMP280_ODR_0_24HZ] = 4000000,
+};
+static_assert(ARRAY_SIZE(bmp280_odr_table) == ARRAY_SIZE(bmp280_tstby_table),
+ "BMP280 ODR and t_stby table sizes don't match!");
static const int bme280_odr_table[][2] = {
[BME280_ODR_0HZ] = {0, 0},
@@ -1042,6 +1055,20 @@ static const int bme280_odr_table[][2] = {
[BME280_ODR_51_8HZ] = {51, 800000},
[BME280_ODR_34_1HZ] = {34, 100000},
};
+static const int bme280_tstby_table[] = {
+ [BME280_ODR_0HZ] = 0,
+ [BME280_ODR_107HZ] = 0,
+ [BME280_ODR_102HZ] = 500,
+ [BME280_ODR_13_9HZ] = 62500,
+ [BME280_ODR_7_44HZ] = 125000,
+ [BME280_ODR_3_85HZ] = 250000,
+ [BME280_ODR_1_96HZ] = 500000,
+ [BME280_ODR_0_99HZ] = 1000000,
+ [BME280_ODR_51_8HZ] = 10000,
+ [BME280_ODR_34_1HZ] = 20000,
+};
+static_assert(ARRAY_SIZE(bme280_odr_table) == ARRAY_SIZE(bme280_tstby_table),
+ "BME280 ODR and t_stby table sizes don't match!");
static int bmp280_preinit(struct bmp280_data *data)
{
@@ -1121,6 +1148,23 @@ static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
return meas_time_us;
}
+static void bmp280_calc_sampling_freq(struct bmp280_data *data, int *val, int *val2)
+{
+ unsigned int cycle_time_us;
+ unsigned long freq_uHz;
+
+ if (data->chip_info->sampling_freq_tstby) {
+ cycle_time_us = bmp280_calc_meas_time_us(data);
+ cycle_time_us += data->chip_info->sampling_freq_tstby[data->sampling_freq];
+ freq_uHz = MICROHZ_PER_HZ*USEC_PER_SEC / cycle_time_us;
+ *val = freq_uHz / MICROHZ_PER_HZ;
+ *val2 = freq_uHz % MICROHZ_PER_HZ;
+ } else {
+ *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0];
+ *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1];
+ }
+}
+
static int bmp280_wait_conv(struct bmp280_data *data)
{
unsigned int reg, meas_time_us, initial_wait;
@@ -1181,7 +1225,9 @@ static int bmp280_chip_config(struct bmp280_data *data)
BMP280_OSRS_TEMP_MASK |
BMP280_OSRS_PRESS_MASK |
BMP280_MODE_MASK,
- osrs | (data->sampling_freq ? BMP280_NORMAL : BMP280_SLEEP));
+ osrs | BMP280_SLEEP);
+ /* Ensure a mode transition on next measurement */
+ data->op_mode = BMP280_SLEEP;
if (ret)
return ret;
if (ret) {
@@ -1290,6 +1336,7 @@ const struct bmp280_chip_info bmp280_chip_info = {
.num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
.iir_filter_coeff_default = 2,
+ .sampling_freq_tstby = bmp280_tstby_table,
.sampling_freq_avail = bmp280_odr_table,
.num_sampling_freq_avail = ARRAY_SIZE(bmp280_odr_table) * 2,
.sampling_freq_default = BMP280_ODR_0HZ,
@@ -1305,6 +1352,7 @@ const struct bmp280_chip_info bmp280_chip_info = {
.read_calib = bmp280_read_calib,
.set_mode = bmp280_set_mode,
.wait_conv = bmp280_wait_conv,
+ .calc_sampling_freq = bmp280_calc_sampling_freq,
.preinit = bmp280_preinit,
.trigger_handler = bmp280_trigger_handler,
@@ -1483,6 +1531,7 @@ const struct bmp280_chip_info bme280_chip_info = {
.num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp280_iir_filter_coeffs_avail),
.iir_filter_coeff_default = 2,
+ .sampling_freq_tstby = bme280_tstby_table,
.sampling_freq_avail = bme280_odr_table,
.num_sampling_freq_avail = ARRAY_SIZE(bme280_odr_table) * 2,
.sampling_freq_default = BME280_ODR_0HZ,
@@ -1501,6 +1550,7 @@ const struct bmp280_chip_info bme280_chip_info = {
.read_calib = bme280_read_calib,
.set_mode = bmp280_set_mode,
.wait_conv = bmp280_wait_conv,
+ .calc_sampling_freq = bmp280_calc_sampling_freq,
.preinit = bmp280_preinit,
.trigger_handler = bme280_trigger_handler,
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index c15d0c74d4b6..19420709162c 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -521,6 +521,7 @@ struct bmp280_chip_info {
int num_iir_filter_coeffs_avail;
int iir_filter_coeff_default;
+ const int *sampling_freq_tstby;
const int (*sampling_freq_avail)[2];
int num_sampling_freq_avail;
int sampling_freq_default;
@@ -540,6 +541,7 @@ struct bmp280_chip_info {
int (*preinit)(struct bmp280_data *data);
int (*set_mode)(struct bmp280_data *data, enum bmp280_op_mode mode);
int (*wait_conv)(struct bmp280_data *data);
+ void (*calc_sampling_freq)(struct bmp280_data *data, int *val, int *val2);
int (*trigger_probe)(struct iio_dev *indio_dev);
irqreturn_t (*trigger_handler)(int irq, void *p);
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* [RFC PATCH v2 9/9] iio: pressure: bmp280: test longer autosuspend (WIP)
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (7 preceding siblings ...)
2025-08-10 18:58 ` [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
@ 2025-08-10 18:58 ` Achim Gratz
2025-08-17 17:05 ` Jonathan Cameron
2025-08-11 12:14 ` [RFC PATCH v2 0/9] Fixes and enhancements for the bmp280 driver Andy Shevchenko
2025-08-11 20:17 ` Jonathan Cameron
10 siblings, 1 reply; 71+ messages in thread
From: Achim Gratz @ 2025-08-10 18:58 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Autosuspend delay should be configurable from sysfs via the power
attributes, but that is apparently not working for me. Since the
standard value for autosuspend_delay is shorter than my typical
measurement period and a suspend/resume incurs both additional latency
and stronger tailing on the acquisition time, monkey-patch a 2s value
in until I can figure out how to do this properly.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 5c4126e4eccd..7d51ab0b92e9 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -3500,6 +3500,8 @@ int bmp280_common_probe(struct device *dev,
* start-up time.
*/
pm_runtime_set_autosuspend_delay(dev, data->start_up_time_us / 10);
+ /* test */
+ pm_runtime_set_autosuspend_delay(dev, 2*MSEC_PER_SEC);
pm_runtime_use_autosuspend(dev);
pm_runtime_put(dev);
--
2.50.1
^ permalink raw reply related [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-10 18:13 ` Jonathan Cameron
@ 2025-08-10 19:01 ` ASSI
2025-08-11 20:14 ` Jonathan Cameron
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-08-10 19:01 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> On Sun, 3 Aug 2025 16:08:00 +0200
> Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
>
>> These devices were using a hardcoded IIR filter of length 4. Enable
>> filter_low_pass_3db_frequency settings to control the filter length
>> settings of the device (as done already for the BMx380 and BMx580
>> devices, even though the 3dB corner has an inverse relation to the
>> filter length). Remove an offset of 1 from the internal handling of
>> the available values.
>
> This confuses me. Are we saying those other devices have a 3db frequency
> control that is not obeying the ABI? If so that sneaked in past me but
> please don't continue that (and we should fix that broken use of the ABI).
This is correct. The attribute directly controls the tap length of the
filter and more taps means lower 3dB corner frequency. Besides, it
isn't easy to even figure out what the corner frequency is, since it
depends both on further settings of the device (provided you want the
actual corner frequency and not one that's normalized to the sampling
frequency) and the internal IIR equation, although you could sort of
reverse engineer it from the step response graph in the datasheet since
it's unlikely to be something complex. I've had a brief look, but there
doesn't appear to be a more appropriate attribute that could be used
within the IIO framework, like timeconstant / tau maybe?
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-10 18:11 ` Jonathan Cameron
@ 2025-08-10 19:12 ` ASSI
2025-08-11 19:48 ` Jonathan Cameron
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-08-10 19:12 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> Call it BMP280_ODR_MODE_FORCED rather than making it 0HZ related?
> Using the value 0 for the sysfs interface doesn't make much sense though.
Technically 0Hz is correct, though: it dosn't cycle at all until we
tell it to do a single measurement.
> Even if it is a pain to work out, we should estimate what it means to
> use force mode wrt to how fast a single sample can be obtain.
MODE_FORCED just doesn't work well ffor devices that do mukltiple
measurements at once that then need to be read one by one. At least not
by using the sysfs read request as the trigger for the measurement,
which is what the earlier patch did that went into v6.13
> It may be that is such that we don't bother with the other slow sampling
> frequency modes if they are slower as they aren't useful vs only reading
> when we want to.
The way these devices work is that you can read the result of the
last measurement as often as you want and in any order, even while
there's another measurement is in progress; and you can chose to have
free-running measurements or host triggered ones. It's the current sysfs
implementation that enforces a rigidity that wasn't there before the
driver was changed to make the device sleep between measurements.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices
2025-08-10 18:58 ` [RFC PATCH v2 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices Achim Gratz
@ 2025-08-10 19:49 ` Andy Shevchenko
2025-08-16 18:42 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-10 19:49 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 10, 2025 at 8:59 PM Achim Gratz <Achim.Gratz@stromeko.de> wrote:
>
> Currently the measurement wait time is fixed at the maximum value
> according to the datasheet, resulting in about 15% overhead compared
> the typical values. Implement an adaptive wait that uses
> regmap_read_poll_timeout() and optimize the polling parameters so that
> the overhead is reduced.
> Link: https://lore.kernel.org/linux-iio/CAHp75VfQxSgQwJQsym9X58G6o4UUgz6EQ4ouhhx82aOHv_if2g@mail.gmail.com/
> Suggested-by: Andy Shevchenko <andy@kernel.org>
I'm not sure this tag may be used as I suggested implementation detail
and not the idea behind the change as a whole.
> Tested-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
This is confusing. Does it mean you haven't tested the patches without this tag?
Note, it's a must to test by the author that's why the tag is
_implied_, no need to make it explicit. I.o.w. author of the code is
supposed to test that before sending (or comment that the code is
untested in the cover letter and/or comment block of the email).
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
...
> + /*
> + * Split the wait into an initial wait of ~94% of the typical
wait --> waiting time
> + * measurement time (which is ~87% of the maximum measurement
> + * time we have calculated) and then use a polling wait until
> + * the measurement finishes. Provide 2ms extra slack in the
> + * timeout value to compensate for any error in accumulated
> + * actual wait time. Minimum two poll cycles, but maximum 2ms
> + * duration where found to be the best compromise in overhead
where --> were
> + * over a range of oversampling settings.
> + */
> + initial_wait = (13 * meas_time_us) / 16;
> + fsleep(initial_wait);
What if meas_time_us == 1?
> + meas_time_us -= initial_wait;
> + ret = regmap_read_poll_timeout(data->regmap, BMP280_REG_STATUS, reg,
> + !(reg & BMP280_REG_STATUS_MEAS_BIT),
> + MIN((2 * USEC_PER_MSEC), (meas_time_us >> 1)),
MIN() is for the constants, please change it to the proper macro.
Also note that this is a C language and not LISP, i.e. remove unneeded
parentheses.
> + (2 * USEC_PER_MSEC + meas_time_us));
Ditto.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 0/9] Fixes and enhancements for the bmp280 driver
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (8 preceding siblings ...)
2025-08-10 18:58 ` [RFC PATCH v2 9/9] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
@ 2025-08-11 12:14 ` Andy Shevchenko
2025-08-11 20:17 ` Jonathan Cameron
10 siblings, 0 replies; 71+ messages in thread
From: Andy Shevchenko @ 2025-08-11 12:14 UTC (permalink / raw)
To: Achim Gratz
Cc: linux-iio, Jonathan Cameron, David Lechner, Andy Shevchenko,
Nuno Sá
On Sun, Aug 10, 2025 at 08:58:37PM +0200, Achim Gratz wrote:
> Revision History:
> =================
>
> v1:
> - initial proposal, incorrectly prefixed "bmp280" instead of "RFC PATCH"
> - patch series presented in the order it was created
>
> v1 -> v2:
> - prefix as "RFC PATCH"
> - drop channel switching
> - rewrite to present patches in smaller units and in logical steps
Do not reuse the same email thread for a new version: The rule of thumb -- new
version implies new independent email thread.
> With v6.13 a change was made to the bmp280 drivers to use MODE_FORCED
> instead of MODE_NORMAL. This broke userspace functionality: reading
> from sysfs interfaces no longer worked and an error was thrown
> "Measurement cycle didn't complete". This series fixes the underlying
> bugs affecting the measurement time calculation and implements
> additional functionality not available for the BMx280 devices
> previously to allow the use of the sysfs interface in MODE_NORMAL
> again and control the corresponding parameters. The implementation
> follows the already existing facilities for the BMx[35]80 devices even
> though the actual functionality of the BMx280 devices is slightly
> different.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-10 19:12 ` ASSI
@ 2025-08-11 19:48 ` Jonathan Cameron
2025-08-12 19:53 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-11 19:48 UTC (permalink / raw)
To: ASSI; +Cc: linux-iio
On Sun, 10 Aug 2025 21:12:25 +0200
ASSI <Stromeko@nexgo.de> wrote:
> Jonathan Cameron writes:
> > Call it BMP280_ODR_MODE_FORCED rather than making it 0HZ related?
> > Using the value 0 for the sysfs interface doesn't make much sense though.
>
> Technically 0Hz is correct, though: it dosn't cycle at all until we
> tell it to do a single measurement.
For cases where we 'trigger' an event we normally use sampling frequency
to be 1/(total time to capture a set of readings) Idea being it's
the frequency at which you get results if you immediately trigger
another one. Doing that here doesn't correspond to 0Hz.
Main problem is no standard userspace code is going to understand
a value of 0Hz as that effectively means no readings ever.
>
> > Even if it is a pain to work out, we should estimate what it means to
> > use force mode wrt to how fast a single sample can be obtain.
>
> MODE_FORCED just doesn't work well ffor devices that do mukltiple
> measurements at once that then need to be read one by one. At least not
> by using the sysfs read request as the trigger for the measurement,
> which is what the earlier patch did that went into v6.13
I understand it works poorly under at least some circumstances. It's
just the issue of 0Hz not being a way people would expect to control this
or how any other driver does it.
>
> > It may be that is such that we don't bother with the other slow sampling
> > frequency modes if they are slower as they aren't useful vs only reading
> > when we want to.
>
> The way these devices work is that you can read the result of the
> last measurement as often as you want and in any order, even while
> there's another measurement is in progress; and you can chose to have
> free-running measurements or host triggered ones. It's the current sysfs
> implementation that enforces a rigidity that wasn't there before the
> driver was changed to make the device sleep between measurements.
Okay, with that in mind...
Another approach might be to stash the timestamp of the last 'forced'
event and if it is 'sufficiently' recent just go with the readings of
other channels grabbed at that time. If it's not we pay the cost of
another read cycle. That's close to doing a runtime pm autosuspend
on many other sensors where we take the view that if no one asked
for a while, we will pay the cost of a new power up and hence put the
sensor to sleep.
Hooking a single forced capture up to a hrtimer trigger would also
be somewhat similar to this but the interface to userspace is
rather more different so perhaps not the right way to think about it
here.
Jonathan
>
>
> Regards,
> Achim.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-10 19:01 ` ASSI
@ 2025-08-11 20:14 ` Jonathan Cameron
2025-08-12 19:34 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-11 20:14 UTC (permalink / raw)
To: ASSI; +Cc: linux-iio
On Sun, 10 Aug 2025 21:01:24 +0200
ASSI <Stromeko@nexgo.de> wrote:
> Jonathan Cameron writes:
> > On Sun, 3 Aug 2025 16:08:00 +0200
> > Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> >
> >> These devices were using a hardcoded IIR filter of length 4. Enable
> >> filter_low_pass_3db_frequency settings to control the filter length
> >> settings of the device (as done already for the BMx380 and BMx580
> >> devices, even though the 3dB corner has an inverse relation to the
> >> filter length). Remove an offset of 1 from the internal handling of
> >> the available values.
> >
> > This confuses me. Are we saying those other devices have a 3db frequency
> > control that is not obeying the ABI? If so that sneaked in past me but
> > please don't continue that (and we should fix that broken use of the ABI).
>
> This is correct. The attribute directly controls the tap length of the
> filter and more taps means lower 3dB corner frequency. Besides, it
> isn't easy to even figure out what the corner frequency is, since it
> depends both on further settings of the device (provided you want the
> actual corner frequency and not one that's normalized to the sampling
> frequency) and the internal IIR equation, although you could sort of
> reverse engineer it from the step response graph in the datasheet since
> it's unlikely to be something complex. I've had a brief look, but there
> doesn't appear to be a more appropriate attribute that could be used
> within the IIO framework, like timeconstant / tau maybe?
>
We stuck to 3DB point for these because all most anything else is annoyingly
filter type dependent with no real consistency of meaning. At least 3dB is
something you can establish if you have a reasonable amount of info about the
filter (or a plot!)
Obviously they are almost always effected by sampling frequency so that maths
can be rather non trivial.
Vs a completely misleading tap length control, an approx 3dB eyeballed
off a plot is an improvement.
Adding more filter parameters is likely to end up with a very complex
userspace, so if we have any way to get an approx 3dB point, stick to that.
Been way to long since I last did any digital filter stuff, but poking google
ai thing with "IIR filter y_t = (a -1)/a * y_(t-1) + x_t/a"
came back with 3dB in digital angular frequency as
w_c = arccos ((2a^2 - 2a - 1) / (2a(a - 1))
Which might be right.
It's pretty unusual to not find a frequency plot that we could read it
directly off on a datasheet :(
Any filter design folk about who can sanity check the AI output?
Jonathan
>
> Regards,
> Achim.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 0/9] Fixes and enhancements for the bmp280 driver
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
` (9 preceding siblings ...)
2025-08-11 12:14 ` [RFC PATCH v2 0/9] Fixes and enhancements for the bmp280 driver Andy Shevchenko
@ 2025-08-11 20:17 ` Jonathan Cameron
10 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-11 20:17 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 10 Aug 2025 20:58:37 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Revision History:
> =================
Hi Achim
For future reference, don't send new versions in reply to old threads.
That's a sure fire way to reduce the chance anyone looks at them as they
get filed pages back in many email clients and the threads can become
very very complex if discussion on multiple versions overlaps.
Series title and version number is enough for people figure out the relationships.
>
> v1:
> - initial proposal, incorrectly prefixed "bmp280" instead of "RFC PATCH"
> - patch series presented in the order it was created
>
> v1 -> v2:
> - prefix as "RFC PATCH"
> - drop channel switching
> - rewrite to present patches in smaller units and in logical steps
>
> With v6.13 a change was made to the bmp280 drivers to use MODE_FORCED
> instead of MODE_NORMAL. This broke userspace functionality: reading
> from sysfs interfaces no longer worked and an error was thrown
> "Measurement cycle didn't complete". This series fixes the underlying
> bugs affecting the measurement time calculation and implements
> additional functionality not available for the BMx280 devices
> previously to allow the use of the sysfs interface in MODE_NORMAL
> again and control the corresponding parameters. The implementation
> follows the already existing facilities for the BMx[35]80 devices even
> though the actual functionality of the BMx280 devices is slightly
> different.
>
> Achim Gratz (9):
> iio: pressure: bmp280: correct meas_time_us calculation
> iio: pressure: bmp280: implement adaptive wait for BMx280 devices
> iio: pressure: bmp280: implement adaptive wait for BMP380 devices
> iio: pressure: bmp280: refactoring
> iio: pressure: bmp280: remove code duplication
> iio: pressure: bmp280: enable filter settings for BMx280
> iio: pressure: bmp280: implement sampling_frequency for BMx280
> iio: pressure: bmp280: implement sampling_frequency calculation for
> BMx280
> iio: pressure: bmp280: test longer autosuspend (WIP)
>
> drivers/iio/pressure/bmp280-core.c | 350 +++++++++++++++++++++++------
> drivers/iio/pressure/bmp280.h | 22 ++
> 2 files changed, 300 insertions(+), 72 deletions(-)
>
> ---
>
> Comments:
>
> Thanks for allo the comments on my v1 patch series. I have not seen
> any reaction to my on-list replies however, so it appears y'all are
> expecting to Cc: everyone involved?
>
> I've just seen new responses from James, but these are not taken into
> account for v2 obviously.
>
> The dropped channel switching code may be revisited / resurrected at a
> later time. However it can not fully achieve what I want anyway for
> how I use the sensor and the later implemented controls for several
> sensor parameters get the desired performance back.
>
> The remaining sticky point is the control of the autosuspend delay.
> If the sensor is suspended between measurements, then even when it is
> operating in MODE_NORMAL, an additional latency of 12…15ms is incured
> when the interval between measurements is long enough to trigger
> autosuspend. I have set the hardcoded value to 2s as a test (see the
> last patch in the series) and this additional latency vanishes,
> interestingly also the tailing to long measurement times I have
> observed otherwise is also much reduced. However so far I've not come
> up with an idea of how to control the autosuspend delay from
> userspace, to wit:
>
> /sys/bus/iio/devices/iio:device0/power/async: disabled
> /sys/bus/iio/devices/iio:device0/power/autosuspend_delay_ms:
> '/sys/bus/iio/devices/iio:device0/power/autosuspend_delay_ms': Input/output error
> /sys/bus/iio/devices/iio:device0/power/control: auto
> /sys/bus/iio/devices/iio:device0/power/runtime_active_kids: 0
> /sys/bus/iio/devices/iio:device0/power/runtime_active_time: 0
> /sys/bus/iio/devices/iio:device0/power/runtime_enabled: disabled
> /sys/bus/iio/devices/iio:device0/power/runtime_status: unsupported
> /sys/bus/iio/devices/iio:device0/power/runtime_suspended_time: 0
> /sys/bus/iio/devices/iio:device0/power/runtime_usage: 0
> -rw-r--r-- 1 root root 4096 Aug 10 18:41 async
> -rw-r--r-- 1 root root 4096 Aug 10 18:41 autosuspend_delay_ms
> -rw-r--r-- 1 root root 4096 Aug 10 18:41 control
> -r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_active_kids
> -r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_active_time
> -r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_enabled
> -r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_status
> -r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_suspended_time
> -r--r--r-- 1 root root 4096 Aug 10 18:41 runtime_usage
>
> …which according to the kernel documentation is due to a lack of
> unspecified support from the driver. Now, it appears I should be able
> to switch off autosuspend altogether by changing control from "auto"
> to "on", but that doesn't seem to take effect; also I'd rather
> configure a sensible value in accordance to my measurement settings.
> The other handful of IIO drivers I've looked at that set this
> parameter don't do things differently, so I don't know if there's
> anything that can be done about it.
>
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-11 20:14 ` Jonathan Cameron
@ 2025-08-12 19:34 ` ASSI
2025-08-17 14:51 ` Jonathan Cameron
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-08-12 19:34 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> We stuck to 3DB point for these because all most anything else is annoyingly
> filter type dependent with no real consistency of meaning. At least 3dB is
> something you can establish if you have a reasonable amount of info about the
> filter (or a plot!)
If you look at my .sig you might glean I probably know the odd thing or
two about filters… and 3dB frequency is just as meaningless without
knowing the filter type even before one enters into whether or not there
is peaking and resonance.
> Obviously they are almost always effected by sampling frequency so that maths
> can be rather non trivial.
>
> Vs a completely misleading tap length control, an approx 3dB eyeballed
> off a plot is an improvement.
Donning my hat as a user: I beg to differ. I know this device has 8
different settings for the tap length of some otherwise unspecified
filter (you can deduce that it must be a a recursive shift and
accumulate type thing) and more taps mean larger timeconstant / somewhat
better smoothing. I really just want to chose among these eight
settings and not calculate a 3dB frequency that isn't in the datasheet
(and maybe even a different one depending on the four other three-bit
choices I have w.r.t. device settings).
I imagine the reason this particular device uses this attribute is
purely due to the fact that it was already available and corresponds
roughly to what the control does.
> Adding more filter parameters is likely to end up with a very complex
> userspace, so if we have any way to get an approx 3dB point, stick to
> that.
Filter settings: 0, 2, 4, 8, 16 (see datasheet, that's 2**i below)
That's the simplest I can think of, really. Per the datasheet, the
actual filter is:
y(t) = ( (y(t-1) << i) - y(t-1) + x(t) ) >> i
= 2**-i * x(t) (2**i-1)*2**-i * y(t-1) )
The canonical recursive single-pole LP has two coefficients, which
should be 1-d and d (d because it's the sample decay).
2**-i + (2**i-1)*2**-i = 2**-1 * ( 1 + 2**i - 1 ) = 1
so check that. The time constant (rise time to 63%) is then
tau = -1/ln(d)
Oddly enough the data sheet gives time to >75%, but that is just a
scaling factor of ln(0.25) on the tau. The nomalized corner frequency then is:
fc/fs = -ln(d)/(2pi)
So lets check that:
|---+--------+--------+--------+--------+-----------+----------|
| i | 1-d | d | tau | t>75% | datasheet | fc/fs |
|---+--------+--------+--------+--------+-----------+----------|
| 0 | 1 | 0 | --- | --- | 1 | 1 |
| 1 | 0.5 | 0.5 | 1.443 | 2.000 | 1.443 | 0.110318 |
| 2 | 0.25 | 0.75 | 3.476 | 4.819 | 3.476 | 0.045786 |
| 3 | 0.125 | 0.875 | 7.489 | 10.382 | 7.489 | 0.021252 |
| 4 | 0.0625 | 0.9375 | 15.495 | 21.481 | 15.495 | 0.010272 |
|---+--------+--------+--------+--------+-----------+----------|
> Been way to long since I last did any digital filter stuff, but poking google
> ai thing with "IIR filter y_t = (a -1)/a * y_(t-1) + x_t/a"
> came back with 3dB in digital angular frequency as
>
> w_c = arccos ((2a^2 - 2a - 1) / (2a(a - 1))
> Which might be right.
Given that it says w_c and said angular frequency, I'd wager a guess
that there's a factor 2pi that needs to go. Yep, close enough
numerically. Next time I'm bored I will whip out the trigonometric
identities table in Bronstein/Semendjajew and see why that arccos
espression is the same as -ln(d).
I'd still rather specify the filter as integers than having to enter
those floating-point numbers to get the device set up.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-11 19:48 ` Jonathan Cameron
@ 2025-08-12 19:53 ` ASSI
2025-08-17 15:10 ` Jonathan Cameron
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-08-12 19:53 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> For cases where we 'trigger' an event we normally use sampling frequency
> to be 1/(total time to capture a set of readings) Idea being it's
> the frequency at which you get results if you immediately trigger
> another one. Doing that here doesn't correspond to 0Hz.
From the device point of view the setting _is_ 0Hz. That you are going
to read it back-to-back is not something it can know.
There is one more problem with your idea: since that parameter is the
only way to switch between modes, implementing it you way would mean
that MODE_NORMAL+t_stby=0 would map to the same frequency as MODE_FORCED
and then we're back to square one that there is no parameter to tell us
which mode we want.
> Main problem is no standard userspace code is going to understand
> a value of 0Hz as that effectively means no readings ever.
I am "userspace" and I well enough that I'm going to get one sample per
read.
>>
>> > Even if it is a pain to work out, we should estimate what it means to
>> > use force mode wrt to how fast a single sample can be obtain.
>>
>> MODE_FORCED just doesn't work well ffor devices that do mukltiple
>> measurements at once that then need to be read one by one. At least not
>> by using the sysfs read request as the trigger for the measurement,
>> which is what the earlier patch did that went into v6.13
>
> I understand it works poorly under at least some circumstances. It's
> just the issue of 0Hz not being a way people would expect to control this
> or how any other driver does it.
Beside any other driver (which I've not looked at), you're willing to
break an existing one? Because no existing userspace that use this
driver will be working past that change.
> Another approach might be to stash the timestamp of the last 'forced'
> event and if it is 'sufficiently' recent just go with the readings of
> other channels grabbed at that time. If it's not we pay the cost of
> another read cycle. That's close to doing a runtime pm autosuspend
> on many other sensors where we take the view that if no one asked
> for a while, we will pay the cost of a new power up and hence put the
> sensor to sleep.
I've actually looked at that and found it lacking. That just makes
MODE_FORCED a permanent thing that totally ignores that the sensor is
supposed to be operated in free-running MODE_NORMAL in many
applications. MODE_FORCED really is for things like wheather stations
where it gets woken up onece every few minutes. As long as there is no
separate attribute or module parameter to switch between operation
modes, this would be removing exactly the functionality that I want to
use.
> Hooking a single forced capture up to a hrtimer trigger would also
> be somewhat similar to this but the interface to userspace is
> rather more different so perhaps not the right way to think about it
> here.
I haven't been able to get this to work, I've never got a reading out of
the buffer. I'll try again once the distribution I#m using has enabled
sysfs triggers, which are easier to test with hopefully.
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices
2025-08-10 19:49 ` Andy Shevchenko
@ 2025-08-16 18:42 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-08-16 18:42 UTC (permalink / raw)
To: linux-iio
Andy Shevchenko writes:
>> Suggested-by: Andy Shevchenko <andy@kernel.org>
>
> I'm not sure this tag may be used as I suggested implementation detail
> and not the idea behind the change as a whole.
OK, will remove this.
>> Tested-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
>
> This is confusing. Does it mean you haven't tested the patches without this tag?
> Note, it's a must to test by the author that's why the tag is
> _implied_, no need to make it explicit. I.o.w. author of the code is
> supposed to test that before sending (or comment that the code is
> untested in the cover letter and/or comment block of the email).
I intended it to mean that I actually tested the full range of
attributes, unlike what apparently happened with the previous version of
this function. But I see what you mean, I'll take it out then.
> MIN() is for the constants, please change it to the proper macro.
> Also note that this is a C language and not LISP, i.e. remove unneeded
> parentheses.
Ack, the macro probably has enough argument sanitization so this is no
worry here.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-12 19:34 ` ASSI
@ 2025-08-17 14:51 ` Jonathan Cameron
0 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 14:51 UTC (permalink / raw)
To: ASSI; +Cc: linux-iio
On Tue, 12 Aug 2025 21:34:35 +0200
ASSI <Stromeko@nexgo.de> wrote:
> Jonathan Cameron writes:
> > We stuck to 3DB point for these because all most anything else is annoyingly
> > filter type dependent with no real consistency of meaning. At least 3dB is
> > something you can establish if you have a reasonable amount of info about the
> > filter (or a plot!)
>
> If you look at my .sig you might glean I probably know the odd thing or
> two about filters… and 3dB frequency is just as meaningless without
> knowing the filter type even before one enters into whether or not there
> is peaking and resonance.
I have no problem with proposals to enhance the filter description, but
in general on the basis of the sort of filters that get applied to
reduce sensor noise, their primary job is either high or low pass filtering.
In both those cases 3dB point gives a useful single number indication.
If you know your signal is expected to change at a particular maximum frequency
and want to be sure to not filter that excessively set the 3dB point beyond it
and for (most) filters that will work fine, if not necessarily being the ideal choice.
>
> > Obviously they are almost always effected by sampling frequency so that maths
> > can be rather non trivial.
> >
> > Vs a completely misleading tap length control, an approx 3dB eyeballed
> > off a plot is an improvement.
>
> Donning my hat as a user: I beg to differ. I know this device has 8
> different settings for the tap length of some otherwise unspecified
> filter (you can deduce that it must be a a recursive shift and
> accumulate type thing) and more taps mean larger timeconstant / somewhat
> better smoothing.
As user of 'this specific device that decided to read the datasheet' then
yes I agree with you. Most users aren't in that category. They have
no interest in opening a datasheet. They just want to run generic software
that offers them settings that are moderately generic.
Key here is a major / the main purpose of the IIO subsystem is generalization
of interfaces across many devices where the datasheets choose different
descriptions. Note that 3dB frequencies are a common filter parameter found
on datasheets. Unfortunately, filters are one of the fiddliest things to
describe in succinct fashion.
> I really just want to chose among these eight
> settings and not calculate a 3dB frequency that isn't in the datasheet
> (and maybe even a different one depending on the four other three-bit
> choices I have w.r.t. device settings).
>
> I imagine the reason this particular device uses this attribute is
> purely due to the fact that it was already available and corresponds
> roughly to what the control does.
The ABI documents are clear on how we describe filter controls.
Any misuse of that is simply a bug. Unfortunately in some cases we
missed that bug in review.
>
> > Adding more filter parameters is likely to end up with a very complex
> > userspace, so if we have any way to get an approx 3dB point, stick to
> > that.
>
> Filter settings: 0, 2, 4, 8, 16 (see datasheet, that's 2**i below)
>
> That's the simplest I can think of, really. Per the datasheet, the
> actual filter is:
>
> y(t) = ( (y(t-1) << i) - y(t-1) + x(t) ) >> i
> = 2**-i * x(t) (2**i-1)*2**-i * y(t-1) )
>
> The canonical recursive single-pole LP has two coefficients, which
> should be 1-d and d (d because it's the sample decay).
>
> 2**-i + (2**i-1)*2**-i = 2**-1 * ( 1 + 2**i - 1 ) = 1
>
> so check that. The time constant (rise time to 63%) is then
>
> tau = -1/ln(d)
>
> Oddly enough the data sheet gives time to >75%, but that is just a
> scaling factor of ln(0.25) on the tau. The nomalized corner frequency then is:
>
> fc/fs = -ln(d)/(2pi)
>
> So lets check that:
>
> |---+--------+--------+--------+--------+-----------+----------|
> | i | 1-d | d | tau | t>75% | datasheet | fc/fs |
> |---+--------+--------+--------+--------+-----------+----------|
> | 0 | 1 | 0 | --- | --- | 1 | 1 |
> | 1 | 0.5 | 0.5 | 1.443 | 2.000 | 1.443 | 0.110318 |
> | 2 | 0.25 | 0.75 | 3.476 | 4.819 | 3.476 | 0.045786 |
> | 3 | 0.125 | 0.875 | 7.489 | 10.382 | 7.489 | 0.021252 |
> | 4 | 0.0625 | 0.9375 | 15.495 | 21.481 | 15.495 | 0.010272 |
> |---+--------+--------+--------+--------+-----------+----------|
>
> > Been way to long since I last did any digital filter stuff, but poking google
> > ai thing with "IIR filter y_t = (a -1)/a * y_(t-1) + x_t/a"
> > came back with 3dB in digital angular frequency as
> >
> > w_c = arccos ((2a^2 - 2a - 1) / (2a(a - 1))
> > Which might be right.
>
> Given that it says w_c and said angular frequency, I'd wager a guess
> that there's a factor 2pi that needs to go. Yep, close enough
> numerically. Next time I'm bored I will whip out the trigonometric
> identities table in Bronstein/Semendjajew and see why that arccos
> espression is the same as -ln(d).
>
> I'd still rather specify the filter as integers than having to enter
> those floating-point numbers to get the device set up.
>
Sorry, the ABI has been there a long time and we aren't changing it now.
If you want to propose additional filter description (which to avoid
breaking userspace software would most likely be dependent read only
attributes - i.e. 3dB remains the control but we can provide
informative other values if they generalize to a wideish class of filters)
then I'm happy to consider it and maybe even dig my filter books
out the garage if I can't find a good online reference.
Jonathan
>
> Regards,
> Achim.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-12 19:53 ` ASSI
@ 2025-08-17 15:10 ` Jonathan Cameron
2025-08-17 16:36 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 15:10 UTC (permalink / raw)
To: ASSI; +Cc: linux-iio
On Tue, 12 Aug 2025 21:53:00 +0200
ASSI <Stromeko@nexgo.de> wrote:
> Jonathan Cameron writes:
> > For cases where we 'trigger' an event we normally use sampling frequency
> > to be 1/(total time to capture a set of readings) Idea being it's
> > the frequency at which you get results if you immediately trigger
> > another one. Doing that here doesn't correspond to 0Hz.
>
> From the device point of view the setting _is_ 0Hz. That you are going
> to read it back-to-back is not something it can know.
We can argue this for ever and there is lots of precedence
of treating on demand sensor sampling frequency as 1/period.
(though seems we haven't documented that which isn't great - see reference
later).
>
> There is one more problem with your idea: since that parameter is the
> only way to switch between modes, implementing it you way would mean
> that MODE_NORMAL+t_stby=0 would map to the same frequency as MODE_FORCED
> and then we're back to square one that there is no parameter to tell us
> which mode we want.
That's a fair point that I'd missed. I was kind of assuming there was
a power up time that made the (pseudo)frequency for MODE_FORCED a
good bit less than the the MODE_NORMAL case which thinking more on it
would have put it in the middle of the MODE_NORMAL cases so not
helpful either.
>
> > Main problem is no standard userspace code is going to understand
> > a value of 0Hz as that effectively means no readings ever.
>
> I am "userspace" and I well enough that I'm going to get one sample per
> read.
You are writer of one specific bit of userspace code.
If you look at a generic application like the stuff ADI builds on top
of IIO then that is going to be a very odd value to see.
>
> >>
> >> > Even if it is a pain to work out, we should estimate what it means to
> >> > use force mode wrt to how fast a single sample can be obtain.
> >>
> >> MODE_FORCED just doesn't work well ffor devices that do mukltiple
> >> measurements at once that then need to be read one by one. At least not
> >> by using the sysfs read request as the trigger for the measurement,
> >> which is what the earlier patch did that went into v6.13
> >
> > I understand it works poorly under at least some circumstances. It's
> > just the issue of 0Hz not being a way people would expect to control this
> > or how any other driver does it.
>
> Beside any other driver (which I've not looked at), you're willing to
> break an existing one? Because no existing userspace that use this
> driver will be working past that change.
Existing code doesn't use sampling frequency and works, though slowly
after that power saving related change. It was the wrong default
choice but we missed it at the time - probably because both the author
and reviewers were thinking slow reads where the only thing likely
to be required by users of this device (see later). We should have
stuck to the periodic sampling unless we detected (runtime pm
autosuspend probably) that we were not doing frequent reads.
>
> > Another approach might be to stash the timestamp of the last 'forced'
> > event and if it is 'sufficiently' recent just go with the readings of
> > other channels grabbed at that time. If it's not we pay the cost of
> > another read cycle. That's close to doing a runtime pm autosuspend
> > on many other sensors where we take the view that if no one asked
> > for a while, we will pay the cost of a new power up and hence put the
> > sensor to sleep.
>
> I've actually looked at that and found it lacking. That just makes
> MODE_FORCED a permanent thing that totally ignores that the sensor is
> supposed to be operated in free-running MODE_NORMAL in many
> applications.
An additional feature would be to detect repeated reads
and deciding to to autoswitch out of mode forced (probably on second read
of a channel within a short period).
> MODE_FORCED really is for things like wheather stations
> where it gets woken up onece every few minutes. As long as there is no
> separate attribute or module parameter to switch between operation
> modes, this would be removing exactly the functionality that I want to
> use.
Ok. I misunderstood this. It's not that you want to grab
all the channels quickly (but only do that infrequently) it's that you
want to do measurement of rapidly changing pressure? That's fair enough
as a use case, I just wasn't expecting to see it for this part (vs the
ones that have pipe connectors or similar)
>
> > Hooking a single forced capture up to a hrtimer trigger would also
> > be somewhat similar to this but the interface to userspace is
> > rather more different so perhaps not the right way to think about it
> > here.
>
> I haven't been able to get this to work, I've never got a reading out of
> the buffer. I'll try again once the distribution I#m using has enabled
> sysfs triggers, which are easier to test with hopefully.
Ok. Lets park that one for now. This isn't a case where we have to get
readings at the same time for multiple channels to be useful, they just
need for your usecase not to be too far apart. So buffered support isn't
urgent.
Given the situation I'll accept the slight oddity of a 0Hz sampling_frequency.
It may confuse some software but as long as the default is sensible
sampling frequency isn't (I believe) that commonly tweaked for sysfs
reads anyway. Tends to be much more relevant with high speed buffered
capture.
Hmm. Seems I let an exception for this in once before. Sorry had forgotten
that until I was wondering what docs update we need.
https://elixir.bootlin.com/linux/v6.16/source/Documentation/ABI/testing/sysfs-bus-iio#L112
So can you add a note to that doc covering this case (can be a follow up
patch if everything else is fine for v2)?
Sometimes these corner cases take a bit of arguing out. Thanks for
your patience!
Thanks,
Jonathan
>
>
> Achim.
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 1/9] iio: pressure: bmp280: correct meas_time_us calculation
2025-08-10 18:58 ` [RFC PATCH v2 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
@ 2025-08-17 15:16 ` Jonathan Cameron
0 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 15:16 UTC (permalink / raw)
To: Achim Gratz, linux-iio; +Cc: David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 10 Aug 2025 20:58:38 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Correction of meas_time_us initialization based on an observation and
> partial patch by David Lechner.
>
> There was also a thinko in bmp280_wait_conv: data->oversampling_humid
> can actually be 0 (for an oversampling_ratio of 1), so it can not be
> used to detect the presence of the humidity measurement capability.
> Use data->chip_info->oversampling_humid_avail instead, which is NULL
> for chips that cannot measure humidity and therefore need to skip that
> part of the calculation.
Hi Achim,
This addresses part of the change (and that bit is fine) but doesn't
mention the other part. See below.
>
> Closes: https://lore.kernel.org/linux-iio/875xgfg0wz.fsf@Gerda.invalid/
> Fixes: 26ccfaa9ddaa ("iio: pressure: bmp280: Use sleep and forced mode for oneshot captures")
> Suggested-by: David Lechner <dlechner@baylibre.com>
> Tested-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
>
> ---
>
> Notes
> =====
>
> Since the BMx280 device support was added, oversampling=0
> actually is a valid setting (meaning that measurement channel is off),
> but actually allowing that setting to be used by changing the data
> structure to hold the actual value instead of its ilog2 would require
> more extensive changes elsewhere in the code.
>
> Further changes would be necesary to avoid the awkward use of -1 as
> the value that would currently be necessary to achieve a setting of 0
> in the register.
>
> Datasheet values and median actual measurement times through sysfs for
> a single reading with my BME280 connected to a 400kHz I²C bus provided
> by the i915 IGP VGA port:
>
> |--------------+---------+---------+----------+----------|
> | Oversampling | Typical | Maximum | Measured | Overhead |
> | Ratio | [ms] | [ms] | [ms] | [ms] |
> |--------------+---------+---------+----------+----------|
> | 16 | 98.0 | 112.8 | 122.1 | 9.3 |
> | 8 | 50.0 | 57.6 | 63.6 | 6.0 |
> | 4 | 26.0 | 30.0 | 34.6 | 4.6 |
> | 2 | 14.0 | 16.2 | 21.7 | 5.5 |
> | 1 | 8.0 | 9.3 | 14.8 | 5.5 |
> |--------------+---------+---------+----------+----------|
>
> Reading all three channels via sysfs triples those times, including
> the overhead of course.
>
> It is also impossible to obtain all three values from
> the same measurement with MODE_FORCED, which is in a way a limitation
> of the sysfs interface AFAIU.
Sort of. As per other discussion, there are a few drivers that
do work around this but in general the intent is that if you want a
'scan' of multiple channels taken together then the buffered interface
is the only way to guarantee that.
> ---
> drivers/iio/pressure/bmp280-core.c | 15 +++++++++------
> 1 file changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index f37f20776c89..5bec63c1bc11 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -1042,13 +1042,16 @@ static int bmp280_wait_conv(struct bmp280_data *data)
> unsigned int reg, meas_time_us;
> int ret;
>
> - /* Check if we are using a BME280 device */
> - if (data->oversampling_humid)
> - meas_time_us = BMP280_PRESS_HUMID_MEAS_OFFSET +
> - BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
> + /* Constant part of the measurement time */
> + meas_time_us = BMP280_MEAS_OFFSET;
I'm fine with this being necessary but it's not mentioned in the patch description
that all measurement times need to be increased by this time.
Add something to the description to cover this change.
>
> - else
> - meas_time_us = 0;
> + /*
> + * Check if we are using a BME280 device,
> + * Humidity measurement time
> + */
> + if (data->chip_info->oversampling_humid_avail)
> + meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
> + BIT(data->oversampling_humid) * BMP280_MEAS_DUR;
>
> /* Pressure measurement time */
> meas_time_us += BMP280_PRESS_HUMID_MEAS_OFFSET +
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 4/9] iio: pressure: bmp280: refactoring
2025-08-10 18:58 ` [RFC PATCH v2 4/9] iio: pressure: bmp280: refactoring Achim Gratz
@ 2025-08-17 15:23 ` Jonathan Cameron
0 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 15:23 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 10 Aug 2025 20:58:41 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
Put a little more in the patch title. Tricky to get balance right
but simply refactoring isn't enough.
Maybe
iio: pressure: bmp280: Factor out measurement time calculation
> Refactor the measurement time calculation into a new function
> bmp280_calc_meas_time_us() and use it in bmp280_wait_conv(). This is
> currently the only consumer of this value, however calculation of
> output data rate values will also require it. As already commented in
> bm280.h:468, but not actually implemented for the BMx280 devices,
> sampling_frequency can be emulated indirectly via t_standby
> configuration.
>
> Also move the setting of BMP280_MODE_FORCED from
> bmp280_read_raw_impl() into bmp[235]80_wait_conv(), as the measurement
> cannot be started without having set the mode immediately before
> starting the wait, so .wait_conv() should not have to rely on getting
> called in the right context. No mode setting is required for BMP180,
> which only has a dummy bmp180_wait_conv() implementation anyway.
Having a function called wait_conv that includes starting the conv, which I think
is what the MODE_FORCED is doing is not ideal. Maybe needs a rename
to just conv()?
Otherwise lgtm
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
> ---
> drivers/iio/pressure/bmp280-core.c | 50 +++++++++++++++++++++++-------
> 1 file changed, 39 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 7630c9d1265a..4f5982a36200 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -624,10 +624,6 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
>
> switch (mask) {
> case IIO_CHAN_INFO_PROCESSED:
> - ret = data->chip_info->set_mode(data, BMP280_FORCED);
> - if (ret)
> - return ret;
> -
> ret = data->chip_info->wait_conv(data);
> if (ret)
> return ret;
> @@ -661,10 +657,6 @@ static int bmp280_read_raw_impl(struct iio_dev *indio_dev,
> return -EINVAL;
> }
> case IIO_CHAN_INFO_RAW:
> - ret = data->chip_info->set_mode(data, BMP280_FORCED);
> - if (ret)
> - return ret;
> -
> ret = data->chip_info->wait_conv(data);
> if (ret)
> return ret;
> @@ -1037,10 +1029,9 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
> return 0;
> }
>
> -static int bmp280_wait_conv(struct bmp280_data *data)
> +static unsigned int bmp280_calc_meas_time_us(struct bmp280_data *data)
> {
> - unsigned int reg, meas_time_us, initial_wait;
> - int ret;
> + unsigned int meas_time_us;
>
> /* Constant part of the measurement time */
> meas_time_us = BMP280_MEAS_OFFSET;
> @@ -1060,6 +1051,24 @@ static int bmp280_wait_conv(struct bmp280_data *data)
> /* Temperature measurement time */
> meas_time_us += BIT(data->oversampling_temp) * BMP280_MEAS_DUR;
>
> + /* Waiting time according to the BM(P/E)2 Sensor API (maximum value) */
> + return meas_time_us;
> +}
> +
> +static int bmp280_wait_conv(struct bmp280_data *data)
> +{
> + unsigned int reg, meas_time_us, initial_wait;
> + int ret;
> +
> + /*
> + * Each new measurement requires mode setting, as at the end
> + * of the measurement cycle the sensor enters MODE_SLEEP
> + * again.
> + */
> + ret = data->chip_info->set_mode(data, BMP280_FORCED);
> + if (ret)
> + return ret;
> +
> /*
> * Split the wait into an initial wait of ~94% of the typical
> * measurement time (which is ~87% of the maximum measurement
> @@ -1070,6 +1079,7 @@ static int bmp280_wait_conv(struct bmp280_data *data)
> * duration where found to be the best compromise in overhead
> * over a range of oversampling settings.
> */
> + meas_time_us = bmp280_calc_meas_time_us(data);
> initial_wait = (13 * meas_time_us) / 16;
> fsleep(initial_wait);
> meas_time_us -= initial_wait;
> @@ -1717,6 +1727,15 @@ static int bmp380_wait_conv(struct bmp280_data *data)
> unsigned int reg, meas_time_us, initial_wait;
> int ret;
>
> + /*
> + * Each new measurement requires mode setting, as at the end
> + * of the measurement cycle the sensor enters MODE_SLEEP
> + * again.
> + */
> + ret = data->chip_info->set_mode(data, BMP280_FORCED);
> + if (ret)
> + return ret;
> +
> /* Offset measurement time */
> meas_time_us = BMP380_MEAS_OFFSET;
>
> @@ -2457,6 +2476,15 @@ static int bmp580_wait_conv(struct bmp280_data *data)
> };
> unsigned int meas_time_us;
>
> + /*
> + * Each new measurement requires mode setting, as at the end
> + * of the measurement cycle the sensor enters MODE_SLEEP
> + * again.
> + */
> + ret = data->chip_info->set_mode(data, BMP280_FORCED);
> + if (ret)
> + return ret;
> +
> meas_time_us = 4 * USEC_PER_MSEC +
> time_conv_temp[data->oversampling_temp] +
> time_conv_press[data->oversampling_press];
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-17 15:10 ` Jonathan Cameron
@ 2025-08-17 16:36 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-08-17 16:36 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> Sometimes these corner cases take a bit of arguing out. Thanks for
> your patience!
Just so you're not wondering why there isn't a v3, I could not work at
the code this weekend and will not be for the next two or three weeks
most likely as well. I'll get back to it when I can shore up enough
time to work a few hours without interruption.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 6/9] iio: pressure: bmp280: enable filter settings for BMx280
2025-08-10 18:58 ` [RFC PATCH v2 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
@ 2025-08-17 16:37 ` Jonathan Cameron
0 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 16:37 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 10 Aug 2025 20:58:43 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> These devices were using a hardcoded IIR filter of length 4. Enable
> filter_low_pass_3db_frequency settings to control the filter length
> settings of the device as done already for the BMx380 and BMx580
> devices, even though the 3dB corner has an inverse relation to the
> filter length. Remove a superfluous offset of -1 from the internal
> handling of the available values and use the table entries directly.
> Keep the default value at the previous hardcoded value to keep
> identical device behaviour after module load.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
See continuing discussion on v1.
Jonathan
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 7/9] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-10 18:58 ` [RFC PATCH v2 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
@ 2025-08-17 16:53 ` Jonathan Cameron
2025-08-17 17:36 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 16:53 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 10 Aug 2025 20:58:44 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
Hi Achim,
> As was already commented in bm280.h:468, sampling_frequency can be
> emulated on BMx280 devices indirectly via t_standby configuration.
> Actually implement it to enable this useful feature. This allows to
> switch between MODE_FORCED and MODE_NORMAL operation and use the same
> sysfs read implementations for both modes.
>
> the bmp[235]_wait_conv() functions check if the sensor already
> operates in NORMAL_MODE and skips the wait for measurement complettion
completion
> unless a mode transition is required to save the overhead of
> re-setting the same mode superfluously.
When you say 'mode transition' here is this contradicting the
"already operates in NORMAL_MODE" part above? I suspect you just don't
need the "unless" onwards part of this.
>
> The actual sampling frequency depends on the oversampling_ratio
> settings. In order to not complicate the code too much, the available
> sampling frequency values are fixed and have been calculated for
> oversampling_ratio=1 on all available channels assuming maximum
> measurement duration per the data sheet, corresponding to the minimum
> achievable sampling frequency for the highest measurement speed
> configuration.
Agreed it is more complicated but as the driver supports oversampling ratio
then you need to compensate the sampling frequencies for that to comply
with the expected ABI. This is a common corner case. Long ago we had
to decide whether to do oversampling as assumed to slow down sampling
frequency or not and given we had devices that had a separate burst
clock for oversampling alongside the triggering of a burst we went with
that way around.
>
> THe ODR tables for the BM[35]80 devices have been extended to allow
> for MODE_FORCED operation also and the handling of the table values is
> adapted accordingly.
>
> Report of the actual sampling frequency via sysfs is possible, but not
> yet implemented. In preparation for that implementation the
> calculation of measurement time has previously been factored out from
> bmp280_wait_conv into bmp280_calc_meas_time_us.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
>
> ---
>
> Calculated ODR values:
> |--------+---------+---------|
> | t_sb | min ODR | min ODR |
> | [ms] | BMP280 | BME280 |
> |--------+---------+---------|
> | 0 | 155.642 | 107.527 |
> | 0.5 | 144.404 | 102.041 |
> | 62.5 | 14.509 | 13.928 |
> | 125.0 | 7.609 | 7.446 |
> | 250.0 | 3.900 | 3.857 |
> | 500.0 | 1.975 | 1.963 |
> | 1000.0 | 0.994 | 0.991 |
> | 2000.0 | 0.498 | 0.498 |
> | 4000.0 | 0.250 | 0.249 |
> | 10.0 | 60.883 | 51.813 |
> | 20.0 | 37.843 | 34.130 |
> |--------+---------+---------|
> ---
> drivers/iio/pressure/bmp280-core.c | 165 +++++++++++++++++++++++------
> drivers/iio/pressure/bmp280.h | 20 ++++
> 2 files changed, 155 insertions(+), 30 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 0ee40b6abb44..a66b90b3ddb8 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -64,7 +64,47 @@
> */
> enum { AC1, AC2, AC3, AC4, AC5, AC6, B1, B2, MB, MC, MD };
>
> +/*
> + * Output Data Rate of 0Hz is indicating operation in MODE_FORCED,
> + * otherwise ODR = 1/(t_meas + t_stby) (rounded down to three digits)
> + *
> + * t_meas is the maximum data sheet value calculated for an
> + * oversampling ratio of 1 for all available channels of the
> + * respective device
> + */
> +enum bmp280_odr {
> + BMP280_ODR_0HZ,
> + BMP280_ODR_155HZ, /* t_meas_max = 6.425ms, t_sb = 0.0ms */
> + BMP280_ODR_144HZ, /* t_meas_max = 6.425ms, t_sb = 0.5ms */
> + BMP280_ODR_14_5HZ, /* t_meas_max = 6.425ms, t_sb = 62.5ms */
> + BMP280_ODR_7_60HZ, /* t_meas_max = 6.425ms, t_sb = 125ms */
> + BMP280_ODR_3_90HZ, /* t_meas_max = 6.425ms, t_sb = 250ms */
> + BMP280_ODR_1_97HZ, /* t_meas_max = 6.425ms, t_sb = 500ms */
> + BMP280_ODR_0_99HZ, /* t_meas_max = 6.425ms, t_sb = 1000ms */
> + BMP280_ODR_0_49HZ, /* t_meas_max = 6.425ms, t_sb = 2000ms */
> + BMP280_ODR_0_24HZ, /* t_meas_max = 6.425ms, t_sb = 4000ms */
> +};
> +
> +/*
> + * BME280 redefines the meaning of the last two register settings
> + * vs. BMP280, which are now out of order with the other values but
> + * need to be in that exact position
> + */
> +enum bme280_odr {
> + BME280_ODR_0HZ,
> + BME280_ODR_107HZ, /* t_meas_max = 9.300ms, t_sb = 0.5ms */
> + BME280_ODR_102HZ, /* t_meas_max = 9.300ms, t_sb = 0.5ms */
> + BME280_ODR_13_9HZ, /* t_meas_max = 9.300ms, t_sb = 62.5ms */
> + BME280_ODR_7_44HZ, /* t_meas_max = 9.300ms, t_sb = 125ms */
> + BME280_ODR_3_85HZ, /* t_meas_max = 9.300ms, t_sb = 250ms */
> + BME280_ODR_1_96HZ, /* t_meas_max = 9.300ms, t_sb = 500ms */
> + BME280_ODR_0_99HZ, /* t_meas_max = 9.300ms, t_sb = 1000ms */
> + BME280_ODR_51_8HZ, /* t_meas_max = 9.300ms, t_sb = 10ms */
> + BME280_ODR_34_1HZ, /* t_meas_max = 9.300ms, t_sb = 20ms */
> +};
> +
> enum bmp380_odr {
> + BMP380_ODR_0HZ,
> BMP380_ODR_200HZ,
> BMP380_ODR_100HZ,
> BMP380_ODR_50HZ,
> @@ -86,6 +126,7 @@ enum bmp380_odr {
> };
>
> enum bmp580_odr {
> + BMP580_ODR_0HZ,
Whilst I've accepted using 0 as the sysfs value, internally can we name it
BMP580_ODR_FORCED on ODR_ONESHOT maybe so that we can see what it is immediately
in here. Then match that explicitly rather than checking for != 0 below.
> BMP580_ODR_240HZ,
> BMP580_ODR_218HZ,
> BMP580_ODR_199HZ,
>
> -static int bmp280_write_sampling_frequency(struct bmp280_data *data,
> +static int bmp280_write_sampling_freq(struct bmp280_data *data,
> int val, int val2)
> {
> const int (*avail)[2] = data->chip_info->sampling_freq_avail;
> @@ -893,7 +939,7 @@ static int bmp280_write_raw_impl(struct iio_dev *indio_dev,
> return -EINVAL;
> }
> case IIO_CHAN_INFO_SAMP_FREQ:
> - return bmp280_write_sampling_frequency(data, val, val2);
> + return bmp280_write_sampling_freq(data, val, val2);
> case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> return bmp280_write_iir_filter_coeffs(data, val);
> default:
> @@ -971,6 +1017,32 @@ static const unsigned long bme280_avail_scan_masks[] = {
> 0
> };
>
> +static const int bmp280_odr_table[][2] = {
> + [BMP280_ODR_0HZ] = {0, 0},
Preference in IIO is { 0, 0 },
etc
As mentioned above you'll need to have the data for
the different oversampling rates as well and pick the right
array depending on how that is set.
> + [BMP280_ODR_155HZ] = {155, 0},
> + [BMP280_ODR_144HZ] = {144, 0},
> + [BMP280_ODR_14_5HZ] = {14, 500000},
> + [BMP280_ODR_7_60HZ] = {7, 600000},
> + [BMP280_ODR_3_90HZ] = {3, 900000},
> + [BMP280_ODR_1_97HZ] = {1, 970000},
> + [BMP280_ODR_0_99HZ] = {0, 990000},
> + [BMP280_ODR_0_49HZ] = {0, 490000},
> + [BMP280_ODR_0_24HZ] = {0, 240000},
> +};
> +
> +static const int bme280_odr_table[][2] = {
> + [BME280_ODR_0HZ] = {0, 0},
> + [BME280_ODR_107HZ] = {107, 0},
> + [BME280_ODR_102HZ] = {102, 0},
> + [BME280_ODR_13_9HZ] = {13, 900000},
> + [BME280_ODR_7_44HZ] = {7, 440000},
> + [BME280_ODR_3_85HZ] = {3, 850000},
> + [BME280_ODR_1_96HZ] = {1, 960000},
> + [BME280_ODR_0_99HZ] = {0, 990000},
> + [BME280_ODR_51_8HZ] = {51, 800000},
> + [BME280_ODR_34_1HZ] = {34, 100000},
> +};
> +
> static int bmp280_preinit(struct bmp280_data *data)
> {
> struct device *dev = data->dev;
> @@ -1008,6 +1080,9 @@ static int bmp280_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
> {
> int ret;
>
> + /* Ensure a mode transition on next measurement if we take an error exit */
> + data->op_mode = BMP280_SLEEP;
> +
> ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
> BMP280_MODE_MASK, bmp280_operation_mode[mode]);
> if (ret) {
> @@ -1051,12 +1126,15 @@ static int bmp280_wait_conv(struct bmp280_data *data)
> unsigned int reg, meas_time_us, initial_wait;
> int ret;
>
> - /*
> - * Each new measurement requires mode setting, as at the end
> - * of the measurement cycle the sensor enters MODE_SLEEP
> - * again.
> - */
> - ret = data->chip_info->set_mode(data, BMP280_FORCED);
> + /* No mode transition and already in NORMAL_MODE, skip wait */
> + if (data->sampling_freq && data->op_mode == BMP280_NORMAL)
> + return 0;
> +
> + /* switch mode based on sampling_freq */
> + data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
> +
> + /* Mode transition or measurement in MODE_FORCED */
> + ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED);
Use data->op_mode? However, generally we'd set that only after success of the set_mode
call, so use a local variable for the new mode and set the data->op_mode to that once
succeeded in setting the mode.
> if (ret)
> return ret;
>
> @@ -1078,6 +1156,7 @@ static int bmp280_wait_conv(struct bmp280_data *data)
> !(reg & BMP280_REG_STATUS_MEAS_BIT),
> MIN((2 * USEC_PER_MSEC), (meas_time_us >> 1)),
> (2 * USEC_PER_MSEC + meas_time_us));
> +
Unrelated and not necessarily a good change. Shouldn't be here.
> if (ret) {
> dev_err(data->dev, "failed to read status register.\n");
> return ret;
> @@ -1095,21 +1174,24 @@ static int bmp280_chip_config(struct bmp280_data *data)
> {
> u8 osrs = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
> FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
> + u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK, (data->sampling_freq ?: 1) - 1);
> int ret;
>
> ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
> BMP280_OSRS_TEMP_MASK |
> BMP280_OSRS_PRESS_MASK |
> BMP280_MODE_MASK,
> - osrs | BMP280_MODE_SLEEP);
> + osrs | (data->sampling_freq ? BMP280_NORMAL : BMP280_SLEEP));
> + if (ret)
> + return ret;
> if (ret) {
> dev_err(data->dev, "failed to write ctrl_meas register\n");
> return ret;
> }
>
> ret = regmap_update_bits(data->regmap, BMP280_REG_CONFIG,
> - BMP280_FILTER_MASK,
> - data->iir_filter_coeff);
> + BMP280_FILTER_MASK | BMP280_TSTBY_MASK,
> + tstby | BMP280_FILTER_4X);
I'd not bother with aligning like this unless it is common in this driver.
This sort of forcing tends to just lead to code churn as further changes
turn up over time and doesn't really help readability, particularly in
this order. Maybe just put the filter setting under the filter mask
and testby under TSTBY_MASK and it will both align better and be easier to
follow.
>
> @@ -1727,12 +1817,20 @@ static int bmp380_wait_conv(struct bmp280_data *data)
> unsigned int reg, meas_time_us, initial_wait;
> int ret;
>
> - /*
> - * Each new measurement requires mode setting, as at the end
> - * of the measurement cycle the sensor enters MODE_SLEEP
> - * again.
> - */
> - ret = data->chip_info->set_mode(data, BMP280_FORCED);
> + /* nothing to wait for, read already available data */
> + if (data->op_mode == BMP280_NORMAL)
> + return 0;
> +
> + /* switch mode based on sampling_freq */
> + data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
> +
> + /* Mode transition or measurement in MODE_FORCED */
> + ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED);
Use data->op_mode
> + if (ret)
> + return ret;
> +
> + /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
I'm not sure if this question is for reviewers or something you want to check out yourself.
> + ret = data->chip_info->set_mode(data, data->op_mode);
> if (ret)
> return ret;
> @@ -3363,10 +3465,13 @@ static int bmp280_runtime_suspend(struct device *dev)
> {
> struct iio_dev *indio_dev = dev_get_drvdata(dev);
> struct bmp280_data *data = iio_priv(indio_dev);
> -
> - data->chip_info->set_mode(data, BMP280_SLEEP);
> + int ret;
>
> fsleep(data->start_up_time_us);
> + ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_SLEEP);
> + if (ret)
> + return ret;
> +
> return regulator_bulk_disable(BMP280_NUM_SUPPLIES, data->supplies);
> }
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-08-10 18:58 ` [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
@ 2025-08-17 17:04 ` Jonathan Cameron
2025-08-17 17:40 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 17:04 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 10 Aug 2025 20:58:45 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Report of the actual sampling frequency via sysfs is implemented based
> on the maximum measurement cycle time, depending on oversampling_ratio
> and t_standby settings. If the device dependent table for the
> t_standby values is missing, the reported value is taken from the ODR
> table as before, which enables the support for the BMx[35]80 devices
> to be unchanged.
Ah. Ok. I was thinking you weren't handling the oversampling multiplication
but you do it in here. Great. However without sampling_frequency_available
how is the user going to figure out what to set? That will need to take
the oversampling ratios into account.
This driver seems to have the infrastructure for providing available attributes
but is it hooked up? I can't find where info_mask_*_available is set for
any of the channels. Maybe I'm missing something, but if not would be
good to fix that as part of your improvements.
otherwise this code looks fine to me.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 9/9] iio: pressure: bmp280: test longer autosuspend (WIP)
2025-08-10 18:58 ` [RFC PATCH v2 9/9] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
@ 2025-08-17 17:05 ` Jonathan Cameron
2025-08-17 17:44 ` ASSI
0 siblings, 1 reply; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-17 17:05 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 10 Aug 2025 20:58:46 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Autosuspend delay should be configurable from sysfs via the power
> attributes, but that is apparently not working for me. Since the
> standard value for autosuspend_delay is shorter than my typical
> measurement period and a suspend/resume incurs both additional latency
> and stronger tailing on the acquisition time, monkey-patch a 2s value
> in until I can figure out how to do this properly.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Currently delay seems very short anyway, so I wouldn't mind increasing
it like you have here.
Jonathan
> ---
> drivers/iio/pressure/bmp280-core.c | 2 ++
> 1 file changed, 2 insertions(+)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 5c4126e4eccd..7d51ab0b92e9 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -3500,6 +3500,8 @@ int bmp280_common_probe(struct device *dev,
> * start-up time.
> */
> pm_runtime_set_autosuspend_delay(dev, data->start_up_time_us / 10);
> + /* test */
> + pm_runtime_set_autosuspend_delay(dev, 2*MSEC_PER_SEC);
> pm_runtime_use_autosuspend(dev);
> pm_runtime_put(dev);
>
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 7/9] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-08-17 16:53 ` Jonathan Cameron
@ 2025-08-17 17:36 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-08-17 17:36 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
>> + /* switch mode based on sampling_freq */
>> + data->op_mode = data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED;
>> +
>> + /* Mode transition or measurement in MODE_FORCED */
>> + ret = data->chip_info->set_mode(data, data->sampling_freq ? BMP280_NORMAL : BMP280_FORCED);
>
> Use data->op_mode? However, generally we'd set that only after success of the set_mode
> call, so use a local variable for the new mode and set the data->op_mode to that once
> succeeded in setting the mode.
Ack. In a previous version of the code I couldn't use it, but now I can
as I explicitly set it to the correct value further up.
>> if (ret)
>> return ret;
>>
>> @@ -1078,6 +1156,7 @@ static int bmp280_wait_conv(struct bmp280_data *data)
>> !(reg & BMP280_REG_STATUS_MEAS_BIT),
>> MIN((2 * USEC_PER_MSEC), (meas_time_us >> 1)),
>> (2 * USEC_PER_MSEC + meas_time_us));
>> +
> Unrelated and not necessarily a good change. Shouldn't be here.
Already removed on my end, just didn't make it into v2.
>> + if (ret)
>> + return ret;
>> +
>> + /* is this really necessary or can we skip if op_mode is already BMP280_NORMAL? */
>
> I'm not sure if this question is for reviewers or something you want to check out yourself.
It was a reminder to check why sometimes the measurement would get stuck
and not deliver any new values, which turned out to be a bug in handling
suspend / resume.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-08-17 17:04 ` Jonathan Cameron
@ 2025-08-17 17:40 ` ASSI
2025-08-18 17:52 ` Jonathan Cameron
0 siblings, 1 reply; 71+ messages in thread
From: ASSI @ 2025-08-17 17:40 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> This driver seems to have the infrastructure for providing available attributes
> but is it hooked up? I can't find where info_mask_*_available is set for
> any of the channels. Maybe I'm missing something, but if not would be
> good to fix that as part of your improvements.
I think not, there isn't any *_available sysfs files I can see. Where
can I look up examples of how to enable these?
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 9/9] iio: pressure: bmp280: test longer autosuspend (WIP)
2025-08-17 17:05 ` Jonathan Cameron
@ 2025-08-17 17:44 ` ASSI
0 siblings, 0 replies; 71+ messages in thread
From: ASSI @ 2025-08-17 17:44 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> On Sun, 10 Aug 2025 20:58:46 +0200
> Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
>
>> Autosuspend delay should be configurable from sysfs via the power
>> attributes, but that is apparently not working for me. Since the
>> standard value for autosuspend_delay is shorter than my typical
>> measurement period and a suspend/resume incurs both additional latency
>> and stronger tailing on the acquisition time, monkey-patch a 2s value
>> in until I can figure out how to do this properly.
>>
>> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
>
> Currently delay seems very short anyway, so I wouldn't mind increasing
> it like you have here.
Yes, I think something like that would be a better default value, but
I'd still like to figure out why I cannot actually control this with the
sysfs power/ attributes that are present. Somehow it seems that this
support is only halfway enabled and while that triggeres the presence of
the control files, the actual handling is not functional yet.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 71+ messages in thread
* Re: [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-08-17 17:40 ` ASSI
@ 2025-08-18 17:52 ` Jonathan Cameron
0 siblings, 0 replies; 71+ messages in thread
From: Jonathan Cameron @ 2025-08-18 17:52 UTC (permalink / raw)
To: ASSI; +Cc: linux-iio
On Sun, 17 Aug 2025 19:40:49 +0200
ASSI <Stromeko@nexgo.de> wrote:
> Jonathan Cameron writes:
> > This driver seems to have the infrastructure for providing available attributes
> > but is it hooked up? I can't find where info_mask_*_available is set for
> > any of the channels. Maybe I'm missing something, but if not would be
> > good to fix that as part of your improvements.
>
> I think not, there isn't any *_available sysfs files I can see. Where
> can I look up examples of how to enable these?
Any driver that sets both iio_dev.info_mask_*_available
(separate, shared_by_type etc)
and the read_avail callback.
There are two ways to represent data, either a list in which case return
IIO_AVAIL_LIST from the callback and provide a suitable array of value / value pairs
or a range with start, step, stop in which case return IIO_AVAIL_RANGE.
Seems like someone half implemented it in this driver but then stopped.
Not something I tend to look for when reviewing, but I guess I should add that
to my mental list of things to check.
Jonathan
>
>
> Regards,
> Achim.
^ permalink raw reply [flat|nested] 71+ messages in thread
end of thread, other threads:[~2025-08-18 17:52 UTC | newest]
Thread overview: 71+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-17 23:30 [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 1/4] iio: pressure: bmp280: Use sleep and forced mode for oneshot captures Vasileios Amoiridis
2025-06-28 18:45 ` ASSI
2025-06-28 20:57 ` David Lechner
2025-06-29 7:43 ` ASSI
2025-07-11 19:17 ` ASSI
2025-07-12 14:49 ` ASSI
2025-07-21 19:15 ` ASSI
2025-07-26 18:34 ` ASSI
2025-07-27 19:08 ` ASSI
2024-10-17 23:30 ` [PATCH v9 2/4] dt-bindings: iio: pressure: bmp085: Add interrupts for BMP3xx and BMP5xx devices Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 3/4] iio: pressure: bmp280: Add data ready trigger support Vasileios Amoiridis
2024-10-17 23:30 ` [PATCH v9 4/4] iio: pressure: bmp280: Move bmp085 interrupt to new configuration Vasileios Amoiridis
2024-10-19 13:55 ` [PATCH v9 0/4] pressure: bmp280: Minor cleanup and interrupt support Jonathan Cameron
2025-08-03 14:07 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Achim Gratz
2025-08-03 14:07 ` [bmp280 v1 1/6] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
2025-08-06 15:46 ` Jonathan Cameron
2025-08-06 17:53 ` ASSI
2025-08-10 18:04 ` Jonathan Cameron
2025-08-03 14:07 ` [bmp280 v1 2/6] iio: pressure: bmp280: reduce overhead on read with MODE_FORCED Achim Gratz
2025-08-03 20:12 ` Andy Shevchenko
2025-08-06 15:58 ` Jonathan Cameron
2025-08-06 18:00 ` ASSI
2025-08-03 14:07 ` [bmp280 v1 3/6] iio: pressure: bmp280: implement sampling_frequency for BMx280 Achim Gratz
2025-08-03 20:26 ` Andy Shevchenko
2025-08-04 17:29 ` ASSI
2025-08-10 18:11 ` Jonathan Cameron
2025-08-10 19:12 ` ASSI
2025-08-11 19:48 ` Jonathan Cameron
2025-08-12 19:53 ` ASSI
2025-08-17 15:10 ` Jonathan Cameron
2025-08-17 16:36 ` ASSI
2025-08-03 14:08 ` [bmp280 v1 4/6] iio: pressure: bmp280: enable filter settings " Achim Gratz
2025-08-03 20:28 ` Andy Shevchenko
2025-08-04 17:14 ` ASSI
2025-08-10 18:13 ` Jonathan Cameron
2025-08-10 19:01 ` ASSI
2025-08-11 20:14 ` Jonathan Cameron
2025-08-12 19:34 ` ASSI
2025-08-17 14:51 ` Jonathan Cameron
2025-08-03 14:08 ` [bmp280 v1 5/6] iio: pressure: bmp280: remove code duplication Achim Gratz
2025-08-03 20:30 ` Andy Shevchenko
2025-08-10 18:19 ` Jonathan Cameron
2025-08-03 14:08 ` [bmp280 v1 6/6] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280 Achim Gratz
2025-08-03 20:37 ` Andy Shevchenko
2025-08-04 17:20 ` ASSI
2025-08-03 19:20 ` [bmp280 v1 0/6] Fixes and enhancements for the bmp280 driver Andy Shevchenko
2025-08-10 18:58 ` [RFC PATCH v2 0/9] " Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
2025-08-17 15:16 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices Achim Gratz
2025-08-10 19:49 ` Andy Shevchenko
2025-08-16 18:42 ` ASSI
2025-08-10 18:58 ` [RFC PATCH v2 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 4/9] iio: pressure: bmp280: refactoring Achim Gratz
2025-08-17 15:23 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 5/9] iio: pressure: bmp280: remove code duplication Achim Gratz
2025-08-10 18:58 ` [RFC PATCH v2 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
2025-08-17 16:37 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
2025-08-17 16:53 ` Jonathan Cameron
2025-08-17 17:36 ` ASSI
2025-08-10 18:58 ` [RFC PATCH v2 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
2025-08-17 17:04 ` Jonathan Cameron
2025-08-17 17:40 ` ASSI
2025-08-18 17:52 ` Jonathan Cameron
2025-08-10 18:58 ` [RFC PATCH v2 9/9] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
2025-08-17 17:05 ` Jonathan Cameron
2025-08-17 17:44 ` ASSI
2025-08-11 12:14 ` [RFC PATCH v2 0/9] Fixes and enhancements for the bmp280 driver Andy Shevchenko
2025-08-11 20:17 ` Jonathan Cameron
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).