iio: humidity: Add triggered buffer support for AM2315

Signed-off-by: Tiberiu Breana <tiberiu.a.breana@intel.com>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
This commit is contained in:
Tiberiu Breana 2016-04-18 17:50:44 +03:00 committed by Jonathan Cameron
parent 366a3270c1
commit 0d96d5ead3
1 changed files with 78 additions and 3 deletions

View File

@ -15,8 +15,11 @@
#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
@ -26,12 +29,14 @@
#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;
}