iio: Add support for adc101 and adc121c to ti-adc081c
v3 cover iio: Add support for adc101 and adc121c to ti-adc081c
Version 3 fixes review comments:
* Avoid using VLAs in trigger_handler.
* Add an array of model types and make driver_data an index in the table.
Crestez Dan Leonard (2):
ti-adc081c: Add support for adc101c and adc121c
ti-adc081c: Initial triggered buffer support
drivers/iio/adc/Kconfig | 6 +-- drivers/iio/adc/ti-adc081c.c | 118 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 109 insertions(+), 15 deletions(-)
Signature · 1 line
2.5.5
PATCH v3 1/2 ti-adc081c: Add support for adc101c and adc121c
These chips have an almost identical interface but support a different number of value bits. Datasheet links for comparison:
* http://www.ti.com/lit/ds/symlink/adc081c021.pdf
* http://www.ti.com/lit/ds/symlink/adc101c021.pdf
* http://www.ti.com/lit/ds/symlink/adc121c021.pdf
--- drivers/iio/adc/Kconfig | 6 +++--- drivers/iio/adc/ti-adc081c.c | 51 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-)
drivers/iio/adc/Kconfig +3 -3
@@ -385,11 +385,11 @@ config ROCKCHIP_SARADC module will be called rockchip_saradc. config TI_ADC081C - tristate "Texas Instruments ADC081C021/027" + tristate "Texas Instruments ADC081C/ADC101C/ADC121C family" depends on I2C help - If you say yes here you get support for Texas Instruments ADC081C021 - and ADC081C027 ADC chips. + If you say yes here you get support for Texas Instruments ADC081C, + ADC101C and ADC121C ADC chips. This driver can also be built as a module. If so, the module will be called ti-adc081c.
drivers/iio/adc/ti-adc081c.c +47 -4
112 lines not on this page · raw message
Signature · 1 line
2.5.5
Re: [PATCH v3 1/2] ti-adc081c: Add support for adc101c and adc121c
Quoted 8 lines · Crestez Dan Leonard
These chips have an almost identical interface but support a different number of value bits. Datasheet links for comparison:
* http://www.ti.com/lit/ds/symlink/adc081c021.pdf
* http://www.ti.com/lit/ds/symlink/adc101c021.pdf
* http://www.ti.com/lit/ds/symlink/adc121c021.pdfSigned-off-by Crestez Dan Leonard <[email protected]>
Very nice.
Applied to the togreg branch of iio.git - initially pushed out as testing for the autobuilders to play with it.
Thanks,
Jonathan
Quoted 151 lines
--- drivers/iio/adc/Kconfig | 6 +++--- drivers/iio/adc/ti-adc081c.c | 51 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 7 deletions(-)drivers/iio/adc/Kconfig +3
-3@@ -385,11 +385,11 @@ config ROCKCHIP_SARADC module will be called rockchip_saradc. config TI_ADC081C - tristate "Texas Instruments ADC081C021/027" + tristate "Texas Instruments ADC081C/ADC101C/ADC121C family" depends on I2C help - If you say yes here you get support for Texas Instruments ADC081C021 - and ADC081C027 ADC chips. + If you say yes here you get support for Texas Instruments ADC081C, + ADC101C and ADC121C ADC chips. This driver can also be built as a module. If so, the module will be called ti-adc081c.drivers/iio/adc/ti-adc081c.c +47
-4@@ -1,9 +1,21 @@/* +* TI ADC081C/ADC101C/ADC121C 8/10/12-bit ADC driver +* * Copyright (C) 2012 Avionic Design GmbH +* Copyright (C) 2016 Intel * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. +* +* Datasheets: +* http://www.ti.com/lit/ds/symlink/adc081c021.pdf +* http://www.ti.com/lit/ds/symlink/adc101c021.pdf +* http://www.ti.com/lit/ds/symlink/adc121c021.pdf +* +* The devices have a very similar interface and differ mostly in the number of +* bits handled. For the 8-bit and 10-bit models the least-significant 4 or 2 +* bits of value registers are reserved. */ #include <linux/err.h> @@ -17,6 +29,9 @@struct adc081c {struct i2c_client *i2c;struct regulator *ref; + +/* 8, 10 or 12 */ +int bits; };#define REG_CONV_RES 0x00@@ -34,7 +49,7 @@ static int adc081c_read_raw(struct iio_dev *iio,if (err <0 )return err; - *value = (err >>4 ) &0xff ; + *value = (err &0xFFF ) >> (12 - adc->bits);return IIO_VAL_INT ;case IIO_CHAN_INFO_SCALE :@@ -43,7 +58,7 @@ static int adc081c_read_raw(struct iio_dev *iio,return err; *value = err /1000 ; - *shift =8 ; + *shift = adc->bits;return IIO_VAL_FRACTIONAL_LOG2 ;@@ -60,6 +75,28 @@ static const struct iio_chan_spec adc081c_channel = { .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), }; +struct adcxx1c_model { +int bits; +}; + +#define ADCxx1C_MODEL (_bits) \ + { \ + .bits = (_bits), \ + } + +/* Model ids are indexes in _models array */ +enum adcxx1c_model_id { +ADC081C =0 , +ADC101C =1 , +ADC121C =2 , +}; + +static struct adcxx1c_model adcxx1c_models[] = { +ADCxx1C_MODEL (8 ), +ADCxx1C_MODEL (10 ), +ADCxx1C_MODEL (12 ), +}; +static const struct iio_info adc081c_info = { .read_raw = adc081c_read_raw, .driver_module =THIS_MODULE ,@@ -70,6 +107,7 @@ static int adc081c_probe(struct i2c_client *client, {struct iio_dev *iio;struct adc081c *adc; +struct adcxx1c_model *model = &adcxx1c_models[id->driver_data];int err;if (!i2c_check_functionality (client->adapter,I2C_FUNC_SMBUS_WORD_DATA ))@@ -81,6 +119,7 @@ static int adc081c_probe(struct i2c_client *client, adc =iio_priv (iio); adc->i2c = client; + adc->bits = model->bits; adc->ref =devm_regulator_get (&client->dev,"vref" );if (IS_ERR (adc->ref))@@ -124,7 +163,9 @@ static int adc081c_remove(struct i2c_client *client) }static const struct i2c_device_id adc081c_id[] = { - {"adc081c" ,0 }, + {"adc081c" ,ADC081C }, + {"adc101c" ,ADC101C }, + {"adc121c" ,ADC121C }, { } };MODULE_DEVICE_TABLE (i2c, adc081c_id);@@ -132,6 +173,8 @@ MODULE_DEVICE_TABLE(i2c, adc081c_id);#ifdef CONFIG_OF static const struct of_device_id adc081c_of_match[] = { { .compatible ="ti,adc081c" }, + { .compatible ="ti,adc101c" }, + { .compatible ="ti,adc121c" }, { } };MODULE_DEVICE_TABLE (of, adc081c_of_match);@@ -149,5 +192,5 @@ static struct i2c_driver adc081c_driver = {module_i2c_driver (adc081c_driver);MODULE_AUTHOR ("Thierry Reding <[email protected]>" ); -MODULE_DESCRIPTION ("Texas Instruments ADC081C021/027 driver" ); +MODULE_DESCRIPTION ("Texas Instruments ADC081C/ADC101C/ADC121C driver" );MODULE_LICENSE ("GPL v2" );
PATCH v3 2/2 ti-adc081c: Initial triggered buffer support
In reply to Crestez Dan LeonardUsing this requires software triggers like CONFIG_IIO_HRTIMER_TRIGGER.
The device can be configured to do internal periodic sampling but does not offer some sort of interrupt on data ready. Interrupts can only trigger when values get out of a specific range.
--- drivers/iio/adc/ti-adc081c.c | 77 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 13 deletions(-)
drivers/iio/adc/ti-adc081c.c +64 -13
@@ -24,6 +24,9 @@#include <linux/of.h> #include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include <linux/regulator/consumer.h> struct adc081c {
@@ -69,21 +72,42 @@ static int adc081c_read_raw(struct iio_dev *iio,return -EINVAL ; } -static const struct iio_chan_spec adc081c_channel = { - .type =IIO_VOLTAGE , - .info_mask_shared_by_type =BIT (IIO_CHAN_INFO_SCALE ), - .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ), -}; +#define ADCxx1C_CHAN (_bits) { \ + .type = IIO_VOLTAGE, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = 16, \ + .shift = 12 - (_bits), \ + .endianness = IIO_CPU, \ + }, \ +} + +#define DEFINE_ADCxx1C_CHANNELS (_name, _bits) \ + static const struct iio_chan_spec _name ## _channels[] = { \ + ADCxx1C_CHAN((_bits)), \ + IIO_CHAN_SOFT_TIMESTAMP(1), \ + }; \ + +#define ADC081C_NUM_CHANNELS 2struct adcxx1c_model { +const struct iio_chan_spec * channels;int bits; }; -#define ADCxx1C_MODEL (_bits) \ +#define ADCxx1C_MODEL (_name, _bits) \ { \ + .channels = _name ## _channels, \ .bits = (_bits), \ } +DEFINE_ADCxx1C_CHANNELS (adc081c,8 ); +DEFINE_ADCxx1C_CHANNELS (adc101c,10 ); +DEFINE_ADCxx1C_CHANNELS (adc121c,12 ); +/* Model ids are indexes in _models array */ enum adcxx1c_model_id {ADC081C =0 ,
@@ -92,9 +116,9 @@ enum adcxx1c_model_id { };static struct adcxx1c_model adcxx1c_models[] = { -ADCxx1C_MODEL (8 ), -ADCxx1C_MODEL (10 ), -ADCxx1C_MODEL (12 ), +ADCxx1C_MODEL (adc081c,8 ), +ADCxx1C_MODEL (adc101c,10 ), +ADCxx1C_MODEL (adc121c,12 ), };static const struct iio_info adc081c_info = {
@@ -102,6 +126,24 @@ static const struct iio_info adc081c_info = { .driver_module = THIS_MODULE, }; +static irqreturn_t adc081c_trigger_handler (int irq,void *p) +{ +struct iio_poll_func *pf = p; +struct iio_dev *indio_dev = pf->indio_dev; +struct adc081c *data =iio_priv (indio_dev); +u16 buf[8 ];/* 2 bytes data + 6 bytes padding + 8 bytes timestamp */ +int ret; + + ret =i2c_smbus_read_word_swapped (data->i2c,REG_CONV_RES ); +if (ret <0 ) + goto out; + buf[0 ] = ret; +iio_push_to_buffers_with_timestamp (indio_dev, buf,iio_get_time_ns ()); +out: +iio_trigger_notify_done (indio_dev->trig); +return IRQ_HANDLED ; +} +static int adc081c_probe (struct i2c_client *client,const struct i2c_device_id *id) {
@@ -134,18 +176,26 @@ static int adc081c_probe(struct i2c_client *client, iio->modes =INDIO_DIRECT_MODE ; iio->info = &adc081c_info; - iio->channels = &adc081c_channel; - iio->num_channels =1 ; + iio->channels = model->channels; + iio->num_channels =ADC081C_NUM_CHANNELS ; + + err =iio_triggered_buffer_setup (iio,NULL , adc081c_trigger_handler,NULL ); +if (err <0 ) { +dev_err (&client->dev,"iio triggered buffer setup failed\n" ); + goto err_regulator_disable; + } err =iio_device_register (iio);if (err <0 ) - goto regulator_disable; + goto err_buffer_cleanup;i2c_set_clientdata (client, iio);return 0 ; -regulator_disable: +err_buffer_cleanup: +iio_triggered_buffer_cleanup (iio); +err_regulator_disable:regulator_disable (adc->ref);return err;
@@ -157,6 +207,7 @@ static int adc081c_remove(struct i2c_client *client)struct adc081c *adc =iio_priv (iio);iio_device_unregister (iio); +iio_triggered_buffer_cleanup (iio);regulator_disable (adc->ref);return 0 ;
Signature · 1 line
2.5.5
Jonathan Cameron
maintainerRe: [PATCH v3 2/2] ti-adc081c: Initial triggered buffer support
Quoted 7 lines · Crestez Dan Leonard
Using this requires software triggers like
CONFIG_IIO_HRTIMER_TRIGGER.The device can be configured to do internal periodic sampling but does not offer some sort of interrupt on data ready. Interrupts can only trigger when values get out of a specific range.
Signed-off-by Crestez Dan Leonard <[email protected]>
One totally trivial comment inline.
Applied to the togreg branch of iio.git - pushed out as testing for the autobuilders to play with it.
Thanks,
Jonathan
Quoted 120 lines
--- drivers/iio/adc/ti-adc081c.c | 77 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 13 deletions(-)drivers/iio/adc/ti-adc081c.c +59
-11@@ -24,6 +24,9 @@#include <linux/of.h> #include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> #include <linux/regulator/consumer.h> struct adc081c {@@ -69,21 +72,42 @@ static int adc081c_read_raw(struct iio_dev *iio,return -EINVAL ; } -static const struct iio_chan_spec adc081c_channel = { - .type =IIO_VOLTAGE , - .info_mask_shared_by_type =BIT (IIO_CHAN_INFO_SCALE ), - .info_mask_separate =BIT (IIO_CHAN_INFO_RAW ), -}; +#define ADCxx1C_CHAN (_bits) { \ + .type = IIO_VOLTAGE, \ + .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ + .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = 16, \ + .shift = 12 - (_bits), \ + .endianness = IIO_CPU, \ + }, \ +} + +#define DEFINE_ADCxx1C_CHANNELS (_name, _bits) \ + static const struct iio_chan_spec _name ## _channels[] = { \ + ADCxx1C_CHAN((_bits)), \ + IIO_CHAN_SOFT_TIMESTAMP(1), \ + }; \ + +#define ADC081C_NUM_CHANNELS 2struct adcxx1c_model { +const struct iio_chan_spec * channels;int bits; }; -#define ADCxx1C_MODEL (_bits) \ +#define ADCxx1C_MODEL (_name, _bits) \ { \ + .channels = _name ## _channels, \ .bits = (_bits), \ } +DEFINE_ADCxx1C_CHANNELS (adc081c,8 ); +DEFINE_ADCxx1C_CHANNELS (adc101c,10 ); +DEFINE_ADCxx1C_CHANNELS (adc121c,12 ); +/* Model ids are indexes in _models array */ enum adcxx1c_model_id {ADC081C =0 ,@@ -92,9 +116,9 @@ enum adcxx1c_model_id { };static struct adcxx1c_model adcxx1c_models[] = { -ADCxx1C_MODEL (8 ), -ADCxx1C_MODEL (10 ), -ADCxx1C_MODEL (12 ), +ADCxx1C_MODEL (adc081c,8 ), +ADCxx1C_MODEL (adc101c,10 ), +ADCxx1C_MODEL (adc121c,12 ), };static const struct iio_info adc081c_info = {@@ -102,6 +126,24 @@ static const struct iio_info adc081c_info = { .driver_module = THIS_MODULE, }; +static irqreturn_t adc081c_trigger_handler (int irq,void *p) +{ +struct iio_poll_func *pf = p; +struct iio_dev *indio_dev = pf->indio_dev; +struct adc081c *data =iio_priv (indio_dev); +u16 buf[8 ];/* 2 bytes data + 6 bytes padding + 8 bytes timestamp */ +int ret; + + ret =i2c_smbus_read_word_swapped (data->i2c,REG_CONV_RES ); +if (ret <0 ) + goto out; + buf[0 ] = ret; +iio_push_to_buffers_with_timestamp (indio_dev, buf,iio_get_time_ns ()); +out: +iio_trigger_notify_done (indio_dev->trig); +return IRQ_HANDLED ; +} +static int adc081c_probe (struct i2c_client *client,const struct i2c_device_id *id) {@@ -134,18 +176,26 @@ static int adc081c_probe(struct i2c_client *client, iio->modes =INDIO_DIRECT_MODE ; iio->info = &adc081c_info; - iio->channels = &adc081c_channel; - iio->num_channels =1 ; + iio->channels = model->channels; + iio->num_channels =ADC081C_NUM_CHANNELS ; + + err =iio_triggered_buffer_setup (iio,NULL , adc081c_trigger_handler,NULL ); +if (err <0 ) { +dev_err (&client->dev,"iio triggered buffer setup failed\n" ); + goto err_regulator_disable; + }
drivers/iio/adc/ti-adc081c.c static int adc081c_probe(struct i2c_client *client, · line 148
Quoted 10 lines
drivers/iio/adc/ti-adc081c.c +1
-2err =iio_device_register (iio);if (err <0 ) - goto regulator_disable; + goto err_buffer_cleanup;i2c_set_clientdata (client, iio);return 0 ; -regulator_disable:
Technically an unrelated change, but can't say I really care!
Quoted 15 lines
drivers/iio/adc/ti-adc081c.c +4
-0+err_buffer_cleanup: +iio_triggered_buffer_cleanup (iio); +err_regulator_disable:regulator_disable (adc->ref);return err;@@ -157,6 +207,7 @@ static int adc081c_remove(struct i2c_client *client)struct adc081c *adc =iio_priv (iio);iio_device_unregister (iio); +iio_triggered_buffer_cleanup (iio);regulator_disable (adc->ref);return 0 ;