* [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver
@ 2025-09-28 17:26 Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
` (10 more replies)
0 siblings, 11 replies; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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
v2 -> v3:
- incorporate comments/suggestions on v2
- clean up
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 (patches 0001 through
005) and implements additional functionality (patches 0006 through
009) 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 hardware 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: rename wait_conv() to conv(), factor out
measurement time calculation
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 | 504 +++++++++++++++++++++--------
drivers/iio/pressure/bmp280.h | 26 +-
2 files changed, 387 insertions(+), 143 deletions(-)
--
Comments:
Thanks for all suggestions and comments on my v1 and v2 patch series.
I've not had time to work on the suggested further changes to the
implementation, to recap that would entail implementing the
*_available attributes and completely reworking the handling of the
ODR and filter settings to better conform to the API:
1. A list of available values for each setting should be
associated via the *_available attribute (since these are a
fixed number for each parameter due to the register
mapping);
2. Available output data rate settings would be variable
depending on the OSR (at the moment the setting is fixed,
but the reading is variable);
3. Filter settings would be done by 3dB corner (either real or
normalized frequency) instead of the divisor (bitshift)
applied to produce the decay value of the underlying
recursive IIR.
Anything from 2. on would break userspace (again), but make the
implementation more conformant with the API. I think there needs to
be more discission of how to re-structure the code to support this:
the current static tables would become really large, however setting
dynamic calculations up so that the small number of valid register
values can get extracted would be rather complex and error-prone. So
it is likely there should be some combination of both approaches used.
The remaining sticky point is the control of the autosuspend delay
(patch 0099). 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 from within the driver
implementation.
^ permalink raw reply [flat|nested] 19+ messages in thread
* [RFC PATCH v3 1/9] iio: pressure: bmp280: correct meas_time_us calculation
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-10-04 15:21 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 1/1] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
` (9 subsequent siblings)
10 siblings, 1 reply; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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.
The constant part of the measurement time (as described in the
datasheet and implemented in the BM(P/E)2 Sensor API) was apparently
forgotten (it was already correctly applied for the BMP380) and is now
used.
There was also another thinko in bmp280_wait_conv:
data->oversampling_humid can actually have a value of 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 must 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 register 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 as each read triggers a new measurement on all
enabled channels. It is therefore also impossible to obtain all
channel values from the same measurement cycle with MODE_FORCED, which
is in a way a limitation of the sysfs interface and can only be
obtained by using buffered reads.
---
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 6cdc8ed53520..2078b810745b 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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 1/1] iio: pressure: bmp280: test longer autosuspend (WIP)
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-09-28 19:10 ` ASSI
2025-09-28 17:26 ` [RFC PATCH v3 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices Achim Gratz
` (8 subsequent siblings)
10 siblings, 1 reply; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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 4edabdd17f57..6415ac8e2927 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -3514,6 +3514,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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 1/1] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices Achim Gratz
` (7 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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/
Tested-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
Use of regmap_read_poll_timeout was suggested by Andy Shevchenko.
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 | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 2078b810745b..b413f1949952 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,28 @@ 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 waiting time into an initial part of ~94% of the
+ * typical measurement time (which is ~87% of the maximum
+ * measurement time we have calculated) and then use polling
+ * until the measurement finishes. Provide 2ms extra slack in
+ * the timeout value to compensate for any error in
+ * accumulated actual waiting time. Minimum two poll cycles,
+ * but maximum 2ms duration were found to be the best
+ * compromise in overhead over a range of oversampling
+ * settings.
+ *
+ * Measurement time can not be smaller than
+ * BMP280_MEAS_OFFSET, so the fsleep will always receive a
+ * strictly positive argument.
+ */
+ 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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (2 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 4/9] iio: pressure: bmp280: rename wait_conv() to conv(), factor out measurement time calculation Achim Gratz
` (6 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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 b413f1949952..cd305b6f022d 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -1716,8 +1716,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;
@@ -1730,10 +1730,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;
@@ -2444,15 +2449,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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 4/9] iio: pressure: bmp280: rename wait_conv() to conv(), factor out measurement time calculation
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (3 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 5/9] iio: pressure: bmp280: remove code duplication Achim Gratz
` (5 subsequent siblings)
10 siblings, 0 replies; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Rename wait_conv() to conv() as the function actually starts the
measurement conversion and does not just wait for it to complete.
Refactor the measurement time calculation into a new function
bmp280_calc_meas_time_us() and use it in bmp280_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 and will need this value for the calculation.
Also move the setting of BMP280_MODE_FORCED from
bmp280_read_raw_impl() into bmp[235]80_conv(), as the measurement
cannot be started without having set the mode immediately before
starting the measurement, so *_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_conv() implementation anyway to
keep a consistent device structure.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 74 ++++++++++++++++++++----------
drivers/iio/pressure/bmp280.h | 2 +-
2 files changed, 52 insertions(+), 24 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index cd305b6f022d..2dd36493acb4 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -624,11 +624,7 @@ 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);
+ ret = data->chip_info->conv(data);
if (ret)
return ret;
@@ -661,11 +657,7 @@ 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);
+ ret = data->chip_info->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_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 waiting time into an initial part of ~94% of the
* typical measurement time (which is ~87% of the maximum
@@ -1075,6 +1084,7 @@ static int bmp280_wait_conv(struct bmp280_data *data)
* BMP280_MEAS_OFFSET, so the fsleep will always receive a
* strictly positive argument.
*/
+ meas_time_us = bmp280_calc_meas_time_us(data);
initial_wait = (13 * meas_time_us) / 16;
fsleep(initial_wait);
meas_time_us -= initial_wait;
@@ -1217,7 +1227,7 @@ const struct bmp280_chip_info bmp280_chip_info = {
.read_press = bmp280_read_press,
.read_calib = bmp280_read_calib,
.set_mode = bmp280_set_mode,
- .wait_conv = bmp280_wait_conv,
+ .conv = bmp280_conv,
.preinit = bmp280_preinit,
.trigger_handler = bmp280_trigger_handler,
@@ -1402,7 +1412,7 @@ const struct bmp280_chip_info bme280_chip_info = {
.read_humid = bme280_read_humid,
.read_calib = bme280_read_calib,
.set_mode = bmp280_set_mode,
- .wait_conv = bmp280_wait_conv,
+ .conv = bmp280_conv,
.preinit = bmp280_preinit,
.trigger_handler = bme280_trigger_handler,
@@ -1714,11 +1724,20 @@ static int bmp380_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
return 0;
}
-static int bmp380_wait_conv(struct bmp280_data *data)
+static int bmp380_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;
@@ -1730,7 +1749,7 @@ static int bmp380_wait_conv(struct bmp280_data *data)
meas_time_us += BMP380_TEMP_MEAS_OFFSET +
BIT(data->oversampling_temp) * BMP380_MEAS_DUR;
- /* See bmp280_wait_conv() */
+ /* See bmp280_conv() */
initial_wait = (13 * meas_time_us) / 16;
fsleep(initial_wait);
meas_time_us -= initial_wait;
@@ -2019,7 +2038,7 @@ const struct bmp280_chip_info bmp380_chip_info = {
.read_press = bmp380_read_press,
.read_calib = bmp380_read_calib,
.set_mode = bmp380_set_mode,
- .wait_conv = bmp380_wait_conv,
+ .conv = bmp380_conv,
.preinit = bmp380_preinit,
.trigger_probe = bmp380_trigger_probe,
@@ -2443,7 +2462,7 @@ static int bmp580_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
return 0;
}
-static int bmp580_wait_conv(struct bmp280_data *data)
+static int bmp580_conv(struct bmp280_data *data)
{
/*
* Taken from datasheet, Section 2 "Specification, Table 3 "Electrical
@@ -2459,6 +2478,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];
@@ -2712,7 +2740,7 @@ const struct bmp280_chip_info bmp580_chip_info = {
.read_temp = bmp580_read_temp,
.read_press = bmp580_read_press,
.set_mode = bmp580_set_mode,
- .wait_conv = bmp580_wait_conv,
+ .conv = bmp580_conv,
.preinit = bmp580_preinit,
.trigger_probe = bmp580_trigger_probe,
@@ -2968,7 +2996,7 @@ static int bmp180_set_mode(struct bmp280_data *data, enum bmp280_op_mode mode)
}
/* Keep compatibility with newer generations of the sensor */
-static int bmp180_wait_conv(struct bmp280_data *data)
+static int bmp180_conv(struct bmp280_data *data)
{
return 0;
}
@@ -3047,7 +3075,7 @@ const struct bmp280_chip_info bmp180_chip_info = {
.read_press = bmp180_read_press,
.read_calib = bmp180_read_calib,
.set_mode = bmp180_set_mode,
- .wait_conv = bmp180_wait_conv,
+ .conv = bmp180_conv,
.trigger_handler = bmp180_trigger_handler,
};
@@ -3125,7 +3153,7 @@ const struct bmp280_chip_info bmp085_chip_info = {
.read_press = bmp180_read_press,
.read_calib = bmp180_read_calib,
.set_mode = bmp180_set_mode,
- .wait_conv = bmp180_wait_conv,
+ .conv = bmp180_conv,
.trigger_probe = bmp085_trigger_probe,
.trigger_handler = bmp180_trigger_handler,
diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h
index 25bb9c743a05..df90ed720bc6 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -519,7 +519,7 @@ struct bmp280_chip_info {
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);
+ int (*conv)(struct bmp280_data *data);
int (*trigger_probe)(struct iio_dev *indio_dev);
irqreturn_t (*trigger_handler)(int irq, void *p);
--
2.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 5/9] iio: pressure: bmp280: remove code duplication
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (4 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 4/9] iio: pressure: bmp280: rename wait_conv() to conv(), factor out measurement time calculation Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-10-04 15:12 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
` (4 subsequent siblings)
10 siblings, 1 reply; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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 2dd36493acb4..4f5c4bd89067 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->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->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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 6/9] iio: pressure: bmp280: enable filter settings for BMx280
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (5 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 5/9] iio: pressure: bmp280: remove code duplication Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-10-04 15:21 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
` (3 subsequent siblings)
10 siblings, 1 reply; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 UTC (permalink / raw)
To: linux-iio
Cc: Jonathan Cameron, David Lechner, Andy Shevchenko, Nuno Sá,
Achim Gratz
Follow the existing implementation for the BMx380 and BMx580 devices
even though it doesn't conform to the API: The BMx280 devices were
using a hardcoded value of 4, corresponding to the lowest corner
frequency. Enable filter_low_pass_3db_frequency settings to control
the filter settings of the device. The actual 3dB corner freqquency
has an inverse relation to the value, which represents approximately
the tau of the filter (for which the iio framework does not seem to
have a suitable parameter). 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 ensure identical device behaviour after module load.
A change of the implementation to actually follow the API (breaking
existing userspace) requires further discussion and more extensive
changes elsewhere in the code and are left for later.
---
Filter coefficient settings in hardware: off, 2, 4, 8, 16, mapped to
register values 0, 1, 2, 3, 4 (that's i and 2**i below), 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) )
That's the simplest filter that can be implemented in hardware,
really; the canonical recursive single-pole LP with no gain 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 | 2**i | 1-d | d | tau | t>75% | datasheet | fc/fs |
|---+------+--------+--------+--------+--------+-----------+----------|
| 0 | 1 | 1 | 0 | --- | --- | 1 | 1 |
| 1 | 2 | 0.5 | 0.5 | 1.443 | 2.000 | 2 | 0.110318 |
| 2 | 4 | 0.25 | 0.75 | 3.476 | 4.819 | 5 | 0.045786 |
| 3 | 8 | 0.125 | 0.875 | 7.489 | 10.382 | 11 | 0.021252 |
| 4 | 16 | 0.0625 | 0.9375 | 15.495 | 21.481 | 22 | 0.010272 |
|---+------+--------+--------+--------+--------+-----------+----------|
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
drivers/iio/pressure/bmp280-core.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 4f5c4bd89067..e72cfd4c10b9 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;
@@ -1095,6 +1100,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 filter = FIELD_PREP(BMP280_FILTER_MASK, data->iir_filter_coeff;
int ret;
ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
@@ -1109,7 +1115,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);
+ filter);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1174,6 +1180,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,
@@ -1203,6 +1210,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,
@@ -1385,6 +1396,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,
@@ -1982,7 +1997,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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 7/9] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (6 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-10-04 15:32 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
` (2 subsequent siblings)
10 siblings, 1 reply; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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. As MODE_FORCED is a driver
feature, the corresponding entry in the ODR table has to be added
after the actual register settings. The resulting register setting is
either masked by the driver or clamped to a permissible value on
device, so does not disturb the device operation. MODE_FORCE is
triggered by setting a sampling frequency of 0Hz, following the
precedent of stm32_timer_trigger.
The bmp[235]_conv() functions check if the sensor already operates in
NORMAL_MODE and skip waiting for measurement completion to save the
overhead of the superfluous mode seting.
The actual sampling frequency depends on the oversampling_ratio
settings. In order to keep the constant ODR tables, 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 truncated to three significant
digits; 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 in
chip_config 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_conv into bmp280_calc_meas_time_us.
Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
---
BME280 redefines the last two ODR register settings vs. BMP280, which
are therefore out of order w.r.t. the other values.
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 | --- |
| 4000.0 | 0.250 | --- |
| 10.0 | --- | 51.813 |
| 20.0 | --- | 34.130 |
|--------+---------+---------|
Proper consideration of the OSR when setting sampling_frequency could
be introduced in a later patch after discussion of how to handle the
combinatorial explosion of the table size or alternatively a
complicated on-the-fly computation that also depends on the device
type. Note in particular that there are combinations of OSR and ODR
settings for the BMP580 at least that are illegal and hence replaced
by the device with a default setting, something this driver also
currently does not check for or handle.
This driver currently also lacks the the *_available attributes and
all associated implementation for all supported devices. This should
be introduced in conjunction with the previously mentioned patch, so
that the available settings for the current configuration can be
obtained from user space.
---
drivers/iio/pressure/bmp280-core.c | 297 ++++++++++++++++++++---------
drivers/iio/pressure/bmp280.h | 22 ++-
2 files changed, 228 insertions(+), 91 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index e72cfd4c10b9..9ade6d9e047b 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -64,7 +64,53 @@
*/
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) (truncated 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
+ *
+ * ODR tables start with ODR_FORCED == 0Hz, which is not a register
+ * setting. Any non-zero value indicates a valid setting that will
+ * have to be decremented to get the respective register value.
+ */
+enum bmp280_odr {
+ /* BMP280_ODR_FORCED is a driver feature, not a register setting */
+ BMP280_ODR_FORCED,
+ BMP280_ODR_144HZ, /* t_meas = 6.425ms, t_sb = 0.5ms */
+ BMP280_ODR_14_5HZ, /* t_meas = 6.425ms, t_sb = 62.5ms */
+ BMP280_ODR_7_60HZ, /* t_meas = 6.425ms, t_sb = 125ms */
+ BMP280_ODR_3_90HZ, /* t_meas = 6.425ms, t_sb = 250ms */
+ BMP280_ODR_1_97HZ, /* t_meas = 6.425ms, t_sb = 500ms */
+ BMP280_ODR_0_994HZ, /* t_meas = 6.425ms, t_sb = 1000ms */
+ BMP280_ODR_0_498HZ, /* t_meas = 6.425ms, t_sb = 2000ms */
+ BMP280_ODR_0_250HZ, /* t_meas = 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 as they are used as the register
+ * setting
+ */
+enum bme280_odr {
+ /* BME280_ODR_FORCED is a driver feature, not a register setting */
+ BME280_ODR_FORCED,
+ BME280_ODR_102HZ, /* t_meas = 9.300ms, t_sb = 0.5ms */
+ BME280_ODR_13_9HZ, /* t_meas = 9.300ms, t_sb = 62.5ms */
+ BME280_ODR_7_44HZ, /* t_meas = 9.300ms, t_sb = 125ms */
+ BME280_ODR_3_85HZ, /* t_meas = 9.300ms, t_sb = 250ms */
+ BME280_ODR_1_96HZ, /* t_meas = 9.300ms, t_sb = 500ms */
+ BME280_ODR_0_991HZ, /* t_meas = 9.300ms, t_sb = 1000ms */
+ BME280_ODR_51_8HZ, /* t_meas = 9.300ms, t_sb = 10ms */
+ BME280_ODR_34_1HZ, /* t_meas = 9.300ms, t_sb = 20ms */
+};
+
enum bmp380_odr {
+ /* BMP380_ODR_FORCED is a driver feature, not a register setting */
+ BMP380_ODR_FORCED,
BMP380_ODR_200HZ,
BMP380_ODR_100HZ,
BMP380_ODR_50HZ,
@@ -86,6 +132,8 @@ enum bmp380_odr {
};
enum bmp580_odr {
+ /* BMP380_ODR_FORCED is a driver feature, not a register setting */
+ BMP580_ODR_FORCED,
BMP580_ODR_240HZ,
BMP580_ODR_218HZ,
BMP580_ODR_199HZ,
@@ -159,7 +207,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 +224,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 +245,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 +262,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 +279,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 +869,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 +946,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 +1024,34 @@ static const unsigned long bme280_avail_scan_masks[] = {
0
};
+static const int bmp280_odr_table[][2] = {
+ /* BMP280_ODR_FORCED is a driver feature, not a register setting */
+ [BMP280_ODR_FORCED] = { 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_498HZ] = { 0, 498000 },
+ [BMP280_ODR_0_250HZ] = { 0, 250000 },
+};
+
+static const int bme280_odr_table[][2] = {
+ /* BMP380_ODR_FORCED is a driver feature, not a register setting */
+ [BME280_ODR_FORCED] = { 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_991HZ] = { 0, 991000 },
+ [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 +1089,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 +1135,15 @@ static int bmp280_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;
@@ -1098,24 +1185,28 @@ static int bmp280_conv(struct bmp280_data *data)
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 filter = FIELD_PREP(BMP280_FILTER_MASK, data->iir_filter_coeff;
+ u8 osr_temp = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1);
+ u8 osr_press = FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
+ u8 filter = FIELD_PREP(BMP280_FILTER_MASK, data->iir_filter_coeff);
+ u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK, (data->sampling_freq ?: 1) - 1);
+ u8 mode = FIELD_PREP(BMP280_MODE_MASK, data->sampling_freq ? BMP280_NORMAL : BMP280_SLEEP);
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);
+ osr_temp | osr_press | mode);
+ 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,
- filter);
+ BMP280_FILTER_MASK | BMP280_TSTBY_MASK,
+ filter | tstby);
if (ret) {
dev_err(data->dev, "failed to write config register\n");
return ret;
@@ -1214,6 +1305,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_FORCED,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1233,7 +1328,7 @@ EXPORT_SYMBOL_NS(bmp280_chip_info, "IIO_BMP280");
static int bme280_chip_config(struct bmp280_data *data)
{
- u8 osrs = FIELD_PREP(BME280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1);
+ u8 osr_humid = FIELD_PREP(BME280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1);
int ret;
/*
@@ -1241,7 +1336,7 @@ static int bme280_chip_config(struct bmp280_data *data)
* temperature/pressure is set to become effective.
*/
ret = regmap_update_bits(data->regmap, BME280_REG_CTRL_HUMIDITY,
- BME280_OSRS_HUMIDITY_MASK, osrs);
+ BME280_OSRS_HUMIDITY_MASK, osr_humid);
if (ret) {
dev_err(data->dev, "failed to set humidity oversampling");
return ret;
@@ -1400,6 +1495,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_FORCED,
+
.temp_coeffs = bmp280_temp_coeffs,
.temp_coeffs_type = IIO_VAL_FRACTIONAL,
.press_coeffs = bmp280_press_coeffs,
@@ -1675,24 +1774,26 @@ static int bmp380_read_calib(struct bmp280_data *data)
}
static const int bmp380_odr_table[][2] = {
- [BMP380_ODR_200HZ] = {200, 0},
- [BMP380_ODR_100HZ] = {100, 0},
- [BMP380_ODR_50HZ] = {50, 0},
- [BMP380_ODR_25HZ] = {25, 0},
- [BMP380_ODR_12_5HZ] = {12, 500000},
- [BMP380_ODR_6_25HZ] = {6, 250000},
- [BMP380_ODR_3_125HZ] = {3, 125000},
- [BMP380_ODR_1_5625HZ] = {1, 562500},
- [BMP380_ODR_0_78HZ] = {0, 781250},
- [BMP380_ODR_0_39HZ] = {0, 390625},
- [BMP380_ODR_0_2HZ] = {0, 195313},
- [BMP380_ODR_0_1HZ] = {0, 97656},
- [BMP380_ODR_0_05HZ] = {0, 48828},
- [BMP380_ODR_0_02HZ] = {0, 24414},
- [BMP380_ODR_0_01HZ] = {0, 12207},
- [BMP380_ODR_0_006HZ] = {0, 6104},
- [BMP380_ODR_0_003HZ] = {0, 3052},
- [BMP380_ODR_0_0015HZ] = {0, 1526},
+ /* BMP380_ODR_FORCED is a driver feature, not a register setting */
+ [BMP380_ODR_FORCED] = { 0, 0 },
+ [BMP380_ODR_200HZ] = { 200, 0 },
+ [BMP380_ODR_100HZ] = { 100, 0 },
+ [BMP380_ODR_50HZ] = { 50, 0 },
+ [BMP380_ODR_25HZ] = { 25, 0 },
+ [BMP380_ODR_12_5HZ] = { 12, 500000 },
+ [BMP380_ODR_6_25HZ] = { 6, 250000 },
+ [BMP380_ODR_3_125HZ] = { 3, 125000 },
+ [BMP380_ODR_1_5625HZ] = { 1, 562500 },
+ [BMP380_ODR_0_78HZ] = { 0, 781250 },
+ [BMP380_ODR_0_39HZ] = { 0, 390625 },
+ [BMP380_ODR_0_2HZ] = { 0, 195313 },
+ [BMP380_ODR_0_1HZ] = { 0, 97656 },
+ [BMP380_ODR_0_05HZ] = { 0, 48828 },
+ [BMP380_ODR_0_02HZ] = { 0, 24414 },
+ [BMP380_ODR_0_01HZ] = { 0, 12207 },
+ [BMP380_ODR_0_006HZ] = { 0, 6104 },
+ [BMP380_ODR_0_003HZ] = { 0, 3052 },
+ [BMP380_ODR_0_0015HZ] = { 0, 1526 },
};
static int bmp380_preinit(struct bmp280_data *data)
@@ -1730,12 +1831,19 @@ static int bmp380_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;
+
+ ret = data->chip_info->set_mode(data, data->op_mode);
if (ret)
return ret;
@@ -1807,7 +1915,7 @@ static int bmp380_chip_config(struct bmp280_data *data)
/* Configure output data rate */
ret = regmap_update_bits_check(data->regmap, BMP380_REG_ODR,
- BMP380_ODRS_MASK, data->sampling_freq,
+ BMP380_ODRS_MASK, (data->sampling_freq ?: 1) - 1,
&aux);
if (ret) {
dev_err(data->dev, "failed to write ODR selection register\n");
@@ -2061,7 +2169,7 @@ static int bmp580_soft_reset(struct bmp280_data *data)
fsleep(2000);
/* Dummy read of chip_id */
- ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®);
+ ret = regmap_read(data->regmap, BMP580_REG_ID, ®);
if (ret) {
dev_err(data->dev, "failed to reestablish comms after reset\n");
return ret;
@@ -2205,38 +2313,40 @@ static int bmp580_read_press(struct bmp280_data *data, u32 *raw_press)
}
static const int bmp580_odr_table[][2] = {
- [BMP580_ODR_240HZ] = {240, 0},
- [BMP580_ODR_218HZ] = {218, 0},
- [BMP580_ODR_199HZ] = {199, 0},
- [BMP580_ODR_179HZ] = {179, 0},
- [BMP580_ODR_160HZ] = {160, 0},
- [BMP580_ODR_149HZ] = {149, 0},
- [BMP580_ODR_140HZ] = {140, 0},
- [BMP580_ODR_129HZ] = {129, 0},
- [BMP580_ODR_120HZ] = {120, 0},
- [BMP580_ODR_110HZ] = {110, 0},
- [BMP580_ODR_100HZ] = {100, 0},
- [BMP580_ODR_89HZ] = {89, 0},
- [BMP580_ODR_80HZ] = {80, 0},
- [BMP580_ODR_70HZ] = {70, 0},
- [BMP580_ODR_60HZ] = {60, 0},
- [BMP580_ODR_50HZ] = {50, 0},
- [BMP580_ODR_45HZ] = {45, 0},
- [BMP580_ODR_40HZ] = {40, 0},
- [BMP580_ODR_35HZ] = {35, 0},
- [BMP580_ODR_30HZ] = {30, 0},
- [BMP580_ODR_25HZ] = {25, 0},
- [BMP580_ODR_20HZ] = {20, 0},
- [BMP580_ODR_15HZ] = {15, 0},
- [BMP580_ODR_10HZ] = {10, 0},
- [BMP580_ODR_5HZ] = {5, 0},
- [BMP580_ODR_4HZ] = {4, 0},
- [BMP580_ODR_3HZ] = {3, 0},
- [BMP580_ODR_2HZ] = {2, 0},
- [BMP580_ODR_1HZ] = {1, 0},
- [BMP580_ODR_0_5HZ] = {0, 500000},
- [BMP580_ODR_0_25HZ] = {0, 250000},
- [BMP580_ODR_0_125HZ] = {0, 125000},
+ /* BMP580_ODR_FORCED is a driver feature, not a register setting */
+ [BMP580_ODR_FORCED] = { 0, 0 },
+ [BMP580_ODR_240HZ] = { 240, 0 },
+ [BMP580_ODR_218HZ] = { 218, 0 },
+ [BMP580_ODR_199HZ] = { 199, 0 },
+ [BMP580_ODR_179HZ] = { 179, 0 },
+ [BMP580_ODR_160HZ] = { 160, 0 },
+ [BMP580_ODR_149HZ] = { 149, 0 },
+ [BMP580_ODR_140HZ] = { 140, 0 },
+ [BMP580_ODR_129HZ] = { 129, 0 },
+ [BMP580_ODR_120HZ] = { 120, 0 },
+ [BMP580_ODR_110HZ] = { 110, 0 },
+ [BMP580_ODR_100HZ] = { 100, 0 },
+ [BMP580_ODR_89HZ] = { 89, 0 },
+ [BMP580_ODR_80HZ] = { 80, 0 },
+ [BMP580_ODR_70HZ] = { 70, 0 },
+ [BMP580_ODR_60HZ] = { 60, 0 },
+ [BMP580_ODR_50HZ] = { 50, 0 },
+ [BMP580_ODR_45HZ] = { 45, 0 },
+ [BMP580_ODR_40HZ] = { 40, 0 },
+ [BMP580_ODR_35HZ] = { 35, 0 },
+ [BMP580_ODR_30HZ] = { 30, 0 },
+ [BMP580_ODR_25HZ] = { 25, 0 },
+ [BMP580_ODR_20HZ] = { 20, 0 },
+ [BMP580_ODR_15HZ] = { 15, 0 },
+ [BMP580_ODR_10HZ] = { 10, 0 },
+ [BMP580_ODR_5HZ] = { 5, 0 },
+ [BMP580_ODR_4HZ] = { 4, 0 },
+ [BMP580_ODR_3HZ] = { 3, 0 },
+ [BMP580_ODR_2HZ] = { 2, 0 },
+ [BMP580_ODR_1HZ] = { 1, 0 },
+ [BMP580_ODR_0_5HZ] = { 0, 500000 },
+ [BMP580_ODR_0_25HZ] = { 0, 250000 },
+ [BMP580_ODR_0_125HZ] = { 0, 125000 },
};
static const int bmp580_nvmem_addrs[] = { 0x20, 0x21, 0x22 };
@@ -2403,7 +2513,7 @@ static int bmp580_preinit(struct bmp280_data *data)
return ret;
/* Post powerup sequence */
- ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®);
+ ret = regmap_read(data->regmap, BMP580_REG_ID, ®);
if (ret) {
dev_err(data->dev, "failed to establish comms with the chip\n");
return ret;
@@ -2478,13 +2588,17 @@ static int bmp580_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;
@@ -2552,7 +2666,7 @@ static int bmp580_chip_config(struct bmp280_data *data)
/* Configure output data rate */
ret = regmap_update_bits_check(data->regmap, BMP580_REG_ODR_CONFIG, BMP580_ODR_MASK,
- FIELD_PREP(BMP580_ODR_MASK, data->sampling_freq),
+ FIELD_PREP(BMP580_ODR_MASK, data->sampling_freq ?: 1) - 1,
&aux);
if (ret) {
dev_err(data->dev, "failed to write ODR configuration register\n");
@@ -2707,7 +2821,7 @@ static const int bmp580_temp_coeffs[] = { 125, 13 };
static const int bmp580_press_coeffs[] = { 1, 64000};
const struct bmp280_chip_info bmp580_chip_info = {
- .id_reg = BMP580_REG_CHIP_ID,
+ .id_reg = BMP580_REG_ID,
.chip_id = bmp580_chip_ids,
.num_chip_id = ARRAY_SIZE(bmp580_chip_ids),
.regmap_config = &bmp580_regmap_config,
@@ -3367,10 +3481,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 df90ed720bc6..8e05cdf869e7 100644
--- a/drivers/iio/pressure/bmp280.h
+++ b/drivers/iio/pressure/bmp280.h
@@ -13,7 +13,7 @@
#define BMP580_REG_OSR_CONFIG 0x36
#define BMP580_REG_IF_CONFIG 0x13
#define BMP580_REG_REV_ID 0x02
-#define BMP580_REG_CHIP_ID 0x01
+#define BMP580_REG_ID 0x01
/* OOR allows to configure a pressure alarm */
#define BMP580_REG_OOR_CONFIG 0x35
#define BMP580_REG_OOR_RANGE 0x34
@@ -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_10 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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 8/9] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (7 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-10-04 15:37 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 9/9] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
2025-10-04 15:07 ` [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Jonathan Cameron
10 siblings, 1 reply; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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 | 60 +++++++++++++++++++++++++++---
drivers/iio/pressure/bmp280.h | 2 +
2 files changed, 56 insertions(+), 6 deletions(-)
diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
index 9ade6d9e047b..4edabdd17f57 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"
@@ -764,9 +765,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)
@@ -1027,21 +1026,33 @@ static const unsigned long bme280_avail_scan_masks[] = {
static const int bmp280_odr_table[][2] = {
/* BMP280_ODR_FORCED is a driver feature, not a register setting */
[BMP280_ODR_FORCED] = { 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_994HZ] = { 0, 990000 },
[BMP280_ODR_0_498HZ] = { 0, 498000 },
[BMP280_ODR_0_250HZ] = { 0, 250000 },
};
+static const int bmp280_tstby_table[] = {
+ /* BMP280_ODR_FORCED is a driver feature, not a register setting */
+ [BMP280_ODR_FORCED] = 0,
+ [BMP280_ODR_144HZ] = 0.5*USEC_PER_MSEC,
+ [BMP280_ODR_14_5HZ] = 62.5*USEC_PER_MSEC,
+ [BMP280_ODR_7_60HZ] = 125*USEC_PER_MSEC,
+ [BMP280_ODR_3_90HZ] = 250*USEC_PER_MSEC,
+ [BMP280_ODR_1_97HZ] = 500*USEC_PER_MSEC,
+ [BMP280_ODR_0_994HZ] = 1*USEC_PER_SEC,
+ [BMP280_ODR_0_498HZ] = 2*USEC_PER_SEC,
+ [BMP280_ODR_0_250HZ] = 4*USEC_PER_SEC,
+};
+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] = {
/* BMP380_ODR_FORCED is a driver feature, not a register setting */
[BME280_ODR_FORCED] = { 0, 0 },
- [BME280_ODR_107HZ] = { 107, 0 },
[BME280_ODR_102HZ] = { 102, 0 },
[BME280_ODR_13_9HZ] = { 13, 900000 },
[BME280_ODR_7_44HZ] = { 7, 440000 },
@@ -1051,6 +1062,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[] = {
+ /* BMP380_ODR_FORCED is a driver feature, not a register setting */
+ [BME280_ODR_FORCED] = 0,
+ [BME280_ODR_102HZ] = 0.5*USEC_PER_MSEC,
+ [BME280_ODR_13_9HZ] = 62.5*USEC_PER_MSEC,
+ [BME280_ODR_7_44HZ] = 125*USEC_PER_MSEC,
+ [BME280_ODR_3_85HZ] = 250*USEC_PER_MSEC,
+ [BME280_ODR_1_96HZ] = 500*USEC_PER_MSEC,
+ [BME280_ODR_0_991HZ] = 1*USEC_PER_SEC,
+ [BME280_ODR_51_8HZ] = 10*USEC_PER_MSEC,
+ [BME280_ODR_34_1HZ] = 20*USEC_PER_MSEC,
+};
+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)
{
@@ -1130,6 +1155,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_conv(struct bmp280_data *data)
{
unsigned int reg, meas_time_us, initial_wait;
@@ -1197,6 +1239,8 @@ static int bmp280_chip_config(struct bmp280_data *data)
BMP280_OSRS_PRESS_MASK |
BMP280_MODE_MASK,
osr_temp | osr_press | mode);
+ /* Ensure a mode transition on next measurement */
+ data->op_mode = BMP280_SLEEP;
if (ret)
return ret;
if (ret) {
@@ -1305,6 +1349,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_FORCED,
@@ -1320,6 +1365,7 @@ const struct bmp280_chip_info bmp280_chip_info = {
.read_calib = bmp280_read_calib,
.set_mode = bmp280_set_mode,
.conv = bmp280_conv,
+ .calc_sampling_freq = bmp280_calc_sampling_freq,
.preinit = bmp280_preinit,
.trigger_handler = bmp280_trigger_handler,
@@ -1495,6 +1541,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_FORCED,
@@ -1513,6 +1560,7 @@ const struct bmp280_chip_info bme280_chip_info = {
.read_calib = bme280_read_calib,
.set_mode = bmp280_set_mode,
.conv = bmp280_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 8e05cdf869e7..ed7c5ad7d568 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 (*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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [RFC PATCH v3 9/9] iio: pressure: bmp280: test longer autosuspend (WIP)
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (8 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
@ 2025-09-28 17:26 ` Achim Gratz
2025-10-04 15:07 ` [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Jonathan Cameron
10 siblings, 0 replies; 19+ messages in thread
From: Achim Gratz @ 2025-09-28 17:26 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 4edabdd17f57..6415ac8e2927 100644
--- a/drivers/iio/pressure/bmp280-core.c
+++ b/drivers/iio/pressure/bmp280-core.c
@@ -3514,6 +3514,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.51.0
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v3 1/1] iio: pressure: bmp280: test longer autosuspend (WIP)
2025-09-28 17:26 ` [RFC PATCH v3 1/1] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
@ 2025-09-28 19:10 ` ASSI
0 siblings, 0 replies; 19+ messages in thread
From: ASSI @ 2025-09-28 19:10 UTC (permalink / raw)
To: linux-iio
Please disregard, this should not have been sent with this subject and
is patch 9/9 in the series.
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
` (9 preceding siblings ...)
2025-09-28 17:26 ` [RFC PATCH v3 9/9] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
@ 2025-10-04 15:07 ` Jonathan Cameron
2025-10-04 16:59 ` ASSI
10 siblings, 1 reply; 19+ messages in thread
From: Jonathan Cameron @ 2025-10-04 15:07 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 28 Sep 2025 19:26:27 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> 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
>
> v2 -> v3:
> - incorporate comments/suggestions on v2
> - clean up
>
> 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 (patches 0001 through
> 005) and implements additional functionality (patches 0006 through
> 009) 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 hardware is slightly different.
>
Hi Achim,
A small process related question. Why is this an RFC?
I'd typically expect an RFC to have a cover letter with some open questions
or another statement of why the author wants comments rather than the
code to be merged.
Jonathan
> 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: rename wait_conv() to conv(), factor out
> measurement time calculation
> 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 | 504 +++++++++++++++++++++--------
> drivers/iio/pressure/bmp280.h | 26 +-
> 2 files changed, 387 insertions(+), 143 deletions(-)
>
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v3 5/9] iio: pressure: bmp280: remove code duplication
2025-09-28 17:26 ` [RFC PATCH v3 5/9] iio: pressure: bmp280: remove code duplication Achim Gratz
@ 2025-10-04 15:12 ` Jonathan Cameron
0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2025-10-04 15:12 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 28 Sep 2025 19:26:33 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> 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>
Hi Achim
One minor thing inline. If nothing else comes up I might tweak this whilst
applying (though it's so minor I might not bother!)
J
> ---
> 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 2dd36493acb4..4f5c4bd89067 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->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;
> + }
Should you be respinning for any reason. Blank line here would be consistent with
other cases above and below.
> *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->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:
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v3 1/9] iio: pressure: bmp280: correct meas_time_us calculation
2025-09-28 17:26 ` [RFC PATCH v3 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
@ 2025-10-04 15:21 ` Jonathan Cameron
0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2025-10-04 15:21 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 28 Sep 2025 19:26:28 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Correction of meas_time_us initialization based on an observation and
> partial patch by David Lechner.
>
> The constant part of the measurement time (as described in the
> datasheet and implemented in the BM(P/E)2 Sensor API) was apparently
> forgotten (it was already correctly applied for the BMP380) and is now
> used.
>
> There was also another thinko in bmp280_wait_conv:
> data->oversampling_humid can actually have a value of 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 must 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>
Applied this to the fixes-togreg branch of iio.git. I'll send a pull request
for that shortly after rc1. The others will have to wait until that is available upstream.
>
> ---
>
> Notes
> =====
>
> Since the BMx280 device support was added, oversampling=0 actually is
> a valid register 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 as each read triggers a new measurement on all
> enabled channels. It is therefore also impossible to obtain all
> channel values from the same measurement cycle with MODE_FORCED, which
> is in a way a limitation of the sysfs interface and can only be
> obtained by using buffered reads.
> ---
> 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 6cdc8ed53520..2078b810745b 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 +
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v3 6/9] iio: pressure: bmp280: enable filter settings for BMx280
2025-09-28 17:26 ` [RFC PATCH v3 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
@ 2025-10-04 15:21 ` Jonathan Cameron
0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2025-10-04 15:21 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 28 Sep 2025 19:26:34 +0200
Achim Gratz <Achim.Gratz@Stromeko.DE> wrote:
> Follow the existing implementation for the BMx380 and BMx580 devices
> even though it doesn't conform to the API: The BMx280 devices were
> using a hardcoded value of 4, corresponding to the lowest corner
> frequency. Enable filter_low_pass_3db_frequency settings to control
> the filter settings of the device. The actual 3dB corner freqquency
> has an inverse relation to the value, which represents approximately
> the tau of the filter (for which the iio framework does not seem to
> have a suitable parameter).
>
> 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 ensure identical device behaviour after module load.
>
> A change of the implementation to actually follow the API (breaking
> existing userspace) requires further discussion and more extensive
> changes elsewhere in the code and are left for later.
I'm not keen to introduce additional cases of the non compliant ABI
even if it is just more parts in the same driver.
So patch looks fine in so far as what it does, but that issue is a blocker.
J
>
> ---
>
> Filter coefficient settings in hardware: off, 2, 4, 8, 16, mapped to
> register values 0, 1, 2, 3, 4 (that's i and 2**i below), 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) )
>
> That's the simplest filter that can be implemented in hardware,
> really; the canonical recursive single-pole LP with no gain 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 | 2**i | 1-d | d | tau | t>75% | datasheet | fc/fs |
> |---+------+--------+--------+--------+--------+-----------+----------|
> | 0 | 1 | 1 | 0 | --- | --- | 1 | 1 |
> | 1 | 2 | 0.5 | 0.5 | 1.443 | 2.000 | 2 | 0.110318 |
> | 2 | 4 | 0.25 | 0.75 | 3.476 | 4.819 | 5 | 0.045786 |
> | 3 | 8 | 0.125 | 0.875 | 7.489 | 10.382 | 11 | 0.021252 |
> | 4 | 16 | 0.0625 | 0.9375 | 15.495 | 21.481 | 22 | 0.010272 |
> |---+------+--------+--------+--------+--------+-----------+----------|
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
> ---
> drivers/iio/pressure/bmp280-core.c | 23 +++++++++++++++++++----
> 1 file changed, 19 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index 4f5c4bd89067..e72cfd4c10b9 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;
>
> @@ -1095,6 +1100,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 filter = FIELD_PREP(BMP280_FILTER_MASK, data->iir_filter_coeff;
> int ret;
>
> ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS,
> @@ -1109,7 +1115,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);
> + filter);
> if (ret) {
> dev_err(data->dev, "failed to write config register\n");
> return ret;
> @@ -1174,6 +1180,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,
> @@ -1203,6 +1210,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,
> @@ -1385,6 +1396,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,
> @@ -1982,7 +1997,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] 19+ messages in thread
* Re: [RFC PATCH v3 7/9] iio: pressure: bmp280: implement sampling_frequency for BMx280
2025-09-28 17:26 ` [RFC PATCH v3 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
@ 2025-10-04 15:32 ` Jonathan Cameron
0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2025-10-04 15:32 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 28 Sep 2025 19:26:35 +0200
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 read implementations for both modes. As MODE_FORCED is a driver
> feature, the corresponding entry in the ODR table has to be added
> after the actual register settings. The resulting register setting is
> either masked by the driver or clamped to a permissible value on
> device, so does not disturb the device operation. MODE_FORCE is
> triggered by setting a sampling frequency of 0Hz, following the
> precedent of stm32_timer_trigger.
>
> The bmp[235]_conv() functions check if the sensor already operates in
> NORMAL_MODE and skip waiting for measurement completion to save the
> overhead of the superfluous mode seting.
>
> The actual sampling frequency depends on the oversampling_ratio
> settings. In order to keep the constant ODR tables, 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 truncated to three significant
> digits; 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 in
> chip_config 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_conv into bmp280_calc_meas_time_us.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
>
A few unrelated changes have slipped in here that should be broken out
so that this patch is clearly doing just one thing rather than several.
> ---
>
> BME280 redefines the last two ODR register settings vs. BMP280, which
> are therefore out of order w.r.t. the other values.
>
> 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 | --- |
> | 4000.0 | 0.250 | --- |
> | 10.0 | --- | 51.813 |
> | 20.0 | --- | 34.130 |
> |--------+---------+---------|
>
> Proper consideration of the OSR when setting sampling_frequency could
> be introduced in a later patch after discussion of how to handle the
> combinatorial explosion of the table size or alternatively a
> complicated on-the-fly computation that also depends on the device
> type. Note in particular that there are combinations of OSR and ODR
> settings for the BMP580 at least that are illegal and hence replaced
> by the device with a default setting, something this driver also
> currently does not check for or handle.
I'm a little confused. Is calculating this on demand what the next patch
is doing?
>
> This driver currently also lacks the the *_available attributes and
> all associated implementation for all supported devices. This should
> be introduced in conjunction with the previously mentioned patch, so
> that the available settings for the current configuration can be
> obtained from user space.
> ---
> drivers/iio/pressure/bmp280-core.c | 297 ++++++++++++++++++++---------
> drivers/iio/pressure/bmp280.h | 22 ++-
> 2 files changed, 228 insertions(+), 91 deletions(-)
>
> diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c
> index e72cfd4c10b9..9ade6d9e047b 100644
> --- a/drivers/iio/pressure/bmp280-core.c
> +++ b/drivers/iio/pressure/bmp280-core.c
> @@ -816,7 +869,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 +946,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);
Rename is fine, but not in a patch doing anything more substantial.
> case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY:
> return bmp280_write_iir_filter_coeffs(data, val);
> default:
> @@ -971,6 +1024,34 @@ static const unsigned long bme280_avail_scan_masks[] = {
> 0
> };
> @@ -1098,24 +1185,28 @@ static int bmp280_conv(struct bmp280_data *data)
>
> 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 filter = FIELD_PREP(BMP280_FILTER_MASK, data->iir_filter_coeff;
> + u8 osr_temp = FIELD_PREP(BMP280_OSRS_TEMP_MASK, data->oversampling_temp + 1);
> + u8 osr_press = FIELD_PREP(BMP280_OSRS_PRESS_MASK, data->oversampling_press + 1);
> + u8 filter = FIELD_PREP(BMP280_FILTER_MASK, data->iir_filter_coeff);
> + u8 tstby = FIELD_PREP(BMP280_TSTBY_MASK, (data->sampling_freq ?: 1) - 1);
> + u8 mode = FIELD_PREP(BMP280_MODE_MASK, data->sampling_freq ? BMP280_NORMAL : BMP280_SLEEP);
> 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);
> + osr_temp | osr_press | mode);
> + if (ret)
> + return ret;
> if (ret) {
Some rebase issue? Can't get here for obvious reasons! :)
> dev_err(data->dev, "failed to write ctrl_meas register\n");
> return ret;
> }
> @@ -1675,24 +1774,26 @@ static int bmp380_read_calib(struct bmp280_data *data)
> }
>
> static const int bmp380_odr_table[][2] = {
> - [BMP380_ODR_200HZ] = {200, 0},
> - [BMP380_ODR_100HZ] = {100, 0},
> - [BMP380_ODR_50HZ] = {50, 0},
> - [BMP380_ODR_25HZ] = {25, 0},
> - [BMP380_ODR_12_5HZ] = {12, 500000},
> - [BMP380_ODR_6_25HZ] = {6, 250000},
> - [BMP380_ODR_3_125HZ] = {3, 125000},
> - [BMP380_ODR_1_5625HZ] = {1, 562500},
> - [BMP380_ODR_0_78HZ] = {0, 781250},
> - [BMP380_ODR_0_39HZ] = {0, 390625},
> - [BMP380_ODR_0_2HZ] = {0, 195313},
> - [BMP380_ODR_0_1HZ] = {0, 97656},
> - [BMP380_ODR_0_05HZ] = {0, 48828},
> - [BMP380_ODR_0_02HZ] = {0, 24414},
> - [BMP380_ODR_0_01HZ] = {0, 12207},
> - [BMP380_ODR_0_006HZ] = {0, 6104},
> - [BMP380_ODR_0_003HZ] = {0, 3052},
> - [BMP380_ODR_0_0015HZ] = {0, 1526},
> + /* BMP380_ODR_FORCED is a driver feature, not a register setting */
> + [BMP380_ODR_FORCED] = { 0, 0 },
Similar to below. The reformat is unrelated cause of noise in this patch
(but nice to have in a precursor!)
> + [BMP380_ODR_200HZ] = { 200, 0 },
> + [BMP380_ODR_100HZ] = { 100, 0 },
> + [BMP380_ODR_50HZ] = { 50, 0 },
> + [BMP380_ODR_25HZ] = { 25, 0 },
> + [BMP380_ODR_12_5HZ] = { 12, 500000 },
> + [BMP380_ODR_6_25HZ] = { 6, 250000 },
> + [BMP380_ODR_3_125HZ] = { 3, 125000 },
> + [BMP380_ODR_1_5625HZ] = { 1, 562500 },
> + [BMP380_ODR_0_78HZ] = { 0, 781250 },
> + [BMP380_ODR_0_39HZ] = { 0, 390625 },
> + [BMP380_ODR_0_2HZ] = { 0, 195313 },
> + [BMP380_ODR_0_1HZ] = { 0, 97656 },
> + [BMP380_ODR_0_05HZ] = { 0, 48828 },
> + [BMP380_ODR_0_02HZ] = { 0, 24414 },
> + [BMP380_ODR_0_01HZ] = { 0, 12207 },
> + [BMP380_ODR_0_006HZ] = { 0, 6104 },
> + [BMP380_ODR_0_003HZ] = { 0, 3052 },
> + [BMP380_ODR_0_0015HZ] = { 0, 1526 },
> };
> @@ -2061,7 +2169,7 @@ static int bmp580_soft_reset(struct bmp280_data *data)
> fsleep(2000);
>
> /* Dummy read of chip_id */
> - ret = regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®);
> + ret = regmap_read(data->regmap, BMP580_REG_ID, ®);
Unrelated change.
> if (ret) {
> dev_err(data->dev, "failed to reestablish comms after reset\n");
> return ret;
> @@ -2205,38 +2313,40 @@ static int bmp580_read_press(struct bmp280_data *data, u32 *raw_press)
> }
>
> static const int bmp580_odr_table[][2] = {
> - [BMP580_ODR_240HZ] = {240, 0},
whilst I do prefer your new formatting. That's mostly an unrelated change
that should be in a different patch. This one should just
introduce the new entrees.
> - [BMP580_ODR_218HZ] = {218, 0},
> - [BMP580_ODR_199HZ] = {199, 0},
> - [BMP580_ODR_179HZ] = {179, 0},
> - [BMP580_ODR_160HZ] = {160, 0},
> - [BMP580_ODR_149HZ] = {149, 0},
> - [BMP580_ODR_140HZ] = {140, 0},
> - [BMP580_ODR_129HZ] = {129, 0},
> - [BMP580_ODR_120HZ] = {120, 0},
> - [BMP580_ODR_110HZ] = {110, 0},
> - [BMP580_ODR_100HZ] = {100, 0},
> - [BMP580_ODR_89HZ] = {89, 0},
> - [BMP580_ODR_80HZ] = {80, 0},
> - [BMP580_ODR_70HZ] = {70, 0},
> - [BMP580_ODR_60HZ] = {60, 0},
> - [BMP580_ODR_50HZ] = {50, 0},
> - [BMP580_ODR_45HZ] = {45, 0},
> - [BMP580_ODR_40HZ] = {40, 0},
> - [BMP580_ODR_35HZ] = {35, 0},
> - [BMP580_ODR_30HZ] = {30, 0},
> - [BMP580_ODR_25HZ] = {25, 0},
> - [BMP580_ODR_20HZ] = {20, 0},
> - [BMP580_ODR_15HZ] = {15, 0},
> - [BMP580_ODR_10HZ] = {10, 0},
> - [BMP580_ODR_5HZ] = {5, 0},
> - [BMP580_ODR_4HZ] = {4, 0},
> - [BMP580_ODR_3HZ] = {3, 0},
> - [BMP580_ODR_2HZ] = {2, 0},
> - [BMP580_ODR_1HZ] = {1, 0},
> - [BMP580_ODR_0_5HZ] = {0, 500000},
> - [BMP580_ODR_0_25HZ] = {0, 250000},
> - [BMP580_ODR_0_125HZ] = {0, 125000},
> + /* BMP580_ODR_FORCED is a driver feature, not a register setting */
> + [BMP580_ODR_FORCED] = { 0, 0 },
> + [BMP580_ODR_240HZ] = { 240, 0 },
> + [BMP580_ODR_218HZ] = { 218, 0 },
> + [BMP580_ODR_199HZ] = { 199, 0 },
> + [BMP580_ODR_179HZ] = { 179, 0 },
> + [BMP580_ODR_160HZ] = { 160, 0 },
> + [BMP580_ODR_149HZ] = { 149, 0 },
> + [BMP580_ODR_140HZ] = { 140, 0 },
> + [BMP580_ODR_129HZ] = { 129, 0 },
> + [BMP580_ODR_120HZ] = { 120, 0 },
> + [BMP580_ODR_110HZ] = { 110, 0 },
> + [BMP580_ODR_100HZ] = { 100, 0 },
> + [BMP580_ODR_89HZ] = { 89, 0 },
> + [BMP580_ODR_80HZ] = { 80, 0 },
> + [BMP580_ODR_70HZ] = { 70, 0 },
> + [BMP580_ODR_60HZ] = { 60, 0 },
> + [BMP580_ODR_50HZ] = { 50, 0 },
> + [BMP580_ODR_45HZ] = { 45, 0 },
> + [BMP580_ODR_40HZ] = { 40, 0 },
> + [BMP580_ODR_35HZ] = { 35, 0 },
> + [BMP580_ODR_30HZ] = { 30, 0 },
> + [BMP580_ODR_25HZ] = { 25, 0 },
> + [BMP580_ODR_20HZ] = { 20, 0 },
> + [BMP580_ODR_15HZ] = { 15, 0 },
> + [BMP580_ODR_10HZ] = { 10, 0 },
> + [BMP580_ODR_5HZ] = { 5, 0 },
> + [BMP580_ODR_4HZ] = { 4, 0 },
> + [BMP580_ODR_3HZ] = { 3, 0 },
> + [BMP580_ODR_2HZ] = { 2, 0 },
> + [BMP580_ODR_1HZ] = { 1, 0 },
> + [BMP580_ODR_0_5HZ] = { 0, 500000 },
> + [BMP580_ODR_0_25HZ] = { 0, 250000 },
> + [BMP580_ODR_0_125HZ] = { 0, 125000 },
> };
>
> @@ -2707,7 +2821,7 @@ static const int bmp580_temp_coeffs[] = { 125, 13 };
> static const int bmp580_press_coeffs[] = { 1, 64000};
>
> const struct bmp280_chip_info bmp580_chip_info = {
> - .id_reg = BMP580_REG_CHIP_ID,
> + .id_reg = BMP580_REG_ID,
As below. Unrelated change. Separate patch with clear reasoning for why.
> .chip_id = bmp580_chip_ids,
> .num_chip_id = ARRAY_SIZE(bmp580_chip_ids),
> .regmap_config = &bmp580_regmap_config,
> @@ -3367,10 +3481,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);
Add a comment on why we need a sleep before setting the mode.
It's unusual to need resume to sleep before doing anything at all.
> + 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 df90ed720bc6..8e05cdf869e7 100644
> --- a/drivers/iio/pressure/bmp280.h
> +++ b/drivers/iio/pressure/bmp280.h
> @@ -13,7 +13,7 @@
> #define BMP580_REG_OSR_CONFIG 0x36
> #define BMP580_REG_IF_CONFIG 0x13
> #define BMP580_REG_REV_ID 0x02
> -#define BMP580_REG_CHIP_ID 0x01
> +#define BMP580_REG_ID 0x01
That looks like an unrelated change.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v3 8/9] iio: pressure: bmp280: implement sampling_frequency calculation for BMx280
2025-09-28 17:26 ` [RFC PATCH v3 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
@ 2025-10-04 15:37 ` Jonathan Cameron
0 siblings, 0 replies; 19+ messages in thread
From: Jonathan Cameron @ 2025-10-04 15:37 UTC (permalink / raw)
To: Achim Gratz; +Cc: linux-iio, David Lechner, Andy Shevchenko, Nuno Sá
On Sun, 28 Sep 2025 19:26:36 +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.
>
> Signed-off-by: Achim Gratz <Achim.Gratz@Stromeko.DE>
Ah. I see now (question in previous patch) that this is doing single point
(read of sampling_frequency) report rather than calculating the data
for sampling_frequency_available.
Fair enough as a start. Trying to represent the many effective control
dimensions for sampling frequency is challenging.
If we aren't providing read_avail for it that is fine.
I am a little confused wrt to controlling it though.
How do we adjust sampling frequency?
Jonathan
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver
2025-10-04 15:07 ` [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Jonathan Cameron
@ 2025-10-04 16:59 ` ASSI
0 siblings, 0 replies; 19+ messages in thread
From: ASSI @ 2025-10-04 16:59 UTC (permalink / raw)
To: linux-iio
Jonathan Cameron writes:
> A small process related question. Why is this an RFC?
I've been fixing up the driver on my end so I could update the kernel
again past v6.12 (I'm on 6.17 now, which has revealed some more issues
with the autosuspend), but it turns out that this driver has more than
one problem and I wasn't sure if they were all going to get fixed. I
think that's still an open question based on the feedback so far.
> I'd typically expect an RFC to have a cover letter with some open questions
> or another statement of why the author wants comments rather than the
> code to be merged.
Yeah, I guess I could have broken it up into more pieces and send them
separately, but then on the other hand I think that would have obscured
some of the issues that need discussion.
Regards,
Achim.
--
+<[Q+ Matrix-12 WAVE#46+305 Neuron microQkb Andromeda XTk Blofeld]>+
DIY Stuff:
http://Synth.Stromeko.net/DIY.html
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2025-10-04 16:59 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-28 17:26 [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 1/9] iio: pressure: bmp280: correct meas_time_us calculation Achim Gratz
2025-10-04 15:21 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 1/1] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
2025-09-28 19:10 ` ASSI
2025-09-28 17:26 ` [RFC PATCH v3 2/9] iio: pressure: bmp280: implement adaptive wait for BMx280 devices Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 3/9] iio: pressure: bmp280: implement adaptive wait for BMP380 devices Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 4/9] iio: pressure: bmp280: rename wait_conv() to conv(), factor out measurement time calculation Achim Gratz
2025-09-28 17:26 ` [RFC PATCH v3 5/9] iio: pressure: bmp280: remove code duplication Achim Gratz
2025-10-04 15:12 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 6/9] iio: pressure: bmp280: enable filter settings for BMx280 Achim Gratz
2025-10-04 15:21 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 7/9] iio: pressure: bmp280: implement sampling_frequency " Achim Gratz
2025-10-04 15:32 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 8/9] iio: pressure: bmp280: implement sampling_frequency calculation " Achim Gratz
2025-10-04 15:37 ` Jonathan Cameron
2025-09-28 17:26 ` [RFC PATCH v3 9/9] iio: pressure: bmp280: test longer autosuspend (WIP) Achim Gratz
2025-10-04 15:07 ` [RFC PATCH v3 0/9] Fixes and enhancements for the bmp280 driver Jonathan Cameron
2025-10-04 16:59 ` ASSI
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox