diff options
Diffstat (limited to 'drivers/iio/pressure')
33 files changed, 2285 insertions, 753 deletions
diff --git a/drivers/iio/pressure/Kconfig b/drivers/iio/pressure/Kconfig index 9c2d9bf8f100..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 @@ -79,7 +79,6 @@ config DPS310 config HID_SENSOR_PRESS depends on HID_SENSOR_HUB select IIO_BUFFER - select IIO_TRIGGERED_BUFFER select HID_SENSOR_IIO_COMMON select HID_SENSOR_IIO_TRIGGER tristate "HID PRESS" @@ -101,6 +100,17 @@ config HP03 To compile this driver as a module, choose M here: the module will be called hp03. +config ICP10100 + tristate "InvenSense ICP-101xx pressure and temperature sensor" + depends on I2C + select CRC8 + help + Say yes here to build support for InvenSense ICP-101xx barometric + pressure and temperature sensor. + + To compile this driver as a module, choose M here: the module + will be called icp10100. + config MPL115 tristate @@ -184,30 +194,35 @@ config IIO_ST_PRESS tristate "STMicroelectronics pressure sensor Driver" depends on (I2C || SPI_MASTER) && SYSFS select IIO_ST_SENSORS_CORE - select IIO_ST_PRESS_I2C if (I2C) - select IIO_ST_PRESS_SPI if (SPI_MASTER) select IIO_TRIGGERED_BUFFER if (IIO_BUFFER) help Say yes here to build support for STMicroelectronics pressure sensors: LPS001WP, LPS25H, LPS331AP, LPS22HB, LPS22HH. - This driver can also be built as a module. If so, these modules - will be created: - - st_pressure (core functions for the driver [it is mandatory]); - - st_pressure_i2c (necessary for the I2C devices [optional*]); - - st_pressure_spi (necessary for the SPI devices [optional*]); - - (*) one of these is necessary to do something. + Also need to enable at least one of I2C and SPI interface drivers + below. config IIO_ST_PRESS_I2C - tristate - depends on IIO_ST_PRESS - depends on IIO_ST_SENSORS_I2C + tristate "STMicroelectronics pressure sensor I2C Interface" + depends on I2C && IIO_ST_PRESS + default I2C && IIO_ST_PRESS + select IIO_ST_SENSORS_I2C + help + Build support for STMicroelectronics pressure sensor I2C interface. + + To compile this driver as a module, choose M here. The module + will be called st_pressure_i2c. config IIO_ST_PRESS_SPI - tristate - depends on IIO_ST_PRESS - depends on IIO_ST_SENSORS_SPI + tristate "STMicroelectronics pressure sensor SPI Interface" + depends on SPI_MASTER && IIO_ST_PRESS + default SPI_MASTER && IIO_ST_PRESS + select IIO_ST_SENSORS_SPI + help + Build support for STMicroelectronics pressure sensor SPI interface. + + To compile this driver as a module, choose M here. The module + will be called st_pressure_spi. config T5403 tristate "EPCOS T5403 digital barometric pressure sensor driver" diff --git a/drivers/iio/pressure/Makefile b/drivers/iio/pressure/Makefile index 5a79192d8cb5..083ae87ff48f 100644 --- a/drivers/iio/pressure/Makefile +++ b/drivers/iio/pressure/Makefile @@ -14,6 +14,7 @@ obj-$(CONFIG_DPS310) += dps310.o obj-$(CONFIG_IIO_CROS_EC_BARO) += cros_ec_baro.o obj-$(CONFIG_HID_SENSOR_PRESS) += hid-sensor-press.o obj-$(CONFIG_HP03) += hp03.o +obj-$(CONFIG_ICP10100) += icp10100.o obj-$(CONFIG_MPL115) += mpl115.o obj-$(CONFIG_MPL115_I2C) += mpl115_i2c.o obj-$(CONFIG_MPL115_SPI) += mpl115_spi.o diff --git a/drivers/iio/pressure/abp060mg.c b/drivers/iio/pressure/abp060mg.c index 267aad8af0a6..e1c3bdb371ee 100644 --- a/drivers/iio/pressure/abp060mg.c +++ b/drivers/iio/pressure/abp060mg.c @@ -194,7 +194,6 @@ static int abp060mg_probe(struct i2c_client *client, abp060mg_init_device(indio_dev, cfg_id); - indio_dev->dev.parent = &client->dev; indio_dev->name = dev_name(&client->dev); indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &abp060mg_info; diff --git a/drivers/iio/pressure/bmp280-core.c b/drivers/iio/pressure/bmp280-core.c index 29c209cc1108..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)) @@ -271,6 +411,8 @@ static u32 bmp280_compensate_humidity(struct bmp280_data *data, + (s32)2097152) * calib->H2 + 8192) >> 14); var -= ((((var >> 15) * (var >> 15)) >> 7) * (s32)calib->H1) >> 4; + var = clamp_val(var, 0, 419430400); + return var >> 12; }; @@ -284,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; @@ -307,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; @@ -333,18 +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, - (u8 *) &tmp, 3); + 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"); @@ -367,10 +508,9 @@ 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); @@ -378,13 +518,13 @@ static int bmp280_read_press(struct bmp280_data *data, return ret; ret = regmap_bulk_read(data->regmap, BMP280_REG_PRESS_MSB, - (u8 *) &tmp, 3); + 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,10 +540,9 @@ static int bmp280_read_press(struct bmp280_data *data, static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) { - int ret; - __be16 tmp = 0; - 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); @@ -411,13 +550,13 @@ static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2) return ret; ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB, - (u8 *) &tmp, 2); + &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"); @@ -434,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); @@ -476,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; @@ -491,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; @@ -508,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; @@ -525,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; @@ -543,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); @@ -568,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; } @@ -575,64 +829,56 @@ static int bmp280_write_raw(struct iio_dev *indio_dev, return ret; } -static ssize_t bmp280_show_avail(char *buf, const int *vals, const int n) +static int bmp280_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) { - size_t len = 0; - int i; - - for (i = 0; i < n; i++) - len += scnprintf(buf + len, PAGE_SIZE - len, "%d ", vals[i]); - - buf[len - 1] = '\n'; - - return len; -} - -static ssize_t bmp280_show_temp_oversampling_avail(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); - - return bmp280_show_avail(buf, data->chip_info->oversampling_temp_avail, - data->chip_info->num_oversampling_temp_avail); -} - -static ssize_t bmp280_show_press_oversampling_avail(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct bmp280_data *data = iio_priv(dev_to_iio_dev(dev)); + struct bmp280_data *data = iio_priv(indio_dev); - return bmp280_show_avail(buf, data->chip_info->oversampling_press_avail, - data->chip_info->num_oversampling_press_avail); + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + switch (chan->type) { + case IIO_PRESSURE: + *vals = data->chip_info->oversampling_press_avail; + *length = data->chip_info->num_oversampling_press_avail; + break; + case IIO_TEMP: + *vals = data->chip_info->oversampling_temp_avail; + *length = data->chip_info->num_oversampling_temp_avail; + break; + default: + return -EINVAL; + } + *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; + } } -static IIO_DEVICE_ATTR(in_temp_oversampling_ratio_available, - S_IRUGO, bmp280_show_temp_oversampling_avail, NULL, 0); - -static IIO_DEVICE_ATTR(in_pressure_oversampling_ratio_available, - S_IRUGO, bmp280_show_press_oversampling_avail, NULL, 0); - -static struct attribute *bmp280_attributes[] = { - &iio_dev_attr_in_temp_oversampling_ratio_available.dev_attr.attr, - &iio_dev_attr_in_pressure_oversampling_ratio_available.dev_attr.attr, - NULL, -}; - -static const struct attribute_group bmp280_attrs_group = { - .attrs = bmp280_attributes, -}; - static const struct iio_info bmp280_info = { .read_raw = &bmp280_read_raw, + .read_avail = &bmp280_read_avail, .write_raw = &bmp280_write_raw, - .attrs = &bmp280_attrs_group, }; 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 | @@ -660,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 @@ -690,30 +954,408 @@ 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) - init_completion(&data->done); + reinit_completion(&data->done); ret = regmap_write(data->regmap, BMP280_REG_CTRL_MEAS, ctrl_meas); if (ret) @@ -730,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 = @@ -753,54 +1395,56 @@ static int bmp180_measure(struct bmp280_data *data, u8 ctrl_meas) static int bmp180_read_adc_temp(struct bmp280_data *data, int *val) { int ret; - __be16 tmp = 0; - 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, (u8 *)&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; } @@ -813,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); @@ -825,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) @@ -848,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, (u8 *)&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; } @@ -872,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; @@ -903,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); @@ -933,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) @@ -965,10 +1620,12 @@ static int bmp085_fetch_eoc_irq(struct device *dev, irq_trig = irqd_get_trigger_type(irq_get_irq_data(irq)); if (irq_trig != IRQF_TRIGGER_RISING) { - dev_err(dev, "non-rising trigger given for EOC interrupt, " - "trying to enforce it\n"); + dev_err(dev, "non-rising trigger given for EOC interrupt, trying to enforce it\n"); irq_trig = IRQF_TRIGGER_RISING; } + + init_completion(&data->done); + ret = devm_request_threaded_irq(dev, irq, bmp085_eoc_irq, @@ -1008,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) @@ -1022,38 +1680,37 @@ int bmp280_common_probe(struct device *dev, mutex_init(&data->lock); data->dev = dev; - indio_dev->dev.parent = 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, @@ -1082,15 +1739,16 @@ int bmp280_common_probe(struct device *dev, usleep_range(data->start_up_time, data->start_up_time + 100); /* Bring chip out of reset if there is an assigned GPIO line */ - gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH); + gpiod = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); /* Deassert the signal */ - if (!IS_ERR(gpiod)) { + if (gpiod) { dev_info(dev, "release reset\n"); gpiod_set_value(gpiod, 0); } 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) { @@ -1099,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; @@ -1110,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 @@ -1155,9 +1810,8 @@ int bmp280_common_probe(struct device *dev, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL(bmp280_common_probe); +EXPORT_SYMBOL_NS(bmp280_common_probe, IIO_BMP280); -#ifdef CONFIG_PM static int bmp280_runtime_suspend(struct device *dev) { struct iio_dev *indio_dev = dev_get_drvdata(dev); @@ -1178,15 +1832,9 @@ static int bmp280_runtime_resume(struct device *dev) usleep_range(data->start_up_time, data->start_up_time + 100); return data->chip_info->chip_config(data); } -#endif /* CONFIG_PM */ -const struct dev_pm_ops bmp280_dev_pm_ops = { - SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, - pm_runtime_force_resume) - SET_RUNTIME_PM_OPS(bmp280_runtime_suspend, - bmp280_runtime_resume, NULL) -}; -EXPORT_SYMBOL(bmp280_dev_pm_ops); +EXPORT_RUNTIME_DEV_PM_OPS(bmp280_dev_pm_ops, bmp280_runtime_suspend, + bmp280_runtime_resume, NULL); MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor"); diff --git a/drivers/iio/pressure/bmp280-i2c.c b/drivers/iio/pressure/bmp280-i2c.c index 8b03ea15c0d0..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); @@ -58,7 +63,7 @@ static struct i2c_driver bmp280_i2c_driver = { .driver = { .name = "bmp280", .of_match_table = bmp280_of_i2c_match, - .pm = &bmp280_dev_pm_ops, + .pm = pm_ptr(&bmp280_dev_pm_ops), }, .probe = bmp280_i2c_probe, .id_table = bmp280_i2c_id, @@ -68,3 +73,4 @@ module_i2c_driver(bmp280_i2c_driver); MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>"); MODULE_DESCRIPTION("Driver for Bosch Sensortec BMP180/BMP280 pressure and temperature sensor"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_BMP280); diff --git a/drivers/iio/pressure/bmp280-regmap.c b/drivers/iio/pressure/bmp280-regmap.c index 08c00ac32bda..c98c67970265 100644 --- a/drivers/iio/pressure/bmp280-regmap.c +++ b/drivers/iio/pressure/bmp280-regmap.c @@ -13,7 +13,7 @@ static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool bmp180_is_volatile_reg(struct device *dev, unsigned int reg) @@ -39,7 +39,7 @@ const struct regmap_config bmp180_regmap_config = { .writeable_reg = bmp180_is_writeable_reg, .volatile_reg = bmp180_is_volatile_reg, }; -EXPORT_SYMBOL(bmp180_regmap_config); +EXPORT_SYMBOL_NS(bmp180_regmap_config, IIO_BMP280); static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) { @@ -51,7 +51,7 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg) return true; default: return false; - }; + } } static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg) @@ -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, @@ -82,4 +125,16 @@ const struct regmap_config bmp280_regmap_config = { .writeable_reg = bmp280_is_writeable_reg, .volatile_reg = bmp280_is_volatile_reg, }; -EXPORT_SYMBOL(bmp280_regmap_config); +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 625b86878ad8..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); @@ -109,7 +114,7 @@ static struct spi_driver bmp280_spi_driver = { .driver = { .name = "bmp280", .of_match_table = bmp280_of_spi_match, - .pm = &bmp280_dev_pm_ops, + .pm = pm_ptr(&bmp280_dev_pm_ops), }, .id_table = bmp280_spi_id, .probe = bmp280_spi_probe, @@ -118,3 +123,4 @@ module_spi_driver(bmp280_spi_driver); MODULE_DESCRIPTION("BMP280 SPI bus driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_BMP280); 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/cros_ec_baro.c b/drivers/iio/pressure/cros_ec_baro.c index b521bebd551c..2649c2f89e89 100644 --- a/drivers/iio/pressure/cros_ec_baro.c +++ b/drivers/iio/pressure/cros_ec_baro.c @@ -14,6 +14,7 @@ #include <linux/iio/triggered_buffer.h> #include <linux/iio/trigger_consumer.h> #include <linux/kernel.h> +#include <linux/mod_devicetable.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/platform_data/cros_ec_commands.h> @@ -96,8 +97,11 @@ static int cros_ec_baro_write(struct iio_dev *indio_dev, /* Always roundup, so caller gets at least what it asks for. */ st->core.param.sensor_range.roundup = 1; - if (cros_ec_motion_send_host_cmd(&st->core, 0)) - ret = -EIO; + ret = cros_ec_motion_send_host_cmd(&st->core, 0); + if (ret == 0) { + st->core.range_updated = true; + st->core.curr_range = val; + } break; default: ret = cros_ec_sensors_core_write(&st->core, chan, val, val2, @@ -134,21 +138,19 @@ static int cros_ec_baro_probe(struct platform_device *pdev) if (!indio_dev) return -ENOMEM; - ret = cros_ec_sensors_core_init(pdev, indio_dev, true); + ret = cros_ec_sensors_core_init(pdev, indio_dev, true, + cros_ec_sensors_capture); if (ret) return ret; indio_dev->info = &cros_ec_baro_info; state = iio_priv(indio_dev); - state->core.type = state->core.resp->info.type; - state->core.loc = state->core.resp->info.location; channel = state->channels; /* Common part */ channel->info_mask_separate = BIT(IIO_CHAN_INFO_RAW); channel->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SCALE) | - BIT(IIO_CHAN_INFO_SAMP_FREQ) | - BIT(IIO_CHAN_INFO_FREQUENCY); + BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->info_mask_shared_by_all_available = BIT(IIO_CHAN_INFO_SAMP_FREQ); channel->scan_type.realbits = CROS_EC_SENSOR_BITS; @@ -182,12 +184,8 @@ static int cros_ec_baro_probe(struct platform_device *pdev) state->core.read_ec_sensors_data = cros_ec_sensors_read_cmd; - ret = devm_iio_triggered_buffer_setup(dev, indio_dev, NULL, - cros_ec_sensors_capture, NULL); - if (ret) - return ret; - - return devm_iio_device_register(dev, indio_dev); + return cros_ec_sensors_core_register(dev, indio_dev, + cros_ec_sensors_push_data); } static const struct platform_device_id cros_ec_baro_ids[] = { @@ -201,6 +199,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_baro_ids); static struct platform_driver cros_ec_baro_platform_driver = { .driver = { .name = "cros-ec-baro", + .pm = &cros_ec_sensors_pm_ops, }, .probe = cros_ec_baro_probe, .id_table = cros_ec_baro_ids, diff --git a/drivers/iio/pressure/dlhl60d.c b/drivers/iio/pressure/dlhl60d.c index b8c99e7bd6cf..f0b0d198c6d4 100644 --- a/drivers/iio/pressure/dlhl60d.c +++ b/drivers/iio/pressure/dlhl60d.c @@ -5,7 +5,7 @@ * Copyright (c) 2019 AVL DiTEST GmbH * Tomislav Denis <tomislav.denis@avl.com> * - * Datasheet: http://www.allsensors.com/cad/DS-0355_Rev_B.PDF + * Datasheet: https://www.allsensors.com/cad/DS-0355_Rev_B.PDF */ #include <linux/module.h> @@ -47,7 +47,7 @@ struct dlh_state { struct dlh_info info; bool use_interrupt; struct completion completion; - u8 rx_buf[DLH_NUM_READ_BYTES] ____cacheline_aligned; + u8 rx_buf[DLH_NUM_READ_BYTES]; }; static struct dlh_info dlh_info_tbl[] = { @@ -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; } @@ -311,8 +310,6 @@ static int dlh_probe(struct i2c_client *client, st->use_interrupt = false; indio_dev->name = id->name; - indio_dev->dev.parent = &client->dev; - indio_dev->dev.of_node = client->dev.of_node; indio_dev->info = &dlh_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = dlh_channels; diff --git a/drivers/iio/pressure/dps310.c b/drivers/iio/pressure/dps310.c index 2c1943bbc433..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) @@ -732,7 +842,6 @@ static int dps310_probe(struct i2c_client *client, data->client = client; mutex_init(&data->lock); - iio->dev.parent = &client->dev; iio->name = id->name; iio->channels = dps310_channels; iio->num_channels = ARRAY_SIZE(dps310_channels); @@ -748,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); @@ -813,9 +876,16 @@ static const struct i2c_device_id dps310_id[] = { }; MODULE_DEVICE_TABLE(i2c, dps310_id); +static const struct acpi_device_id dps310_acpi_match[] = { + { "IFX3100" }, + {} +}; +MODULE_DEVICE_TABLE(acpi, dps310_acpi_match); + static struct i2c_driver dps310_driver = { .driver = { .name = DPS310_DEV_NAME, + .acpi_match_table = dps310_acpi_match, }, .probe = dps310_probe, .id_table = dps310_id, diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c index 953235052155..a9215eb32d70 100644 --- a/drivers/iio/pressure/hid-sensor-press.c +++ b/drivers/iio/pressure/hid-sensor-press.c @@ -6,29 +6,36 @@ #include <linux/device.h> #include <linux/platform_device.h> #include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/irq.h> +#include <linux/mod_devicetable.h> #include <linux/slab.h> -#include <linux/delay.h> #include <linux/hid-sensor-hub.h> #include <linux/iio/iio.h> -#include <linux/iio/sysfs.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> #include "../common/hid-sensors/hid-sensor-trigger.h" -#define CHANNEL_SCAN_INDEX_PRESSURE 0 +enum { + CHANNEL_SCAN_INDEX_PRESSURE, + CHANNEL_SCAN_INDEX_TIMESTAMP, +}; struct press_state { struct hid_sensor_hub_callbacks callbacks; struct hid_sensor_common common_attributes; struct hid_sensor_hub_attribute_info press_attr; - u32 press_data; + struct { + u32 press_data; + u64 timestamp __aligned(8); + } scan; int scale_pre_decml; int scale_post_decml; int scale_precision; int value_offset; + s64 timestamp; +}; + +static const u32 press_sensitivity_addresses[] = { + HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE, + HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE }; /* Channel definitions */ @@ -41,7 +48,9 @@ static const struct iio_chan_spec press_channels[] = { BIT(IIO_CHAN_INFO_SAMP_FREQ) | BIT(IIO_CHAN_INFO_HYSTERESIS), .scan_index = CHANNEL_SCAN_INDEX_PRESSURE, - } + }, + IIO_CHAN_SOFT_TIMESTAMP(CHANNEL_SCAN_INDEX_TIMESTAMP) + }; /* Adjust channel real bits based on report descriptor */ @@ -154,14 +163,6 @@ static const struct iio_info press_info = { .write_raw = &press_write_raw, }; -/* Function to push data to buffer */ -static void hid_sensor_push_data(struct iio_dev *indio_dev, const void *data, - int len) -{ - dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); - iio_push_to_buffers(indio_dev, data); -} - /* Callback handler to send event after all samples are received and captured */ static int press_proc_event(struct hid_sensor_hub_device *hsdev, unsigned usage_id, @@ -171,10 +172,13 @@ static int press_proc_event(struct hid_sensor_hub_device *hsdev, struct press_state *press_state = iio_priv(indio_dev); dev_dbg(&indio_dev->dev, "press_proc_event\n"); - if (atomic_read(&press_state->common_attributes.data_ready)) - hid_sensor_push_data(indio_dev, - &press_state->press_data, - sizeof(press_state->press_data)); + if (atomic_read(&press_state->common_attributes.data_ready)) { + if (!press_state->timestamp) + press_state->timestamp = iio_get_time_ns(indio_dev); + + iio_push_to_buffers_with_timestamp( + indio_dev, &press_state->scan, press_state->timestamp); + } return 0; } @@ -191,9 +195,13 @@ static int press_capture_sample(struct hid_sensor_hub_device *hsdev, switch (usage_id) { case HID_USAGE_SENSOR_ATMOSPHERIC_PRESSURE: - press_state->press_data = *(u32 *)raw_data; + press_state->scan.press_data = *(u32 *)raw_data; ret = 0; break; + case HID_USAGE_SENSOR_TIME_TIMESTAMP: + press_state->timestamp = hid_sensor_convert_timestamp( + &press_state->common_attributes, *(s64 *)raw_data); + break; default: break; } @@ -227,17 +235,6 @@ static int press_parse_report(struct platform_device *pdev, &st->press_attr, &st->scale_pre_decml, &st->scale_post_decml); - /* Set Sensitivity field ids, when there is no individual modifier */ - if (st->common_attributes.sensitivity.index < 0) { - sensor_hub_input_get_attribute_info(hsdev, - HID_FEATURE_REPORT, usage_id, - HID_USAGE_SENSOR_DATA_MOD_CHANGE_SENSITIVITY_ABS | - HID_USAGE_SENSOR_DATA_ATMOSPHERIC_PRESSURE, - &st->common_attributes.sensitivity); - dev_dbg(&pdev->dev, "Sensitivity index:report %d:%d\n", - st->common_attributes.sensitivity.index, - st->common_attributes.sensitivity.report_id); - } return ret; } @@ -262,14 +259,16 @@ static int hid_press_probe(struct platform_device *pdev) ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_PRESSURE, - &press_state->common_attributes); + &press_state->common_attributes, + press_sensitivity_addresses, + ARRAY_SIZE(press_sensitivity_addresses)); if (ret) { dev_err(&pdev->dev, "failed to setup common attributes\n"); return ret; } - indio_dev->channels = kmemdup(press_channels, sizeof(press_channels), - GFP_KERNEL); + indio_dev->channels = devm_kmemdup(&pdev->dev, press_channels, + sizeof(press_channels), GFP_KERNEL); if (!indio_dev->channels) { dev_err(&pdev->dev, "failed to duplicate channels\n"); return -ENOMEM; @@ -280,28 +279,22 @@ static int hid_press_probe(struct platform_device *pdev) HID_USAGE_SENSOR_PRESSURE, press_state); if (ret) { dev_err(&pdev->dev, "failed to setup attributes\n"); - goto error_free_dev_mem; + return ret; } indio_dev->num_channels = ARRAY_SIZE(press_channels); - indio_dev->dev.parent = &pdev->dev; indio_dev->info = &press_info; indio_dev->name = name; indio_dev->modes = INDIO_DIRECT_MODE; - ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - NULL, NULL); - if (ret) { - dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); - goto error_free_dev_mem; - } atomic_set(&press_state->common_attributes.data_ready, 0); + ret = hid_sensor_setup_trigger(indio_dev, name, &press_state->common_attributes); if (ret) { dev_err(&pdev->dev, "trigger setup failed\n"); - goto error_unreg_buffer_funcs; + return ret; } ret = iio_device_register(indio_dev); @@ -325,11 +318,7 @@ static int hid_press_probe(struct platform_device *pdev) error_iio_unreg: iio_device_unregister(indio_dev); error_remove_trigger: - hid_sensor_remove_trigger(&press_state->common_attributes); -error_unreg_buffer_funcs: - iio_triggered_buffer_cleanup(indio_dev); -error_free_dev_mem: - kfree(indio_dev->channels); + hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); return ret; } @@ -342,9 +331,7 @@ static int hid_press_remove(struct platform_device *pdev) sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_PRESSURE); iio_device_unregister(indio_dev); - hid_sensor_remove_trigger(&press_state->common_attributes); - iio_triggered_buffer_cleanup(indio_dev); - kfree(indio_dev->channels); + hid_sensor_remove_trigger(indio_dev, &press_state->common_attributes); return 0; } @@ -372,3 +359,4 @@ module_platform_driver(hid_press_platform_driver); MODULE_DESCRIPTION("HID Sensor Pressure"); MODULE_AUTHOR("Archana Patni <archana.patni@intel.com>"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_HID); diff --git a/drivers/iio/pressure/hp03.c b/drivers/iio/pressure/hp03.c index 026ba15ef68f..9538118c9648 100644 --- a/drivers/iio/pressure/hp03.c +++ b/drivers/iio/pressure/hp03.c @@ -224,7 +224,6 @@ static int hp03_probe(struct i2c_client *client, priv->client = client; mutex_init(&priv->lock); - indio_dev->dev.parent = dev; indio_dev->name = id->name; indio_dev->channels = hp03_channels; indio_dev->num_channels = ARRAY_SIZE(hp03_channels); @@ -243,47 +242,26 @@ static int hp03_probe(struct i2c_client *client, * which has it's dedicated I2C address and contains * the calibration constants for the sensor. */ - priv->eeprom_client = i2c_new_dummy_device(client->adapter, HP03_EEPROM_ADDR); + priv->eeprom_client = devm_i2c_new_dummy_device(dev, client->adapter, + HP03_EEPROM_ADDR); if (IS_ERR(priv->eeprom_client)) { dev_err(dev, "New EEPROM I2C device failed\n"); return PTR_ERR(priv->eeprom_client); } - priv->eeprom_regmap = regmap_init_i2c(priv->eeprom_client, - &hp03_regmap_config); + priv->eeprom_regmap = devm_regmap_init_i2c(priv->eeprom_client, + &hp03_regmap_config); if (IS_ERR(priv->eeprom_regmap)) { dev_err(dev, "Failed to allocate EEPROM regmap\n"); - ret = PTR_ERR(priv->eeprom_regmap); - goto err_cleanup_eeprom_client; + return PTR_ERR(priv->eeprom_regmap); } - ret = iio_device_register(indio_dev); + ret = devm_iio_device_register(dev, indio_dev); if (ret) { dev_err(dev, "Failed to register IIO device\n"); - goto err_cleanup_eeprom_regmap; + return ret; } - i2c_set_clientdata(client, indio_dev); - - return 0; - -err_cleanup_eeprom_regmap: - regmap_exit(priv->eeprom_regmap); - -err_cleanup_eeprom_client: - i2c_unregister_device(priv->eeprom_client); - return ret; -} - -static int hp03_remove(struct i2c_client *client) -{ - struct iio_dev *indio_dev = i2c_get_clientdata(client); - struct hp03_priv *priv = iio_priv(indio_dev); - - iio_device_unregister(indio_dev); - regmap_exit(priv->eeprom_regmap); - i2c_unregister_device(priv->eeprom_client); - return 0; } @@ -305,7 +283,6 @@ static struct i2c_driver hp03_driver = { .of_match_table = hp03_of_match, }, .probe = hp03_probe, - .remove = hp03_remove, .id_table = hp03_id, }; module_i2c_driver(hp03_driver); diff --git a/drivers/iio/pressure/hp206c.c b/drivers/iio/pressure/hp206c.c index 3ac3632e7242..986b7a59712e 100644 --- a/drivers/iio/pressure/hp206c.c +++ b/drivers/iio/pressure/hp206c.c @@ -18,6 +18,8 @@ #include <linux/util_macros.h> #include <linux/acpi.h> +#include <asm/unaligned.h> + /* I2C commands: */ #define HP206C_CMD_SOFT_RST 0x06 @@ -93,12 +95,12 @@ static int hp206c_read_20bit(struct i2c_client *client, u8 cmd) int ret; u8 values[3]; - ret = i2c_smbus_read_i2c_block_data(client, cmd, 3, values); + ret = i2c_smbus_read_i2c_block_data(client, cmd, sizeof(values), values); if (ret < 0) return ret; - if (ret != 3) + if (ret != sizeof(values)) return -EIO; - return ((values[0] & 0xF) << 16) | (values[1] << 8) | (values[2]); + return get_unaligned_be24(&values[0]) & GENMASK(19, 0); } /* Spin for max 160ms until DEV_RDY is 1, or return error. */ @@ -376,7 +378,6 @@ static int hp206c_probe(struct i2c_client *client, indio_dev->info = &hp206c_info; indio_dev->name = id->name; - indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = hp206c_channels; indio_dev->num_channels = ARRAY_SIZE(hp206c_channels); diff --git a/drivers/iio/pressure/icp10100.c b/drivers/iio/pressure/icp10100.c new file mode 100644 index 000000000000..b62f28585db5 --- /dev/null +++ b/drivers/iio/pressure/icp10100.c @@ -0,0 +1,659 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2020 InvenSense, Inc. + * + * Driver for InvenSense ICP-1010xx barometric pressure and temperature sensor. + * + * Datasheet: + * http://www.invensense.com/wp-content/uploads/2018/01/DS-000186-ICP-101xx-v1.2.pdf + */ + +#include <linux/device.h> +#include <linux/module.h> +#include <linux/mod_devicetable.h> +#include <linux/i2c.h> +#include <linux/pm_runtime.h> +#include <linux/crc8.h> +#include <linux/mutex.h> +#include <linux/delay.h> +#include <linux/log2.h> +#include <linux/math64.h> +#include <linux/regulator/consumer.h> +#include <linux/iio/iio.h> + +#define ICP10100_ID_REG_GET(_reg) ((_reg) & 0x003F) +#define ICP10100_ID_REG 0x08 +#define ICP10100_RESPONSE_WORD_LENGTH 3 +#define ICP10100_CRC8_WORD_LENGTH 2 +#define ICP10100_CRC8_POLYNOMIAL 0x31 +#define ICP10100_CRC8_INIT 0xFF + +enum icp10100_mode { + ICP10100_MODE_LP, /* Low power mode: 1x sampling */ + ICP10100_MODE_N, /* Normal mode: 2x sampling */ + ICP10100_MODE_LN, /* Low noise mode: 4x sampling */ + ICP10100_MODE_ULN, /* Ultra low noise mode: 8x sampling */ + ICP10100_MODE_NB, +}; + +struct icp10100_state { + struct mutex lock; + struct i2c_client *client; + struct regulator *vdd; + enum icp10100_mode mode; + int16_t cal[4]; +}; + +struct icp10100_command { + __be16 cmd; + unsigned long wait_us; + unsigned long wait_max_us; + size_t response_word_nb; +}; + +static const struct icp10100_command icp10100_cmd_soft_reset = { + .cmd = cpu_to_be16(0x805D), + .wait_us = 170, + .wait_max_us = 200, + .response_word_nb = 0, +}; + +static const struct icp10100_command icp10100_cmd_read_id = { + .cmd = cpu_to_be16(0xEFC8), + .wait_us = 0, + .response_word_nb = 1, +}; + +static const struct icp10100_command icp10100_cmd_read_otp = { + .cmd = cpu_to_be16(0xC7F7), + .wait_us = 0, + .response_word_nb = 1, +}; + +static const struct icp10100_command icp10100_cmd_measure[] = { + [ICP10100_MODE_LP] = { + .cmd = cpu_to_be16(0x401A), + .wait_us = 1800, + .wait_max_us = 2000, + .response_word_nb = 3, + }, + [ICP10100_MODE_N] = { + .cmd = cpu_to_be16(0x48A3), + .wait_us = 6300, + .wait_max_us = 6500, + .response_word_nb = 3, + }, + [ICP10100_MODE_LN] = { + .cmd = cpu_to_be16(0x5059), + .wait_us = 23800, + .wait_max_us = 24000, + .response_word_nb = 3, + }, + [ICP10100_MODE_ULN] = { + .cmd = cpu_to_be16(0x58E0), + .wait_us = 94500, + .wait_max_us = 94700, + .response_word_nb = 3, + }, +}; + +static const uint8_t icp10100_switch_mode_otp[] = + {0xC5, 0x95, 0x00, 0x66, 0x9c}; + +DECLARE_CRC8_TABLE(icp10100_crc8_table); + +static inline int icp10100_i2c_xfer(struct i2c_adapter *adap, + struct i2c_msg *msgs, int num) +{ + int ret; + + ret = i2c_transfer(adap, msgs, num); + if (ret < 0) + return ret; + + if (ret != num) + return -EIO; + + return 0; +} + +static int icp10100_send_cmd(struct icp10100_state *st, + const struct icp10100_command *cmd, + __be16 *buf, size_t buf_len) +{ + size_t size = cmd->response_word_nb * ICP10100_RESPONSE_WORD_LENGTH; + uint8_t data[16]; + uint8_t *ptr; + uint8_t *buf_ptr = (uint8_t *)buf; + struct i2c_msg msgs[2] = { + { + .addr = st->client->addr, + .flags = 0, + .len = 2, + .buf = (uint8_t *)&cmd->cmd, + }, { + .addr = st->client->addr, + .flags = I2C_M_RD, + .len = size, + .buf = data, + }, + }; + uint8_t crc; + unsigned int i; + int ret; + + if (size > sizeof(data)) + return -EINVAL; + + if (cmd->response_word_nb > 0 && + (buf == NULL || buf_len < (cmd->response_word_nb * 2))) + return -EINVAL; + + dev_dbg(&st->client->dev, "sending cmd %#x\n", be16_to_cpu(cmd->cmd)); + + if (cmd->response_word_nb > 0 && cmd->wait_us == 0) { + /* direct command-response without waiting */ + ret = icp10100_i2c_xfer(st->client->adapter, msgs, + ARRAY_SIZE(msgs)); + if (ret) + return ret; + } else { + /* transfer command write */ + ret = icp10100_i2c_xfer(st->client->adapter, &msgs[0], 1); + if (ret) + return ret; + if (cmd->wait_us > 0) + usleep_range(cmd->wait_us, cmd->wait_max_us); + /* transfer response read if needed */ + if (cmd->response_word_nb > 0) { + ret = icp10100_i2c_xfer(st->client->adapter, &msgs[1], 1); + if (ret) + return ret; + } else { + return 0; + } + } + + /* process read words with crc checking */ + for (i = 0; i < cmd->response_word_nb; ++i) { + ptr = &data[i * ICP10100_RESPONSE_WORD_LENGTH]; + crc = crc8(icp10100_crc8_table, ptr, ICP10100_CRC8_WORD_LENGTH, + ICP10100_CRC8_INIT); + if (crc != ptr[ICP10100_CRC8_WORD_LENGTH]) { + dev_err(&st->client->dev, "crc error recv=%#x calc=%#x\n", + ptr[ICP10100_CRC8_WORD_LENGTH], crc); + return -EIO; + } + *buf_ptr++ = ptr[0]; + *buf_ptr++ = ptr[1]; + } + + return 0; +} + +static int icp10100_read_cal_otp(struct icp10100_state *st) +{ + __be16 val; + int i; + int ret; + + /* switch into OTP read mode */ + ret = i2c_master_send(st->client, icp10100_switch_mode_otp, + ARRAY_SIZE(icp10100_switch_mode_otp)); + if (ret < 0) + return ret; + if (ret != ARRAY_SIZE(icp10100_switch_mode_otp)) + return -EIO; + + /* read 4 calibration values */ + for (i = 0; i < 4; ++i) { + ret = icp10100_send_cmd(st, &icp10100_cmd_read_otp, + &val, sizeof(val)); + if (ret) + return ret; + st->cal[i] = be16_to_cpu(val); + dev_dbg(&st->client->dev, "cal[%d] = %d\n", i, st->cal[i]); + } + + return 0; +} + +static int icp10100_init_chip(struct icp10100_state *st) +{ + __be16 val; + uint16_t id; + int ret; + + /* read and check id */ + ret = icp10100_send_cmd(st, &icp10100_cmd_read_id, &val, sizeof(val)); + if (ret) + return ret; + id = ICP10100_ID_REG_GET(be16_to_cpu(val)); + if (id != ICP10100_ID_REG) { + dev_err(&st->client->dev, "invalid id %#x\n", id); + return -ENODEV; + } + + /* read calibration data from OTP */ + ret = icp10100_read_cal_otp(st); + if (ret) + return ret; + + /* reset chip */ + return icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0); +} + +static int icp10100_get_measures(struct icp10100_state *st, + uint32_t *pressure, uint16_t *temperature) +{ + const struct icp10100_command *cmd; + __be16 measures[3]; + int ret; + + ret = pm_runtime_resume_and_get(&st->client->dev); + if (ret < 0) + return ret; + + mutex_lock(&st->lock); + cmd = &icp10100_cmd_measure[st->mode]; + ret = icp10100_send_cmd(st, cmd, measures, sizeof(measures)); + mutex_unlock(&st->lock); + if (ret) + goto error_measure; + + *pressure = (be16_to_cpu(measures[0]) << 8) | + (be16_to_cpu(measures[1]) >> 8); + *temperature = be16_to_cpu(measures[2]); + + pm_runtime_mark_last_busy(&st->client->dev); +error_measure: + pm_runtime_put_autosuspend(&st->client->dev); + return ret; +} + +static uint32_t icp10100_get_pressure(struct icp10100_state *st, + uint32_t raw_pressure, uint16_t raw_temp) +{ + static int32_t p_calib[] = {45000, 80000, 105000}; + static int32_t lut_lower = 3670016; + static int32_t lut_upper = 12058624; + static int32_t inv_quadr_factor = 16777216; + static int32_t offset_factor = 2048; + int64_t val1, val2; + int32_t p_lut[3]; + int32_t t, t_square; + int64_t a, b, c; + uint32_t pressure_mPa; + + dev_dbg(&st->client->dev, "raw: pressure = %u, temp = %u\n", + raw_pressure, raw_temp); + + /* compute p_lut values */ + t = (int32_t)raw_temp - 32768; + t_square = t * t; + val1 = (int64_t)st->cal[0] * (int64_t)t_square; + p_lut[0] = lut_lower + (int32_t)div_s64(val1, inv_quadr_factor); + val1 = (int64_t)st->cal[1] * (int64_t)t_square; + p_lut[1] = offset_factor * st->cal[3] + + (int32_t)div_s64(val1, inv_quadr_factor); + val1 = (int64_t)st->cal[2] * (int64_t)t_square; + p_lut[2] = lut_upper + (int32_t)div_s64(val1, inv_quadr_factor); + dev_dbg(&st->client->dev, "p_lut = [%d, %d, %d]\n", + p_lut[0], p_lut[1], p_lut[2]); + + /* compute a, b, c factors */ + val1 = (int64_t)p_lut[0] * (int64_t)p_lut[1] * + (int64_t)(p_calib[0] - p_calib[1]) + + (int64_t)p_lut[1] * (int64_t)p_lut[2] * + (int64_t)(p_calib[1] - p_calib[2]) + + (int64_t)p_lut[2] * (int64_t)p_lut[0] * + (int64_t)(p_calib[2] - p_calib[0]); + val2 = (int64_t)p_lut[2] * (int64_t)(p_calib[0] - p_calib[1]) + + (int64_t)p_lut[0] * (int64_t)(p_calib[1] - p_calib[2]) + + (int64_t)p_lut[1] * (int64_t)(p_calib[2] - p_calib[0]); + c = div64_s64(val1, val2); + dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, c = %lld\n", + val1, val2, c); + val1 = (int64_t)p_calib[0] * (int64_t)p_lut[0] - + (int64_t)p_calib[1] * (int64_t)p_lut[1] - + (int64_t)(p_calib[1] - p_calib[0]) * c; + val2 = (int64_t)p_lut[0] - (int64_t)p_lut[1]; + a = div64_s64(val1, val2); + dev_dbg(&st->client->dev, "val1 = %lld, val2 = %lld, a = %lld\n", + val1, val2, a); + b = ((int64_t)p_calib[0] - a) * ((int64_t)p_lut[0] + c); + dev_dbg(&st->client->dev, "b = %lld\n", b); + + /* + * pressure_Pa = a + (b / (c + raw_pressure)) + * pressure_mPa = 1000 * pressure_Pa + */ + pressure_mPa = 1000LL * a + div64_s64(1000LL * b, c + raw_pressure); + + return pressure_mPa; +} + +static int icp10100_read_raw_measures(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2) +{ + struct icp10100_state *st = iio_priv(indio_dev); + uint32_t raw_pressure; + uint16_t raw_temp; + uint32_t pressure_mPa; + int ret; + + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + + ret = icp10100_get_measures(st, &raw_pressure, &raw_temp); + if (ret) + goto error_release; + + switch (chan->type) { + case IIO_PRESSURE: + pressure_mPa = icp10100_get_pressure(st, raw_pressure, + raw_temp); + /* mPa to kPa */ + *val = pressure_mPa / 1000000; + *val2 = pressure_mPa % 1000000; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_TEMP: + *val = raw_temp; + ret = IIO_VAL_INT; + break; + default: + ret = -EINVAL; + break; + } + +error_release: + iio_device_release_direct_mode(indio_dev); + return ret; +} + +static int icp10100_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct icp10100_state *st = iio_priv(indio_dev); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + case IIO_CHAN_INFO_PROCESSED: + return icp10100_read_raw_measures(indio_dev, chan, val, val2); + case IIO_CHAN_INFO_SCALE: + switch (chan->type) { + case IIO_TEMP: + /* 1000 * 175°C / 65536 in m°C */ + *val = 2; + *val2 = 670288; + return IIO_VAL_INT_PLUS_MICRO; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_OFFSET: + switch (chan->type) { + case IIO_TEMP: + /* 1000 * -45°C in m°C */ + *val = -45000; + return IIO_VAL_INT; + default: + return -EINVAL; + } + break; + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + mutex_lock(&st->lock); + *val = 1 << st->mode; + mutex_unlock(&st->lock); + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static int icp10100_read_avail(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + const int **vals, int *type, int *length, + long mask) +{ + static int oversamplings[] = {1, 2, 4, 8}; + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + *vals = oversamplings; + *type = IIO_VAL_INT; + *length = ARRAY_SIZE(oversamplings); + return IIO_AVAIL_LIST; + default: + return -EINVAL; + } +} + +static int icp10100_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, int val2, long mask) +{ + struct icp10100_state *st = iio_priv(indio_dev); + unsigned int mode; + int ret; + + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + /* oversampling is always positive and a power of 2 */ + if (val <= 0 || !is_power_of_2(val)) + return -EINVAL; + mode = ilog2(val); + if (mode >= ICP10100_MODE_NB) + return -EINVAL; + ret = iio_device_claim_direct_mode(indio_dev); + if (ret) + return ret; + mutex_lock(&st->lock); + st->mode = mode; + mutex_unlock(&st->lock); + iio_device_release_direct_mode(indio_dev); + return 0; + default: + return -EINVAL; + } +} + +static int icp10100_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + switch (mask) { + case IIO_CHAN_INFO_OVERSAMPLING_RATIO: + return IIO_VAL_INT; + default: + return -EINVAL; + } +} + +static const struct iio_info icp10100_info = { + .read_raw = icp10100_read_raw, + .read_avail = icp10100_read_avail, + .write_raw = icp10100_write_raw, + .write_raw_get_fmt = icp10100_write_raw_get_fmt, +}; + +static const struct iio_chan_spec icp10100_channels[] = { + { + .type = IIO_PRESSURE, + .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), + .info_mask_shared_by_all = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, { + .type = IIO_TEMP, + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | + BIT(IIO_CHAN_INFO_SCALE) | + BIT(IIO_CHAN_INFO_OFFSET), + .info_mask_shared_by_all = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + .info_mask_shared_by_all_available = + BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO), + }, +}; + +static int icp10100_enable_regulator(struct icp10100_state *st) +{ + int ret; + + ret = regulator_enable(st->vdd); + if (ret) + return ret; + msleep(100); + + return 0; +} + +static void icp10100_disable_regulator_action(void *data) +{ + struct icp10100_state *st = data; + int ret; + + ret = regulator_disable(st->vdd); + if (ret) + dev_err(&st->client->dev, "error %d disabling vdd\n", ret); +} + +static void icp10100_pm_disable(void *data) +{ + struct device *dev = data; + + pm_runtime_disable(dev); +} + +static int icp10100_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct iio_dev *indio_dev; + struct icp10100_state *st; + int ret; + + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + dev_err(&client->dev, "plain i2c transactions not supported\n"); + return -ENODEV; + } + + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + i2c_set_clientdata(client, indio_dev); + indio_dev->name = client->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = icp10100_channels; + indio_dev->num_channels = ARRAY_SIZE(icp10100_channels); + indio_dev->info = &icp10100_info; + + st = iio_priv(indio_dev); + mutex_init(&st->lock); + st->client = client; + st->mode = ICP10100_MODE_N; + + st->vdd = devm_regulator_get(&client->dev, "vdd"); + if (IS_ERR(st->vdd)) + return PTR_ERR(st->vdd); + + ret = icp10100_enable_regulator(st); + if (ret) + return ret; + + ret = devm_add_action_or_reset(&client->dev, + icp10100_disable_regulator_action, st); + if (ret) + return ret; + + /* has to be done before the first i2c communication */ + crc8_populate_msb(icp10100_crc8_table, ICP10100_CRC8_POLYNOMIAL); + + ret = icp10100_init_chip(st); + if (ret) { + dev_err(&client->dev, "init chip error %d\n", ret); + return ret; + } + + /* enable runtime pm with autosuspend delay of 2s */ + pm_runtime_get_noresume(&client->dev); + pm_runtime_set_active(&client->dev); + pm_runtime_enable(&client->dev); + pm_runtime_set_autosuspend_delay(&client->dev, 2000); + pm_runtime_use_autosuspend(&client->dev); + pm_runtime_put(&client->dev); + ret = devm_add_action_or_reset(&client->dev, icp10100_pm_disable, + &client->dev); + if (ret) + return ret; + + return devm_iio_device_register(&client->dev, indio_dev); +} + +static int icp10100_suspend(struct device *dev) +{ + struct icp10100_state *st = iio_priv(dev_get_drvdata(dev)); + int ret; + + mutex_lock(&st->lock); + ret = regulator_disable(st->vdd); + mutex_unlock(&st->lock); + + return ret; +} + +static int icp10100_resume(struct device *dev) +{ + struct icp10100_state *st = iio_priv(dev_get_drvdata(dev)); + int ret; + + mutex_lock(&st->lock); + + ret = icp10100_enable_regulator(st); + if (ret) + goto out_unlock; + + /* reset chip */ + ret = icp10100_send_cmd(st, &icp10100_cmd_soft_reset, NULL, 0); + +out_unlock: + mutex_unlock(&st->lock); + return ret; +} + +static DEFINE_RUNTIME_DEV_PM_OPS(icp10100_pm, icp10100_suspend, icp10100_resume, + NULL); + +static const struct of_device_id icp10100_of_match[] = { + { + .compatible = "invensense,icp10100", + }, + { } +}; +MODULE_DEVICE_TABLE(of, icp10100_of_match); + +static const struct i2c_device_id icp10100_id[] = { + { "icp10100", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, icp10100_id); + +static struct i2c_driver icp10100_driver = { + .driver = { + .name = "icp10100", + .pm = pm_ptr(&icp10100_pm), + .of_match_table = icp10100_of_match, + }, + .probe = icp10100_probe, + .id_table = icp10100_id, +}; +module_i2c_driver(icp10100_driver); + +MODULE_AUTHOR("InvenSense, Inc."); +MODULE_DESCRIPTION("InvenSense icp10100 driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/pressure/mpl115.c b/drivers/iio/pressure/mpl115.c index ca81a3dc5646..5bf5b9abe6f1 100644 --- a/drivers/iio/pressure/mpl115.c +++ b/drivers/iio/pressure/mpl115.c @@ -160,7 +160,6 @@ int mpl115_probe(struct device *dev, const char *name, indio_dev->info = &mpl115_info; indio_dev->name = name; - indio_dev->dev.parent = dev; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = mpl115_channels; indio_dev->num_channels = ARRAY_SIZE(mpl115_channels); @@ -188,7 +187,7 @@ int mpl115_probe(struct device *dev, const char *name, return devm_iio_device_register(dev, indio_dev); } -EXPORT_SYMBOL_GPL(mpl115_probe); +EXPORT_SYMBOL_NS_GPL(mpl115_probe, IIO_MPL115); MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); MODULE_DESCRIPTION("Freescale MPL115 pressure/temperature driver"); diff --git a/drivers/iio/pressure/mpl115_i2c.c b/drivers/iio/pressure/mpl115_i2c.c index ac1f12bcb65e..099ab1c6832c 100644 --- a/drivers/iio/pressure/mpl115_i2c.c +++ b/drivers/iio/pressure/mpl115_i2c.c @@ -62,3 +62,4 @@ module_i2c_driver(mpl115_i2c_driver); MODULE_AUTHOR("Peter Meerwald <pmeerw@pmeerw.net>"); MODULE_DESCRIPTION("Freescale MPL115A2 pressure/temperature driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_MPL115); diff --git a/drivers/iio/pressure/mpl115_spi.c b/drivers/iio/pressure/mpl115_spi.c index 4d064f98f56a..7feec87e2704 100644 --- a/drivers/iio/pressure/mpl115_spi.c +++ b/drivers/iio/pressure/mpl115_spi.c @@ -101,3 +101,4 @@ module_spi_driver(mpl115_spi_driver); MODULE_AUTHOR("Akinobu Mita <akinobu.mita@gmail.com>"); MODULE_DESCRIPTION("Freescale MPL115A1 pressure/temperature driver"); MODULE_LICENSE("GPL"); +MODULE_IMPORT_NS(IIO_MPL115); diff --git a/drivers/iio/pressure/mpl3115.c b/drivers/iio/pressure/mpl3115.c index d066f3c5a8a6..2f22aba61e4d 100644 --- a/drivers/iio/pressure/mpl3115.c +++ b/drivers/iio/pressure/mpl3115.c @@ -74,7 +74,6 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, int *val, int *val2, long mask) { struct mpl3115_data *data = iio_priv(indio_dev); - __be32 tmp = 0; int ret; switch (mask) { @@ -84,7 +83,9 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, return ret; switch (chan->type) { - case IIO_PRESSURE: /* in 0.25 pascal / LSB */ + case IIO_PRESSURE: { /* in 0.25 pascal / LSB */ + __be32 tmp = 0; + mutex_lock(&data->lock); ret = mpl3115_request(data); if (ret < 0) { @@ -96,10 +97,13 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); if (ret < 0) break; - *val = be32_to_cpu(tmp) >> 12; + *val = be32_to_cpu(tmp) >> chan->scan_type.shift; ret = IIO_VAL_INT; break; - case IIO_TEMP: /* in 0.0625 celsius / LSB */ + } + case IIO_TEMP: { /* in 0.0625 celsius / LSB */ + __be16 tmp; + mutex_lock(&data->lock); ret = mpl3115_request(data); if (ret < 0) { @@ -111,9 +115,11 @@ static int mpl3115_read_raw(struct iio_dev *indio_dev, mutex_unlock(&data->lock); if (ret < 0) break; - *val = sign_extend32(be32_to_cpu(tmp) >> 20, 11); + *val = sign_extend32(be16_to_cpu(tmp) >> chan->scan_type.shift, + chan->scan_type.realbits - 1); ret = IIO_VAL_INT; break; + } default: ret = -EINVAL; break; @@ -144,7 +150,14 @@ static irqreturn_t mpl3115_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct mpl3115_data *data = iio_priv(indio_dev); - u8 buffer[16]; /* 32-bit channel + 16-bit channel + padding + ts */ + /* + * 32-bit channel + 16-bit channel + padding + ts + * Note that it is possible for only one of the first 2 + * channels to be enabled. If that happens, the first element + * of the buffer may be either 16 or 32-bits. As such we cannot + * use a simple structure definition to express this data layout. + */ + u8 buffer[16] __aligned(8); int ret, pos = 0; mutex_lock(&data->lock); @@ -241,7 +254,6 @@ static int mpl3115_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); indio_dev->info = &mpl3115_info; indio_dev->name = id->name; - indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = mpl3115_channels; indio_dev->num_channels = ARRAY_SIZE(mpl3115_channels); @@ -278,18 +290,15 @@ static int mpl3115_standby(struct mpl3115_data *data) data->ctrl_reg1 & ~MPL3115_CTRL_ACTIVE); } -static int mpl3115_remove(struct i2c_client *client) +static void mpl3115_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); mpl3115_standby(iio_priv(indio_dev)); - - return 0; } -#ifdef CONFIG_PM_SLEEP static int mpl3115_suspend(struct device *dev) { return mpl3115_standby(iio_priv(i2c_get_clientdata( @@ -305,11 +314,8 @@ static int mpl3115_resume(struct device *dev) data->ctrl_reg1); } -static SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, mpl3115_resume); -#define MPL3115_PM_OPS (&mpl3115_pm_ops) -#else -#define MPL3115_PM_OPS NULL -#endif +static DEFINE_SIMPLE_DEV_PM_OPS(mpl3115_pm_ops, mpl3115_suspend, + mpl3115_resume); static const struct i2c_device_id mpl3115_id[] = { { "mpl3115", 0 }, @@ -327,7 +333,7 @@ static struct i2c_driver mpl3115_driver = { .driver = { .name = "mpl3115", .of_match_table = mpl3115_of_match, - .pm = MPL3115_PM_OPS, + .pm = pm_sleep_ptr(&mpl3115_pm_ops), }, .probe = mpl3115_probe, .remove = mpl3115_remove, diff --git a/drivers/iio/pressure/ms5611.h b/drivers/iio/pressure/ms5611.h index bc06271fa38b..cbc9349c342a 100644 --- a/drivers/iio/pressure/ms5611.h +++ b/drivers/iio/pressure/ms5611.h @@ -50,9 +50,9 @@ struct ms5611_state { const struct ms5611_osr *pressure_osr; const struct ms5611_osr *temp_osr; - int (*reset)(struct device *dev); - int (*read_prom_word)(struct device *dev, int index, u16 *word); - int (*read_adc_temp_and_pressure)(struct device *dev, + int (*reset)(struct ms5611_state *st); + int (*read_prom_word)(struct ms5611_state *st, int index, u16 *word); + int (*read_adc_temp_and_pressure)(struct ms5611_state *st, s32 *temp, s32 *pressure); struct ms5611_chip_info *chip_info; @@ -61,6 +61,6 @@ struct ms5611_state { int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, const char *name, int type); -int ms5611_remove(struct iio_dev *indio_dev); +void ms5611_remove(struct iio_dev *indio_dev); #endif /* _MS5611_H */ diff --git a/drivers/iio/pressure/ms5611_core.c b/drivers/iio/pressure/ms5611_core.c index 2f598ad91621..717521de66c4 100644 --- a/drivers/iio/pressure/ms5611_core.c +++ b/drivers/iio/pressure/ms5611_core.c @@ -85,8 +85,7 @@ static int ms5611_read_prom(struct iio_dev *indio_dev) struct ms5611_state *st = iio_priv(indio_dev); for (i = 0; i < MS5611_PROM_WORDS_NB; i++) { - ret = st->read_prom_word(&indio_dev->dev, - i, &st->chip_info->prom[i]); + ret = st->read_prom_word(st, i, &st->chip_info->prom[i]); if (ret < 0) { dev_err(&indio_dev->dev, "failed to read prom at %d\n", i); @@ -108,7 +107,7 @@ static int ms5611_read_temp_and_pressure(struct iio_dev *indio_dev, int ret; struct ms5611_state *st = iio_priv(indio_dev); - ret = st->read_adc_temp_and_pressure(&indio_dev->dev, temp, pressure); + ret = st->read_adc_temp_and_pressure(st, temp, pressure); if (ret < 0) { dev_err(&indio_dev->dev, "failed to read temperature and pressure\n"); @@ -196,7 +195,7 @@ static int ms5611_reset(struct iio_dev *indio_dev) int ret; struct ms5611_state *st = iio_priv(indio_dev); - ret = st->reset(&indio_dev->dev); + ret = st->reset(st); if (ret < 0) { dev_err(&indio_dev->dev, "failed to reset device\n"); return ret; @@ -212,16 +211,21 @@ static irqreturn_t ms5611_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ms5611_state *st = iio_priv(indio_dev); - s32 buf[4]; /* s32 (pressure) + s32 (temp) + 2 * s32 (timestamp) */ + /* Ensure buffer elements are naturally aligned */ + struct { + s32 channels[2]; + s64 ts __aligned(8); + } scan; int ret; mutex_lock(&st->lock); - ret = ms5611_read_temp_and_pressure(indio_dev, &buf[1], &buf[0]); + ret = ms5611_read_temp_and_pressure(indio_dev, &scan.channels[1], + &scan.channels[0]); mutex_unlock(&st->lock); if (ret < 0) goto err; - iio_push_to_buffers_with_timestamp(indio_dev, buf, + iio_push_to_buffers_with_timestamp(indio_dev, &scan, iio_get_time_ns(indio_dev)); err: @@ -435,7 +439,6 @@ int ms5611_probe(struct iio_dev *indio_dev, struct device *dev, st->pressure_osr = &ms5611_avail_pressure_osr[ARRAY_SIZE(ms5611_avail_pressure_osr) - 1]; - indio_dev->dev.parent = dev; indio_dev->name = name; indio_dev->info = &ms5611_info; indio_dev->channels = ms5611_channels; @@ -468,17 +471,15 @@ err_fini: ms5611_fini(indio_dev); return ret; } -EXPORT_SYMBOL(ms5611_probe); +EXPORT_SYMBOL_NS(ms5611_probe, IIO_MS5611); -int ms5611_remove(struct iio_dev *indio_dev) +void ms5611_remove(struct iio_dev *indio_dev) { iio_device_unregister(indio_dev); iio_triggered_buffer_cleanup(indio_dev); ms5611_fini(indio_dev); - - return 0; } -EXPORT_SYMBOL(ms5611_remove); +EXPORT_SYMBOL_NS(ms5611_remove, IIO_MS5611); MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("MS5611 core driver"); diff --git a/drivers/iio/pressure/ms5611_i2c.c b/drivers/iio/pressure/ms5611_i2c.c index 8089c59adce5..b681a4183909 100644 --- a/drivers/iio/pressure/ms5611_i2c.c +++ b/drivers/iio/pressure/ms5611_i2c.c @@ -14,21 +14,21 @@ #include <linux/delay.h> #include <linux/i2c.h> #include <linux/module.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> + +#include <asm/unaligned.h> #include "ms5611.h" -static int ms5611_i2c_reset(struct device *dev) +static int ms5611_i2c_reset(struct ms5611_state *st) { - struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); - return i2c_smbus_write_byte(st->client, MS5611_RESET); } -static int ms5611_i2c_read_prom_word(struct device *dev, int index, u16 *word) +static int ms5611_i2c_read_prom_word(struct ms5611_state *st, int index, + u16 *word) { int ret; - struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); ret = i2c_smbus_read_word_swapped(st->client, MS5611_READ_PROM_WORD + (index << 1)); @@ -50,16 +50,15 @@ static int ms5611_i2c_read_adc(struct ms5611_state *st, s32 *val) if (ret < 0) return ret; - *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + *val = get_unaligned_be24(&buf[0]); return 0; } -static int ms5611_i2c_read_adc_temp_and_pressure(struct device *dev, +static int ms5611_i2c_read_adc_temp_and_pressure(struct ms5611_state *st, s32 *temp, s32 *pressure) { int ret; - struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); const struct ms5611_osr *osr = st->temp_osr; ret = i2c_smbus_write_byte(st->client, osr->cmd); @@ -106,19 +105,17 @@ static int ms5611_i2c_probe(struct i2c_client *client, return ms5611_probe(indio_dev, &client->dev, id->name, id->driver_data); } -static int ms5611_i2c_remove(struct i2c_client *client) +static void ms5611_i2c_remove(struct i2c_client *client) { - return ms5611_remove(i2c_get_clientdata(client)); + ms5611_remove(i2c_get_clientdata(client)); } -#if defined(CONFIG_OF) static const struct of_device_id ms5611_i2c_matches[] = { { .compatible = "meas,ms5611" }, { .compatible = "meas,ms5607" }, { } }; MODULE_DEVICE_TABLE(of, ms5611_i2c_matches); -#endif static const struct i2c_device_id ms5611_id[] = { { "ms5611", MS5611 }, @@ -130,7 +127,7 @@ MODULE_DEVICE_TABLE(i2c, ms5611_id); static struct i2c_driver ms5611_driver = { .driver = { .name = "ms5611", - .of_match_table = of_match_ptr(ms5611_i2c_matches) + .of_match_table = ms5611_i2c_matches, }, .id_table = ms5611_id, .probe = ms5611_i2c_probe, @@ -141,3 +138,4 @@ module_i2c_driver(ms5611_driver); MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("MS5611 i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MS5611); diff --git a/drivers/iio/pressure/ms5611_spi.c b/drivers/iio/pressure/ms5611_spi.c index b463eaa799ab..432e912096f4 100644 --- a/drivers/iio/pressure/ms5611_spi.c +++ b/drivers/iio/pressure/ms5611_spi.c @@ -9,22 +9,23 @@ #include <linux/delay.h> #include <linux/module.h> #include <linux/spi/spi.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> + +#include <asm/unaligned.h> #include "ms5611.h" -static int ms5611_spi_reset(struct device *dev) +static int ms5611_spi_reset(struct ms5611_state *st) { u8 cmd = MS5611_RESET; - struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); return spi_write_then_read(st->client, &cmd, 1, NULL, 0); } -static int ms5611_spi_read_prom_word(struct device *dev, int index, u16 *word) +static int ms5611_spi_read_prom_word(struct ms5611_state *st, int index, + u16 *word) { int ret; - struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); ret = spi_w8r16be(st->client, MS5611_READ_PROM_WORD + (index << 1)); if (ret < 0) @@ -35,26 +36,24 @@ static int ms5611_spi_read_prom_word(struct device *dev, int index, u16 *word) return 0; } -static int ms5611_spi_read_adc(struct device *dev, s32 *val) +static int ms5611_spi_read_adc(struct ms5611_state *st, s32 *val) { int ret; u8 buf[3] = { MS5611_READ_ADC }; - struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); ret = spi_write_then_read(st->client, buf, 1, buf, 3); if (ret < 0) return ret; - *val = (buf[0] << 16) | (buf[1] << 8) | buf[2]; + *val = get_unaligned_be24(&buf[0]); return 0; } -static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev, +static int ms5611_spi_read_adc_temp_and_pressure(struct ms5611_state *st, s32 *temp, s32 *pressure) { int ret; - struct ms5611_state *st = iio_priv(dev_to_iio_dev(dev)); const struct ms5611_osr *osr = st->temp_osr; /* @@ -66,7 +65,7 @@ static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev, return ret; usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL)); - ret = ms5611_spi_read_adc(dev, temp); + ret = ms5611_spi_read_adc(st, temp); if (ret < 0) return ret; @@ -76,7 +75,7 @@ static int ms5611_spi_read_adc_temp_and_pressure(struct device *dev, return ret; usleep_range(osr->conv_usec, osr->conv_usec + (osr->conv_usec / 10UL)); - return ms5611_spi_read_adc(dev, pressure); + return ms5611_spi_read_adc(st, pressure); } static int ms5611_spi_probe(struct spi_device *spi) @@ -108,19 +107,17 @@ static int ms5611_spi_probe(struct spi_device *spi) spi_get_device_id(spi)->driver_data); } -static int ms5611_spi_remove(struct spi_device *spi) +static void ms5611_spi_remove(struct spi_device *spi) { - return ms5611_remove(spi_get_drvdata(spi)); + ms5611_remove(spi_get_drvdata(spi)); } -#if defined(CONFIG_OF) static const struct of_device_id ms5611_spi_matches[] = { { .compatible = "meas,ms5611" }, { .compatible = "meas,ms5607" }, { } }; MODULE_DEVICE_TABLE(of, ms5611_spi_matches); -#endif static const struct spi_device_id ms5611_id[] = { { "ms5611", MS5611 }, @@ -132,7 +129,7 @@ MODULE_DEVICE_TABLE(spi, ms5611_id); static struct spi_driver ms5611_driver = { .driver = { .name = "ms5611", - .of_match_table = of_match_ptr(ms5611_spi_matches) + .of_match_table = ms5611_spi_matches }, .id_table = ms5611_id, .probe = ms5611_spi_probe, @@ -143,3 +140,4 @@ module_spi_driver(ms5611_driver); MODULE_AUTHOR("Tomasz Duszynski <tduszyns@gmail.com>"); MODULE_DESCRIPTION("MS5611 spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MS5611); diff --git a/drivers/iio/pressure/ms5637.c b/drivers/iio/pressure/ms5637.c index f49c7003c72a..70c70019142a 100644 --- a/drivers/iio/pressure/ms5637.c +++ b/drivers/iio/pressure/ms5637.c @@ -22,6 +22,7 @@ #include <linux/kernel.h> #include <linux/stat.h> #include <linux/module.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> @@ -29,9 +30,25 @@ #include "../common/ms_sensors/ms_sensors_i2c.h" +struct ms_tp_data { + const char *name; + const struct ms_tp_hw_data *hw; +}; + static const int ms5637_samp_freq[6] = { 960, 480, 240, 120, 60, 30 }; -/* String copy of the above const for readability purpose */ -static const char ms5637_show_samp_freq[] = "960 480 240 120 60 30"; + +static ssize_t ms5637_show_samp_freq(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ms_tp_dev *dev_data = iio_priv(indio_dev); + int i, len = 0; + + for (i = 0; i <= dev_data->hw->max_res_index; i++) + len += sysfs_emit_at(buf, len, "%u ", ms5637_samp_freq[i]); + sysfs_emit_at(buf, len - 1, "\n"); + + return len; +} static int ms5637_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *channel, int *val, @@ -108,10 +125,10 @@ static const struct iio_chan_spec ms5637_channels[] = { } }; -static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq); +static IIO_DEV_ATTR_SAMP_FREQ_AVAIL(ms5637_show_samp_freq); static struct attribute *ms5637_attributes[] = { - &iio_const_attr_sampling_frequency_available.dev_attr.attr, + &iio_dev_attr_sampling_frequency_available.dev_attr.attr, NULL, }; @@ -128,6 +145,7 @@ static const struct iio_info ms5637_info = { static int ms5637_probe(struct i2c_client *client, const struct i2c_device_id *id) { + const struct ms_tp_data *data; struct ms_tp_dev *dev_data; struct iio_dev *indio_dev; int ret; @@ -141,18 +159,25 @@ static int ms5637_probe(struct i2c_client *client, return -EOPNOTSUPP; } + if (id) + data = (const struct ms_tp_data *)id->driver_data; + else + data = device_get_match_data(&client->dev); + if (!data) + return -EINVAL; + indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*dev_data)); if (!indio_dev) return -ENOMEM; dev_data = iio_priv(indio_dev); dev_data->client = client; - dev_data->res_index = 5; + dev_data->res_index = data->hw->max_res_index; + dev_data->hw = data->hw; mutex_init(&dev_data->lock); indio_dev->info = &ms5637_info; - indio_dev->name = id->name; - indio_dev->dev.parent = &client->dev; + indio_dev->name = data->name; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = ms5637_channels; indio_dev->num_channels = ARRAY_SIZE(ms5637_channels); @@ -170,20 +195,44 @@ static int ms5637_probe(struct i2c_client *client, return devm_iio_device_register(&client->dev, indio_dev); } +static const struct ms_tp_hw_data ms5637_hw_data = { + .prom_len = 7, + .max_res_index = 5 +}; + +static const struct ms_tp_hw_data ms5803_hw_data = { + .prom_len = 8, + .max_res_index = 4 +}; + +static const struct ms_tp_data ms5637_data = { .name = "ms5637", .hw = &ms5637_hw_data }; + +static const struct ms_tp_data ms5803_data = { .name = "ms5803", .hw = &ms5803_hw_data }; + +static const struct ms_tp_data ms5805_data = { .name = "ms5805", .hw = &ms5637_hw_data }; + +static const struct ms_tp_data ms5837_data = { .name = "ms5837", .hw = &ms5637_hw_data }; + +static const struct ms_tp_data ms8607_data = { + .name = "ms8607-temppressure", + .hw = &ms5637_hw_data, +}; + static const struct i2c_device_id ms5637_id[] = { - {"ms5637", 0}, - {"ms5805", 0}, - {"ms5837", 0}, - {"ms8607-temppressure", 0}, + {"ms5637", (kernel_ulong_t)&ms5637_data }, + {"ms5805", (kernel_ulong_t)&ms5805_data }, + {"ms5837", (kernel_ulong_t)&ms5837_data }, + {"ms8607-temppressure", (kernel_ulong_t)&ms8607_data }, {} }; MODULE_DEVICE_TABLE(i2c, ms5637_id); static const struct of_device_id ms5637_of_match[] = { - { .compatible = "meas,ms5637", }, - { .compatible = "meas,ms5805", }, - { .compatible = "meas,ms5837", }, - { .compatible = "meas,ms8607-temppressure", }, + { .compatible = "meas,ms5637", .data = &ms5637_data }, + { .compatible = "meas,ms5803", .data = &ms5803_data }, + { .compatible = "meas,ms5805", .data = &ms5805_data }, + { .compatible = "meas,ms5837", .data = &ms5837_data }, + { .compatible = "meas,ms8607-temppressure", .data = &ms8607_data }, { }, }; MODULE_DEVICE_TABLE(of, ms5637_of_match); @@ -193,7 +242,7 @@ static struct i2c_driver ms5637_driver = { .id_table = ms5637_id, .driver = { .name = "ms5637", - .of_match_table = of_match_ptr(ms5637_of_match), + .of_match_table = ms5637_of_match, }, }; @@ -203,3 +252,4 @@ MODULE_DESCRIPTION("Measurement-Specialties ms5637 temperature & pressure driver MODULE_AUTHOR("William Markezana <william.markezana@meas-spec.com>"); MODULE_AUTHOR("Ludovic Tancerel <ludovic.tancerel@maplehightech.com>"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_MEAS_SPEC_SENSORS); diff --git a/drivers/iio/pressure/st_pressure.h b/drivers/iio/pressure/st_pressure.h index 5c746ff6087e..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 @@ -41,13 +43,8 @@ static __maybe_unused const struct st_sensors_platform_data default_press_pdata .drdy_int_pin = 1, }; -const struct st_sensor_settings *st_press_get_settings(const char *name); -int st_press_common_probe(struct iio_dev *indio_dev); -void st_press_common_remove(struct iio_dev *indio_dev); - #ifdef CONFIG_IIO_BUFFER int st_press_allocate_ring(struct iio_dev *indio_dev); -void st_press_deallocate_ring(struct iio_dev *indio_dev); int st_press_trig_set_state(struct iio_trigger *trig, bool state); #define ST_PRESS_TRIGGER_SET_STATE (&st_press_trig_set_state) #else /* CONFIG_IIO_BUFFER */ @@ -55,10 +52,6 @@ static inline int st_press_allocate_ring(struct iio_dev *indio_dev) { return 0; } - -static inline void st_press_deallocate_ring(struct iio_dev *indio_dev) -{ -} #define ST_PRESS_TRIGGER_SET_STATE NULL #endif /* CONFIG_IIO_BUFFER */ diff --git a/drivers/iio/pressure/st_pressure_buffer.c b/drivers/iio/pressure/st_pressure_buffer.c index 418dbf9e6e1e..0dbf357c2c22 100644 --- a/drivers/iio/pressure/st_pressure_buffer.c +++ b/drivers/iio/pressure/st_pressure_buffer.c @@ -7,16 +7,10 @@ * Denis Ciocca <denis.ciocca@st.com> */ -#include <linux/module.h> #include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/stat.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/delay.h> #include <linux/iio/iio.h> #include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> +#include <linux/iio/trigger.h> #include <linux/iio/triggered_buffer.h> #include <linux/iio/common/st_sensors.h> @@ -31,34 +25,12 @@ int st_press_trig_set_state(struct iio_trigger *trig, bool state) static int st_press_buffer_postenable(struct iio_dev *indio_dev) { - int err; - - err = iio_triggered_buffer_postenable(indio_dev); - if (err < 0) - return err; - - err = st_sensors_set_enable(indio_dev, true); - if (err < 0) - goto st_press_buffer_predisable; - - return 0; - -st_press_buffer_predisable: - iio_triggered_buffer_predisable(indio_dev); - return err; + return st_sensors_set_enable(indio_dev, true); } static int st_press_buffer_predisable(struct iio_dev *indio_dev) { - int err, err2; - - err = st_sensors_set_enable(indio_dev, false); - - err2 = iio_triggered_buffer_predisable(indio_dev); - if (!err) - err = err2; - - return err; + return st_sensors_set_enable(indio_dev, false); } static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { @@ -68,15 +40,6 @@ static const struct iio_buffer_setup_ops st_press_buffer_setup_ops = { int st_press_allocate_ring(struct iio_dev *indio_dev) { - return iio_triggered_buffer_setup(indio_dev, NULL, - &st_sensors_trigger_handler, &st_press_buffer_setup_ops); + return devm_iio_triggered_buffer_setup(indio_dev->dev.parent, indio_dev, + NULL, &st_sensors_trigger_handler, &st_press_buffer_setup_ops); } - -void st_press_deallocate_ring(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} - -MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); -MODULE_DESCRIPTION("STMicroelectronics pressures buffer"); -MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/pressure/st_pressure_core.c b/drivers/iio/pressure/st_pressure_core.c index bd972cec4830..80176e3083af 100644 --- a/drivers/iio/pressure/st_pressure_core.c +++ b/drivers/iio/pressure/st_pressure_core.c @@ -9,17 +9,11 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> -#include <linux/errno.h> -#include <linux/types.h> -#include <linux/interrupt.h> -#include <linux/i2c.h> -#include <linux/irq.h> -#include <linux/delay.h> +#include <linux/mutex.h> +#include <linux/sysfs.h> #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> #include <linux/iio/trigger.h> -#include <linux/iio/buffer.h> #include <asm/unaligned.h> #include <linux/iio/common/st_sensors.h> @@ -558,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, @@ -566,16 +630,12 @@ static int st_press_write_raw(struct iio_dev *indio_dev, int val2, long mask) { - int err; - switch (mask) { case IIO_CHAN_INFO_SAMP_FREQ: if (val2) return -EINVAL; - mutex_lock(&indio_dev->mlock); - err = st_sensors_set_odr(indio_dev, val); - mutex_unlock(&indio_dev->mlock); - return err; + + return st_sensors_set_odr(indio_dev, val); default: return -EINVAL; } @@ -678,25 +738,21 @@ const struct st_sensor_settings *st_press_get_settings(const char *name) return &st_press_sensors_settings[index]; } -EXPORT_SYMBOL(st_press_get_settings); +EXPORT_SYMBOL_NS(st_press_get_settings, IIO_ST_SENSORS); int st_press_common_probe(struct iio_dev *indio_dev) { struct st_sensor_data *press_data = iio_priv(indio_dev); - struct st_sensors_platform_data *pdata = - (struct st_sensors_platform_data *)press_data->dev->platform_data; + struct device *parent = indio_dev->dev.parent; + struct st_sensors_platform_data *pdata = dev_get_platdata(parent); int err; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->info = &press_info; - err = st_sensors_power_enable(indio_dev); - if (err) - return err; - err = st_sensors_verify_id(indio_dev); if (err < 0) - goto st_press_power_off; + return err; /* * Skip timestamping channel while declaring available channels to @@ -708,9 +764,7 @@ int st_press_common_probe(struct iio_dev *indio_dev) indio_dev->channels = press_data->sensor_settings->ch; indio_dev->num_channels = press_data->sensor_settings->num_ch; - press_data->current_fullscale = - (struct st_sensor_fullscale_avl *) - &press_data->sensor_settings->fs.fs_avl[0]; + press_data->current_fullscale = &press_data->sensor_settings->fs.fs_avl[0]; press_data->odr = press_data->sensor_settings->odr.odr_avl[0].hz; @@ -721,54 +775,24 @@ int st_press_common_probe(struct iio_dev *indio_dev) err = st_sensors_init_sensor(indio_dev, pdata); if (err < 0) - goto st_press_power_off; + return err; err = st_press_allocate_ring(indio_dev); if (err < 0) - goto st_press_power_off; + return err; if (press_data->irq > 0) { err = st_sensors_allocate_trigger(indio_dev, ST_PRESS_TRIGGER_OPS); if (err < 0) - goto st_press_probe_trigger_error; + return err; } - err = iio_device_register(indio_dev); - if (err) - goto st_press_device_register_error; - - dev_info(&indio_dev->dev, "registered pressure sensor %s\n", - indio_dev->name); - - return err; - -st_press_device_register_error: - if (press_data->irq > 0) - st_sensors_deallocate_trigger(indio_dev); -st_press_probe_trigger_error: - st_press_deallocate_ring(indio_dev); -st_press_power_off: - st_sensors_power_disable(indio_dev); - - return err; -} -EXPORT_SYMBOL(st_press_common_probe); - -void st_press_common_remove(struct iio_dev *indio_dev) -{ - struct st_sensor_data *press_data = iio_priv(indio_dev); - - st_sensors_power_disable(indio_dev); - - iio_device_unregister(indio_dev); - if (press_data->irq > 0) - st_sensors_deallocate_trigger(indio_dev); - - st_press_deallocate_ring(indio_dev); + return devm_iio_device_register(parent, indio_dev); } -EXPORT_SYMBOL(st_press_common_remove); +EXPORT_SYMBOL_NS(st_press_common_probe, IIO_ST_SENSORS); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics pressures driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/pressure/st_pressure_i2c.c b/drivers/iio/pressure/st_pressure_i2c.c index 09c6903f99b8..58fede861891 100644 --- a/drivers/iio/pressure/st_pressure_i2c.c +++ b/drivers/iio/pressure/st_pressure_i2c.c @@ -7,9 +7,10 @@ * Denis Ciocca <denis.ciocca@st.com> */ +#include <linux/acpi.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/i2c.h> #include <linux/iio/iio.h> @@ -46,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); @@ -66,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); @@ -98,18 +104,11 @@ static int st_press_i2c_probe(struct i2c_client *client, if (ret < 0) return ret; - ret = st_press_common_probe(indio_dev); - if (ret < 0) + ret = st_sensors_power_enable(indio_dev); + if (ret) return ret; - return 0; -} - -static int st_press_i2c_remove(struct i2c_client *client) -{ - st_press_common_remove(i2c_get_clientdata(client)); - - return 0; + return st_press_common_probe(indio_dev); } static struct i2c_driver st_press_driver = { @@ -119,7 +118,6 @@ static struct i2c_driver st_press_driver = { .acpi_match_table = ACPI_PTR(st_press_acpi_match), }, .probe = st_press_i2c_probe, - .remove = st_press_i2c_remove, .id_table = st_press_id_table, }; module_i2c_driver(st_press_driver); @@ -127,3 +125,4 @@ module_i2c_driver(st_press_driver); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics pressures i2c driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/pressure/st_pressure_spi.c b/drivers/iio/pressure/st_pressure_spi.c index b5ee3ec2764f..25cca5ad7c55 100644 --- a/drivers/iio/pressure/st_pressure_spi.c +++ b/drivers/iio/pressure/st_pressure_spi.c @@ -9,7 +9,7 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/slab.h> +#include <linux/mod_devicetable.h> #include <linux/spi/spi.h> #include <linux/iio/iio.h> @@ -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); @@ -82,18 +86,11 @@ static int st_press_spi_probe(struct spi_device *spi) if (err < 0) return err; - err = st_press_common_probe(indio_dev); - if (err < 0) + err = st_sensors_power_enable(indio_dev); + if (err) return err; - return 0; -} - -static int st_press_spi_remove(struct spi_device *spi) -{ - st_press_common_remove(spi_get_drvdata(spi)); - - return 0; + return st_press_common_probe(indio_dev); } static const struct spi_device_id st_press_id_table[] = { @@ -104,6 +101,11 @@ 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" }, + { "lps22hb-press" }, {}, }; MODULE_DEVICE_TABLE(spi, st_press_id_table); @@ -114,7 +116,6 @@ static struct spi_driver st_press_driver = { .of_match_table = st_press_of_match, }, .probe = st_press_spi_probe, - .remove = st_press_spi_remove, .id_table = st_press_id_table, }; module_spi_driver(st_press_driver); @@ -122,3 +123,4 @@ module_spi_driver(st_press_driver); MODULE_AUTHOR("Denis Ciocca <denis.ciocca@st.com>"); MODULE_DESCRIPTION("STMicroelectronics pressures spi driver"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ST_SENSORS); diff --git a/drivers/iio/pressure/t5403.c b/drivers/iio/pressure/t5403.c index 22abd28071b7..685fcf65334f 100644 --- a/drivers/iio/pressure/t5403.c +++ b/drivers/iio/pressure/t5403.c @@ -236,7 +236,6 @@ static int t5403_probe(struct i2c_client *client, i2c_set_clientdata(client, indio_dev); indio_dev->info = &t5403_info; indio_dev->name = id->name; - indio_dev->dev.parent = &client->dev; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = t5403_channels; indio_dev->num_channels = ARRAY_SIZE(t5403_channels); diff --git a/drivers/iio/pressure/zpa2326.c b/drivers/iio/pressure/zpa2326.c index 99dfe33ee402..67119a9b95fc 100644 --- a/drivers/iio/pressure/zpa2326.c +++ b/drivers/iio/pressure/zpa2326.c @@ -64,6 +64,7 @@ #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <asm/unaligned.h> #include "zpa2326.h" /* 200 ms should be enough for the longest conversion time in one-shot mode. */ @@ -102,7 +103,7 @@ static const struct zpa2326_frequency *zpa2326_highest_frequency(void) } /** - * struct zpa_private - Per-device internal private state + * struct zpa2326_private - Per-device internal private state * @timestamp: Buffered samples ready datum. * @regmap: Underlying I2C / SPI bus adapter used to abstract slave register * accesses. @@ -161,7 +162,7 @@ bool zpa2326_isreg_writeable(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_GPL(zpa2326_isreg_writeable); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_writeable, IIO_ZPA2326); bool zpa2326_isreg_readable(struct device *dev, unsigned int reg) { @@ -190,7 +191,7 @@ bool zpa2326_isreg_readable(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_GPL(zpa2326_isreg_readable); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_readable, IIO_ZPA2326); bool zpa2326_isreg_precious(struct device *dev, unsigned int reg) { @@ -203,7 +204,7 @@ bool zpa2326_isreg_precious(struct device *dev, unsigned int reg) return false; } } -EXPORT_SYMBOL_GPL(zpa2326_isreg_precious); +EXPORT_SYMBOL_NS_GPL(zpa2326_isreg_precious, IIO_ZPA2326); /** * zpa2326_enable_device() - Enable device, i.e. get out of low power mode. @@ -648,7 +649,7 @@ const struct dev_pm_ops zpa2326_pm_ops = { SET_RUNTIME_PM_OPS(zpa2326_runtime_suspend, zpa2326_runtime_resume, NULL) }; -EXPORT_SYMBOL_GPL(zpa2326_pm_ops); +EXPORT_SYMBOL_NS_GPL(zpa2326_pm_ops, IIO_ZPA2326); /** * zpa2326_resume() - Request the PM layer to power supply the device. @@ -664,8 +665,10 @@ static int zpa2326_resume(const struct iio_dev *indio_dev) int err; err = pm_runtime_get_sync(indio_dev->dev.parent); - if (err < 0) + if (err < 0) { + pm_runtime_put(indio_dev->dev.parent); return err; + } if (err > 0) { /* @@ -1005,22 +1008,20 @@ static int zpa2326_fetch_raw_sample(const struct iio_dev *indio_dev, struct regmap *regs = ((struct zpa2326_private *) iio_priv(indio_dev))->regmap; int err; + u8 v[3]; switch (type) { case IIO_PRESSURE: zpa2326_dbg(indio_dev, "fetching raw pressure sample"); - err = regmap_bulk_read(regs, ZPA2326_PRESS_OUT_XL_REG, value, - 3); + err = regmap_bulk_read(regs, ZPA2326_PRESS_OUT_XL_REG, v, sizeof(v)); if (err) { zpa2326_warn(indio_dev, "failed to fetch pressure (%d)", err); return err; } - /* Pressure is a 24 bits wide little-endian unsigned int. */ - *value = (((u8 *)value)[2] << 16) | (((u8 *)value)[1] << 8) | - ((u8 *)value)[0]; + *value = get_unaligned_le24(&v[0]); return IIO_VAL_INT; @@ -1243,19 +1244,17 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev) const struct zpa2326_private *priv = iio_priv(indio_dev); int err; - /* Plug our own trigger event handler. */ - err = iio_triggered_buffer_postenable(indio_dev); - if (err) - goto err; - if (!priv->waken) { /* * We were already power supplied. Just clear hardware FIFO to * get rid of samples acquired during previous rounds (if any). */ err = zpa2326_clear_fifo(indio_dev, 0); - if (err) - goto err_buffer_predisable; + if (err) { + zpa2326_err(indio_dev, + "failed to enable buffering (%d)", err); + return err; + } } if (!iio_trigger_using_own(indio_dev) && priv->waken) { @@ -1264,18 +1263,14 @@ static int zpa2326_postenable_buffer(struct iio_dev *indio_dev) * powered up: reconfigure one-shot mode. */ err = zpa2326_config_oneshot(indio_dev, priv->irq); - if (err) - goto err_buffer_predisable; + if (err) { + zpa2326_err(indio_dev, + "failed to enable buffering (%d)", err); + return err; + } } return 0; - -err_buffer_predisable: - iio_triggered_buffer_predisable(indio_dev); -err: - zpa2326_err(indio_dev, "failed to enable buffering (%d)", err); - - return err; } static int zpa2326_postdisable_buffer(struct iio_dev *indio_dev) @@ -1288,7 +1283,6 @@ static int zpa2326_postdisable_buffer(struct iio_dev *indio_dev) static const struct iio_buffer_setup_ops zpa2326_buffer_setup_ops = { .preenable = zpa2326_preenable_buffer, .postenable = zpa2326_postenable_buffer, - .predisable = iio_triggered_buffer_predisable, .postdisable = zpa2326_postdisable_buffer }; @@ -1388,7 +1382,7 @@ static const struct iio_trigger_ops zpa2326_trigger_ops = { }; /** - * zpa2326_init_trigger() - Create an interrupt driven / hardware trigger + * zpa2326_init_managed_trigger() - Create interrupt driven / hardware trigger * allowing to notify external devices a new sample is * ready. * @parent: Hardware sampling device @indio_dev is a child of. @@ -1414,12 +1408,12 @@ static int zpa2326_init_managed_trigger(struct device *parent, return 0; trigger = devm_iio_trigger_alloc(parent, "%s-dev%d", - indio_dev->name, indio_dev->id); + indio_dev->name, + iio_device_id(indio_dev)); if (!trigger) return -ENOMEM; /* Basic setup. */ - trigger->dev.parent = parent; trigger->ops = &zpa2326_trigger_ops; private->trigger = trigger; @@ -1602,7 +1596,6 @@ static struct iio_dev *zpa2326_create_managed_iiodev(struct device *device, /* Setup for userspace synchronous on demand sampling. */ indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->dev.parent = device; indio_dev->channels = zpa2326_channels; indio_dev->num_channels = ARRAY_SIZE(zpa2326_channels); indio_dev->name = name; @@ -1705,7 +1698,7 @@ poweroff: return err; } -EXPORT_SYMBOL_GPL(zpa2326_probe); +EXPORT_SYMBOL_NS_GPL(zpa2326_probe, IIO_ZPA2326); void zpa2326_remove(const struct device *parent) { @@ -1716,7 +1709,7 @@ void zpa2326_remove(const struct device *parent) zpa2326_sleep(indio_dev); zpa2326_power_off(indio_dev, iio_priv(indio_dev)); } -EXPORT_SYMBOL_GPL(zpa2326_remove); +EXPORT_SYMBOL_NS_GPL(zpa2326_remove, IIO_ZPA2326); MODULE_AUTHOR("Gregor Boirie <gregor.boirie@parrot.com>"); MODULE_DESCRIPTION("Core driver for Murata ZPA2326 pressure sensor"); diff --git a/drivers/iio/pressure/zpa2326_i2c.c b/drivers/iio/pressure/zpa2326_i2c.c index 1a65791ba279..f26dd8cbb387 100644 --- a/drivers/iio/pressure/zpa2326_i2c.c +++ b/drivers/iio/pressure/zpa2326_i2c.c @@ -10,7 +10,7 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/i2c.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> #include "zpa2326.h" /* @@ -53,11 +53,9 @@ static int zpa2326_probe_i2c(struct i2c_client *client, zpa2326_i2c_hwid(client), regmap); } -static int zpa2326_remove_i2c(struct i2c_client *client) +static void zpa2326_remove_i2c(struct i2c_client *client) { zpa2326_remove(&client->dev); - - return 0; } static const struct i2c_device_id zpa2326_i2c_ids[] = { @@ -66,18 +64,16 @@ static const struct i2c_device_id zpa2326_i2c_ids[] = { }; MODULE_DEVICE_TABLE(i2c, zpa2326_i2c_ids); -#if defined(CONFIG_OF) static const struct of_device_id zpa2326_i2c_matches[] = { { .compatible = "murata,zpa2326" }, { } }; MODULE_DEVICE_TABLE(of, zpa2326_i2c_matches); -#endif static struct i2c_driver zpa2326_i2c_driver = { .driver = { .name = "zpa2326-i2c", - .of_match_table = of_match_ptr(zpa2326_i2c_matches), + .of_match_table = zpa2326_i2c_matches, .pm = ZPA2326_PM_OPS, }, .probe = zpa2326_probe_i2c, @@ -89,3 +85,4 @@ module_i2c_driver(zpa2326_i2c_driver); MODULE_AUTHOR("Gregor Boirie <gregor.boirie@parrot.com>"); MODULE_DESCRIPTION("I2C driver for Murata ZPA2326 pressure sensor"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ZPA2326); diff --git a/drivers/iio/pressure/zpa2326_spi.c b/drivers/iio/pressure/zpa2326_spi.c index f37a4c738c75..9c1bcb82d360 100644 --- a/drivers/iio/pressure/zpa2326_spi.c +++ b/drivers/iio/pressure/zpa2326_spi.c @@ -10,7 +10,7 @@ #include <linux/module.h> #include <linux/regmap.h> #include <linux/spi/spi.h> -#include <linux/of_device.h> +#include <linux/mod_devicetable.h> #include "zpa2326.h" /* @@ -57,11 +57,9 @@ static int zpa2326_probe_spi(struct spi_device *spi) spi->irq, ZPA2326_DEVICE_ID, regmap); } -static int zpa2326_remove_spi(struct spi_device *spi) +static void zpa2326_remove_spi(struct spi_device *spi) { zpa2326_remove(&spi->dev); - - return 0; } static const struct spi_device_id zpa2326_spi_ids[] = { @@ -70,18 +68,16 @@ static const struct spi_device_id zpa2326_spi_ids[] = { }; MODULE_DEVICE_TABLE(spi, zpa2326_spi_ids); -#if defined(CONFIG_OF) static const struct of_device_id zpa2326_spi_matches[] = { { .compatible = "murata,zpa2326" }, { } }; MODULE_DEVICE_TABLE(of, zpa2326_spi_matches); -#endif static struct spi_driver zpa2326_spi_driver = { .driver = { .name = "zpa2326-spi", - .of_match_table = of_match_ptr(zpa2326_spi_matches), + .of_match_table = zpa2326_spi_matches, .pm = ZPA2326_PM_OPS, }, .probe = zpa2326_probe_spi, @@ -93,3 +89,4 @@ module_spi_driver(zpa2326_spi_driver); MODULE_AUTHOR("Gregor Boirie <gregor.boirie@parrot.com>"); MODULE_DESCRIPTION("SPI driver for Murata ZPA2326 pressure sensor"); MODULE_LICENSE("GPL v2"); +MODULE_IMPORT_NS(IIO_ZPA2326); |