summaryrefslogtreecommitdiffstats
path: root/drivers/hwmon/ads1015.c
diff options
context:
space:
mode:
authorDirk Eibach <eibach@gdsys.de>2011-03-21 17:59:37 +0100
committerJean Delvare <khali@endymion.delvare>2011-03-21 17:59:37 +0100
commitc0046867f34bb81ec3f237ebbc5241ae678b8379 (patch)
treea5d9e95c3fcd09a53dac9ce88abb00f4bef4a4fc /drivers/hwmon/ads1015.c
parentfdf241a8ed93236915c70717a4b6dfb856274496 (diff)
downloadop-kernel-dev-c0046867f34bb81ec3f237ebbc5241ae678b8379.zip
op-kernel-dev-c0046867f34bb81ec3f237ebbc5241ae678b8379.tar.gz
hwmon: (ads1015) Make gain and datarate configurable
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. Signed-off-by: Dirk Eibach <eibach@gdsys.de> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers/hwmon/ads1015.c')
-rw-r--r--drivers/hwmon/ads1015.c149
1 files changed, 109 insertions, 40 deletions
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c
index fa02f20..e9beeda 100644
--- a/drivers/hwmon/ads1015.c
+++ b/drivers/hwmon/ads1015.c
@@ -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) {
- msleep(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);
OpenPOWER on IntegriCloud