diff options
author | Dirk Eibach <eibach@gdsys.de> | 2011-03-21 12:59:37 -0400 |
---|---|---|
committer | Jean Delvare <khali@endymion.delvare> | 2011-03-21 12:59:37 -0400 |
commit | c0046867f34bb81ec3f237ebbc5241ae678b8379 (patch) | |
tree | a5d9e95c3fcd09a53dac9ce88abb00f4bef4a4fc /drivers/hwmon/ads1015.c | |
parent | fdf241a8ed93236915c70717a4b6dfb856274496 (diff) |
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.c | 149 |
1 files changed, 109 insertions, 40 deletions
diff --git a/drivers/hwmon/ads1015.c b/drivers/hwmon/ads1015.c index fa02f20b79ff..e9beeda4cbe5 100644 --- a/drivers/hwmon/ads1015.c +++ b/drivers/hwmon/ads1015.c | |||
@@ -45,12 +45,18 @@ enum { | |||
45 | static const unsigned int fullscale_table[8] = { | 45 | static const unsigned int fullscale_table[8] = { |
46 | 6144, 4096, 2048, 1024, 512, 256, 256, 256 }; | 46 | 6144, 4096, 2048, 1024, 512, 256, 256, 256 }; |
47 | 47 | ||
48 | #define ADS1015_CONFIG_CHANNELS 8 | 48 | /* Data rates in samples per second */ |
49 | static const unsigned int data_rate_table[8] = { | ||
50 | 128, 250, 490, 920, 1600, 2400, 3300, 3300 }; | ||
51 | |||
49 | #define ADS1015_DEFAULT_CHANNELS 0xff | 52 | #define ADS1015_DEFAULT_CHANNELS 0xff |
53 | #define ADS1015_DEFAULT_PGA 2 | ||
54 | #define ADS1015_DEFAULT_DATA_RATE 4 | ||
50 | 55 | ||
51 | struct ads1015_data { | 56 | struct ads1015_data { |
52 | struct device *hwmon_dev; | 57 | struct device *hwmon_dev; |
53 | struct mutex update_lock; /* mutex protect updates */ | 58 | struct mutex update_lock; /* mutex protect updates */ |
59 | struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; | ||
54 | }; | 60 | }; |
55 | 61 | ||
56 | static s32 ads1015_read_reg(struct i2c_client *client, unsigned int reg) | 62 | 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, | |||
71 | { | 77 | { |
72 | u16 config; | 78 | u16 config; |
73 | s16 conversion; | 79 | s16 conversion; |
74 | unsigned int pga; | ||
75 | int fullscale; | ||
76 | unsigned int k; | ||
77 | struct ads1015_data *data = i2c_get_clientdata(client); | 80 | struct ads1015_data *data = i2c_get_clientdata(client); |
81 | unsigned int pga = data->channel_data[channel].pga; | ||
82 | int fullscale; | ||
83 | unsigned int data_rate = data->channel_data[channel].data_rate; | ||
84 | unsigned int conversion_time_ms; | ||
78 | int res; | 85 | int res; |
79 | 86 | ||
80 | mutex_lock(&data->update_lock); | 87 | mutex_lock(&data->update_lock); |
81 | 88 | ||
82 | /* get fullscale voltage */ | 89 | /* get channel parameters */ |
83 | res = ads1015_read_reg(client, ADS1015_CONFIG); | 90 | res = ads1015_read_reg(client, ADS1015_CONFIG); |
84 | if (res < 0) | 91 | if (res < 0) |
85 | goto err_unlock; | 92 | goto err_unlock; |
86 | config = res; | 93 | config = res; |
87 | pga = (config >> 9) & 0x0007; | ||
88 | fullscale = fullscale_table[pga]; | 94 | fullscale = fullscale_table[pga]; |
95 | conversion_time_ms = DIV_ROUND_UP(1000, data_rate_table[data_rate]); | ||
89 | 96 | ||
90 | /* set channel and start single conversion */ | 97 | /* setup and start single conversion */ |
91 | config &= ~(0x0007 << 12); | 98 | config &= 0x001f; |
92 | config |= (1 << 15) | (1 << 8) | (channel & 0x0007) << 12; | 99 | config |= (1 << 15) | (1 << 8); |
100 | config |= (channel & 0x0007) << 12; | ||
101 | config |= (pga & 0x0007) << 9; | ||
102 | config |= (data_rate & 0x0007) << 5; | ||
93 | 103 | ||
94 | /* wait until conversion finished */ | ||
95 | res = ads1015_write_reg(client, ADS1015_CONFIG, config); | 104 | res = ads1015_write_reg(client, ADS1015_CONFIG, config); |
96 | if (res < 0) | 105 | if (res < 0) |
97 | goto err_unlock; | 106 | goto err_unlock; |
98 | for (k = 0; k < 5; ++k) { | 107 | |
99 | msleep(1); | 108 | /* wait until conversion finished */ |
100 | res = ads1015_read_reg(client, ADS1015_CONFIG); | 109 | msleep(conversion_time_ms); |
101 | if (res < 0) | 110 | res = ads1015_read_reg(client, ADS1015_CONFIG); |
102 | goto err_unlock; | 111 | if (res < 0) |
103 | config = res; | 112 | goto err_unlock; |
104 | if (config & (1 << 15)) | 113 | config = res; |
105 | break; | 114 | if (!(config & (1 << 15))) { |
106 | } | 115 | /* conversion not finished in time */ |
107 | if (k == 5) { | ||
108 | res = -EIO; | 116 | res = -EIO; |
109 | goto err_unlock; | 117 | goto err_unlock; |
110 | } | 118 | } |
@@ -160,35 +168,97 @@ static int ads1015_remove(struct i2c_client *client) | |||
160 | int k; | 168 | int k; |
161 | 169 | ||
162 | hwmon_device_unregister(data->hwmon_dev); | 170 | hwmon_device_unregister(data->hwmon_dev); |
163 | for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) | 171 | for (k = 0; k < ADS1015_CHANNELS; ++k) |
164 | device_remove_file(&client->dev, &ads1015_in[k].dev_attr); | 172 | device_remove_file(&client->dev, &ads1015_in[k].dev_attr); |
165 | kfree(data); | 173 | kfree(data); |
166 | return 0; | 174 | return 0; |
167 | } | 175 | } |
168 | 176 | ||
169 | static unsigned int ads1015_get_exported_channels(struct i2c_client *client) | ||
170 | { | ||
171 | struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev); | ||
172 | #ifdef CONFIG_OF | 177 | #ifdef CONFIG_OF |
173 | struct device_node *np = client->dev.of_node; | 178 | static int ads1015_get_channels_config_of(struct i2c_client *client) |
174 | const __be32 *of_channels; | 179 | { |
175 | int of_channels_size; | 180 | struct ads1015_data *data = i2c_get_clientdata(client); |
181 | struct device_node *node; | ||
182 | |||
183 | if (!client->dev.of_node | ||
184 | || !of_get_next_child(client->dev.of_node, NULL)) | ||
185 | return -EINVAL; | ||
186 | |||
187 | for_each_child_of_node(client->dev.of_node, node) { | ||
188 | const __be32 *property; | ||
189 | int len; | ||
190 | unsigned int channel; | ||
191 | unsigned int pga = ADS1015_DEFAULT_PGA; | ||
192 | unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE; | ||
193 | |||
194 | property = of_get_property(node, "reg", &len); | ||
195 | if (!property || len != sizeof(int)) { | ||
196 | dev_err(&client->dev, "invalid reg on %s\n", | ||
197 | node->full_name); | ||
198 | continue; | ||
199 | } | ||
200 | |||
201 | channel = be32_to_cpup(property); | ||
202 | if (channel > ADS1015_CHANNELS) { | ||
203 | dev_err(&client->dev, | ||
204 | "invalid channel index %d on %s\n", | ||
205 | channel, node->full_name); | ||
206 | continue; | ||
207 | } | ||
208 | |||
209 | property = of_get_property(node, "ti,gain", &len); | ||
210 | if (property && len == sizeof(int)) { | ||
211 | pga = be32_to_cpup(property); | ||
212 | if (pga > 6) { | ||
213 | dev_err(&client->dev, | ||
214 | "invalid gain on %s\n", | ||
215 | node->full_name); | ||
216 | } | ||
217 | } | ||
218 | |||
219 | property = of_get_property(node, "ti,datarate", &len); | ||
220 | if (property && len == sizeof(int)) { | ||
221 | data_rate = be32_to_cpup(property); | ||
222 | if (data_rate > 7) { | ||
223 | dev_err(&client->dev, | ||
224 | "invalid data_rate on %s\n", | ||
225 | node->full_name); | ||
226 | } | ||
227 | } | ||
228 | |||
229 | data->channel_data[channel].enabled = true; | ||
230 | data->channel_data[channel].pga = pga; | ||
231 | data->channel_data[channel].data_rate = data_rate; | ||
232 | } | ||
233 | |||
234 | return 0; | ||
235 | } | ||
176 | #endif | 236 | #endif |
177 | 237 | ||
238 | static void ads1015_get_channels_config(struct i2c_client *client) | ||
239 | { | ||
240 | unsigned int k; | ||
241 | struct ads1015_data *data = i2c_get_clientdata(client); | ||
242 | struct ads1015_platform_data *pdata = dev_get_platdata(&client->dev); | ||
243 | |||
178 | /* prefer platform data */ | 244 | /* prefer platform data */ |
179 | if (pdata) | 245 | if (pdata) { |
180 | return pdata->exported_channels; | 246 | memcpy(data->channel_data, pdata->channel_data, |
247 | sizeof(data->channel_data)); | ||
248 | return; | ||
249 | } | ||
181 | 250 | ||
182 | #ifdef CONFIG_OF | 251 | #ifdef CONFIG_OF |
183 | /* fallback on OF */ | 252 | if (!ads1015_get_channels_config_of(client)) |
184 | of_channels = of_get_property(np, "exported-channels", | 253 | return; |
185 | &of_channels_size); | ||
186 | if (of_channels && (of_channels_size == sizeof(*of_channels))) | ||
187 | return be32_to_cpup(of_channels); | ||
188 | #endif | 254 | #endif |
189 | 255 | ||
190 | /* fallback on default configuration */ | 256 | /* fallback on default configuration */ |
191 | return ADS1015_DEFAULT_CHANNELS; | 257 | for (k = 0; k < ADS1015_CHANNELS; ++k) { |
258 | data->channel_data[k].enabled = true; | ||
259 | data->channel_data[k].pga = ADS1015_DEFAULT_PGA; | ||
260 | data->channel_data[k].data_rate = ADS1015_DEFAULT_DATA_RATE; | ||
261 | } | ||
192 | } | 262 | } |
193 | 263 | ||
194 | static int ads1015_probe(struct i2c_client *client, | 264 | static int ads1015_probe(struct i2c_client *client, |
@@ -196,7 +266,6 @@ static int ads1015_probe(struct i2c_client *client, | |||
196 | { | 266 | { |
197 | struct ads1015_data *data; | 267 | struct ads1015_data *data; |
198 | int err; | 268 | int err; |
199 | unsigned int exported_channels; | ||
200 | unsigned int k; | 269 | unsigned int k; |
201 | 270 | ||
202 | data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL); | 271 | data = kzalloc(sizeof(struct ads1015_data), GFP_KERNEL); |
@@ -209,9 +278,9 @@ static int ads1015_probe(struct i2c_client *client, | |||
209 | mutex_init(&data->update_lock); | 278 | mutex_init(&data->update_lock); |
210 | 279 | ||
211 | /* build sysfs attribute group */ | 280 | /* build sysfs attribute group */ |
212 | exported_channels = ads1015_get_exported_channels(client); | 281 | ads1015_get_channels_config(client); |
213 | for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) { | 282 | for (k = 0; k < ADS1015_CHANNELS; ++k) { |
214 | if (!(exported_channels & (1<<k))) | 283 | if (!data->channel_data[k].enabled) |
215 | continue; | 284 | continue; |
216 | err = device_create_file(&client->dev, &ads1015_in[k].dev_attr); | 285 | err = device_create_file(&client->dev, &ads1015_in[k].dev_attr); |
217 | if (err) | 286 | if (err) |
@@ -227,7 +296,7 @@ static int ads1015_probe(struct i2c_client *client, | |||
227 | return 0; | 296 | return 0; |
228 | 297 | ||
229 | exit_remove: | 298 | exit_remove: |
230 | for (k = 0; k < ADS1015_CONFIG_CHANNELS; ++k) | 299 | for (k = 0; k < ADS1015_CHANNELS; ++k) |
231 | device_remove_file(&client->dev, &ads1015_in[k].dev_attr); | 300 | device_remove_file(&client->dev, &ads1015_in[k].dev_attr); |
232 | exit_free: | 301 | exit_free: |
233 | kfree(data); | 302 | kfree(data); |