Third set of IIO new device support, cleanups and features for the 4.19 cycle.

This is a somewhat sneaky late pull request given Linus has announced
 a likely 1 week delay.  If it is too late I'll resend after the merge
 window.  I merged in the fixes branch as those are primarily around
 things queued for the merge window.
 
 Particulary good to see the output of our Himanshu Jha, a GSOC student
 who developed the bme680 driver.
 
 New device support:
 * bme680 gas sensor (with temperature, humidity and pressure)
   - new driver to support this device
 * vcn4000
   - support vcnl4200 (lots of rework to allow this)
   - ids added for VCNL4010 and VCNL4020 sensors
 
 New features:
 * ad9523
   - support the various external signal options via gpios.
 
 Cleanups and fixes
 * ad_sigma_delta
   - unsigned long for a timeout.
 * ad9523
   - fix a wrong return value that was indicating successful write failed
     and might lead to an infinite loop.
 * si1133
   - fix an impossible test.
   - fix an uninitialsed variable by reading from the device in all paths.
 * xilinx xadc
   - check for return values in clk related functions
   - limit the pcap clock frequency to supported ranges.
   - stash the irq to avoid calling platform_get_irq from the remove path.
   - ensure the irq is actually requested before we enable the hardware to
     output it.
 -----BEGIN PGP SIGNATURE-----
 
 iQJFBAABCAAvFiEEbilms4eEBlKRJoGxVIU0mcT0FogFAlth+aERHGppYzIzQGtl
 cm5lbC5vcmcACgkQVIU0mcT0FojlVw//bnip7t+HAAExI9gAMYUYre8rpC+LrVy7
 vA+Z64p2NRRtsAskYCul0b+g+eX83qth3sl1fDDvHgwuZx5/Pe5Pny6K8Wx/824c
 roEBu3qh5q7tke+E5GINhu60qIJZX6bNevkZ3UhTHgmjBgvBYP5MdWPM2OY7LOUt
 5/XkcYOaDO4Q9SHHZeXvbuTUPW1bLTRd2iN+KOSIkQ0wdoG8lwNPLuu+gpSJgQAb
 n5fR8dRlnvuLsefrCaoNzmrpoD/zQbU5PS31btSghCJtFJrnuiaGrIIRjBPIuuM8
 2jG7RA1Lka0hdR1IFDAfeAMzS1OkxqzAKtdQeBUxv0x0291JqJdI5Wkmo/sSehRd
 bkJaWVY96+PglbOyXJ9t2RfQrZ8pgAoHTqUXK+qCBP1N/XpcnsDWM+zbeWPPTaDx
 xuXCba58p8W0D1UeYdSdjTORAxekEFBAakTXfsTHrNg8w78WAZLGLg0cTST6umRl
 FNzDMzZLS4kJ1a8er8+yH2PgjW5WLqkP5iG7K0Z1js4A2Fxu9EH6M3Hym2hxtLVA
 OHq9qkMD5OrOVYoKxusX8ilyWE0DLimvEfw25mNXtBnGxE43jlGDVT48dUwXpIJK
 Ll9ihASfixc0q5tSE0fjuIuprMYI6bzL4laH60usFTK35EmL1jtBeOo3F6AZ6HL5
 4LEHBG9L9vI=
 =lYzx
 -----END PGP SIGNATURE-----

Merge tag 'iio-for-4.19c' of git://git.kernel.org/pub/scm/linux/kernel/git/jic23/iio into staging-next

Jonathan writes:

Third set of IIO new device support, cleanups and features for the 4.19 cycle.

This is a somewhat sneaky late pull request given Linus has announced
a likely 1 week delay.  If it is too late I'll resend after the merge
window.  I merged in the fixes branch as those are primarily around
things queued for the merge window.

Particulary good to see the output of our Himanshu Jha, a GSOC student
who developed the bme680 driver.

New device support:
* bme680 gas sensor (with temperature, humidity and pressure)
  - new driver to support this device
* vcn4000
  - support vcnl4200 (lots of rework to allow this)
  - ids added for VCNL4010 and VCNL4020 sensors

New features:
* ad9523
  - support the various external signal options via gpios.

Cleanups and fixes
* ad_sigma_delta
  - unsigned long for a timeout.
* ad9523
  - fix a wrong return value that was indicating successful write failed
    and might lead to an infinite loop.
* si1133
  - fix an impossible test.
  - fix an uninitialsed variable by reading from the device in all paths.
* xilinx xadc
  - check for return values in clk related functions
  - limit the pcap clock frequency to supported ranges.
  - stash the irq to avoid calling platform_get_irq from the remove path.
  - ensure the irq is actually requested before we enable the hardware to
    output it.
This commit is contained in:
Greg Kroah-Hartman 2018-08-02 08:07:54 +02:00
commit c0f460ffeb
13 changed files with 1560 additions and 43 deletions

View File

@ -209,6 +209,7 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
unsigned int mode, unsigned int channel)
{
int ret;
unsigned long timeout;
ret = ad_sigma_delta_set_channel(sigma_delta, channel);
if (ret)
@ -224,8 +225,8 @@ static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta,
sigma_delta->irq_dis = false;
enable_irq(sigma_delta->spi->irq);
ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ);
if (ret == 0) {
timeout = wait_for_completion_timeout(&sigma_delta->completion, 2 * HZ);
if (timeout == 0) {
sigma_delta->irq_dis = true;
disable_irq_nosync(sigma_delta->spi->irq);
ret = -EIO;

View File

@ -322,6 +322,7 @@ static irqreturn_t xadc_zynq_interrupt_handler(int irq, void *devid)
#define XADC_ZYNQ_TCK_RATE_MAX 50000000
#define XADC_ZYNQ_IGAP_DEFAULT 20
#define XADC_ZYNQ_PCAP_RATE_MAX 200000000
static int xadc_zynq_setup(struct platform_device *pdev,
struct iio_dev *indio_dev, int irq)
@ -332,6 +333,7 @@ static int xadc_zynq_setup(struct platform_device *pdev,
unsigned int div;
unsigned int igap;
unsigned int tck_rate;
int ret;
/* TODO: Figure out how to make igap and tck_rate configurable */
igap = XADC_ZYNQ_IGAP_DEFAULT;
@ -340,6 +342,15 @@ static int xadc_zynq_setup(struct platform_device *pdev,
xadc->zynq_intmask = ~0;
pcap_rate = clk_get_rate(xadc->clk);
if (!pcap_rate)
return -EINVAL;
if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) {
ret = clk_set_rate(xadc->clk,
(unsigned long)XADC_ZYNQ_PCAP_RATE_MAX);
if (ret)
return ret;
}
if (tck_rate > pcap_rate / 2) {
div = 2;
@ -366,6 +377,12 @@ static int xadc_zynq_setup(struct platform_device *pdev,
XADC_ZYNQ_CFG_REDGE | XADC_ZYNQ_CFG_WEDGE |
tck_div | XADC_ZYNQ_CFG_IGAP(igap));
if (pcap_rate > XADC_ZYNQ_PCAP_RATE_MAX) {
ret = clk_set_rate(xadc->clk, pcap_rate);
if (ret)
return ret;
}
return 0;
}
@ -887,6 +904,9 @@ static int xadc_write_raw(struct iio_dev *indio_dev,
unsigned long clk_rate = xadc_get_dclk_rate(xadc);
unsigned int div;
if (!clk_rate)
return -EINVAL;
if (info != IIO_CHAN_INFO_SAMP_FREQ)
return -EINVAL;
@ -1155,6 +1175,7 @@ static int xadc_probe(struct platform_device *pdev)
xadc = iio_priv(indio_dev);
xadc->ops = id->data;
xadc->irq = irq;
init_completion(&xadc->completion);
mutex_init(&xadc->mutex);
spin_lock_init(&xadc->lock);
@ -1205,15 +1226,15 @@ static int xadc_probe(struct platform_device *pdev)
if (ret)
goto err_free_samplerate_trigger;
ret = xadc->ops->setup(pdev, indio_dev, irq);
if (ret)
goto err_clk_disable_unprepare;
ret = request_irq(irq, xadc->ops->interrupt_handler, 0,
ret = request_irq(xadc->irq, xadc->ops->interrupt_handler, 0,
dev_name(&pdev->dev), indio_dev);
if (ret)
goto err_clk_disable_unprepare;
ret = xadc->ops->setup(pdev, indio_dev, xadc->irq);
if (ret)
goto err_free_irq;
for (i = 0; i < 16; i++)
xadc_read_adc_reg(xadc, XADC_REG_THRESHOLD(i),
&xadc->threshold[i]);
@ -1237,8 +1258,10 @@ static int xadc_probe(struct platform_device *pdev)
goto err_free_irq;
/* Disable all alarms */
xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK,
XADC_CONF1_ALARM_MASK);
ret = xadc_update_adc_reg(xadc, XADC_REG_CONF1, XADC_CONF1_ALARM_MASK,
XADC_CONF1_ALARM_MASK);
if (ret)
goto err_free_irq;
/* Set thresholds to min/max */
for (i = 0; i < 16; i++) {
@ -1266,7 +1289,7 @@ static int xadc_probe(struct platform_device *pdev)
return 0;
err_free_irq:
free_irq(irq, indio_dev);
free_irq(xadc->irq, indio_dev);
err_clk_disable_unprepare:
clk_disable_unprepare(xadc->clk);
err_free_samplerate_trigger:
@ -1288,7 +1311,6 @@ static int xadc_remove(struct platform_device *pdev)
{
struct iio_dev *indio_dev = platform_get_drvdata(pdev);
struct xadc *xadc = iio_priv(indio_dev);
int irq = platform_get_irq(pdev, 0);
iio_device_unregister(indio_dev);
if (xadc->ops->flags & XADC_FLAGS_BUFFERED) {
@ -1296,7 +1318,7 @@ static int xadc_remove(struct platform_device *pdev)
iio_trigger_free(xadc->convst_trigger);
iio_triggered_buffer_cleanup(indio_dev);
}
free_irq(irq, indio_dev);
free_irq(xadc->irq, indio_dev);
clk_disable_unprepare(xadc->clk);
cancel_delayed_work(&xadc->zynq_unmask_work);
kfree(xadc->data);

View File

@ -68,6 +68,7 @@ struct xadc {
spinlock_t lock;
struct completion completion;
int irq;
};
struct xadc_ops {

View File

@ -21,6 +21,29 @@ config ATLAS_PH_SENSOR
To compile this driver as module, choose M here: the
module will be called atlas-ph-sensor.
config BME680
tristate "Bosch Sensortec BME680 sensor driver"
depends on (I2C || SPI)
select REGMAP
select BME680_I2C if I2C
select BME680_SPI if SPI
help
Say yes here to build support for Bosch Sensortec BME680 sensor with
temperature, pressure, humidity and gas sensing capability.
This driver can also be built as a module. If so, the module for I2C
would be called bme680_i2c and bme680_spi for SPI support.
config BME680_I2C
tristate
depends on I2C && BME680
select REGMAP_I2C
config BME680_SPI
tristate
depends on SPI && BME680
select REGMAP_SPI
config CCS811
tristate "AMS CCS811 VOC sensor"
depends on I2C

View File

@ -4,6 +4,9 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_ATLAS_PH_SENSOR) += atlas-ph-sensor.o
obj-$(CONFIG_BME680) += bme680_core.o
obj-$(CONFIG_BME680_I2C) += bme680_i2c.o
obj-$(CONFIG_BME680_SPI) += bme680_spi.o
obj-$(CONFIG_CCS811) += ccs811.o
obj-$(CONFIG_IAQCORE) += ams-iaq-core.o
obj-$(CONFIG_VZ89X) += vz89x.o

View File

@ -0,0 +1,96 @@
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef BME680_H_
#define BME680_H_
#define BME680_REG_CHIP_I2C_ID 0xD0
#define BME680_REG_CHIP_SPI_ID 0x50
#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_REG_STATUS 0x73
#define BME680_SPI_MEM_PAGE_BIT BIT(4)
#define BME680_SPI_MEM_PAGE_1_VAL 1
#define BME680_REG_TEMP_MSB 0x22
#define BME680_REG_PRESS_MSB 0x1F
#define BM6880_REG_HUMIDITY_MSB 0x25
#define BME680_REG_GAS_MSB 0x2A
#define BME680_REG_GAS_R_LSB 0x2B
#define BME680_GAS_STAB_BIT BIT(4)
#define BME680_REG_CTRL_HUMIDITY 0x72
#define BME680_OSRS_HUMIDITY_MASK GENMASK(2, 0)
#define BME680_REG_CTRL_MEAS 0x74
#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_REG_CONFIG 0x75
#define BME680_FILTER_MASK GENMASK(4, 2)
#define BME680_FILTER_COEFF_VAL BIT(1)
/* TEMP/PRESS/HUMID reading skipped */
#define BME680_MEAS_SKIPPED 0x8000
#define BME680_MAX_OVERFLOW_VAL 0x40000000
#define BME680_HUM_REG_SHIFT_VAL 4
#define BME680_BIT_H1_DATA_MSK 0x0F
#define BME680_REG_RES_HEAT_RANGE 0x02
#define BME680_RHRANGE_MSK 0x30
#define BME680_REG_RES_HEAT_VAL 0x00
#define BME680_REG_RANGE_SW_ERR 0x04
#define BME680_RSERROR_MSK 0xF0
#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)
/* Calibration Parameters */
#define BME680_T2_LSB_REG 0x8A
#define BME680_T3_REG 0x8C
#define BME680_P1_LSB_REG 0x8E
#define BME680_P2_LSB_REG 0x90
#define BME680_P3_REG 0x92
#define BME680_P4_LSB_REG 0x94
#define BME680_P5_LSB_REG 0x96
#define BME680_P7_REG 0x98
#define BME680_P6_REG 0x99
#define BME680_P8_LSB_REG 0x9C
#define BME680_P9_LSB_REG 0x9E
#define BME680_P10_REG 0xA0
#define BME680_H2_LSB_REG 0xE2
#define BME680_H2_MSB_REG 0xE1
#define BME680_H1_MSB_REG 0xE3
#define BME680_H1_LSB_REG 0xE2
#define BME680_H3_REG 0xE4
#define BME680_H4_REG 0xE5
#define BME680_H5_REG 0xE6
#define BME680_H6_REG 0xE7
#define BME680_H7_REG 0xE8
#define BME680_T1_LSB_REG 0xE9
#define BME680_GH2_LSB_REG 0xEB
#define BME680_GH1_REG 0xED
#define BME680_GH3_REG 0xEE
extern const struct regmap_config bme680_regmap_config;
int bme680_core_probe(struct device *dev, struct regmap *regmap,
const char *name);
#endif /* BME680_H_ */

View File

@ -0,0 +1,959 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Bosch BME680 - Temperature, Pressure, Humidity & Gas Sensor
*
* Copyright (C) 2017 - 2018 Bosch Sensortec GmbH
* Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
*
* Datasheet:
* https://ae-bst.resource.bosch.com/media/_tech/media/datasheets/BST-BME680-DS001-00.pdf
*/
#include <linux/acpi.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 "bme680.h"
struct bme680_calib {
u16 par_t1;
s16 par_t2;
s8 par_t3;
u16 par_p1;
s16 par_p2;
s8 par_p3;
s16 par_p4;
s16 par_p5;
s8 par_p6;
s8 par_p7;
s16 par_p8;
s16 par_p9;
u8 par_p10;
u16 par_h1;
u16 par_h2;
s8 par_h3;
s8 par_h4;
s8 par_h5;
s8 par_h6;
s8 par_h7;
s8 par_gh1;
s16 par_gh2;
s8 par_gh3;
u8 res_heat_range;
s8 res_heat_val;
s8 range_sw_err;
};
struct bme680_data {
struct regmap *regmap;
struct bme680_calib bme680;
u8 oversampling_temp;
u8 oversampling_press;
u8 oversampling_humid;
u16 heater_dur;
u16 heater_temp;
/*
* Carryover value from temperature conversion, used in pressure
* and humidity compensation calculations.
*/
s32 t_fine;
};
const struct regmap_config bme680_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
EXPORT_SYMBOL(bme680_regmap_config);
static const struct iio_chan_spec bme680_channels[] = {
{
.type = IIO_TEMP,
.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) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
},
{
.type = IIO_HUMIDITYRELATIVE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO),
},
{
.type = IIO_RESISTANCE,
.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
},
};
static const int bme680_oversampling_avail[] = { 1, 2, 4, 8, 16 };
static int bme680_read_calib(struct bme680_data *data,
struct bme680_calib *calib)
{
struct device *dev = regmap_get_device(data->regmap);
unsigned int tmp, tmp_msb, tmp_lsb;
int ret;
__le16 buf;
/* Temperature related coefficients */
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);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T2_LSB_REG\n");
return ret;
}
calib->par_t2 = le16_to_cpu(buf);
ret = regmap_read(data->regmap, BME680_T3_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_T3_REG\n");
return ret;
}
calib->par_t3 = tmp;
/* Pressure related coefficients */
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);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P2_LSB_REG\n");
return ret;
}
calib->par_p2 = le16_to_cpu(buf);
ret = regmap_read(data->regmap, BME680_P3_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P3_REG\n");
return ret;
}
calib->par_p3 = tmp;
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);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P5_LSB_REG\n");
return ret;
}
calib->par_p5 = le16_to_cpu(buf);
ret = regmap_read(data->regmap, BME680_P6_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P6_REG\n");
return ret;
}
calib->par_p6 = tmp;
ret = regmap_read(data->regmap, BME680_P7_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P7_REG\n");
return ret;
}
calib->par_p7 = tmp;
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);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P9_LSB_REG\n");
return ret;
}
calib->par_p9 = le16_to_cpu(buf);
ret = regmap_read(data->regmap, BME680_P10_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_P10_REG\n");
return ret;
}
calib->par_p10 = tmp;
/* Humidity related coefficients */
ret = regmap_read(data->regmap, BME680_H1_MSB_REG, &tmp_msb);
if (ret < 0) {
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);
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);
ret = regmap_read(data->regmap, BME680_H3_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H3_REG\n");
return ret;
}
calib->par_h3 = tmp;
ret = regmap_read(data->regmap, BME680_H4_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H4_REG\n");
return ret;
}
calib->par_h4 = tmp;
ret = regmap_read(data->regmap, BME680_H5_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H5_REG\n");
return ret;
}
calib->par_h5 = tmp;
ret = regmap_read(data->regmap, BME680_H6_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H6_REG\n");
return ret;
}
calib->par_h6 = tmp;
ret = regmap_read(data->regmap, BME680_H7_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_H7_REG\n");
return ret;
}
calib->par_h7 = tmp;
/* Gas heater related coefficients */
ret = regmap_read(data->regmap, BME680_GH1_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_GH1_REG\n");
return ret;
}
calib->par_gh1 = tmp;
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;
}
calib->par_gh2 = le16_to_cpu(buf);
ret = regmap_read(data->regmap, BME680_GH3_REG, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read BME680_GH3_REG\n");
return ret;
}
calib->par_gh3 = tmp;
/* Other coefficients */
ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_RANGE, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read resistance heat range\n");
return ret;
}
calib->res_heat_range = (tmp & BME680_RHRANGE_MSK) / 16;
ret = regmap_read(data->regmap, BME680_REG_RES_HEAT_VAL, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read resistance heat value\n");
return ret;
}
calib->res_heat_val = tmp;
ret = regmap_read(data->regmap, BME680_REG_RANGE_SW_ERR, &tmp);
if (ret < 0) {
dev_err(dev, "failed to read range software error\n");
return ret;
}
calib->range_sw_err = (tmp & BME680_RSERROR_MSK) / 16;
return 0;
}
/*
* Taken from Bosch BME680 API:
* https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L876
*
* Returns temperature measurement in DegC, resolutions is 0.01 DegC. Therefore,
* output value of "3233" represents 32.33 DegC.
*/
static s16 bme680_compensate_temp(struct bme680_data *data,
s32 adc_temp)
{
struct bme680_calib *calib = &data->bme680;
s64 var1, var2, var3;
s16 calc_temp;
var1 = (adc_temp >> 3) - (calib->par_t1 << 1);
var2 = (var1 * calib->par_t2) >> 11;
var3 = ((var1 >> 1) * (var1 >> 1)) >> 12;
var3 = (var3 * (calib->par_t3 << 4)) >> 14;
data->t_fine = var2 + var3;
calc_temp = (data->t_fine * 5 + 128) >> 8;
return calc_temp;
}
/*
* Taken from Bosch BME680 API:
* https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L896
*
* Returns pressure measurement in Pa. Output value of "97356" represents
* 97356 Pa = 973.56 hPa.
*/
static u32 bme680_compensate_press(struct bme680_data *data,
u32 adc_press)
{
struct bme680_calib *calib = &data->bme680;
s32 var1, var2, var3, press_comp;
var1 = (data->t_fine >> 1) - 64000;
var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * calib->par_p6) >> 2;
var2 = var2 + (var1 * calib->par_p5 << 1);
var2 = (var2 >> 2) + (calib->par_p4 << 16);
var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) *
(calib->par_p3 << 5)) >> 3) +
((calib->par_p2 * var1) >> 1);
var1 = var1 >> 18;
var1 = ((32768 + var1) * calib->par_p1) >> 15;
press_comp = 1048576 - adc_press;
press_comp = ((press_comp - (var2 >> 12)) * 3125);
if (press_comp >= BME680_MAX_OVERFLOW_VAL)
press_comp = ((press_comp / (u32)var1) << 1);
else
press_comp = ((press_comp << 1) / (u32)var1);
var1 = (calib->par_p9 * (((press_comp >> 3) *
(press_comp >> 3)) >> 13)) >> 12;
var2 = ((press_comp >> 2) * calib->par_p8) >> 13;
var3 = ((press_comp >> 8) * (press_comp >> 8) *
(press_comp >> 8) * calib->par_p10) >> 17;
press_comp += (var1 + var2 + var3 + (calib->par_p7 << 7)) >> 4;
return press_comp;
}
/*
* Taken from Bosch BME680 API:
* https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L937
*
* Returns humidity measurement in percent, resolution is 0.001 percent. Output
* value of "43215" represents 43.215 %rH.
*/
static u32 bme680_compensate_humid(struct bme680_data *data,
u16 adc_humid)
{
struct bme680_calib *calib = &data->bme680;
s32 var1, var2, var3, var4, var5, var6, temp_scaled, calc_hum;
temp_scaled = (data->t_fine * 5 + 128) >> 8;
var1 = (adc_humid - ((s32) ((s32) calib->par_h1 * 16))) -
(((temp_scaled * (s32) calib->par_h3) / 100) >> 1);
var2 = ((s32) calib->par_h2 *
(((temp_scaled * calib->par_h4) / 100) +
(((temp_scaled * ((temp_scaled * calib->par_h5) / 100))
>> 6) / 100) + (1 << 14))) >> 10;
var3 = var1 * var2;
var4 = calib->par_h6 << 7;
var4 = (var4 + ((temp_scaled * calib->par_h7) / 100)) >> 4;
var5 = ((var3 >> 14) * (var3 >> 14)) >> 10;
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;
return calc_hum;
}
/*
* Taken from Bosch BME680 API:
* https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L973
*
* Returns gas measurement in Ohm. Output value of "82986" represent 82986 ohms.
*/
static u32 bme680_compensate_gas(struct bme680_data *data, u16 gas_res_adc,
u8 gas_range)
{
struct bme680_calib *calib = &data->bme680;
s64 var1;
u64 var2;
s64 var3;
u32 calc_gas_res;
/* Look up table for the possible gas range values */
const u32 lookupTable[16] = {2147483647u, 2147483647u,
2147483647u, 2147483647u, 2147483647u,
2126008810u, 2147483647u, 2130303777u,
2147483647u, 2147483647u, 2143188679u,
2136746228u, 2147483647u, 2126008810u,
2147483647u, 2147483647u};
var1 = ((1340 + (5 * (s64) calib->range_sw_err)) *
((s64) lookupTable[gas_range])) >> 16;
var2 = ((gas_res_adc << 15) - 16777216) + var1;
var3 = ((125000 << (15 - gas_range)) * var1) >> 9;
var3 += (var2 >> 1);
calc_gas_res = div64_s64(var3, (s64) var2);
return calc_gas_res;
}
/*
* Taken from Bosch BME680 API:
* https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L1002
*/
static u8 bme680_calc_heater_res(struct bme680_data *data, u16 temp)
{
struct bme680_calib *calib = &data->bme680;
s32 var1, var2, var3, var4, var5, heatr_res_x100;
u8 heatr_res;
if (temp > 400) /* Cap temperature */
temp = 400;
var1 = (((s32) BME680_AMB_TEMP * calib->par_gh3) / 1000) * 256;
var2 = (calib->par_gh1 + 784) * (((((calib->par_gh2 + 154009) *
temp * 5) / 100)
+ 3276800) / 10);
var3 = var1 + (var2 / 2);
var4 = (var3 / (calib->res_heat_range + 4));
var5 = 131 * calib->res_heat_val + 65536;
heatr_res_x100 = ((var4 / var5) - 250) * 34;
heatr_res = (heatr_res_x100 + 50) / 100;
return heatr_res;
}
/*
* Taken from Bosch BME680 API:
* https://github.com/BoschSensortec/BME680_driver/blob/63bb5336/bme680.c#L1188
*/
static u8 bme680_calc_heater_dur(u16 dur)
{
u8 durval, factor = 0;
if (dur >= 0xfc0) {
durval = 0xff; /* Max duration */
} else {
while (dur > 0x3F) {
dur = dur / 4;
factor += 1;
}
durval = dur + (factor * 64);
}
return durval;
}
static int bme680_set_mode(struct bme680_data *data, bool mode)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
if (mode) {
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_MODE_MASK, BME680_MODE_FORCED);
if (ret < 0)
dev_err(dev, "failed to set forced mode\n");
} else {
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_MODE_MASK, BME680_MODE_SLEEP);
if (ret < 0)
dev_err(dev, "failed to set sleep mode\n");
}
return ret;
}
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);
/*
* Highly recommended to set oversampling of humidity before
* temperature/pressure oversampling.
*/
ret = regmap_update_bits(data->regmap, BME680_REG_CTRL_HUMIDITY,
BME680_OSRS_HUMIDITY_MASK, osrs);
if (ret < 0) {
dev_err(dev, "failed to write ctrl_hum register\n");
return ret;
}
/* IIR filter settings */
ret = regmap_update_bits(data->regmap, BME680_REG_CONFIG,
BME680_FILTER_MASK,
BME680_FILTER_COEFF_VAL);
if (ret < 0) {
dev_err(dev, "failed to write config register\n");
return ret;
}
osrs = FIELD_PREP(BME680_OSRS_TEMP_MASK, data->oversampling_temp + 1) |
FIELD_PREP(BME680_OSRS_PRESS_MASK, data->oversampling_press + 1);
ret = regmap_write_bits(data->regmap, BME680_REG_CTRL_MEAS,
BME680_OSRS_TEMP_MASK |
BME680_OSRS_PRESS_MASK,
osrs);
if (ret < 0)
dev_err(dev, "failed to write ctrl_meas register\n");
return ret;
}
static int bme680_gas_config(struct bme680_data *data)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
u8 heatr_res, heatr_dur;
heatr_res = bme680_calc_heater_res(data, data->heater_temp);
/* set target heater temperature */
ret = regmap_write(data->regmap, BME680_REG_RES_HEAT_0, heatr_res);
if (ret < 0) {
dev_err(dev, "failed to write res_heat_0 register\n");
return ret;
}
heatr_dur = bme680_calc_heater_dur(data->heater_dur);
/* 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");
return ret;
}
/* Selecting the runGas and NB conversion settings for the sensor */
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);
if (ret < 0)
dev_err(dev, "failed to write ctrl_gas_1 register\n");
return ret;
}
static int bme680_read_temp(struct bme680_data *data,
int *val, int *val2)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
__be32 tmp = 0;
s32 adc_temp;
s16 comp_temp;
/* set forced mode to trigger measurement */
ret = bme680_set_mode(data, true);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, BME680_REG_TEMP_MSB,
(u8 *) &tmp, 3);
if (ret < 0) {
dev_err(dev, "failed to read temperature\n");
return ret;
}
adc_temp = be32_to_cpu(tmp) >> 12;
if (adc_temp == BME680_MEAS_SKIPPED) {
/* reading was skipped */
dev_err(dev, "reading temperature skipped\n");
return -EINVAL;
}
comp_temp = bme680_compensate_temp(data, adc_temp);
/*
* val might be NULL if we're called by the read_press/read_humid
* routine which is callled to get t_fine value used in
* compensate_press/compensate_humid to get compensated
* pressure/humidity readings.
*/
if (val && val2) {
*val = comp_temp;
*val2 = 100;
return IIO_VAL_FRACTIONAL;
}
return ret;
}
static int bme680_read_press(struct bme680_data *data,
int *val, int *val2)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
__be32 tmp = 0;
s32 adc_press;
/* Read and compensate temperature to get a reading of t_fine */
ret = bme680_read_temp(data, NULL, NULL);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, BME680_REG_PRESS_MSB,
(u8 *) &tmp, 3);
if (ret < 0) {
dev_err(dev, "failed to read pressure\n");
return ret;
}
adc_press = be32_to_cpu(tmp) >> 12;
if (adc_press == BME680_MEAS_SKIPPED) {
/* reading was skipped */
dev_err(dev, "reading pressure skipped\n");
return -EINVAL;
}
*val = bme680_compensate_press(data, adc_press);
*val2 = 100;
return IIO_VAL_FRACTIONAL;
}
static int bme680_read_humid(struct bme680_data *data,
int *val, int *val2)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
__be16 tmp = 0;
s32 adc_humidity;
u32 comp_humidity;
/* Read and compensate temperature to get a reading of t_fine */
ret = bme680_read_temp(data, NULL, NULL);
if (ret < 0)
return ret;
ret = regmap_bulk_read(data->regmap, BM6880_REG_HUMIDITY_MSB,
(u8 *) &tmp, 2);
if (ret < 0) {
dev_err(dev, "failed to read humidity\n");
return ret;
}
adc_humidity = be16_to_cpu(tmp);
if (adc_humidity == BME680_MEAS_SKIPPED) {
/* reading was skipped */
dev_err(dev, "reading humidity skipped\n");
return -EINVAL;
}
comp_humidity = bme680_compensate_humid(data, adc_humidity);
*val = comp_humidity;
*val2 = 1000;
return IIO_VAL_FRACTIONAL;
}
static int bme680_read_gas(struct bme680_data *data,
int *val)
{
struct device *dev = regmap_get_device(data->regmap);
int ret;
__be16 tmp = 0;
unsigned int check;
u16 adc_gas_res;
u8 gas_range;
/* Set heater settings */
ret = bme680_gas_config(data);
if (ret < 0) {
dev_err(dev, "failed to set gas config\n");
return ret;
}
/* set forced mode to trigger measurement */
ret = bme680_set_mode(data, true);
if (ret < 0)
return ret;
ret = regmap_read(data->regmap, BME680_REG_MEAS_STAT_0, &check);
if (check & BME680_GAS_MEAS_BIT) {
dev_err(dev, "gas measurement incomplete\n");
return -EBUSY;
}
ret = regmap_read(data->regmap, BME680_REG_GAS_R_LSB, &check);
if (ret < 0) {
dev_err(dev, "failed to read gas_r_lsb register\n");
return ret;
}
/*
* occurs if either the gas heating duration was insuffient
* to reach the target heater temperature or the target
* heater temperature was too high for the heater sink to
* reach.
*/
if ((check & BME680_GAS_STAB_BIT) == 0) {
dev_err(dev, "heater failed to reach the target temperature\n");
return -EINVAL;
}
ret = regmap_bulk_read(data->regmap, BME680_REG_GAS_MSB,
(u8 *) &tmp, 2);
if (ret < 0) {
dev_err(dev, "failed to read gas resistance\n");
return ret;
}
gas_range = check & BME680_GAS_RANGE_MASK;
adc_gas_res = be16_to_cpu(tmp) >> BME680_ADC_GAS_RES_SHIFT;
*val = bme680_compensate_gas(data, adc_gas_res, gas_range);
return IIO_VAL_INT;
}
static int bme680_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val, int *val2, long mask)
{
struct bme680_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_PROCESSED:
switch (chan->type) {
case IIO_TEMP:
return bme680_read_temp(data, val, val2);
case IIO_PRESSURE:
return bme680_read_press(data, val, val2);
case IIO_HUMIDITYRELATIVE:
return bme680_read_humid(data, val, val2);
case IIO_RESISTANCE:
return bme680_read_gas(data, val);
default:
return -EINVAL;
}
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_TEMP:
*val = 1 << data->oversampling_temp;
return IIO_VAL_INT;
case IIO_PRESSURE:
*val = 1 << data->oversampling_press;
return IIO_VAL_INT;
case IIO_HUMIDITYRELATIVE:
*val = 1 << data->oversampling_humid;
return IIO_VAL_INT;
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static int bme680_write_oversampling_ratio_temp(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_temp = ilog2(val);
return bme680_chip_config(data);
}
}
return -EINVAL;
}
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;
}
static int bme680_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct bme680_data *data = iio_priv(indio_dev);
switch (mask) {
case IIO_CHAN_INFO_OVERSAMPLING_RATIO:
switch (chan->type) {
case IIO_TEMP:
return bme680_write_oversampling_ratio_temp(data, val);
case IIO_PRESSURE:
return bme680_write_oversampling_ratio_press(data, val);
case IIO_HUMIDITYRELATIVE:
return bme680_write_oversampling_ratio_humid(data, val);
default:
return -EINVAL;
}
default:
return -EINVAL;
}
}
static const char bme680_oversampling_ratio_show[] = "1 2 4 8 16";
static IIO_CONST_ATTR(oversampling_ratio_available,
bme680_oversampling_ratio_show);
static struct attribute *bme680_attributes[] = {
&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
NULL,
};
static const struct attribute_group bme680_attribute_group = {
.attrs = bme680_attributes,
};
static const struct iio_info bme680_info = {
.read_raw = &bme680_read_raw,
.write_raw = &bme680_write_raw,
.attrs = &bme680_attribute_group,
};
static const char *bme680_match_acpi_device(struct device *dev)
{
const struct acpi_device_id *id;
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
return dev_name(dev);
}
int bme680_core_probe(struct device *dev, struct regmap *regmap,
const char *name)
{
struct iio_dev *indio_dev;
struct bme680_data *data;
int ret;
indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
if (!indio_dev)
return -ENOMEM;
if (!name && ACPI_HANDLE(dev))
name = bme680_match_acpi_device(dev);
data = iio_priv(indio_dev);
dev_set_drvdata(dev, indio_dev);
data->regmap = regmap;
indio_dev->dev.parent = dev;
indio_dev->name = name;
indio_dev->channels = bme680_channels;
indio_dev->num_channels = ARRAY_SIZE(bme680_channels);
indio_dev->info = &bme680_info;
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->heater_temp = 320; /* degree Celsius */
data->heater_dur = 150; /* milliseconds */
ret = bme680_chip_config(data);
if (ret < 0) {
dev_err(dev, "failed to set chip_config data\n");
return ret;
}
ret = bme680_gas_config(data);
if (ret < 0) {
dev_err(dev, "failed to set gas config data\n");
return ret;
}
ret = bme680_read_calib(data, &data->bme680);
if (ret < 0) {
dev_err(dev,
"failed to read calibration coefficients at probe\n");
return ret;
}
return devm_iio_device_register(dev, indio_dev);
}
EXPORT_SYMBOL_GPL(bme680_core_probe);
MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
MODULE_DESCRIPTION("Bosch BME680 Driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,85 @@
// SPDX-License-Identifier: GPL-2.0
/*
* BME680 - I2C Driver
*
* Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
*
* 7-Bit I2C slave address is:
* - 0x76 if SDO is pulled to GND
* - 0x77 if SDO is pulled to VDDIO
*
* Note: SDO pin cannot be left floating otherwise I2C address
* will be undefined.
*/
#include <linux/acpi.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include "bme680.h"
static int bme680_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct regmap *regmap;
const char *name = NULL;
unsigned int val;
int ret;
regmap = devm_regmap_init_i2c(client, &bme680_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&client->dev, "Failed to register i2c regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
ret = regmap_write(regmap, BME680_REG_SOFT_RESET_I2C,
BME680_CMD_SOFTRESET);
if (ret < 0) {
dev_err(&client->dev, "Failed to reset chip\n");
return ret;
}
ret = regmap_read(regmap, BME680_REG_CHIP_I2C_ID, &val);
if (ret < 0) {
dev_err(&client->dev, "Error reading I2C chip ID\n");
return ret;
}
if (val != BME680_CHIP_ID_VAL) {
dev_err(&client->dev, "Wrong chip ID, got %x expected %x\n",
val, BME680_CHIP_ID_VAL);
return -ENODEV;
}
if (id)
name = id->name;
return bme680_core_probe(&client->dev, regmap, name);
}
static const struct i2c_device_id bme680_i2c_id[] = {
{"bme680", 0},
{},
};
MODULE_DEVICE_TABLE(i2c, bme680_i2c_id);
static const struct acpi_device_id bme680_acpi_match[] = {
{"BME0680", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
static struct i2c_driver bme680_i2c_driver = {
.driver = {
.name = "bme680_i2c",
.acpi_match_table = ACPI_PTR(bme680_acpi_match),
},
.probe = bme680_i2c_probe,
.id_table = bme680_i2c_id,
};
module_i2c_driver(bme680_i2c_driver);
MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
MODULE_DESCRIPTION("BME680 I2C driver");
MODULE_LICENSE("GPL v2");

View File

@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0
/*
* BME680 - SPI Driver
*
* Copyright (C) 2018 Himanshu Jha <himanshujha199640@gmail.com>
*/
#include <linux/acpi.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/spi/spi.h>
#include "bme680.h"
static int bme680_regmap_spi_write(void *context, const void *data,
size_t count)
{
struct spi_device *spi = context;
u8 buf[2];
memcpy(buf, data, 2);
/*
* The SPI register address (= full register address without bit 7)
* and the write command (bit7 = RW = '0')
*/
buf[0] &= ~0x80;
return spi_write_then_read(spi, buf, 2, NULL, 0);
}
static int bme680_regmap_spi_read(void *context, const void *reg,
size_t reg_size, void *val, size_t val_size)
{
struct spi_device *spi = context;
return spi_write_then_read(spi, reg, reg_size, val, val_size);
}
static struct regmap_bus bme680_regmap_bus = {
.write = bme680_regmap_spi_write,
.read = bme680_regmap_spi_read,
.reg_format_endian_default = REGMAP_ENDIAN_BIG,
.val_format_endian_default = REGMAP_ENDIAN_BIG,
};
static int bme680_spi_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct regmap *regmap;
unsigned int val;
int ret;
spi->bits_per_word = 8;
ret = spi_setup(spi);
if (ret < 0) {
dev_err(&spi->dev, "spi_setup failed!\n");
return ret;
}
regmap = devm_regmap_init(&spi->dev, &bme680_regmap_bus,
&spi->dev, &bme680_regmap_config);
if (IS_ERR(regmap)) {
dev_err(&spi->dev, "Failed to register spi regmap %d\n",
(int)PTR_ERR(regmap));
return PTR_ERR(regmap);
}
ret = regmap_write(regmap, BME680_REG_SOFT_RESET_SPI,
BME680_CMD_SOFTRESET);
if (ret < 0) {
dev_err(&spi->dev, "Failed to reset chip\n");
return ret;
}
/* after power-on reset, Page 0(0x80-0xFF) of spi_mem_page is active */
ret = regmap_read(regmap, BME680_REG_CHIP_SPI_ID, &val);
if (ret < 0) {
dev_err(&spi->dev, "Error reading SPI chip ID\n");
return ret;
}
if (val != BME680_CHIP_ID_VAL) {
dev_err(&spi->dev, "Wrong chip ID, got %x expected %x\n",
val, BME680_CHIP_ID_VAL);
return -ENODEV;
}
/*
* select Page 1 of spi_mem_page to enable access to
* to registers from address 0x00 to 0x7F.
*/
ret = regmap_write_bits(regmap, BME680_REG_STATUS,
BME680_SPI_MEM_PAGE_BIT,
BME680_SPI_MEM_PAGE_1_VAL);
if (ret < 0) {
dev_err(&spi->dev, "failed to set page 1 of spi_mem_page\n");
return ret;
}
return bme680_core_probe(&spi->dev, regmap, id->name);
}
static const struct spi_device_id bme680_spi_id[] = {
{"bme680", 0},
{},
};
MODULE_DEVICE_TABLE(spi, bme680_spi_id);
static const struct acpi_device_id bme680_acpi_match[] = {
{"BME0680", 0},
{},
};
MODULE_DEVICE_TABLE(acpi, bme680_acpi_match);
static struct spi_driver bme680_spi_driver = {
.driver = {
.name = "bme680_spi",
.acpi_match_table = ACPI_PTR(bme680_acpi_match),
},
.probe = bme680_spi_probe,
.id_table = bme680_spi_id,
};
module_spi_driver(bme680_spi_driver);
MODULE_AUTHOR("Himanshu Jha <himanshujha199640@gmail.com>");
MODULE_DESCRIPTION("Bosch BME680 SPI driver");
MODULE_LICENSE("GPL v2");

View File

@ -12,6 +12,7 @@
#include <linux/sysfs.h>
#include <linux/spi/spi.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio/consumer.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/delay.h>
@ -268,6 +269,9 @@ struct ad9523_state {
struct regulator *reg;
struct ad9523_platform_data *pdata;
struct iio_chan_spec ad9523_channels[AD9523_NUM_CHAN];
struct gpio_desc *pwrdown_gpio;
struct gpio_desc *reset_gpio;
struct gpio_desc *sync_gpio;
unsigned long vcxo_freq;
unsigned long vco_freq;
@ -518,7 +522,7 @@ static ssize_t ad9523_store(struct device *dev,
return ret;
if (!state)
return 0;
return len;
mutex_lock(&st->lock);
switch ((u32)this_attr->address) {
@ -988,6 +992,32 @@ static int ad9523_probe(struct spi_device *spi)
return ret;
}
st->pwrdown_gpio = devm_gpiod_get_optional(&spi->dev, "powerdown",
GPIOD_OUT_HIGH);
if (IS_ERR(st->pwrdown_gpio)) {
ret = PTR_ERR(st->pwrdown_gpio);
goto error_disable_reg;
}
st->reset_gpio = devm_gpiod_get_optional(&spi->dev, "reset",
GPIOD_OUT_LOW);
if (IS_ERR(st->reset_gpio)) {
ret = PTR_ERR(st->reset_gpio);
goto error_disable_reg;
}
if (st->reset_gpio) {
udelay(1);
gpiod_direction_output(st->reset_gpio, 1);
}
st->sync_gpio = devm_gpiod_get_optional(&spi->dev, "sync",
GPIOD_OUT_HIGH);
if (IS_ERR(st->sync_gpio)) {
ret = PTR_ERR(st->sync_gpio);
goto error_disable_reg;
}
spi_set_drvdata(spi, indio_dev);
st->spi = spi;
st->pdata = pdata;

View File

@ -450,11 +450,12 @@ config US5182D
will be called us5182d.
config VCNL4000
tristate "VCNL4000/4010/4020 combined ALS and proximity sensor"
tristate "VCNL4000/4010/4020/4200 combined ALS and proximity sensor"
depends on I2C
help
Say Y here if you want to build a driver for the Vishay VCNL4000,
VCNL4010, VCNL4020 combined ambient light and proximity sensor.
VCNL4010, VCNL4020, VCNL4200 combined ambient light and proximity
sensor.
To compile this driver as a module, choose M here: the
module will be called vcnl4000.

View File

@ -409,6 +409,9 @@ static int si1133_command(struct si1133_data *data, u8 cmd)
err = -ETIMEDOUT;
goto out;
}
err = regmap_read(data->regmap, SI1133_REG_RESPONSE0, &resp);
if (err)
goto out;
} else {
err = regmap_read_poll_timeout(data->regmap,
SI1133_REG_RESPONSE0, resp,
@ -838,7 +841,7 @@ static int si1133_write_raw(struct iio_dev *iio_dev,
switch (chan->type) {
case IIO_INTENSITY:
case IIO_UVINDEX:
if (val != 0 || val != 1)
if (val != 0 && val != 1)
return -EINVAL;
return si1133_update_adcsens(data,

View File

@ -1,5 +1,5 @@
/*
* vcnl4000.c - Support for Vishay VCNL4000/4010/4020 combined ambient
* vcnl4000.c - Support for Vishay VCNL4000/4010/4020/4200 combined ambient
* light and proximity sensor
*
* Copyright 2012 Peter Meerwald <pmeerw@pmeerw.net>
@ -8,13 +8,15 @@
* the GNU General Public License. See the file COPYING in the main
* directory of this archive for more details.
*
* IIO driver for VCNL4000 (7-bit I2C slave address 0x13)
* IIO driver for:
* VCNL4000/10/20 (7-bit I2C slave address 0x13)
* VCNL4200 (7-bit I2C slave address 0x51)
*
* TODO:
* allow to adjust IR current
* proximity threshold and event handling
* periodic ALS/proximity measurement (VCNL4010/20)
* interrupts (VCNL4010/20)
* interrupts (VCNL4010/20, VCNL4200)
*/
#include <linux/module.h>
@ -26,8 +28,9 @@
#include <linux/iio/sysfs.h>
#define VCNL4000_DRV_NAME "vcnl4000"
#define VCNL4000_ID 0x01
#define VCNL4010_ID 0x02 /* for VCNL4020, VCNL4010 */
#define VCNL4000_PROD_ID 0x01
#define VCNL4010_PROD_ID 0x02 /* for VCNL4020, VCNL4010 */
#define VCNL4200_PROD_ID 0x58
#define VCNL4000_COMMAND 0x80 /* Command register */
#define VCNL4000_PROD_REV 0x81 /* Product ID and Revision ID */
@ -40,23 +43,124 @@
#define VCNL4000_PS_MEAS_FREQ 0x89 /* Proximity test signal frequency */
#define VCNL4000_PS_MOD_ADJ 0x8a /* Proximity modulator timing adjustment */
#define VCNL4200_AL_CONF 0x00 /* Ambient light configuration */
#define VCNL4200_PS_CONF1 0x03 /* Proximity configuration */
#define VCNL4200_PS_DATA 0x08 /* Proximity data */
#define VCNL4200_AL_DATA 0x09 /* Ambient light data */
#define VCNL4200_DEV_ID 0x0e /* Device ID, slave address and version */
/* Bit masks for COMMAND register */
#define VCNL4000_AL_RDY BIT(6) /* ALS data ready? */
#define VCNL4000_PS_RDY BIT(5) /* proximity data ready? */
#define VCNL4000_AL_OD BIT(4) /* start on-demand ALS measurement */
#define VCNL4000_PS_OD BIT(3) /* start on-demand proximity measurement */
struct vcnl4000_data {
struct i2c_client *client;
enum vcnl4000_device_ids {
VCNL4000,
VCNL4010,
VCNL4200,
};
struct vcnl4200_channel {
u8 reg;
ktime_t last_measurement;
ktime_t sampling_rate;
struct mutex lock;
};
struct vcnl4000_data {
struct i2c_client *client;
enum vcnl4000_device_ids id;
int rev;
int al_scale;
const struct vcnl4000_chip_spec *chip_spec;
struct mutex vcnl4000_lock;
struct vcnl4200_channel vcnl4200_al;
struct vcnl4200_channel vcnl4200_ps;
};
struct vcnl4000_chip_spec {
const char *prod;
int (*init)(struct vcnl4000_data *data);
int (*measure_light)(struct vcnl4000_data *data, int *val);
int (*measure_proximity)(struct vcnl4000_data *data, int *val);
};
static const struct i2c_device_id vcnl4000_id[] = {
{ "vcnl4000", 0 },
{ "vcnl4000", VCNL4000 },
{ "vcnl4010", VCNL4010 },
{ "vcnl4020", VCNL4010 },
{ "vcnl4200", VCNL4200 },
{ }
};
MODULE_DEVICE_TABLE(i2c, vcnl4000_id);
static int vcnl4000_init(struct vcnl4000_data *data)
{
int ret, prod_id;
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
if (ret < 0)
return ret;
prod_id = ret >> 4;
switch (prod_id) {
case VCNL4000_PROD_ID:
if (data->id != VCNL4000)
dev_warn(&data->client->dev,
"wrong device id, use vcnl4000");
break;
case VCNL4010_PROD_ID:
if (data->id != VCNL4010)
dev_warn(&data->client->dev,
"wrong device id, use vcnl4010/4020");
break;
default:
return -ENODEV;
}
data->rev = ret & 0xf;
data->al_scale = 250000;
mutex_init(&data->vcnl4000_lock);
return 0;
};
static int vcnl4200_init(struct vcnl4000_data *data)
{
int ret;
ret = i2c_smbus_read_word_data(data->client, VCNL4200_DEV_ID);
if (ret < 0)
return ret;
if ((ret & 0xff) != VCNL4200_PROD_ID)
return -ENODEV;
data->rev = (ret >> 8) & 0xf;
/* Set defaults and enable both channels */
ret = i2c_smbus_write_byte_data(data->client, VCNL4200_AL_CONF, 0x00);
if (ret < 0)
return ret;
ret = i2c_smbus_write_byte_data(data->client, VCNL4200_PS_CONF1, 0x00);
if (ret < 0)
return ret;
data->al_scale = 24000;
data->vcnl4200_al.reg = VCNL4200_AL_DATA;
data->vcnl4200_ps.reg = VCNL4200_PS_DATA;
/* Integration time is 50ms, but the experiments show 54ms in total. */
data->vcnl4200_al.sampling_rate = ktime_set(0, 54000 * 1000);
data->vcnl4200_ps.sampling_rate = ktime_set(0, 4200 * 1000);
data->vcnl4200_al.last_measurement = ktime_set(0, 0);
data->vcnl4200_ps.last_measurement = ktime_set(0, 0);
mutex_init(&data->vcnl4200_al.lock);
mutex_init(&data->vcnl4200_ps.lock);
return 0;
};
static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
u8 rdy_mask, u8 data_reg, int *val)
{
@ -64,7 +168,7 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
__be16 buf;
int ret;
mutex_lock(&data->lock);
mutex_lock(&data->vcnl4000_lock);
ret = i2c_smbus_write_byte_data(data->client, VCNL4000_COMMAND,
req_mask);
@ -93,16 +197,88 @@ static int vcnl4000_measure(struct vcnl4000_data *data, u8 req_mask,
if (ret < 0)
goto fail;
mutex_unlock(&data->lock);
mutex_unlock(&data->vcnl4000_lock);
*val = be16_to_cpu(buf);
return 0;
fail:
mutex_unlock(&data->lock);
mutex_unlock(&data->vcnl4000_lock);
return ret;
}
static int vcnl4200_measure(struct vcnl4000_data *data,
struct vcnl4200_channel *chan, int *val)
{
int ret;
s64 delta;
ktime_t next_measurement;
mutex_lock(&chan->lock);
next_measurement = ktime_add(chan->last_measurement,
chan->sampling_rate);
delta = ktime_us_delta(next_measurement, ktime_get());
if (delta > 0)
usleep_range(delta, delta + 500);
chan->last_measurement = ktime_get();
mutex_unlock(&chan->lock);
ret = i2c_smbus_read_word_data(data->client, chan->reg);
if (ret < 0)
return ret;
*val = ret;
return 0;
}
static int vcnl4000_measure_light(struct vcnl4000_data *data, int *val)
{
return vcnl4000_measure(data,
VCNL4000_AL_OD, VCNL4000_AL_RDY,
VCNL4000_AL_RESULT_HI, val);
}
static int vcnl4200_measure_light(struct vcnl4000_data *data, int *val)
{
return vcnl4200_measure(data, &data->vcnl4200_al, val);
}
static int vcnl4000_measure_proximity(struct vcnl4000_data *data, int *val)
{
return vcnl4000_measure(data,
VCNL4000_PS_OD, VCNL4000_PS_RDY,
VCNL4000_PS_RESULT_HI, val);
}
static int vcnl4200_measure_proximity(struct vcnl4000_data *data, int *val)
{
return vcnl4200_measure(data, &data->vcnl4200_ps, val);
}
static const struct vcnl4000_chip_spec vcnl4000_chip_spec_cfg[] = {
[VCNL4000] = {
.prod = "VCNL4000",
.init = vcnl4000_init,
.measure_light = vcnl4000_measure_light,
.measure_proximity = vcnl4000_measure_proximity,
},
[VCNL4010] = {
.prod = "VCNL4010/4020",
.init = vcnl4000_init,
.measure_light = vcnl4000_measure_light,
.measure_proximity = vcnl4000_measure_proximity,
},
[VCNL4200] = {
.prod = "VCNL4200",
.init = vcnl4200_init,
.measure_light = vcnl4200_measure_light,
.measure_proximity = vcnl4200_measure_proximity,
},
};
static const struct iio_chan_spec vcnl4000_channels[] = {
{
.type = IIO_LIGHT,
@ -125,16 +301,12 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
case IIO_CHAN_INFO_RAW:
switch (chan->type) {
case IIO_LIGHT:
ret = vcnl4000_measure(data,
VCNL4000_AL_OD, VCNL4000_AL_RDY,
VCNL4000_AL_RESULT_HI, val);
ret = data->chip_spec->measure_light(data, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
case IIO_PROXIMITY:
ret = vcnl4000_measure(data,
VCNL4000_PS_OD, VCNL4000_PS_RDY,
VCNL4000_PS_RESULT_HI, val);
ret = data->chip_spec->measure_proximity(data, val);
if (ret < 0)
return ret;
return IIO_VAL_INT;
@ -146,7 +318,7 @@ static int vcnl4000_read_raw(struct iio_dev *indio_dev,
return -EINVAL;
*val = 0;
*val2 = 250000;
*val2 = data->al_scale;
return IIO_VAL_INT_PLUS_MICRO;
default:
return -EINVAL;
@ -162,7 +334,7 @@ static int vcnl4000_probe(struct i2c_client *client,
{
struct vcnl4000_data *data;
struct iio_dev *indio_dev;
int ret, prod_id;
int ret;
indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
if (!indio_dev)
@ -171,19 +343,15 @@ static int vcnl4000_probe(struct i2c_client *client,
data = iio_priv(indio_dev);
i2c_set_clientdata(client, indio_dev);
data->client = client;
mutex_init(&data->lock);
data->id = id->driver_data;
data->chip_spec = &vcnl4000_chip_spec_cfg[data->id];
ret = i2c_smbus_read_byte_data(data->client, VCNL4000_PROD_REV);
ret = data->chip_spec->init(data);
if (ret < 0)
return ret;
prod_id = ret >> 4;
if (prod_id != VCNL4010_ID && prod_id != VCNL4000_ID)
return -ENODEV;
dev_dbg(&client->dev, "%s Ambient light/proximity sensor, Rev: %02x\n",
(prod_id == VCNL4010_ID) ? "VCNL4010/4020" : "VCNL4000",
ret & 0xf);
data->chip_spec->prod, data->rev);
indio_dev->dev.parent = &client->dev;
indio_dev->info = &vcnl4000_info;