BigW Consortium Gitlab

Commit fea8fa44 by David Frey

Copy bme680 driver from linux-stable v4.20-rc1

This commit overwrites the previous backporting that was done in order to introduce the backporting work as a separate commit to simplify future maintenance.
parent a3b500be
/*
* Copyright (C) 2014 Felix Fietkau <nbd@nbd.name>
* Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef _LINUX_BITFIELD_H
#define _LINUX_BITFIELD_H
#include <asm/byteorder.h>
/*
* Bitfield access macros
*
* FIELD_{GET,PREP} macros take as first parameter shifted mask
* from which they extract the base mask and shift amount.
* Mask must be a compilation time constant.
*
* Example:
*
* #define REG_FIELD_A GENMASK(6, 0)
* #define REG_FIELD_B BIT(7)
* #define REG_FIELD_C GENMASK(15, 8)
* #define REG_FIELD_D GENMASK(31, 16)
*
* Get:
* a = FIELD_GET(REG_FIELD_A, reg);
* b = FIELD_GET(REG_FIELD_B, reg);
*
* Set:
* reg = FIELD_PREP(REG_FIELD_A, 1) |
* FIELD_PREP(REG_FIELD_B, 0) |
* FIELD_PREP(REG_FIELD_C, c) |
* FIELD_PREP(REG_FIELD_D, 0x40);
*
* Modify:
* reg &= ~REG_FIELD_C;
* reg |= FIELD_PREP(REG_FIELD_C, c);
*/
#define __bf_shf(x) (__builtin_ffsll(x) - 1)
/**
* FIELD_PREP() - prepare a bitfield element
* @_mask: shifted mask defining the field's length and position
* @_val: value to put in the field
*
* FIELD_PREP() masks and shifts up the value. The result should
* be combined with other fields of the bitfield using logical OR.
*/
#define FIELD_PREP(_mask, _val) \
({ \
((typeof(_mask))(_val) << __bf_shf(_mask)) & (_mask); \
})
#endif
cflags:
{
// This driver depends on IIO
-DCONFIG_IIO
-DCONFIG_IIO_BUFFER
-DCONFIG_IIO_TRIGGERRED_BUFFER
-DDEBUG
-DREGMAP
-DREGMAP_I2C
}
sources:
{
bme680_i2c.c
bme680_core.c
}
requires:
{
kernelModules:
{
#if ${MANGOH_KERNEL_LACKS_IIO} = 1
$CURDIR/../iio/iio
#endif // MANGOH_KERNEL_LACKS_IIO
}
}
......@@ -4,10 +4,10 @@
#define BME680_REG_CHIP_I2C_ID 0xD0
#define BME680_REG_CHIP_SPI_ID 0x50
#define BME680_CHIP_ID_VAL 0x61
#define BME680_CHIP_ID_VAL 0x61
#define BME680_REG_SOFT_RESET_I2C 0xE0
#define BME680_REG_SOFT_RESET_SPI 0x60
#define BME680_CMD_SOFTRESET 0xB6
#define BME680_CMD_SOFTRESET 0xB6
#define BME680_REG_STATUS 0x73
#define BME680_SPI_MEM_PAGE_BIT BIT(4)
#define BME680_SPI_MEM_PAGE_1_VAL 1
......@@ -18,6 +18,7 @@
#define BME680_REG_GAS_MSB 0x2A
#define BME680_REG_GAS_R_LSB 0x2B
#define BME680_GAS_STAB_BIT BIT(4)
#define BME680_GAS_RANGE_MASK GENMASK(3, 0)
#define BME680_REG_CTRL_HUMIDITY 0x72
#define BME680_OSRS_HUMIDITY_MASK GENMASK(2, 0)
......@@ -26,9 +27,8 @@
#define BME680_OSRS_TEMP_MASK GENMASK(7, 5)
#define BME680_OSRS_PRESS_MASK GENMASK(4, 2)
#define BME680_MODE_MASK GENMASK(1, 0)
#define BME680_MODE_FORCED 1
#define BME680_MODE_SLEEP 0
#define BME680_MODE_FORCED 1
#define BME680_MODE_SLEEP 0
#define BME680_REG_CONFIG 0x75
#define BME680_FILTER_MASK GENMASK(4, 2)
......@@ -39,24 +39,21 @@
#define BME680_MAX_OVERFLOW_VAL 0x40000000
#define BME680_HUM_REG_SHIFT_VAL 4
#define BME680_BIT_H1_DATA_MSK 0x0F
#define BME680_BIT_H1_DATA_MASK GENMASK(3, 0)
#define BME680_REG_RES_HEAT_RANGE 0x02
#define BME680_RHRANGE_MSK 0x30
#define BME680_RHRANGE_MASK GENMASK(5, 4)
#define BME680_REG_RES_HEAT_VAL 0x00
#define BME680_REG_RANGE_SW_ERR 0x04
#define BME680_RSERROR_MSK 0xF0
#define BME680_RSERROR_MASK GENMASK(7, 4)
#define BME680_REG_RES_HEAT_0 0x5A
#define BME680_REG_GAS_WAIT_0 0x64
#define BME680_GAS_RANGE_MASK 0x0F
#define BME680_ADC_GAS_RES_SHIFT 6
#define BME680_AMB_TEMP 25
#define BME680_REG_CTRL_GAS_1 0x71
#define BME680_RUN_GAS_MASK BIT(4)
#define BME680_NB_CONV_MASK GENMASK(3, 0)
#define BME680_RUN_GAS_EN_BIT BIT(4)
#define BME680_NB_CONV_0_VAL 0
#define BME680_REG_MEAS_STAT_0 0x1D
#define BME680_GAS_MEAS_BIT BIT(6)
......
......@@ -9,21 +9,15 @@
* https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME680-DS001-00.pdf
*/
#include <linux/acpi.h>
#include "bitfield.h"
#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/log2.h>
#include <linux/regmap.h>
#include <linux/iio/iio.h>
#include <linux/iio/sysfs.h>
#include <linux/version.h>
#include "bme680.h"
#define regmap_write_bits regmap_update_bits
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 2, 0)
#define IIO_SUPPORTS_OVERSAMPLING_RATIO
#endif
#include "bme680.h"
struct bme680_calib {
u16 par_t1;
......@@ -78,24 +72,18 @@ EXPORT_SYMBOL(bme680_regmap_config);
static const struct iio_chan_spec bme680_channels[] = {
{
.type = IIO_TEMP,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED)
#ifdef IIO_SUPPORTS_OVERSAMPLING_RATIO
| BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
#endif
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
},
{
.type = IIO_PRESSURE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED)
#ifdef IIO_SUPPORTS_OVERSAMPLING_RATIO
| BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
#endif
.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)
#ifdef IIO_SUPPORTS_OVERSAMPLING_RATIO
| BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
#endif
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
},
{
.type = IIO_RESISTANCE,
......@@ -103,8 +91,6 @@ static const struct iio_chan_spec bme680_channels[] = {
},
};
static const int bme680_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static int bme680_read_calib(struct bme680_data *data,
struct bme680_calib *calib)
{
......@@ -114,16 +100,14 @@ static int bme680_read_calib(struct bme680_data *data,
__le16 buf;
/* Temperature related coefficients */
ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_T1_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T1_LSB_REG\n");
return ret;
}
calib->par_t1 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_T2_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T2_LSB_REG\n");
return ret;
......@@ -138,16 +122,14 @@ static int bme680_read_calib(struct bme680_data *data,
calib->par_t3 = tmp;
/* Pressure related coefficients */
ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P1_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P1_LSB_REG\n");
return ret;
}
calib->par_p1 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P2_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P2_LSB_REG\n");
return ret;
......@@ -161,16 +143,14 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_p3 = tmp;
ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P4_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P4_LSB_REG\n");
return ret;
}
calib->par_p4 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P5_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P5_LSB_REG\n");
return ret;
......@@ -191,16 +171,14 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_p7 = tmp;
ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P8_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P8_LSB_REG\n");
return ret;
}
calib->par_p8 = le16_to_cpu(buf);
ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_P9_LSB_REG, (u8 *) &buf, 2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P9_LSB_REG\n");
return ret;
......@@ -220,30 +198,26 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read BME680_H1_MSB_REG\n");
return ret;
}
ret = regmap_read(data->regmap, BME680_H1_LSB_REG, &tmp_lsb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H1_LSB_REG\n");
return ret;
}
calib->par_h1 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
(tmp_lsb & BME680_BIT_H1_DATA_MSK);
(tmp_lsb & BME680_BIT_H1_DATA_MASK);
ret = regmap_read(data->regmap, BME680_H2_MSB_REG, &tmp_msb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H2_MSB_REG\n");
return ret;
}
ret = regmap_read(data->regmap, BME680_H2_LSB_REG, &tmp_lsb);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H2_LSB_REG\n");
return ret;
}
calib->par_h2 = (tmp_msb << BME680_HUM_REG_SHIFT_VAL) |
(tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
(tmp_lsb >> BME680_HUM_REG_SHIFT_VAL);
ret = regmap_read(data->regmap, BME680_H3_REG, &tmp);
if (ret < 0) {
......@@ -288,8 +262,8 @@ static int bme680_read_calib(struct bme680_data *data,
}
calib->par_gh1 = tmp;
ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG,
(u8 *) &buf, 2);
ret = regmap_bulk_read(data->regmap, BME680_GH2_LSB_REG, (u8 *) &buf,
2);
if (ret < 0) {
dev_err(dev, "failed to read BME680_GH2_LSB_REG\n");
return ret;
......@@ -309,7 +283,7 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read resistance heat range\n");
return ret;
}
calib->res_heat_range = (tmp & BME680_RHRANGE_MSK) / 16;
calib->res_heat_range = FIELD_GET(BME680_RHRANGE_MASK, tmp);
ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_VAL, &tmp);
if (ret < 0) {
......@@ -323,7 +297,7 @@ static int bme680_read_calib(struct bme680_data *data,
dev_err(dev, "failed to read range software error\n");
return ret;
}
calib->range_sw_err = (tmp & BME680_RSERROR_MSK) / 16;
calib->range_sw_err = FIELD_GET(BME680_RSERROR_MASK, tmp);
return 0;
}
......@@ -420,10 +394,7 @@ static u32 bme680_compensate_humid(struct bme680_data *data,
var6 = (var4 * var5) >> 1;
calc_hum = (((var3 + var6) >> 10) * 1000) >> 12;
if (calc_hum > 100000) /* Cap at 100%rH */
calc_hum = 100000;
else if (calc_hum < 0)
calc_hum = 0;
calc_hum = clamp(calc_hum, 0, 100000); /* clamp between 0-100 %rH */
return calc_hum;
}
......@@ -530,12 +501,20 @@ static int bme680_set_mode(struct bme680_data *data, bool mode)
return ret;
}
static u8 bme680_oversampling_to_reg(u8 val)
{
return ilog2(val) + 1;
}
static int bme680_chip_config(struct bme680_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
u8 osrs = FIELD_PREP(BME680_OSRS_HUMIDITY_MASK,
data->oversampling_humid + 1);
u8 osrs;
osrs = FIELD_PREP(
BME680_OSRS_HUMIDITY_MASK,
bme680_oversampling_to_reg(data->oversampling_humid));
/*
* Highly recommended to set oversampling of humidity before
* temperature/pressure oversampling.
......@@ -556,12 +535,12 @@ static int bme680_chip_config(struct bme680_data *data)
return ret;
}
osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
FIELD_PREP(BME680_OSRS_PRESS_MASK, data->oversampling_press + 1);
osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK,
bme680_oversampling_to_reg(data->oversampling_temp)) |
FIELD_PREP(BME680_OSRS_PRESS_MASK,
bme680_oversampling_to_reg(data->oversampling_press));
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_OSRS_TEMP_MASK |
BME680_OSRS_PRESS_MASK,
BME680_OSRS_TEMP_MASK | BME680_OSRS_PRESS_MASK,
osrs);
if (ret < 0)
dev_err(dev, "failed to write ctrl_meas register\n");
......@@ -589,14 +568,15 @@ static int bme680_gas_config(struct bme680_data *data)
/* set target heating duration */
ret = regmap_write(data->regmap, BME680_REG_GAS_WAIT_0, heatr_dur);
if (ret < 0) {
dev_err(dev, "failted to write gas_wait_0 register\n");
dev_err(dev, "failed to write gas_wait_0 register\n");
return ret;
}
/* Selecting the runGas and NB conversion settings for the sensor */
/* Enable the gas sensor and select heater profile set-point 0 */
ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_GAS_1,
BME680_RUN_GAS_MASK | BME680_NB_CONV_MASK,
BME680_RUN_GAS_EN_BIT | BME680_NB_CONV_0_VAL);
FIELD_PREP(BME680_RUN_GAS_MASK, 1) |
FIELD_PREP(BME680_NB_CONV_MASK, 0));
if (ret < 0)
dev_err(dev, "failed to write ctrl_gas_1 register\n");
......@@ -791,99 +771,61 @@ static int bme680_read_raw(struct iio_dev *indio_dev,
default:
return -EINVAL;
}
#ifdef IIO_SUPPORTS_OVERSAMPLING_RATIO
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_TEMP:
*val = 1 << data->oversampling_temp;
*val = data->oversampling_temp;
return IIO_VAL_INT;
case IIO_PRESSURE:
*val = 1 << data->oversampling_press;
*val = data->oversampling_press;
return IIO_VAL_INT;
case IIO_HUMIDITYRELATIVE:
*val = 1 << data->oversampling_humid;
*val = data->oversampling_humid;
return IIO_VAL_INT;
default:
return -EINVAL;
}
#endif
default:
return -EINVAL;
}
}
#ifdef IIO_SUPPORTS_OVERSAMPLING_RATIO
static int bme680_write_oversampling_ratio_temp(struct bme680_data *data,
int val)
static bool bme680_is_valid_oversampling(int rate)
{
int i;
for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
if (bme680_oversampling_avail[i] == val) {
data->oversampling_temp = ilog2(val);
return bme680_chip_config(data);
}
}
return -EINVAL;
return (rate > 0 && rate <= 16 && is_power_of_2(rate));
}
static int bme680_write_oversampling_ratio_press(struct bme680_data *data,
int val)
{
int i;
for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
if (bme680_oversampling_avail[i] == val) {
data->oversampling_press = ilog2(val);
return bme680_chip_config(data);
}
}
return -EINVAL;
}
static int bme680_write_oversampling_ratio_humid(struct bme680_data *data,
int val)
{
int i;
for (i = 0; i < ARRAY_SIZE(bme680_oversampling_avail); i++) {
if (bme680_oversampling_avail[i] == val) {
data->oversampling_humid = ilog2(val);
return bme680_chip_config(data);
}
}
return -EINVAL;
}
#endif
static int bme680_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
#ifdef IIO_SUPPORTS_OVERSAMPLING_RATIO
struct bme680_data *data = iio_priv(indio_dev);
#endif
if (val2 != 0)
return -EINVAL;
switch (mask) {
#ifdef IIO_SUPPORTS_OVERSAMPLING_RATIO
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
{
if (!bme680_is_valid_oversampling(val))
return -EINVAL;
switch (chan->type) {
case IIO_TEMP:
return bme680_write_oversampling_ratio_temp(data, val);
data->oversampling_temp = val;
break;
case IIO_PRESSURE:
return bme680_write_oversampling_ratio_press(data, val);
data->oversampling_press = val;
break;
case IIO_HUMIDITYRELATIVE:
return bme680_write_oversampling_ratio_humid(data, val);
data->oversampling_humid = val;
break;
default:
return -EINVAL;
}
#endif
return bme680_chip_config(data);
}
default:
return -EINVAL;
}
......@@ -945,9 +887,9 @@ int bme680_core_probe(struct device *dev, struct regmap *regmap,
indio_dev->modes = INDIO_DIRECT_MODE;
/* default values for the sensor */
data->oversampling_humid = ilog2(2); /* 2X oversampling rate */
data->oversampling_press = ilog2(4); /* 4X oversampling rate */
data->oversampling_temp = ilog2(8); /* 8X oversampling rate */
data->oversampling_humid = 2; /* 2X oversampling rate */
data->oversampling_press = 4; /* 4X oversampling rate */
data->oversampling_temp = 8; /* 8X oversampling rate */
data->heater_temp = 320; /* degree Celsius */
data->heater_dur = 150; /* milliseconds */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment