iio: humidity: hdc100x: add triggered buffer support for HDC100X
PATCH 1/1 iio: humidity: hdc100x: add triggered buffer support for HDC100X
Triggered buffer support uses the HDC100X's dual acquisition mode to read both humidity and temperature in one shot.
--- drivers/iio/humidity/Kconfig | 2 + drivers/iio/humidity/hdc100x.c | 144 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 140 insertions(+), 6 deletions(-)
drivers/iio/humidity/Kconfig +2 -0
@@ -25,6 +25,8 @@ config DHT11 config HDC100X tristate "TI HDC100x relative humidity and temperature sensor" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for the TI HDC100x series of relative humidity and temperature sensors.
drivers/iio/humidity/hdc100x.c +138 -6
218 lines not on this page · raw message
Signature · 1 line
2.1.4
Quoted 3 lines
Triggered buffer support uses the HDC100X's dual acquisition mode to read both humidity and temperature in one shot.
comments below
Quoted 45 lines
Signed-off-by Alison Schofield <[email protected]>Cc Daniel Baluta <[email protected]>--- drivers/iio/humidity/Kconfig | 2 + drivers/iio/humidity/hdc100x.c | 144 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 140 insertions(+), 6 deletions(-)drivers/iio/humidity/Kconfig +2
-0@@ -25,6 +25,8 @@ config DHT11 config HDC100X tristate "TI HDC100x relative humidity and temperature sensor" depends on I2C + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER help Say yes here to build support for the TI HDC100x series of relative humidity and temperature sensors.drivers/iio/humidity/hdc100x.c +6
-0@@ -22,13 +22,19 @@#include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #define HDC100X_REG_TEMP 0x00#define HDC100X_REG_HUMIDITY 0x01#define HDC100X_REG_CONFIG 0x02 +#define HDC100X_REG_CONFIG_ACQ_MODE BIT(12)#define HDC100X_REG_CONFIG_HEATER_EN BIT(13) +#define HDC100X_ALL_CHANNEL_MASK GENMASK(1, 0) +struct hdc100x_data {struct i2c_client *client;struct mutex lock;
drivers/iio/humidity/hdc100x.c static const struct iio_chan_spec hdc100x_channels[] = { · line 101
Quoted 9 lines
drivers/iio/humidity/hdc100x.c +6
-0@@ -87,20 +93,36 @@ static const struct iio_chan_spec hdc100x_channels[] = {BIT (IIO_CHAN_INFO_SCALE ) |BIT (IIO_CHAN_INFO_INT_TIME ) | BIT(IIO_CHAN_INFO_OFFSET), + .scan_index = 0, + .scan_type = { + .sign = 's', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU,
why not use IIO_BE? this avoids the ugly, open-coded endianness conversion in trigger_handler()
Quoted 95 lines
drivers/iio/humidity/hdc100x.c +55
-3+ }, }, { .type = IIO_HUMIDITYRELATIVE, .address = HDC100X_REG_HUMIDITY, .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ) |BIT (IIO_CHAN_INFO_SCALE ) | -BIT (IIO_CHAN_INFO_INT_TIME ) + BIT(IIO_CHAN_INFO_INT_TIME), + .scan_index = 1, + .scan_type = { + .sign = 'u', + .realbits = 16, + .storagebits = 16, + .endianness = IIO_CPU, + }, }, { .type = IIO_CURRENT, .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), .extend_name = "heater", .output = 1, + .scan_index =-1 , }, + IIO_CHAN_SOFT_TIMESTAMP(3), };static int hdc100x_update_config (struct hdc100x_data *data,int mask,int val)@@ -191,18 +213,21 @@ static int hdc100x_read_raw(struct iio_dev *indio_dev,case IIO_CHAN_INFO_RAW : {int ret; -mutex_lock (&data->lock);if (chan->type ==IIO_CURRENT ) { *val =hdc100x_get_heater_status (data); ret =IIO_VAL_INT ; }else { + ret =iio_device_claim_direct_mode (indio_dev); +if (ret) +return ret; + ret =hdc100x_get_measurement (data, chan); +iio_device_release_direct_mode (indio_dev);if (ret >=0 ) { *val = ret; ret =IIO_VAL_INT ; } } -mutex_unlock (&data->lock);return ret; }case IIO_CHAN_INFO_INT_TIME :@@ -259,6 +284,89 @@ static int hdc100x_write_raw(struct iio_dev *indio_dev, } } +static int hdc100x_buffer_postenable (struct iio_dev *indio_dev) +{ +struct hdc100x_data *data =iio_priv (indio_dev); +int ret; + +/* Buffer is enabled. First set ACQ Mode, then attach poll func */ +mutex_lock (&data->lock); + ret =hdc100x_update_config (data,HDC100X_REG_CONFIG_ACQ_MODE , +HDC100X_REG_CONFIG_ACQ_MODE ); +mutex_unlock (&data->lock); +if (ret) +return ret; + +return iio_triggered_buffer_postenable (indio_dev); +} + +static int hdc100x_buffer_predisable (struct iio_dev *indio_dev) +{ +struct hdc100x_data *data =iio_priv (indio_dev); +int ret; + +/* First detach poll func, then reset ACQ mode. OK to disable buffer */ + ret =iio_triggered_buffer_predisable (indio_dev); +if (ret) +return ret; + +mutex_lock (&data->lock); + ret =hdc100x_update_config (data,HDC100X_REG_CONFIG_ACQ_MODE ,0 ); +mutex_unlock (&data->lock); +return ret; +} + +static const struct iio_buffer_setup_ops hdc_buffer_setup_ops = { + .preenable =NULL , + .postenable = hdc100x_buffer_postenable, + .predisable = hdc100x_buffer_predisable, + .postdisable =NULL , +}; +
drivers/iio/humidity/hdc100x.c static int hdc100x_write_raw(struct iio_dev *indio_dev, · line 335
Quoted 10 lines
drivers/iio/humidity/hdc100x.c +10
-0+static irqreturn_t hdc100x_trigger_handler (int irq,void *p) +{ +struct iio_poll_func *pf = p; +struct iio_dev *indio_dev = pf->indio_dev; +struct hdc100x_data *data =iio_priv (indio_dev); +struct i2c_client *client = data->client; +int delay = data->adc_int_us[0 ] + data->adc_int_us[1 ]; +int ret, i, bit; +u8 recv_buf[4 ]; +s16 push_buf[8 ];/* 2x s16 + padding + 8 byte timestamp */
two different buffers really needed?
for ALL_CHANNEL_MASK can read directly to push_buf; why is this a special case anyway?
if only first channel set, can read directly to push_buf
if only second channel set, have to move data within push_buf
don't do endianness conversion if not strictly needed
Quoted 10 lines
drivers/iio/humidity/hdc100x.c +10
-0+ +/* dual read starts at temp register */ + ret =i2c_smbus_write_byte (client,HDC100X_REG_TEMP ); +if (ret <0 ) { +dev_err (&client->dev,"cannot start measurement\n" ); + goto err; + } +usleep_range (delay, delay +1000 ); + + ret =i2c_master_recv (client, recv_buf,sizeof (recv_buf));
drivers/iio/humidity/hdc100x.c static int hdc100x_write_raw(struct iio_dev *indio_dev, · line 355
Quoted 10 lines
drivers/iio/humidity/hdc100x.c +10
-0+if (ret <0 ) { +dev_err (&client->dev,"cannot read sensor data\n" ); + goto err; + } +if (*indio_dev->active_scan_mask ==HDC100X_ALL_CHANNEL_MASK ) { + push_buf[0 ] = recv_buf[0 ] <<8 | recv_buf[1 ]; + push_buf[1 ] = recv_buf[2 ] <<8 | recv_buf[3 ]; + }else { + i =0 ; + for_each_set_bit(bit, indio_dev->active_scan_mask,
loop probably overkill for exactly two channels
Quoted 71 lines
drivers/iio/humidity/hdc100x.c +41
-3+ indio_dev->masklength) { + push_buf[i] = bit ? (recv_buf[2 ] <<8 | recv_buf[3 ]) + : (recv_buf[0 ] <<8 | recv_buf[1 ]); + i++; + } + } +iio_push_to_buffers_with_timestamp (indio_dev, push_buf, +iio_get_time_ns (indio_dev)); +err: +iio_trigger_notify_done (indio_dev->trig); + +return IRQ_HANDLED ; +} +static const struct iio_info hdc100x_info = { .read_raw = hdc100x_read_raw, .write_raw = hdc100x_write_raw,@@ -271,9 +379,10 @@ static int hdc100x_probe(struct i2c_client *client, {struct iio_dev *indio_dev;struct hdc100x_data *data; +int ret; -if (!i2c_check_functionality (client->adapter, -I2C_FUNC_SMBUS_WORD_DATA |I2C_FUNC_SMBUS_BYTE )) +if (!i2c_check_functionality (client->adapter,I2C_FUNC_SMBUS_WORD_DATA | +I2C_FUNC_SMBUS_BYTE |I2C_FUNC_I2C ))return -EOPNOTSUPP ; indio_dev =devm_iio_device_alloc (&client->dev,sizeof (*data));@@ -296,8 +405,30 @@ static int hdc100x_probe(struct i2c_client *client,/* be sure we are in a known state */ hdc100x_set_it_time (data,0 , hdc100x_int_time[0 ][0 ]);hdc100x_set_it_time (data,1 , hdc100x_int_time[1 ][0 ]); +hdc100x_update_config (data,HDC100X_REG_CONFIG_ACQ_MODE ,0 ); + + ret =iio_triggered_buffer_setup (indio_dev,NULL , + hdc100x_trigger_handler, + &hdc_buffer_setup_ops); +if (ret <0 ) { +dev_err (&client->dev,"iio triggered buffer setup failed\n" ); +return ret; + } + ret =iio_device_register (indio_dev); +if (ret <0 ) +iio_triggered_buffer_cleanup (indio_dev); + +return ret; +} + +static int hdc100x_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 devm_iio_device_register (&client->dev, indio_dev); +return 0 ; }static const struct i2c_device_id hdc100x_id[] = {@@ -311,6 +442,7 @@ static struct i2c_driver hdc100x_driver = { .name = "hdc100x", }, .probe = hdc100x_probe, + .remove = hdc100x_remove, .id_table = hdc100x_id, };module_i2c_driver (hdc100x_driver);
Signature · 2 lines
Peter Meerwald-Stadler +43-664-2444418 (mobile)