blob: 5fb041da04537268eeee49d82b3099efe9ede11c [file] [log] [blame]
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -08001/* Copyright (c) 2012, The Linux Foundation. All rights reserved.
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 */
12
13#define pr_fmt(fmt) "%s: " fmt, __func__
14
15#include <linux/kernel.h>
16#include <linux/of.h>
17#include <linux/err.h>
18#include <linux/init.h>
19#include <linux/slab.h>
20#include <linux/delay.h>
21#include <linux/mutex.h>
22#include <linux/types.h>
23#include <linux/hwmon.h>
24#include <linux/module.h>
25#include <linux/debugfs.h>
26#include <linux/spmi.h>
27#include <linux/of_irq.h>
28#include <linux/interrupt.h>
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070029#include <linux/completion.h>
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -070030#include <linux/qpnp/qpnp-adc.h>
31#include <linux/platform_device.h>
32
33/* Min ADC code represets 0V */
34#define QPNP_VADC_MIN_ADC_CODE 0x6000
35/* Max ADC code represents full-scale range of 1.8V */
36#define QPNP_VADC_MAX_ADC_CODE 0xA800
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -070037#define KELVINMIL_DEGMIL 273160
38
39/* Units for temperature below (on x axis) is in 0.1DegC as
40 required by the battery driver. Note the resolution used
41 here to compute the table was done for DegC to milli-volts.
42 In consideration to limit the size of the table for the given
43 temperature range below, the result is linearly interpolated
44 and provided to the battery driver in the units desired for
45 their framework which is 0.1DegC. True resolution of 0.1DegC
46 will result in the below table size to increase by 10 times */
47static const struct qpnp_vadc_map_pt adcmap_btm_threshold[] = {
48 {-300, 1642},
49 {-200, 1544},
50 {-100, 1414},
51 {0, 1260},
52 {10, 1244},
53 {20, 1228},
54 {30, 1212},
55 {40, 1195},
56 {50, 1179},
57 {60, 1162},
58 {70, 1146},
59 {80, 1129},
60 {90, 1113},
61 {100, 1097},
62 {110, 1080},
63 {120, 1064},
64 {130, 1048},
65 {140, 1032},
66 {150, 1016},
67 {160, 1000},
68 {170, 985},
69 {180, 969},
70 {190, 954},
71 {200, 939},
72 {210, 924},
73 {220, 909},
74 {230, 894},
75 {240, 880},
76 {250, 866},
77 {260, 852},
78 {270, 838},
79 {280, 824},
80 {290, 811},
81 {300, 798},
82 {310, 785},
83 {320, 773},
84 {330, 760},
85 {340, 748},
86 {350, 736},
87 {360, 725},
88 {370, 713},
89 {380, 702},
90 {390, 691},
91 {400, 681},
92 {410, 670},
93 {420, 660},
94 {430, 650},
95 {440, 640},
96 {450, 631},
97 {460, 622},
98 {470, 613},
99 {480, 604},
100 {490, 595},
101 {500, 587},
102 {510, 579},
103 {520, 571},
104 {530, 563},
105 {540, 556},
106 {550, 548},
107 {560, 541},
108 {570, 534},
109 {580, 527},
110 {590, 521},
111 {600, 514},
112 {610, 508},
113 {620, 502},
114 {630, 496},
115 {640, 490},
116 {650, 485},
117 {660, 281},
118 {670, 274},
119 {680, 267},
120 {690, 260},
121 {700, 254},
122 {710, 247},
123 {720, 241},
124 {730, 235},
125 {740, 229},
126 {750, 224},
127 {760, 218},
128 {770, 213},
129 {780, 208},
130 {790, 203}
131};
132
133static const struct qpnp_vadc_map_pt adcmap_ntcg_104ef_104fb[] = {
134 {696483, -40960},
135 {649148, -39936},
136 {605368, -38912},
137 {564809, -37888},
138 {527215, -36864},
139 {492322, -35840},
140 {460007, -34816},
141 {429982, -33792},
142 {402099, -32768},
143 {376192, -31744},
144 {352075, -30720},
145 {329714, -29696},
146 {308876, -28672},
147 {289480, -27648},
148 {271417, -26624},
149 {254574, -25600},
150 {238903, -24576},
151 {224276, -23552},
152 {210631, -22528},
153 {197896, -21504},
154 {186007, -20480},
155 {174899, -19456},
156 {164521, -18432},
157 {154818, -17408},
158 {145744, -16384},
159 {137265, -15360},
160 {129307, -14336},
161 {121866, -13312},
162 {114896, -12288},
163 {108365, -11264},
164 {102252, -10240},
165 {96499, -9216},
166 {91111, -8192},
167 {86055, -7168},
168 {81308, -6144},
169 {76857, -5120},
170 {72660, -4096},
171 {68722, -3072},
172 {65020, -2048},
173 {61538, -1024},
174 {58261, 0},
175 {55177, 1024},
176 {52274, 2048},
177 {49538, 3072},
178 {46962, 4096},
179 {44531, 5120},
180 {42243, 6144},
181 {40083, 7168},
182 {38045, 8192},
183 {36122, 9216},
184 {34308, 10240},
185 {32592, 11264},
186 {30972, 12288},
187 {29442, 13312},
188 {27995, 14336},
189 {26624, 15360},
190 {25333, 16384},
191 {24109, 17408},
192 {22951, 18432},
193 {21854, 19456},
194 {20807, 20480},
195 {19831, 21504},
196 {18899, 22528},
197 {18016, 23552},
198 {17178, 24576},
199 {16384, 25600},
200 {15631, 26624},
201 {14916, 27648},
202 {14237, 28672},
203 {13593, 29696},
204 {12976, 30720},
205 {12400, 31744},
206 {11848, 32768},
207 {11324, 33792},
208 {10825, 34816},
209 {10354, 35840},
210 {9900, 36864},
211 {9471, 37888},
212 {9062, 38912},
213 {8674, 39936},
214 {8306, 40960},
215 {7951, 41984},
216 {7616, 43008},
217 {7296, 44032},
218 {6991, 45056},
219 {6701, 46080},
220 {6424, 47104},
221 {6160, 48128},
222 {5908, 49152},
223 {5667, 50176},
224 {5439, 51200},
225 {5219, 52224},
226 {5010, 53248},
227 {4810, 54272},
228 {4619, 55296},
229 {4440, 56320},
230 {4263, 57344},
231 {4097, 58368},
232 {3938, 59392},
233 {3785, 60416},
234 {3637, 61440},
235 {3501, 62464},
236 {3368, 63488},
237 {3240, 64512},
238 {3118, 65536},
239 {2998, 66560},
240 {2889, 67584},
241 {2782, 68608},
242 {2680, 69632},
243 {2581, 70656},
244 {2490, 71680},
245 {2397, 72704},
246 {2310, 73728},
247 {2227, 74752},
248 {2147, 75776},
249 {2064, 76800},
250 {1998, 77824},
251 {1927, 78848},
252 {1860, 79872},
253 {1795, 80896},
254 {1736, 81920},
255 {1673, 82944},
256 {1615, 83968},
257 {1560, 84992},
258 {1507, 86016},
259 {1456, 87040},
260 {1407, 88064},
261 {1360, 89088},
262 {1314, 90112},
263 {1271, 91136},
264 {1228, 92160},
265 {1189, 93184},
266 {1150, 94208},
267 {1112, 95232},
268 {1076, 96256},
269 {1042, 97280},
270 {1008, 98304},
271 {976, 99328},
272 {945, 100352},
273 {915, 101376},
274 {886, 102400},
275 {859, 103424},
276 {832, 104448},
277 {807, 105472},
278 {782, 106496},
279 {756, 107520},
280 {735, 108544},
281 {712, 109568},
282 {691, 110592},
283 {670, 111616},
284 {650, 112640},
285 {631, 113664},
286 {612, 114688},
287 {594, 115712},
288 {577, 116736},
289 {560, 117760},
290 {544, 118784},
291 {528, 119808},
292 {513, 120832},
293 {498, 121856},
294 {483, 122880},
295 {470, 123904},
296 {457, 124928},
297 {444, 125952},
298 {431, 126976},
299 {419, 128000}
300};
301
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800302/* Voltage to temperature */
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700303static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800304 {1758, -40},
305 {1742, -35},
306 {1719, -30},
307 {1691, -25},
308 {1654, -20},
309 {1608, -15},
310 {1551, -10},
311 {1483, -5},
312 {1404, 0},
313 {1315, 5},
314 {1218, 10},
315 {1114, 15},
316 {1007, 20},
317 {900, 25},
318 {795, 30},
319 {696, 35},
320 {605, 40},
321 {522, 45},
322 {448, 50},
323 {383, 55},
324 {327, 60},
325 {278, 65},
326 {237, 70},
327 {202, 75},
328 {172, 80},
329 {146, 85},
330 {125, 90},
331 {107, 95},
332 {92, 100},
333 {79, 105},
334 {68, 110},
335 {59, 115},
336 {51, 120},
337 {44, 125}
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700338};
339
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800340/* Voltage to temperature */
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700341static const struct qpnp_vadc_map_pt adcmap_150k_104ef_104fb[] = {
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800342 {1738, -40},
343 {1714, -35},
344 {1682, -30},
345 {1641, -25},
346 {1589, -20},
347 {1526, -15},
348 {1451, -10},
349 {1363, -5},
350 {1266, 0},
351 {1159, 5},
352 {1048, 10},
353 {936, 15},
354 {825, 20},
355 {720, 25},
356 {622, 30},
357 {533, 35},
358 {454, 40},
359 {385, 45},
360 {326, 50},
361 {275, 55},
362 {232, 60},
363 {195, 65},
364 {165, 70},
365 {139, 75},
366 {118, 80},
367 {100, 85},
368 {85, 90},
369 {73, 95},
370 {62, 100},
371 {53, 105},
372 {46, 110},
373 {40, 115},
374 {34, 120},
375 {30, 125}
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700376};
377
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800378static int32_t qpnp_adc_map_voltage_temp(const struct qpnp_vadc_map_pt *pts,
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700379 uint32_t tablesize, int32_t input, int64_t *output)
380{
381 bool descending = 1;
382 uint32_t i = 0;
383
384 if ((pts == NULL) || (output == NULL))
385 return -EINVAL;
386
387 /* Check if table is descending or ascending */
388 if (tablesize > 1) {
389 if (pts[0].x < pts[1].x)
390 descending = 0;
391 }
392
393 while (i < tablesize) {
394 if ((descending == 1) && (pts[i].x < input)) {
395 /* table entry is less than measured
396 value and table is descending, stop */
397 break;
398 } else if ((descending == 0) &&
399 (pts[i].x > input)) {
400 /* table entry is greater than measured
401 value and table is ascending, stop */
402 break;
403 } else {
404 i++;
405 }
406 }
407
408 if (i == 0)
409 *output = pts[0].y;
410 else if (i == tablesize)
411 *output = pts[tablesize-1].y;
412 else {
413 /* result is between search_index and search_index-1 */
414 /* interpolate linearly */
415 *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
416 (input - pts[i-1].x))/
417 (pts[i].x - pts[i-1].x))+
418 pts[i-1].y);
419 }
420
421 return 0;
422}
423
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800424static int32_t qpnp_adc_map_temp_voltage(const struct qpnp_vadc_map_pt *pts,
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700425 uint32_t tablesize, int32_t input, int64_t *output)
426{
427 bool descending = 1;
428 uint32_t i = 0;
429
430 if ((pts == NULL) || (output == NULL))
431 return -EINVAL;
432
433 /* Check if table is descending or ascending */
434 if (tablesize > 1) {
435 if (pts[0].y < pts[1].y)
436 descending = 0;
437 }
438
439 while (i < tablesize) {
440 if ((descending == 1) && (pts[i].y < input)) {
441 /* table entry is less than measured
442 value and table is descending, stop */
443 break;
444 } else if ((descending == 0) && (pts[i].y > input)) {
445 /* table entry is greater than measured
446 value and table is ascending, stop */
447 break;
448 } else {
449 i++;
450 }
451 }
452
453 if (i == 0) {
454 *output = pts[0].x;
455 } else if (i == tablesize) {
456 *output = pts[tablesize-1].x;
457 } else {
458 /* result is between search_index and search_index-1 */
459 /* interpolate linearly */
460 *output = (((int32_t) ((pts[i].x - pts[i-1].x)*
461 (input - pts[i-1].y))/
462 (pts[i].y - pts[i-1].y))+
463 pts[i-1].x);
464 }
465
466 return 0;
467}
468
469static int64_t qpnp_adc_scale_ratiometric_calib(int32_t adc_code,
470 const struct qpnp_adc_properties *adc_properties,
471 const struct qpnp_vadc_chan_properties *chan_properties)
472{
473 int64_t adc_voltage = 0;
474 bool negative_offset = 0;
475
476 if (!chan_properties || !chan_properties->offset_gain_numerator ||
477 !chan_properties->offset_gain_denominator || !adc_properties)
478 return -EINVAL;
479
480 adc_voltage = (adc_code -
481 chan_properties->adc_graph[CALIB_RATIOMETRIC].adc_gnd)
482 * adc_properties->adc_vdd_reference;
483 if (adc_voltage < 0) {
484 negative_offset = 1;
485 adc_voltage = -adc_voltage;
486 }
487 do_div(adc_voltage,
488 chan_properties->adc_graph[CALIB_RATIOMETRIC].dy);
489 if (negative_offset)
490 adc_voltage = -adc_voltage;
491
492 return adc_voltage;
493}
494
495int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
496 const struct qpnp_adc_properties *adc_properties,
497 const struct qpnp_vadc_chan_properties *chan_properties,
498 struct qpnp_vadc_result *adc_chan_result)
499{
500 int64_t pmic_voltage = 0;
501 bool negative_offset = 0;
502
503 if (!chan_properties || !chan_properties->offset_gain_numerator ||
504 !chan_properties->offset_gain_denominator || !adc_properties
505 || !adc_chan_result)
506 return -EINVAL;
507
508 pmic_voltage = (adc_code -
509 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
510 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
511 if (pmic_voltage < 0) {
512 negative_offset = 1;
513 pmic_voltage = -pmic_voltage;
514 }
515 do_div(pmic_voltage,
516 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
517 if (negative_offset)
518 pmic_voltage = -pmic_voltage;
519 pmic_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
520
521 if (pmic_voltage > 0) {
522 /* 2mV/K */
523 adc_chan_result->measurement = pmic_voltage*
524 chan_properties->offset_gain_denominator;
525
526 do_div(adc_chan_result->measurement,
527 chan_properties->offset_gain_numerator * 2);
528 } else {
529 adc_chan_result->measurement = 0;
530 }
531 /* Change to .001 deg C */
532 adc_chan_result->measurement -= KELVINMIL_DEGMIL;
533 adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
534
535 return 0;
536}
537EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
538
539/* Scales the ADC code to 0.001 degrees C using the map
540 * table for the XO thermistor.
541 */
542int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
543 const struct qpnp_adc_properties *adc_properties,
544 const struct qpnp_vadc_chan_properties *chan_properties,
545 struct qpnp_vadc_result *adc_chan_result)
546{
547 int64_t xo_thm = 0;
548
549 if (!chan_properties || !chan_properties->offset_gain_numerator ||
550 !chan_properties->offset_gain_denominator || !adc_properties
551 || !adc_chan_result)
552 return -EINVAL;
553
554 xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
555 adc_properties, chan_properties);
556 xo_thm <<= 4;
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800557 qpnp_adc_map_voltage_temp(adcmap_ntcg_104ef_104fb,
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700558 ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
559 xo_thm, &adc_chan_result->physical);
560
561 return 0;
562}
563EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
564
565int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
566 const struct qpnp_adc_properties *adc_properties,
567 const struct qpnp_vadc_chan_properties *chan_properties,
568 struct qpnp_vadc_result *adc_chan_result)
569{
570 int64_t bat_voltage = 0;
571
572 bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
573 adc_properties, chan_properties);
574
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800575 return qpnp_adc_map_temp_voltage(
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700576 adcmap_btm_threshold,
577 ARRAY_SIZE(adcmap_btm_threshold),
578 bat_voltage,
579 &adc_chan_result->physical);
580}
581EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
582
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700583int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
584 const struct qpnp_adc_properties *adc_properties,
585 const struct qpnp_vadc_chan_properties *chan_properties,
586 struct qpnp_vadc_result *adc_chan_result)
587{
588 int64_t therm_voltage = 0;
589
590 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
591 adc_properties, chan_properties);
592
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800593 qpnp_adc_map_voltage_temp(adcmap_150k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700594 ARRAY_SIZE(adcmap_150k_104ef_104fb),
595 therm_voltage, &adc_chan_result->physical);
596
597 return 0;
598}
599EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu1);
600
601int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
602 const struct qpnp_adc_properties *adc_properties,
603 const struct qpnp_vadc_chan_properties *chan_properties,
604 struct qpnp_vadc_result *adc_chan_result)
605{
606 int64_t therm_voltage = 0;
607
608 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
609 adc_properties, chan_properties);
610
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800611 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700612 ARRAY_SIZE(adcmap_100k_104ef_104fb),
613 therm_voltage, &adc_chan_result->physical);
614
615 return 0;
616}
617EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
618
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800619int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
620{
621 int64_t adc_voltage = 0;
622 struct qpnp_vadc_linear_graph param1;
623 int negative_offset;
624
625 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
626
627 adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
628 if (adc_voltage < 0) {
629 negative_offset = 1;
630 adc_voltage = -adc_voltage;
631 }
632
633 do_div(adc_voltage, param1.dy);
634
635 qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
636 ARRAY_SIZE(adcmap_100k_104ef_104fb),
637 adc_voltage, result);
638 if (negative_offset)
639 adc_voltage = -adc_voltage;
640
641 return 0;
642}
643EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
644
645int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
646{
647 struct qpnp_vadc_linear_graph param1;
648 int rc;
649
650 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
651
652 rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
653 ARRAY_SIZE(adcmap_100k_104ef_104fb),
654 param->low_thr_temp, &param->low_thr_voltage);
655 if (rc)
656 return rc;
657
658 param->low_thr_voltage *= param1.dy;
659 do_div(param->low_thr_voltage, param1.adc_vref);
660 param->low_thr_voltage += param1.adc_gnd;
661
662 rc = qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
663 ARRAY_SIZE(adcmap_100k_104ef_104fb),
664 param->high_thr_temp, &param->high_thr_voltage);
665 if (rc)
666 return rc;
667
668 param->high_thr_voltage *= param1.dy;
669 do_div(param->high_thr_voltage, param1.adc_vref);
670 param->high_thr_voltage += param1.adc_gnd;
671
672 return 0;
673}
674EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
675
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700676int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
677 const struct qpnp_adc_properties *adc_properties,
678 const struct qpnp_vadc_chan_properties *chan_properties,
679 struct qpnp_vadc_result *adc_chan_result)
680{
681 int64_t batt_id_voltage = 0;
682
683 batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
684 adc_properties, chan_properties);
685 adc_chan_result->physical = batt_id_voltage;
686 adc_chan_result->physical = adc_chan_result->measurement;
687
688 return 0;
689}
690EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700691
692int32_t qpnp_adc_scale_default(int32_t adc_code,
693 const struct qpnp_adc_properties *adc_properties,
694 const struct qpnp_vadc_chan_properties *chan_properties,
695 struct qpnp_vadc_result *adc_chan_result)
696{
697 bool negative_rawfromoffset = 0, negative_offset = 0;
698 int64_t scale_voltage = 0;
699
700 if (!chan_properties || !chan_properties->offset_gain_numerator ||
701 !chan_properties->offset_gain_denominator || !adc_properties
702 || !adc_chan_result)
703 return -EINVAL;
704
705 scale_voltage = (adc_code -
706 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
707 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
708 if (scale_voltage < 0) {
709 negative_offset = 1;
710 scale_voltage = -scale_voltage;
711 }
712 do_div(scale_voltage,
713 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
714 if (negative_offset)
715 scale_voltage = -scale_voltage;
716 scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
717
718 if (scale_voltage < 0) {
719 if (adc_properties->bipolar) {
720 scale_voltage = -scale_voltage;
721 negative_rawfromoffset = 1;
722 } else {
723 scale_voltage = 0;
724 }
725 }
726
727 adc_chan_result->measurement = scale_voltage *
728 chan_properties->offset_gain_denominator;
729
730 /* do_div only perform positive integer division! */
731 do_div(adc_chan_result->measurement,
732 chan_properties->offset_gain_numerator);
733
734 if (negative_rawfromoffset)
735 adc_chan_result->measurement = -adc_chan_result->measurement;
736
737 /*
738 * Note: adc_chan_result->measurement is in the unit of
739 * adc_properties.adc_reference. For generic channel processing,
740 * channel measurement is a scale/ratio relative to the adc
741 * reference input
742 */
743 adc_chan_result->physical = adc_chan_result->measurement;
744
745 return 0;
746}
747EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
748
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800749int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
750 uint32_t *low_threshold, uint32_t *high_threshold)
751{
752 struct qpnp_vadc_linear_graph usb_param;
753
754 qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_ABSOLUTE);
755
756 *low_threshold = param->low_thr * usb_param.dy;
757 do_div(*low_threshold, usb_param.adc_vref);
758 *low_threshold += usb_param.adc_gnd;
759
760 *high_threshold = param->high_thr * usb_param.dy;
761 do_div(*high_threshold, usb_param.adc_vref);
762 *high_threshold += usb_param.adc_gnd;
763
764 return 0;
765}
766EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
767
768int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
769 uint32_t *low_threshold, uint32_t *high_threshold)
770{
771 struct qpnp_vadc_linear_graph btm_param;
772 int64_t *low_output = 0, *high_output = 0;
773 int rc = 0;
774
775 qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
776
777 rc = qpnp_adc_map_temp_voltage(
778 adcmap_btm_threshold,
779 ARRAY_SIZE(adcmap_btm_threshold),
780 (param->low_temp),
781 low_output);
782 if (rc)
783 return rc;
784
785 *low_output *= btm_param.dy;
786 do_div(*low_output, btm_param.adc_vref);
787 *low_output += btm_param.adc_gnd;
788
789 rc = qpnp_adc_map_temp_voltage(
790 adcmap_btm_threshold,
791 ARRAY_SIZE(adcmap_btm_threshold),
792 (param->high_temp),
793 high_output);
794 if (rc)
795 return rc;
796
797 *high_output *= btm_param.dy;
798 do_div(*high_output, btm_param.adc_vref);
799 *high_output += btm_param.adc_gnd;
800
801 low_threshold = (uint32_t *) low_output;
802 high_threshold = (uint32_t *) high_output;
803
804 return 0;
805}
806EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
807
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700808int32_t qpnp_vadc_check_result(int32_t *data)
809{
810 if (*data < QPNP_VADC_MIN_ADC_CODE)
811 *data = QPNP_VADC_MIN_ADC_CODE;
812 else if (*data > QPNP_VADC_MAX_ADC_CODE)
813 *data = QPNP_VADC_MAX_ADC_CODE;
814
815 return 0;
816}
817EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
818
819int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
820 struct qpnp_adc_drv *adc_qpnp)
821{
822 struct device_node *node = spmi->dev.of_node;
823 struct resource *res;
824 struct device_node *child;
825 struct qpnp_vadc_amux *adc_channel_list;
826 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700827 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700828 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700829
830 if (!node)
831 return -EINVAL;
832
833 for_each_child_of_node(node, child)
834 count_adc_channel_list++;
835
836 if (!count_adc_channel_list) {
837 pr_err("No channel listing\n");
838 return -EINVAL;
839 }
840
841 adc_qpnp->spmi = spmi;
842
843 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
844 GFP_KERNEL);
845 if (!adc_prop) {
846 dev_err(&spmi->dev, "Unable to allocate memory\n");
847 return -ENOMEM;
848 }
849 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800850 ((sizeof(struct qpnp_vadc_amux)) * count_adc_channel_list),
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700851 GFP_KERNEL);
852 if (!adc_channel_list) {
853 dev_err(&spmi->dev, "Unable to allocate memory\n");
854 return -ENOMEM;
855 }
856
857 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700858 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700859 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
860 if (!amux_prop) {
861 dev_err(&spmi->dev, "Unable to allocate memory\n");
862 return -ENOMEM;
863 }
864
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700865 adc_qpnp->adc_channels = adc_channel_list;
866 adc_qpnp->amux_prop = amux_prop;
867
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700868 for_each_child_of_node(node, child) {
869 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700870 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700871 const char *calibration_param, *channel_name;
872
873 channel_name = of_get_property(child,
874 "label", NULL) ? : child->name;
875 if (!channel_name) {
876 pr_err("Invalid channel name\n");
877 return -EINVAL;
878 }
879
880 rc = of_property_read_u32(child, "qcom,channel-num",
881 &channel_num);
882 if (rc) {
883 pr_err("Invalid channel num\n");
884 return -EINVAL;
885 }
886 rc = of_property_read_u32(child, "qcom,decimation",
887 &decimation);
888 if (rc) {
889 pr_err("Invalid channel decimation property\n");
890 return -EINVAL;
891 }
892 rc = of_property_read_u32(child,
893 "qcom,pre-div-channel-scaling", &scaling);
894 if (rc) {
895 pr_err("Invalid channel scaling property\n");
896 return -EINVAL;
897 }
898 rc = of_property_read_u32(child,
899 "qcom,scale-function", &post_scaling);
900 if (rc) {
901 pr_err("Invalid channel post scaling property\n");
902 return -EINVAL;
903 }
904 rc = of_property_read_u32(child,
905 "qcom,hw-settle-time", &hw_settle_time);
906 if (rc) {
907 pr_err("Invalid channel hw settle time property\n");
908 return -EINVAL;
909 }
910 rc = of_property_read_u32(child,
911 "qcom,fast-avg-setup", &fast_avg_setup);
912 if (rc) {
913 pr_err("Invalid channel fast average setup\n");
914 return -EINVAL;
915 }
916 calibration_param = of_get_property(child,
917 "qcom,calibration-type", NULL);
918 if (!strncmp(calibration_param, "absolute", 8))
919 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700920 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700921 calib_type = CALIB_RATIOMETRIC;
922 else {
923 pr_err("%s: Invalid calibration property\n", __func__);
924 return -EINVAL;
925 }
926 /* Individual channel properties */
927 adc_channel_list[i].name = (char *)channel_name;
928 adc_channel_list[i].channel_num = channel_num;
929 adc_channel_list[i].chan_path_prescaling = scaling;
930 adc_channel_list[i].adc_decimation = decimation;
931 adc_channel_list[i].adc_scale_fn = post_scaling;
932 adc_channel_list[i].hw_settle_time = hw_settle_time;
933 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
934 i++;
935 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700936
937 /* Get the ADC VDD reference voltage and ADC bit resolution */
938 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
939 &adc_prop->adc_vdd_reference);
940 if (rc) {
941 pr_err("Invalid adc vdd reference property\n");
942 return -EINVAL;
943 }
944 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
945 &adc_prop->bitresolution);
946 if (rc) {
947 pr_err("Invalid adc bit resolution property\n");
948 return -EINVAL;
949 }
950 adc_qpnp->adc_prop = adc_prop;
951
952 /* Get the peripheral address */
953 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
954 if (!res) {
955 pr_err("No base address definition\n");
956 return -EINVAL;
957 }
958
959 adc_qpnp->slave = spmi->sid;
960 adc_qpnp->offset = res->start;
961
962 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800963 adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
964 "eoc-int-en-set");
965 if (adc_qpnp->adc_irq_eoc < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700966 pr_err("Invalid irq\n");
967 return -ENXIO;
968 }
969
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700970 init_completion(&adc_qpnp->adc_rslt_completion);
971
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700972 mutex_init(&adc_qpnp->adc_lock);
973
974 return 0;
975}
976EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);