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