Blame view
drivers/hwmon/ads1015.c
8.56 KB
8c22a8f57 hwmon: Add suppor... |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
/* * ads1015.c - lm_sensors driver for ads1015 12-bit 4-input ADC * (C) Copyright 2010 * Dirk Eibach, Guntermann & Drunck GmbH <eibach@gdsys.de> * * Based on the ads7828 driver by Steve Hardy. * * Datasheet available at: http://focus.ti.com/lit/ds/symlink/ads1015.pdf * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <linux/module.h> #include <linux/init.h> #include <linux/slab.h> #include <linux/delay.h> #include <linux/i2c.h> #include <linux/hwmon.h> #include <linux/hwmon-sysfs.h> #include <linux/err.h> #include <linux/mutex.h> |
a140986fd hwmon: (ads1015) ... |
34 |
#include <linux/of_device.h> |
8c22a8f57 hwmon: Add suppor... |
35 |
#include <linux/of.h> |
9010624cc hwmon: (ads1015) ... |
36 |
#include <linux/platform_data/ads1015.h> |
8c22a8f57 hwmon: Add suppor... |
37 38 39 40 41 42 43 44 45 46 |
/* ADS1015 registers */ enum { ADS1015_CONVERSION = 0, ADS1015_CONFIG = 1, }; /* PGA fullscale voltages in mV */ static const unsigned int fullscale_table[8] = { 6144, 4096, 2048, 1024, 512, 256, 256, 256 }; |
c0046867f hwmon: (ads1015) ... |
47 |
/* Data rates in samples per second */ |
60c1f31fc hwmon: (ads1015) ... |
48 49 50 51 52 53 54 |
static const unsigned int data_rate_table_1015[8] = { 128, 250, 490, 920, 1600, 2400, 3300, 3300 }; static const unsigned int data_rate_table_1115[8] = { 8, 16, 32, 64, 128, 250, 475, 860 }; |
c0046867f hwmon: (ads1015) ... |
55 |
|
8c22a8f57 hwmon: Add suppor... |
56 |
#define ADS1015_DEFAULT_CHANNELS 0xff |
c0046867f hwmon: (ads1015) ... |
57 58 |
#define ADS1015_DEFAULT_PGA 2 #define ADS1015_DEFAULT_DATA_RATE 4 |
8c22a8f57 hwmon: Add suppor... |
59 |
|
60c1f31fc hwmon: (ads1015) ... |
60 61 62 63 |
enum ads1015_chips { ads1015, ads1115, }; |
8c22a8f57 hwmon: Add suppor... |
64 65 66 |
struct ads1015_data { struct device *hwmon_dev; struct mutex update_lock; /* mutex protect updates */ |
c0046867f hwmon: (ads1015) ... |
67 |
struct ads1015_channel_data channel_data[ADS1015_CHANNELS]; |
60c1f31fc hwmon: (ads1015) ... |
68 |
enum ads1015_chips id; |
8c22a8f57 hwmon: Add suppor... |
69 |
}; |
1196573fe hwmon: (ads1015) ... |
70 |
static int ads1015_read_adc(struct i2c_client *client, unsigned int channel) |
8c22a8f57 hwmon: Add suppor... |
71 72 |
{ u16 config; |
8c22a8f57 hwmon: Add suppor... |
73 |
struct ads1015_data *data = i2c_get_clientdata(client); |
c0046867f hwmon: (ads1015) ... |
74 |
unsigned int pga = data->channel_data[channel].pga; |
c0046867f hwmon: (ads1015) ... |
75 76 |
unsigned int data_rate = data->channel_data[channel].data_rate; unsigned int conversion_time_ms; |
60c1f31fc hwmon: (ads1015) ... |
77 78 |
const unsigned int * const rate_table = data->id == ads1115 ? data_rate_table_1115 : data_rate_table_1015; |
8c22a8f57 hwmon: Add suppor... |
79 80 81 |
int res; mutex_lock(&data->update_lock); |
c0046867f hwmon: (ads1015) ... |
82 |
/* get channel parameters */ |
90f4102ce hwmon: Use i2c_sm... |
83 |
res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG); |
8c22a8f57 hwmon: Add suppor... |
84 85 86 |
if (res < 0) goto err_unlock; config = res; |
60c1f31fc hwmon: (ads1015) ... |
87 |
conversion_time_ms = DIV_ROUND_UP(1000, rate_table[data_rate]); |
8c22a8f57 hwmon: Add suppor... |
88 |
|
c0046867f hwmon: (ads1015) ... |
89 90 91 92 93 94 |
/* 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; |
8c22a8f57 hwmon: Add suppor... |
95 |
|
90f4102ce hwmon: Use i2c_sm... |
96 |
res = i2c_smbus_write_word_swapped(client, ADS1015_CONFIG, config); |
8c22a8f57 hwmon: Add suppor... |
97 98 |
if (res < 0) goto err_unlock; |
c0046867f hwmon: (ads1015) ... |
99 100 101 |
/* wait until conversion finished */ msleep(conversion_time_ms); |
90f4102ce hwmon: Use i2c_sm... |
102 |
res = i2c_smbus_read_word_swapped(client, ADS1015_CONFIG); |
c0046867f hwmon: (ads1015) ... |
103 104 105 106 107 |
if (res < 0) goto err_unlock; config = res; if (!(config & (1 << 15))) { /* conversion not finished in time */ |
8c22a8f57 hwmon: Add suppor... |
108 109 110 |
res = -EIO; goto err_unlock; } |
90f4102ce hwmon: Use i2c_sm... |
111 |
res = i2c_smbus_read_word_swapped(client, ADS1015_CONVERSION); |
8c22a8f57 hwmon: Add suppor... |
112 113 114 115 116 |
err_unlock: mutex_unlock(&data->update_lock); return res; } |
1196573fe hwmon: (ads1015) ... |
117 118 119 120 121 122 |
static int ads1015_reg_to_mv(struct i2c_client *client, unsigned int channel, s16 reg) { struct ads1015_data *data = i2c_get_clientdata(client); unsigned int pga = data->channel_data[channel].pga; int fullscale = fullscale_table[pga]; |
acc146943 hwmon: (ads1015) ... |
123 |
const int mask = data->id == ads1115 ? 0x7fff : 0x7ff0; |
1196573fe hwmon: (ads1015) ... |
124 |
|
60c1f31fc hwmon: (ads1015) ... |
125 |
return DIV_ROUND_CLOSEST(reg * fullscale, mask); |
1196573fe hwmon: (ads1015) ... |
126 |
} |
8c22a8f57 hwmon: Add suppor... |
127 128 129 130 131 132 |
/* sysfs callback function */ static ssize_t show_in(struct device *dev, struct device_attribute *da, char *buf) { struct sensor_device_attribute *attr = to_sensor_dev_attr(da); struct i2c_client *client = to_i2c_client(dev); |
8c22a8f57 hwmon: Add suppor... |
133 |
int res; |
1196573fe hwmon: (ads1015) ... |
134 |
int index = attr->index; |
8c22a8f57 hwmon: Add suppor... |
135 |
|
1196573fe hwmon: (ads1015) ... |
136 137 138 |
res = ads1015_read_adc(client, index); if (res < 0) return res; |
8c22a8f57 hwmon: Add suppor... |
139 |
|
1196573fe hwmon: (ads1015) ... |
140 141 |
return sprintf(buf, "%d ", ads1015_reg_to_mv(client, index, res)); |
8c22a8f57 hwmon: Add suppor... |
142 |
} |
fdf241a8e hwmon: (ads1015) ... |
143 144 145 146 147 148 149 150 151 |
static const struct sensor_device_attribute ads1015_in[] = { SENSOR_ATTR(in0_input, S_IRUGO, show_in, NULL, 0), SENSOR_ATTR(in1_input, S_IRUGO, show_in, NULL, 1), SENSOR_ATTR(in2_input, S_IRUGO, show_in, NULL, 2), SENSOR_ATTR(in3_input, S_IRUGO, show_in, NULL, 3), SENSOR_ATTR(in4_input, S_IRUGO, show_in, NULL, 4), SENSOR_ATTR(in5_input, S_IRUGO, show_in, NULL, 5), SENSOR_ATTR(in6_input, S_IRUGO, show_in, NULL, 6), SENSOR_ATTR(in7_input, S_IRUGO, show_in, NULL, 7), |
8c22a8f57 hwmon: Add suppor... |
152 153 154 155 156 157 158 159 160 |
}; /* * Driver interface */ static int ads1015_remove(struct i2c_client *client) { struct ads1015_data *data = i2c_get_clientdata(client); |
fdf241a8e hwmon: (ads1015) ... |
161 |
int k; |
8c22a8f57 hwmon: Add suppor... |
162 |
hwmon_device_unregister(data->hwmon_dev); |
c0046867f hwmon: (ads1015) ... |
163 |
for (k = 0; k < ADS1015_CHANNELS; ++k) |
fdf241a8e hwmon: (ads1015) ... |
164 |
device_remove_file(&client->dev, &ads1015_in[k].dev_attr); |
8c22a8f57 hwmon: Add suppor... |
165 166 |
return 0; } |
8c22a8f57 hwmon: Add suppor... |
167 |
#ifdef CONFIG_OF |
c0046867f hwmon: (ads1015) ... |
168 169 170 171 172 173 174 175 176 177 |
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) { |
8e35762fd hwmon: (ads1015) ... |
178 |
u32 pval; |
c0046867f hwmon: (ads1015) ... |
179 180 181 |
unsigned int channel; unsigned int pga = ADS1015_DEFAULT_PGA; unsigned int data_rate = ADS1015_DEFAULT_DATA_RATE; |
8e35762fd hwmon: (ads1015) ... |
182 |
if (of_property_read_u32(node, "reg", &pval)) { |
bb923fdc3 hwmon: (ads1015) ... |
183 184 |
dev_err(&client->dev, "invalid reg on %pOF ", node); |
c0046867f hwmon: (ads1015) ... |
185 186 |
continue; } |
8e35762fd hwmon: (ads1015) ... |
187 |
channel = pval; |
56de1377a hwmon: (ads1015) ... |
188 |
if (channel >= ADS1015_CHANNELS) { |
c0046867f hwmon: (ads1015) ... |
189 |
dev_err(&client->dev, |
bb923fdc3 hwmon: (ads1015) ... |
190 191 192 |
"invalid channel index %d on %pOF ", channel, node); |
c0046867f hwmon: (ads1015) ... |
193 194 |
continue; } |
8e35762fd hwmon: (ads1015) ... |
195 196 |
if (!of_property_read_u32(node, "ti,gain", &pval)) { pga = pval; |
c0046867f hwmon: (ads1015) ... |
197 |
if (pga > 6) { |
bb923fdc3 hwmon: (ads1015) ... |
198 199 200 |
dev_err(&client->dev, "invalid gain on %pOF ", node); |
e98142955 hwmon: (ads1015) ... |
201 |
return -EINVAL; |
c0046867f hwmon: (ads1015) ... |
202 203 |
} } |
8e35762fd hwmon: (ads1015) ... |
204 205 |
if (!of_property_read_u32(node, "ti,datarate", &pval)) { data_rate = pval; |
c0046867f hwmon: (ads1015) ... |
206 207 |
if (data_rate > 7) { dev_err(&client->dev, |
bb923fdc3 hwmon: (ads1015) ... |
208 209 |
"invalid data_rate on %pOF ", node); |
e98142955 hwmon: (ads1015) ... |
210 |
return -EINVAL; |
c0046867f hwmon: (ads1015) ... |
211 212 213 214 215 216 217 218 219 220 |
} } data->channel_data[channel].enabled = true; data->channel_data[channel].pga = pga; data->channel_data[channel].data_rate = data_rate; } return 0; } |
8c22a8f57 hwmon: Add suppor... |
221 |
#endif |
c0046867f hwmon: (ads1015) ... |
222 223 224 225 226 |
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); |
8c22a8f57 hwmon: Add suppor... |
227 |
/* prefer platform data */ |
c0046867f hwmon: (ads1015) ... |
228 229 230 231 232 |
if (pdata) { memcpy(data->channel_data, pdata->channel_data, sizeof(data->channel_data)); return; } |
8c22a8f57 hwmon: Add suppor... |
233 234 |
#ifdef CONFIG_OF |
c0046867f hwmon: (ads1015) ... |
235 236 |
if (!ads1015_get_channels_config_of(client)) return; |
8c22a8f57 hwmon: Add suppor... |
237 238 239 |
#endif /* fallback on default configuration */ |
c0046867f hwmon: (ads1015) ... |
240 241 242 243 244 |
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; } |
8c22a8f57 hwmon: Add suppor... |
245 246 247 248 249 250 251 |
} static int ads1015_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct ads1015_data *data; int err; |
8c22a8f57 hwmon: Add suppor... |
252 |
unsigned int k; |
8c22a8f57 hwmon: Add suppor... |
253 |
|
57457e314 hwmon: (ads1015) ... |
254 255 256 257 |
data = devm_kzalloc(&client->dev, sizeof(struct ads1015_data), GFP_KERNEL); if (!data) return -ENOMEM; |
a140986fd hwmon: (ads1015) ... |
258 259 260 261 262 263 |
if (client->dev.of_node) data->id = (enum ads1015_chips) of_device_get_match_data(&client->dev); else data->id = id->driver_data; |
8c22a8f57 hwmon: Add suppor... |
264 265 266 267 |
i2c_set_clientdata(client, data); mutex_init(&data->update_lock); /* build sysfs attribute group */ |
c0046867f hwmon: (ads1015) ... |
268 269 270 |
ads1015_get_channels_config(client); for (k = 0; k < ADS1015_CHANNELS; ++k) { if (!data->channel_data[k].enabled) |
8c22a8f57 hwmon: Add suppor... |
271 |
continue; |
fdf241a8e hwmon: (ads1015) ... |
272 273 |
err = device_create_file(&client->dev, &ads1015_in[k].dev_attr); if (err) |
363434b5d hwmon: (ads1015) ... |
274 |
goto exit_remove; |
8c22a8f57 hwmon: Add suppor... |
275 |
} |
8c22a8f57 hwmon: Add suppor... |
276 277 278 279 280 281 282 283 284 285 |
data->hwmon_dev = hwmon_device_register(&client->dev); if (IS_ERR(data->hwmon_dev)) { err = PTR_ERR(data->hwmon_dev); goto exit_remove; } return 0; exit_remove: |
c0046867f hwmon: (ads1015) ... |
286 |
for (k = 0; k < ADS1015_CHANNELS; ++k) |
fdf241a8e hwmon: (ads1015) ... |
287 |
device_remove_file(&client->dev, &ads1015_in[k].dev_attr); |
8c22a8f57 hwmon: Add suppor... |
288 289 290 291 |
return err; } static const struct i2c_device_id ads1015_id[] = { |
60c1f31fc hwmon: (ads1015) ... |
292 293 |
{ "ads1015", ads1015}, { "ads1115", ads1115}, |
8c22a8f57 hwmon: Add suppor... |
294 295 296 |
{ } }; MODULE_DEVICE_TABLE(i2c, ads1015_id); |
a140986fd hwmon: (ads1015) ... |
297 298 299 300 301 302 303 304 305 306 307 308 |
static const struct of_device_id ads1015_of_match[] = { { .compatible = "ti,ads1015", .data = (void *)ads1015 }, { .compatible = "ti,ads1115", .data = (void *)ads1115 }, { }, }; MODULE_DEVICE_TABLE(of, ads1015_of_match); |
8c22a8f57 hwmon: Add suppor... |
309 310 311 |
static struct i2c_driver ads1015_driver = { .driver = { .name = "ads1015", |
a140986fd hwmon: (ads1015) ... |
312 |
.of_match_table = of_match_ptr(ads1015_of_match), |
8c22a8f57 hwmon: Add suppor... |
313 314 315 316 317 |
}, .probe = ads1015_probe, .remove = ads1015_remove, .id_table = ads1015_id, }; |
f0967eea8 hwmon: convert dr... |
318 |
module_i2c_driver(ads1015_driver); |
8c22a8f57 hwmon: Add suppor... |
319 320 321 322 |
MODULE_AUTHOR("Dirk Eibach <eibach@gdsys.de>"); MODULE_DESCRIPTION("ADS1015 driver"); MODULE_LICENSE("GPL"); |