iio: chemical: ccs811: Add triggered buffer support
authorNarcisa Ana Maria Vasile <narcisaanamaria12@gmail.com>
Thu, 17 Aug 2017 11:34:29 +0000 (14:34 +0300)
committerJonathan Cameron <Jonathan.Cameron@huawei.com>
Fri, 18 Aug 2017 07:08:02 +0000 (08:08 +0100)
A software trigger such as hrtimer can be used to capture the data
that will be stored in the buffer.

Cc: Daniel Baluta <daniel.baluta@gmail.com>
Cc: Alison Schofield <amsfield22@gmail.com>
Signed-off-by: Narcisa Ana Maria Vasile <narcisaanamaria12@gmail.com>
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
drivers/iio/chemical/Kconfig
drivers/iio/chemical/ccs811.c

index 4d799b5cceac27d4f13941cb5ffd5c1c07e732f6..5cb5be7612b46bcd4cf52b6c30371fbf4b04e900 100644 (file)
@@ -24,6 +24,8 @@ config ATLAS_PH_SENSOR
 config CCS811
        tristate "AMS CCS811 VOC sensor"
        depends on I2C
+    select IIO_BUFFER
+    select IIO_TRIGGERED_BUFFER
        help
          Say Y here to build I2C interface support for the AMS
          CCS811 VOC (Volatile Organic Compounds) sensor
index 8dbb5eddeb1f3098be9e82c40b9c5892f720da9a..840a6cbd5f0f43b94945001022b45b331646b4a7 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
 #include <linux/module.h>
 
 #define CCS811_STATUS          0x00
@@ -76,25 +79,42 @@ static const struct iio_chan_spec ccs811_channels[] = {
        {
                .type = IIO_CURRENT,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                                     BIT(IIO_CHAN_INFO_SCALE)
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .scan_index = -1,
        }, {
                .type = IIO_VOLTAGE,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                                     BIT(IIO_CHAN_INFO_SCALE)
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .scan_index = -1,
        }, {
                .type = IIO_CONCENTRATION,
                .channel2 = IIO_MOD_CO2,
                .modified = 1,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
                                      BIT(IIO_CHAN_INFO_OFFSET) |
-                                     BIT(IIO_CHAN_INFO_SCALE)
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .scan_index = 0,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_BE,
+               },
        }, {
                .type = IIO_CONCENTRATION,
                .channel2 = IIO_MOD_VOC,
                .modified = 1,
                .info_mask_separate =  BIT(IIO_CHAN_INFO_RAW) |
-                                      BIT(IIO_CHAN_INFO_SCALE)
+                                      BIT(IIO_CHAN_INFO_SCALE),
+               .scan_index = 1,
+               .scan_type = {
+                       .sign = 'u',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_BE,
+               },
        },
+       IIO_CHAN_SOFT_TIMESTAMP(2),
 };
 
 /*
@@ -253,6 +273,31 @@ static const struct iio_info ccs811_info = {
        .driver_module = THIS_MODULE,
 };
 
+static irqreturn_t ccs811_trigger_handler(int irq, void *p)
+{
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct ccs811_data *data = iio_priv(indio_dev);
+       struct i2c_client *client = data->client;
+       s16 buf[8]; /* s16 eCO2 + s16 TVOC + padding + 8 byte timestamp */
+       int ret;
+
+       ret = i2c_smbus_read_i2c_block_data(client, CCS811_ALG_RESULT_DATA, 4,
+                                           (u8 *)&buf);
+       if (ret != 4) {
+               dev_err(&client->dev, "cannot read sensor data\n");
+               goto err;
+       }
+
+       iio_push_to_buffers_with_timestamp(indio_dev, buf,
+                                          iio_get_time_ns(indio_dev));
+
+err:
+       iio_trigger_notify_done(indio_dev->trig);
+
+       return IRQ_HANDLED;
+}
+
 static int ccs811_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -305,7 +350,27 @@ static int ccs811_probe(struct i2c_client *client,
        indio_dev->channels = ccs811_channels;
        indio_dev->num_channels = ARRAY_SIZE(ccs811_channels);
 
-       return iio_device_register(indio_dev);
+       ret = iio_triggered_buffer_setup(indio_dev, NULL,
+                                        ccs811_trigger_handler, NULL);
+
+       if (ret < 0) {
+               dev_err(&client->dev, "triggered buffer setup failed\n");
+               goto err_poweroff;
+       }
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0) {
+               dev_err(&client->dev, "unable to register iio device\n");
+               goto err_buffer_cleanup;
+       }
+       return 0;
+
+err_buffer_cleanup:
+       iio_triggered_buffer_cleanup(indio_dev);
+err_poweroff:
+       i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE, CCS811_MODE_IDLE);
+
+       return ret;
 }
 
 static int ccs811_remove(struct i2c_client *client)
@@ -313,6 +378,7 @@ static int ccs811_remove(struct i2c_client *client)
        struct iio_dev *indio_dev = i2c_get_clientdata(client);
 
        iio_device_unregister(indio_dev);
+       iio_triggered_buffer_cleanup(indio_dev);
 
        return i2c_smbus_write_byte_data(client, CCS811_MEAS_MODE,
                                         CCS811_MODE_IDLE);