[PATCH 3/3] iio: pressure: bmp280: add humidity support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Enable humidity support for the BME280 part

Signed-off-by: Matt Ranostay <matt.ranostay@xxxxxxxxx>
---
 drivers/iio/pressure/bmp280.c | 137 ++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 133 insertions(+), 4 deletions(-)

diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c
index e80cbf3b21fc..9e3a9f00cd84 100644
--- a/drivers/iio/pressure/bmp280.c
+++ b/drivers/iio/pressure/bmp280.c
@@ -18,6 +18,8 @@
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
 
+#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
@@ -26,11 +28,20 @@
 #define BMP280_REG_PRESS_MSB		0xF7
 
 #define BMP280_REG_CONFIG		0xF5
+#define BMP280_REG_CTRL_HUMIDITY	0xF2
 #define BMP280_REG_CTRL_MEAS		0xF4
 #define BMP280_REG_STATUS		0xF3
 #define BMP280_REG_RESET		0xE0
 #define BMP280_REG_ID			0xD0
 
+/* 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
 
@@ -44,6 +55,14 @@
 #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_HUMIDITY_SKIP	0
+#define BMP280_OSRS_HUMIDITY_1X		BIT(0)
+#define BMP280_OSRS_HUMIDITY_2X		BIT(1)
+#define BMP280_OSRS_HUMIDITY_4X		(BIT(1) | BIT(0))
+#define BMP280_OSRS_HUMIDITY_8X		BIT(2)
+#define BMP280_OSRS_HUMIDITY_16X	(BIT(2) | BIT(0))
+
 #define BMP280_OSRS_TEMP_MASK		(BIT(7) | BIT(6) | BIT(5))
 #define BMP280_OSRS_TEMP_SKIP		0
 #define BMP280_OSRS_TEMP_1X		BIT(5)
@@ -93,6 +112,13 @@ struct bmp280_chip_info {
 	int (*init)(struct bmp280_data *);
 };
 
+static int bme280_chip_init(struct bmp280_data *data)
+{
+	return regmap_update_bits(data->regmap, BMP280_REG_CTRL_HUMIDITY,
+				  BMP280_OSRS_HUMIDITY_MASK,
+				  BMP280_OSRS_HUMIDITY_16X);
+}
+
 static struct bmp280_chip_info bmp280_chip_info_table[] = {
 	[bmp280] = {
 		.id = BMP280_CHIP_ID,
@@ -100,7 +126,8 @@ static struct bmp280_chip_info bmp280_chip_info_table[] = {
 	},
 	[bme280] = {
 		.id = BME280_CHIP_ID,
-		.num_channels = 2,
+		.num_channels = 3,
+		.init = bme280_chip_init,
 	},
 };
 
@@ -120,12 +147,17 @@ static const struct iio_chan_spec bmp280_channels[] = {
 		.type = IIO_TEMP,
 		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
 	},
+	{
+		.type = IIO_HUMIDITYRELATIVE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+	},
 };
 
 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;
@@ -137,6 +169,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:
@@ -154,7 +188,7 @@ 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,
@@ -162,11 +196,74 @@ static const struct regmap_config bmp280_regmap_config = {
 };
 
 /*
+ * 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(le16_to_cpu(tmp) >> 4 | (le16_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) & 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
  * value.
  *
- * Taken from datasheet, Section 3.11.3, "Compensation formula".
+ * Taken from BMP280 datasheet, Section 3.11.3, "Compensation formula".
  */
 static s32 bmp280_compensate_temp(struct bmp280_data *data,
 				  s32 adc_temp)
@@ -206,7 +303,7 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data,
  * integer bits and 8 fractional bits).  Output value of "24674867"
  * represents 24674867/256 = 96386.2 Pa = 963.862 hPa
  *
- * Taken from datasheet, Section 3.11.3, "Compensation formula".
+ * Taken from BMP280 datasheet, Section 3.11.3, "Compensation formula".
  */
 static u32 bmp280_compensate_press(struct bmp280_data *data,
 				   s32 adc_press)
@@ -301,6 +398,35 @@ static int bmp280_read_press(struct bmp280_data *data,
 	return IIO_VAL_FRACTIONAL;
 }
 
+static int bmp280_read_humidity(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_PRESS_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)
@@ -313,6 +439,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 = bmp280_read_humidity(data, val, val2);
+			break;
 		case IIO_PRESSURE:
 			ret = bmp280_read_press(data, val, val2);
 			break;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-iio" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Input]     [Linux Kernel]     [Linux SCSI]     [X.org]

  Powered by Linux