iio: humidity: Add triggered buffer support for AM2315
authorTiberiu Breana <tiberiu.a.breana@intel.com>
Mon, 18 Apr 2016 14:50:44 +0000 (17:50 +0300)
committerJonathan Cameron <jic23@kernel.org>
Sun, 24 Apr 2016 09:00:20 +0000 (10:00 +0100)
Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
drivers/iio/humidity/am2315.c

index d392fc8a9d1614c7321d1526b070b6d26fa260a1..3be6d209a1595961ddd19dbcf8fc240f07617a77 100644 (file)
 #include <linux/i2c.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/iio/buffer.h>
 #include <linux/iio/iio.h>
 #include <linux/iio/sysfs.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
 
 #define AM2315_REG_HUM_MSB                     0x00
 #define AM2315_REG_HUM_LSB                     0x01
 #define AM2315_FUNCTION_READ                   0x03
 #define AM2315_HUM_OFFSET                      2
 #define AM2315_TEMP_OFFSET                     4
+#define AM2315_ALL_CHANNEL_MASK                        GENMASK(1, 0)
 
 #define AM2315_DRIVER_NAME                     "am2315"
 
 struct am2315_data {
        struct i2c_client *client;
        struct mutex lock;
+       s16 buffer[8]; /* 2x16-bit channels + 2x16 padding + 4x16 timestamp */
 };
 
 struct am2315_sensor_data {
@@ -43,13 +48,28 @@ static const struct iio_chan_spec am2315_channels[] = {
        {
                .type = IIO_HUMIDITYRELATIVE,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                                     BIT(IIO_CHAN_INFO_SCALE)
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .scan_index = 0,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_CPU,
+               },
        },
        {
                .type = IIO_TEMP,
                .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
-                                     BIT(IIO_CHAN_INFO_SCALE)
+                                     BIT(IIO_CHAN_INFO_SCALE),
+               .scan_index = 1,
+               .scan_type = {
+                       .sign = 's',
+                       .realbits = 16,
+                       .storagebits = 16,
+                       .endianness = IIO_CPU,
+               },
        },
+       IIO_CHAN_SOFT_TIMESTAMP(2),
 };
 
 /* CRC calculation algorithm, as specified in the datasheet (page 13). */
@@ -134,6 +154,44 @@ exit_unlock:
        return ret;
 }
 
+static irqreturn_t am2315_trigger_handler(int irq, void *p)
+{
+       int i;
+       int ret;
+       int bit;
+       struct iio_poll_func *pf = p;
+       struct iio_dev *indio_dev = pf->indio_dev;
+       struct am2315_data *data = iio_priv(indio_dev);
+       struct am2315_sensor_data sensor_data;
+
+       ret = am2315_read_data(data, &sensor_data);
+       if (ret < 0) {
+               mutex_unlock(&data->lock);
+               goto err;
+       }
+
+       mutex_lock(&data->lock);
+       if (*(indio_dev->active_scan_mask) == AM2315_ALL_CHANNEL_MASK) {
+               data->buffer[0] = sensor_data.hum_data;
+               data->buffer[1] = sensor_data.temp_data;
+       } else {
+               i = 0;
+               for_each_set_bit(bit, indio_dev->active_scan_mask,
+                                indio_dev->masklength) {
+                       data->buffer[i] = (bit ? sensor_data.temp_data :
+                                                sensor_data.hum_data);
+                       i++;
+               }
+       }
+       mutex_unlock(&data->lock);
+
+       iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+                                          pf->timestamp);
+err:
+       iio_trigger_notify_done(indio_dev->trig);
+       return IRQ_HANDLED;
+}
+
 static int am2315_read_raw(struct iio_dev *indio_dev,
                           struct iio_chan_spec const *chan,
                           int *val, int *val2, long mask)
@@ -166,6 +224,7 @@ static const struct iio_info am2315_info = {
 static int am2315_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
+       int ret;
        struct iio_dev *indio_dev;
        struct am2315_data *data;
 
@@ -187,7 +246,22 @@ static int am2315_probe(struct i2c_client *client,
        indio_dev->channels = am2315_channels;
        indio_dev->num_channels = ARRAY_SIZE(am2315_channels);
 
-       return iio_device_register(indio_dev);
+       ret = iio_triggered_buffer_setup(indio_dev, NULL,
+                                        am2315_trigger_handler, NULL);
+       if (ret < 0) {
+               dev_err(&client->dev, "iio triggered buffer setup failed\n");
+               return ret;
+       }
+
+       ret = iio_device_register(indio_dev);
+       if (ret < 0)
+               goto err_buffer_cleanup;
+
+       return 0;
+
+err_buffer_cleanup:
+       iio_triggered_buffer_cleanup(indio_dev);
+       return ret;
 }
 
 static int am2315_remove(struct i2c_client *client)
@@ -195,6 +269,7 @@ static int am2315_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 0;
 }