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