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