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@xxxxxxxx> Acked-by: Grant Likely <grant.likely@xxxxxxxxxxxx> > --- > .../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@xxxxxxxxxxxxxxxx > https://lists.ozlabs.org/listinfo/devicetree-discuss _______________________________________________ lm-sensors mailing list lm-sensors@xxxxxxxxxxxxxx http://lists.lm-sensors.org/mailman/listinfo/lm-sensors