diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-10-08 18:56:37 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-10-08 18:56:37 +0300 |
commit | a09476668e3016ea4a7b0a7ebd02f44e0546c12c (patch) | |
tree | 0a2e435d40b1785bc3df0c455fbf858adc28d36c /drivers/iio/pressure | |
parent | e8bc52cb8df80c31c73c726ab58ea9746e9ff734 (diff) | |
parent | 7cd04013fbf3e6dcb67ca6b59aa813269a2ad9ce (diff) | |
download | linux-a09476668e3016ea4a7b0a7ebd02f44e0546c12c.tar.xz |
Merge tag 'char-misc-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc and other driver updates from Greg KH:
"Here is the large set of char/misc and other small driver subsystem
changes for 6.1-rc1. Loads of different things in here:
- IIO driver updates, additions, and changes. Probably the largest
part of the diffstat
- habanalabs driver update with support for new hardware and
features, the second largest part of the diff.
- fpga subsystem driver updates and additions
- mhi subsystem updates
- Coresight driver updates
- gnss subsystem updates
- extcon driver updates
- icc subsystem updates
- fsi subsystem updates
- nvmem subsystem and driver updates
- misc driver updates
- speakup driver additions for new features
- lots of tiny driver updates and cleanups
All of these have been in the linux-next tree for a while with no
reported issues"
* tag 'char-misc-6.1-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (411 commits)
w1: Split memcpy() of struct cn_msg flexible array
spmi: pmic-arb: increase SPMI transaction timeout delay
spmi: pmic-arb: block access for invalid PMIC arbiter v5 SPMI writes
spmi: pmic-arb: correct duplicate APID to PPID mapping logic
spmi: pmic-arb: add support to dispatch interrupt based on IRQ status
spmi: pmic-arb: check apid against limits before calling irq handler
spmi: pmic-arb: do not ack and clear peripheral interrupts in cleanup_irq
spmi: pmic-arb: handle spurious interrupt
spmi: pmic-arb: add a print in cleanup_irq
drivers: spmi: Directly use ida_alloc()/free()
MAINTAINERS: add TI ECAP driver info
counter: ti-ecap-capture: capture driver support for ECAP
Documentation: ABI: sysfs-bus-counter: add frequency & num_overflows items
dt-bindings: counter: add ti,am62-ecap-capture.yaml
counter: Introduce the COUNTER_COMP_ARRAY component type
counter: Consolidate Counter extension sysfs attribute creation
counter: Introduce the Count capture component
counter: 104-quad-8: Add Signal polarity component
counter: Introduce the Signal polarity component
counter: interrupt-cnt: Implement watch_validate callback
...
Diffstat (limited to 'drivers/iio/pressure')
-rw-r--r-- | drivers/iio/pressure/Kconfig | 6 | ||||
-rw-r--r-- | drivers/iio/pressure/bmp280-core.c | 974 | ||||
-rw-r--r-- | drivers/iio/pressure/bmp280-i2c.c | 15 | ||||
-rw-r--r-- | drivers/iio/pressure/bmp280-regmap.c | 55 | ||||
-rw-r--r-- | drivers/iio/pressure/bmp280-spi.c | 5 | ||||
-rw-r--r-- | drivers/iio/pressure/bmp280.h | 164 | ||||
-rw-r--r-- | drivers/iio/pressure/dlhl60d.c | 5 | ||||
-rw-r--r-- | drivers/iio/pressure/dps310.c | 262 | ||||
-rw-r--r-- | drivers/iio/pressure/icp10100.c | 10 | ||||
-rw-r--r-- | drivers/iio/pressure/st_pressure.h | 2 | ||||
-rw-r--r-- | drivers/iio/pressure/st_pressure_core.c | 70 | ||||
-rw-r--r-- | drivers/iio/pressure/st_pressure_i2c.c | 5 | ||||
-rw-r--r-- | drivers/iio/pressure/st_pressure_spi.c | 5 |
13 files changed, 1276 insertions, 302 deletions
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 0ff756cea63a..c9453389e4f7 100644 --- a/drivers/iio/pressure/Kconfig +++ b/drivers/iio/pressure/Kconfig @@ -17,14 +17,14 @@ config ABP060MG will be called abp060mg. config BMP280 - tristate "Bosch Sensortec BMP180/BMP280 pressure sensor I2C driver" + tristate "Bosch Sensortec BMP180/BMP280/BMP380 pressure sensor I2C 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 and BMP280 - pressure and temperature sensors. Also supports the BME280 with + Say yes here to build support for Bosch Sensortec BMP180, BMP280 and + BMP380 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 diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index fe7aa81e7cc9..c0aff78489b4 100644 --- a/drivers/iio/pressure/bmp280-core.c +++ b/drivers/iio/pressure/bmp280-core.c @@ -9,13 +9,22 @@ * Driver for Bosch Sensortec BMP180 and BMP280 digital pressure sensor. * * Datasheet: - * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP180-DS000-121.pdf - * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BMP280-DS001-12.pdf - * https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME280_DS001-11.pdf + * https://cdn-shop.adafruit.com/datasheets/BST-BMP180-DS000-09.pdf + * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf + * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf + * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp388-ds001.pdf + * + * Notice: + * The link to the bmp180 datasheet points to an outdated version missing these changes: + * - Changed document referral from ANP015 to BST-MPS-AN004-00 on page 26 + * - Updated equation for B3 param on section 3.5 to ((((long)AC1 * 4 + X3) << oss) + 2) / 4 + * - Updated RoHS directive to 2011/65/EU effective 8 June 2011 on page 26 */ #define pr_fmt(fmt) "bmp280: " fmt +#include <linux/bitops.h> +#include <linux/bitfield.h> #include <linux/device.h> #include <linux/module.h> #include <linux/regmap.h> @@ -30,6 +39,8 @@ #include <linux/pm_runtime.h> #include <linux/random.h> +#include <asm/unaligned.h> + #include "bmp280.h" /* @@ -74,12 +85,51 @@ struct bmp280_calib { 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, + BMP380_ODR_100HZ, + BMP380_ODR_50HZ, + BMP380_ODR_25HZ, + BMP380_ODR_12_5HZ, + BMP380_ODR_6_25HZ, + BMP380_ODR_3_125HZ, + BMP380_ODR_1_5625HZ, + BMP380_ODR_0_78HZ, + BMP380_ODR_0_39HZ, + BMP380_ODR_0_2HZ, + BMP380_ODR_0_1HZ, + BMP380_ODR_0_05HZ, + BMP380_ODR_0_02HZ, + BMP380_ODR_0_01HZ, + BMP380_ODR_0_006HZ, + BMP380_ODR_0_003HZ, + BMP380_ODR_0_0015HZ, +}; + struct bmp280_data { struct device *dev; struct mutex lock; @@ -90,6 +140,7 @@ struct bmp280_data { 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 */ @@ -98,36 +149,99 @@ struct bmp280_data { 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. */ -enum { T1, T2, T3 }; -enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 }; +enum { T1, T2, T3, P1, P2, P3, P4, P5, P6, P7, P8, P9 }; + +enum { + /* Temperature calib indexes */ + BMP380_T1 = 0, + BMP380_T2 = 2, + BMP380_T3 = 4, + /* Pressure calib indexes */ + BMP380_P1 = 5, + BMP380_P2 = 7, + BMP380_P3 = 9, + BMP380_P4 = 10, + BMP380_P5 = 11, + BMP380_P6 = 13, + BMP380_P7 = 15, + BMP380_P8 = 16, + BMP380_P9 = 17, + BMP380_P10 = 19, + BMP380_P11 = 20, +}; static const struct iio_chan_spec bmp280_channels[] = { { @@ -147,56 +261,81 @@ static const struct iio_chan_spec bmp280_channels[] = { }, }; -static int bmp280_read_calib(struct bmp280_data *data, - struct bmp280_calib *calib, - unsigned int chip) +static const struct iio_chan_spec bmp380_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + }, + { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + }, + { + .type = IIO_HUMIDITYRELATIVE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) | + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ) | + BIT(IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY), + }, +}; + +static int bmp280_read_calib(struct bmp280_data *data) { + struct bmp280_calib *calib = &data->calib.bmp280; int ret; - unsigned int tmp; - __le16 l16; - __be16 b16; - struct device *dev = data->dev; - __le16 t_buf[BMP280_COMP_TEMP_REG_COUNT / 2]; - __le16 p_buf[BMP280_COMP_PRESS_REG_COUNT / 2]; - /* Read temperature calibration values. */ + + /* Read temperature and pressure calibration values. */ ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START, - t_buf, BMP280_COMP_TEMP_REG_COUNT); + data->bmp280_cal_buf, sizeof(data->bmp280_cal_buf)); if (ret < 0) { dev_err(data->dev, - "failed to read temperature calibration parameters\n"); + "failed to read temperature and pressure calibration parameters\n"); return ret; } - /* Toss the temperature calibration data into the entropy pool */ - add_device_randomness(t_buf, sizeof(t_buf)); + /* Toss the temperature and pressure calibration data into the entropy pool */ + add_device_randomness(data->bmp280_cal_buf, sizeof(data->bmp280_cal_buf)); + + /* Parse temperature calibration values. */ + calib->T1 = le16_to_cpu(data->bmp280_cal_buf[T1]); + calib->T2 = le16_to_cpu(data->bmp280_cal_buf[T2]); + calib->T3 = le16_to_cpu(data->bmp280_cal_buf[T3]); + + /* Parse pressure calibration values. */ + calib->P1 = le16_to_cpu(data->bmp280_cal_buf[P1]); + calib->P2 = le16_to_cpu(data->bmp280_cal_buf[P2]); + calib->P3 = le16_to_cpu(data->bmp280_cal_buf[P3]); + calib->P4 = le16_to_cpu(data->bmp280_cal_buf[P4]); + calib->P5 = le16_to_cpu(data->bmp280_cal_buf[P5]); + calib->P6 = le16_to_cpu(data->bmp280_cal_buf[P6]); + calib->P7 = le16_to_cpu(data->bmp280_cal_buf[P7]); + calib->P8 = le16_to_cpu(data->bmp280_cal_buf[P8]); + calib->P9 = le16_to_cpu(data->bmp280_cal_buf[P9]); - calib->T1 = le16_to_cpu(t_buf[T1]); - calib->T2 = le16_to_cpu(t_buf[T2]); - calib->T3 = le16_to_cpu(t_buf[T3]); + return 0; +} - /* Read pressure calibration values. */ - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START, - p_buf, BMP280_COMP_PRESS_REG_COUNT); - if (ret < 0) { - dev_err(data->dev, - "failed to read pressure calibration parameters\n"); +static int bme280_read_calib(struct bmp280_data *data) +{ + struct bmp280_calib *calib = &data->calib.bmp280; + struct device *dev = data->dev; + unsigned int tmp; + int ret; + + /* Load shared calibration params with bmp280 first */ + ret = bmp280_read_calib(data); + if (ret < 0) { + dev_err(dev, "failed to read common bmp280 calibration parameters\n"); return ret; } - /* Toss the pressure calibration data into the entropy pool */ - add_device_randomness(p_buf, sizeof(p_buf)); - - calib->P1 = le16_to_cpu(p_buf[P1]); - calib->P2 = le16_to_cpu(p_buf[P2]); - calib->P3 = le16_to_cpu(p_buf[P3]); - calib->P4 = le16_to_cpu(p_buf[P4]); - calib->P5 = le16_to_cpu(p_buf[P5]); - calib->P6 = le16_to_cpu(p_buf[P6]); - calib->P7 = le16_to_cpu(p_buf[P7]); - calib->P8 = le16_to_cpu(p_buf[P8]); - calib->P9 = le16_to_cpu(p_buf[P9]); - /* * Read humidity calibration values. * Due to some odd register addressing we cannot just @@ -204,8 +343,6 @@ static int bmp280_read_calib(struct bmp280_data *data, * value separately and sometimes do some bit shifting... * Humidity data is only available on BME280. */ - if (chip != BME280_CHIP_ID) - return 0; ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &tmp); if (ret < 0) { @@ -214,12 +351,13 @@ static int bmp280_read_calib(struct bmp280_data *data, } calib->H1 = tmp; - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &l16, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, + &data->le16, sizeof(data->le16)); if (ret < 0) { dev_err(dev, "failed to read H2 comp value\n"); return ret; } - calib->H2 = sign_extend32(le16_to_cpu(l16), 15); + calib->H2 = sign_extend32(le16_to_cpu(data->le16), 15); ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &tmp); if (ret < 0) { @@ -228,20 +366,22 @@ static int bmp280_read_calib(struct bmp280_data *data, } calib->H3 = tmp; - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &b16, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, + &data->be16, sizeof(data->be16)); if (ret < 0) { dev_err(dev, "failed to read H4 comp value\n"); return ret; } - calib->H4 = sign_extend32(((be16_to_cpu(b16) >> 4) & 0xff0) | - (be16_to_cpu(b16) & 0xf), 11); + calib->H4 = sign_extend32(((be16_to_cpu(data->be16) >> 4) & 0xff0) | + (be16_to_cpu(data->be16) & 0xf), 11); - ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &l16, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, + &data->le16, sizeof(data->le16)); if (ret < 0) { dev_err(dev, "failed to read H5 comp value\n"); return ret; } - calib->H5 = sign_extend32(((le16_to_cpu(l16) >> 4) & 0xfff), 11); + calib->H5 = sign_extend32(FIELD_GET(BMP280_COMP_H5_MASK, le16_to_cpu(data->le16)), 11); ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp); if (ret < 0) { @@ -261,8 +401,8 @@ static int bmp280_read_calib(struct bmp280_data *data, static u32 bmp280_compensate_humidity(struct bmp280_data *data, s32 adc_humidity) { - s32 var; struct bmp280_calib *calib = &data->calib.bmp280; + s32 var; var = ((s32)data->t_fine) - (s32)76800; var = ((((adc_humidity << 14) - (calib->H4 << 20) - (calib->H5 * var)) @@ -286,8 +426,8 @@ static u32 bmp280_compensate_humidity(struct bmp280_data *data, static s32 bmp280_compensate_temp(struct bmp280_data *data, s32 adc_temp) { - s32 var1, var2; struct bmp280_calib *calib = &data->calib.bmp280; + s32 var1, var2; var1 = (((adc_temp >> 3) - ((s32)calib->T1 << 1)) * ((s32)calib->T2)) >> 11; @@ -309,8 +449,8 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data, static u32 bmp280_compensate_press(struct bmp280_data *data, s32 adc_press) { - s64 var1, var2, p; struct bmp280_calib *calib = &data->calib.bmp280; + s64 var1, var2, p; var1 = ((s64)data->t_fine) - 128000; var2 = var1 * var1 * (s64)calib->P6; @@ -335,17 +475,17 @@ static u32 bmp280_compensate_press(struct bmp280_data *data, static int bmp280_read_temp(struct bmp280_data *data, int *val) { - int ret; - __be32 tmp = 0; s32 adc_temp, comp_temp; + int ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, &tmp, 3); + ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB, + data->buf, sizeof(data->buf)); if (ret < 0) { dev_err(data->dev, "failed to read temperature\n"); return ret; } - adc_temp = be32_to_cpu(tmp) >> 12; + adc_temp = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf)); if (adc_temp == BMP280_TEMP_SKIPPED) { /* reading was skipped */ dev_err(data->dev, "reading temperature skipped\n"); @@ -368,23 +508,23 @@ static int bmp280_read_temp(struct bmp280_data *data, static int bmp280_read_press(struct bmp280_data *data, int *val, int *val2) { - int ret; - __be32 tmp = 0; - s32 adc_press; u32 comp_press; + s32 adc_press; + int ret; /* Read and compensate temperature so we get a reading of t_fine. */ ret = bmp280_read_temp(data, NULL); if (ret < 0) return ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, &tmp, 3); + ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, + data->buf, sizeof(data->buf)); if (ret < 0) { dev_err(data->dev, "failed to read pressure\n"); return ret; } - adc_press = be32_to_cpu(tmp) >> 12; + adc_press = FIELD_GET(BMP280_MEAS_TRIM_MASK, get_unaligned_be24(data->buf)); if (adc_press == BMP280_PRESS_SKIPPED) { /* reading was skipped */ dev_err(data->dev, "reading pressure skipped\n"); @@ -400,23 +540,23 @@ static int bmp280_read_press(struct bmp280_data *data, static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) { - __be16 tmp; - int ret; - s32 adc_humidity; u32 comp_humidity; + s32 adc_humidity; + int ret; /* Read and compensate temperature so we get a reading of t_fine. */ ret = bmp280_read_temp(data, NULL); if (ret < 0) return ret; - ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, &tmp, 2); + ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, + &data->be16, sizeof(data->be16)); if (ret < 0) { dev_err(data->dev, "failed to read humidity\n"); return ret; } - adc_humidity = be16_to_cpu(tmp); + adc_humidity = be16_to_cpu(data->be16); if (adc_humidity == BMP280_HUMIDITY_SKIPPED) { /* reading was skipped */ dev_err(data->dev, "reading humidity skipped\n"); @@ -433,8 +573,8 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int *val, int *val2, long mask) { - int ret; struct bmp280_data *data = iio_priv(indio_dev); + int ret; pm_runtime_get_sync(data->dev); mutex_lock(&data->lock); @@ -475,6 +615,25 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, break; } break; + case IIO_CHAN_INFO_SAMP_FREQ: + if (!data->chip_info->sampling_freq_avail) { + ret = -EINVAL; + break; + } + + *val = data->chip_info->sampling_freq_avail[data->sampling_freq][0]; + *val2 = data->chip_info->sampling_freq_avail[data->sampling_freq][1]; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + if (!data->chip_info->iir_filter_coeffs_avail) { + ret = -EINVAL; + break; + } + + *val = (1 << data->iir_filter_coeff) - 1; + ret = IIO_VAL_INT; + break; default: ret = -EINVAL; break; @@ -490,15 +649,23 @@ static int bmp280_read_raw(struct iio_dev *indio_dev, static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, int val) { - int i; const int *avail = data->chip_info->oversampling_humid_avail; const int n = data->chip_info->num_oversampling_humid_avail; + int ret, prev; + int i; for (i = 0; i < n; i++) { if (avail[i] == val) { + prev = data->oversampling_humid; data->oversampling_humid = ilog2(val); - return data->chip_info->chip_config(data); + ret = data->chip_info->chip_config(data); + if (ret) { + data->oversampling_humid = prev; + data->chip_info->chip_config(data); + return ret; + } + return 0; } } return -EINVAL; @@ -507,15 +674,23 @@ static int bmp280_write_oversampling_ratio_humid(struct bmp280_data *data, static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data, int val) { - int i; const int *avail = data->chip_info->oversampling_temp_avail; const int n = data->chip_info->num_oversampling_temp_avail; + int ret, prev; + int i; for (i = 0; i < n; i++) { if (avail[i] == val) { + prev = data->oversampling_temp; data->oversampling_temp = ilog2(val); - return data->chip_info->chip_config(data); + ret = data->chip_info->chip_config(data); + if (ret) { + data->oversampling_temp = prev; + data->chip_info->chip_config(data); + return ret; + } + return 0; } } return -EINVAL; @@ -524,15 +699,73 @@ static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data, static int bmp280_write_oversampling_ratio_press(struct bmp280_data *data, int val) { - int i; const int *avail = data->chip_info->oversampling_press_avail; const int n = data->chip_info->num_oversampling_press_avail; + int ret, prev; + int i; for (i = 0; i < n; i++) { if (avail[i] == val) { + prev = data->oversampling_press; data->oversampling_press = ilog2(val); - return data->chip_info->chip_config(data); + ret = data->chip_info->chip_config(data); + if (ret) { + data->oversampling_press = prev; + data->chip_info->chip_config(data); + return ret; + } + return 0; + } + } + return -EINVAL; +} + +static int bmp280_write_sampling_frequency(struct bmp280_data *data, + int val, int val2) +{ + const int (*avail)[2] = data->chip_info->sampling_freq_avail; + const int n = data->chip_info->num_sampling_freq_avail; + int ret, prev; + int i; + + for (i = 0; i < n; i++) { + if (avail[i][0] == val && avail[i][1] == val2) { + prev = data->sampling_freq; + data->sampling_freq = i; + + ret = data->chip_info->chip_config(data); + if (ret) { + data->sampling_freq = prev; + data->chip_info->chip_config(data); + return ret; + } + return 0; + } + } + return -EINVAL; +} + +static int bmp280_write_iir_filter_coeffs(struct bmp280_data *data, int val) +{ + const int *avail = data->chip_info->iir_filter_coeffs_avail; + const int n = data->chip_info->num_iir_filter_coeffs_avail; + int ret, prev; + int i; + + for (i = 0; i < n; i++) { + if (avail[i] - 1 == val) { + prev = data->iir_filter_coeff; + data->iir_filter_coeff = i; + + ret = data->chip_info->chip_config(data); + if (ret) { + data->iir_filter_coeff = prev; + data->chip_info->chip_config(data); + return ret; + + } + return 0; } } return -EINVAL; @@ -542,9 +775,15 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, int val, int val2, long mask) { - int ret = 0; struct bmp280_data *data = iio_priv(indio_dev); + int ret = 0; + /* + * Helper functions to update sensor running configuration. + * If an error happens applying new settings, will try restore + * previous parameters to ensure the sensor is left in a known + * working configuration. + */ switch (mask) { case IIO_CHAN_INFO_OVERSAMPLING_RATIO: pm_runtime_get_sync(data->dev); @@ -567,6 +806,22 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, pm_runtime_mark_last_busy(data->dev); pm_runtime_put_autosuspend(data->dev); break; + case IIO_CHAN_INFO_SAMP_FREQ: + pm_runtime_get_sync(data->dev); + mutex_lock(&data->lock); + ret = bmp280_write_sampling_frequency(data, val, val2); + mutex_unlock(&data->lock); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + break; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + pm_runtime_get_sync(data->dev); + mutex_lock(&data->lock); + ret = bmp280_write_iir_filter_coeffs(data, val); + mutex_unlock(&data->lock); + pm_runtime_mark_last_busy(data->dev); + pm_runtime_put_autosuspend(data->dev); + break; default: return -EINVAL; } @@ -597,6 +852,17 @@ static int bmp280_read_avail(struct iio_dev *indio_dev, } *type = IIO_VAL_INT; return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_SAMP_FREQ: + *vals = (const int *)data->chip_info->sampling_freq_avail; + *type = IIO_VAL_INT_PLUS_MICRO; + /* Values are stored in a 2D matrix */ + *length = data->chip_info->num_sampling_freq_avail; + return IIO_AVAIL_LIST; + case IIO_CHAN_INFO_LOW_PASS_FILTER_3DB_FREQUENCY: + *vals = data->chip_info->iir_filter_coeffs_avail; + *type = IIO_VAL_INT; + *length = data->chip_info->num_iir_filter_coeffs_avail; + return IIO_AVAIL_LIST; default: return -EINVAL; } @@ -610,9 +876,9 @@ static const struct iio_info bmp280_info = { 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); int ret; - u8 osrs = BMP280_OSRS_TEMP_X(data->oversampling_temp + 1) | - BMP280_OSRS_PRESS_X(data->oversampling_press + 1); ret = regmap_write_bits(data->regmap, BMP280_REG_CTRL_MEAS, BMP280_OSRS_TEMP_MASK | @@ -640,21 +906,39 @@ 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 = { + .id_reg = BMP280_REG_ID, + .start_up_time = 2000, + .channels = bmp280_channels, + .num_channels = 2, + .oversampling_temp_avail = bmp280_oversampling_avail, .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail), + /* + * Oversampling config values on BMx280 have one additional setting + * that other generations of the family don't: + * The value 0 means the measurement is bypassed instead of + * oversampling set to x1. + * + * To account for this difference, and preserve the same common + * config logic, this is handled later on chip_config callback + * incrementing one unit the oversampling setting. + */ + .oversampling_temp_default = BMP280_OSRS_TEMP_2X - 1, .oversampling_press_avail = bmp280_oversampling_avail, .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail), + .oversampling_press_default = BMP280_OSRS_PRESS_16X - 1, .chip_config = bmp280_chip_config, .read_temp = bmp280_read_temp, .read_press = bmp280_read_press, + .read_calib = bmp280_read_calib, }; static int bme280_chip_config(struct bmp280_data *data) { + u8 osrs = FIELD_PREP(BMP280_OSRS_HUMIDITY_MASK, data->oversampling_humid + 1); int ret; - u8 osrs = BMP280_OSRS_HUMIDITIY_X(data->oversampling_humid + 1); /* * Oversampling of humidity must be set before oversampling of @@ -670,27 +954,405 @@ static int bme280_chip_config(struct bmp280_data *data) } static const struct bmp280_chip_info bme280_chip_info = { + .id_reg = BMP280_REG_ID, + .start_up_time = 2000, + .channels = bmp280_channels, + .num_channels = 3, + .oversampling_temp_avail = bmp280_oversampling_avail, .num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail), + .oversampling_temp_default = BMP280_OSRS_TEMP_2X - 1, .oversampling_press_avail = bmp280_oversampling_avail, .num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail), + .oversampling_press_default = BMP280_OSRS_PRESS_16X - 1, .oversampling_humid_avail = bmp280_oversampling_avail, .num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail), + .oversampling_humid_default = BMP280_OSRS_HUMIDITY_16X - 1, .chip_config = bme280_chip_config, .read_temp = bmp280_read_temp, .read_press = bmp280_read_press, .read_humid = bmp280_read_humid, + .read_calib = bme280_read_calib, }; -static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) +/* + * Helper function to send a command to BMP3XX sensors. + * + * Sensor processes commands written to the CMD register and signals + * execution result through "cmd_rdy" and "cmd_error" flags available on + * STATUS and ERROR registers. + */ +static int bmp380_cmd(struct bmp280_data *data, u8 cmd) +{ + unsigned int reg; + int ret; + + /* Check if device is ready to process a command */ + ret = regmap_read(data->regmap, BMP380_REG_STATUS, ®); + if (ret) { + dev_err(data->dev, "failed to read error register\n"); + return ret; + } + if (!(reg & BMP380_STATUS_CMD_RDY_MASK)) { + dev_err(data->dev, "device is not ready to accept commands\n"); + return -EBUSY; + } + + /* Send command to process */ + ret = regmap_write(data->regmap, BMP380_REG_CMD, cmd); + if (ret) { + dev_err(data->dev, "failed to send command to device\n"); + return ret; + } + /* Wait for 2ms for command to be processed */ + usleep_range(data->start_up_time, data->start_up_time + 100); + /* Check for command processing error */ + ret = regmap_read(data->regmap, BMP380_REG_ERROR, ®); + if (ret) { + dev_err(data->dev, "error reading ERROR reg\n"); + return ret; + } + if (reg & BMP380_ERR_CMD_MASK) { + dev_err(data->dev, "error processing command 0x%X\n", cmd); + return -EINVAL; + } + + return 0; +} + +/* + * Returns temperature in Celsius dregrees, resolution is 0.01º C. Output value of + * "5123" equals 51.2º C. t_fine carries fine temperature as global value. + * + * Taken from datasheet, Section Appendix 9, "Compensation formula" and repo + * https://github.com/BoschSensortec/BMP3-Sensor-API. + */ +static s32 bmp380_compensate_temp(struct bmp280_data *data, u32 adc_temp) +{ + s64 var1, var2, var3, var4, var5, var6, comp_temp; + struct bmp380_calib *calib = &data->calib.bmp380; + + var1 = ((s64) adc_temp) - (((s64) calib->T1) << 8); + var2 = var1 * ((s64) calib->T2); + var3 = var1 * var1; + var4 = var3 * ((s64) calib->T3); + var5 = (var2 << 18) + var4; + var6 = var5 >> 32; + data->t_fine = (s32) var6; + comp_temp = (var6 * 25) >> 14; + + comp_temp = clamp_val(comp_temp, BMP380_MIN_TEMP, BMP380_MAX_TEMP); + return (s32) comp_temp; +} + +/* + * Returns pressure in Pa as an unsigned 32 bit integer in fractional Pascal. + * Output value of "9528709" represents 9528709/100 = 95287.09 Pa = 952.8709 hPa. + * + * Taken from datasheet, Section 9.3. "Pressure compensation" and repository + * https://github.com/BoschSensortec/BMP3-Sensor-API. + */ +static u32 bmp380_compensate_press(struct bmp280_data *data, u32 adc_press) +{ + s64 var1, var2, var3, var4, var5, var6, offset, sensitivity; + struct bmp380_calib *calib = &data->calib.bmp380; + u32 comp_press; + + var1 = (s64)data->t_fine * (s64)data->t_fine; + var2 = var1 >> 6; + var3 = (var2 * ((s64) data->t_fine)) >> 8; + var4 = ((s64)calib->P8 * var3) >> 5; + var5 = ((s64)calib->P7 * var1) << 4; + var6 = ((s64)calib->P6 * (s64)data->t_fine) << 22; + offset = ((s64)calib->P5 << 47) + var4 + var5 + var6; + var2 = ((s64)calib->P4 * var3) >> 5; + var4 = ((s64)calib->P3 * var1) << 2; + var5 = ((s64)calib->P2 - ((s64)1 << 14)) * + ((s64)data->t_fine << 21); + sensitivity = (((s64) calib->P1 - ((s64) 1 << 14)) << 46) + + var2 + var4 + var5; + var1 = (sensitivity >> 24) * (s64)adc_press; + var2 = (s64)calib->P10 * (s64)data->t_fine; + var3 = var2 + ((s64)calib->P9 << 16); + var4 = (var3 * (s64)adc_press) >> 13; + + /* + * Dividing by 10 followed by multiplying by 10 to avoid + * possible overflow caused by (uncomp_data->pressure * partial_data4). + */ + var5 = ((s64)adc_press * div_s64(var4, 10)) >> 9; + var5 *= 10; + var6 = (s64)adc_press * (s64)adc_press; + var2 = ((s64)calib->P11 * var6) >> 16; + var3 = (var2 * (s64)adc_press) >> 7; + var4 = (offset >> 2) + var1 + var5 + var3; + comp_press = ((u64)var4 * 25) >> 40; + + comp_press = clamp_val(comp_press, BMP380_MIN_PRES, BMP380_MAX_PRES); + return comp_press; +} + +static int bmp380_read_temp(struct bmp280_data *data, int *val) +{ + s32 comp_temp; + u32 adc_temp; + int ret; + + ret = regmap_bulk_read(data->regmap, BMP380_REG_TEMP_XLSB, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read temperature\n"); + return ret; + } + + adc_temp = get_unaligned_le24(data->buf); + if (adc_temp == BMP380_TEMP_SKIPPED) { + dev_err(data->dev, "reading temperature skipped\n"); + return -EIO; + } + comp_temp = bmp380_compensate_temp(data, adc_temp); + + /* + * Val might be NULL if we're called by the read_press routine, + * who only cares about the carry over t_fine value. + */ + if (val) { + /* IIO reports temperatures in milli Celsius */ + *val = comp_temp * 10; + return IIO_VAL_INT; + } + + return 0; +} + +static int bmp380_read_press(struct bmp280_data *data, int *val, int *val2) +{ + s32 comp_press; + u32 adc_press; + int ret; + + /* Read and compensate for temperature so we get a reading of t_fine */ + ret = bmp380_read_temp(data, NULL); + if (ret) + return ret; + + ret = regmap_bulk_read(data->regmap, BMP380_REG_PRESS_XLSB, + data->buf, sizeof(data->buf)); + if (ret) { + dev_err(data->dev, "failed to read pressure\n"); + return ret; + } + + adc_press = get_unaligned_le24(data->buf); + if (adc_press == BMP380_PRESS_SKIPPED) { + dev_err(data->dev, "reading pressure skipped\n"); + return -EIO; + } + comp_press = bmp380_compensate_press(data, adc_press); + + *val = comp_press; + /* Compensated pressure is in cPa (centipascals) */ + *val2 = 100000; + + return IIO_VAL_FRACTIONAL; +} + +static int bmp380_read_calib(struct bmp280_data *data) +{ + struct bmp380_calib *calib = &data->calib.bmp380; + int ret; + + /* Read temperature and pressure calibration data */ + ret = regmap_bulk_read(data->regmap, BMP380_REG_CALIB_TEMP_START, + data->bmp380_cal_buf, sizeof(data->bmp380_cal_buf)); + if (ret) { + dev_err(data->dev, + "failed to read temperature calibration parameters\n"); + return ret; + } + + /* Toss the temperature calibration data into the entropy pool */ + add_device_randomness(data->bmp380_cal_buf, sizeof(data->bmp380_cal_buf)); + + /* Parse calibration values */ + calib->T1 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_T1]); + calib->T2 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_T2]); + calib->T3 = data->bmp380_cal_buf[BMP380_T3]; + calib->P1 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P1]); + calib->P2 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P2]); + calib->P3 = data->bmp380_cal_buf[BMP380_P3]; + calib->P4 = data->bmp380_cal_buf[BMP380_P4]; + calib->P5 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P5]); + calib->P6 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P6]); + calib->P7 = data->bmp380_cal_buf[BMP380_P7]; + calib->P8 = data->bmp380_cal_buf[BMP380_P8]; + calib->P9 = get_unaligned_le16(&data->bmp380_cal_buf[BMP380_P9]); + calib->P10 = data->bmp380_cal_buf[BMP380_P10]; + calib->P11 = data->bmp380_cal_buf[BMP380_P11]; + + return 0; +} + +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}, +}; + +static int bmp380_chip_config(struct bmp280_data *data) { + bool change = false, aux; + unsigned int tmp; + u8 osrs; int ret; + + /* Configure power control register */ + ret = regmap_update_bits(data->regmap, BMP380_REG_POWER_CONTROL, + BMP380_CTRL_SENSORS_MASK, + BMP380_CTRL_SENSORS_PRESS_EN | + BMP380_CTRL_SENSORS_TEMP_EN); + if (ret) { + dev_err(data->dev, + "failed to write operation control register\n"); + return ret; + } + + /* Configure oversampling */ + osrs = FIELD_PREP(BMP380_OSRS_TEMP_MASK, data->oversampling_temp) | + FIELD_PREP(BMP380_OSRS_PRESS_MASK, data->oversampling_press); + + ret = regmap_update_bits_check(data->regmap, BMP380_REG_OSR, + BMP380_OSRS_TEMP_MASK | + BMP380_OSRS_PRESS_MASK, + osrs, &aux); + if (ret) { + dev_err(data->dev, "failed to write oversampling register\n"); + return ret; + } + change = change || aux; + + /* Configure output data rate */ + ret = regmap_update_bits_check(data->regmap, BMP380_REG_ODR, + BMP380_ODRS_MASK, data->sampling_freq, &aux); + if (ret) { + dev_err(data->dev, "failed to write ODR selection register\n"); + return ret; + } + change = change || aux; + + /* Set filter data */ + ret = regmap_update_bits_check(data->regmap, BMP380_REG_CONFIG, BMP380_FILTER_MASK, + FIELD_PREP(BMP380_FILTER_MASK, data->iir_filter_coeff), + &aux); + if (ret) { + dev_err(data->dev, "failed to write config register\n"); + return ret; + } + change = change || aux; + + if (change) { + /* + * The configurations errors are detected on the fly during a measurement + * cycle. If the sampling frequency is too low, it's faster to reset + * the measurement loop than wait until the next measurement is due. + * + * Resets sensor measurement loop toggling between sleep and normal + * operating modes. + */ + ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, + BMP380_MODE_MASK, + FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_SLEEP)); + if (ret) { + dev_err(data->dev, "failed to set sleep mode\n"); + return ret; + } + usleep_range(2000, 2500); + ret = regmap_write_bits(data->regmap, BMP380_REG_POWER_CONTROL, + BMP380_MODE_MASK, + FIELD_PREP(BMP380_MODE_MASK, BMP380_MODE_NORMAL)); + if (ret) { + dev_err(data->dev, "failed to set normal mode\n"); + return ret; + } + /* + * Waits for measurement before checking configuration error flag. + * Selected longest measure time indicated in section 3.9.1 + * in the datasheet. + */ + msleep(80); + + /* Check config error flag */ + ret = regmap_read(data->regmap, BMP380_REG_ERROR, &tmp); + if (ret) { + dev_err(data->dev, + "failed to read error register\n"); + return ret; + } + if (tmp & BMP380_ERR_CONF_MASK) { + dev_warn(data->dev, + "sensor flagged configuration as incompatible\n"); + return -EINVAL; + } + } + + return 0; +} + +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 = { + .id_reg = BMP380_REG_ID, + .start_up_time = 2000, + .channels = bmp380_channels, + .num_channels = 2, + + .oversampling_temp_avail = bmp380_oversampling_avail, + .num_oversampling_temp_avail = ARRAY_SIZE(bmp380_oversampling_avail), + .oversampling_temp_default = ilog2(1), + + .oversampling_press_avail = bmp380_oversampling_avail, + .num_oversampling_press_avail = ARRAY_SIZE(bmp380_oversampling_avail), + .oversampling_press_default = ilog2(4), + + .sampling_freq_avail = bmp380_odr_table, + .num_sampling_freq_avail = ARRAY_SIZE(bmp380_odr_table) * 2, + .sampling_freq_default = BMP380_ODR_50HZ, + + .iir_filter_coeffs_avail = bmp380_iir_filter_coeffs_avail, + .num_iir_filter_coeffs_avail = ARRAY_SIZE(bmp380_iir_filter_coeffs_avail), + .iir_filter_coeff_default = 2, + + .chip_config = bmp380_chip_config, + .read_temp = bmp380_read_temp, + .read_press = bmp380_read_press, + .read_calib = bmp380_read_calib, +}; + +static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) +{ const int conversion_time_max[] = { 4500, 7500, 13500, 25500 }; unsigned int delay_us; unsigned int ctrl; + int ret; if (data->use_eoc) reinit_completion(&data->done); @@ -710,7 +1372,7 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) if (!ret) dev_err(data->dev, "timeout waiting for completion\n"); } else { - if (ctrl_meas == BMP180_MEAS_TEMP) + if (FIELD_GET(BMP180_MEAS_CTRL_MASK, ctrl_meas) == BMP180_MEAS_TEMP) delay_us = 4500; else delay_us = @@ -732,55 +1394,57 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) { - __be16 tmp; int ret; - ret = bmp180_measure(data, BMP180_MEAS_TEMP); + ret = bmp180_measure(data, + FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_TEMP) | + BMP180_MEAS_SCO); if (ret) return ret; - ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, &tmp, 2); + ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, + &data->be16, sizeof(data->be16)); if (ret) return ret; - *val = be16_to_cpu(tmp); + *val = be16_to_cpu(data->be16); return 0; } -static int bmp180_read_calib(struct bmp280_data *data, - struct bmp180_calib *calib) +static int bmp180_read_calib(struct bmp280_data *data) { + struct bmp180_calib *calib = &data->calib.bmp180; int ret; int i; - __be16 buf[BMP180_REG_CALIB_COUNT / 2]; - ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START, buf, - sizeof(buf)); + ret = regmap_bulk_read(data->regmap, BMP180_REG_CALIB_START, + data->bmp180_cal_buf, sizeof(data->bmp180_cal_buf)); if (ret < 0) return ret; /* None of the words has the value 0 or 0xFFFF */ - for (i = 0; i < ARRAY_SIZE(buf); i++) { - if (buf[i] == cpu_to_be16(0) || buf[i] == cpu_to_be16(0xffff)) + for (i = 0; i < ARRAY_SIZE(data->bmp180_cal_buf); i++) { + if (data->bmp180_cal_buf[i] == cpu_to_be16(0) || + data->bmp180_cal_buf[i] == cpu_to_be16(0xffff)) return -EIO; } /* Toss the calibration data into the entropy pool */ - add_device_randomness(buf, sizeof(buf)); - - calib->AC1 = be16_to_cpu(buf[AC1]); - calib->AC2 = be16_to_cpu(buf[AC2]); - calib->AC3 = be16_to_cpu(buf[AC3]); - calib->AC4 = be16_to_cpu(buf[AC4]); - calib->AC5 = be16_to_cpu(buf[AC5]); - calib->AC6 = be16_to_cpu(buf[AC6]); - calib->B1 = be16_to_cpu(buf[B1]); - calib->B2 = be16_to_cpu(buf[B2]); - calib->MB = be16_to_cpu(buf[MB]); - calib->MC = be16_to_cpu(buf[MC]); - calib->MD = be16_to_cpu(buf[MD]); + add_device_randomness(data->bmp180_cal_buf, sizeof(data->bmp180_cal_buf)); + + calib->AC1 = be16_to_cpu(data->bmp180_cal_buf[AC1]); + calib->AC2 = be16_to_cpu(data->bmp180_cal_buf[AC2]); + calib->AC3 = be16_to_cpu(data->bmp180_cal_buf[AC3]); + calib->AC4 = be16_to_cpu(data->bmp180_cal_buf[AC4]); + calib->AC5 = be16_to_cpu(data->bmp180_cal_buf[AC5]); + calib->AC6 = be16_to_cpu(data->bmp180_cal_buf[AC6]); + calib->B1 = be16_to_cpu(data->bmp180_cal_buf[B1]); + calib->B2 = be16_to_cpu(data->bmp180_cal_buf[B2]); + calib->MB = be16_to_cpu(data->bmp180_cal_buf[MB]); + calib->MC = be16_to_cpu(data->bmp180_cal_buf[MC]); + calib->MD = be16_to_cpu(data->bmp180_cal_buf[MD]); return 0; } @@ -793,8 +1457,8 @@ static int bmp180_read_calib(struct bmp280_data *data, */ static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) { - s32 x1, x2; struct bmp180_calib *calib = &data->calib.bmp180; + s32 x1, x2; x1 = ((adc_temp - calib->AC6) * calib->AC5) >> 15; x2 = (calib->MC << 11) / (x1 + calib->MD); @@ -805,8 +1469,8 @@ static s32 bmp180_compensate_temp(struct bmp280_data *data, s32 adc_temp) static int bmp180_read_temp(struct bmp280_data *data, int *val) { - int ret; s32 adc_temp, comp_temp; + int ret; ret = bmp180_read_adc_temp(data, &adc_temp); if (ret) @@ -828,19 +1492,22 @@ static int bmp180_read_temp(struct bmp280_data *data, int *val) static int bmp180_read_adc_press(struct bmp280_data *data, int *val) { - int ret; - __be32 tmp = 0; u8 oss = data->oversampling_press; + int ret; - ret = bmp180_measure(data, BMP180_MEAS_PRESS_X(oss)); + ret = bmp180_measure(data, + FIELD_PREP(BMP180_MEAS_CTRL_MASK, BMP180_MEAS_PRESS) | + FIELD_PREP(BMP180_OSRS_PRESS_MASK, oss) | + BMP180_MEAS_SCO); if (ret) return ret; - ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, &tmp, 3); + ret = regmap_bulk_read(data->regmap, BMP180_REG_OUT_MSB, + data->buf, sizeof(data->buf)); if (ret) return ret; - *val = (be32_to_cpu(tmp) >> 8) >> (8 - oss); + *val = get_unaligned_be24(data->buf) >> (8 - oss); return 0; } @@ -852,11 +1519,11 @@ static int bmp180_read_adc_press(struct bmp280_data *data, int *val) */ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) { + struct bmp180_calib *calib = &data->calib.bmp180; + s32 oss = data->oversampling_press; s32 x1, x2, x3, p; s32 b3, b6; u32 b4, b7; - s32 oss = data->oversampling_press; - struct bmp180_calib *calib = &data->calib.bmp180; b6 = data->t_fine - 4000; x1 = (calib->B2 * (b6 * b6 >> 12)) >> 11; @@ -883,9 +1550,9 @@ static u32 bmp180_compensate_press(struct bmp280_data *data, s32 adc_press) static int bmp180_read_press(struct bmp280_data *data, int *val, int *val2) { - int ret; - s32 adc_press; u32 comp_press; + s32 adc_press; + int ret; /* Read and compensate temperature so we get a reading of t_fine. */ ret = bmp180_read_temp(data, NULL); @@ -913,17 +1580,25 @@ 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 = { + .id_reg = BMP280_REG_ID, + .start_up_time = 2000, + .channels = bmp280_channels, + .num_channels = 2, + .oversampling_temp_avail = bmp180_oversampling_temp_avail, .num_oversampling_temp_avail = ARRAY_SIZE(bmp180_oversampling_temp_avail), + .oversampling_temp_default = 0, .oversampling_press_avail = bmp180_oversampling_press_avail, .num_oversampling_press_avail = ARRAY_SIZE(bmp180_oversampling_press_avail), + .oversampling_press_default = BMP180_MEAS_PRESS_8X, .chip_config = bmp180_chip_config, .read_temp = bmp180_read_temp, .read_press = bmp180_read_press, + .read_calib = bmp180_read_calib, }; static irqreturn_t bmp085_eoc_irq(int irq, void *d) @@ -990,11 +1665,12 @@ int bmp280_common_probe(struct device *dev, const char *name, int irq) { - int ret; + const struct bmp280_chip_info *chip_info; struct iio_dev *indio_dev; struct bmp280_data *data; - unsigned int chip_id; struct gpio_desc *gpiod; + unsigned int chip_id; + int ret; indio_dev = devm_iio_device_alloc(dev, sizeof(*data)); if (!indio_dev) @@ -1005,36 +1681,36 @@ int bmp280_common_probe(struct device *dev, data->dev = dev; indio_dev->name = name; - indio_dev->channels = bmp280_channels; indio_dev->info = &bmp280_info; indio_dev->modes = INDIO_DIRECT_MODE; switch (chip) { case BMP180_CHIP_ID: - indio_dev->num_channels = 2; - data->chip_info = &bmp180_chip_info; - data->oversampling_press = ilog2(8); - data->oversampling_temp = ilog2(1); - data->start_up_time = 10000; + chip_info = &bmp180_chip_info; break; case BMP280_CHIP_ID: - indio_dev->num_channels = 2; - data->chip_info = &bmp280_chip_info; - data->oversampling_press = ilog2(16); - data->oversampling_temp = ilog2(2); - data->start_up_time = 2000; + chip_info = &bmp280_chip_info; break; case BME280_CHIP_ID: - indio_dev->num_channels = 3; - data->chip_info = &bme280_chip_info; - data->oversampling_press = ilog2(16); - data->oversampling_humid = ilog2(16); - data->oversampling_temp = ilog2(2); - data->start_up_time = 2000; + 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 */ + indio_dev->channels = chip_info->channels; + indio_dev->num_channels = chip_info->num_channels; + data->oversampling_press = chip_info->oversampling_press_default; + data->oversampling_humid = chip_info->oversampling_humid_default; + data->oversampling_temp = chip_info->oversampling_temp_default; + data->iir_filter_coeff = chip_info->iir_filter_coeff_default; + data->sampling_freq = chip_info->sampling_freq_default; + data->start_up_time = chip_info->start_up_time; /* Bring up regulators */ regulator_bulk_set_supply_names(data->supplies, @@ -1071,7 +1747,8 @@ int bmp280_common_probe(struct device *dev, } data->regmap = regmap; - ret = regmap_read(regmap, BMP280_REG_ID, &chip_id); + + ret = regmap_read(regmap, data->chip_info->id_reg, &chip_id); if (ret < 0) return ret; if (chip_id != chip) { @@ -1080,6 +1757,13 @@ 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; + } + ret = data->chip_info->chip_config(data); if (ret < 0) return ret; @@ -1091,21 +1775,11 @@ int bmp280_common_probe(struct device *dev, * non-volatile memory during production". Let's read them out at probe * time once. They will not change. */ - if (chip_id == BMP180_CHIP_ID) { - ret = bmp180_read_calib(data, &data->calib.bmp180); - if (ret < 0) { - dev_err(data->dev, - "failed to read calibration coefficients\n"); - return ret; - } - } else if (chip_id == BMP280_CHIP_ID || chip_id == BME280_CHIP_ID) { - ret = bmp280_read_calib(data, &data->calib.bmp280, chip_id); - if (ret < 0) { - dev_err(data->dev, - "failed to read calibration coefficients\n"); - return ret; - } - } + + 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 diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index bf4a7a617537..0c27211f3ea0 100644 --- a/drivers/iio/pressure/bmp280-i2c.c +++ b/drivers/iio/pressure/bmp280-i2c.c @@ -19,6 +19,9 @@ static int bmp280_i2c_probe(struct i2c_client *client, case BME280_CHIP_ID: regmap_config = &bmp280_regmap_config; break; + case BMP380_CHIP_ID: + regmap_config = &bmp380_regmap_config; + break; default: return -EINVAL; } @@ -37,19 +40,21 @@ static int bmp280_i2c_probe(struct i2c_client *client, } static const struct of_device_id bmp280_of_i2c_match[] = { - { .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID }, - { .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID }, - { .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID }, { .compatible = "bosch,bmp085", .data = (void *)BMP180_CHIP_ID }, + { .compatible = "bosch,bmp180", .data = (void *)BMP180_CHIP_ID }, + { .compatible = "bosch,bmp280", .data = (void *)BMP280_CHIP_ID }, + { .compatible = "bosch,bme280", .data = (void *)BME280_CHIP_ID }, + { .compatible = "bosch,bmp380", .data = (void *)BMP380_CHIP_ID }, { }, }; MODULE_DEVICE_TABLE(of, bmp280_of_i2c_match); static const struct i2c_device_id bmp280_i2c_id[] = { - {"bmp280", BMP280_CHIP_ID }, - {"bmp180", BMP180_CHIP_ID }, {"bmp085", BMP180_CHIP_ID }, + {"bmp180", BMP180_CHIP_ID }, + {"bmp280", BMP280_CHIP_ID }, {"bme280", BME280_CHIP_ID }, + {"bmp380", BMP380_CHIP_ID }, { }, }; MODULE_DEVICE_TABLE(i2c, bmp280_i2c_id); diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c index 969698518984..c98c67970265 100644 --- a/drivers/iio/pressure/bmp280-regmap.c +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -72,6 +72,49 @@ static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg) } } +static bool bmp380_is_writeable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP380_REG_CMD: + case BMP380_REG_CONFIG: + case BMP380_REG_FIFO_CONFIG_1: + case BMP380_REG_FIFO_CONFIG_2: + case BMP380_REG_FIFO_WATERMARK_LSB: + case BMP380_REG_FIFO_WATERMARK_MSB: + case BMP380_REG_POWER_CONTROL: + case BMP380_REG_INT_CONTROL: + case BMP380_REG_IF_CONFIG: + case BMP380_REG_ODR: + case BMP380_REG_OSR: + return true; + default: + return false; + } +} + +static bool bmp380_is_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case BMP380_REG_TEMP_XLSB: + case BMP380_REG_TEMP_LSB: + case BMP380_REG_TEMP_MSB: + case BMP380_REG_PRESS_XLSB: + case BMP380_REG_PRESS_LSB: + case BMP380_REG_PRESS_MSB: + case BMP380_REG_SENSOR_TIME_XLSB: + case BMP380_REG_SENSOR_TIME_LSB: + case BMP380_REG_SENSOR_TIME_MSB: + case BMP380_REG_INT_STATUS: + case BMP380_REG_FIFO_DATA: + case BMP380_REG_STATUS: + case BMP380_REG_ERROR: + case BMP380_REG_EVENT: + return true; + default: + return false; + } +} + const struct regmap_config bmp280_regmap_config = { .reg_bits = 8, .val_bits = 8, @@ -83,3 +126,15 @@ const struct regmap_config bmp280_regmap_config = { .volatile_reg = bmp280_is_volatile_reg, }; EXPORT_SYMBOL_NS(bmp280_regmap_config, IIO_BMP280); + +const struct regmap_config bmp380_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + + .max_register = BMP380_REG_CMD, + .cache_type = REGCACHE_RBTREE, + + .writeable_reg = bmp380_is_writeable_reg, + .volatile_reg = bmp380_is_volatile_reg, +}; +EXPORT_SYMBOL_NS(bmp380_regmap_config, IIO_BMP280); diff --git a/drivers/iio/pressure/bmp280-spi.c b/drivers/iio/pressure/bmp280-spi.c index 4cfaf3e869b8..011c68e07ebf 100644 --- a/drivers/iio/pressure/bmp280-spi.c +++ b/drivers/iio/pressure/bmp280-spi.c @@ -66,6 +66,9 @@ static int bmp280_spi_probe(struct spi_device *spi) case BME280_CHIP_ID: regmap_config = &bmp280_regmap_config; break; + case BMP380_CHIP_ID: + regmap_config = &bmp380_regmap_config; + break; default: return -EINVAL; } @@ -92,6 +95,7 @@ static const struct of_device_id bmp280_of_spi_match[] = { { .compatible = "bosch,bmp181", }, { .compatible = "bosch,bmp280", }, { .compatible = "bosch,bme280", }, + { .compatible = "bosch,bmp380", }, { }, }; MODULE_DEVICE_TABLE(of, bmp280_of_spi_match); @@ -101,6 +105,7 @@ static const struct spi_device_id bmp280_spi_id[] = { { "bmp181", BMP180_CHIP_ID }, { "bmp280", BMP280_CHIP_ID }, { "bme280", BME280_CHIP_ID }, + { "bmp380", BMP380_CHIP_ID }, { } }; MODULE_DEVICE_TABLE(spi, bmp280_spi_id); diff --git a/drivers/iio/pressure/bmp280.h b/drivers/iio/pressure/bmp280.h index 57ba0e85db91..c791325c7416 100644 --- a/drivers/iio/pressure/bmp280.h +++ b/drivers/iio/pressure/bmp280.h @@ -3,6 +3,87 @@ #include <linux/device.h> #include <linux/regmap.h> +/* BMP380 specific registers */ +#define BMP380_REG_CMD 0x7E +#define BMP380_REG_CONFIG 0x1F +#define BMP380_REG_ODR 0x1D +#define BMP380_REG_OSR 0x1C +#define BMP380_REG_POWER_CONTROL 0x1B +#define BMP380_REG_IF_CONFIG 0x1A +#define BMP380_REG_INT_CONTROL 0x19 +#define BMP380_REG_INT_STATUS 0x11 +#define BMP380_REG_EVENT 0x10 +#define BMP380_REG_STATUS 0x03 +#define BMP380_REG_ERROR 0x02 +#define BMP380_REG_ID 0x00 + +#define BMP380_REG_FIFO_CONFIG_1 0x18 +#define BMP380_REG_FIFO_CONFIG_2 0x17 +#define BMP380_REG_FIFO_WATERMARK_MSB 0x16 +#define BMP380_REG_FIFO_WATERMARK_LSB 0x15 +#define BMP380_REG_FIFO_DATA 0x14 +#define BMP380_REG_FIFO_LENGTH_MSB 0x13 +#define BMP380_REG_FIFO_LENGTH_LSB 0x12 + +#define BMP380_REG_SENSOR_TIME_MSB 0x0E +#define BMP380_REG_SENSOR_TIME_LSB 0x0D +#define BMP380_REG_SENSOR_TIME_XLSB 0x0C + +#define BMP380_REG_TEMP_MSB 0x09 +#define BMP380_REG_TEMP_LSB 0x08 +#define BMP380_REG_TEMP_XLSB 0x07 + +#define BMP380_REG_PRESS_MSB 0x06 +#define BMP380_REG_PRESS_LSB 0x05 +#define BMP380_REG_PRESS_XLSB 0x04 + +#define BMP380_REG_CALIB_TEMP_START 0x31 +#define BMP380_CALIB_REG_COUNT 21 + +#define BMP380_FILTER_MASK GENMASK(3, 1) +#define BMP380_FILTER_OFF 0 +#define BMP380_FILTER_1X 1 +#define BMP380_FILTER_3X 2 +#define BMP380_FILTER_7X 3 +#define BMP380_FILTER_15X 4 +#define BMP380_FILTER_31X 5 +#define BMP380_FILTER_63X 6 +#define BMP380_FILTER_127X 7 + +#define BMP380_OSRS_TEMP_MASK GENMASK(5, 3) +#define BMP380_OSRS_PRESS_MASK GENMASK(2, 0) + +#define BMP380_ODRS_MASK GENMASK(4, 0) + +#define BMP380_CTRL_SENSORS_MASK GENMASK(1, 0) +#define BMP380_CTRL_SENSORS_PRESS_EN BIT(0) +#define BMP380_CTRL_SENSORS_TEMP_EN BIT(1) +#define BMP380_MODE_MASK GENMASK(5, 4) +#define BMP380_MODE_SLEEP 0 +#define BMP380_MODE_FORCED 1 +#define BMP380_MODE_NORMAL 3 + +#define BMP380_MIN_TEMP -4000 +#define BMP380_MAX_TEMP 8500 +#define BMP380_MIN_PRES 3000000 +#define BMP380_MAX_PRES 12500000 + +#define BMP380_CMD_NOOP 0x00 +#define BMP380_CMD_EXTMODE_EN_MID 0x34 +#define BMP380_CMD_FIFO_FLUSH 0xB0 +#define BMP380_CMD_SOFT_RESET 0xB6 + +#define BMP380_STATUS_CMD_RDY_MASK BIT(4) +#define BMP380_STATUS_DRDY_PRESS_MASK BIT(5) +#define BMP380_STATUS_DRDY_TEMP_MASK BIT(6) + +#define BMP380_ERR_FATAL_MASK BIT(0) +#define BMP380_ERR_CMD_MASK BIT(1) +#define BMP380_ERR_CONF_MASK BIT(2) + +#define BMP380_TEMP_SKIPPED 0x800000 +#define BMP380_PRESS_SKIPPED 0x800000 + /* BMP280 specific registers */ #define BMP280_REG_HUMIDITY_LSB 0xFE #define BMP280_REG_HUMIDITY_MSB 0xFD @@ -13,6 +94,9 @@ #define BMP280_REG_PRESS_LSB 0xF8 #define BMP280_REG_PRESS_MSB 0xF7 +/* Helper mask to truncate excess 4 bits on pressure and temp readings */ +#define BMP280_MEAS_TRIM_MASK GENMASK(24, 4) + #define BMP280_REG_CONFIG 0xF5 #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_STATUS 0xF3 @@ -32,44 +116,46 @@ #define BMP280_REG_COMP_PRESS_START 0x8E #define BMP280_COMP_PRESS_REG_COUNT 18 -#define BMP280_FILTER_MASK (BIT(4) | BIT(3) | BIT(2)) +#define BMP280_COMP_H5_MASK GENMASK(15, 4) + +#define BMP280_CONTIGUOUS_CALIB_REGS (BMP280_COMP_TEMP_REG_COUNT + \ + BMP280_COMP_PRESS_REG_COUNT) + +#define BMP280_FILTER_MASK GENMASK(4, 2) #define BMP280_FILTER_OFF 0 -#define BMP280_FILTER_2X BIT(2) -#define BMP280_FILTER_4X BIT(3) -#define BMP280_FILTER_8X (BIT(3) | BIT(2)) -#define BMP280_FILTER_16X BIT(4) +#define BMP280_FILTER_2X 1 +#define BMP280_FILTER_4X 2 +#define BMP280_FILTER_8X 3 +#define BMP280_FILTER_16X 4 -#define BMP280_OSRS_HUMIDITY_MASK (BIT(2) | BIT(1) | BIT(0)) -#define BMP280_OSRS_HUMIDITIY_X(osrs_h) ((osrs_h) << 0) +#define BMP280_OSRS_HUMIDITY_MASK GENMASK(2, 0) #define BMP280_OSRS_HUMIDITY_SKIP 0 -#define BMP280_OSRS_HUMIDITY_1X BMP280_OSRS_HUMIDITIY_X(1) -#define BMP280_OSRS_HUMIDITY_2X BMP280_OSRS_HUMIDITIY_X(2) -#define BMP280_OSRS_HUMIDITY_4X BMP280_OSRS_HUMIDITIY_X(3) -#define BMP280_OSRS_HUMIDITY_8X BMP280_OSRS_HUMIDITIY_X(4) -#define BMP280_OSRS_HUMIDITY_16X BMP280_OSRS_HUMIDITIY_X(5) +#define BMP280_OSRS_HUMIDITY_1X 1 +#define BMP280_OSRS_HUMIDITY_2X 2 +#define BMP280_OSRS_HUMIDITY_4X 3 +#define BMP280_OSRS_HUMIDITY_8X 4 +#define BMP280_OSRS_HUMIDITY_16X 5 -#define BMP280_OSRS_TEMP_MASK (BIT(7) | BIT(6) | BIT(5)) +#define BMP280_OSRS_TEMP_MASK GENMASK(7, 5) #define BMP280_OSRS_TEMP_SKIP 0 -#define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5) -#define BMP280_OSRS_TEMP_1X BMP280_OSRS_TEMP_X(1) -#define BMP280_OSRS_TEMP_2X BMP280_OSRS_TEMP_X(2) -#define BMP280_OSRS_TEMP_4X BMP280_OSRS_TEMP_X(3) -#define BMP280_OSRS_TEMP_8X BMP280_OSRS_TEMP_X(4) -#define BMP280_OSRS_TEMP_16X BMP280_OSRS_TEMP_X(5) - -#define BMP280_OSRS_PRESS_MASK (BIT(4) | BIT(3) | BIT(2)) +#define BMP280_OSRS_TEMP_1X 1 +#define BMP280_OSRS_TEMP_2X 2 +#define BMP280_OSRS_TEMP_4X 3 +#define BMP280_OSRS_TEMP_8X 4 +#define BMP280_OSRS_TEMP_16X 5 + +#define BMP280_OSRS_PRESS_MASK GENMASK(4, 2) #define BMP280_OSRS_PRESS_SKIP 0 -#define BMP280_OSRS_PRESS_X(osrs_p) ((osrs_p) << 2) -#define BMP280_OSRS_PRESS_1X BMP280_OSRS_PRESS_X(1) -#define BMP280_OSRS_PRESS_2X BMP280_OSRS_PRESS_X(2) -#define BMP280_OSRS_PRESS_4X BMP280_OSRS_PRESS_X(3) -#define BMP280_OSRS_PRESS_8X BMP280_OSRS_PRESS_X(4) -#define BMP280_OSRS_PRESS_16X BMP280_OSRS_PRESS_X(5) - -#define BMP280_MODE_MASK (BIT(1) | BIT(0)) +#define BMP280_OSRS_PRESS_1X 1 +#define BMP280_OSRS_PRESS_2X 2 +#define BMP280_OSRS_PRESS_4X 3 +#define BMP280_OSRS_PRESS_8X 4 +#define BMP280_OSRS_PRESS_16X 5 + +#define BMP280_MODE_MASK GENMASK(1, 0) #define BMP280_MODE_SLEEP 0 -#define BMP280_MODE_FORCED BIT(0) -#define BMP280_MODE_NORMAL (BIT(1) | BIT(0)) +#define BMP280_MODE_FORCED 1 +#define BMP280_MODE_NORMAL 3 /* BMP180 specific registers */ #define BMP180_REG_OUT_XLSB 0xF8 @@ -79,19 +165,22 @@ #define BMP180_REG_CALIB_START 0xAA #define BMP180_REG_CALIB_COUNT 22 +#define BMP180_MEAS_CTRL_MASK GENMASK(4, 0) +#define BMP180_MEAS_TEMP 0x0E +#define BMP180_MEAS_PRESS 0x14 #define BMP180_MEAS_SCO BIT(5) -#define BMP180_MEAS_TEMP (0x0E | BMP180_MEAS_SCO) -#define BMP180_MEAS_PRESS_X(oss) ((oss) << 6 | 0x14 | BMP180_MEAS_SCO) -#define BMP180_MEAS_PRESS_1X BMP180_MEAS_PRESS_X(0) -#define BMP180_MEAS_PRESS_2X BMP180_MEAS_PRESS_X(1) -#define BMP180_MEAS_PRESS_4X BMP180_MEAS_PRESS_X(2) -#define BMP180_MEAS_PRESS_8X BMP180_MEAS_PRESS_X(3) +#define BMP180_OSRS_PRESS_MASK GENMASK(7, 6) +#define BMP180_MEAS_PRESS_1X 0 +#define BMP180_MEAS_PRESS_2X 1 +#define BMP180_MEAS_PRESS_4X 2 +#define BMP180_MEAS_PRESS_8X 3 /* BMP180 and BMP280 common registers */ #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_RESET 0xE0 #define BMP280_REG_ID 0xD0 +#define BMP380_CHIP_ID 0x50 #define BMP180_CHIP_ID 0x55 #define BMP280_CHIP_ID 0x58 #define BME280_CHIP_ID 0x60 @@ -105,6 +194,7 @@ /* Regmap configurations */ extern const struct regmap_config bmp180_regmap_config; extern const struct regmap_config bmp280_regmap_config; +extern const struct regmap_config bmp380_regmap_config; /* Probe called from different transports */ int bmp280_common_probe(struct device *dev, diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c index 5f6bb3603a8b..f0b0d198c6d4 100644 --- a/drivers/iio/pressure/dlhl60d.c +++ b/drivers/iio/pressure/dlhl60d.c @@ -129,9 +129,8 @@ static int dlh_read_direct(struct dlh_state *st, if (ret) return ret; - *pressure = get_unaligned_be32(&st->rx_buf[1]) >> 8; - *temperature = get_unaligned_be32(&st->rx_buf[3]) & - GENMASK(DLH_NUM_TEMP_BITS - 1, 0); + *pressure = get_unaligned_be24(&st->rx_buf[1]); + *temperature = get_unaligned_be24(&st->rx_buf[4]); return 0; } diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 36fb7ae0d0a9..984a3f511a1a 100644 --- a/drivers/iio/pressure/dps310.c +++ b/drivers/iio/pressure/dps310.c @@ -89,6 +89,7 @@ struct dps310_data { s32 c00, c10, c20, c30, c01, c11, c21; s32 pressure_raw; s32 temp_raw; + bool timeout_recovery_failed; }; static const struct iio_chan_spec dps310_channels[] = { @@ -159,6 +160,102 @@ static int dps310_get_coefs(struct dps310_data *data) return 0; } +/* + * Some versions of the chip will read temperatures in the ~60C range when + * it's actually ~20C. This is the manufacturer recommended workaround + * to correct the issue. The registers used below are undocumented. + */ +static int dps310_temp_workaround(struct dps310_data *data) +{ + int rc; + int reg; + + rc = regmap_read(data->regmap, 0x32, ®); + if (rc) + return rc; + + /* + * If bit 1 is set then the device is okay, and the workaround does not + * need to be applied + */ + if (reg & BIT(1)) + return 0; + + rc = regmap_write(data->regmap, 0x0e, 0xA5); + if (rc) + return rc; + + rc = regmap_write(data->regmap, 0x0f, 0x96); + if (rc) + return rc; + + rc = regmap_write(data->regmap, 0x62, 0x02); + if (rc) + return rc; + + rc = regmap_write(data->regmap, 0x0e, 0x00); + if (rc) + return rc; + + return regmap_write(data->regmap, 0x0f, 0x00); +} + +static int dps310_startup(struct dps310_data *data) +{ + int rc; + int ready; + + /* + * Set up pressure sensor in single sample, one measurement per second + * mode + */ + rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0); + if (rc) + return rc; + + /* + * Set up external (MEMS) temperature sensor in single sample, one + * measurement per second mode + */ + rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT); + if (rc) + return rc; + + /* Temp and pressure shifts are disabled when PRC <= 8 */ + rc = regmap_write_bits(data->regmap, DPS310_CFG_REG, + DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0); + if (rc) + return rc; + + /* MEAS_CFG doesn't update correctly unless first written with 0 */ + rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG, + DPS310_MEAS_CTRL_BITS, 0); + if (rc) + return rc; + + /* Turn on temperature and pressure measurement in the background */ + rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG, + DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN | + DPS310_TEMP_EN | DPS310_BACKGROUND); + if (rc) + return rc; + + /* + * Calibration coefficients required for reporting temperature. + * They are available 40ms after the device has started + */ + rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, + ready & DPS310_COEF_RDY, 10000, 40000); + if (rc) + return rc; + + rc = dps310_get_coefs(data); + if (rc) + return rc; + + return dps310_temp_workaround(data); +} + static int dps310_get_pres_precision(struct dps310_data *data) { int rc; @@ -297,11 +394,69 @@ static int dps310_get_temp_k(struct dps310_data *data) return scale_factors[ilog2(rc)]; } +static int dps310_reset_wait(struct dps310_data *data) +{ + int rc; + + rc = regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC); + if (rc) + return rc; + + /* Wait for device chip access: 2.5ms in specification */ + usleep_range(2500, 12000); + return 0; +} + +static int dps310_reset_reinit(struct dps310_data *data) +{ + int rc; + + rc = dps310_reset_wait(data); + if (rc) + return rc; + + return dps310_startup(data); +} + +static int dps310_ready_status(struct dps310_data *data, int ready_bit, int timeout) +{ + int sleep = DPS310_POLL_SLEEP_US(timeout); + int ready; + + return regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, ready & ready_bit, + sleep, timeout); +} + +static int dps310_ready(struct dps310_data *data, int ready_bit, int timeout) +{ + int rc; + + rc = dps310_ready_status(data, ready_bit, timeout); + if (rc) { + if (rc == -ETIMEDOUT && !data->timeout_recovery_failed) { + /* Reset and reinitialize the chip. */ + if (dps310_reset_reinit(data)) { + data->timeout_recovery_failed = true; + } else { + /* Try again to get sensor ready status. */ + if (dps310_ready_status(data, ready_bit, timeout)) + data->timeout_recovery_failed = true; + else + return 0; + } + } + + return rc; + } + + data->timeout_recovery_failed = false; + return 0; +} + static int dps310_read_pres_raw(struct dps310_data *data) { int rc; int rate; - int ready; int timeout; s32 raw; u8 val[3]; @@ -313,9 +468,7 @@ static int dps310_read_pres_raw(struct dps310_data *data) timeout = DPS310_POLL_TIMEOUT_US(rate); /* Poll for sensor readiness; base the timeout upon the sample rate. */ - rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, - ready & DPS310_PRS_RDY, - DPS310_POLL_SLEEP_US(timeout), timeout); + rc = dps310_ready(data, DPS310_PRS_RDY, timeout); if (rc) goto done; @@ -352,7 +505,6 @@ static int dps310_read_temp_raw(struct dps310_data *data) { int rc; int rate; - int ready; int timeout; if (mutex_lock_interruptible(&data->lock)) @@ -362,10 +514,8 @@ static int dps310_read_temp_raw(struct dps310_data *data) timeout = DPS310_POLL_TIMEOUT_US(rate); /* Poll for sensor readiness; base the timeout upon the sample rate. */ - rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, - ready & DPS310_TMP_RDY, - DPS310_POLL_SLEEP_US(timeout), timeout); - if (rc < 0) + rc = dps310_ready(data, DPS310_TMP_RDY, timeout); + if (rc) goto done; rc = dps310_read_temp_ready(data); @@ -660,7 +810,7 @@ static void dps310_reset(void *action_data) { struct dps310_data *data = action_data; - regmap_write(data->regmap, DPS310_RESET, DPS310_RESET_MAGIC); + dps310_reset_wait(data); } static const struct regmap_config dps310_regmap_config = { @@ -677,52 +827,12 @@ static const struct iio_info dps310_info = { .write_raw = dps310_write_raw, }; -/* - * Some verions of chip will read temperatures in the ~60C range when - * its actually ~20C. This is the manufacturer recommended workaround - * to correct the issue. The registers used below are undocumented. - */ -static int dps310_temp_workaround(struct dps310_data *data) -{ - int rc; - int reg; - - rc = regmap_read(data->regmap, 0x32, ®); - if (rc < 0) - return rc; - - /* - * If bit 1 is set then the device is okay, and the workaround does not - * need to be applied - */ - if (reg & BIT(1)) - return 0; - - rc = regmap_write(data->regmap, 0x0e, 0xA5); - if (rc < 0) - return rc; - - rc = regmap_write(data->regmap, 0x0f, 0x96); - if (rc < 0) - return rc; - - rc = regmap_write(data->regmap, 0x62, 0x02); - if (rc < 0) - return rc; - - rc = regmap_write(data->regmap, 0x0e, 0x00); - if (rc < 0) - return rc; - - return regmap_write(data->regmap, 0x0f, 0x00); -} - static int dps310_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct dps310_data *data; struct iio_dev *iio; - int rc, ready; + int rc; iio = devm_iio_device_alloc(&client->dev, sizeof(*data)); if (!iio) @@ -747,54 +857,8 @@ static int dps310_probe(struct i2c_client *client, if (rc) return rc; - /* - * Set up pressure sensor in single sample, one measurement per second - * mode - */ - rc = regmap_write(data->regmap, DPS310_PRS_CFG, 0); - - /* - * Set up external (MEMS) temperature sensor in single sample, one - * measurement per second mode - */ - rc = regmap_write(data->regmap, DPS310_TMP_CFG, DPS310_TMP_EXT); - if (rc < 0) - return rc; - - /* Temp and pressure shifts are disabled when PRC <= 8 */ - rc = regmap_write_bits(data->regmap, DPS310_CFG_REG, - DPS310_PRS_SHIFT_EN | DPS310_TMP_SHIFT_EN, 0); - if (rc < 0) - return rc; - - /* MEAS_CFG doesn't update correctly unless first written with 0 */ - rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG, - DPS310_MEAS_CTRL_BITS, 0); - if (rc < 0) - return rc; - - /* Turn on temperature and pressure measurement in the background */ - rc = regmap_write_bits(data->regmap, DPS310_MEAS_CFG, - DPS310_MEAS_CTRL_BITS, DPS310_PRS_EN | - DPS310_TEMP_EN | DPS310_BACKGROUND); - if (rc < 0) - return rc; - - /* - * Calibration coefficients required for reporting temperature. - * They are available 40ms after the device has started - */ - rc = regmap_read_poll_timeout(data->regmap, DPS310_MEAS_CFG, ready, - ready & DPS310_COEF_RDY, 10000, 40000); - if (rc < 0) - return rc; - - rc = dps310_get_coefs(data); - if (rc < 0) - return rc; - - rc = dps310_temp_workaround(data); - if (rc < 0) + rc = dps310_startup(data); + if (rc) return rc; rc = devm_iio_device_register(&client->dev, iio); diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c index af4621eaa6b5..b62f28585db5 100644 --- a/drivers/iio/pressure/icp10100.c +++ b/drivers/iio/pressure/icp10100.c @@ -595,7 +595,7 @@ static int icp10100_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } -static int __maybe_unused icp10100_suspend(struct device *dev) +static int icp10100_suspend(struct device *dev) { struct icp10100_state *st = iio_priv(dev_get_drvdata(dev)); int ret; @@ -607,7 +607,7 @@ static int __maybe_unused icp10100_suspend(struct device *dev) return ret; } -static int __maybe_unused icp10100_resume(struct device *dev) +static int icp10100_resume(struct device *dev) { struct icp10100_state *st = iio_priv(dev_get_drvdata(dev)); int ret; @@ -626,8 +626,8 @@ out_unlock: return ret; } -static UNIVERSAL_DEV_PM_OPS(icp10100_pm, icp10100_suspend, icp10100_resume, - NULL); +static DEFINE_RUNTIME_DEV_PM_OPS(icp10100_pm, icp10100_suspend, icp10100_resume, + NULL); static const struct of_device_id icp10100_of_match[] = { { @@ -646,7 +646,7 @@ MODULE_DEVICE_TABLE(i2c, icp10100_id); static struct i2c_driver icp10100_driver = { .driver = { .name = "icp10100", - .pm = &icp10100_pm, + .pm = pm_ptr(&icp10100_pm), .of_match_table = icp10100_of_match, }, .probe = icp10100_probe, diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index 156e6a72dc5c..6e11bea784fa 100644 --- a/drivers/iio/pressure/st_pressure.h +++ b/drivers/iio/pressure/st_pressure.h @@ -22,6 +22,7 @@ enum st_press_type { LPS33HW, LPS35HW, LPS22HH, + LPS22DF, ST_PRESS_MAX, }; @@ -32,6 +33,7 @@ enum st_press_type { #define LPS33HW_PRESS_DEV_NAME "lps33hw" #define LPS35HW_PRESS_DEV_NAME "lps35hw" #define LPS22HH_PRESS_DEV_NAME "lps22hh" +#define LPS22DF_PRESS_DEV_NAME "lps22df" /** * struct st_sensors_platform_data - default press platform data diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index 76913a2028d2..80176e3083af 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -552,6 +552,76 @@ static const struct st_sensor_settings st_press_sensors_settings[] = { .multi_read_bit = false, .bootime = 2, }, + { + /* + * CUSTOM VALUES FOR LPS22DF SENSOR + * See LPS22DF datasheet: + * http://www.st.com/resource/en/datasheet/lps22df.pdf + */ + .wai = 0xb4, + .wai_addr = ST_SENSORS_DEFAULT_WAI_ADDRESS, + .sensors_supported = { + [0] = LPS22DF_PRESS_DEV_NAME, + }, + .ch = (struct iio_chan_spec *)st_press_lps22hb_channels, + .num_ch = ARRAY_SIZE(st_press_lps22hb_channels), + .odr = { + .addr = 0x10, + .mask = 0x78, + .odr_avl = { + { .hz = 1, .value = 0x01 }, + { .hz = 4, .value = 0x02 }, + { .hz = 10, .value = 0x03 }, + { .hz = 25, .value = 0x04 }, + { .hz = 50, .value = 0x05 }, + { .hz = 75, .value = 0x06 }, + { .hz = 100, .value = 0x07 }, + { .hz = 200, .value = 0x08 }, + }, + }, + .pw = { + .addr = 0x10, + .mask = 0x78, + .value_off = ST_SENSORS_DEFAULT_POWER_OFF_VALUE, + }, + .fs = { + .fs_avl = { + /* + * Pressure and temperature sensitivity values + * as defined in table 2 of LPS22DF datasheet. + */ + [0] = { + .num = ST_PRESS_FS_AVL_1260MB, + .gain = ST_PRESS_KPASCAL_NANO_SCALE, + .gain2 = ST_PRESS_LPS22HB_LSB_PER_CELSIUS, + }, + }, + }, + .bdu = { + .addr = 0x11, + .mask = BIT(3), + }, + .drdy_irq = { + .int1 = { + .addr = 0x13, + .mask = BIT(5), + .addr_od = 0x12, + .mask_od = BIT(1), + }, + .addr_ihl = 0x12, + .mask_ihl = BIT(3), + .stat_drdy = { + .addr = ST_SENSORS_DEFAULT_STAT_ADDR, + .mask = 0x03, + }, + }, + .sim = { + .addr = 0x0E, + .value = BIT(5), + }, + .multi_read_bit = false, + .bootime = 2, + }, }; static int st_press_write_raw(struct iio_dev *indio_dev, diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 7035777fd988..58fede861891 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -47,6 +47,10 @@ static const struct of_device_id st_press_of_match[] = { .compatible = "st,lps22hh", .data = LPS22HH_PRESS_DEV_NAME, }, + { + .compatible = "st,lps22df", + .data = LPS22DF_PRESS_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_press_of_match); @@ -67,6 +71,7 @@ static const struct i2c_device_id st_press_id_table[] = { { LPS33HW_PRESS_DEV_NAME, LPS33HW }, { LPS35HW_PRESS_DEV_NAME, LPS35HW }, { LPS22HH_PRESS_DEV_NAME, LPS22HH }, + { LPS22DF_PRESS_DEV_NAME, LPS22DF }, {}, }; MODULE_DEVICE_TABLE(i2c, st_press_id_table); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index bfab8e7fb061..25cca5ad7c55 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -51,6 +51,10 @@ static const struct of_device_id st_press_of_match[] = { .compatible = "st,lps22hh", .data = LPS22HH_PRESS_DEV_NAME, }, + { + .compatible = "st,lps22df", + .data = LPS22DF_PRESS_DEV_NAME, + }, {}, }; MODULE_DEVICE_TABLE(of, st_press_of_match); @@ -97,6 +101,7 @@ static const struct spi_device_id st_press_id_table[] = { { LPS33HW_PRESS_DEV_NAME }, { LPS35HW_PRESS_DEV_NAME }, { LPS22HH_PRESS_DEV_NAME }, + { LPS22DF_PRESS_DEV_NAME }, { "lps001wp-press" }, { "lps25h-press", }, { "lps331ap-press" }, |