blob: 7b27f72164a3496b7e10735ad1cc4e6fa175fb76 [file] [log] [blame]
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -07001/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 */
14#include <linux/kernel.h>
15#include <linux/err.h>
16#include <linux/module.h>
17#include <linux/mfd/pm8xxx/pm8xxx-adc.h>
18#define KELVINMIL_DEGMIL 273160
19
20static const struct pm8xxx_adc_map_pt adcmap_batttherm[] = {
21 {41001, -30},
22 {40017, -20},
23 {38721, -10},
24 {37186, 0},
25 {35554, 10},
26 {33980, 20},
27 {33253, 25},
28 {32580, 30},
29 {31412, 40},
30 {30481, 50},
31 {29759, 60},
32 {29209, 70},
33 {28794, 80}
34};
35
36static const struct pm8xxx_adc_map_pt adcmap_btm_threshold[] = {
Siddartha Mohanadossae39c902011-11-09 17:54:31 -080037 {-30, 1642},
38 {-20, 1544},
39 {-10, 1414},
40 {0, 1260},
41 {1, 1244},
42 {2, 1228},
43 {3, 1212},
44 {4, 1195},
45 {5, 1179},
46 {6, 1162},
47 {7, 1146},
48 {8, 1129},
49 {9, 1113},
50 {10, 1097},
51 {11, 1080},
52 {12, 1064},
53 {13, 1048},
54 {14, 1032},
55 {15, 1016},
56 {16, 1000},
57 {17, 985},
58 {18, 969},
59 {19, 954},
60 {20, 939},
61 {21, 924},
62 {22, 909},
63 {23, 894},
64 {24, 880},
65 {25, 866},
66 {26, 852},
67 {27, 838},
68 {28, 824},
69 {29, 811},
70 {30, 798},
71 {31, 785},
72 {32, 773},
73 {33, 760},
74 {34, 748},
75 {35, 736},
76 {36, 725},
77 {37, 713},
78 {38, 702},
79 {39, 691},
80 {40, 681},
81 {41, 670},
82 {42, 660},
83 {43, 650},
84 {44, 640},
85 {45, 631},
86 {46, 622},
87 {47, 613},
88 {48, 604},
89 {49, 595},
90 {50, 587},
91 {51, 579},
92 {52, 571},
93 {53, 563},
94 {54, 556},
95 {55, 548},
96 {56, 541},
97 {57, 534},
98 {58, 527},
99 {59, 521},
100 {60, 514},
101 {61, 508},
102 {62, 502},
103 {63, 496},
104 {64, 490},
105 {65, 485},
106 {66, 281},
107 {67, 274},
108 {68, 267},
109 {69, 260},
110 {70, 254},
111 {71, 247},
112 {72, 241},
113 {73, 235},
114 {74, 229},
115 {75, 224},
116 {76, 218},
117 {77, 213},
118 {78, 208},
119 {79, 203}
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700120};
121
122static const struct pm8xxx_adc_map_pt adcmap_pa_therm[] = {
123 {41350, -30},
124 {41282, -29},
125 {41211, -28},
126 {41137, -27},
127 {41060, -26},
128 {40980, -25},
129 {40897, -24},
130 {40811, -23},
131 {40721, -22},
132 {40629, -21},
133 {40533, -20},
134 {40434, -19},
135 {40331, -18},
136 {40226, -17},
137 {40116, -16},
138 {40004, -15},
139 {39888, -14},
140 {39769, -13},
141 {39647, -12},
142 {39521, -11},
143 {39392, -10},
144 {39260, -9},
145 {39124, -8},
146 {38986, -7},
147 {38845, -6},
148 {38700, -5},
149 {38553, -4},
150 {38403, -3},
151 {38250, -2},
152 {38094, -1},
153 {37936, 0},
154 {37776, 1},
155 {37613, 2},
156 {37448, 3},
157 {37281, 4},
158 {37112, 5},
159 {36942, 6},
160 {36770, 7},
161 {36596, 8},
162 {36421, 9},
163 {36245, 10},
164 {36068, 11},
165 {35890, 12},
166 {35712, 13},
167 {35532, 14},
168 {35353, 15},
169 {35173, 16},
170 {34993, 17},
171 {34813, 18},
172 {34634, 19},
173 {34455, 20},
174 {34276, 21},
175 {34098, 22},
176 {33921, 23},
177 {33745, 24},
178 {33569, 25},
179 {33395, 26},
180 {33223, 27},
181 {33051, 28},
182 {32881, 29},
183 {32713, 30},
184 {32547, 31},
185 {32382, 32},
186 {32219, 33},
187 {32058, 34},
188 {31899, 35},
189 {31743, 36},
190 {31588, 37},
191 {31436, 38},
192 {31285, 39},
193 {31138, 40},
194 {30992, 41},
195 {30849, 42},
196 {30708, 43},
197 {30570, 44},
198 {30434, 45},
199 {30300, 46},
200 {30169, 47},
201 {30041, 48},
202 {29915, 49},
203 {29791, 50},
204 {29670, 51},
205 {29551, 52},
206 {29435, 53},
207 {29321, 54},
208 {29210, 55},
209 {29101, 56},
210 {28994, 57},
211 {28890, 58},
212 {28788, 59},
213 {28688, 60},
214 {28590, 61},
215 {28495, 62},
216 {28402, 63},
217 {28311, 64},
218 {28222, 65},
219 {28136, 66},
220 {28051, 67},
221 {27968, 68},
222 {27888, 69},
223 {27809, 70},
224 {27732, 71},
225 {27658, 72},
226 {27584, 73},
227 {27513, 74},
228 {27444, 75},
229 {27376, 76},
230 {27310, 77},
231 {27245, 78},
232 {27183, 79},
233 {27121, 80},
234 {27062, 81},
235 {27004, 82},
236 {26947, 83},
237 {26892, 84},
238 {26838, 85},
239 {26785, 86},
240 {26734, 87},
241 {26684, 88},
242 {26636, 89},
243 {26588, 90}
244};
245
246static const struct pm8xxx_adc_map_pt adcmap_ntcg_104ef_104fb[] = {
247 {696483, -40960},
248 {649148, -39936},
249 {605368, -38912},
250 {564809, -37888},
251 {527215, -36864},
252 {492322, -35840},
253 {460007, -34816},
254 {429982, -33792},
255 {402099, -32768},
256 {376192, -31744},
257 {352075, -30720},
258 {329714, -29696},
259 {308876, -28672},
260 {289480, -27648},
261 {271417, -26624},
262 {254574, -25600},
263 {238903, -24576},
264 {224276, -23552},
265 {210631, -22528},
266 {197896, -21504},
267 {186007, -20480},
268 {174899, -19456},
269 {164521, -18432},
270 {154818, -17408},
271 {145744, -16384},
272 {137265, -15360},
273 {129307, -14336},
274 {121866, -13312},
275 {114896, -12288},
276 {108365, -11264},
277 {102252, -10240},
278 {96499, -9216},
279 {91111, -8192},
280 {86055, -7168},
281 {81308, -6144},
282 {76857, -5120},
283 {72660, -4096},
284 {68722, -3072},
285 {65020, -2048},
286 {61538, -1024},
287 {58261, 0},
288 {55177, 1024},
289 {52274, 2048},
290 {49538, 3072},
291 {46962, 4096},
292 {44531, 5120},
293 {42243, 6144},
294 {40083, 7168},
295 {38045, 8192},
296 {36122, 9216},
297 {34308, 10240},
298 {32592, 11264},
299 {30972, 12288},
300 {29442, 13312},
301 {27995, 14336},
302 {26624, 15360},
303 {25333, 16384},
304 {24109, 17408},
305 {22951, 18432},
306 {21854, 19456},
307 {20807, 20480},
308 {19831, 21504},
309 {18899, 22528},
310 {18016, 23552},
311 {17178, 24576},
312 {16384, 25600},
313 {15631, 26624},
314 {14916, 27648},
315 {14237, 28672},
316 {13593, 29696},
317 {12976, 30720},
318 {12400, 31744},
319 {11848, 32768},
320 {11324, 33792},
321 {10825, 34816},
322 {10354, 35840},
323 {9900, 36864},
324 {9471, 37888},
325 {9062, 38912},
326 {8674, 39936},
327 {8306, 40960},
328 {7951, 41984},
329 {7616, 43008},
330 {7296, 44032},
331 {6991, 45056},
332 {6701, 46080},
333 {6424, 47104},
334 {6160, 48128},
335 {5908, 49152},
336 {5667, 50176},
337 {5439, 51200},
338 {5219, 52224},
339 {5010, 53248},
340 {4810, 54272},
341 {4619, 55296},
342 {4440, 56320},
343 {4263, 57344},
344 {4097, 58368},
345 {3938, 59392},
346 {3785, 60416},
347 {3637, 61440},
348 {3501, 62464},
349 {3368, 63488},
350 {3240, 64512},
351 {3118, 65536},
352 {2998, 66560},
353 {2889, 67584},
354 {2782, 68608},
355 {2680, 69632},
356 {2581, 70656},
357 {2490, 71680},
358 {2397, 72704},
359 {2310, 73728},
360 {2227, 74752},
361 {2147, 75776},
362 {2064, 76800},
363 {1998, 77824},
364 {1927, 78848},
365 {1860, 79872},
366 {1795, 80896},
367 {1736, 81920},
368 {1673, 82944},
369 {1615, 83968},
370 {1560, 84992},
371 {1507, 86016},
372 {1456, 87040},
373 {1407, 88064},
374 {1360, 89088},
375 {1314, 90112},
376 {1271, 91136},
377 {1228, 92160},
378 {1189, 93184},
379 {1150, 94208},
380 {1112, 95232},
381 {1076, 96256},
382 {1042, 97280},
383 {1008, 98304},
384 {976, 99328},
385 {945, 100352},
386 {915, 101376},
387 {886, 102400},
388 {859, 103424},
389 {832, 104448},
390 {807, 105472},
391 {782, 106496},
392 {756, 107520},
393 {735, 108544},
394 {712, 109568},
395 {691, 110592},
396 {670, 111616},
397 {650, 112640},
398 {631, 113664},
399 {612, 114688},
400 {594, 115712},
401 {577, 116736},
402 {560, 117760},
403 {544, 118784},
404 {528, 119808},
405 {513, 120832},
406 {498, 121856},
407 {483, 122880},
408 {470, 123904},
409 {457, 124928},
410 {444, 125952},
411 {431, 126976},
412 {419, 128000}
413};
414
415static int32_t pm8xxx_adc_map_linear(const struct pm8xxx_adc_map_pt *pts,
416 uint32_t tablesize, int32_t input, int64_t *output)
417{
418 bool descending = 1;
419 uint32_t i = 0;
420
421 if ((pts == NULL) || (output == NULL))
422 return -EINVAL;
423
424 /* Check if table is descending or ascending */
425 if (tablesize > 1) {
426 if (pts[0].x < pts[1].x)
427 descending = 0;
428 }
429
430 while (i < tablesize) {
431 if ((descending == 1) && (pts[i].x < input)) {
432 /* table entry is less than measured
433 value and table is descending, stop */
434 break;
435 } else if ((descending == 0) &&
436 (pts[i].x > input)) {
437 /* table entry is greater than measured
438 value and table is ascending, stop */
439 break;
440 } else {
441 i++;
442 }
443 }
444
445 if (i == 0)
446 *output = pts[0].y;
447 else if (i == tablesize)
448 *output = pts[tablesize-1].y;
449 else {
450 /* result is between search_index and search_index-1 */
451 /* interpolate linearly */
452 *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
453 (input - pts[i-1].x))/
454 (pts[i].x - pts[i-1].x))+
455 pts[i-1].y);
456 }
457
458 return 0;
459}
460
461int32_t pm8xxx_adc_scale_default(int32_t adc_code,
462 const struct pm8xxx_adc_properties *adc_properties,
463 const struct pm8xxx_adc_chan_properties *chan_properties,
464 struct pm8xxx_adc_chan_result *adc_chan_result)
465{
466 bool negative_rawfromoffset = 0;
467 int32_t rawfromoffset = 0;
468
469 if (!chan_properties || !chan_properties->offset_gain_numerator ||
470 !chan_properties->offset_gain_denominator || !adc_properties
471 || !adc_chan_result)
472 return -EINVAL;
473
474 rawfromoffset = adc_code -
475 chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
476
477 adc_chan_result->adc_code = adc_code;
478 if (rawfromoffset < 0) {
479 if (adc_properties->bipolar) {
480 rawfromoffset = -rawfromoffset;
481 negative_rawfromoffset = 1;
482 } else {
483 rawfromoffset = 0;
484 }
485 }
486
487 if (rawfromoffset >= 1 << adc_properties->bitresolution)
488 rawfromoffset = (1 << adc_properties->bitresolution) - 1;
489
490 adc_chan_result->measurement = (int64_t)rawfromoffset *
491 chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx *
492 chan_properties->offset_gain_denominator;
493
494 /* do_div only perform positive integer division! */
495 do_div(adc_chan_result->measurement,
496 chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy *
497 chan_properties->offset_gain_numerator);
498
499 if (negative_rawfromoffset)
500 adc_chan_result->measurement = -adc_chan_result->measurement;
501
502 /* Note: adc_chan_result->measurement is in the unit of
503 * adc_properties.adc_reference. For generic channel processing,
504 * channel measurement is a scale/ratio relative to the adc
505 * reference input */
506 adc_chan_result->physical = (int32_t) adc_chan_result->measurement;
507
508 return 0;
509}
510EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_default);
511
512int32_t pm8xxx_adc_scale_batt_therm(int32_t adc_code,
513 const struct pm8xxx_adc_properties *adc_properties,
514 const struct pm8xxx_adc_chan_properties *chan_properties,
515 struct pm8xxx_adc_chan_result *adc_chan_result)
516{
517 /* Note: adc_chan_result->measurement is in the unit of
518 adc_properties.adc_reference */
519 adc_chan_result->measurement = adc_code;
520 /* convert mV ---> degC using the table */
521 return pm8xxx_adc_map_linear(
522 adcmap_batttherm,
523 ARRAY_SIZE(adcmap_batttherm),
524 adc_code,
525 &adc_chan_result->physical);
526}
527EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_batt_therm);
528
529int32_t pm8xxx_adc_scale_pa_therm(int32_t adc_code,
530 const struct pm8xxx_adc_properties *adc_properties,
531 const struct pm8xxx_adc_chan_properties *chan_properties,
532 struct pm8xxx_adc_chan_result *adc_chan_result)
533{
534 /* Note: adc_chan_result->measurement is in the unit of
535 adc_properties.adc_reference */
536 adc_chan_result->measurement = adc_code;
537 /* convert mV ---> degC using the table */
538 return pm8xxx_adc_map_linear(
539 adcmap_pa_therm,
540 ARRAY_SIZE(adcmap_pa_therm),
541 adc_code,
542 &adc_chan_result->physical);
543}
544EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_pa_therm);
545
546int32_t pm8xxx_adc_scale_pmic_therm(int32_t adc_code,
547 const struct pm8xxx_adc_properties *adc_properties,
548 const struct pm8xxx_adc_chan_properties *chan_properties,
549 struct pm8xxx_adc_chan_result *adc_chan_result)
550{
551 int32_t rawfromoffset;
552
553 if (!chan_properties || !chan_properties->offset_gain_numerator ||
554 !chan_properties->offset_gain_denominator || !adc_properties
555 || !adc_chan_result)
556 return -EINVAL;
557
558 adc_chan_result->adc_code = adc_code;
559 rawfromoffset = adc_code -
560 chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
561 if (rawfromoffset > 0) {
562 if (rawfromoffset >= 1 << adc_properties->bitresolution)
563 rawfromoffset = (1 << adc_properties->bitresolution)
564 - 1;
565 /* 2mV/K */
566 adc_chan_result->measurement = (int64_t)rawfromoffset*
567 chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dx *
568 chan_properties->offset_gain_denominator * 1000;
569
570 do_div(adc_chan_result->measurement,
571 chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].dy *
572 chan_properties->offset_gain_numerator*2);
573 } else {
574 adc_chan_result->measurement = 0;
575 }
576 /* Note: adc_chan_result->measurement is in the unit of
577 adc_properties.adc_reference */
578 adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
579 /* Change to .001 deg C */
580 adc_chan_result->physical -= KELVINMIL_DEGMIL;
581 adc_chan_result->measurement <<= 1;
582
583 return 0;
584}
585EXPORT_SYMBOL_GPL(pm8xxx_adc_scale_pmic_therm);
586
587/* Scales the ADC code to 0.001 degrees C using the map
588 * table for the XO thermistor.
589 */
590int32_t pm8xxx_adc_tdkntcg_therm(int32_t adc_code,
591 const struct pm8xxx_adc_properties *adc_properties,
592 const struct pm8xxx_adc_chan_properties *chan_properties,
593 struct pm8xxx_adc_chan_result *adc_chan_result)
594{
595 int32_t rt_r25;
596 int32_t offset = chan_properties->adc_graph[ADC_CALIB_ABSOLUTE].offset;
597
598 rt_r25 = adc_code - offset;
599
600 pm8xxx_adc_map_linear(adcmap_ntcg_104ef_104fb,
601 ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
602 rt_r25, &adc_chan_result->physical);
603
604 return 0;
605}
606EXPORT_SYMBOL_GPL(pm8xxx_adc_tdkntcg_therm);
607
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800608int32_t pm8xxx_adc_batt_scaler(struct pm8xxx_adc_arb_btm_param *btm_param,
609 const struct pm8xxx_adc_properties *adc_properties,
610 const struct pm8xxx_adc_chan_properties *chan_properties)
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700611{
612 int rc;
613
614 rc = pm8xxx_adc_map_linear(
615 adcmap_btm_threshold,
616 ARRAY_SIZE(adcmap_btm_threshold),
617 btm_param->low_thr_temp,
618 &btm_param->low_thr_voltage);
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800619 if (rc)
620 return rc;
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700621
Siddartha Mohanadossae39c902011-11-09 17:54:31 -0800622 btm_param->low_thr_voltage *=
623 chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy;
624 do_div(btm_param->low_thr_voltage, adc_properties->adc_vdd_reference);
625 btm_param->low_thr_voltage +=
626 chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd;
627
628 rc = pm8xxx_adc_map_linear(
629 adcmap_btm_threshold,
630 ARRAY_SIZE(adcmap_btm_threshold),
631 btm_param->high_thr_temp,
632 &btm_param->high_thr_voltage);
633 if (rc)
634 return rc;
635
636 btm_param->high_thr_voltage *=
637 chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].dy;
638 do_div(btm_param->high_thr_voltage, adc_properties->adc_vdd_reference);
639 btm_param->high_thr_voltage +=
640 chan_properties->adc_graph[ADC_CALIB_RATIOMETRIC].adc_gnd;
641
Siddartha Mohanadoss17607d22011-10-05 10:36:20 -0700642
643 return rc;
644}
645EXPORT_SYMBOL_GPL(pm8xxx_adc_batt_scaler);