mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2025-01-20 09:58:04 +07:00
iio: pressure: bmp280: add humidity support
Enable humidity support for the BME280 part Signed-off-by: Matt Ranostay <matt.ranostay@intel.com> Acked-by: Vlad Dogaru <vlad.dogaru@intel.com> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
parent
b7a96bb96f
commit
14beaa8f5a
@ -12,7 +12,8 @@ config BMP280
|
||||
select REGMAP_I2C
|
||||
help
|
||||
Say yes here to build support for Bosch Sensortec BMP180 and BMP280
|
||||
pressure and temperature sensors.
|
||||
pressure and temperature sensors. Also supports the BE280 with
|
||||
an additional humidty sensor channel.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called bmp280.
|
||||
|
@ -10,6 +10,7 @@
|
||||
* 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
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "bmp280: " fmt
|
||||
@ -23,6 +24,8 @@
|
||||
#include <linux/iio/sysfs.h>
|
||||
|
||||
/* BMP280 specific registers */
|
||||
#define BMP280_REG_HUMIDITY_LSB 0xFE
|
||||
#define BMP280_REG_HUMIDITY_MSB 0xFD
|
||||
#define BMP280_REG_TEMP_XLSB 0xFC
|
||||
#define BMP280_REG_TEMP_LSB 0xFB
|
||||
#define BMP280_REG_TEMP_MSB 0xFA
|
||||
@ -31,7 +34,17 @@
|
||||
#define BMP280_REG_PRESS_MSB 0xF7
|
||||
|
||||
#define BMP280_REG_CONFIG 0xF5
|
||||
#define BMP280_REG_CTRL_MEAS 0xF4
|
||||
#define BMP280_REG_STATUS 0xF3
|
||||
#define BMP280_REG_CTRL_HUMIDITY 0xF2
|
||||
|
||||
/* Due to non linear mapping, and data sizes we can't do a bulk read */
|
||||
#define BMP280_REG_COMP_H1 0xA1
|
||||
#define BMP280_REG_COMP_H2 0xE1
|
||||
#define BMP280_REG_COMP_H3 0xE3
|
||||
#define BMP280_REG_COMP_H4 0xE4
|
||||
#define BMP280_REG_COMP_H5 0xE5
|
||||
#define BMP280_REG_COMP_H6 0xE7
|
||||
|
||||
#define BMP280_REG_COMP_TEMP_START 0x88
|
||||
#define BMP280_COMP_TEMP_REG_COUNT 6
|
||||
@ -46,6 +59,15 @@
|
||||
#define BMP280_FILTER_8X (BIT(3) | BIT(2))
|
||||
#define BMP280_FILTER_16X BIT(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_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_TEMP_MASK (BIT(7) | BIT(6) | BIT(5))
|
||||
#define BMP280_OSRS_TEMP_SKIP 0
|
||||
#define BMP280_OSRS_TEMP_X(osrs_t) ((osrs_t) << 5)
|
||||
@ -92,6 +114,7 @@
|
||||
|
||||
#define BMP180_CHIP_ID 0x55
|
||||
#define BMP280_CHIP_ID 0x58
|
||||
#define BME280_CHIP_ID 0x60
|
||||
#define BMP280_SOFT_RESET_VAL 0xB6
|
||||
|
||||
struct bmp280_data {
|
||||
@ -103,6 +126,7 @@ struct bmp280_data {
|
||||
/* log of base 2 of oversampling rate */
|
||||
u8 oversampling_press;
|
||||
u8 oversampling_temp;
|
||||
u8 oversampling_humid;
|
||||
|
||||
/*
|
||||
* Carryover value from temperature conversion, used in pressure
|
||||
@ -120,9 +144,13 @@ struct bmp280_chip_info {
|
||||
const int *oversampling_press_avail;
|
||||
int num_oversampling_press_avail;
|
||||
|
||||
const int *oversampling_humid_avail;
|
||||
int num_oversampling_humid_avail;
|
||||
|
||||
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 *);
|
||||
};
|
||||
|
||||
/*
|
||||
@ -143,12 +171,18 @@ static const struct iio_chan_spec bmp280_channels[] = {
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
},
|
||||
{
|
||||
.type = IIO_HUMIDITYRELATIVE,
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
|
||||
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
|
||||
},
|
||||
};
|
||||
|
||||
static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_CONFIG:
|
||||
case BMP280_REG_CTRL_HUMIDITY:
|
||||
case BMP280_REG_CTRL_MEAS:
|
||||
case BMP280_REG_RESET:
|
||||
return true;
|
||||
@ -160,6 +194,8 @@ static bool bmp280_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
static bool bmp280_is_volatile_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
case BMP280_REG_HUMIDITY_LSB:
|
||||
case BMP280_REG_HUMIDITY_MSB:
|
||||
case BMP280_REG_TEMP_XLSB:
|
||||
case BMP280_REG_TEMP_LSB:
|
||||
case BMP280_REG_TEMP_MSB:
|
||||
@ -177,13 +213,77 @@ static const struct regmap_config bmp280_regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
|
||||
.max_register = BMP280_REG_TEMP_XLSB,
|
||||
.max_register = BMP280_REG_HUMIDITY_LSB,
|
||||
.cache_type = REGCACHE_RBTREE,
|
||||
|
||||
.writeable_reg = bmp280_is_writeable_reg,
|
||||
.volatile_reg = bmp280_is_volatile_reg,
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns humidity in percent, resolution is 0.01 percent. Output value of
|
||||
* "47445" represents 47445/1024 = 46.333 %RH.
|
||||
*
|
||||
* Taken from BME280 datasheet, Section 4.2.3, "Compensation formula".
|
||||
*/
|
||||
|
||||
static u32 bmp280_compensate_humidity(struct bmp280_data *data,
|
||||
s32 adc_humidity)
|
||||
{
|
||||
struct device *dev = &data->client->dev;
|
||||
unsigned int H1, H3, tmp;
|
||||
int H2, H4, H5, H6, ret, var;
|
||||
|
||||
ret = regmap_read(data->regmap, BMP280_REG_COMP_H1, &H1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H1 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H2, &tmp, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H2 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
H2 = sign_extend32(le16_to_cpu(tmp), 15);
|
||||
|
||||
ret = regmap_read(data->regmap, BMP280_REG_COMP_H3, &H3);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H3 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H4, &tmp, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H4 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
H4 = sign_extend32(((be16_to_cpu(tmp) >> 4) & 0xff0) |
|
||||
(be16_to_cpu(tmp) & 0xf), 11);
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_H5, &tmp, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H5 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
H5 = sign_extend32(((le16_to_cpu(tmp) >> 4) & 0xfff), 11);
|
||||
|
||||
ret = regmap_read(data->regmap, BMP280_REG_COMP_H6, &tmp);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "failed to read H6 comp value\n");
|
||||
return ret;
|
||||
}
|
||||
H6 = sign_extend32(tmp, 7);
|
||||
|
||||
var = ((s32)data->t_fine) - 76800;
|
||||
var = ((((adc_humidity << 14) - (H4 << 20) - (H5 * var)) + 16384) >> 15)
|
||||
* (((((((var * H6) >> 10) * (((var * H3) >> 11) + 32768)) >> 10)
|
||||
+ 2097152) * H2 + 8192) >> 14);
|
||||
var -= ((((var >> 15) * (var >> 15)) >> 7) * H1) >> 4;
|
||||
|
||||
return var >> 12;
|
||||
};
|
||||
|
||||
/*
|
||||
* Returns temperature in DegC, resolution is 0.01 DegC. Output value of
|
||||
* "5123" equals 51.23 DegC. t_fine carries fine temperature as global
|
||||
@ -324,6 +424,34 @@ static int bmp280_read_press(struct bmp280_data *data,
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
}
|
||||
|
||||
static int bmp280_read_humid(struct bmp280_data *data, int *val, int *val2)
|
||||
{
|
||||
int ret;
|
||||
__be16 tmp = 0;
|
||||
s32 adc_humidity;
|
||||
u32 comp_humidity;
|
||||
|
||||
/* Read and compensate temperature so we get a reading of t_fine. */
|
||||
ret = bmp280_read_temp(data, NULL);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, BMP280_REG_HUMIDITY_MSB,
|
||||
(u8 *) &tmp, 2);
|
||||
if (ret < 0) {
|
||||
dev_err(&data->client->dev, "failed to read humidity\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
adc_humidity = be16_to_cpu(tmp);
|
||||
comp_humidity = bmp280_compensate_humidity(data, adc_humidity);
|
||||
|
||||
*val = comp_humidity;
|
||||
*val2 = 1024;
|
||||
|
||||
return IIO_VAL_FRACTIONAL;
|
||||
}
|
||||
|
||||
static int bmp280_read_raw(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan,
|
||||
int *val, int *val2, long mask)
|
||||
@ -336,6 +464,9 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_PROCESSED:
|
||||
switch (chan->type) {
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
ret = data->chip_info->read_humid(data, val, val2);
|
||||
break;
|
||||
case IIO_PRESSURE:
|
||||
ret = data->chip_info->read_press(data, val, val2);
|
||||
break;
|
||||
@ -349,6 +480,10 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
|
||||
break;
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
switch (chan->type) {
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
*val = 1 << data->oversampling_humid;
|
||||
ret = IIO_VAL_INT;
|
||||
break;
|
||||
case IIO_PRESSURE:
|
||||
*val = 1 << data->oversampling_press;
|
||||
ret = IIO_VAL_INT;
|
||||
@ -372,6 +507,23 @@ static int bmp280_read_raw(struct iio_dev *indio_dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (avail[i] == val) {
|
||||
data->oversampling_humid = ilog2(val);
|
||||
|
||||
return data->chip_info->chip_config(data);
|
||||
}
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int bmp280_write_oversampling_ratio_temp(struct bmp280_data *data,
|
||||
int val)
|
||||
{
|
||||
@ -417,6 +569,9 @@ static int bmp280_write_raw(struct iio_dev *indio_dev,
|
||||
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
|
||||
mutex_lock(&data->lock);
|
||||
switch (chan->type) {
|
||||
case IIO_HUMIDITYRELATIVE:
|
||||
ret = bmp280_write_oversampling_ratio_humid(data, val);
|
||||
break;
|
||||
case IIO_PRESSURE:
|
||||
ret = bmp280_write_oversampling_ratio_press(data, val);
|
||||
break;
|
||||
@ -535,6 +690,37 @@ static const struct bmp280_chip_info bmp280_chip_info = {
|
||||
.read_press = bmp280_read_press,
|
||||
};
|
||||
|
||||
static int bme280_chip_config(struct bmp280_data *data)
|
||||
{
|
||||
int ret = bmp280_chip_config(data);
|
||||
u8 osrs = BMP280_OSRS_HUMIDITIY_X(data->oversampling_humid + 1);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY,
|
||||
BMP280_OSRS_HUMIDITY_MASK, osrs);
|
||||
}
|
||||
|
||||
static const struct bmp280_chip_info bme280_chip_info = {
|
||||
.regmap_config = &bmp280_regmap_config,
|
||||
|
||||
.oversampling_temp_avail = bmp280_oversampling_avail,
|
||||
.num_oversampling_temp_avail = ARRAY_SIZE(bmp280_oversampling_avail),
|
||||
|
||||
.oversampling_press_avail = bmp280_oversampling_avail,
|
||||
.num_oversampling_press_avail = ARRAY_SIZE(bmp280_oversampling_avail),
|
||||
|
||||
.oversampling_humid_avail = bmp280_oversampling_avail,
|
||||
.num_oversampling_humid_avail = ARRAY_SIZE(bmp280_oversampling_avail),
|
||||
|
||||
.chip_config = bme280_chip_config,
|
||||
.read_temp = bmp280_read_temp,
|
||||
.read_press = bmp280_read_press,
|
||||
.read_humid = bmp280_read_humid,
|
||||
};
|
||||
|
||||
|
||||
static bool bmp180_is_writeable_reg(struct device *dev, unsigned int reg)
|
||||
{
|
||||
switch (reg) {
|
||||
@ -849,21 +1035,29 @@ static int bmp280_probe(struct i2c_client *client,
|
||||
indio_dev->dev.parent = &client->dev;
|
||||
indio_dev->name = id->name;
|
||||
indio_dev->channels = bmp280_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(bmp280_channels);
|
||||
indio_dev->info = &bmp280_info;
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
switch (id->driver_data) {
|
||||
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);
|
||||
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);
|
||||
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);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -895,6 +1089,7 @@ static const struct acpi_device_id bmp280_acpi_match[] = {
|
||||
{"BMP0280", BMP280_CHIP_ID },
|
||||
{"BMP0180", BMP180_CHIP_ID },
|
||||
{"BMP0085", BMP180_CHIP_ID },
|
||||
{"BME0280", BME280_CHIP_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, bmp280_acpi_match);
|
||||
@ -903,6 +1098,7 @@ static const struct i2c_device_id bmp280_id[] = {
|
||||
{"bmp280", BMP280_CHIP_ID },
|
||||
{"bmp180", BMP180_CHIP_ID },
|
||||
{"bmp085", BMP180_CHIP_ID },
|
||||
{"bme280", BME280_CHIP_ID },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, bmp280_id);
|
||||
|
Loading…
Reference in New Issue
Block a user