Add support for pressure sensor Bosch BMP580
Subsystems (2)
v3 cover Add support for pressure sensor Bosch BMP580
This patchset adds support for the new pressure sensors BMP580 extending the bmp280 driver.
Patch 1 introduces a minor refactor of the driver structure to change how the device matching and driver initialization is performed. In place of the chips ids, the driver_data now contains a pointer to its chip_info. To perform this change, a series of declarations previously on the core file were migrated to the shared header file, to allow access to specific fields on the chip_info on the I2C and SPI drivers. This change is required because BMP380 and BMP580 have the same chip_id and values would collide using the chip_id as the driver_data value.
Patch 2 introduces new preinit callback and unifies init logic across all supported variants.
Patch 3 made calibration callback function optional.
Patch 4 deletes misleading i2c reference on bmp280 Kconfig entry. Patch 5 extends the bmp280 driver with the new logic to read measurements and configure the operation parameters for the BMP580 sensors. Patch 6 updates the devicetree binding docs with the new sensor id. Patch 7 adds the NVMEM operations to read and program the NVM user range contained in the non-volatile memory of the BMP580 sensors.
Changes in v3:
* Refactor driver structure to use chip_info structs as driver_data and updated i2c and spi implementations device match codepaths.
* Deleted Kconfig driver title misleading i2c reference.
* Made calibration reading optional as a prerequisite patch in preparation for the bmp580 built in compensation.
* Break command helper function in soft-reset helper function and NVM operation helper.
* Fixed minor styling issues thorough patches.
Changes in v2:
* For patch 3, fixed missing retcodes reported by the kernel test robot.
* For patch 5, fixed logic paths that left the sensor mutex locked reported by the kernel test robot.
Angel Iglesias (7):
iio: pressure: bmp280: Use chip_info pointers for each chip as driver
data
iio: pressure: bmp280: Add preinit callback
iio: pressure: bmp280: Make read calibration callback optional
iio: pressure: Kconfig: Delete misleading I2C reference on bmp280
title
iio: pressure: bmp280: Add support for new sensor BMP580
dt-bindings: iio: pressure: bmp085: Add BMP580 compatible string
iio: pressure: bmp280: Add nvmem operations for BMP580
.../bindings/iio/pressure/bmp085.yaml | 2 + drivers/iio/pressure/Kconfig | 6 +- drivers/iio/pressure/bmp280-core.c | 762 ++++++++++++++---- drivers/iio/pressure/bmp280-i2c.c | 45 +- drivers/iio/pressure/bmp280-regmap.c | 60 ++ drivers/iio/pressure/bmp280-spi.c | 47 +- drivers/iio/pressure/bmp280.h | 273 ++++++- 7 files changed, 958 insertions(+), 237 deletions(-)
base-commit: 354f23ac2c8703d170354577738edad159a7d37b
Signature · 1 line
2.39.1
PATCH v3 1/7 iio: pressure: bmp280: Use chip_info pointers for each chip as driver data
Refactor driver I2C and SPI implementations using pointers for each variant's chip_info as the driver data. Adds the regmap configuration to the chip_info struct.
drivers/iio/pressure/bmp280-core.c +19 -171
@@ -49,65 +49,6 @@*/ enum {AC1 ,AC2 ,AC3 ,AC4 ,AC5 ,AC6 ,B1 ,B2 ,MB ,MC ,MD }; -struct bmp180_calib { -s16 AC1; -s16 AC2; -s16 AC3; -u16 AC4; -u16 AC5; -u16 AC6; -s16 B1; -s16 B2; -s16 MB; -s16 MC; -s16 MD; -}; - -/* See datasheet Section 4.2.2. */ -struct bmp280_calib { -u16 T1; -s16 T2; -s16 T3; -u16 P1; -s16 P2; -s16 P3; -s16 P4; -s16 P5; -s16 P6; -s16 P7; -s16 P8; -s16 P9; -u8 H1; -s16 H2; -u8 H3; -s16 H4; -s16 H5; -s8 H6; -}; - -/* See datasheet Section 3.11.1. */ -struct bmp380_calib { -u16 T1; -u16 T2; -s8 T3; -s16 P1; -s16 P2; -s8 P3; -s8 P4; -u16 P5; -u16 P6; -s8 P7; -s8 P8; -s16 P9; -s8 P10; -s8 P11; -}; - -static const char *const bmp280_supply_names[] = { -"vddd" ,"vdda" -}; - -#define BMP280_NUM_SUPPLIES ARRAY_SIZE(bmp280_supply_names)enum bmp380_odr {BMP380_ODR_200HZ ,
@@ -130,94 +71,6 @@ enum bmp380_odr { BMP380_ODR_0_0015HZ, }; -struct bmp280_data { -struct device *dev; -struct mutex lock; -struct regmap *regmap; -struct completion done; -bool use_eoc; -const struct bmp280_chip_info *chip_info; -union { -struct bmp180_calib bmp180; -struct bmp280_calib bmp280; -struct bmp380_calib bmp380; - } calib; -struct regulator_bulk_data supplies[BMP280_NUM_SUPPLIES ]; -unsigned int start_up_time;/* in microseconds */ - -/* log of base 2 of oversampling rate */ -u8 oversampling_press; -u8 oversampling_temp; -u8 oversampling_humid; -u8 iir_filter_coeff; - -/* -* BMP380 devices introduce sampling frequency configuration. See -* datasheet sections 3.3.3. and 4.3.19 for more details. -* -* BMx280 devices allowed indirect configuration of sampling frequency -* changing the t_standby duration between measurements, as detailed on -* section 3.6.3 of the datasheet. -*/ -int sampling_freq; - -/* -* Carryover value from temperature conversion, used in pressure -* calculation. -*/ -s32 t_fine; - -/* -* DMA (thus cache coherency maintenance) may require the -* transfer buffers to live in their own cache lines. -*/ -union { -/* Sensor data buffer */ -u8 buf[3 ]; -/* Calibration data buffers */ -__le16 bmp280_cal_buf[BMP280_CONTIGUOUS_CALIB_REGS /2 ]; -__be16 bmp180_cal_buf[BMP180_REG_CALIB_COUNT /2 ]; -u8 bmp380_cal_buf[BMP380_CALIB_REG_COUNT ]; -/* Miscellaneous, endianess-aware data buffers */ -__le16 le16; -__be16 be16; - }__aligned(IIO_DMA_MINALIGN) ; -}; - -struct bmp280_chip_info { -unsigned int id_reg; - -const struct iio_chan_spec *channels; -int num_channels; -unsigned int start_up_time; - -const int *oversampling_temp_avail; -int num_oversampling_temp_avail; -int oversampling_temp_default; - -const int *oversampling_press_avail; -int num_oversampling_press_avail; -int oversampling_press_default; - -const int *oversampling_humid_avail; -int num_oversampling_humid_avail; -int oversampling_humid_default; - -const int *iir_filter_coeffs_avail; -int num_iir_filter_coeffs_avail; -int iir_filter_coeff_default; - -const int (*sampling_freq_avail)[2 ]; -int num_sampling_freq_avail; -int sampling_freq_default; - -int (*chip_config)(struct bmp280_data *); -int (*read_temp)(struct bmp280_data *,int *); -int (*read_press)(struct bmp280_data *,int *,int *); -int (*read_humid)(struct bmp280_data *,int *,int *); -int (*read_calib)(struct bmp280_data *); -}; -/* * These enums are used for indexing into the array of compensation * parameters for BMP280.
@@ -905,8 +758,10 @@ static int bmp280_chip_config(struct bmp280_data *data)static const int bmp280_oversampling_avail[] = {1 ,2 ,4 ,8 ,16 }; -static const struct bmp280_chip_info bmp280_chip_info = { +const struct bmp280_chip_info bmp280_chip_info = { .id_reg =BMP280_REG_ID , + .chip_id =BMP280_CHIP_ID , + .regmap_config = &bmp280_regmap_config, .start_up_time =2000 , .channels = bmp280_channels, .num_channels =2 ,
@@ -934,6 +789,7 @@ static const struct bmp280_chip_info bmp280_chip_info = { .read_press = bmp280_read_press, .read_calib = bmp280_read_calib, }; +EXPORT_SYMBOL_NS (bmp280_chip_info,IIO_BMP280 );static int bme280_chip_config (struct bmp280_data *data) {
@@ -953,8 +809,10 @@ static int bme280_chip_config(struct bmp280_data *data)return bmp280_chip_config (data); } -static const struct bmp280_chip_info bme280_chip_info = { +const struct bmp280_chip_info bme280_chip_info = { .id_reg =BMP280_REG_ID , + .chip_id =BME280_CHIP_ID , + .regmap_config = &bmp280_regmap_config, .start_up_time =2000 , .channels = bmp280_channels, .num_channels =3 ,
@@ -977,6 +835,7 @@ static const struct bmp280_chip_info bme280_chip_info = { .read_humid = bmp280_read_humid, .read_calib = bme280_read_calib, }; +EXPORT_SYMBOL_NS (bme280_chip_info,IIO_BMP280 );/* * Helper function to send a command to BMP3XX sensors.
@@ -1319,8 +1178,10 @@ static int bmp380_chip_config(struct bmp280_data *data)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 struct bmp280_chip_info bmp380_chip_info = { +const struct bmp280_chip_info bmp380_chip_info = { .id_reg =BMP380_REG_ID , + .chip_id =BMP380_CHIP_ID , + .regmap_config = &bmp380_regmap_config, .start_up_time =2000 , .channels = bmp380_channels, .num_channels =2 ,
@@ -1346,6 +1207,7 @@ static const struct bmp280_chip_info bmp380_chip_info = { .read_press = bmp380_read_press, .read_calib = bmp380_read_calib, }; +EXPORT_SYMBOL_NS (bmp380_chip_info,IIO_BMP280 );static int bmp180_measure (struct bmp280_data *data,u8 ctrl_meas) {
@@ -1579,8 +1441,10 @@ static int bmp180_chip_config(struct bmp280_data *data)static const int bmp180_oversampling_temp_avail[] = {1 };static const int bmp180_oversampling_press_avail[] = {1 ,2 ,4 ,8 }; -static const struct bmp280_chip_info bmp180_chip_info = { +const struct bmp280_chip_info bmp180_chip_info = { .id_reg =BMP280_REG_ID , + .chip_id =BMP180_CHIP_ID , + .regmap_config = &bmp180_regmap_config, .start_up_time =2000 , .channels = bmp280_channels, .num_channels =2 ,
@@ -1600,6 +1464,7 @@ static const struct bmp280_chip_info bmp180_chip_info = { .read_press = bmp180_read_press, .read_calib = bmp180_read_calib, }; +EXPORT_SYMBOL_NS (bmp180_chip_info,IIO_BMP280 );static irqreturn_t bmp085_eoc_irq (int irq,void *d) {
@@ -1661,11 +1526,10 @@ static void bmp280_regulators_disable(void *data)int bmp280_common_probe (struct device *dev,struct regmap *regmap, -unsigned int chip, +const struct bmp280_chip_info *chip_info,const char *name,int irq) { -const struct bmp280_chip_info *chip_info;struct iio_dev *indio_dev;struct bmp280_data *data;struct gpio_desc *gpiod;
@@ -1684,22 +1548,6 @@ int bmp280_common_probe(struct device *dev, indio_dev->info = &bmp280_info; indio_dev->modes =INDIO_DIRECT_MODE ; -switch (chip) { -case BMP180_CHIP_ID : - chip_info = &bmp180_chip_info; -break ; -case BMP280_CHIP_ID : - chip_info = &bmp280_chip_info; -break ; -case BME280_CHIP_ID : - chip_info = &bme280_chip_info; -break ; -case BMP380_CHIP_ID : - chip_info = &bmp380_chip_info; -break ; -default : -return -EINVAL ; - } data->chip_info = chip_info;/* Apply initial values from chip info structure */
@@ -1751,9 +1599,9 @@ int bmp280_common_probe(struct device *dev, ret =regmap_read (regmap, data->chip_info->id_reg, &chip_id);if (ret <0 )return ret; -if (chip_id != chip) { +if (chip_id != data->chip_info->chip_id) {dev_err (dev,"bad chip id: expected %x got %x\n" , - chip, chip_id); + data->chip_info->chip_id, chip_id);return -EINVAL ; }
drivers/iio/pressure/bmp280-i2c.c +16 -27
68 lines not on this page · raw message
drivers/iio/pressure/bmp280-spi.c +17 -28
78 lines not on this page · raw message
drivers/iio/pressure/bmp280.h +163 -1
183 lines not on this page · raw message
Signature · 1 line
2.39.1
PATCH v3 2/7 iio: pressure: bmp280: Add preinit callback
In reply to Angel IglesiasAdds preinit callback to execute operations on probe before applying initial configuration.
drivers/iio/pressure/bmp280-core.c +12 -5
@@ -1076,6 +1076,12 @@ static const int bmp380_odr_table[][2] = { [BMP380_ODR_0_0015HZ] = {0, 1526}, }; +static int bmp380_preinit (struct bmp280_data *data) +{ +/* BMP3xx requires soft-reset as part of initialization */ +return bmp380_cmd (data,BMP380_CMD_SOFT_RESET ); +} +static int bmp380_chip_config (struct bmp280_data *data) {bool change = false, aux;
@@ -1206,6 +1212,7 @@ const struct bmp280_chip_info bmp380_chip_info = { .read_temp = bmp380_read_temp, .read_press = bmp380_read_press, .read_calib = bmp380_read_calib, + .preinit = bmp380_preinit, };EXPORT_SYMBOL_NS (bmp380_chip_info,IIO_BMP280 );
@@ -1605,11 +1612,11 @@ int bmp280_common_probe(struct device *dev,return -EINVAL ; } -/* BMP3xx requires soft-reset as part of initialization */ -if (chip_id ==BMP380_CHIP_ID ) { - ret =bmp380_cmd (data,BMP380_CMD_SOFT_RESET ); -if (ret <0 ) -return ret; +if (data->chip_info->preinit) { + ret = data->chip_info->preinit (data); +if (ret) +return dev_err_probe (data->dev, ret, +"error running preinit tasks\n" ); } ret = data->chip_info->chip_config (data);
drivers/iio/pressure/bmp280.h +1 -0
@@ -345,6 +345,7 @@ struct bmp280_chip_info {int (*read_press)(struct bmp280_data *,int *,int *);int (*read_humid)(struct bmp280_data *,int *,int *);int (*read_calib)(struct bmp280_data *); +int (*preinit)(struct bmp280_data *); };/* Chip infos for each variant */
Signature · 1 line
2.39.1
PATCH v3 3/7 iio: pressure: bmp280: Make read calibration callback optional
In reply to Angel IglesiasNewer models do not require read the calibration parameters and apply the compensation algorithms in the sensor.
drivers/iio/pressure/bmp280-core.c +6 -4
@@ -1631,10 +1631,12 @@ int bmp280_common_probe(struct device *dev,* time once. They will not change. */ - ret = data->chip_info->read_calib (data); -if (ret <0 ) -return dev_err_probe (data->dev, ret, -"failed to read calibration coefficients\n" ); +if (data->chip_info->read_calib) { + ret = data->chip_info->read_calib (data); +if (ret <0 ) +return dev_err_probe (data->dev, ret, +"failed to read calibration coefficients\n" ); + }/* * Attempt to grab an optional EOC IRQ - only the BMP085 has this
Signature · 1 line
2.39.1
PATCH v3 4/7 iio: pressure: Kconfig: Delete misleading I2C reference on bmp280 title
In reply to Angel IglesiasTitle entry for BMP280 called the driver an I2C implementation, when the driver supports both I2C and SPI.
drivers/iio/pressure/Kconfig +1 -1
@@ -17,7 +17,7 @@ config ABP060MG will be called abp060mg. config BMP280 - tristate "Bosch Sensortec BMP180/BMP280/BMP380 pressure sensor I2C driver" + tristate "Bosch Sensortec BMP180/BMP280/BMP380 pressure sensor driver" depends on (I2C || SPI_MASTER) select REGMAP select BMP280_I2C if (I2C)
Signature · 1 line
2.39.1
PATCH v3 5/7 iio: pressure: bmp280: Add support for new sensor BMP580
In reply to Angel IglesiasAdds compatibility with the new sensor generation, the BMP580.
The measurement and initialization codepaths are adapted from the device datasheet and the repository from manufacturer at
https://github.com/boschsensortec/BMP5-Sensor-API.
drivers/iio/pressure/Kconfig +3 -3
@@ -17,14 +17,14 @@ config ABP060MG will be called abp060mg. config BMP280 - tristate "Bosch Sensortec BMP180/BMP280/BMP380 pressure sensor driver" + tristate "Bosch Sensortec BMP180/BMP280/BMP380/BMP580 pressure sensor driver" depends on (I2C || SPI_MASTER) select REGMAP select BMP280_I2C if (I2C) select BMP280_SPI if (SPI_MASTER) help - Say yes here to build support for Bosch Sensortec BMP180, BMP280 and - BMP380 pressure and temperature sensors. Also supports the BME280 with + Say yes here to build support for Bosch Sensortec BMP180, BMP280, BMP380 + and BMP580 pressure and temperature sensors. Also supports the BME280 with an additional humidity sensor channel. To compile this driver as a module, choose M here: the core module
drivers/iio/pressure/bmp280-core.c +333 -0
351 lines not on this page · raw message
drivers/iio/pressure/bmp280-i2c.c +2 -0
@@ -34,6 +34,7 @@ static const struct of_device_id bmp280_of_i2c_match[] = { { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, { .compatible = "bosch,bme280", .data = &bme280_chip_info }, { .compatible = "bosch,bmp380", .data = &bmp380_chip_info }, + { .compatible = "bosch,bmp580", .data = &bmp580_chip_info }, { }, };MODULE_DEVICE_TABLE (of, bmp280_of_i2c_match);
@@ -44,6 +45,7 @@ static const struct i2c_device_id bmp280_i2c_id[] = { {"bmp280", (kernel_ulong_t)&bmp280_chip_info }, {"bme280", (kernel_ulong_t)&bme280_chip_info }, {"bmp380", (kernel_ulong_t)&bmp380_chip_info }, + {"bmp580", (kernel_ulong_t)&bmp580_chip_info }, { }, };MODULE_DEVICE_TABLE (i2c, bmp280_i2c_id);
drivers/iio/pressure/bmp280-regmap.c +60 -0
69 lines not on this page · raw message
drivers/iio/pressure/bmp280-spi.c +2 -0
@@ -85,6 +85,7 @@ static const struct of_device_id bmp280_of_spi_match[] = { { .compatible = "bosch,bmp280", .data = &bmp280_chip_info }, { .compatible = "bosch,bme280", .data = &bmp280_chip_info }, { .compatible = "bosch,bmp380", .data = &bmp380_chip_info }, + { .compatible = "bosch,bmp580", .data = &bmp580_chip_info }, { }, };MODULE_DEVICE_TABLE (of, bmp280_of_spi_match);
@@ -95,6 +96,7 @@ static const struct spi_device_id bmp280_spi_id[] = { { "bmp280", (kernel_ulong_t)&bmp280_chip_info }, { "bme280", (kernel_ulong_t)&bmp280_chip_info }, { "bmp380", (kernel_ulong_t)&bmp380_chip_info }, + { "bmp580", (kernel_ulong_t)&bmp580_chip_info }, { } };MODULE_DEVICE_TABLE (spi, bmp280_spi_id);
drivers/iio/pressure/bmp280.h +105 -0
128 lines not on this page · raw message
Signature · 1 line
2.39.1
PATCH v3 6/7 dt-bindings: iio: pressure: bmp085: Add BMP580 compatible string
In reply to Angel IglesiasAdd bosch,bmp580 to compatible string for the new family of sensors. This family includes the BMP580 and BMP581 sensors. The register map in this family presents significant departures from previous generations.
Documentation/devicetree/bindings/iio/pressure/bmp085.yaml +2 -0
@@ -17,6 +17,7 @@ description: | https://www.bosch-sensortec.com/bst/products/all_products/bmp280 https://www.bosch-sensortec.com/bst/products/all_products/bme280 https://www.bosch-sensortec.com/bst/products/all_products/bmp380 + https://www.bosch-sensortec.com/bst/products/all_products/bmp580 properties: compatible:
@@ -26,6 +27,7 @@ properties: - bosch,bmp280 - bosch,bme280 - bosch,bmp380 + - bosch,bmp580 reg: maxItems: 1
Signature · 1 line
2.39.1
PATCH v3 7/7 iio: pressure: bmp280: Add nvmem operations for BMP580
In reply to Angel IglesiasThe pressure sensor BMP580 contains a non-volatile memory that stores trimming and configuration params. That memory provides an programmable user range of three 2-byte words.
drivers/iio/pressure/bmp280-core.c +217 -1
@@ -28,6 +28,7 @@#include <linux/bitfield.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/nvmem-provider.h> #include <linux/regmap.h> #include <linux/delay.h> #include <linux/iio/iio.h>
@@ -1290,6 +1291,88 @@ static int bmp580_soft_reset(struct bmp280_data *data)return 0 ; } +#define NVM_READ false +#define NVM_WRITE true + +/** +* bmp580_nvm_operation() - Helper function to commit NVM memory operations +* @data: sensor data struct +* @is_write: flag to signal write operation +*/ +static int bmp580_nvm_operation (struct bmp280_data *data,bool is_write) +{ +unsigned long deadline; +unsigned int reg; +int ret; + +/* Check NVM ready flag */ + ret =regmap_read (data->regmap,BMP580_REG_STATUS , ®); +if (ret) { +dev_err (data->dev,"failed to check nvm status\n" ); +return ret; + } +if (!(reg &BMP580_STATUS_NVM_RDY_MASK )) { +dev_err (data->dev,"sensor's nvm is not ready\n" ); +return -EIO ; + } + +/* Send NVM operation sequence */ + ret =regmap_write (data->regmap,BMP580_REG_CMD ,BMP580_CMD_NVM_OP_SEQ_0 ); +if (ret) { +dev_err (data->dev,"failed to send nvm operation's first sequence\n" ); +return ret; + } +if (is_write) { +/* Send NVM write sequence */ + ret =regmap_write (data->regmap,BMP580_REG_CMD , +BMP580_CMD_NVM_WRITE_SEQ_1 ); +if (ret) { +dev_err (data->dev,"failed to send nvm write sequence\n" ); +return ret; + } +/* Datasheet says on 4.8.1.2 it takes approximately 10ms */ +usleep_range (10000 ,10500 ); + deadline = jiffies +msecs_to_jiffies (10 ); + }else { +/* Send NVM read sequence */ + ret =regmap_write (data->regmap,BMP580_REG_CMD , +BMP580_CMD_NVM_READ_SEQ_1 ); +if (ret) { +dev_err (data->dev,"failed to send nvm read sequence\n" ); +return ret; + } +/* Datasheet says on 4.8.1.1 it takes approximately 200us */ +usleep_range (200 ,250 ); + deadline = jiffies +usecs_to_jiffies (200 ); + } +if (ret) { +dev_err (data->dev,"failed to write command sequence\n" ); +return -EIO ; + } + +/* Wait until NVM is ready again */ +do { + ret =regmap_read (data->regmap,BMP580_REG_STATUS , ®); +if (ret) { +dev_err (data->dev,"failed to check nvm status\n" ); + reg &= ~BMP580_STATUS_NVM_RDY_MASK ; + } + }while (time_before (jiffies, deadline) && !(reg &BMP580_STATUS_NVM_RDY_MASK )); +if (!(reg &BMP580_STATUS_NVM_RDY_MASK )) { +dev_err (data->dev, +"reached timeout waiting for nvm operation completion\n" ); +return -ETIMEDOUT ; + } + +/* Check NVM error flags */ +if ((reg &BMP580_STATUS_NVM_ERR_MASK ) || (reg &BMP580_STATUS_NVM_CMD_ERR_MASK )) { +dev_err (data->dev,"error processing nvm operation\n" ); +return -EIO ; + } + +return 0 ; +} +/* * Contrary to previous sensors families, compensation algorithm is builtin. * We are only required to read the register raw data and adapt the ranges
@@ -1384,8 +1467,140 @@ static const int bmp580_odr_table[][2] = { [BMP580_ODR_0_125HZ] = {0, 125000}, }; +const int bmp580_nvmem_addrs[] = {0x20 ,0x21 ,0x22 }; + +static int bmp580_nvmem_read (void *priv,unsigned int offset,void *val, +size_t bytes) +{ +struct bmp280_data *data = priv; +u16 *dst = val; +int ret, addr; + +pm_runtime_get_sync (data->dev); +mutex_lock (&data->lock); + +/* Set sensor in standby mode */ + ret =regmap_update_bits (data->regmap,BMP580_REG_ODR_CONFIG , +BMP580_MODE_MASK |BMP580_ODR_DEEPSLEEP_DIS , +BMP580_ODR_DEEPSLEEP_DIS | +FIELD_PREP (BMP580_MODE_MASK ,BMP580_MODE_SLEEP )); +if (ret) { +dev_err (data->dev,"failed to change sensor to standby mode\n" ); + goto exit; + } +/* Wait standby transition time */ +usleep_range (2500 ,3000 ); + +while (bytes >=sizeof (u16)) { + addr = bmp580_nvmem_addrs[offset /sizeof (u16)]; + + ret =regmap_write (data->regmap,BMP580_REG_NVM_ADDR , +FIELD_PREP (BMP580_NVM_ROW_ADDR_MASK , addr)); +if (ret) { +dev_err (data->dev,"error writing nvm address\n" ); + goto exit; + } + + ret =bmp580_nvm_operation (data,NVM_READ ); +if (ret) + goto exit; + + ret =regmap_bulk_read (data->regmap,BMP580_REG_NVM_DATA_LSB , &data->le16, +sizeof (data->le16)); +if (ret) { +dev_err (data->dev,"error reading nvm data regs\n" ); + goto exit; + } + + *dst++ =le16_to_cpu (data->le16); + bytes -=sizeof (u16); + offset +=sizeof (u16); + } +exit: +/* Restore chip config */ + data->chip_info->chip_config (data); +mutex_unlock (&data->lock); +pm_runtime_mark_last_busy (data->dev); +pm_runtime_put_autosuspend (data->dev); +return ret; +} + +static int bmp580_nvmem_write (void *priv,unsigned int offset,void *val, +size_t bytes) +{ +struct bmp280_data *data = priv; +u16 *buf = val; +int ret, addr; + +pm_runtime_get_sync (data->dev); +mutex_lock (&data->lock); + +/* Set sensor in standby mode */ + ret =regmap_update_bits (data->regmap,BMP580_REG_ODR_CONFIG , +BMP580_MODE_MASK |BMP580_ODR_DEEPSLEEP_DIS , +BMP580_ODR_DEEPSLEEP_DIS | +FIELD_PREP (BMP580_MODE_MASK ,BMP580_MODE_SLEEP )); +if (ret) { +dev_err (data->dev,"failed to change sensor to standby mode\n" ); + goto exit; + } +/* Wait standby transition time */ +usleep_range (2500 ,3000 ); + +while (bytes >=sizeof (u16)) { + addr = bmp580_nvmem_addrs[offset /sizeof (u16)]; + + ret =regmap_write (data->regmap,BMP580_REG_NVM_ADDR ,BMP580_NVM_PROG_EN | +FIELD_PREP (BMP580_NVM_ROW_ADDR_MASK , addr)); +if (ret) { +dev_err (data->dev,"error writing nvm address\n" ); + goto exit; + } + data->le16 =cpu_to_le16 (*buf++); + + ret =regmap_bulk_write (data->regmap,BMP580_REG_NVM_DATA_LSB , &data->le16, +sizeof (data->le16)); +if (ret) { +dev_err (data->dev,"error writing LSB NVM data regs\n" ); + goto exit; + } + + ret =bmp580_nvm_operation (data,NVM_WRITE ); +if (ret) + goto exit; + +/* Disable programming mode bit */ + ret =regmap_update_bits (data->regmap,BMP580_REG_NVM_ADDR , +BMP580_NVM_PROG_EN ,0 ); +if (ret) { +dev_err (data->dev,"error resetting nvm write\n" ); + goto exit; + } + + bytes -=sizeof (u16); + offset +=sizeof (u16); + } +exit: +/* Restore chip config */ + data->chip_info->chip_config (data); +mutex_unlock (&data->lock); +pm_runtime_mark_last_busy (data->dev); +pm_runtime_put_autosuspend (data->dev); +return ret; +} +static int bmp580_preinit (struct bmp280_data *data) { +struct nvmem_config config = { + .dev = data->dev, + .priv = data, + .name ="bmp580_nvmem" , + .word_size =sizeof (u16), + .stride =sizeof (u16), + .size =3 *sizeof (u16), + .reg_read = bmp580_nvmem_read, + .reg_write = bmp580_nvmem_write, + };unsigned int reg;int ret;
@@ -1413,7 +1628,8 @@ static int bmp580_preinit(struct bmp280_data *data)return -EIO ; } -return 0 ; +/* Register nvmem device */ +return PTR_ERR_OR_ZERO (devm_nvmem_register (config.dev, &config)); }static int bmp580_chip_config (struct bmp280_data *data)
drivers/iio/pressure/bmp280.h +3 -0
@@ -104,6 +104,9 @@#define BMP580_FILTER_63X 6#define BMP580_FILTER_127X 7 +#define BMP580_NVM_ROW_ADDR_MASK GENMASK(5, 0) +#define BMP580_NVM_PROG_EN BIT(6) +#define BMP580_TEMP_SKIPPED 0x7f7f7f#define BMP580_PRESS_SKIPPED 0x7f7f7f
Signature · 1 line
2.39.1
Re: [PATCH v3 7/7] iio: pressure: bmp280: Add nvmem operations for BMP580
Quoted 3 lines · Angel Iglesias
The pressure sensor BMP580 contains a non-volatile memory that stores trimming and configuration params. That memory provides an programmable user range of three 2-byte words.
...
drivers/iio/pressure/bmp280-core.c static int bmp580_soft_reset(struct bmp280_data *data) · line 1295
Quoted 2 lines
drivers/iio/pressure/bmp280-core.c +2
-0+#define NVM_READ false +#define NVM_WRITE true
How is it helpful and why it's not namespaced properly (can collide with NVM framework)?
...
drivers/iio/pressure/bmp280-core.c static int bmp580_soft_reset(struct bmp280_data *data) · line 1360
Quoted 8 lines
drivers/iio/pressure/bmp280-core.c +8
-0+/* Wait until NVM is ready again */ +do { + ret =regmap_read (data->regmap,BMP580_REG_STATUS , ®); +if (ret) { +dev_err (data->dev,"failed to check nvm status\n" ); + reg &= ~BMP580_STATUS_NVM_RDY_MASK ; + } + }while (time_before (jiffies, deadline) && !(reg &BMP580_STATUS_NVM_RDY_MASK ));
regmap_read_poll_timeout()?
Review
Quoted 1 line
(quoted diff) +1
-0+ if (!(reg & BMP580_STATUS_NVM_RDY_MASK)) {
if (ret) {
...
return ret;
}Quoted 4 lines
drivers/iio/pressure/bmp280-core.c +4
-0+dev_err (data->dev, +"reached timeout waiting for nvm operation completion\n" ); +return -ETIMEDOUT ; + }
...
Review
Quoted 1 line
(quoted diff) +1
-0+ while (bytes >= sizeof(u16)) {
sizeof(*dst) ?
Or sizeof(data->le16)?
Review
Quoted 1 line
(quoted diff) +1
-0+ addr = bmp580_nvmem_addrs[offset / sizeof(u16)];
Ditto.
...
Review
Quoted 2 lines
(quoted diff) +2
-0+ bytes -= sizeof(u16); + offset += sizeof(u16);
Ditto.
Quoted 1 line
(quoted diff) +1
-0+ }
...
drivers/iio/pressure/bmp280-core.c static const int bmp580_odr_table[][2] = { · line 1530
Quoted 3 lines
drivers/iio/pressure/bmp280-core.c +3
-0+static int bmp580_nvmem_write (void *priv,unsigned int offset,void *val, +size_t bytes) +{
Same comments as per above function.
Quoted 1 line
}
Signature · 2 lines
With Best Regards, Andy Shevchenko
Quoted 12 lines · Angel Iglesias
This patchset adds support for the new pressure sensors BMP580 extending the bmp280 driver.
Patch 1 introduces a minor refactor of the driver structure to change how the device matching and driver initialization is performed. In place of the chips ids, the
driver_datanow contains a pointer to itschip_info. To perform this change, a series of declarations previously on the core file were migrated to the shared header file, to allow access to specific fields on thechip_infoon the I2C and SPI drivers. This change is required because BMP380 and BMP580 have the samechip_idand values would collide using thechip_idas thedriver_datavalue.
Patch 2 introduces new preinit callback and unifies init logic across all
Quoted 8 lines
supported variants.
Patch 3 made calibration callback function optional.
Patch 4 deletes misleading i2c reference on bmp280Kconfigentry. Patch 5 extends the bmp280 driver with the new logic to read measurements and configure the operation parameters for the BMP580 sensors. Patch 6 updates the devicetree binding docs with the new sensor id. Patch 7 adds the NVMEM operations to read and program the NVM user range contained in the non-volatile memory of the BMP580 sensors.
Patches 1-5 are good enough for me,
If anything, we can fix in the followups.
Signature · 2 lines
With Best Regards, Andy Shevchenko
Re: [PATCH v3 7/7] iio: pressure: bmp280: Add nvmem operations for BMP580
In reply to Andy ShevchenkoQuoted 5 lines · Andy Shevchenko
Quoted 3 lines · Angel Iglesias
The pressure sensor BMP580 contains a non-volatile memory that stores trimming and configuration params. That memory provides an programmable user range of three 2-byte words.
Quoted 7 lines
...
drivers/iio/pressure/bmp280-core.c static int bmp580_soft_reset(struct bmp280_data *data) · line 1295
Quoted 2 lines
drivers/iio/pressure/bmp280-core.c +2
-0+#define NVM_READ false +#define NVM_WRITE trueHow is it helpful and why it's not namespaced properly (can collide with NVM framework)?
I thought it could provide clarity using those aliases calling bmp580_nvm_operation() helper function on nvmen callbacks, instead of using just true or false. Not my brightest idea for sure.
Quoted 12 lines
...
Quoted 9 lines
+ /* Wait until NVM is ready again */
+ do {
+ ret =regmap_read(data->regmap, BMP580_REG_STATUS, ®); + if (ret) {
+ dev_err(data->dev, "failed to check nvm status\n"); + reg &= ~BMP580_STATUS_NVM_RDY_MASK;
+ }
+ } while (time_before(jiffies, deadline)&& !(reg &BMP580_STATUS_NVM_RDY_MASK));
Quoted 1 line
regmap_read_poll_timeout()?
Yes, thanks for pointing out, that's way better than the current loop.
Quoted 35 lines
Quoted 2 lines
+ if (!(reg &
BMP580_STATUS_NVM_RDY_MASK)) {if (ret) {
...
return ret;
}Quoted 5 lines
+ dev_err(data->dev,
+ "reached timeout waiting for nvm operation completion\n");
+ return-ETIMEDOUT;
+ }...
Quoted 1 line
+ while (bytes >= sizeof(u16)) {
sizeof(*dst)?Or
sizeof(data->le16)?Quoted 1 line
+ addr = bmp580_nvmem_addrs[offset / sizeof(u16)];
Ditto.
...
Quoted 2 lines
+ bytes -= sizeof(u16);
+ offset += sizeof(u16);Ditto.
Quoted 1 line
+ }
Quoted 7 lines
...
drivers/iio/pressure/bmp280-core.c static const int bmp580_odr_table[][2] = { · line 1530
Quoted 3 lines
drivers/iio/pressure/bmp280-core.c +3
-0+static int bmp580_nvmem_write (void *priv,unsigned int offset,void *val, + size_t bytes) +{Same comments as per above function.
Got it!
Quoted 3 lines
Quoted 1 line
}
Thanks for your time,
Angel
Jonathan Cameron
maintainerRe: [PATCH v3 5/7] iio: pressure: bmp280: Add support for new sensor BMP580
In reply to Angel IglesiasQuoted 8 lines · On Sun, 29 Jan 2023 02:33:07 +0100 Angel Iglesias <[email protected]>…
Adds compatibility with the new sensor generation, the BMP580.
The measurement and initialization codepaths are adapted from the device datasheet and the repository from manufacturer at
https://github.com/boschsensortec/BMP5-Sensor-API.Signed-off-by Angel Iglesias <[email protected]>
Hi Angel,
As you are doing one more version anyway, a few really minor comments inline.
Thanks,
Jonathan
Quoted 9 lines
drivers/iio/pressure/bmp280-core.c +0
-0/* * These enums are used for indexing into the array of compensation * parameters for BMP280.
drivers/iio/pressure/bmp280-core.c const struct bmp280_chip_info bmp380_chip_info = { · line 1256
Quoted 5 lines
drivers/iio/pressure/bmp280-core.c +2
-0@@ -1216,6 +1252,303 @@ const struct bmp280_chip_info bmp380_chip_info = { };EXPORT_SYMBOL_NS (bmp380_chip_info,IIO_BMP280 ); +/* +* BMP5xx soft reset procedure
Wild cards are often a bad idea, even in comments. Tend to end up covering some device that works differently. With that in mind, not sure this comment adds anything over the function name.
drivers/iio/pressure/bmp280-core.c const struct bmp280_chip_info bmp380_chip_info = { · line 1263
Quoted 7 lines
drivers/iio/pressure/bmp280-core.c +7
-0+*/ +static int bmp580_soft_reset (struct bmp280_data *data) +{ +unsigned int reg; +int ret; + +/* Write reset word to CMD register */
Not that informative as comments go.
drivers/iio/pressure/bmp280-core.c const struct bmp280_chip_info bmp380_chip_info = { · line 1269
Quoted 6 lines
drivers/iio/pressure/bmp280-core.c +6
-0+ ret =regmap_write (data->regmap,BMP580_REG_CMD ,BMP580_CMD_SOFT_RESET ); +if (ret) { +dev_err (data->dev,"failed to send reset command to device\n" ); +return ret; + } +/* Wait 2ms for reset completion */
nor is this one - drop them both.
drivers/iio/pressure/bmp280-core.c const struct bmp280_chip_info bmp380_chip_info = { · line 1272
Quoted 3 lines
drivers/iio/pressure/bmp280-core.c +3
-0+usleep_range (2000 ,2500 ); + +/* Dummy read of chip_id */
Now this one is good as not obvious why read is here so keep it!
drivers/iio/pressure/bmp280-core.c const struct bmp280_chip_info bmp380_chip_info = { · line 1279
Quoted 7 lines
drivers/iio/pressure/bmp280-core.c +7
-0+ ret =regmap_read (data->regmap,BMP580_REG_CHIP_ID , ®); +if (ret) { +dev_err (data->dev,"failed to reestablish comms after reset\n" ); +return ret; + } + +/* Check if POR bit is set on interrupt reg */
Not sure the comment adds anything not obviously from code. I'd be inclined to drop it.
Quoted 33 lines
drivers/iio/pressure/bmp280-core.c +33
-0+ ret =regmap_read (data->regmap,BMP580_REG_INT_STATUS , ®); +if (ret) { +dev_err (data->dev,"error reading interrupt status register\n" ); +return ret; + } +if (!(reg &BMP580_INT_STATUS_POR_MASK )) { +dev_err (data->dev,"error resetting sensor\n" ); +return -EINVAL ; + } + +return 0 ; +} + +/* +* Contrary to previous sensors families, compensation algorithm is builtin. +* We are only required to read the register raw data and adapt the ranges +* for what is expected on IIO ABI. +*/ + +static int bmp580_read_temp (struct bmp280_data *data,int *val) +{ +s32 raw_temp; +int ret; + + ret =regmap_bulk_read (data->regmap,BMP580_REG_TEMP_XLSB , data->buf, +sizeof (data->buf)); +if (ret) { +dev_err (data->dev,"failed to read temperature\n" ); +return ret; + } + + raw_temp =get_unaligned_le24 (data->buf); +if (raw_temp ==BMP580_TEMP_SKIPPED ) {
drivers/iio/pressure/bmp280-core.c const struct bmp280_chip_info bmp380_chip_info = { · line 1322
Quoted 10 lines
drivers/iio/pressure/bmp280-core.c +10
-0+dev_err (data->dev,"reading temperature skipped\n" ); +return -EIO ; + } + +/* +* Temperature is returned in Celsius degrees in fractional +* form down 2^16. We reescale by x1000 to return milli Celsius +* to respect IIO ABI. +*/ + *val = (raw_temp *1000 ) >>16 ;
Why not use IIO_VAL_FRACTION_LOG2 and keep the precision?
Quoted 2 lines
drivers/iio/pressure/bmp280-core.c +2
-0+return IIO_VAL_INT ; +}
Re: [PATCH v3 5/7] iio: pressure: bmp280: Add support for new sensor BMP580
Quoted 40 lines · Jonathan Cameron
Quoted 8 lines · On Sun, 29 Jan 2023 02:33:07 +0100 Angel Iglesias <[email protected]>…
Adds compatibility with the new sensor generation, the BMP580.
The measurement and initialization codepaths are adapted from the device datasheet and the repository from manufacturer at
https://github.com/boschsensortec/BMP5-Sensor-API.Signed-off-by Angel Iglesias <[email protected]>Hi Angel,
As you are doing one more version anyway, a few really minor comments inline.
Thanks,
Jonathan
Quoted 12 lines
drivers/iio/pressure/bmp280-core.c +0
-0/*
* These enums are used for indexing into the array of compensation
* parameters for BMP280.drivers/iio/pressure/bmp280-core.c +0
-0@@ -1216,6 +1252,303 @@ const struct bmp280_chip_info bmp380_chip_info = { }; EXPORT_SYMBOL_NS(bmp380_chip_info, IIO_BMP280);Quoted 3 lines
+/*
+ * BMP5xx soft reset procedureWild cards are often a bad idea, even in comments. Tend to end up covering some device that works differently. With that in mind, not sure this comment adds anything over the function name.
Quoted 8 lines
drivers/iio/pressure/bmp280-core.c const struct bmp280_chip_info bmp380_chip_info = { · line 1263
Quoted 7 lines
+ */
drivers/iio/pressure/bmp280-core.c +6
-0+static int bmp580_soft_reset (struct bmp280_data *data) +{ + unsigned int reg; + int ret; + + /* Write reset word to CMD register */Not that informative as comments go.
Understood!
Quoted 64 lines
Quoted 9 lines
+ ret =
regmap_write(data->regmap, BMP580_REG_CMD, BMP580_CMD_SOFT_RESET);
+ if (ret) {
+ dev_err(data->dev, "failed to send reset command to device\n");
+ return ret;
+ }
+ /* Wait 2ms for reset completion */nor is this one - drop them both.
Quoted 3 lines
+ usleep_range(2000, 2500);
+
+ /* Dummy read ofchip_id*/Now this one is good as not obvious why read is here so keep it!
Quoted 8 lines
+ ret =
regmap_read(data->regmap, BMP580_REG_CHIP_ID, ®); + if (ret) {
+ dev_err(data->dev, "failed to reestablish comms after reset\n");
+ return ret;
+ }
+
+ /* Check if POR bit is set on interrupt reg */Not sure the comment adds anything not obviously from code. I'd be inclined to drop it.
Quoted 40 lines
+ ret =
regmap_read(data->regmap, BMP580_REG_INT_STATUS, ®); + if (ret) {
+ dev_err(data->dev, "error reading interrupt status register\n");
+ return ret;
+ }
+ if (!(reg &BMP580_INT_STATUS_POR_MASK)) {
+ dev_err(data->dev, "error resetting sensor\n"); + return-EINVAL;
+ }drivers/iio/pressure/bmp280-core.c +6
-0+ + return 0; +} + +/* +* Contrary to previous sensors families, compensation algorithm is builtin.
+ * We are only required to read the register raw data and adapt the ranges
+ * for what is expected on IIO ABI.
+ */drivers/iio/pressure/bmp280-core.c +7
-0+ +static int bmp580_read_temp (struct bmp280_data *data,int *val) +{ + s32 raw_temp; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP580_REG_TEMP_XLSB, data-Quoted 1 line
buf,
+
sizeof(data->buf));
+ if (ret) {
+ dev_err(data->dev, "failed to read temperature\n"); + return ret;
+ }drivers/iio/pressure/bmp280-core.c +7
-0+ + raw_temp = get_unaligned_le24(data->buf); + if (raw_temp == BMP580_TEMP_SKIPPED) { + dev_err(data->dev, "reading temperature skipped\n"); + return -EIO; + } +
Quoted 8 lines
Quoted 6 lines
+ /*
+ * Temperature is returned in Celsius degrees in fractional + * form down 2^16. We reescale by x1000 to return milli Celsius + * to respect IIO ABI.
+ */
+ *val = (raw_temp* 1000) >> 16;Why not use
IIO_VAL_FRACTION_LOG2and keep the precision?
Although this sensor has a resolution of 1/2^16, its absolute accuracy is of +/- 0.5ºC so I suppose in the end we aren't really losing precision. But in the future a high accuracy variant of the sensor might pop up (like the bmp384 in the previous gen) so I think is a good idea to keep the precision. Thanks for the heads up!
Quoted 4 lines
Quoted 2 lines
+ return
IIO_VAL_INT;
+}
Thanks for your time!
Angel