devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] hwmon: (ads1015) Make gain and datarate configurable
@ 2011-03-09 13:52 Dirk Eibach
  2011-03-09 14:40 ` [lm-sensors] " Guenter Roeck
                   ` (2 more replies)
  0 siblings, 3 replies; 13+ messages in thread
From: Dirk Eibach @ 2011-03-09 13:52 UTC (permalink / raw)
  To: lm-sensors
  Cc: linux-doc, rdunlap, devicetree-discuss, w.sang, khali,
	Dirk Eibach

Signed-off-by: Dirk Eibach <eibach@gdsys.de>
---
 .../devicetree/bindings/hwmon/ads1015.txt          |   73 ++++++++++++++
 Documentation/devicetree/bindings/i2c/ads1015.txt  |   29 ------
 Documentation/hwmon/ads1015                        |   48 +++++++---
 drivers/hwmon/ads1015.c                            |  104 ++++++++++++++++----
 include/linux/i2c/ads1015.h                        |    8 ++
 5 files changed, 202 insertions(+), 60 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/hwmon/ads1015.txt
 delete mode 100644 Documentation/devicetree/bindings/i2c/ads1015.txt

diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
new file mode 100644
index 0000000..fb6e139
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
@@ -0,0 +1,73 @@
+ADS1015 (I2C)
+
+This device is a 12-bit A-D converter with 4 inputs.
+
+The inputs can be used single ended or in certain differential combinations.
+
+For configuration all possible combinations are mapped to 8 channels:
+  0: Voltage over AIN0 and AIN1.
+  1: Voltage over AIN0 and AIN3.
+  2: Voltage over AIN1 and AIN3.
+  3: Voltage over AIN2 and AIN3.
+  4: Voltage over AIN0 and GND.
+  5: Voltage over AIN1 and GND.
+  6: Voltage over AIN2 and GND.
+  7: Voltage over AIN3 and GND.
+
+Each channel can be configured indvidually:
+ - pga ist the programmable gain amplifier
+    0: FS = +/- 6.144 V
+    1: FS = +/- 4.096 V
+    2: FS = +/- 2.048 V (default)
+    3: FS = +/- 1.024 V
+    4: FS = +/- 0.512 V
+    5: FS = +/- 0.256 V
+ - data_rate in samples per second
+    0: 128
+    1: 250
+    2: 490
+    3: 920
+    4: 1600
+    5: 2400
+    6: 3300
+
+1) The /ads1015 node
+
+  Required properties:
+
+   - compatible : must be "ti,ads1015"
+   - reg : I2C busaddress of the device
+   - #address-cells : must be <1>
+   - #size-cells : must be <0>
+
+  The node contains child nodes for each channel that the platform uses.
+
+  Example ADS1015 node:
+
+    ads1015@49 {
+	    compatible = "ti,ads1015";
+	    reg = <0x49>;
+	    #address-cells = <1>;
+	    #size-cells = <0>;
+
+	    [ child node definitions... ]
+    }
+
+2) channel nodes
+
+  Required properties:
+
+   - reg : the channel number
+
+  Optional properties:
+
+   - ti,gain : the programmable gain amplifier setting
+   - ti,datarate : the converter datarate
+
+  Example ADS1015 node:
+
+    channel@4 {
+	    reg = <4>;
+	    ti,gain = <3>;
+	    ti,datarate = <5>;
+    };
diff --git a/Documentation/devicetree/bindings/i2c/ads1015.txt b/Documentation/devicetree/bindings/i2c/ads1015.txt
deleted file mode 100644
index 985e24d..0000000
--- a/Documentation/devicetree/bindings/i2c/ads1015.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-ADS1015 (I2C)
-
-This device is a 12-bit A-D converter with 4 inputs.
-
-The inputs can be used single ended or in certain differential combinations.
-
-For configuration all possible combinations are mapped to 8 channels:
-0: Voltage over AIN0 and AIN1.
-1: Voltage over AIN0 and AIN3.
-2: Voltage over AIN1 and AIN3.
-3: Voltage over AIN2 and AIN3.
-4: Voltage over AIN0 and GND.
-5: Voltage over AIN1 and GND.
-6: Voltage over AIN2 and GND.
-7: Voltage over AIN3 and GND.
-
-Optional properties:
-
- - exported-channels : exported_channels is a bitmask that specifies which
-		       channels should be accessible by the user.
-
-Example:
-ads1015@49 {
-	compatible = "ti,ads1015";
-	reg = <0x49>;
-	exported-channels = <0x14>;
-};
-
-In this example only channel 2 and 4 would be accessible by the user.
diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
index 56ee797..30250ca 100644
--- a/Documentation/hwmon/ads1015
+++ b/Documentation/hwmon/ads1015
@@ -38,30 +38,52 @@ Platform Data
 
 In linux/i2c/ads1015.h platform data is defined as:
 
+struct ads1015_channel_data {
+	unsigned int pga;
+	unsigned int data_rate;
+};
+
 struct ads1015_platform_data {
 	unsigned int exported_channels;
+	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
 };
 
 exported_channels is a bitmask that specifies which inputs should be exported.
 
+channel_data contains configuration data for the exported inputs:
+- pga ist the programmable gain amplifier
+  0: FS = +/- 6.144 V
+  1: FS = +/- 4.096 V
+  2: FS = +/- 2.048 V (default)
+  3: FS = +/- 1.024 V
+  4: FS = +/- 0.512 V
+  5: FS = +/- 0.256 V
+- data_rate in samples per second
+  0: 128
+  1: 250
+  2: 490
+  3: 920
+  4: 1600
+  5: 2400
+  6: 3300
+
 Example:
 struct ads1015_platform_data data = {
-	.exported_channels = (1 << 2) | (1 << 4)
+	.exported_channels = (1 << 2) | (1 << 4),
+	.channel_data = {
+		{},
+		{},
+		{ .pga = 1, .data_rate = 0 },
+		{},
+		{ .pga = 4, .data_rate = 5},
+	}
 };
 
-In this case only in2_input and in4_input would be created.
+In this case only in2_input(FS +/- 4.096 V, 128 SPS) and in4_input
+(FS +/- 0.512 V, 2400 SPS) would be created.
 
 Devicetree
 ----------
 
-The ads1015 node may have an "exported-channels" property.
-exported_channels is a bitmask that specifies which inputs should be exported.
-
-Example:
-ads1015@49 {
-	compatible = "ti,ads1015";
-	reg = <0x49>;
-	exported-channels = < 0x14 >;
-};
-
-In this case only in2_input and in4_input would be created.
+Configuration is also possible via devicetree:
+Documentation/devicetree/bindings/hwmon/ads1015.txt
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index 8ef2b60..8657863 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
+#include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
@@ -45,12 +45,18 @@ enum {
 static const unsigned int fullscale_table[8] = {
 	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
 
-#define ADS1015_CONFIG_CHANNELS 8
+/* Data rates in samples per second */
+static const unsigned int data_rate_table[8] = {
+	128, 250, 490, 920, 1600, 2400, 3300, 3300 };
+
 #define ADS1015_DEFAULT_CHANNELS 0xff
+#define ADS1015_DEFAULT_PGA 2
+#define ADS1015_DEFAULT_DATA_RATE 4
 
 struct ads1015_data {
 	struct device *hwmon_dev;
 	struct mutex update_lock; /* mutex protect updates */
+	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
 };
 
 static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
@@ -71,32 +77,38 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
 {
 	u16 config;
 	s16 conversion;
-	unsigned int pga;
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	unsigned int pga = data->channel_data[channel].pga;
 	int fullscale;
+	unsigned int data_rate = data->channel_data[channel].data_rate;
+	unsigned int conversion_time_ms;
 	unsigned int k;
-	struct ads1015_data *data = i2c_get_clientdata(client);
 	int res;
 
 	mutex_lock(&data->update_lock);
 
-	/* get fullscale voltage */
+	/* get channel parameters */
 	res = ads1015_read_reg(client, ADS1015_CONFIG);
 	if (res < 0)
 		goto err_unlock;
 	config = res;
-	pga = (config >> 9) & 0x0007;
 	fullscale = fullscale_table[pga];
+	conversion_time_ms = 1 + 1000 / data_rate_table[data_rate];
 
 	/* set channel and start single conversion */
-	config &= ~(0x0007 << 12);
-	config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12;
+	config &= 0x001f;
+	config |= (1 << 15) | (1 << 8);
+	config |= (channel & 0x0007) << 12;
+	config |= (pga & 0x0007) << 9;
+	config |= (data_rate & 0x0007) << 5;
 
-	/* wait until conversion finished */
 	res = ads1015_write_reg(client, ADS1015_CONFIG, config);
 	if (res < 0)
 		goto err_unlock;
+
+	/* wait until conversion finished */
 	for (k = 0; k < 5; ++k) {
-		schedule_timeout(msecs_to_jiffies(1));
+		msleep(k ? 1 : conversion_time_ms);
 		res = ads1015_read_reg(client, ADS1015_CONFIG);
 		if (res < 0)
 			goto err_unlock;
@@ -168,26 +180,82 @@ static int ads1015_remove(struct i2c_client *client)
 
 static unsigned int ads1015_get_exported_channels(struct i2c_client *client)
 {
+	unsigned int k;
+	struct ads1015_data *data = i2c_get_clientdata(client);
 	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
 #ifdef CONFIG_OF
-	struct device_node *np = client->dev.of_node;
-	const __be32 *of_channels;
-	int of_channels_size;
+	unsigned int of_exported_channels = 0;
+	struct device_node *node;
 #endif
 
 	/* prefer platform data */
-	if (pdata)
+	if (pdata) {
+		memcpy(data->channel_data, pdata->channel_data,
+		       sizeof(data->channel_data));
 		return pdata->exported_channels;
+	}
 
 #ifdef CONFIG_OF
 	/* fallback on OF */
-	of_channels = of_get_property(np, "exported-channels",
-				      &of_channels_size);
-	if (of_channels && (of_channels_size == sizeof(*of_channels)))
-		return be32_to_cpup(of_channels);
+	if (!client->dev.of_node
+	    || !of_get_next_child(client->dev.of_node, NULL))
+		goto fallback_default;
+
+	for_each_child_of_node(client->dev.of_node, node) {
+		const __be32 *property;
+		int len;
+		unsigned int channel;
+		unsigned int pga = ADS1015_DEFAULT_PGA;
+		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
+
+		property = of_get_property(node, "reg", &len);
+		if (!property || (len < sizeof(int))) {
+			dev_err(&client->dev, "ads1015: invalid reg on %s\n",
+				node->full_name);
+			continue;
+		}
+
+		channel = be32_to_cpup(property);
+		if (channel > ADS1015_CONFIG_CHANNELS) {
+			dev_err(&client->dev, "ads1015: invalid addr=%x on %s\n",
+				channel, node->full_name);
+			continue;
+		}
+
+		property = of_get_property(node, "ti,gain", &len);
+		if (property && (len == sizeof(int))) {
+			pga = be32_to_cpup(property);
+			if (pga > 7) {
+				dev_err(&client->dev,
+					"ads1015: invalid gain on %s\n",
+					node->full_name);
+			}
+		}
+
+		property = of_get_property(node, "ti,datarate", &len);
+		if (property && (len == sizeof(int))) {
+			data_rate = be32_to_cpup(property);
+			if (data_rate > 7)
+				dev_err(&client->dev,
+					"ads1015: invalid data_rate on %s\n",
+					node->full_name);
+		}
+
+		of_exported_channels |= (1 << channel);
+		data->channel_data[channel].pga = pga;
+		data->channel_data[channel].data_rate = data_rate;
+	}
+
+	return of_exported_channels;
 #endif
 
 	/* fallback on default configuration */
+fallback_default:
+	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
+		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
+		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
+	}
+
 	return ADS1015_DEFAULT_CHANNELS;
 }
 
diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
index 8541c6a..8f32040 100644
--- a/include/linux/i2c/ads1015.h
+++ b/include/linux/i2c/ads1015.h
@@ -21,8 +21,16 @@
 #ifndef LINUX_ADS1015_H
 #define LINUX_ADS1015_H
 
+#define ADS1015_CONFIG_CHANNELS 8
+
+struct ads1015_channel_data {
+	unsigned int pga;
+	unsigned int data_rate;
+};
+
 struct ads1015_platform_data {
 	unsigned int exported_channels;
+	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
 };
 
 #endif /* LINUX_ADS1015_H */
-- 
1.5.6.5


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

* Re: [lm-sensors] [PATCH] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-09 13:52 [PATCH] hwmon: (ads1015) Make gain and datarate configurable Dirk Eibach
@ 2011-03-09 14:40 ` Guenter Roeck
  2011-03-09 14:47   ` Eibach, Dirk
  2011-03-10 19:04 ` Guenter Roeck
  2011-03-12  8:18 ` Grant Likely
  2 siblings, 1 reply; 13+ messages in thread
From: Guenter Roeck @ 2011-03-09 14:40 UTC (permalink / raw)
  To: Dirk Eibach
  Cc: lm-sensors@lm-sensors.org, linux-doc@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, w.sang@pengutronix.de,
	rdunlap@xenotime.net

Hi Dirk,

On Wed, Mar 09, 2011 at 08:52:40AM -0500, Dirk Eibach wrote:
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>
> ---
>  .../devicetree/bindings/hwmon/ads1015.txt          |   73 ++++++++++++++
>  Documentation/devicetree/bindings/i2c/ads1015.txt  |   29 ------
>  Documentation/hwmon/ads1015                        |   48 +++++++---
>  drivers/hwmon/ads1015.c                            |  104 ++++++++++++++++----
>  include/linux/i2c/ads1015.h                        |    8 ++
>  5 files changed, 202 insertions(+), 60 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/hwmon/ads1015.txt
>  delete mode 100644 Documentation/devicetree/bindings/i2c/ads1015.txt
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> new file mode 100644
> index 0000000..fb6e139
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> @@ -0,0 +1,73 @@
> +ADS1015 (I2C)
> +
> +This device is a 12-bit A-D converter with 4 inputs.
> +
> +The inputs can be used single ended or in certain differential combinations.
> +
> +For configuration all possible combinations are mapped to 8 channels:
> +  0: Voltage over AIN0 and AIN1.
> +  1: Voltage over AIN0 and AIN3.
> +  2: Voltage over AIN1 and AIN3.
> +  3: Voltage over AIN2 and AIN3.
> +  4: Voltage over AIN0 and GND.
> +  5: Voltage over AIN1 and GND.
> +  6: Voltage over AIN2 and GND.
> +  7: Voltage over AIN3 and GND.
> +
> +Each channel can be configured indvidually:
> + - pga ist the programmable gain amplifier
> +    0: FS = +/- 6.144 V
> +    1: FS = +/- 4.096 V
> +    2: FS = +/- 2.048 V (default)
> +    3: FS = +/- 1.024 V
> +    4: FS = +/- 0.512 V
> +    5: FS = +/- 0.256 V
> + - data_rate in samples per second
> +    0: 128
> +    1: 250
> +    2: 490
> +    3: 920
> +    4: 1600
> +    5: 2400
> +    6: 3300
> +

I thought the data rate only applies for continuous mode, which you don't use.
What does it do in single shot mode ?

Thanks,
Guenter

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

* RE: [lm-sensors] [PATCH] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-09 14:40 ` [lm-sensors] " Guenter Roeck
@ 2011-03-09 14:47   ` Eibach, Dirk
  0 siblings, 0 replies; 13+ messages in thread
From: Eibach, Dirk @ 2011-03-09 14:47 UTC (permalink / raw)
  To: Guenter Roeck; +Cc: lm-sensors, linux-doc, devicetree-discuss, w.sang, rdunlap


> Hi Dirk,

Hi Guenter,

> ...
> > +Each channel can be configured indvidually:
> > + - pga ist the programmable gain amplifier
> > +    0: FS = +/- 6.144 V
> > +    1: FS = +/- 4.096 V
> > +    2: FS = +/- 2.048 V (default)
> > +    3: FS = +/- 1.024 V
> > +    4: FS = +/- 0.512 V
> > +    5: FS = +/- 0.256 V
> > + - data_rate in samples per second
> > +    0: 128
> > +    1: 250
> > +    2: 490
> > +    3: 920
> > +    4: 1600
> > +    5: 2400
> > +    6: 3300
> > +
> 
> I thought the data rate only applies for continuous mode, 
> which you don't use.
> What does it do in single shot mode ?

It affects the sigma delta integration time and as a result the
conversion time.

> Thanks,
> Guenter

Cheers
Dirk



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

* Re: [lm-sensors] [PATCH] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-09 13:52 [PATCH] hwmon: (ads1015) Make gain and datarate configurable Dirk Eibach
  2011-03-09 14:40 ` [lm-sensors] " Guenter Roeck
@ 2011-03-10 19:04 ` Guenter Roeck
  2011-03-12  8:18 ` Grant Likely
  2 siblings, 0 replies; 13+ messages in thread
From: Guenter Roeck @ 2011-03-10 19:04 UTC (permalink / raw)
  To: Dirk Eibach
  Cc: lm-sensors@lm-sensors.org, linux-doc@vger.kernel.org,
	devicetree-discuss@lists.ozlabs.org, w.sang@pengutronix.de,
	rdunlap@xenotime.net

Hi Dirk,

On Wed, 2011-03-09 at 08:52 -0500, Dirk Eibach wrote:
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>
> ---
>  .../devicetree/bindings/hwmon/ads1015.txt          |   73 ++++++++++++++
>  Documentation/devicetree/bindings/i2c/ads1015.txt  |   29 ------
>  Documentation/hwmon/ads1015                        |   48 +++++++---
>  drivers/hwmon/ads1015.c                            |  104 ++++++++++++++++----
>  include/linux/i2c/ads1015.h                        |    8 ++
>  5 files changed, 202 insertions(+), 60 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/hwmon/ads1015.txt
>  delete mode 100644 Documentation/devicetree/bindings/i2c/ads1015.txt
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> new file mode 100644
> index 0000000..fb6e139
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> @@ -0,0 +1,73 @@
> +ADS1015 (I2C)
> +
> +This device is a 12-bit A-D converter with 4 inputs.
> +
> +The inputs can be used single ended or in certain differential combinations.
> +
> +For configuration all possible combinations are mapped to 8 channels:
> +  0: Voltage over AIN0 and AIN1.
> +  1: Voltage over AIN0 and AIN3.
> +  2: Voltage over AIN1 and AIN3.
> +  3: Voltage over AIN2 and AIN3.
> +  4: Voltage over AIN0 and GND.
> +  5: Voltage over AIN1 and GND.
> +  6: Voltage over AIN2 and GND.
> +  7: Voltage over AIN3 and GND.
> +
> +Each channel can be configured indvidually:
> + - pga ist the programmable gain amplifier
> +    0: FS = +/- 6.144 V
> +    1: FS = +/- 4.096 V
> +    2: FS = +/- 2.048 V (default)
> +    3: FS = +/- 1.024 V
> +    4: FS = +/- 0.512 V
> +    5: FS = +/- 0.256 V
> + - data_rate in samples per second
> +    0: 128
> +    1: 250
> +    2: 490
> +    3: 920
> +    4: 1600
> +    5: 2400
> +    6: 3300
> +
Just a thought ... if you specify the data rate (and possibly pga) this
way, you'll have to redefine its meaning for ads1115. If you just define
it as "samples per second" and then calculate the index from it in the
code (eg as closest match), you'd be done.

> +1) The /ads1015 node
> +
> +  Required properties:
> +
> +   - compatible : must be "ti,ads1015"
> +   - reg : I2C busaddress of the device
> +   - #address-cells : must be <1>
> +   - #size-cells : must be <0>
> +
> +  The node contains child nodes for each channel that the platform uses.
> +
> +  Example ADS1015 node:
> +
> +    ads1015@49 {
> +           compatible = "ti,ads1015";
> +           reg = <0x49>;
> +           #address-cells = <1>;
> +           #size-cells = <0>;
> +
> +           [ child node definitions... ]
> +    }
> +
> +2) channel nodes
> +
> +  Required properties:
> +
> +   - reg : the channel number
> +
> +  Optional properties:
> +
> +   - ti,gain : the programmable gain amplifier setting
> +   - ti,datarate : the converter datarate
> +
> +  Example ADS1015 node:
> +
> +    channel@4 {
> +           reg = <4>;
> +           ti,gain = <3>;
> +           ti,datarate = <5>;
> +    };
> diff --git a/Documentation/devicetree/bindings/i2c/ads1015.txt b/Documentation/devicetree/bindings/i2c/ads1015.txt
> deleted file mode 100644
> index 985e24d..0000000
> --- a/Documentation/devicetree/bindings/i2c/ads1015.txt
> +++ /dev/null
> @@ -1,29 +0,0 @@
> -ADS1015 (I2C)
> -
> -This device is a 12-bit A-D converter with 4 inputs.
> -
> -The inputs can be used single ended or in certain differential combinations.
> -
> -For configuration all possible combinations are mapped to 8 channels:
> -0: Voltage over AIN0 and AIN1.
> -1: Voltage over AIN0 and AIN3.
> -2: Voltage over AIN1 and AIN3.
> -3: Voltage over AIN2 and AIN3.
> -4: Voltage over AIN0 and GND.
> -5: Voltage over AIN1 and GND.
> -6: Voltage over AIN2 and GND.
> -7: Voltage over AIN3 and GND.
> -
> -Optional properties:
> -
> - - exported-channels : exported_channels is a bitmask that specifies which
> -                      channels should be accessible by the user.
> -
> -Example:
> -ads1015@49 {
> -       compatible = "ti,ads1015";
> -       reg = <0x49>;
> -       exported-channels = <0x14>;
> -};
> -
> -In this example only channel 2 and 4 would be accessible by the user.
> diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
> index 56ee797..30250ca 100644
> --- a/Documentation/hwmon/ads1015
> +++ b/Documentation/hwmon/ads1015
> @@ -38,30 +38,52 @@ Platform Data
> 
>  In linux/i2c/ads1015.h platform data is defined as:
> 
> +struct ads1015_channel_data {
> +       unsigned int pga;
> +       unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
>         unsigned int exported_channels;
> +       struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
> 
>  exported_channels is a bitmask that specifies which inputs should be exported.
> 
> +channel_data contains configuration data for the exported inputs:
> +- pga ist the programmable gain amplifier
> +  0: FS = +/- 6.144 V
> +  1: FS = +/- 4.096 V
> +  2: FS = +/- 2.048 V (default)
> +  3: FS = +/- 1.024 V
> +  4: FS = +/- 0.512 V
> +  5: FS = +/- 0.256 V
> +- data_rate in samples per second
> +  0: 128
> +  1: 250
> +  2: 490
> +  3: 920
> +  4: 1600
> +  5: 2400
> +  6: 3300
> +
>  Example:
>  struct ads1015_platform_data data = {
> -       .exported_channels = (1 << 2) | (1 << 4)
> +       .exported_channels = (1 << 2) | (1 << 4),
> +       .channel_data = {
> +               {},
> +               {},
> +               { .pga = 1, .data_rate = 0 },
> +               {},
> +               { .pga = 4, .data_rate = 5},

Should have a blank between 5 and } for consistency.

> +       }
>  };
> 
> -In this case only in2_input and in4_input would be created.
> +In this case only in2_input(FS +/- 4.096 V, 128 SPS) and in4_input
> +(FS +/- 0.512 V, 2400 SPS) would be created.
> 
>  Devicetree
>  ----------
> 
> -The ads1015 node may have an "exported-channels" property.
> -exported_channels is a bitmask that specifies which inputs should be exported.
> -
> -Example:
> -ads1015@49 {
> -       compatible = "ti,ads1015";
> -       reg = <0x49>;
> -       exported-channels = < 0x14 >;
> -};
> -
> -In this case only in2_input and in4_input would be created.
> +Configuration is also possible via devicetree:
> +Documentation/devicetree/bindings/hwmon/ads1015.txt
> diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
> index 8ef2b60..8657863 100644
> --- a/drivers/hwmon/ads1015.c
> +++ b/drivers/hwmon/ads1015.c
> @@ -25,7 +25,7 @@
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> -#include <linux/jiffies.h>
> +#include <linux/delay.h>
>  #include <linux/i2c.h>
>  #include <linux/hwmon.h>
>  #include <linux/hwmon-sysfs.h>
> @@ -45,12 +45,18 @@ enum {
>  static const unsigned int fullscale_table[8] = {
>         6144, 4096, 2048, 1024, 512, 256, 256, 256 };
> 
> -#define ADS1015_CONFIG_CHANNELS 8
> +/* Data rates in samples per second */
> +static const unsigned int data_rate_table[8] = {
> +       128, 250, 490, 920, 1600, 2400, 3300, 3300 };
> +
>  #define ADS1015_DEFAULT_CHANNELS 0xff
> +#define ADS1015_DEFAULT_PGA 2
> +#define ADS1015_DEFAULT_DATA_RATE 4
> 
>  struct ads1015_data {
>         struct device *hwmon_dev;
>         struct mutex update_lock; /* mutex protect updates */
> +       struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
> 
>  static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
> @@ -71,32 +77,38 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
>  {
>         u16 config;
>         s16 conversion;
> -       unsigned int pga;
> +       struct ads1015_data *data = i2c_get_clientdata(client);
> +       unsigned int pga = data->channel_data[channel].pga;
>         int fullscale;
> +       unsigned int data_rate = data->channel_data[channel].data_rate;
> +       unsigned int conversion_time_ms;
>         unsigned int k;
> -       struct ads1015_data *data = i2c_get_clientdata(client);
>         int res;
> 
>         mutex_lock(&data->update_lock);
> 
> -       /* get fullscale voltage */
> +       /* get channel parameters */
>         res = ads1015_read_reg(client, ADS1015_CONFIG);
>         if (res < 0)
>                 goto err_unlock;
>         config = res;
> -       pga = (config >> 9) & 0x0007;
>         fullscale = fullscale_table[pga];
> +       conversion_time_ms = 1 + 1000 / data_rate_table[data_rate];
> 
>         /* set channel and start single conversion */
> -       config &= ~(0x0007 << 12);
> -       config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12;
> +       config &= 0x001f;
> +       config |= (1 << 15) | (1 << 8);
> +       config |= (channel & 0x0007) << 12;
> +       config |= (pga & 0x0007) << 9;
> +       config |= (data_rate & 0x0007) << 5;
> 
> -       /* wait until conversion finished */
>         res = ads1015_write_reg(client, ADS1015_CONFIG, config);
>         if (res < 0)
>                 goto err_unlock;
> +
> +       /* wait until conversion finished */
>         for (k = 0; k < 5; ++k) {
> -               schedule_timeout(msecs_to_jiffies(1));
> +               msleep(k ? 1 : conversion_time_ms);
>                 res = ads1015_read_reg(client, ADS1015_CONFIG);
>                 if (res < 0)
>                         goto err_unlock;
> @@ -168,26 +180,82 @@ static int ads1015_remove(struct i2c_client *client)
> 
>  static unsigned int ads1015_get_exported_channels(struct i2c_client *client)
>  {
> +       unsigned int k;
> +       struct ads1015_data *data = i2c_get_clientdata(client);
>         struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
>  #ifdef CONFIG_OF
> -       struct device_node *np = client->dev.of_node;
> -       const __be32 *of_channels;
> -       int of_channels_size;
> +       unsigned int of_exported_channels = 0;
> +       struct device_node *node;
>  #endif
> 
>         /* prefer platform data */
> -       if (pdata)
> +       if (pdata) {
> +               memcpy(data->channel_data, pdata->channel_data,
> +                      sizeof(data->channel_data));
>                 return pdata->exported_channels;
> +       }
> 
>  #ifdef CONFIG_OF
>         /* fallback on OF */
> -       of_channels = of_get_property(np, "exported-channels",
> -                                     &of_channels_size);
> -       if (of_channels && (of_channels_size == sizeof(*of_channels)))
> -               return be32_to_cpup(of_channels);
> +       if (!client->dev.of_node
> +           || !of_get_next_child(client->dev.of_node, NULL))
> +               goto fallback_default;
> +
> +       for_each_child_of_node(client->dev.of_node, node) {
> +               const __be32 *property;
> +               int len;
> +               unsigned int channel;
> +               unsigned int pga = ADS1015_DEFAULT_PGA;
> +               unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
> +
> +               property = of_get_property(node, "reg", &len);
> +               if (!property || (len < sizeof(int))) {
> +                       dev_err(&client->dev, "ads1015: invalid reg on %s\n",
> +                               node->full_name);
> +                       continue;
> +               }
> +
> +               channel = be32_to_cpup(property);
> +               if (channel > ADS1015_CONFIG_CHANNELS) {
> +                       dev_err(&client->dev, "ads1015: invalid addr=%x on %s\n",
> +                               channel, node->full_name);
> +                       continue;
> +               }

Can channel be < 0 ?

> +
> +               property = of_get_property(node, "ti,gain", &len);
> +               if (property && (len == sizeof(int))) {
> +                       pga = be32_to_cpup(property);
> +                       if (pga > 7) {
> +                               dev_err(&client->dev,
> +                                       "ads1015: invalid gain on %s\n",
> +                                       node->full_name);
> +                       }
> +               }

Can pga be < 0 ? Also, no action if pga is bad ?

> +
> +               property = of_get_property(node, "ti,datarate", &len);
> +               if (property && (len == sizeof(int))) {
> +                       data_rate = be32_to_cpup(property);
> +                       if (data_rate > 7)
> +                               dev_err(&client->dev,
> +                                       "ads1015: invalid data_rate on %s\n",
> +                                       node->full_name);
> +               }

No action if data_rate is bad ? And can it be < 0 ?

> +
> +               of_exported_channels |= (1 << channel);
> +               data->channel_data[channel].pga = pga;
> +               data->channel_data[channel].data_rate = data_rate;
> +       }
> +
> +       return of_exported_channels;
>  #endif
> 
>         /* fallback on default configuration */
> +fallback_default:
> +       for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
> +               data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
> +               data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
> +       }
> +
>         return ADS1015_DEFAULT_CHANNELS;
>  }
> 
> diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
> index 8541c6a..8f32040 100644
> --- a/include/linux/i2c/ads1015.h
> +++ b/include/linux/i2c/ads1015.h
> @@ -21,8 +21,16 @@
>  #ifndef LINUX_ADS1015_H
>  #define LINUX_ADS1015_H
> 
> +#define ADS1015_CONFIG_CHANNELS 8
> +
> +struct ads1015_channel_data {
> +       unsigned int pga;
> +       unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
>         unsigned int exported_channels;
> +       struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
> 
>  #endif /* LINUX_ADS1015_H */
> --
> 1.5.6.5
> 
> 
> _______________________________________________
> lm-sensors mailing list
> lm-sensors@lm-sensors.org
> http://lists.lm-sensors.org/mailman/listinfo/lm-sensors



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

* Re: [PATCH] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-09 13:52 [PATCH] hwmon: (ads1015) Make gain and datarate configurable Dirk Eibach
  2011-03-09 14:40 ` [lm-sensors] " Guenter Roeck
  2011-03-10 19:04 ` Guenter Roeck
@ 2011-03-12  8:18 ` Grant Likely
  2011-03-16 10:01   ` [PATCH v2] " Dirk Eibach
  2 siblings, 1 reply; 13+ messages in thread
From: Grant Likely @ 2011-03-12  8:18 UTC (permalink / raw)
  To: Dirk Eibach; +Cc: lm-sensors, linux-doc, devicetree-discuss, rdunlap, khali

On Wed, Mar 09, 2011 at 02:52:40PM +0100, Dirk Eibach wrote:
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>

Hi Dirk,

Patches need a description.  Very seldom is the patch title
sufficient, and usually only for trivial stuff.  Tell us some details
about what the patch does and what testing has been performed on it.

> ---
>  .../devicetree/bindings/hwmon/ads1015.txt          |   73 ++++++++++++++
>  Documentation/devicetree/bindings/i2c/ads1015.txt  |   29 ------

Huh?  What tree is this patch committed against?  If this is a
follow-on to a previous patch, then the patch description should
detail that information.

>  Documentation/hwmon/ads1015                        |   48 +++++++---
>  drivers/hwmon/ads1015.c                            |  104 ++++++++++++++++----
>  include/linux/i2c/ads1015.h                        |    8 ++
>  5 files changed, 202 insertions(+), 60 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/hwmon/ads1015.txt
>  delete mode 100644 Documentation/devicetree/bindings/i2c/ads1015.txt
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> new file mode 100644
> index 0000000..fb6e139
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> @@ -0,0 +1,73 @@
> +ADS1015 (I2C)
> +
> +This device is a 12-bit A-D converter with 4 inputs.
> +
> +The inputs can be used single ended or in certain differential combinations.
> +
> +For configuration all possible combinations are mapped to 8 channels:
> +  0: Voltage over AIN0 and AIN1.
> +  1: Voltage over AIN0 and AIN3.
> +  2: Voltage over AIN1 and AIN3.
> +  3: Voltage over AIN2 and AIN3.
> +  4: Voltage over AIN0 and GND.
> +  5: Voltage over AIN1 and GND.
> +  6: Voltage over AIN2 and GND.
> +  7: Voltage over AIN3 and GND.
> +
> +Each channel can be configured indvidually:
> + - pga ist the programmable gain amplifier
> +    0: FS = +/- 6.144 V
> +    1: FS = +/- 4.096 V
> +    2: FS = +/- 2.048 V (default)
> +    3: FS = +/- 1.024 V
> +    4: FS = +/- 0.512 V
> +    5: FS = +/- 0.256 V
> + - data_rate in samples per second
> +    0: 128
> +    1: 250
> +    2: 490
> +    3: 920
> +    4: 1600
> +    5: 2400
> +    6: 3300
> +
> +1) The /ads1015 node
> +
> +  Required properties:
> +
> +   - compatible : must be "ti,ads1015"
> +   - reg : I2C busaddress of the device
> +   - #address-cells : must be <1>
> +   - #size-cells : must be <0>
> +
> +  The node contains child nodes for each channel that the platform uses.
> +
> +  Example ADS1015 node:
> +
> +    ads1015@49 {
> +	    compatible = "ti,ads1015";
> +	    reg = <0x49>;
> +	    #address-cells = <1>;
> +	    #size-cells = <0>;
> +
> +	    [ child node definitions... ]
> +    }
> +
> +2) channel nodes
> +
> +  Required properties:
> +
> +   - reg : the channel number
> +
> +  Optional properties:
> +
> +   - ti,gain : the programmable gain amplifier setting
> +   - ti,datarate : the converter datarate
> +
> +  Example ADS1015 node:
> +
> +    channel@4 {
> +	    reg = <4>;
> +	    ti,gain = <3>;
> +	    ti,datarate = <5>;
> +    };

Binding looks good to me.

> diff --git a/Documentation/devicetree/bindings/i2c/ads1015.txt b/Documentation/devicetree/bindings/i2c/ads1015.txt
> deleted file mode 100644
> index 985e24d..0000000
> --- a/Documentation/devicetree/bindings/i2c/ads1015.txt
> +++ /dev/null
> @@ -1,29 +0,0 @@
> -ADS1015 (I2C)
> -
> -This device is a 12-bit A-D converter with 4 inputs.
> -
> -The inputs can be used single ended or in certain differential combinations.
> -
> -For configuration all possible combinations are mapped to 8 channels:
> -0: Voltage over AIN0 and AIN1.
> -1: Voltage over AIN0 and AIN3.
> -2: Voltage over AIN1 and AIN3.
> -3: Voltage over AIN2 and AIN3.
> -4: Voltage over AIN0 and GND.
> -5: Voltage over AIN1 and GND.
> -6: Voltage over AIN2 and GND.
> -7: Voltage over AIN3 and GND.
> -
> -Optional properties:
> -
> - - exported-channels : exported_channels is a bitmask that specifies which
> -		       channels should be accessible by the user.
> -
> -Example:
> -ads1015@49 {
> -	compatible = "ti,ads1015";
> -	reg = <0x49>;
> -	exported-channels = <0x14>;
> -};
> -
> -In this example only channel 2 and 4 would be accessible by the user.
> diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
> index 56ee797..30250ca 100644
> --- a/Documentation/hwmon/ads1015
> +++ b/Documentation/hwmon/ads1015
> @@ -38,30 +38,52 @@ Platform Data
>  
>  In linux/i2c/ads1015.h platform data is defined as:
>  
> +struct ads1015_channel_data {
> +	unsigned int pga;
> +	unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
>  	unsigned int exported_channels;
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  exported_channels is a bitmask that specifies which inputs should be exported.
>  
> +channel_data contains configuration data for the exported inputs:
> +- pga ist the programmable gain amplifier
> +  0: FS = +/- 6.144 V
> +  1: FS = +/- 4.096 V
> +  2: FS = +/- 2.048 V (default)
> +  3: FS = +/- 1.024 V
> +  4: FS = +/- 0.512 V
> +  5: FS = +/- 0.256 V
> +- data_rate in samples per second
> +  0: 128
> +  1: 250
> +  2: 490
> +  3: 920
> +  4: 1600
> +  5: 2400
> +  6: 3300
> +
>  Example:
>  struct ads1015_platform_data data = {
> -	.exported_channels = (1 << 2) | (1 << 4)
> +	.exported_channels = (1 << 2) | (1 << 4),
> +	.channel_data = {
> +		{},
> +		{},
> +		{ .pga = 1, .data_rate = 0 },
> +		{},
> +		{ .pga = 4, .data_rate = 5},
> +	}

You can use explicit C99 array initializers here which would be more
concise; something like:

.channel_data = {
	[2] = { .pga = 1, .data_rate = 0 },
	[4] = { .pga = 4, .data_rate = 5 },
}

Also, would it not make sense to encode the exported_channels bit into
this array too.  Maybe something like this?

.channel_data = {
	[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
	[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
}



>  };
>  
> -In this case only in2_input and in4_input would be created.
> +In this case only in2_input(FS +/- 4.096 V, 128 SPS) and in4_input
> +(FS +/- 0.512 V, 2400 SPS) would be created.
>  
>  Devicetree
>  ----------
>  
> -The ads1015 node may have an "exported-channels" property.
> -exported_channels is a bitmask that specifies which inputs should be exported.
> -
> -Example:
> -ads1015@49 {
> -	compatible = "ti,ads1015";
> -	reg = <0x49>;
> -	exported-channels = < 0x14 >;
> -};
> -
> -In this case only in2_input and in4_input would be created.
> +Configuration is also possible via devicetree:
> +Documentation/devicetree/bindings/hwmon/ads1015.txt
> diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
> index 8ef2b60..8657863 100644
> --- a/drivers/hwmon/ads1015.c
> +++ b/drivers/hwmon/ads1015.c
> @@ -25,7 +25,7 @@
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> -#include <linux/jiffies.h>
> +#include <linux/delay.h>
>  #include <linux/i2c.h>
>  #include <linux/hwmon.h>
>  #include <linux/hwmon-sysfs.h>
> @@ -45,12 +45,18 @@ enum {
>  static const unsigned int fullscale_table[8] = {
>  	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
>  
> -#define ADS1015_CONFIG_CHANNELS 8
> +/* Data rates in samples per second */
> +static const unsigned int data_rate_table[8] = {
> +	128, 250, 490, 920, 1600, 2400, 3300, 3300 };
> +
>  #define ADS1015_DEFAULT_CHANNELS 0xff
> +#define ADS1015_DEFAULT_PGA 2
> +#define ADS1015_DEFAULT_DATA_RATE 4
>  
>  struct ads1015_data {
>  	struct device *hwmon_dev;
>  	struct mutex update_lock; /* mutex protect updates */
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
> @@ -71,32 +77,38 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
>  {
>  	u16 config;
>  	s16 conversion;
> -	unsigned int pga;
> +	struct ads1015_data *data = i2c_get_clientdata(client);
> +	unsigned int pga = data->channel_data[channel].pga;
>  	int fullscale;
> +	unsigned int data_rate = data->channel_data[channel].data_rate;
> +	unsigned int conversion_time_ms;
>  	unsigned int k;
> -	struct ads1015_data *data = i2c_get_clientdata(client);
>  	int res;
>  
>  	mutex_lock(&data->update_lock);
>  
> -	/* get fullscale voltage */
> +	/* get channel parameters */
>  	res = ads1015_read_reg(client, ADS1015_CONFIG);
>  	if (res < 0)
>  		goto err_unlock;
>  	config = res;
> -	pga = (config >> 9) & 0x0007;
>  	fullscale = fullscale_table[pga];
> +	conversion_time_ms = 1 + 1000 / data_rate_table[data_rate];
>  
>  	/* set channel and start single conversion */
> -	config &= ~(0x0007 << 12);
> -	config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12;
> +	config &= 0x001f;
> +	config |= (1 << 15) | (1 << 8);
> +	config |= (channel & 0x0007) << 12;
> +	config |= (pga & 0x0007) << 9;
> +	config |= (data_rate & 0x0007) << 5;
>  
> -	/* wait until conversion finished */
>  	res = ads1015_write_reg(client, ADS1015_CONFIG, config);
>  	if (res < 0)
>  		goto err_unlock;
> +
> +	/* wait until conversion finished */
>  	for (k = 0; k < 5; ++k) {
> -		schedule_timeout(msecs_to_jiffies(1));
> +		msleep(k ? 1 : conversion_time_ms);
>  		res = ads1015_read_reg(client, ADS1015_CONFIG);
>  		if (res < 0)
>  			goto err_unlock;
> @@ -168,26 +180,82 @@ static int ads1015_remove(struct i2c_client *client)
>  
>  static unsigned int ads1015_get_exported_channels(struct i2c_client *client)
>  {
> +	unsigned int k;
> +	struct ads1015_data *data = i2c_get_clientdata(client);
>  	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
>  #ifdef CONFIG_OF
> -	struct device_node *np = client->dev.of_node;
> -	const __be32 *of_channels;
> -	int of_channels_size;
> +	unsigned int of_exported_channels = 0;
> +	struct device_node *node;
>  #endif
>  
>  	/* prefer platform data */
> -	if (pdata)
> +	if (pdata) {
> +		memcpy(data->channel_data, pdata->channel_data,
> +		       sizeof(data->channel_data));
>  		return pdata->exported_channels;
> +	}
>  
>  #ifdef CONFIG_OF
>  	/* fallback on OF */
> -	of_channels = of_get_property(np, "exported-channels",
> -				      &of_channels_size);
> -	if (of_channels && (of_channels_size == sizeof(*of_channels)))
> -		return be32_to_cpup(of_channels);
> +	if (!client->dev.of_node
> +	    || !of_get_next_child(client->dev.of_node, NULL))
> +		goto fallback_default;
> +
> +	for_each_child_of_node(client->dev.of_node, node) {
> +		const __be32 *property;
> +		int len;
> +		unsigned int channel;
> +		unsigned int pga = ADS1015_DEFAULT_PGA;
> +		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
> +
> +		property = of_get_property(node, "reg", &len);
> +		if (!property || (len < sizeof(int))) {
> +			dev_err(&client->dev, "ads1015: invalid reg on %s\n",
> +				node->full_name);
> +			continue;
> +		}
> +
> +		channel = be32_to_cpup(property);
> +		if (channel > ADS1015_CONFIG_CHANNELS) {
> +			dev_err(&client->dev, "ads1015: invalid addr=%x on %s\n",
> +				channel, node->full_name);
> +			continue;
> +		}
> +
> +		property = of_get_property(node, "ti,gain", &len);
> +		if (property && (len == sizeof(int))) {
> +			pga = be32_to_cpup(property);
> +			if (pga > 7) {
> +				dev_err(&client->dev,
> +					"ads1015: invalid gain on %s\n",
> +					node->full_name);
> +			}
> +		}
> +
> +		property = of_get_property(node, "ti,datarate", &len);
> +		if (property && (len == sizeof(int))) {
> +			data_rate = be32_to_cpup(property);
> +			if (data_rate > 7)
> +				dev_err(&client->dev,
> +					"ads1015: invalid data_rate on %s\n",
> +					node->full_name);
> +		}
> +
> +		of_exported_channels |= (1 << channel);
> +		data->channel_data[channel].pga = pga;
> +		data->channel_data[channel].data_rate = data_rate;
> +	}
> +
> +	return of_exported_channels;
>  #endif
>  
>  	/* fallback on default configuration */
> +fallback_default:
> +	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
> +		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
> +		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
> +	}
> +
>  	return ADS1015_DEFAULT_CHANNELS;
>  }
>  
> diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
> index 8541c6a..8f32040 100644
> --- a/include/linux/i2c/ads1015.h
> +++ b/include/linux/i2c/ads1015.h
> @@ -21,8 +21,16 @@
>  #ifndef LINUX_ADS1015_H
>  #define LINUX_ADS1015_H
>  
> +#define ADS1015_CONFIG_CHANNELS 8
> +
> +struct ads1015_channel_data {
> +	unsigned int pga;
> +	unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
>  	unsigned int exported_channels;
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  #endif /* LINUX_ADS1015_H */
> -- 
> 1.5.6.5
> 
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* [PATCH v2] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-12  8:18 ` Grant Likely
@ 2011-03-16 10:01   ` Dirk Eibach
  2011-03-16 20:46     ` Grant Likely
  2011-03-18 21:02     ` Jean Delvare
  0 siblings, 2 replies; 13+ messages in thread
From: Dirk Eibach @ 2011-03-16 10:01 UTC (permalink / raw)
  To: lm-sensors
  Cc: linux-doc, rdunlap, devicetree-discuss, w.sang, khali,
	Dirk Eibach

Configuration for ads1015 gain and datarate is possible via
devicetree or platform data.

This is a followup patch to previous ads1015 patches on Jean Delvares
tree.

Changes since v1:
- replaced exported_channels bitmask with an enable entry per channel
- improved platform data example in Documentation
- improved patch description

Signed-off-by: Dirk Eibach <eibach@gdsys.de>
---
 .../devicetree/bindings/hwmon/ads1015.txt          |   73 +++++++++++++
 Documentation/devicetree/bindings/i2c/ads1015.txt  |   29 -----
 Documentation/hwmon/ads1015                        |   44 ++++++---
 drivers/hwmon/ads1015.c                            |  113 +++++++++++++++----
 include/linux/i2c/ads1015.h                        |   10 ++-
 5 files changed, 202 insertions(+), 67 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/hwmon/ads1015.txt
 delete mode 100644 Documentation/devicetree/bindings/i2c/ads1015.txt

diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
new file mode 100644
index 0000000..fb6e139
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
@@ -0,0 +1,73 @@
+ADS1015 (I2C)
+
+This device is a 12-bit A-D converter with 4 inputs.
+
+The inputs can be used single ended or in certain differential combinations.
+
+For configuration all possible combinations are mapped to 8 channels:
+  0: Voltage over AIN0 and AIN1.
+  1: Voltage over AIN0 and AIN3.
+  2: Voltage over AIN1 and AIN3.
+  3: Voltage over AIN2 and AIN3.
+  4: Voltage over AIN0 and GND.
+  5: Voltage over AIN1 and GND.
+  6: Voltage over AIN2 and GND.
+  7: Voltage over AIN3 and GND.
+
+Each channel can be configured indvidually:
+ - pga ist the programmable gain amplifier
+    0: FS = +/- 6.144 V
+    1: FS = +/- 4.096 V
+    2: FS = +/- 2.048 V (default)
+    3: FS = +/- 1.024 V
+    4: FS = +/- 0.512 V
+    5: FS = +/- 0.256 V
+ - data_rate in samples per second
+    0: 128
+    1: 250
+    2: 490
+    3: 920
+    4: 1600
+    5: 2400
+    6: 3300
+
+1) The /ads1015 node
+
+  Required properties:
+
+   - compatible : must be "ti,ads1015"
+   - reg : I2C busaddress of the device
+   - #address-cells : must be <1>
+   - #size-cells : must be <0>
+
+  The node contains child nodes for each channel that the platform uses.
+
+  Example ADS1015 node:
+
+    ads1015@49 {
+	    compatible = "ti,ads1015";
+	    reg = <0x49>;
+	    #address-cells = <1>;
+	    #size-cells = <0>;
+
+	    [ child node definitions... ]
+    }
+
+2) channel nodes
+
+  Required properties:
+
+   - reg : the channel number
+
+  Optional properties:
+
+   - ti,gain : the programmable gain amplifier setting
+   - ti,datarate : the converter datarate
+
+  Example ADS1015 node:
+
+    channel@4 {
+	    reg = <4>;
+	    ti,gain = <3>;
+	    ti,datarate = <5>;
+    };
diff --git a/Documentation/devicetree/bindings/i2c/ads1015.txt b/Documentation/devicetree/bindings/i2c/ads1015.txt
deleted file mode 100644
index 985e24d..0000000
--- a/Documentation/devicetree/bindings/i2c/ads1015.txt
+++ /dev/null
@@ -1,29 +0,0 @@
-ADS1015 (I2C)
-
-This device is a 12-bit A-D converter with 4 inputs.
-
-The inputs can be used single ended or in certain differential combinations.
-
-For configuration all possible combinations are mapped to 8 channels:
-0: Voltage over AIN0 and AIN1.
-1: Voltage over AIN0 and AIN3.
-2: Voltage over AIN1 and AIN3.
-3: Voltage over AIN2 and AIN3.
-4: Voltage over AIN0 and GND.
-5: Voltage over AIN1 and GND.
-6: Voltage over AIN2 and GND.
-7: Voltage over AIN3 and GND.
-
-Optional properties:
-
- - exported-channels : exported_channels is a bitmask that specifies which
-		       channels should be accessible by the user.
-
-Example:
-ads1015@49 {
-	compatible = "ti,ads1015";
-	reg = <0x49>;
-	exported-channels = <0x14>;
-};
-
-In this example only channel 2 and 4 would be accessible by the user.
diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
index 56ee797..18a8e00 100644
--- a/Documentation/hwmon/ads1015
+++ b/Documentation/hwmon/ads1015
@@ -38,30 +38,48 @@ Platform Data
 
 In linux/i2c/ads1015.h platform data is defined as:
 
+struct ads1015_channel_data {
+	unsigned int pga;
+	unsigned int data_rate;
+};
+
 struct ads1015_platform_data {
 	unsigned int exported_channels;
+	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
 };
 
 exported_channels is a bitmask that specifies which inputs should be exported.
 
+channel_data contains configuration data for the exported inputs:
+- pga ist the programmable gain amplifier
+  0: FS = +/- 6.144 V
+  1: FS = +/- 4.096 V
+  2: FS = +/- 2.048 V (default)
+  3: FS = +/- 1.024 V
+  4: FS = +/- 0.512 V
+  5: FS = +/- 0.256 V
+- data_rate in samples per second
+  0: 128
+  1: 250
+  2: 490
+  3: 920
+  4: 1600
+  5: 2400
+  6: 3300
+
 Example:
 struct ads1015_platform_data data = {
-	.exported_channels = (1 << 2) | (1 << 4)
+	.channel_data = {
+		[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
+		[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
+	}
 };
 
-In this case only in2_input and in4_input would be created.
+In this case only in2_input(FS +/- 4.096 V, 128 SPS) and in4_input
+(FS +/- 0.512 V, 2400 SPS) would be created.
 
 Devicetree
 ----------
 
-The ads1015 node may have an "exported-channels" property.
-exported_channels is a bitmask that specifies which inputs should be exported.
-
-Example:
-ads1015@49 {
-	compatible = "ti,ads1015";
-	reg = <0x49>;
-	exported-channels = < 0x14 >;
-};
-
-In this case only in2_input and in4_input would be created.
+Configuration is also possible via devicetree:
+Documentation/devicetree/bindings/hwmon/ads1015.txt
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index 8ef2b60..a7c524d 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
+#include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
@@ -45,12 +45,18 @@ enum {
 static const unsigned int fullscale_table[8] = {
 	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
 
-#define ADS1015_CONFIG_CHANNELS 8
+/* Data rates in samples per second */
+static const unsigned int data_rate_table[8] = {
+	128, 250, 490, 920, 1600, 2400, 3300, 3300 };
+
 #define ADS1015_DEFAULT_CHANNELS 0xff
+#define ADS1015_DEFAULT_PGA 2
+#define ADS1015_DEFAULT_DATA_RATE 4
 
 struct ads1015_data {
 	struct device *hwmon_dev;
 	struct mutex update_lock; /* mutex protect updates */
+	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
 };
 
 static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
@@ -71,32 +77,38 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
 {
 	u16 config;
 	s16 conversion;
-	unsigned int pga;
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	unsigned int pga = data->channel_data[channel].pga;
 	int fullscale;
+	unsigned int data_rate = data->channel_data[channel].data_rate;
+	unsigned int conversion_time_ms;
 	unsigned int k;
-	struct ads1015_data *data = i2c_get_clientdata(client);
 	int res;
 
 	mutex_lock(&data->update_lock);
 
-	/* get fullscale voltage */
+	/* get channel parameters */
 	res = ads1015_read_reg(client, ADS1015_CONFIG);
 	if (res < 0)
 		goto err_unlock;
 	config = res;
-	pga = (config >> 9) & 0x0007;
 	fullscale = fullscale_table[pga];
+	conversion_time_ms = 1 + 1000 / data_rate_table[data_rate];
 
 	/* set channel and start single conversion */
-	config &= ~(0x0007 << 12);
-	config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12;
+	config &= 0x001f;
+	config |= (1 << 15) | (1 << 8);
+	config |= (channel & 0x0007) << 12;
+	config |= (pga & 0x0007) << 9;
+	config |= (data_rate & 0x0007) << 5;
 
-	/* wait until conversion finished */
 	res = ads1015_write_reg(client, ADS1015_CONFIG, config);
 	if (res < 0)
 		goto err_unlock;
+
+	/* wait until conversion finished */
 	for (k = 0; k < 5; ++k) {
-		schedule_timeout(msecs_to_jiffies(1));
+		msleep(k ? 1 : conversion_time_ms);
 		res = ads1015_read_reg(client, ADS1015_CONFIG);
 		if (res < 0)
 			goto err_unlock;
@@ -166,29 +178,83 @@ static int ads1015_remove(struct i2c_client *client)
 	return 0;
 }
 
-static unsigned int ads1015_get_exported_channels(struct i2c_client *client)
+static void ads1015_get_exported_channels(struct i2c_client *client)
 {
+	unsigned int k;
+	struct ads1015_data *data = i2c_get_clientdata(client);
 	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
 #ifdef CONFIG_OF
-	struct device_node *np = client->dev.of_node;
-	const __be32 *of_channels;
-	int of_channels_size;
+	struct device_node *node;
 #endif
 
 	/* prefer platform data */
-	if (pdata)
-		return pdata->exported_channels;
+	if (pdata) {
+		memcpy(data->channel_data, pdata->channel_data,
+		       sizeof(data->channel_data));
+		return;
+	}
 
 #ifdef CONFIG_OF
 	/* fallback on OF */
-	of_channels = of_get_property(np, "exported-channels",
-				      &of_channels_size);
-	if (of_channels && (of_channels_size == sizeof(*of_channels)))
-		return be32_to_cpup(of_channels);
+	if (!client->dev.of_node
+	    || !of_get_next_child(client->dev.of_node, NULL))
+		goto fallback_default;
+
+	for_each_child_of_node(client->dev.of_node, node) {
+		const __be32 *property;
+		int len;
+		unsigned int channel;
+		unsigned int pga = ADS1015_DEFAULT_PGA;
+		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
+
+		property = of_get_property(node, "reg", &len);
+		if (!property || (len < sizeof(int))) {
+			dev_err(&client->dev, "ads1015: invalid reg on %s\n",
+				node->full_name);
+			continue;
+		}
+
+		channel = be32_to_cpup(property);
+		if (channel > ADS1015_CONFIG_CHANNELS) {
+			dev_err(&client->dev, "ads1015: invalid addr=%x on %s\n",
+				channel, node->full_name);
+			continue;
+		}
+
+		property = of_get_property(node, "ti,gain", &len);
+		if (property && (len == sizeof(int))) {
+			pga = be32_to_cpup(property);
+			if (pga > 7) {
+				dev_err(&client->dev,
+					"ads1015: invalid gain on %s\n",
+					node->full_name);
+			}
+		}
+
+		property = of_get_property(node, "ti,datarate", &len);
+		if (property && (len == sizeof(int))) {
+			data_rate = be32_to_cpup(property);
+			if (data_rate > 7)
+				dev_err(&client->dev,
+					"ads1015: invalid data_rate on %s\n",
+					node->full_name);
+		}
+
+		data->channel_data[channel].enabled = true;
+		data->channel_data[channel].pga = pga;
+		data->channel_data[channel].data_rate = data_rate;
+	}
+
+	return;
 #endif
 
 	/* fallback on default configuration */
-	return ADS1015_DEFAULT_CHANNELS;
+fallback_default:
+	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
+		data->channel_data[k].enabled = true;
+		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
+		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
+	}
 }
 
 static int ads1015_probe(struct i2c_client *client,
@@ -196,7 +262,6 @@ static int ads1015_probe(struct i2c_client *client,
 {
 	struct ads1015_data *data;
 	int err;
-	unsigned int exported_channels;
 	unsigned int k;
 
 	data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
@@ -209,9 +274,9 @@ static int ads1015_probe(struct i2c_client *client,
 	mutex_init(&data->update_lock);
 
 	/* build sysfs attribute group */
-	exported_channels = ads1015_get_exported_channels(client);
+	ads1015_get_exported_channels(client);
 	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
-		if (!(exported_channels & (1<<k)))
+		if (!data->channel_data[k].enabled)
 			continue;
 		err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
 		if (err)
diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
index 8541c6a..0d9e746 100644
--- a/include/linux/i2c/ads1015.h
+++ b/include/linux/i2c/ads1015.h
@@ -21,8 +21,16 @@
 #ifndef LINUX_ADS1015_H
 #define LINUX_ADS1015_H
 
+#define ADS1015_CONFIG_CHANNELS 8
+
+struct ads1015_channel_data {
+	bool enabled;
+	unsigned int pga;
+	unsigned int data_rate;
+};
+
 struct ads1015_platform_data {
-	unsigned int exported_channels;
+	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
 };
 
 #endif /* LINUX_ADS1015_H */
-- 
1.5.6.5


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

* Re: [PATCH v2] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-16 10:01   ` [PATCH v2] " Dirk Eibach
@ 2011-03-16 20:46     ` Grant Likely
  2011-03-18 21:02     ` Jean Delvare
  1 sibling, 0 replies; 13+ messages in thread
From: Grant Likely @ 2011-03-16 20:46 UTC (permalink / raw)
  To: Dirk Eibach; +Cc: lm-sensors, linux-doc, devicetree-discuss, rdunlap, khali

On Wed, Mar 16, 2011 at 11:01:55AM +0100, Dirk Eibach wrote:
> Configuration for ads1015 gain and datarate is possible via
> devicetree or platform data.
> 
> This is a followup patch to previous ads1015 patches on Jean Delvares
> tree.
> 
> Changes since v1:
> - replaced exported_channels bitmask with an enable entry per channel
> - improved platform data example in Documentation
> - improved patch description
> 
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

> ---
>  .../devicetree/bindings/hwmon/ads1015.txt          |   73 +++++++++++++
>  Documentation/devicetree/bindings/i2c/ads1015.txt  |   29 -----
>  Documentation/hwmon/ads1015                        |   44 ++++++---
>  drivers/hwmon/ads1015.c                            |  113 +++++++++++++++----
>  include/linux/i2c/ads1015.h                        |   10 ++-
>  5 files changed, 202 insertions(+), 67 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/hwmon/ads1015.txt
>  delete mode 100644 Documentation/devicetree/bindings/i2c/ads1015.txt
> 
> diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> new file mode 100644
> index 0000000..fb6e139
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> @@ -0,0 +1,73 @@
> +ADS1015 (I2C)
> +
> +This device is a 12-bit A-D converter with 4 inputs.
> +
> +The inputs can be used single ended or in certain differential combinations.
> +
> +For configuration all possible combinations are mapped to 8 channels:
> +  0: Voltage over AIN0 and AIN1.
> +  1: Voltage over AIN0 and AIN3.
> +  2: Voltage over AIN1 and AIN3.
> +  3: Voltage over AIN2 and AIN3.
> +  4: Voltage over AIN0 and GND.
> +  5: Voltage over AIN1 and GND.
> +  6: Voltage over AIN2 and GND.
> +  7: Voltage over AIN3 and GND.
> +
> +Each channel can be configured indvidually:
> + - pga ist the programmable gain amplifier
> +    0: FS = +/- 6.144 V
> +    1: FS = +/- 4.096 V
> +    2: FS = +/- 2.048 V (default)
> +    3: FS = +/- 1.024 V
> +    4: FS = +/- 0.512 V
> +    5: FS = +/- 0.256 V
> + - data_rate in samples per second
> +    0: 128
> +    1: 250
> +    2: 490
> +    3: 920
> +    4: 1600
> +    5: 2400
> +    6: 3300
> +
> +1) The /ads1015 node
> +
> +  Required properties:
> +
> +   - compatible : must be "ti,ads1015"
> +   - reg : I2C busaddress of the device
> +   - #address-cells : must be <1>
> +   - #size-cells : must be <0>
> +
> +  The node contains child nodes for each channel that the platform uses.
> +
> +  Example ADS1015 node:
> +
> +    ads1015@49 {
> +	    compatible = "ti,ads1015";
> +	    reg = <0x49>;
> +	    #address-cells = <1>;
> +	    #size-cells = <0>;
> +
> +	    [ child node definitions... ]
> +    }
> +
> +2) channel nodes
> +
> +  Required properties:
> +
> +   - reg : the channel number
> +
> +  Optional properties:
> +
> +   - ti,gain : the programmable gain amplifier setting
> +   - ti,datarate : the converter datarate
> +
> +  Example ADS1015 node:
> +
> +    channel@4 {
> +	    reg = <4>;
> +	    ti,gain = <3>;
> +	    ti,datarate = <5>;
> +    };
> diff --git a/Documentation/devicetree/bindings/i2c/ads1015.txt b/Documentation/devicetree/bindings/i2c/ads1015.txt
> deleted file mode 100644
> index 985e24d..0000000
> --- a/Documentation/devicetree/bindings/i2c/ads1015.txt
> +++ /dev/null
> @@ -1,29 +0,0 @@
> -ADS1015 (I2C)
> -
> -This device is a 12-bit A-D converter with 4 inputs.
> -
> -The inputs can be used single ended or in certain differential combinations.
> -
> -For configuration all possible combinations are mapped to 8 channels:
> -0: Voltage over AIN0 and AIN1.
> -1: Voltage over AIN0 and AIN3.
> -2: Voltage over AIN1 and AIN3.
> -3: Voltage over AIN2 and AIN3.
> -4: Voltage over AIN0 and GND.
> -5: Voltage over AIN1 and GND.
> -6: Voltage over AIN2 and GND.
> -7: Voltage over AIN3 and GND.
> -
> -Optional properties:
> -
> - - exported-channels : exported_channels is a bitmask that specifies which
> -		       channels should be accessible by the user.
> -
> -Example:
> -ads1015@49 {
> -	compatible = "ti,ads1015";
> -	reg = <0x49>;
> -	exported-channels = <0x14>;
> -};
> -
> -In this example only channel 2 and 4 would be accessible by the user.
> diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
> index 56ee797..18a8e00 100644
> --- a/Documentation/hwmon/ads1015
> +++ b/Documentation/hwmon/ads1015
> @@ -38,30 +38,48 @@ Platform Data
>  
>  In linux/i2c/ads1015.h platform data is defined as:
>  
> +struct ads1015_channel_data {
> +	unsigned int pga;
> +	unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
>  	unsigned int exported_channels;
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  exported_channels is a bitmask that specifies which inputs should be exported.
>  
> +channel_data contains configuration data for the exported inputs:
> +- pga ist the programmable gain amplifier
> +  0: FS = +/- 6.144 V
> +  1: FS = +/- 4.096 V
> +  2: FS = +/- 2.048 V (default)
> +  3: FS = +/- 1.024 V
> +  4: FS = +/- 0.512 V
> +  5: FS = +/- 0.256 V
> +- data_rate in samples per second
> +  0: 128
> +  1: 250
> +  2: 490
> +  3: 920
> +  4: 1600
> +  5: 2400
> +  6: 3300
> +
>  Example:
>  struct ads1015_platform_data data = {
> -	.exported_channels = (1 << 2) | (1 << 4)
> +	.channel_data = {
> +		[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
> +		[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
> +	}
>  };
>  
> -In this case only in2_input and in4_input would be created.
> +In this case only in2_input(FS +/- 4.096 V, 128 SPS) and in4_input
> +(FS +/- 0.512 V, 2400 SPS) would be created.
>  
>  Devicetree
>  ----------
>  
> -The ads1015 node may have an "exported-channels" property.
> -exported_channels is a bitmask that specifies which inputs should be exported.
> -
> -Example:
> -ads1015@49 {
> -	compatible = "ti,ads1015";
> -	reg = <0x49>;
> -	exported-channels = < 0x14 >;
> -};
> -
> -In this case only in2_input and in4_input would be created.
> +Configuration is also possible via devicetree:
> +Documentation/devicetree/bindings/hwmon/ads1015.txt
> diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
> index 8ef2b60..a7c524d 100644
> --- a/drivers/hwmon/ads1015.c
> +++ b/drivers/hwmon/ads1015.c
> @@ -25,7 +25,7 @@
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> -#include <linux/jiffies.h>
> +#include <linux/delay.h>
>  #include <linux/i2c.h>
>  #include <linux/hwmon.h>
>  #include <linux/hwmon-sysfs.h>
> @@ -45,12 +45,18 @@ enum {
>  static const unsigned int fullscale_table[8] = {
>  	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
>  
> -#define ADS1015_CONFIG_CHANNELS 8
> +/* Data rates in samples per second */
> +static const unsigned int data_rate_table[8] = {
> +	128, 250, 490, 920, 1600, 2400, 3300, 3300 };
> +
>  #define ADS1015_DEFAULT_CHANNELS 0xff
> +#define ADS1015_DEFAULT_PGA 2
> +#define ADS1015_DEFAULT_DATA_RATE 4
>  
>  struct ads1015_data {
>  	struct device *hwmon_dev;
>  	struct mutex update_lock; /* mutex protect updates */
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
> @@ -71,32 +77,38 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
>  {
>  	u16 config;
>  	s16 conversion;
> -	unsigned int pga;
> +	struct ads1015_data *data = i2c_get_clientdata(client);
> +	unsigned int pga = data->channel_data[channel].pga;
>  	int fullscale;
> +	unsigned int data_rate = data->channel_data[channel].data_rate;
> +	unsigned int conversion_time_ms;
>  	unsigned int k;
> -	struct ads1015_data *data = i2c_get_clientdata(client);
>  	int res;
>  
>  	mutex_lock(&data->update_lock);
>  
> -	/* get fullscale voltage */
> +	/* get channel parameters */
>  	res = ads1015_read_reg(client, ADS1015_CONFIG);
>  	if (res < 0)
>  		goto err_unlock;
>  	config = res;
> -	pga = (config >> 9) & 0x0007;
>  	fullscale = fullscale_table[pga];
> +	conversion_time_ms = 1 + 1000 / data_rate_table[data_rate];
>  
>  	/* set channel and start single conversion */
> -	config &= ~(0x0007 << 12);
> -	config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12;
> +	config &= 0x001f;
> +	config |= (1 << 15) | (1 << 8);
> +	config |= (channel & 0x0007) << 12;
> +	config |= (pga & 0x0007) << 9;
> +	config |= (data_rate & 0x0007) << 5;
>  
> -	/* wait until conversion finished */
>  	res = ads1015_write_reg(client, ADS1015_CONFIG, config);
>  	if (res < 0)
>  		goto err_unlock;
> +
> +	/* wait until conversion finished */
>  	for (k = 0; k < 5; ++k) {
> -		schedule_timeout(msecs_to_jiffies(1));
> +		msleep(k ? 1 : conversion_time_ms);
>  		res = ads1015_read_reg(client, ADS1015_CONFIG);
>  		if (res < 0)
>  			goto err_unlock;
> @@ -166,29 +178,83 @@ static int ads1015_remove(struct i2c_client *client)
>  	return 0;
>  }
>  
> -static unsigned int ads1015_get_exported_channels(struct i2c_client *client)
> +static void ads1015_get_exported_channels(struct i2c_client *client)
>  {
> +	unsigned int k;
> +	struct ads1015_data *data = i2c_get_clientdata(client);
>  	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
>  #ifdef CONFIG_OF
> -	struct device_node *np = client->dev.of_node;
> -	const __be32 *of_channels;
> -	int of_channels_size;
> +	struct device_node *node;
>  #endif
>  
>  	/* prefer platform data */
> -	if (pdata)
> -		return pdata->exported_channels;
> +	if (pdata) {
> +		memcpy(data->channel_data, pdata->channel_data,
> +		       sizeof(data->channel_data));
> +		return;
> +	}
>  
>  #ifdef CONFIG_OF
>  	/* fallback on OF */
> -	of_channels = of_get_property(np, "exported-channels",
> -				      &of_channels_size);
> -	if (of_channels && (of_channels_size == sizeof(*of_channels)))
> -		return be32_to_cpup(of_channels);
> +	if (!client->dev.of_node
> +	    || !of_get_next_child(client->dev.of_node, NULL))
> +		goto fallback_default;
> +
> +	for_each_child_of_node(client->dev.of_node, node) {
> +		const __be32 *property;
> +		int len;
> +		unsigned int channel;
> +		unsigned int pga = ADS1015_DEFAULT_PGA;
> +		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
> +
> +		property = of_get_property(node, "reg", &len);
> +		if (!property || (len < sizeof(int))) {
> +			dev_err(&client->dev, "ads1015: invalid reg on %s\n",
> +				node->full_name);
> +			continue;
> +		}
> +
> +		channel = be32_to_cpup(property);
> +		if (channel > ADS1015_CONFIG_CHANNELS) {
> +			dev_err(&client->dev, "ads1015: invalid addr=%x on %s\n",
> +				channel, node->full_name);
> +			continue;
> +		}
> +
> +		property = of_get_property(node, "ti,gain", &len);
> +		if (property && (len == sizeof(int))) {
> +			pga = be32_to_cpup(property);
> +			if (pga > 7) {
> +				dev_err(&client->dev,
> +					"ads1015: invalid gain on %s\n",
> +					node->full_name);
> +			}
> +		}
> +
> +		property = of_get_property(node, "ti,datarate", &len);
> +		if (property && (len == sizeof(int))) {
> +			data_rate = be32_to_cpup(property);
> +			if (data_rate > 7)
> +				dev_err(&client->dev,
> +					"ads1015: invalid data_rate on %s\n",
> +					node->full_name);
> +		}
> +
> +		data->channel_data[channel].enabled = true;
> +		data->channel_data[channel].pga = pga;
> +		data->channel_data[channel].data_rate = data_rate;
> +	}
> +
> +	return;
>  #endif
>  
>  	/* fallback on default configuration */
> -	return ADS1015_DEFAULT_CHANNELS;
> +fallback_default:
> +	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
> +		data->channel_data[k].enabled = true;
> +		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
> +		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
> +	}
>  }
>  
>  static int ads1015_probe(struct i2c_client *client,
> @@ -196,7 +262,6 @@ static int ads1015_probe(struct i2c_client *client,
>  {
>  	struct ads1015_data *data;
>  	int err;
> -	unsigned int exported_channels;
>  	unsigned int k;
>  
>  	data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
> @@ -209,9 +274,9 @@ static int ads1015_probe(struct i2c_client *client,
>  	mutex_init(&data->update_lock);
>  
>  	/* build sysfs attribute group */
> -	exported_channels = ads1015_get_exported_channels(client);
> +	ads1015_get_exported_channels(client);
>  	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
> -		if (!(exported_channels & (1<<k)))
> +		if (!data->channel_data[k].enabled)
>  			continue;
>  		err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
>  		if (err)
> diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
> index 8541c6a..0d9e746 100644
> --- a/include/linux/i2c/ads1015.h
> +++ b/include/linux/i2c/ads1015.h
> @@ -21,8 +21,16 @@
>  #ifndef LINUX_ADS1015_H
>  #define LINUX_ADS1015_H
>  
> +#define ADS1015_CONFIG_CHANNELS 8
> +
> +struct ads1015_channel_data {
> +	bool enabled;
> +	unsigned int pga;
> +	unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
> -	unsigned int exported_channels;
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  #endif /* LINUX_ADS1015_H */
> -- 
> 1.5.6.5
> 
> _______________________________________________
> devicetree-discuss mailing list
> devicetree-discuss@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* Re: [PATCH v2] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-16 10:01   ` [PATCH v2] " Dirk Eibach
  2011-03-16 20:46     ` Grant Likely
@ 2011-03-18 21:02     ` Jean Delvare
  2011-03-21 10:17       ` Eibach, Dirk
  2011-03-21 10:37       ` [PATCH] " Dirk Eibach
  1 sibling, 2 replies; 13+ messages in thread
From: Jean Delvare @ 2011-03-18 21:02 UTC (permalink / raw)
  To: Dirk Eibach; +Cc: lm-sensors, linux-doc, rdunlap, devicetree-discuss, w.sang

Hi Dirk,

On Wed, 16 Mar 2011 11:01:55 +0100, Dirk Eibach wrote:
> Configuration for ads1015 gain and datarate is possible via
> devicetree or platform data.
> 
> This is a followup patch to previous ads1015 patches on Jean Delvares
> tree.
> 
> Changes since v1:
> - replaced exported_channels bitmask with an enable entry per channel
> - improved platform data example in Documentation
> - improved patch description
> 
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>
> ---
>  .../devicetree/bindings/hwmon/ads1015.txt          |   73 +++++++++++++
>  Documentation/devicetree/bindings/i2c/ads1015.txt  |   29 -----
>  Documentation/hwmon/ads1015                        |   44 ++++++---
>  drivers/hwmon/ads1015.c                            |  113 +++++++++++++++----
>  include/linux/i2c/ads1015.h                        |   10 ++-
>  5 files changed, 202 insertions(+), 67 deletions(-)
>  create mode 100644 Documentation/devicetree/bindings/hwmon/ads1015.txt
>  delete mode 100644 Documentation/devicetree/bindings/i2c/ads1015.txt

Took me a little longer than I expected to review this, but here we go
finally:

> 
> diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> new file mode 100644
> index 0000000..fb6e139
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
> @@ -0,0 +1,73 @@
> +ADS1015 (I2C)
> +
> +This device is a 12-bit A-D converter with 4 inputs.
> +
> +The inputs can be used single ended or in certain differential combinations.
> +
> +For configuration all possible combinations are mapped to 8 channels:
> +  0: Voltage over AIN0 and AIN1.
> +  1: Voltage over AIN0 and AIN3.
> +  2: Voltage over AIN1 and AIN3.
> +  3: Voltage over AIN2 and AIN3.
> +  4: Voltage over AIN0 and GND.
> +  5: Voltage over AIN1 and GND.
> +  6: Voltage over AIN2 and GND.
> +  7: Voltage over AIN3 and GND.
> +
> +Each channel can be configured indvidually:

Spelling: individually.

> + - pga ist the programmable gain amplifier

"is", not "ist" ;)

> +    0: FS = +/- 6.144 V

Please include the term "full scale" in the description, otherwise it's
not clear what "FS" means.

> +    1: FS = +/- 4.096 V
> +    2: FS = +/- 2.048 V (default)
> +    3: FS = +/- 1.024 V
> +    4: FS = +/- 0.512 V
> +    5: FS = +/- 0.256 V
> + - data_rate in samples per second
> +    0: 128
> +    1: 250
> +    2: 490
> +    3: 920
> +    4: 1600
> +    5: 2400
> +    6: 3300

These sample rates make me wonder if hwmon is really the right
subsystem for this device. hwmon is more like 2 samples per second.

As you documented the default value for pga, you should do the same for
data_rate.

> +
> +1) The /ads1015 node
> +
> +  Required properties:
> +
> +   - compatible : must be "ti,ads1015"
> +   - reg : I2C busaddress of the device

Missing space between "bus" and "address".

> +   - #address-cells : must be <1>
> +   - #size-cells : must be <0>
> +
> +  The node contains child nodes for each channel that the platform uses.
> +
> +  Example ADS1015 node:
> +
> +    ads1015@49 {
> +	    compatible = "ti,ads1015";
> +	    reg = <0x49>;
> +	    #address-cells = <1>;
> +	    #size-cells = <0>;
> +
> +	    [ child node definitions... ]
> +    }
> +
> +2) channel nodes
> +
> +  Required properties:
> +
> +   - reg : the channel number
> +
> +  Optional properties:
> +
> +   - ti,gain : the programmable gain amplifier setting
> +   - ti,datarate : the converter datarate

Missing space between "data" and "rate" (the second time, of course.)
It's also confusing to have "datarate" for the property, but
"data_rate" as the struct member.

> +
> +  Example ADS1015 node:

This is an example channel node, not ADS1015 node.

> +
> +    channel@4 {
> +	    reg = <4>;
> +	    ti,gain = <3>;
> +	    ti,datarate = <5>;
> +    };
> diff --git a/Documentation/devicetree/bindings/i2c/ads1015.txt b/Documentation/devicetree/bindings/i2c/ads1015.txt
> deleted file mode 100644
> index 985e24d..0000000
> --- a/Documentation/devicetree/bindings/i2c/ads1015.txt
> +++ /dev/null

For the next iteration, please consider that the file was originally
located in Documentation/devicetree/bindings/hwmon. This is where I put
it upon recommendation by Grant Likely. So this new patch should modify
the document in-place, rather than create a new one and delete the old
one.

> @@ -1,29 +0,0 @@
> -ADS1015 (I2C)
> -
> -This device is a 12-bit A-D converter with 4 inputs.
> -
> -The inputs can be used single ended or in certain differential combinations.
> -
> -For configuration all possible combinations are mapped to 8 channels:
> -0: Voltage over AIN0 and AIN1.
> -1: Voltage over AIN0 and AIN3.
> -2: Voltage over AIN1 and AIN3.
> -3: Voltage over AIN2 and AIN3.
> -4: Voltage over AIN0 and GND.
> -5: Voltage over AIN1 and GND.
> -6: Voltage over AIN2 and GND.
> -7: Voltage over AIN3 and GND.
> -
> -Optional properties:
> -
> - - exported-channels : exported_channels is a bitmask that specifies which
> -		       channels should be accessible by the user.
> -
> -Example:
> -ads1015@49 {
> -	compatible = "ti,ads1015";
> -	reg = <0x49>;
> -	exported-channels = <0x14>;
> -};
> -
> -In this example only channel 2 and 4 would be accessible by the user.
> diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
> index 56ee797..18a8e00 100644
> --- a/Documentation/hwmon/ads1015
> +++ b/Documentation/hwmon/ads1015
> @@ -38,30 +38,48 @@ Platform Data
>  
>  In linux/i2c/ads1015.h platform data is defined as:
>  
> +struct ads1015_channel_data {
> +	unsigned int pga;
> +	unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
>  	unsigned int exported_channels;
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };

These structure definitions do not match the actual ones in
<linux/i2c/ads1015.h>. This is a common problem when you duplicate
code... It doesn't stay magically in sync.

>  
>  exported_channels is a bitmask that specifies which inputs should be exported.

exported_channels no longer exists.

>  
> +channel_data contains configuration data for the exported inputs:

It was underlined before that the term "exported" should be avoided
here. "for the used input combinations" would sound better.

> +- pga ist the programmable gain amplifier

"is"

> +  0: FS = +/- 6.144 V
> +  1: FS = +/- 4.096 V
> +  2: FS = +/- 2.048 V (default)

I fail to see how this default is relevant when using platform data. If
the value isn't specified as part of the channel data, it'll be read as
0 by the driver, not 2.

> +  3: FS = +/- 1.024 V
> +  4: FS = +/- 0.512 V
> +  5: FS = +/- 0.256 V
> +- data_rate in samples per second
> +  0: 128
> +  1: 250
> +  2: 490
> +  3: 920
> +  4: 1600
> +  5: 2400
> +  6: 3300
> +

The duplicate documentation between Documentation/hwmon/ads1015 and
Documentation/devicetree/bindings/hwmon/ads1015.txt is somewhat
unpleasant. It will be difficult to keep things in sync over time. I
wonder if this could be avoided.

>  Example:
>  struct ads1015_platform_data data = {
> -	.exported_channels = (1 << 2) | (1 << 4)
> +	.channel_data = {
> +		[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
> +		[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
> +	}
>  };

This looks pretty good, I have to admit :)

>  
> -In this case only in2_input and in4_input would be created.
> +In this case only in2_input(FS +/- 4.096 V, 128 SPS) and in4_input

Space missing before opening parenthesis.

> +(FS +/- 0.512 V, 2400 SPS) would be created.
>  
>  Devicetree
>  ----------
>  
> -The ads1015 node may have an "exported-channels" property.
> -exported_channels is a bitmask that specifies which inputs should be exported.
> -
> -Example:
> -ads1015@49 {
> -	compatible = "ti,ads1015";
> -	reg = <0x49>;
> -	exported-channels = < 0x14 >;
> -};
> -
> -In this case only in2_input and in4_input would be created.
> +Configuration is also possible via devicetree:
> +Documentation/devicetree/bindings/hwmon/ads1015.txt
> diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
> index 8ef2b60..a7c524d 100644
> --- a/drivers/hwmon/ads1015.c
> +++ b/drivers/hwmon/ads1015.c
> @@ -25,7 +25,7 @@
>  #include <linux/module.h>
>  #include <linux/init.h>
>  #include <linux/slab.h>
> -#include <linux/jiffies.h>
> +#include <linux/delay.h>
>  #include <linux/i2c.h>
>  #include <linux/hwmon.h>
>  #include <linux/hwmon-sysfs.h>
> @@ -45,12 +45,18 @@ enum {
>  static const unsigned int fullscale_table[8] = {
>  	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
>  
> -#define ADS1015_CONFIG_CHANNELS 8
> +/* Data rates in samples per second */
> +static const unsigned int data_rate_table[8] = {
> +	128, 250, 490, 920, 1600, 2400, 3300, 3300 };
> +
>  #define ADS1015_DEFAULT_CHANNELS 0xff
> +#define ADS1015_DEFAULT_PGA 2
> +#define ADS1015_DEFAULT_DATA_RATE 4

Does it really make sense to have a default configuration? The chip
needs proper configuration to be usable at all, I would think it makes
sense to make the platform or devicetree data mandatory. I am
particularly worried about the case where the PGA is set improperly: the
input voltage could be over what the chip supports?

Or asking the other way around: do you see any problem with making the
platform data or devicetree data mandatory?

>  
>  struct ads1015_data {
>  	struct device *hwmon_dev;
>  	struct mutex update_lock; /* mutex protect updates */
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
> @@ -71,32 +77,38 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
>  {
>  	u16 config;
>  	s16 conversion;
> -	unsigned int pga;
> +	struct ads1015_data *data = i2c_get_clientdata(client);
> +	unsigned int pga = data->channel_data[channel].pga;
>  	int fullscale;
> +	unsigned int data_rate = data->channel_data[channel].data_rate;
> +	unsigned int conversion_time_ms;
>  	unsigned int k;
> -	struct ads1015_data *data = i2c_get_clientdata(client);
>  	int res;
>  
>  	mutex_lock(&data->update_lock);
>  
> -	/* get fullscale voltage */
> +	/* get channel parameters */
>  	res = ads1015_read_reg(client, ADS1015_CONFIG);
>  	if (res < 0)
>  		goto err_unlock;
>  	config = res;
> -	pga = (config >> 9) & 0x0007;
>  	fullscale = fullscale_table[pga];
> +	conversion_time_ms = 1 + 1000 / data_rate_table[data_rate];

Maybe a suitable use case for DIV_ROUND_UP()?

>  
>  	/* set channel and start single conversion */

You don't only set the channel and start the conversion. You also set
the PGA and data rate.

> -	config &= ~(0x0007 << 12);
> -	config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12;
> +	config &= 0x001f;
> +	config |= (1 << 15) | (1 << 8);
> +	config |= (channel & 0x0007) << 12;
> +	config |= (pga & 0x0007) << 9;
> +	config |= (data_rate & 0x0007) << 5;
>  
> -	/* wait until conversion finished */
>  	res = ads1015_write_reg(client, ADS1015_CONFIG, config);
>  	if (res < 0)
>  		goto err_unlock;
> +
> +	/* wait until conversion finished */
>  	for (k = 0; k < 5; ++k) {
> -		schedule_timeout(msecs_to_jiffies(1));
> +		msleep(k ? 1 : conversion_time_ms);
>  		res = ads1015_read_reg(client, ADS1015_CONFIG);
>  		if (res < 0)
>  			goto err_unlock;

This could be done more efficiently: msleep(conversion_time_ms) before
the loop, and msleep(1) inside the loop (after reading the register.)

That being said... As the conversion rate is known in advance, the
retry loop should never be needed, should it? Did you ever see it
trigger?

> @@ -166,29 +178,83 @@ static int ads1015_remove(struct i2c_client *client)
>  	return 0;
>  }
>  
> -static unsigned int ads1015_get_exported_channels(struct i2c_client *client)
> +static void ads1015_get_exported_channels(struct i2c_client *client)
>  {
> +	unsigned int k;
> +	struct ads1015_data *data = i2c_get_clientdata(client);
>  	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
>  #ifdef CONFIG_OF
> -	struct device_node *np = client->dev.of_node;
> -	const __be32 *of_channels;
> -	int of_channels_size;
> +	struct device_node *node;
>  #endif
>  
>  	/* prefer platform data */
> -	if (pdata)
> -		return pdata->exported_channels;
> +	if (pdata) {
> +		memcpy(data->channel_data, pdata->channel_data,
> +		       sizeof(data->channel_data));
> +		return;
> +	}
>  
>  #ifdef CONFIG_OF
>  	/* fallback on OF */
> -	of_channels = of_get_property(np, "exported-channels",
> -				      &of_channels_size);
> -	if (of_channels && (of_channels_size == sizeof(*of_channels)))
> -		return be32_to_cpup(of_channels);
> +	if (!client->dev.of_node
> +	    || !of_get_next_child(client->dev.of_node, NULL))
> +		goto fallback_default;
> +
> +	for_each_child_of_node(client->dev.of_node, node) {
> +		const __be32 *property;
> +		int len;
> +		unsigned int channel;
> +		unsigned int pga = ADS1015_DEFAULT_PGA;
> +		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
> +
> +		property = of_get_property(node, "reg", &len);
> +		if (!property || (len < sizeof(int))) {

For consistency with the following tests, you should test for len !=
sizeof(int). Note that you can omit the parentheses around this test,
BTW, and same below.

> +			dev_err(&client->dev, "ads1015: invalid reg on %s\n",

The leading "ads1015:" in all error messages is redundant, as dev_err()
will include the client name already.

> +				node->full_name);
> +			continue;
> +		}
> +
> +		channel = be32_to_cpup(property);
> +		if (channel > ADS1015_CONFIG_CHANNELS) {
> +			dev_err(&client->dev, "ads1015: invalid addr=%x on %s\n",
> +				channel, node->full_name);

"addr" is misleading, it is a channel number (sort of, at least), not
an address. I'm sure you can come up with a more useful error message.

> +			continue;
> +		}
> +
> +		property = of_get_property(node, "ti,gain", &len);
> +		if (property && (len == sizeof(int))) {
> +			pga = be32_to_cpup(property);
> +			if (pga > 7) {
> +				dev_err(&client->dev,
> +					"ads1015: invalid gain on %s\n",
> +					node->full_name);
> +			}
> +		}
> +
> +		property = of_get_property(node, "ti,datarate", &len);
> +		if (property && (len == sizeof(int))) {
> +			data_rate = be32_to_cpup(property);
> +			if (data_rate > 7)

I count only 6 possible data rates.

> +				dev_err(&client->dev,
> +					"ads1015: invalid data_rate on %s\n",
> +					node->full_name);

Curly braces would be appreciated, for readability and consistency.

> +		}
> +
> +		data->channel_data[channel].enabled = true;
> +		data->channel_data[channel].pga = pga;
> +		data->channel_data[channel].data_rate = data_rate;
> +	}
> +
> +	return;
>  #endif
>  
>  	/* fallback on default configuration */
> -	return ADS1015_DEFAULT_CHANNELS;
> +fallback_default:

Use of goto and label is discouraged, except for error paths. If you
feel the need for it, it suggests that the devicetree parsing code
should be moved to a separate function. Maybe this would let you merge
the two #ifdef CONFIG_OF blocks, which would be nice, and also get rid
of the following warning I'm seeing:

drivers/hwmon/ads1015.c: In function ‘ads1015_get_exported_channels’:
drivers/hwmon/ads1015.c:252:1: warning: label ‘fallback_default’ defined but not used



> +	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
> +		data->channel_data[k].enabled = true;
> +		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
> +		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
> +	}

As said earlier, I'm really not sure that this default makes any sense.

>  }  
>  static int ads1015_probe(struct i2c_client *client,
> @@ -196,7 +262,6 @@ static int ads1015_probe(struct i2c_client *client,
>  {
>  	struct ads1015_data *data;
>  	int err;
> -	unsigned int exported_channels;
>  	unsigned int k;
>  
>  	data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
> @@ -209,9 +274,9 @@ static int ads1015_probe(struct i2c_client *client,
>  	mutex_init(&data->update_lock);
>  
>  	/* build sysfs attribute group */
> -	exported_channels = ads1015_get_exported_channels(client);
> +	ads1015_get_exported_channels(client);

This function would rather be named ads1015_get_channels_config or
similar.

>  	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
> -		if (!(exported_channels & (1<<k)))
> +		if (!data->channel_data[k].enabled)
>  			continue;
>  		err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
>  		if (err)
> diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
> index 8541c6a..0d9e746 100644
> --- a/include/linux/i2c/ads1015.h
> +++ b/include/linux/i2c/ads1015.h
> @@ -21,8 +21,16 @@
>  #ifndef LINUX_ADS1015_H
>  #define LINUX_ADS1015_H
>  
> +#define ADS1015_CONFIG_CHANNELS 8

I can't make sense of the "CONFIG" part in the name.

> +
> +struct ads1015_channel_data {
> +	bool enabled;
> +	unsigned int pga;
> +	unsigned int data_rate;
> +};
> +
>  struct ads1015_platform_data {
> -	unsigned int exported_channels;
> +	struct ads1015_channel_data channel_data[ADS1015_CONFIG_CHANNELS];
>  };
>  
>  #endif /* LINUX_ADS1015_H */


-- 
Jean Delvare

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

* RE: [PATCH v2] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-18 21:02     ` Jean Delvare
@ 2011-03-21 10:17       ` Eibach, Dirk
  2011-03-21 12:03         ` Jean Delvare
  2011-03-21 10:37       ` [PATCH] " Dirk Eibach
  1 sibling, 1 reply; 13+ messages in thread
From: Eibach, Dirk @ 2011-03-21 10:17 UTC (permalink / raw)
  To: Jean Delvare
  Cc: rdunlap-/UHa2rfvQTnk1uMJSBkQmQ, linux-doc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA

Hi Jean,

> Took me a little longer than I expected to review this, but here we go
> finally:

No problem, I appreciate your careful and detailed reviews very much.

> > +    1: FS = +/- 4.096 V
> > +    2: FS = +/- 2.048 V (default)
> > +    3: FS = +/- 1.024 V
> > +    4: FS = +/- 0.512 V
> > +    5: FS = +/- 0.256 V
> > + - data_rate in samples per second
> > +    0: 128
> > +    1: 250
> > +    2: 490
> > +    3: 920
> > +    4: 1600
> > +    5: 2400
> > +    6: 3300
> 
> These sample rates make me wonder if hwmon is really the 
> right subsystem for this device. hwmon is more like 2 samples 
> per second.

ADS1015 has a beautiful low energy single shot mode which makes it
pretty adorable for hwmon ;)
Sample rate adjustment is only for setting up the sigma delta
parameters.

> The duplicate documentation between 
> Documentation/hwmon/ads1015 and 
> Documentation/devicetree/bindings/hwmon/ads1015.txt is 
> somewhat unpleasant. It will be difficult to keep things in 
> sync over time. I wonder if this could be avoided.

Same here. But no ideas so far.

> >  Example:
> >  struct ads1015_platform_data data = {
> > -	.exported_channels = (1 << 2) | (1 << 4)
> > +	.channel_data = {
> > +		[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
> > +		[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
> > +	}
> >  };
> 
> This looks pretty good, I have to admit :)

Gorgeous ;)

> Does it really make sense to have a default configuration? 
> The chip needs proper configuration to be usable at all, I 
> would think it makes sense to make the platform or devicetree 
> data mandatory. I am particularly worried about the case 
> where the PGA is set improperly: the input voltage could be 
> over what the chip supports?

In fact it does. Default configuration reflects hardware defaults, which
hopefully reflect some default usecase.
The engineer that designed my board actually considered this, so no pga
adjustment is necessary.
Inappropriate PGA settingts can't damage the chip.

> Use of goto and label is discouraged, except for error paths. 

I am not proud of this, but I learned BASIC on a Commodore 116 ;)

Cheers
Dirk
--------------------------------------------------------------------------
Guntermann & Drunck GmbH Systementwicklung 
Dortmunder Str. 4a 
D-57234 Wilnsdorf - Germany 
Tel: +49 (0) 27 39 / 89 01 - 100  Fax: +49 (0) 27 39 / 89 01 - 120 
E-Mail: mailto:sales-dJ+jgKLZIg4@public.gmane.org Web: www.gdsys.de
--------------------------------------------------------------------------
Geschaeftsfuehrer: 
Udo Guntermann - Martin Drunck - Reiner Ruelmann - Klaus Tocke
HRB 2884, Amtsgericht Siegen - WEEE-Reg.-Nr. DE30763240
USt.-Id.-Nr. DE 126575222 - Steuer-Nr. 342 / 5835 / 1041
--------------------------------------------------------------------------
DQS-zertifiziert nach ISO 9001:2008
--------------------------------------------------------------------------

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

* [PATCH] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-18 21:02     ` Jean Delvare
  2011-03-21 10:17       ` Eibach, Dirk
@ 2011-03-21 10:37       ` Dirk Eibach
  2011-03-21 13:05         ` Jean Delvare
  1 sibling, 1 reply; 13+ messages in thread
From: Dirk Eibach @ 2011-03-21 10:37 UTC (permalink / raw)
  To: lm-sensors
  Cc: linux-doc, rdunlap, devicetree-discuss, w.sang, khali,
	Dirk Eibach

Configuration for ads1015 gain and datarate is possible via
devicetree or platform data.

This is a followup patch to previous ads1015 patches on Jean Delvares
tree.

Changes since v1:
- replaced exported_channels bitmask with an enable entry per channel
- improved platform data example in Documentation
- improved patch description

Changes since v2:
- fixed spelling and whitespace in Documentation
- marked default data_rate
- replaced FS by full scale
- removed structure definition from Documentation
- used DIV_ROUND_UP()
- improved comments
- improved waiting for conversion
- moved devicetree stuff to ads1015_get_channels_config_of()
- renamed ads1015_get_exported_channels() to ads1015_get_channels_config()
- renamed ADS1015_CONFIG_CHANNELS to ADS1015_CHANNELS
- fixed some style inconsistencies

Signed-off-by: Dirk Eibach <eibach@gdsys.de>
---
 .../devicetree/bindings/hwmon/ads1015.txt          |   88 +++++++++---
 Documentation/hwmon/ads1015                        |   49 ++++---
 drivers/hwmon/ads1015.c                            |  151 ++++++++++++++------
 include/linux/i2c/ads1015.h                        |   10 ++-
 4 files changed, 212 insertions(+), 86 deletions(-)

diff --git a/Documentation/devicetree/bindings/hwmon/ads1015.txt b/Documentation/devicetree/bindings/hwmon/ads1015.txt
index 985e24d..918a507 100644
--- a/Documentation/devicetree/bindings/hwmon/ads1015.txt
+++ b/Documentation/devicetree/bindings/hwmon/ads1015.txt
@@ -5,25 +5,69 @@ This device is a 12-bit A-D converter with 4 inputs.
 The inputs can be used single ended or in certain differential combinations.
 
 For configuration all possible combinations are mapped to 8 channels:
-0: Voltage over AIN0 and AIN1.
-1: Voltage over AIN0 and AIN3.
-2: Voltage over AIN1 and AIN3.
-3: Voltage over AIN2 and AIN3.
-4: Voltage over AIN0 and GND.
-5: Voltage over AIN1 and GND.
-6: Voltage over AIN2 and GND.
-7: Voltage over AIN3 and GND.
-
-Optional properties:
-
- - exported-channels : exported_channels is a bitmask that specifies which
-		       channels should be accessible by the user.
-
-Example:
-ads1015@49 {
-	compatible = "ti,ads1015";
-	reg = <0x49>;
-	exported-channels = <0x14>;
-};
-
-In this example only channel 2 and 4 would be accessible by the user.
+  0: Voltage over AIN0 and AIN1.
+  1: Voltage over AIN0 and AIN3.
+  2: Voltage over AIN1 and AIN3.
+  3: Voltage over AIN2 and AIN3.
+  4: Voltage over AIN0 and GND.
+  5: Voltage over AIN1 and GND.
+  6: Voltage over AIN2 and GND.
+  7: Voltage over AIN3 and GND.
+
+Each channel can be configured individually:
+ - pga is the programmable gain amplifier (values are full scale)
+    0: +/- 6.144 V
+    1: +/- 4.096 V
+    2: +/- 2.048 V (default)
+    3: +/- 1.024 V
+    4: +/- 0.512 V
+    5: +/- 0.256 V
+ - data_rate in samples per second
+    0: 128
+    1: 250
+    2: 490
+    3: 920
+    4: 1600 (default)
+    5: 2400
+    6: 3300
+
+1) The /ads1015 node
+
+  Required properties:
+
+   - compatible : must be "ti,ads1015"
+   - reg : I2C bus address of the device
+   - #address-cells : must be <1>
+   - #size-cells : must be <0>
+
+  The node contains child nodes for each channel that the platform uses.
+
+  Example ADS1015 node:
+
+    ads1015@49 {
+	    compatible = "ti,ads1015";
+	    reg = <0x49>;
+	    #address-cells = <1>;
+	    #size-cells = <0>;
+
+	    [ child node definitions... ]
+    }
+
+2) channel nodes
+
+  Required properties:
+
+   - reg : the channel number
+
+  Optional properties:
+
+   - ti,gain : the programmable gain amplifier setting
+   - ti,datarate : the converter data rate
+
+  Example ADS1015 channel node:
+
+    channel@4 {
+	    reg = <4>;
+	    ti,gain = <3>;
+	    ti,datarate = <5>;
+    };
diff --git a/Documentation/hwmon/ads1015 b/Documentation/hwmon/ads1015
index 56ee797..f6fe9c2 100644
--- a/Documentation/hwmon/ads1015
+++ b/Documentation/hwmon/ads1015
@@ -19,7 +19,7 @@ This device is a 12-bit A-D converter with 4 inputs.
 
 The inputs can be used single ended or in certain differential combinations.
 
-The inputs can be exported to 8 sysfs input files in0_input - in7_input:
+The inputs can be made available by 8 sysfs input files in0_input - in7_input:
 in0: Voltage over AIN0 and AIN1.
 in1: Voltage over AIN0 and AIN3.
 in2: Voltage over AIN1 and AIN3.
@@ -29,39 +29,44 @@ in5: Voltage over AIN1 and GND.
 in6: Voltage over AIN2 and GND.
 in7: Voltage over AIN3 and GND.
 
-Which inputs are exported can be configured using platform data or devicetree.
+Which inputs are available can be configured using platform data or devicetree.
 
 By default all inputs are exported.
 
 Platform Data
 -------------
 
-In linux/i2c/ads1015.h platform data is defined as:
-
-struct ads1015_platform_data {
-	unsigned int exported_channels;
-};
-
-exported_channels is a bitmask that specifies which inputs should be exported.
+In linux/i2c/ads1015.h platform data is defined, channel_data contains
+configuration data for the used input combinations:
+- pga is the programmable gain amplifier (values are full scale)
+  0: +/- 6.144 V
+  1: +/- 4.096 V
+  2: +/- 2.048 V
+  3: +/- 1.024 V
+  4: +/- 0.512 V
+  5: +/- 0.256 V
+- data_rate in samples per second
+  0: 128
+  1: 250
+  2: 490
+  3: 920
+  4: 1600
+  5: 2400
+  6: 3300
 
 Example:
 struct ads1015_platform_data data = {
-	.exported_channels = (1 << 2) | (1 << 4)
+	.channel_data = {
+		[2] = { .enabled = true, .pga = 1, .data_rate = 0 },
+		[4] = { .enabled = true, .pga = 4, .data_rate = 5 },
+	}
 };
 
-In this case only in2_input and in4_input would be created.
+In this case only in2_input (FS +/- 4.096 V, 128 SPS) and in4_input
+(FS +/- 0.512 V, 2400 SPS) would be created.
 
 Devicetree
 ----------
 
-The ads1015 node may have an "exported-channels" property.
-exported_channels is a bitmask that specifies which inputs should be exported.
-
-Example:
-ads1015@49 {
-	compatible = "ti,ads1015";
-	reg = <0x49>;
-	exported-channels = < 0x14 >;
-};
-
-In this case only in2_input and in4_input would be created.
+Configuration is also possible via devicetree:
+Documentation/devicetree/bindings/hwmon/ads1015.txt
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index 8ef2b60..e9beeda 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -25,7 +25,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/jiffies.h>
+#include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
@@ -45,12 +45,18 @@ enum {
 static const unsigned int fullscale_table[8] = {
 	6144, 4096, 2048, 1024, 512, 256, 256, 256 };
 
-#define ADS1015_CONFIG_CHANNELS 8
+/* Data rates in samples per second */
+static const unsigned int data_rate_table[8] = {
+	128, 250, 490, 920, 1600, 2400, 3300, 3300 };
+
 #define ADS1015_DEFAULT_CHANNELS 0xff
+#define ADS1015_DEFAULT_PGA 2
+#define ADS1015_DEFAULT_DATA_RATE 4
 
 struct ads1015_data {
 	struct device *hwmon_dev;
 	struct mutex update_lock; /* mutex protect updates */
+	struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
 };
 
 static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg)
@@ -71,40 +77,42 @@ static int ads1015_read_value(struct i2c_client *client, unsigned int channel,
 {
 	u16 config;
 	s16 conversion;
-	unsigned int pga;
-	int fullscale;
-	unsigned int k;
 	struct ads1015_data *data = i2c_get_clientdata(client);
+	unsigned int pga = data->channel_data[channel].pga;
+	int fullscale;
+	unsigned int data_rate = data->channel_data[channel].data_rate;
+	unsigned int conversion_time_ms;
 	int res;
 
 	mutex_lock(&data->update_lock);
 
-	/* get fullscale voltage */
+	/* get channel parameters */
 	res = ads1015_read_reg(client, ADS1015_CONFIG);
 	if (res < 0)
 		goto err_unlock;
 	config = res;
-	pga = (config >> 9) & 0x0007;
 	fullscale = fullscale_table[pga];
+	conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]);
 
-	/* set channel and start single conversion */
-	config &= ~(0x0007 << 12);
-	config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12;
+	/* setup and start single conversion */
+	config &= 0x001f;
+	config |= (1 << 15) | (1 << 8);
+	config |= (channel & 0x0007) << 12;
+	config |= (pga & 0x0007) << 9;
+	config |= (data_rate & 0x0007) << 5;
 
-	/* wait until conversion finished */
 	res = ads1015_write_reg(client, ADS1015_CONFIG, config);
 	if (res < 0)
 		goto err_unlock;
-	for (k = 0; k < 5; ++k) {
-		schedule_timeout(msecs_to_jiffies(1));
-		res = ads1015_read_reg(client, ADS1015_CONFIG);
-		if (res < 0)
-			goto err_unlock;
-		config = res;
-		if (config & (1 << 15))
-			break;
-	}
-	if (k == 5) {
+
+	/* wait until conversion finished */
+	msleep(conversion_time_ms);
+	res = ads1015_read_reg(client, ADS1015_CONFIG);
+	if (res < 0)
+		goto err_unlock;
+	config = res;
+	if (!(config & (1 << 15))) {
+		/* conversion not finished in time */
 		res = -EIO;
 		goto err_unlock;
 	}
@@ -160,35 +168,97 @@ static int ads1015_remove(struct i2c_client *client)
 	int k;
 
 	hwmon_device_unregister(data->hwmon_dev);
-	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k)
+	for (k = 0; k < ADS1015_CHANNELS; ++k)
 		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
 	kfree(data);
 	return 0;
 }
 
-static unsigned int ads1015_get_exported_channels(struct i2c_client *client)
-{
-	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
 #ifdef CONFIG_OF
-	struct device_node *np = client->dev.of_node;
-	const __be32 *of_channels;
-	int of_channels_size;
+static int ads1015_get_channels_config_of(struct i2c_client *client)
+{
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	struct device_node *node;
+
+	if (!client->dev.of_node
+	    || !of_get_next_child(client->dev.of_node, NULL))
+		return -EINVAL;
+
+	for_each_child_of_node(client->dev.of_node, node) {
+		const __be32 *property;
+		int len;
+		unsigned int channel;
+		unsigned int pga = ADS1015_DEFAULT_PGA;
+		unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE;
+
+		property = of_get_property(node, "reg", &len);
+		if (!property || len != sizeof(int)) {
+			dev_err(&client->dev, "invalid reg on %s\n",
+				node->full_name);
+			continue;
+		}
+
+		channel = be32_to_cpup(property);
+		if (channel > ADS1015_CHANNELS) {
+			dev_err(&client->dev,
+				"invalid channel index %d on %s\n",
+				channel, node->full_name);
+			continue;
+		}
+
+		property = of_get_property(node, "ti,gain", &len);
+		if (property && len == sizeof(int)) {
+			pga = be32_to_cpup(property);
+			if (pga > 6) {
+				dev_err(&client->dev,
+					"invalid gain on %s\n",
+					node->full_name);
+			}
+		}
+
+		property = of_get_property(node, "ti,datarate", &len);
+		if (property && len == sizeof(int)) {
+			data_rate = be32_to_cpup(property);
+			if (data_rate > 7) {
+				dev_err(&client->dev,
+					"invalid data_rate on %s\n",
+					node->full_name);
+			}
+		}
+
+		data->channel_data[channel].enabled = true;
+		data->channel_data[channel].pga = pga;
+		data->channel_data[channel].data_rate = data_rate;
+	}
+
+	return 0;
+}
 #endif
 
+static void ads1015_get_channels_config(struct i2c_client *client)
+{
+	unsigned int k;
+	struct ads1015_data *data = i2c_get_clientdata(client);
+	struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev);
+
 	/* prefer platform data */
-	if (pdata)
-		return pdata->exported_channels;
+	if (pdata) {
+		memcpy(data->channel_data, pdata->channel_data,
+		       sizeof(data->channel_data));
+		return;
+	}
 
 #ifdef CONFIG_OF
-	/* fallback on OF */
-	of_channels = of_get_property(np, "exported-channels",
-				      &of_channels_size);
-	if (of_channels && (of_channels_size == sizeof(*of_channels)))
-		return be32_to_cpup(of_channels);
+	if (!ads1015_get_channels_config_of(client))
+		return;
 #endif
 
 	/* fallback on default configuration */
-	return ADS1015_DEFAULT_CHANNELS;
+	for (k = 0; k < ADS1015_CHANNELS; ++k) {
+		data->channel_data[k].enabled = true;
+		data->channel_data[k].pga = ADS1015_DEFAULT_PGA;
+		data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE;
+	}
 }
 
 static int ads1015_probe(struct i2c_client *client,
@@ -196,7 +266,6 @@ static int ads1015_probe(struct i2c_client *client,
 {
 	struct ads1015_data *data;
 	int err;
-	unsigned int exported_channels;
 	unsigned int k;
 
 	data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL);
@@ -209,9 +278,9 @@ static int ads1015_probe(struct i2c_client *client,
 	mutex_init(&data->update_lock);
 
 	/* build sysfs attribute group */
-	exported_channels = ads1015_get_exported_channels(client);
-	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) {
-		if (!(exported_channels & (1<<k)))
+	ads1015_get_channels_config(client);
+	for (k = 0; k < ADS1015_CHANNELS; ++k) {
+		if (!data->channel_data[k].enabled)
 			continue;
 		err = device_create_file(&client->dev, &ads1015_in[k].dev_attr);
 		if (err)
@@ -227,7 +296,7 @@ static int ads1015_probe(struct i2c_client *client,
 	return 0;
 
 exit_remove:
-	for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k)
+	for (k = 0; k < ADS1015_CHANNELS; ++k)
 		device_remove_file(&client->dev, &ads1015_in[k].dev_attr);
 exit_free:
 	kfree(data);
diff --git a/include/linux/i2c/ads1015.h b/include/linux/i2c/ads1015.h
index 8541c6a..d5aa2a0 100644
--- a/include/linux/i2c/ads1015.h
+++ b/include/linux/i2c/ads1015.h
@@ -21,8 +21,16 @@
 #ifndef LINUX_ADS1015_H
 #define LINUX_ADS1015_H
 
+#define ADS1015_CHANNELS 8
+
+struct ads1015_channel_data {
+	bool enabled;
+	unsigned int pga;
+	unsigned int data_rate;
+};
+
 struct ads1015_platform_data {
-	unsigned int exported_channels;
+	struct ads1015_channel_data channel_data[ADS1015_CHANNELS];
 };
 
 #endif /* LINUX_ADS1015_H */
-- 
1.5.6.5


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

* Re: [PATCH v2] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-21 10:17       ` Eibach, Dirk
@ 2011-03-21 12:03         ` Jean Delvare
       [not found]           ` <20110321130347.44f5d16d-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
  0 siblings, 1 reply; 13+ messages in thread
From: Jean Delvare @ 2011-03-21 12:03 UTC (permalink / raw)
  To: Eibach, Dirk; +Cc: lm-sensors, linux-doc, rdunlap, devicetree-discuss, w.sang

On Mon, 21 Mar 2011 11:17:42 +0100, Eibach, Dirk wrote:
> > Use of goto and label is discouraged, except for error paths. 
> 
> I am not proud of this, but I learned BASIC on a Commodore 116 ;)

Oh dear, you must be even older than me then :p Locomotive BASIC on an
Amstrad CPC464 for me. I don't remember the exact date... must have
been in 1986.

-- 
Jean Delvare

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

* Re: [PATCH v2] hwmon: (ads1015) Make gain and datarate configurable
       [not found]           ` <20110321130347.44f5d16d-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
@ 2011-03-21 12:53             ` Wolfram Sang
  0 siblings, 0 replies; 13+ messages in thread
From: Wolfram Sang @ 2011-03-21 12:53 UTC (permalink / raw)
  To: Jean Delvare
  Cc: Eibach, Dirk, rdunlap-/UHa2rfvQTnk1uMJSBkQmQ,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
	lm-sensors-GZX6beZjE8VD60Wz+7aTrA


[-- Attachment #1.1: Type: text/plain, Size: 521 bytes --]


> > I am not proud of this, but I learned BASIC on a Commodore 116 ;)
> 
> Oh dear, you must be even older than me then :p Locomotive BASIC on an
> Amstrad CPC464 for me.

Both were released in 1984. (And the BASIC V3.5 of the 116 was quite
better than V2.0 of the Commodore 64 (released in 1982). Still BASIC,
though :)) SCNR, I love the 8-bit era...

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #1.2: Digital signature --]
[-- Type: application/pgp-signature, Size: 198 bytes --]

[-- Attachment #2: Type: text/plain, Size: 192 bytes --]

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ@public.gmane.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

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

* Re: [PATCH] hwmon: (ads1015) Make gain and datarate configurable
  2011-03-21 10:37       ` [PATCH] " Dirk Eibach
@ 2011-03-21 13:05         ` Jean Delvare
  0 siblings, 0 replies; 13+ messages in thread
From: Jean Delvare @ 2011-03-21 13:05 UTC (permalink / raw)
  To: Dirk Eibach; +Cc: lm-sensors, linux-doc, rdunlap, devicetree-discuss, w.sang

On Mon, 21 Mar 2011 11:37:45 +0100, Dirk Eibach wrote:
> Configuration for ads1015 gain and datarate is possible via
> devicetree or platform data.
> 
> This is a followup patch to previous ads1015 patches on Jean Delvares
> tree.
> 
> Changes since v1:
> - replaced exported_channels bitmask with an enable entry per channel
> - improved platform data example in Documentation
> - improved patch description
> 
> Changes since v2:
> - fixed spelling and whitespace in Documentation
> - marked default data_rate
> - replaced FS by full scale
> - removed structure definition from Documentation
> - used DIV_ROUND_UP()
> - improved comments
> - improved waiting for conversion
> - moved devicetree stuff to ads1015_get_channels_config_of()
> - renamed ads1015_get_exported_channels() to ads1015_get_channels_config()
> - renamed ADS1015_CONFIG_CHANNELS to ADS1015_CHANNELS
> - fixed some style inconsistencies
> 
> Signed-off-by: Dirk Eibach <eibach@gdsys.de>
> ---
>  .../devicetree/bindings/hwmon/ads1015.txt          |   88 +++++++++---
>  Documentation/hwmon/ads1015                        |   49 ++++---
>  drivers/hwmon/ads1015.c                            |  151 ++++++++++++++------
>  include/linux/i2c/ads1015.h                        |   10 ++-
>  4 files changed, 212 insertions(+), 86 deletions(-)

Applied, thanks.

I'll send all my hwmon patches to Linus later today.

-- 
Jean Delvare

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

end of thread, other threads:[~2011-03-21 13:05 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-09 13:52 [PATCH] hwmon: (ads1015) Make gain and datarate configurable Dirk Eibach
2011-03-09 14:40 ` [lm-sensors] " Guenter Roeck
2011-03-09 14:47   ` Eibach, Dirk
2011-03-10 19:04 ` Guenter Roeck
2011-03-12  8:18 ` Grant Likely
2011-03-16 10:01   ` [PATCH v2] " Dirk Eibach
2011-03-16 20:46     ` Grant Likely
2011-03-18 21:02     ` Jean Delvare
2011-03-21 10:17       ` Eibach, Dirk
2011-03-21 12:03         ` Jean Delvare
     [not found]           ` <20110321130347.44f5d16d-R0o5gVi9kd7kN2dkZ6Wm7A@public.gmane.org>
2011-03-21 12:53             ` Wolfram Sang
2011-03-21 10:37       ` [PATCH] " Dirk Eibach
2011-03-21 13:05         ` Jean Delvare

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).