Commit | Line | Data |
---|---|---|
1696f364 OK |
1 | /* |
2 | * TWL6030 GPADC module driver | |
3 | * | |
4 | * Copyright (C) 2009-2013 Texas Instruments Inc. | |
5 | * Nishant Kamat <nskamat@ti.com> | |
6 | * Balaji T K <balajitk@ti.com> | |
7 | * Graeme Gregory <gg@slimlogic.co.uk> | |
8 | * Girish S Ghongdemath <girishsg@ti.com> | |
9 | * Ambresh K <ambresh@ti.com> | |
10 | * Oleksandr Kozaruk <oleksandr.kozaruk@ti.com | |
11 | * | |
12 | * Based on twl4030-madc.c | |
13 | * Copyright (C) 2008 Nokia Corporation | |
14 | * Mikko Ylinen <mikko.k.ylinen@nokia.com> | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or | |
17 | * modify it under the terms of the GNU General Public License | |
18 | * version 2 as published by the Free Software Foundation. | |
19 | * | |
20 | * This program is distributed in the hope that it will be useful, but | |
21 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
22 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
23 | * General Public License for more details. | |
24 | * | |
25 | * You should have received a copy of the GNU General Public License | |
26 | * along with this program; if not, write to the Free Software | |
27 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | |
28 | * 02110-1301 USA | |
29 | * | |
30 | */ | |
1696f364 OK |
31 | #include <linux/interrupt.h> |
32 | #include <linux/kernel.h> | |
33 | #include <linux/module.h> | |
34 | #include <linux/platform_device.h> | |
35 | #include <linux/of_platform.h> | |
36 | #include <linux/i2c/twl.h> | |
37 | #include <linux/iio/iio.h> | |
38 | #include <linux/iio/sysfs.h> | |
39 | ||
40 | #define DRIVER_NAME "twl6030_gpadc" | |
41 | ||
42 | /* | |
43 | * twl6030 per TRM has 17 channels, and twl6032 has 19 channels | |
44 | * 2 test network channels are not used, | |
45 | * 2 die temperature channels are not used either, as it is not | |
46 | * defined how to convert ADC value to temperature | |
47 | */ | |
48 | #define TWL6030_GPADC_USED_CHANNELS 13 | |
49 | #define TWL6030_GPADC_MAX_CHANNELS 15 | |
50 | #define TWL6032_GPADC_USED_CHANNELS 15 | |
51 | #define TWL6032_GPADC_MAX_CHANNELS 19 | |
52 | #define TWL6030_GPADC_NUM_TRIM_REGS 16 | |
53 | ||
54 | #define TWL6030_GPADC_CTRL_P1 0x05 | |
55 | ||
56 | #define TWL6032_GPADC_GPSELECT_ISB 0x07 | |
57 | #define TWL6032_GPADC_CTRL_P1 0x08 | |
58 | ||
59 | #define TWL6032_GPADC_GPCH0_LSB 0x0d | |
60 | #define TWL6032_GPADC_GPCH0_MSB 0x0e | |
61 | ||
62 | #define TWL6030_GPADC_CTRL_P1_SP1 BIT(3) | |
63 | ||
64 | #define TWL6030_GPADC_GPCH0_LSB (0x29) | |
65 | ||
66 | #define TWL6030_GPADC_RT_SW1_EOC_MASK BIT(5) | |
67 | ||
68 | #define TWL6030_GPADC_TRIM1 0xCD | |
69 | ||
70 | #define TWL6030_REG_TOGGLE1 0x90 | |
71 | #define TWL6030_GPADCS BIT(1) | |
72 | #define TWL6030_GPADCR BIT(0) | |
73 | ||
74 | /** | |
75 | * struct twl6030_chnl_calib - channel calibration | |
76 | * @gain: slope coefficient for ideal curve | |
77 | * @gain_error: gain error | |
78 | * @offset_error: offset of the real curve | |
79 | */ | |
80 | struct twl6030_chnl_calib { | |
81 | s32 gain; | |
82 | s32 gain_error; | |
83 | s32 offset_error; | |
84 | }; | |
85 | ||
86 | /** | |
87 | * struct twl6030_ideal_code - GPADC calibration parameters | |
88 | * GPADC is calibrated in two points: close to the beginning and | |
89 | * to the and of the measurable input range | |
90 | * | |
91 | * @channel: channel number | |
92 | * @code1: ideal code for the input at the beginning | |
93 | * @code2: ideal code for at the end of the range | |
94 | * @volt1: voltage input at the beginning(low voltage) | |
95 | * @volt2: voltage input at the end(high voltage) | |
96 | */ | |
97 | struct twl6030_ideal_code { | |
98 | int channel; | |
99 | u16 code1; | |
100 | u16 code2; | |
101 | u16 volt1; | |
102 | u16 volt2; | |
103 | }; | |
104 | ||
105 | struct twl6030_gpadc_data; | |
106 | ||
107 | /** | |
108 | * struct twl6030_gpadc_platform_data - platform specific data | |
109 | * @nchannels: number of GPADC channels | |
110 | * @iio_channels: iio channels | |
111 | * @twl6030_ideal: pointer to calibration parameters | |
112 | * @start_conversion: pointer to ADC start conversion function | |
113 | * @channel_to_reg pointer to ADC function to convert channel to | |
114 | * register address for reading conversion result | |
115 | * @calibrate: pointer to calibration function | |
116 | */ | |
117 | struct twl6030_gpadc_platform_data { | |
118 | const int nchannels; | |
119 | const struct iio_chan_spec *iio_channels; | |
120 | const struct twl6030_ideal_code *ideal; | |
121 | int (*start_conversion)(int channel); | |
122 | u8 (*channel_to_reg)(int channel); | |
123 | int (*calibrate)(struct twl6030_gpadc_data *gpadc); | |
124 | }; | |
125 | ||
126 | /** | |
127 | * struct twl6030_gpadc_data - GPADC data | |
128 | * @dev: device pointer | |
129 | * @lock: mutual exclusion lock for the structure | |
130 | * @irq_complete: completion to signal end of conversion | |
131 | * @twl6030_cal_tbl: pointer to calibration data for each | |
132 | * channel with gain error and offset | |
133 | * @pdata: pointer to device specific data | |
134 | */ | |
135 | struct twl6030_gpadc_data { | |
136 | struct device *dev; | |
137 | struct mutex lock; | |
138 | struct completion irq_complete; | |
139 | struct twl6030_chnl_calib *twl6030_cal_tbl; | |
140 | const struct twl6030_gpadc_platform_data *pdata; | |
141 | }; | |
142 | ||
143 | /* | |
144 | * channels 11, 12, 13, 15 and 16 have no calibration data | |
145 | * calibration offset is same for channels 1, 3, 4, 5 | |
146 | * | |
147 | * The data is taken from GPADC_TRIM registers description. | |
148 | * GPADC_TRIM registers keep difference between the code measured | |
149 | * at volt1 and volt2 input voltages and corresponding code1 and code2 | |
150 | */ | |
151 | static const struct twl6030_ideal_code | |
152 | twl6030_ideal[TWL6030_GPADC_USED_CHANNELS] = { | |
153 | [0] = { /* ch 0, external, battery type, resistor value */ | |
154 | .channel = 0, | |
155 | .code1 = 116, | |
156 | .code2 = 745, | |
157 | .volt1 = 141, | |
158 | .volt2 = 910, | |
159 | }, | |
160 | [1] = { /* ch 1, external, battery temperature, NTC resistor value */ | |
161 | .channel = 1, | |
162 | .code1 = 82, | |
163 | .code2 = 900, | |
164 | .volt1 = 100, | |
165 | .volt2 = 1100, | |
166 | }, | |
167 | [2] = { /* ch 2, external, audio accessory/general purpose */ | |
168 | .channel = 2, | |
169 | .code1 = 55, | |
170 | .code2 = 818, | |
171 | .volt1 = 101, | |
172 | .volt2 = 1499, | |
173 | }, | |
174 | [3] = { /* ch 3, external, general purpose */ | |
175 | .channel = 3, | |
176 | .code1 = 82, | |
177 | .code2 = 900, | |
178 | .volt1 = 100, | |
179 | .volt2 = 1100, | |
180 | }, | |
181 | [4] = { /* ch 4, external, temperature measurement/general purpose */ | |
182 | .channel = 4, | |
183 | .code1 = 82, | |
184 | .code2 = 900, | |
185 | .volt1 = 100, | |
186 | .volt2 = 1100, | |
187 | }, | |
188 | [5] = { /* ch 5, external, general purpose */ | |
189 | .channel = 5, | |
190 | .code1 = 82, | |
191 | .code2 = 900, | |
192 | .volt1 = 100, | |
193 | .volt2 = 1100, | |
194 | }, | |
195 | [6] = { /* ch 6, external, general purpose */ | |
196 | .channel = 6, | |
197 | .code1 = 82, | |
198 | .code2 = 900, | |
199 | .volt1 = 100, | |
200 | .volt2 = 1100, | |
201 | }, | |
202 | [7] = { /* ch 7, internal, main battery */ | |
203 | .channel = 7, | |
204 | .code1 = 614, | |
205 | .code2 = 941, | |
206 | .volt1 = 3001, | |
207 | .volt2 = 4599, | |
208 | }, | |
209 | [8] = { /* ch 8, internal, backup battery */ | |
210 | .channel = 8, | |
211 | .code1 = 82, | |
212 | .code2 = 688, | |
213 | .volt1 = 501, | |
214 | .volt2 = 4203, | |
215 | }, | |
216 | [9] = { /* ch 9, internal, external charger input */ | |
217 | .channel = 9, | |
218 | .code1 = 182, | |
219 | .code2 = 818, | |
220 | .volt1 = 2001, | |
221 | .volt2 = 8996, | |
222 | }, | |
223 | [10] = { /* ch 10, internal, VBUS */ | |
224 | .channel = 10, | |
225 | .code1 = 149, | |
226 | .code2 = 818, | |
227 | .volt1 = 1001, | |
228 | .volt2 = 5497, | |
229 | }, | |
230 | [11] = { /* ch 11, internal, VBUS charging current */ | |
231 | .channel = 11, | |
232 | }, | |
233 | /* ch 12, internal, Die temperature */ | |
234 | /* ch 13, internal, Die temperature */ | |
235 | [12] = { /* ch 14, internal, USB ID line */ | |
236 | .channel = 14, | |
237 | .code1 = 48, | |
238 | .code2 = 714, | |
239 | .volt1 = 323, | |
240 | .volt2 = 4800, | |
241 | }, | |
242 | }; | |
243 | ||
244 | static const struct twl6030_ideal_code | |
245 | twl6032_ideal[TWL6032_GPADC_USED_CHANNELS] = { | |
246 | [0] = { /* ch 0, external, battery type, resistor value */ | |
247 | .channel = 0, | |
248 | .code1 = 1441, | |
249 | .code2 = 3276, | |
250 | .volt1 = 440, | |
251 | .volt2 = 1000, | |
252 | }, | |
253 | [1] = { /* ch 1, external, battery temperature, NTC resistor value */ | |
254 | .channel = 1, | |
255 | .code1 = 1441, | |
256 | .code2 = 3276, | |
257 | .volt1 = 440, | |
258 | .volt2 = 1000, | |
259 | }, | |
260 | [2] = { /* ch 2, external, audio accessory/general purpose */ | |
261 | .channel = 2, | |
262 | .code1 = 1441, | |
263 | .code2 = 3276, | |
264 | .volt1 = 660, | |
265 | .volt2 = 1500, | |
266 | }, | |
267 | [3] = { /* ch 3, external, temperature with external diode/general | |
268 | purpose */ | |
269 | .channel = 3, | |
270 | .code1 = 1441, | |
271 | .code2 = 3276, | |
272 | .volt1 = 440, | |
273 | .volt2 = 1000, | |
274 | }, | |
275 | [4] = { /* ch 4, external, temperature measurement/general purpose */ | |
276 | .channel = 4, | |
277 | .code1 = 1441, | |
278 | .code2 = 3276, | |
279 | .volt1 = 440, | |
280 | .volt2 = 1000, | |
281 | }, | |
282 | [5] = { /* ch 5, external, general purpose */ | |
283 | .channel = 5, | |
284 | .code1 = 1441, | |
285 | .code2 = 3276, | |
286 | .volt1 = 440, | |
287 | .volt2 = 1000, | |
288 | }, | |
289 | [6] = { /* ch 6, external, general purpose */ | |
290 | .channel = 6, | |
291 | .code1 = 1441, | |
292 | .code2 = 3276, | |
293 | .volt1 = 440, | |
294 | .volt2 = 1000, | |
295 | }, | |
296 | [7] = { /* ch7, internal, system supply */ | |
297 | .channel = 7, | |
298 | .code1 = 1441, | |
299 | .code2 = 3276, | |
300 | .volt1 = 2200, | |
301 | .volt2 = 5000, | |
302 | }, | |
303 | [8] = { /* ch8, internal, backup battery */ | |
304 | .channel = 8, | |
305 | .code1 = 1441, | |
306 | .code2 = 3276, | |
307 | .volt1 = 2200, | |
308 | .volt2 = 5000, | |
309 | }, | |
310 | [9] = { /* ch 9, internal, external charger input */ | |
311 | .channel = 9, | |
312 | .code1 = 1441, | |
313 | .code2 = 3276, | |
314 | .volt1 = 3960, | |
315 | .volt2 = 9000, | |
316 | }, | |
317 | [10] = { /* ch10, internal, VBUS */ | |
318 | .channel = 10, | |
319 | .code1 = 150, | |
320 | .code2 = 751, | |
321 | .volt1 = 1000, | |
322 | .volt2 = 5000, | |
323 | }, | |
324 | [11] = { /* ch 11, internal, VBUS DC-DC output current */ | |
325 | .channel = 11, | |
326 | .code1 = 1441, | |
327 | .code2 = 3276, | |
328 | .volt1 = 660, | |
329 | .volt2 = 1500, | |
330 | }, | |
331 | /* ch 12, internal, Die temperature */ | |
332 | /* ch 13, internal, Die temperature */ | |
333 | [12] = { /* ch 14, internal, USB ID line */ | |
334 | .channel = 14, | |
335 | .code1 = 1441, | |
336 | .code2 = 3276, | |
337 | .volt1 = 2420, | |
338 | .volt2 = 5500, | |
339 | }, | |
340 | /* ch 15, internal, test network */ | |
341 | /* ch 16, internal, test network */ | |
342 | [13] = { /* ch 17, internal, battery charging current */ | |
343 | .channel = 17, | |
344 | }, | |
345 | [14] = { /* ch 18, internal, battery voltage */ | |
346 | .channel = 18, | |
347 | .code1 = 1441, | |
348 | .code2 = 3276, | |
349 | .volt1 = 2200, | |
350 | .volt2 = 5000, | |
351 | }, | |
352 | }; | |
353 | ||
354 | static inline int twl6030_gpadc_write(u8 reg, u8 val) | |
355 | { | |
356 | return twl_i2c_write_u8(TWL6030_MODULE_GPADC, val, reg); | |
357 | } | |
358 | ||
359 | static inline int twl6030_gpadc_read(u8 reg, u8 *val) | |
360 | { | |
361 | ||
362 | return twl_i2c_read(TWL6030_MODULE_GPADC, val, reg, 2); | |
363 | } | |
364 | ||
365 | static int twl6030_gpadc_enable_irq(u8 mask) | |
366 | { | |
367 | int ret; | |
368 | ||
369 | ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_LINE_B); | |
370 | if (ret < 0) | |
371 | return ret; | |
372 | ||
373 | ret = twl6030_interrupt_unmask(mask, REG_INT_MSK_STS_B); | |
374 | ||
375 | return ret; | |
376 | } | |
377 | ||
378 | static void twl6030_gpadc_disable_irq(u8 mask) | |
379 | { | |
380 | twl6030_interrupt_mask(mask, REG_INT_MSK_LINE_B); | |
381 | twl6030_interrupt_mask(mask, REG_INT_MSK_STS_B); | |
382 | } | |
383 | ||
384 | static irqreturn_t twl6030_gpadc_irq_handler(int irq, void *indio_dev) | |
385 | { | |
386 | struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev); | |
387 | ||
388 | complete(&gpadc->irq_complete); | |
389 | ||
390 | return IRQ_HANDLED; | |
391 | } | |
392 | ||
393 | static int twl6030_start_conversion(int channel) | |
394 | { | |
395 | return twl6030_gpadc_write(TWL6030_GPADC_CTRL_P1, | |
396 | TWL6030_GPADC_CTRL_P1_SP1); | |
397 | } | |
398 | ||
399 | static int twl6032_start_conversion(int channel) | |
400 | { | |
401 | int ret; | |
402 | ||
403 | ret = twl6030_gpadc_write(TWL6032_GPADC_GPSELECT_ISB, channel); | |
404 | if (ret) | |
405 | return ret; | |
406 | ||
407 | return twl6030_gpadc_write(TWL6032_GPADC_CTRL_P1, | |
408 | TWL6030_GPADC_CTRL_P1_SP1); | |
409 | } | |
410 | ||
411 | static u8 twl6030_channel_to_reg(int channel) | |
412 | { | |
413 | return TWL6030_GPADC_GPCH0_LSB + 2 * channel; | |
414 | } | |
415 | ||
416 | static u8 twl6032_channel_to_reg(int channel) | |
417 | { | |
418 | /* | |
419 | * for any prior chosen channel, when the conversion is ready | |
420 | * the result is avalable in GPCH0_LSB, GPCH0_MSB. | |
421 | */ | |
422 | ||
423 | return TWL6032_GPADC_GPCH0_LSB; | |
424 | } | |
425 | ||
426 | static int twl6030_gpadc_lookup(const struct twl6030_ideal_code *ideal, | |
427 | int channel, int size) | |
428 | { | |
429 | int i; | |
430 | ||
431 | for (i = 0; i < size; i++) | |
432 | if (ideal[i].channel == channel) | |
433 | break; | |
434 | ||
435 | return i; | |
436 | } | |
437 | ||
438 | static int twl6030_channel_calibrated(const struct twl6030_gpadc_platform_data | |
439 | *pdata, int channel) | |
440 | { | |
441 | const struct twl6030_ideal_code *ideal = pdata->ideal; | |
442 | int i; | |
443 | ||
444 | i = twl6030_gpadc_lookup(ideal, channel, pdata->nchannels); | |
445 | /* not calibrated channels have 0 in all structure members */ | |
446 | return pdata->ideal[i].code2; | |
447 | } | |
448 | ||
449 | static int twl6030_gpadc_make_correction(struct twl6030_gpadc_data *gpadc, | |
450 | int channel, int raw_code) | |
451 | { | |
452 | const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; | |
453 | int corrected_code; | |
454 | int i; | |
455 | ||
456 | i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); | |
457 | corrected_code = ((raw_code * 1000) - | |
458 | gpadc->twl6030_cal_tbl[i].offset_error) / | |
459 | gpadc->twl6030_cal_tbl[i].gain_error; | |
460 | ||
461 | return corrected_code; | |
462 | } | |
463 | ||
464 | static int twl6030_gpadc_get_raw(struct twl6030_gpadc_data *gpadc, | |
465 | int channel, int *res) | |
466 | { | |
467 | u8 reg = gpadc->pdata->channel_to_reg(channel); | |
468 | __le16 val; | |
469 | int raw_code; | |
470 | int ret; | |
471 | ||
472 | ret = twl6030_gpadc_read(reg, (u8 *)&val); | |
473 | if (ret) { | |
474 | dev_dbg(gpadc->dev, "unable to read register 0x%X\n", reg); | |
475 | return ret; | |
476 | } | |
477 | ||
478 | raw_code = le16_to_cpu(val); | |
479 | dev_dbg(gpadc->dev, "GPADC raw code: %d", raw_code); | |
480 | ||
481 | if (twl6030_channel_calibrated(gpadc->pdata, channel)) | |
482 | *res = twl6030_gpadc_make_correction(gpadc, channel, raw_code); | |
483 | else | |
484 | *res = raw_code; | |
485 | ||
486 | return ret; | |
487 | } | |
488 | ||
489 | static int twl6030_gpadc_get_processed(struct twl6030_gpadc_data *gpadc, | |
490 | int channel, int *val) | |
491 | { | |
492 | const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; | |
493 | int corrected_code; | |
494 | int channel_value; | |
495 | int i; | |
496 | int ret; | |
497 | ||
498 | ret = twl6030_gpadc_get_raw(gpadc, channel, &corrected_code); | |
499 | if (ret) | |
500 | return ret; | |
501 | ||
502 | i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); | |
503 | channel_value = corrected_code * | |
504 | gpadc->twl6030_cal_tbl[i].gain; | |
505 | ||
506 | /* Shift back into mV range */ | |
507 | channel_value /= 1000; | |
508 | ||
509 | dev_dbg(gpadc->dev, "GPADC corrected code: %d", corrected_code); | |
510 | dev_dbg(gpadc->dev, "GPADC value: %d", channel_value); | |
511 | ||
512 | *val = channel_value; | |
513 | ||
514 | return ret; | |
515 | } | |
516 | ||
517 | static int twl6030_gpadc_read_raw(struct iio_dev *indio_dev, | |
518 | const struct iio_chan_spec *chan, | |
519 | int *val, int *val2, long mask) | |
520 | { | |
521 | struct twl6030_gpadc_data *gpadc = iio_priv(indio_dev); | |
522 | int ret; | |
523 | long timeout; | |
524 | ||
525 | mutex_lock(&gpadc->lock); | |
526 | ||
527 | ret = gpadc->pdata->start_conversion(chan->channel); | |
528 | if (ret) { | |
529 | dev_err(gpadc->dev, "failed to start conversion\n"); | |
530 | goto err; | |
531 | } | |
532 | /* wait for conversion to complete */ | |
533 | timeout = wait_for_completion_interruptible_timeout( | |
534 | &gpadc->irq_complete, msecs_to_jiffies(5000)); | |
535 | if (timeout == 0) { | |
536 | ret = -ETIMEDOUT; | |
537 | goto err; | |
538 | } else if (timeout < 0) { | |
1696f364 | 539 | ret = -EINTR; |
2d2da9fc | 540 | goto err; |
1696f364 OK |
541 | } |
542 | ||
543 | switch (mask) { | |
544 | case IIO_CHAN_INFO_RAW: | |
545 | ret = twl6030_gpadc_get_raw(gpadc, chan->channel, val); | |
546 | ret = ret ? -EIO : IIO_VAL_INT; | |
547 | break; | |
548 | ||
549 | case IIO_CHAN_INFO_PROCESSED: | |
550 | ret = twl6030_gpadc_get_processed(gpadc, chan->channel, val); | |
551 | ret = ret ? -EIO : IIO_VAL_INT; | |
552 | break; | |
553 | ||
554 | default: | |
555 | break; | |
556 | } | |
557 | err: | |
558 | mutex_unlock(&gpadc->lock); | |
559 | ||
560 | return ret; | |
561 | } | |
562 | ||
563 | /* | |
564 | * The GPADC channels are calibrated using a two point calibration method. | |
565 | * The channels measured with two known values: volt1 and volt2, and | |
566 | * ideal corresponding output codes are known: code1, code2. | |
567 | * The difference(d1, d2) between ideal and measured codes stored in trim | |
568 | * registers. | |
569 | * The goal is to find offset and gain of the real curve for each calibrated | |
570 | * channel. | |
571 | * gain: k = 1 + ((d2 - d1) / (x2 - x1)) | |
572 | * offset: b = d1 + (k - 1) * x1 | |
573 | */ | |
574 | static void twl6030_calibrate_channel(struct twl6030_gpadc_data *gpadc, | |
575 | int channel, int d1, int d2) | |
576 | { | |
577 | int b, k, gain, x1, x2, i; | |
578 | const struct twl6030_ideal_code *ideal = gpadc->pdata->ideal; | |
579 | ||
580 | i = twl6030_gpadc_lookup(ideal, channel, gpadc->pdata->nchannels); | |
581 | ||
582 | /* Gain */ | |
583 | gain = ((ideal[i].volt2 - ideal[i].volt1) * 1000) / | |
584 | (ideal[i].code2 - ideal[i].code1); | |
585 | ||
586 | x1 = ideal[i].code1; | |
587 | x2 = ideal[i].code2; | |
588 | ||
589 | /* k - real curve gain */ | |
590 | k = 1000 + (((d2 - d1) * 1000) / (x2 - x1)); | |
591 | ||
592 | /* b - offset of the real curve gain */ | |
593 | b = (d1 * 1000) - (k - 1000) * x1; | |
594 | ||
595 | gpadc->twl6030_cal_tbl[i].gain = gain; | |
596 | gpadc->twl6030_cal_tbl[i].gain_error = k; | |
597 | gpadc->twl6030_cal_tbl[i].offset_error = b; | |
598 | ||
599 | dev_dbg(gpadc->dev, "GPADC d1 for Chn: %d = %d\n", channel, d1); | |
600 | dev_dbg(gpadc->dev, "GPADC d2 for Chn: %d = %d\n", channel, d2); | |
601 | dev_dbg(gpadc->dev, "GPADC x1 for Chn: %d = %d\n", channel, x1); | |
602 | dev_dbg(gpadc->dev, "GPADC x2 for Chn: %d = %d\n", channel, x2); | |
603 | dev_dbg(gpadc->dev, "GPADC Gain for Chn: %d = %d\n", channel, gain); | |
604 | dev_dbg(gpadc->dev, "GPADC k for Chn: %d = %d\n", channel, k); | |
605 | dev_dbg(gpadc->dev, "GPADC b for Chn: %d = %d\n", channel, b); | |
606 | } | |
607 | ||
608 | static inline int twl6030_gpadc_get_trim_offset(s8 d) | |
609 | { | |
610 | /* | |
611 | * XXX NOTE! | |
612 | * bit 0 - sign, bit 7 - reserved, 6..1 - trim value | |
613 | * though, the documentation states that trim value | |
614 | * is absolute value, the correct conversion results are | |
615 | * obtained if the value is interpreted as 2's complement. | |
616 | */ | |
617 | __u32 temp = ((d & 0x7f) >> 1) | ((d & 1) << 6); | |
618 | ||
619 | return sign_extend32(temp, 6); | |
620 | } | |
621 | ||
622 | static int twl6030_calibration(struct twl6030_gpadc_data *gpadc) | |
623 | { | |
624 | int ret; | |
625 | int chn; | |
626 | u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS]; | |
627 | s8 d1, d2; | |
628 | ||
629 | /* | |
630 | * for calibration two measurements have been performed at | |
631 | * factory, for some channels, during the production test and | |
632 | * have been stored in registers. This two stored values are | |
633 | * used to correct the measurements. The values represent | |
634 | * offsets for the given input from the output on ideal curve. | |
635 | */ | |
636 | ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs, | |
637 | TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS); | |
638 | if (ret < 0) { | |
639 | dev_err(gpadc->dev, "calibration failed\n"); | |
640 | return ret; | |
641 | } | |
642 | ||
643 | for (chn = 0; chn < TWL6030_GPADC_MAX_CHANNELS; chn++) { | |
644 | ||
645 | switch (chn) { | |
646 | case 0: | |
647 | d1 = trim_regs[0]; | |
648 | d2 = trim_regs[1]; | |
649 | break; | |
650 | case 1: | |
651 | case 3: | |
652 | case 4: | |
653 | case 5: | |
654 | case 6: | |
655 | d1 = trim_regs[4]; | |
656 | d2 = trim_regs[5]; | |
657 | break; | |
658 | case 2: | |
659 | d1 = trim_regs[12]; | |
660 | d2 = trim_regs[13]; | |
661 | break; | |
662 | case 7: | |
663 | d1 = trim_regs[6]; | |
664 | d2 = trim_regs[7]; | |
665 | break; | |
666 | case 8: | |
667 | d1 = trim_regs[2]; | |
668 | d2 = trim_regs[3]; | |
669 | break; | |
670 | case 9: | |
671 | d1 = trim_regs[8]; | |
672 | d2 = trim_regs[9]; | |
673 | break; | |
674 | case 10: | |
675 | d1 = trim_regs[10]; | |
676 | d2 = trim_regs[11]; | |
677 | break; | |
678 | case 14: | |
679 | d1 = trim_regs[14]; | |
680 | d2 = trim_regs[15]; | |
681 | break; | |
682 | default: | |
683 | continue; | |
684 | } | |
685 | ||
686 | d1 = twl6030_gpadc_get_trim_offset(d1); | |
687 | d2 = twl6030_gpadc_get_trim_offset(d2); | |
688 | ||
689 | twl6030_calibrate_channel(gpadc, chn, d1, d2); | |
690 | } | |
691 | ||
692 | return 0; | |
693 | } | |
694 | ||
695 | static int twl6032_get_trim_value(u8 *trim_regs, unsigned int reg0, | |
696 | unsigned int reg1, unsigned int mask0, unsigned int mask1, | |
697 | unsigned int shift0) | |
698 | { | |
699 | int val; | |
700 | ||
701 | val = (trim_regs[reg0] & mask0) << shift0; | |
702 | val |= (trim_regs[reg1] & mask1) >> 1; | |
703 | if (trim_regs[reg1] & 0x01) | |
704 | val = -val; | |
705 | ||
706 | return val; | |
707 | } | |
708 | ||
709 | static int twl6032_calibration(struct twl6030_gpadc_data *gpadc) | |
710 | { | |
711 | int chn, d1 = 0, d2 = 0, temp; | |
712 | u8 trim_regs[TWL6030_GPADC_NUM_TRIM_REGS]; | |
713 | int ret; | |
714 | ||
715 | ret = twl_i2c_read(TWL6030_MODULE_ID2, trim_regs, | |
716 | TWL6030_GPADC_TRIM1, TWL6030_GPADC_NUM_TRIM_REGS); | |
717 | if (ret < 0) { | |
718 | dev_err(gpadc->dev, "calibration failed\n"); | |
719 | return ret; | |
720 | } | |
721 | ||
722 | /* | |
723 | * Loop to calculate the value needed for returning voltages from | |
724 | * GPADC not values. | |
725 | * | |
726 | * gain is calculated to 3 decimal places fixed point. | |
727 | */ | |
728 | for (chn = 0; chn < TWL6032_GPADC_MAX_CHANNELS; chn++) { | |
729 | ||
730 | switch (chn) { | |
731 | case 0: | |
732 | case 1: | |
733 | case 2: | |
734 | case 3: | |
735 | case 4: | |
736 | case 5: | |
737 | case 6: | |
738 | case 11: | |
739 | case 14: | |
740 | d1 = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, | |
741 | 0x06, 2); | |
742 | d2 = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, | |
743 | 0x06, 2); | |
744 | break; | |
745 | case 8: | |
746 | temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, | |
747 | 0x06, 2); | |
748 | d1 = temp + twl6032_get_trim_value(trim_regs, 7, 6, | |
749 | 0x18, 0x1E, 1); | |
750 | ||
751 | temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3F, | |
752 | 0x06, 2); | |
753 | d2 = temp + twl6032_get_trim_value(trim_regs, 9, 7, | |
754 | 0x1F, 0x06, 2); | |
755 | break; | |
756 | case 9: | |
757 | temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, | |
758 | 0x06, 2); | |
759 | d1 = temp + twl6032_get_trim_value(trim_regs, 13, 11, | |
760 | 0x18, 0x1E, 1); | |
761 | ||
762 | temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, | |
763 | 0x06, 2); | |
764 | d2 = temp + twl6032_get_trim_value(trim_regs, 15, 13, | |
765 | 0x1F, 0x06, 1); | |
766 | break; | |
767 | case 10: | |
768 | d1 = twl6032_get_trim_value(trim_regs, 10, 8, 0x0f, | |
769 | 0x0E, 3); | |
770 | d2 = twl6032_get_trim_value(trim_regs, 14, 12, 0x0f, | |
771 | 0x0E, 3); | |
772 | break; | |
773 | case 7: | |
774 | case 18: | |
775 | temp = twl6032_get_trim_value(trim_regs, 2, 0, 0x1f, | |
776 | 0x06, 2); | |
777 | ||
778 | d1 = (trim_regs[4] & 0x7E) >> 1; | |
779 | if (trim_regs[4] & 0x01) | |
780 | d1 = -d1; | |
781 | d1 += temp; | |
782 | ||
783 | temp = twl6032_get_trim_value(trim_regs, 3, 1, 0x3f, | |
784 | 0x06, 2); | |
785 | ||
786 | d2 = (trim_regs[5] & 0xFE) >> 1; | |
787 | if (trim_regs[5] & 0x01) | |
788 | d2 = -d2; | |
789 | ||
790 | d2 += temp; | |
791 | break; | |
792 | default: | |
793 | /* No data for other channels */ | |
794 | continue; | |
795 | } | |
796 | ||
797 | twl6030_calibrate_channel(gpadc, chn, d1, d2); | |
798 | } | |
799 | ||
800 | return 0; | |
801 | } | |
802 | ||
803 | #define TWL6030_GPADC_CHAN(chn, _type, chan_info) { \ | |
804 | .type = _type, \ | |
805 | .channel = chn, \ | |
806 | .info_mask_separate = BIT(chan_info), \ | |
807 | .indexed = 1, \ | |
808 | } | |
809 | ||
810 | static const struct iio_chan_spec twl6030_gpadc_iio_channels[] = { | |
811 | TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
812 | TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW), | |
813 | TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
814 | TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
815 | TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW), | |
816 | TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
817 | TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
818 | TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
819 | TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
820 | TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
821 | TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
822 | TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_RAW), | |
823 | TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
824 | }; | |
825 | ||
826 | static const struct iio_chan_spec twl6032_gpadc_iio_channels[] = { | |
827 | TWL6030_GPADC_CHAN(0, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
828 | TWL6030_GPADC_CHAN(1, IIO_TEMP, IIO_CHAN_INFO_RAW), | |
829 | TWL6030_GPADC_CHAN(2, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
830 | TWL6030_GPADC_CHAN(3, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
831 | TWL6030_GPADC_CHAN(4, IIO_TEMP, IIO_CHAN_INFO_RAW), | |
832 | TWL6030_GPADC_CHAN(5, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
833 | TWL6030_GPADC_CHAN(6, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
834 | TWL6030_GPADC_CHAN(7, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
835 | TWL6030_GPADC_CHAN(8, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
836 | TWL6030_GPADC_CHAN(9, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
837 | TWL6030_GPADC_CHAN(10, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
838 | TWL6030_GPADC_CHAN(11, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
839 | TWL6030_GPADC_CHAN(14, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
840 | TWL6030_GPADC_CHAN(17, IIO_VOLTAGE, IIO_CHAN_INFO_RAW), | |
841 | TWL6030_GPADC_CHAN(18, IIO_VOLTAGE, IIO_CHAN_INFO_PROCESSED), | |
842 | }; | |
843 | ||
844 | static const struct iio_info twl6030_gpadc_iio_info = { | |
845 | .read_raw = &twl6030_gpadc_read_raw, | |
846 | .driver_module = THIS_MODULE, | |
847 | }; | |
848 | ||
849 | static const struct twl6030_gpadc_platform_data twl6030_pdata = { | |
850 | .iio_channels = twl6030_gpadc_iio_channels, | |
851 | .nchannels = TWL6030_GPADC_USED_CHANNELS, | |
852 | .ideal = twl6030_ideal, | |
853 | .start_conversion = twl6030_start_conversion, | |
854 | .channel_to_reg = twl6030_channel_to_reg, | |
855 | .calibrate = twl6030_calibration, | |
856 | }; | |
857 | ||
858 | static const struct twl6030_gpadc_platform_data twl6032_pdata = { | |
859 | .iio_channels = twl6032_gpadc_iio_channels, | |
860 | .nchannels = TWL6032_GPADC_USED_CHANNELS, | |
861 | .ideal = twl6032_ideal, | |
862 | .start_conversion = twl6032_start_conversion, | |
863 | .channel_to_reg = twl6032_channel_to_reg, | |
864 | .calibrate = twl6032_calibration, | |
865 | }; | |
866 | ||
867 | static const struct of_device_id of_twl6030_match_tbl[] = { | |
868 | { | |
869 | .compatible = "ti,twl6030-gpadc", | |
870 | .data = &twl6030_pdata, | |
871 | }, | |
872 | { | |
873 | .compatible = "ti,twl6032-gpadc", | |
874 | .data = &twl6032_pdata, | |
875 | }, | |
876 | { /* end */ } | |
877 | }; | |
0df5a548 | 878 | MODULE_DEVICE_TABLE(of, of_twl6030_match_tbl); |
1696f364 OK |
879 | |
880 | static int twl6030_gpadc_probe(struct platform_device *pdev) | |
881 | { | |
882 | struct device *dev = &pdev->dev; | |
883 | struct twl6030_gpadc_data *gpadc; | |
884 | const struct twl6030_gpadc_platform_data *pdata; | |
885 | const struct of_device_id *match; | |
886 | struct iio_dev *indio_dev; | |
887 | int irq; | |
888 | int ret; | |
889 | ||
fc21acc4 | 890 | match = of_match_device(of_twl6030_match_tbl, dev); |
1696f364 OK |
891 | if (!match) |
892 | return -EINVAL; | |
893 | ||
894 | pdata = match->data; | |
895 | ||
fa659a40 OK |
896 | indio_dev = devm_iio_device_alloc(dev, sizeof(*gpadc)); |
897 | if (!indio_dev) | |
898 | return -ENOMEM; | |
1696f364 OK |
899 | |
900 | gpadc = iio_priv(indio_dev); | |
901 | ||
902 | gpadc->twl6030_cal_tbl = devm_kzalloc(dev, | |
903 | sizeof(*gpadc->twl6030_cal_tbl) * | |
904 | pdata->nchannels, GFP_KERNEL); | |
905 | if (!gpadc->twl6030_cal_tbl) | |
fa659a40 | 906 | return -ENOMEM; |
1696f364 OK |
907 | |
908 | gpadc->dev = dev; | |
909 | gpadc->pdata = pdata; | |
910 | ||
911 | platform_set_drvdata(pdev, indio_dev); | |
912 | mutex_init(&gpadc->lock); | |
913 | init_completion(&gpadc->irq_complete); | |
914 | ||
915 | ret = pdata->calibrate(gpadc); | |
916 | if (ret < 0) { | |
917 | dev_err(&pdev->dev, "failed to read calibration registers\n"); | |
fa659a40 | 918 | return ret; |
1696f364 OK |
919 | } |
920 | ||
921 | irq = platform_get_irq(pdev, 0); | |
922 | if (irq < 0) { | |
923 | dev_err(&pdev->dev, "failed to get irq\n"); | |
fa659a40 | 924 | return irq; |
1696f364 OK |
925 | } |
926 | ||
fa659a40 OK |
927 | ret = devm_request_threaded_irq(dev, irq, NULL, |
928 | twl6030_gpadc_irq_handler, | |
1696f364 | 929 | IRQF_ONESHOT, "twl6030_gpadc", indio_dev); |
1696f364 OK |
930 | |
931 | ret = twl6030_gpadc_enable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); | |
932 | if (ret < 0) { | |
933 | dev_err(&pdev->dev, "failed to enable GPADC interrupt\n"); | |
fa659a40 | 934 | return ret; |
1696f364 OK |
935 | } |
936 | ||
937 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS, | |
938 | TWL6030_REG_TOGGLE1); | |
939 | if (ret < 0) { | |
940 | dev_err(&pdev->dev, "failed to enable GPADC module\n"); | |
fa659a40 | 941 | return ret; |
1696f364 OK |
942 | } |
943 | ||
944 | indio_dev->name = DRIVER_NAME; | |
945 | indio_dev->dev.parent = dev; | |
946 | indio_dev->info = &twl6030_gpadc_iio_info; | |
947 | indio_dev->modes = INDIO_DIRECT_MODE; | |
948 | indio_dev->channels = pdata->iio_channels; | |
949 | indio_dev->num_channels = pdata->nchannels; | |
950 | ||
ae0f29d1 | 951 | return iio_device_register(indio_dev); |
1696f364 OK |
952 | } |
953 | ||
954 | static int twl6030_gpadc_remove(struct platform_device *pdev) | |
955 | { | |
956 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | |
957 | ||
958 | twl6030_gpadc_disable_irq(TWL6030_GPADC_RT_SW1_EOC_MASK); | |
1696f364 | 959 | iio_device_unregister(indio_dev); |
1696f364 OK |
960 | |
961 | return 0; | |
962 | } | |
963 | ||
964 | #ifdef CONFIG_PM_SLEEP | |
965 | static int twl6030_gpadc_suspend(struct device *pdev) | |
966 | { | |
967 | int ret; | |
968 | ||
969 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCR, | |
970 | TWL6030_REG_TOGGLE1); | |
971 | if (ret) | |
77d84ff8 | 972 | dev_err(pdev, "error resetting GPADC (%d)!\n", ret); |
1696f364 OK |
973 | |
974 | return 0; | |
975 | }; | |
976 | ||
977 | static int twl6030_gpadc_resume(struct device *pdev) | |
978 | { | |
979 | int ret; | |
980 | ||
981 | ret = twl_i2c_write_u8(TWL6030_MODULE_ID1, TWL6030_GPADCS, | |
982 | TWL6030_REG_TOGGLE1); | |
983 | if (ret) | |
984 | dev_err(pdev, "error setting GPADC (%d)!\n", ret); | |
985 | ||
986 | return 0; | |
987 | }; | |
988 | #endif | |
989 | ||
990 | static SIMPLE_DEV_PM_OPS(twl6030_gpadc_pm_ops, twl6030_gpadc_suspend, | |
991 | twl6030_gpadc_resume); | |
992 | ||
993 | static struct platform_driver twl6030_gpadc_driver = { | |
994 | .probe = twl6030_gpadc_probe, | |
995 | .remove = twl6030_gpadc_remove, | |
996 | .driver = { | |
997 | .name = DRIVER_NAME, | |
1696f364 OK |
998 | .pm = &twl6030_gpadc_pm_ops, |
999 | .of_match_table = of_twl6030_match_tbl, | |
1000 | }, | |
1001 | }; | |
1002 | ||
1003 | module_platform_driver(twl6030_gpadc_driver); | |
1004 | ||
e5d73218 | 1005 | MODULE_ALIAS("platform:" DRIVER_NAME); |
1696f364 OK |
1006 | MODULE_AUTHOR("Balaji T K <balajitk@ti.com>"); |
1007 | MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>"); | |
1008 | MODULE_AUTHOR("Oleksandr Kozaruk <oleksandr.kozaruk@ti.com"); | |
1009 | MODULE_DESCRIPTION("twl6030 ADC driver"); | |
1010 | MODULE_LICENSE("GPL"); |