All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3 0/2] iio: Add support for adc101 and adc121c to ti-adc081c
@ 2016-04-11 14:24 Crestez Dan Leonard
  2016-04-11 14:24 ` [PATCH v3 1/2] ti-adc081c: Add support for adc101c and adc121c Crestez Dan Leonard
  2016-04-11 14:24 ` [PATCH v3 2/2] ti-adc081c: Initial triggered buffer support Crestez Dan Leonard
  0 siblings, 2 replies; 5+ messages in thread
From: Crestez Dan Leonard @ 2016-04-11 14:24 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Daniel Baluta, Crestez Dan Leonard

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(-)

-- 
2.5.5

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v3 1/2] ti-adc081c: Add support for adc101c and adc121c
  2016-04-11 14:24 [PATCH v3 0/2] iio: Add support for adc101 and adc121c to ti-adc081c Crestez Dan Leonard
@ 2016-04-11 14:24 ` Crestez Dan Leonard
  2016-04-17  9:46   ` Jonathan Cameron
  2016-04-11 14:24 ` [PATCH v3 2/2] ti-adc081c: Initial triggered buffer support Crestez Dan Leonard
  1 sibling, 1 reply; 5+ messages in thread
From: Crestez Dan Leonard @ 2016-04-11 14:24 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Daniel Baluta, 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.pdf

Signed-off-by: Crestez Dan Leonard <leonard.crestez@intel.com>
---
 drivers/iio/adc/Kconfig      |  6 +++---
 drivers/iio/adc/ti-adc081c.c | 51 ++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 50 insertions(+), 7 deletions(-)

diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 5937030..25378c5 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -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.
diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index ecbc121..b977340 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -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 <thierry.reding@avionic-design.de>");
-MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver");
+MODULE_DESCRIPTION("Texas Instruments ADC081C/ADC101C/ADC121C driver");
 MODULE_LICENSE("GPL v2");
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH v3 2/2] ti-adc081c: Initial triggered buffer support
  2016-04-11 14:24 [PATCH v3 0/2] iio: Add support for adc101 and adc121c to ti-adc081c Crestez Dan Leonard
  2016-04-11 14:24 ` [PATCH v3 1/2] ti-adc081c: Add support for adc101c and adc121c Crestez Dan Leonard
@ 2016-04-11 14:24 ` Crestez Dan Leonard
  2016-04-17  9:46   ` Jonathan Cameron
  1 sibling, 1 reply; 5+ messages in thread
From: Crestez Dan Leonard @ 2016-04-11 14:24 UTC (permalink / raw)
  To: Jonathan Cameron, linux-iio
  Cc: linux-kernel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Daniel Baluta, 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 <leonard.crestez@intel.com>
---
 drivers/iio/adc/ti-adc081c.c | 77 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 64 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
index b977340..9fd032d 100644
--- a/drivers/iio/adc/ti-adc081c.c
+++ b/drivers/iio/adc/ti-adc081c.c
@@ -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 2
 
 struct 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;
-- 
2.5.5

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 2/2] ti-adc081c: Initial triggered buffer support
  2016-04-11 14:24 ` [PATCH v3 2/2] ti-adc081c: Initial triggered buffer support Crestez Dan Leonard
@ 2016-04-17  9:46   ` Jonathan Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Cameron @ 2016-04-17  9:46 UTC (permalink / raw)
  To: Crestez Dan Leonard, linux-iio
  Cc: linux-kernel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Daniel Baluta

On 11/04/16 15:24, Crestez Dan Leonard wrote:
> 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 <leonard.crestez@intel.com>
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
> ---
>  drivers/iio/adc/ti-adc081c.c | 77 ++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 64 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
> index b977340..9fd032d 100644
> --- a/drivers/iio/adc/ti-adc081c.c
> +++ b/drivers/iio/adc/ti-adc081c.c
> @@ -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 2
>  
>  struct 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:
Technically an unrelated change, but can't say I really care!
> +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;
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v3 1/2] ti-adc081c: Add support for adc101c and adc121c
  2016-04-11 14:24 ` [PATCH v3 1/2] ti-adc081c: Add support for adc101c and adc121c Crestez Dan Leonard
@ 2016-04-17  9:46   ` Jonathan Cameron
  0 siblings, 0 replies; 5+ messages in thread
From: Jonathan Cameron @ 2016-04-17  9:46 UTC (permalink / raw)
  To: Crestez Dan Leonard, linux-iio
  Cc: linux-kernel, Hartmut Knaack, Lars-Peter Clausen,
	Peter Meerwald-Stadler, Daniel Baluta

On 11/04/16 15:24, Crestez Dan Leonard wrote:
> 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
> 
> Signed-off-by: Crestez Dan Leonard <leonard.crestez@intel.com>
Very nice.

Applied to the togreg branch of iio.git - initially pushed out as
testing for the autobuilders to play with it.

Thanks,

Jonathan
> ---
>  drivers/iio/adc/Kconfig      |  6 +++---
>  drivers/iio/adc/ti-adc081c.c | 51 ++++++++++++++++++++++++++++++++++++++++----
>  2 files changed, 50 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
> index 5937030..25378c5 100644
> --- a/drivers/iio/adc/Kconfig
> +++ b/drivers/iio/adc/Kconfig
> @@ -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.
> diff --git a/drivers/iio/adc/ti-adc081c.c b/drivers/iio/adc/ti-adc081c.c
> index ecbc121..b977340 100644
> --- a/drivers/iio/adc/ti-adc081c.c
> +++ b/drivers/iio/adc/ti-adc081c.c
> @@ -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 <thierry.reding@avionic-design.de>");
> -MODULE_DESCRIPTION("Texas Instruments ADC081C021/027 driver");
> +MODULE_DESCRIPTION("Texas Instruments ADC081C/ADC101C/ADC121C driver");
>  MODULE_LICENSE("GPL v2");
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2016-04-17  9:46 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-04-11 14:24 [PATCH v3 0/2] iio: Add support for adc101 and adc121c to ti-adc081c Crestez Dan Leonard
2016-04-11 14:24 ` [PATCH v3 1/2] ti-adc081c: Add support for adc101c and adc121c Crestez Dan Leonard
2016-04-17  9:46   ` Jonathan Cameron
2016-04-11 14:24 ` [PATCH v3 2/2] ti-adc081c: Initial triggered buffer support Crestez Dan Leonard
2016-04-17  9:46   ` Jonathan Cameron

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.