iio: chemical: ens160: add triggered buffer support
ENS160 supports a data ready interrupt. Use it in combination with triggered buffer for continuous data readings. Signed-off-by: Gustavo Silva <gustavograzs@gmail.com> Link: https://lore.kernel.org/r/20240604225747.7212-5-gustavograzs@gmail.com Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
This commit is contained in:
parent
e3166508a1
commit
0fc26596b4
@ -2,6 +2,6 @@
|
||||
#ifndef ENS160_H_
|
||||
#define ENS160_H_
|
||||
|
||||
int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
|
||||
int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
const char *name);
|
||||
#endif
|
||||
|
@ -10,6 +10,9 @@
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/iio/iio.h>
|
||||
#include <linux/iio/trigger.h>
|
||||
#include <linux/iio/trigger_consumer.h>
|
||||
#include <linux/iio/triggered_buffer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/regmap.h>
|
||||
|
||||
@ -23,6 +26,11 @@
|
||||
|
||||
#define ENS160_REG_OPMODE 0x10
|
||||
|
||||
#define ENS160_REG_CONFIG 0x11
|
||||
#define ENS160_REG_CONFIG_INTEN BIT(0)
|
||||
#define ENS160_REG_CONFIG_INTDAT BIT(1)
|
||||
#define ENS160_REG_CONFIG_INT_CFG BIT(5)
|
||||
|
||||
#define ENS160_REG_MODE_DEEP_SLEEP 0x00
|
||||
#define ENS160_REG_MODE_IDLE 0x01
|
||||
#define ENS160_REG_MODE_STANDARD 0x02
|
||||
@ -48,7 +56,13 @@
|
||||
|
||||
struct ens160_data {
|
||||
struct regmap *regmap;
|
||||
u8 fw_version[3] __aligned(IIO_DMA_MINALIGN);
|
||||
/* Protect reads from the sensor */
|
||||
struct mutex mutex;
|
||||
struct {
|
||||
__le16 chans[2];
|
||||
s64 timestamp __aligned(8);
|
||||
} scan __aligned(IIO_DMA_MINALIGN);
|
||||
u8 fw_version[3];
|
||||
__le16 buf;
|
||||
};
|
||||
|
||||
@ -60,6 +74,13 @@ static const struct iio_chan_spec ens160_channels[] = {
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = ENS160_REG_DATA_TVOC,
|
||||
.scan_index = 0,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
},
|
||||
{
|
||||
.type = IIO_CONCENTRATION,
|
||||
@ -68,7 +89,15 @@ static const struct iio_chan_spec ens160_channels[] = {
|
||||
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
|
||||
BIT(IIO_CHAN_INFO_SCALE),
|
||||
.address = ENS160_REG_DATA_ECO2,
|
||||
.scan_index = 1,
|
||||
.scan_type = {
|
||||
.sign = 'u',
|
||||
.realbits = 16,
|
||||
.storagebits = 16,
|
||||
.endianness = IIO_LE,
|
||||
},
|
||||
},
|
||||
IIO_CHAN_SOFT_TIMESTAMP(2),
|
||||
};
|
||||
|
||||
static int ens160_read_raw(struct iio_dev *indio_dev,
|
||||
@ -80,13 +109,16 @@ static int ens160_read_raw(struct iio_dev *indio_dev,
|
||||
|
||||
switch (mask) {
|
||||
case IIO_CHAN_INFO_RAW:
|
||||
ret = regmap_bulk_read(data->regmap, chan->address,
|
||||
&data->buf, sizeof(data->buf));
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = le16_to_cpu(data->buf);
|
||||
return IIO_VAL_INT;
|
||||
|
||||
iio_device_claim_direct_scoped(return -EBUSY, indio_dev) {
|
||||
guard(mutex)(&data->mutex);
|
||||
ret = regmap_bulk_read(data->regmap, chan->address,
|
||||
&data->buf, sizeof(data->buf));
|
||||
if (ret)
|
||||
return ret;
|
||||
*val = le16_to_cpu(data->buf);
|
||||
return IIO_VAL_INT;
|
||||
}
|
||||
unreachable();
|
||||
case IIO_CHAN_INFO_SCALE:
|
||||
switch (chan->channel2) {
|
||||
case IIO_MOD_CO2:
|
||||
@ -188,7 +220,83 @@ static const struct iio_info ens160_info = {
|
||||
.read_raw = ens160_read_raw,
|
||||
};
|
||||
|
||||
int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
|
||||
static irqreturn_t ens160_trigger_handler(int irq, void *p)
|
||||
{
|
||||
struct iio_poll_func *pf = p;
|
||||
struct iio_dev *indio_dev = pf->indio_dev;
|
||||
struct ens160_data *data = iio_priv(indio_dev);
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&data->mutex);
|
||||
|
||||
ret = regmap_bulk_read(data->regmap, ENS160_REG_DATA_TVOC,
|
||||
data->scan.chans, sizeof(data->scan.chans));
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
iio_push_to_buffers_with_timestamp(indio_dev, &data->scan,
|
||||
pf->timestamp);
|
||||
err:
|
||||
iio_trigger_notify_done(indio_dev->trig);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int ens160_set_trigger_state(struct iio_trigger *trig, bool state)
|
||||
{
|
||||
struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
|
||||
struct ens160_data *data = iio_priv(indio_dev);
|
||||
unsigned int int_bits = ENS160_REG_CONFIG_INTEN |
|
||||
ENS160_REG_CONFIG_INTDAT |
|
||||
ENS160_REG_CONFIG_INT_CFG;
|
||||
|
||||
if (state)
|
||||
return regmap_set_bits(data->regmap, ENS160_REG_CONFIG,
|
||||
int_bits);
|
||||
else
|
||||
return regmap_clear_bits(data->regmap, ENS160_REG_CONFIG,
|
||||
int_bits);
|
||||
}
|
||||
|
||||
static const struct iio_trigger_ops ens160_trigger_ops = {
|
||||
.set_trigger_state = ens160_set_trigger_state,
|
||||
.validate_device = iio_trigger_validate_own_device,
|
||||
};
|
||||
|
||||
static int ens160_setup_trigger(struct iio_dev *indio_dev, int irq)
|
||||
{
|
||||
struct device *dev = indio_dev->dev.parent;
|
||||
struct iio_trigger *trig;
|
||||
int ret;
|
||||
|
||||
trig = devm_iio_trigger_alloc(dev, "%s-dev%d", indio_dev->name,
|
||||
iio_device_id(indio_dev));
|
||||
if (!trig)
|
||||
return dev_err_probe(dev, -ENOMEM,
|
||||
"failed to allocate trigger\n");
|
||||
|
||||
trig->ops = &ens160_trigger_ops;
|
||||
iio_trigger_set_drvdata(trig, indio_dev);
|
||||
|
||||
ret = devm_iio_trigger_register(dev, trig);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
indio_dev->trig = iio_trigger_get(trig);
|
||||
|
||||
ret = devm_request_threaded_irq(dev, irq,
|
||||
iio_trigger_generic_data_rdy_poll,
|
||||
NULL,
|
||||
IRQF_ONESHOT,
|
||||
indio_dev->name,
|
||||
indio_dev->trig);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "failed to request irq\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int devm_ens160_core_probe(struct device *dev, struct regmap *regmap, int irq,
|
||||
const char *name)
|
||||
{
|
||||
struct ens160_data *data;
|
||||
@ -208,10 +316,25 @@ int devm_ens160_core_probe(struct device *dev, struct regmap *regmap,
|
||||
indio_dev->channels = ens160_channels;
|
||||
indio_dev->num_channels = ARRAY_SIZE(ens160_channels);
|
||||
|
||||
if (irq > 0) {
|
||||
ret = ens160_setup_trigger(indio_dev, irq);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret,
|
||||
"failed to setup trigger\n");
|
||||
}
|
||||
|
||||
ret = ens160_chip_init(data);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "chip initialization failed\n");
|
||||
|
||||
mutex_init(&data->mutex);
|
||||
|
||||
ret = devm_iio_triggered_buffer_setup(dev, indio_dev,
|
||||
iio_pollfunc_store_time,
|
||||
ens160_trigger_handler, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_iio_device_register(dev, indio_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_NS(devm_ens160_core_probe, IIO_ENS160);
|
||||
|
@ -29,7 +29,8 @@ static int ens160_i2c_probe(struct i2c_client *client)
|
||||
return dev_err_probe(&client->dev, PTR_ERR(regmap),
|
||||
"Failed to register i2c regmap\n");
|
||||
|
||||
return devm_ens160_core_probe(&client->dev, regmap, "ens160");
|
||||
return devm_ens160_core_probe(&client->dev, regmap, client->irq,
|
||||
"ens160");
|
||||
}
|
||||
|
||||
static const struct i2c_device_id ens160_i2c_id[] = {
|
||||
|
@ -29,7 +29,7 @@ static int ens160_spi_probe(struct spi_device *spi)
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(regmap),
|
||||
"Failed to register spi regmap\n");
|
||||
|
||||
return devm_ens160_core_probe(&spi->dev, regmap, "ens160");
|
||||
return devm_ens160_core_probe(&spi->dev, regmap, spi->irq, "ens160");
|
||||
}
|
||||
|
||||
static const struct of_device_id ens160_spi_of_match[] = {
|
||||
|
Loading…
Reference in New Issue
Block a user