blob: 8e350f0e8f36401e0813c3699ff1b26c1fcfd0f4 [file] [log] [blame]
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -08001/* Copyright (c) 2012-2013, 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
Siddartha Mohanadossb99cfa92013-05-01 20:19:58 -0700133static const struct qpnp_vadc_map_pt adcmap_qrd_btm_threshold[] = {
134 {-200, 1672},
135 {-180, 1656},
136 {-160, 1639},
137 {-140, 1620},
138 {-120, 1599},
139 {-100, 1577},
140 {-80, 1553},
141 {-60, 1527},
142 {-40, 1550},
143 {-20, 1471},
144 {0, 1440},
145 {20, 1408},
146 {40, 1374},
147 {60, 1339},
148 {80, 1303},
149 {100, 1266},
150 {120, 1228},
151 {140, 1190},
152 {160, 1150},
153 {180, 1111},
154 {200, 1071},
155 {220, 1032},
156 {240, 992},
157 {260, 953},
158 {280, 915},
159 {300, 877},
160 {320, 841},
161 {340, 805},
162 {360, 770},
163 {380, 736},
164 {400, 704},
165 {420, 673},
166 {440, 643},
167 {460, 614},
168 {480, 587},
169 {500, 561},
170 {520, 536},
171 {540, 513},
172 {560, 491},
173 {580, 470},
174 {600, 450},
175 {620, 431},
176 {640, 414},
177 {660, 397},
178 {680, 382},
179 {700, 367},
180 {720, 353},
181 {740, 340},
182 {760, 328},
183 {780, 317},
184 {800, 306},
185};
186
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800187/* Voltage to temperature */
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700188static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800189 {1758, -40},
190 {1742, -35},
191 {1719, -30},
192 {1691, -25},
193 {1654, -20},
194 {1608, -15},
195 {1551, -10},
196 {1483, -5},
197 {1404, 0},
198 {1315, 5},
199 {1218, 10},
200 {1114, 15},
201 {1007, 20},
202 {900, 25},
203 {795, 30},
204 {696, 35},
205 {605, 40},
206 {522, 45},
207 {448, 50},
208 {383, 55},
209 {327, 60},
210 {278, 65},
211 {237, 70},
212 {202, 75},
213 {172, 80},
214 {146, 85},
215 {125, 90},
216 {107, 95},
217 {92, 100},
218 {79, 105},
219 {68, 110},
220 {59, 115},
221 {51, 120},
222 {44, 125}
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700223};
224
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800225/* Voltage to temperature */
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700226static const struct qpnp_vadc_map_pt adcmap_150k_104ef_104fb[] = {
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800227 {1738, -40},
228 {1714, -35},
229 {1682, -30},
230 {1641, -25},
231 {1589, -20},
232 {1526, -15},
233 {1451, -10},
234 {1363, -5},
235 {1266, 0},
236 {1159, 5},
237 {1048, 10},
238 {936, 15},
239 {825, 20},
240 {720, 25},
241 {622, 30},
242 {533, 35},
243 {454, 40},
244 {385, 45},
245 {326, 50},
246 {275, 55},
247 {232, 60},
248 {195, 65},
249 {165, 70},
250 {139, 75},
251 {118, 80},
252 {100, 85},
253 {85, 90},
254 {73, 95},
255 {62, 100},
256 {53, 105},
257 {46, 110},
258 {40, 115},
259 {34, 120},
260 {30, 125}
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700261};
262
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800263static int32_t qpnp_adc_map_voltage_temp(const struct qpnp_vadc_map_pt *pts,
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700264 uint32_t tablesize, int32_t input, int64_t *output)
265{
266 bool descending = 1;
267 uint32_t i = 0;
268
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700269 if (pts == NULL)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700270 return -EINVAL;
271
272 /* Check if table is descending or ascending */
273 if (tablesize > 1) {
274 if (pts[0].x < pts[1].x)
275 descending = 0;
276 }
277
278 while (i < tablesize) {
279 if ((descending == 1) && (pts[i].x < input)) {
280 /* table entry is less than measured
281 value and table is descending, stop */
282 break;
283 } else if ((descending == 0) &&
284 (pts[i].x > input)) {
285 /* table entry is greater than measured
286 value and table is ascending, stop */
287 break;
288 } else {
289 i++;
290 }
291 }
292
293 if (i == 0)
294 *output = pts[0].y;
295 else if (i == tablesize)
296 *output = pts[tablesize-1].y;
297 else {
298 /* result is between search_index and search_index-1 */
299 /* interpolate linearly */
300 *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
301 (input - pts[i-1].x))/
302 (pts[i].x - pts[i-1].x))+
303 pts[i-1].y);
304 }
305
306 return 0;
307}
308
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800309static int32_t qpnp_adc_map_temp_voltage(const struct qpnp_vadc_map_pt *pts,
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700310 uint32_t tablesize, int32_t input, int64_t *output)
311{
312 bool descending = 1;
313 uint32_t i = 0;
314
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700315 if (pts == NULL)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700316 return -EINVAL;
317
318 /* Check if table is descending or ascending */
319 if (tablesize > 1) {
320 if (pts[0].y < pts[1].y)
321 descending = 0;
322 }
323
324 while (i < tablesize) {
325 if ((descending == 1) && (pts[i].y < input)) {
326 /* table entry is less than measured
327 value and table is descending, stop */
328 break;
329 } else if ((descending == 0) && (pts[i].y > input)) {
330 /* table entry is greater than measured
331 value and table is ascending, stop */
332 break;
333 } else {
334 i++;
335 }
336 }
337
338 if (i == 0) {
339 *output = pts[0].x;
340 } else if (i == tablesize) {
341 *output = pts[tablesize-1].x;
342 } else {
343 /* result is between search_index and search_index-1 */
344 /* interpolate linearly */
345 *output = (((int32_t) ((pts[i].x - pts[i-1].x)*
346 (input - pts[i-1].y))/
347 (pts[i].y - pts[i-1].y))+
348 pts[i-1].x);
349 }
350
351 return 0;
352}
353
354static int64_t qpnp_adc_scale_ratiometric_calib(int32_t adc_code,
355 const struct qpnp_adc_properties *adc_properties,
356 const struct qpnp_vadc_chan_properties *chan_properties)
357{
358 int64_t adc_voltage = 0;
359 bool negative_offset = 0;
360
361 if (!chan_properties || !chan_properties->offset_gain_numerator ||
362 !chan_properties->offset_gain_denominator || !adc_properties)
363 return -EINVAL;
364
365 adc_voltage = (adc_code -
366 chan_properties->adc_graph[CALIB_RATIOMETRIC].adc_gnd)
367 * adc_properties->adc_vdd_reference;
368 if (adc_voltage < 0) {
369 negative_offset = 1;
370 adc_voltage = -adc_voltage;
371 }
372 do_div(adc_voltage,
373 chan_properties->adc_graph[CALIB_RATIOMETRIC].dy);
374 if (negative_offset)
375 adc_voltage = -adc_voltage;
376
377 return adc_voltage;
378}
379
380int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
381 const struct qpnp_adc_properties *adc_properties,
382 const struct qpnp_vadc_chan_properties *chan_properties,
383 struct qpnp_vadc_result *adc_chan_result)
384{
385 int64_t pmic_voltage = 0;
386 bool negative_offset = 0;
387
388 if (!chan_properties || !chan_properties->offset_gain_numerator ||
389 !chan_properties->offset_gain_denominator || !adc_properties
390 || !adc_chan_result)
391 return -EINVAL;
392
393 pmic_voltage = (adc_code -
394 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
395 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
396 if (pmic_voltage < 0) {
397 negative_offset = 1;
398 pmic_voltage = -pmic_voltage;
399 }
400 do_div(pmic_voltage,
401 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
402 if (negative_offset)
403 pmic_voltage = -pmic_voltage;
404 pmic_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
405
406 if (pmic_voltage > 0) {
407 /* 2mV/K */
408 adc_chan_result->measurement = pmic_voltage*
409 chan_properties->offset_gain_denominator;
410
411 do_div(adc_chan_result->measurement,
412 chan_properties->offset_gain_numerator * 2);
413 } else {
414 adc_chan_result->measurement = 0;
415 }
416 /* Change to .001 deg C */
417 adc_chan_result->measurement -= KELVINMIL_DEGMIL;
418 adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
419
420 return 0;
421}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700422EXPORT_SYMBOL(qpnp_adc_scale_pmic_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700423
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800424int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
425 struct qpnp_adc_tm_btm_param *param,
426 uint32_t *low_threshold, uint32_t *high_threshold)
427{
428 struct qpnp_vadc_linear_graph btm_param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700429 int64_t low_output = 0, high_output = 0;
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700430 int rc = 0, sign = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800431
432 rc = qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_ABSOLUTE);
433 if (rc < 0) {
434 pr_err("Could not acquire gain and offset\n");
435 return rc;
436 }
437
438 /* Convert to Kelvin and account for voltage to be written as 2mV/K */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700439 low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800440 /* Convert to voltage threshold */
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700441 low_output = (low_output - QPNP_ADC_625_UV) * btm_param.dy;
442 if (low_output < 0) {
443 sign = 1;
444 low_output = -low_output;
445 }
446 do_div(low_output, QPNP_ADC_625_UV);
447 if (sign)
448 low_output = -low_output;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700449 low_output += btm_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800450
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700451 sign = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800452 /* Convert to Kelvin and account for voltage to be written as 2mV/K */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700453 high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800454 /* Convert to voltage threshold */
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700455 high_output = (high_output - QPNP_ADC_625_UV) * btm_param.dy;
456 if (high_output < 0) {
457 sign = 1;
458 high_output = -high_output;
459 }
460 do_div(high_output, QPNP_ADC_625_UV);
461 if (sign)
462 high_output = -high_output;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700463 high_output += btm_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800464
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700465 *low_threshold = (uint32_t) low_output;
466 *high_threshold = (uint32_t) high_output;
467 pr_debug("high_temp:%d, low_temp:%d\n", param->high_temp,
468 param->low_temp);
469 pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
470 *low_threshold);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800471
472 return 0;
473}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700474EXPORT_SYMBOL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800475
476/* Scales the ADC code to degC using the mapping
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700477 * table for the XO thermistor.
478 */
479int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
480 const struct qpnp_adc_properties *adc_properties,
481 const struct qpnp_vadc_chan_properties *chan_properties,
482 struct qpnp_vadc_result *adc_chan_result)
483{
484 int64_t xo_thm = 0;
485
486 if (!chan_properties || !chan_properties->offset_gain_numerator ||
487 !chan_properties->offset_gain_denominator || !adc_properties
488 || !adc_chan_result)
489 return -EINVAL;
490
491 xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
492 adc_properties, chan_properties);
Siddartha Mohanadoss0dc06942012-12-23 17:10:10 -0800493
494 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
495 ARRAY_SIZE(adcmap_100k_104ef_104fb),
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700496 xo_thm, &adc_chan_result->physical);
497
498 return 0;
499}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700500EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700501
502int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
503 const struct qpnp_adc_properties *adc_properties,
504 const struct qpnp_vadc_chan_properties *chan_properties,
505 struct qpnp_vadc_result *adc_chan_result)
506{
507 int64_t bat_voltage = 0;
508
509 bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
510 adc_properties, chan_properties);
511
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800512 return qpnp_adc_map_temp_voltage(
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700513 adcmap_btm_threshold,
514 ARRAY_SIZE(adcmap_btm_threshold),
515 bat_voltage,
516 &adc_chan_result->physical);
517}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700518EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700519
Siddartha Mohanadossb99cfa92013-05-01 20:19:58 -0700520int32_t qpnp_adc_scale_qrd_batt_therm(int32_t adc_code,
521 const struct qpnp_adc_properties *adc_properties,
522 const struct qpnp_vadc_chan_properties *chan_properties,
523 struct qpnp_vadc_result *adc_chan_result)
524{
525 int64_t bat_voltage = 0;
526
527 bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
528 adc_properties, chan_properties);
529
530 return qpnp_adc_map_temp_voltage(
531 adcmap_qrd_btm_threshold,
532 ARRAY_SIZE(adcmap_qrd_btm_threshold),
533 bat_voltage,
534 &adc_chan_result->physical);
535}
536EXPORT_SYMBOL(qpnp_adc_scale_qrd_batt_therm);
537
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700538int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
539 const struct qpnp_adc_properties *adc_properties,
540 const struct qpnp_vadc_chan_properties *chan_properties,
541 struct qpnp_vadc_result *adc_chan_result)
542{
543 int64_t therm_voltage = 0;
544
545 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
546 adc_properties, chan_properties);
547
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800548 qpnp_adc_map_voltage_temp(adcmap_150k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700549 ARRAY_SIZE(adcmap_150k_104ef_104fb),
550 therm_voltage, &adc_chan_result->physical);
551
552 return 0;
553}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700554EXPORT_SYMBOL(qpnp_adc_scale_therm_pu1);
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700555
556int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
557 const struct qpnp_adc_properties *adc_properties,
558 const struct qpnp_vadc_chan_properties *chan_properties,
559 struct qpnp_vadc_result *adc_chan_result)
560{
561 int64_t therm_voltage = 0;
562
563 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
564 adc_properties, chan_properties);
565
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800566 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700567 ARRAY_SIZE(adcmap_100k_104ef_104fb),
568 therm_voltage, &adc_chan_result->physical);
569
570 return 0;
571}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700572EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2);
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700573
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800574int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
575{
576 int64_t adc_voltage = 0;
577 struct qpnp_vadc_linear_graph param1;
578 int negative_offset;
579
580 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
581
582 adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
583 if (adc_voltage < 0) {
584 negative_offset = 1;
585 adc_voltage = -adc_voltage;
586 }
587
588 do_div(adc_voltage, param1.dy);
589
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800590 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800591 ARRAY_SIZE(adcmap_100k_104ef_104fb),
592 adc_voltage, result);
593 if (negative_offset)
594 adc_voltage = -adc_voltage;
595
596 return 0;
597}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700598EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800599
600int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
601{
602 struct qpnp_vadc_linear_graph param1;
603 int rc;
604
605 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
606
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800607 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800608 ARRAY_SIZE(adcmap_100k_104ef_104fb),
609 param->low_thr_temp, &param->low_thr_voltage);
610 if (rc)
611 return rc;
612
613 param->low_thr_voltage *= param1.dy;
614 do_div(param->low_thr_voltage, param1.adc_vref);
615 param->low_thr_voltage += param1.adc_gnd;
616
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800617 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800618 ARRAY_SIZE(adcmap_100k_104ef_104fb),
619 param->high_thr_temp, &param->high_thr_voltage);
620 if (rc)
621 return rc;
622
623 param->high_thr_voltage *= param1.dy;
624 do_div(param->high_thr_voltage, param1.adc_vref);
625 param->high_thr_voltage += param1.adc_gnd;
626
627 return 0;
628}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700629EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800630
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700631int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
632 const struct qpnp_adc_properties *adc_properties,
633 const struct qpnp_vadc_chan_properties *chan_properties,
634 struct qpnp_vadc_result *adc_chan_result)
635{
636 int64_t batt_id_voltage = 0;
637
638 batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
639 adc_properties, chan_properties);
640 adc_chan_result->physical = batt_id_voltage;
641 adc_chan_result->physical = adc_chan_result->measurement;
642
643 return 0;
644}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700645EXPORT_SYMBOL(qpnp_adc_scale_batt_id);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700646
647int32_t qpnp_adc_scale_default(int32_t adc_code,
648 const struct qpnp_adc_properties *adc_properties,
649 const struct qpnp_vadc_chan_properties *chan_properties,
650 struct qpnp_vadc_result *adc_chan_result)
651{
652 bool negative_rawfromoffset = 0, negative_offset = 0;
653 int64_t scale_voltage = 0;
654
655 if (!chan_properties || !chan_properties->offset_gain_numerator ||
656 !chan_properties->offset_gain_denominator || !adc_properties
657 || !adc_chan_result)
658 return -EINVAL;
659
660 scale_voltage = (adc_code -
661 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
662 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
663 if (scale_voltage < 0) {
664 negative_offset = 1;
665 scale_voltage = -scale_voltage;
666 }
667 do_div(scale_voltage,
668 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
669 if (negative_offset)
670 scale_voltage = -scale_voltage;
671 scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
672
673 if (scale_voltage < 0) {
674 if (adc_properties->bipolar) {
675 scale_voltage = -scale_voltage;
676 negative_rawfromoffset = 1;
677 } else {
678 scale_voltage = 0;
679 }
680 }
681
682 adc_chan_result->measurement = scale_voltage *
683 chan_properties->offset_gain_denominator;
684
685 /* do_div only perform positive integer division! */
686 do_div(adc_chan_result->measurement,
687 chan_properties->offset_gain_numerator);
688
689 if (negative_rawfromoffset)
690 adc_chan_result->measurement = -adc_chan_result->measurement;
691
692 /*
693 * Note: adc_chan_result->measurement is in the unit of
694 * adc_properties.adc_reference. For generic channel processing,
695 * channel measurement is a scale/ratio relative to the adc
696 * reference input
697 */
698 adc_chan_result->physical = adc_chan_result->measurement;
699
700 return 0;
701}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700702EXPORT_SYMBOL(qpnp_adc_scale_default);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700703
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800704int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800705 uint32_t *low_threshold, uint32_t *high_threshold)
706{
707 struct qpnp_vadc_linear_graph usb_param;
708
Siddartha Mohanadossa9525b62013-01-29 20:06:33 -0800709 qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_RATIOMETRIC);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800710
711 *low_threshold = param->low_thr * usb_param.dy;
712 do_div(*low_threshold, usb_param.adc_vref);
713 *low_threshold += usb_param.adc_gnd;
714
715 *high_threshold = param->high_thr * usb_param.dy;
716 do_div(*high_threshold, usb_param.adc_vref);
717 *high_threshold += usb_param.adc_gnd;
718
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800719 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
720 param->low_thr);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800721 return 0;
722}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700723EXPORT_SYMBOL(qpnp_adc_usb_scaler);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800724
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800725int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
726 uint32_t *low_threshold, uint32_t *high_threshold)
727{
728 struct qpnp_vadc_linear_graph vbatt_param;
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700729 int rc = 0, sign = 0;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700730 int64_t low_thr = 0, high_thr = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800731
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700732 rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
733 if (rc < 0)
734 return rc;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800735
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700736 low_thr = (((param->low_thr/3) - QPNP_ADC_625_UV) *
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700737 vbatt_param.dy);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700738 if (low_thr < 0) {
739 sign = 1;
740 low_thr = -low_thr;
741 }
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700742 do_div(low_thr, QPNP_ADC_625_UV);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700743 if (sign)
744 low_thr = -low_thr;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700745 *low_threshold = low_thr + vbatt_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800746
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700747 sign = 0;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700748 high_thr = (((param->high_thr/3) - QPNP_ADC_625_UV) *
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700749 vbatt_param.dy);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700750 if (high_thr < 0) {
751 sign = 1;
752 high_thr = -high_thr;
753 }
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700754 do_div(high_thr, QPNP_ADC_625_UV);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700755 if (sign)
756 high_thr = -high_thr;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700757 *high_threshold = high_thr + vbatt_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800758
759 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
760 param->low_thr);
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700761 pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
762 *low_threshold);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800763 return 0;
764}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700765EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800766
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800767int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
768 uint32_t *low_threshold, uint32_t *high_threshold)
769{
770 struct qpnp_vadc_linear_graph btm_param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700771 int64_t low_output = 0, high_output = 0;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800772 int rc = 0;
773
774 qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
775
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700776 pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
777 param->low_temp);
778 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800779 adcmap_btm_threshold,
780 ARRAY_SIZE(adcmap_btm_threshold),
781 (param->low_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700782 &low_output);
783 if (rc) {
784 pr_debug("low_temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800785 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700786 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800787
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700788 pr_debug("low_output:%lld\n", low_output);
789 low_output *= btm_param.dy;
790 do_div(low_output, btm_param.adc_vref);
791 low_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800792
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700793 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800794 adcmap_btm_threshold,
795 ARRAY_SIZE(adcmap_btm_threshold),
796 (param->high_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700797 &high_output);
798 if (rc) {
799 pr_debug("high temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800800 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700801 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800802
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700803 pr_debug("high_output:%lld\n", high_output);
804 high_output *= btm_param.dy;
805 do_div(high_output, btm_param.adc_vref);
806 high_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800807
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700808 /* btm low temperature correspondes to high voltage threshold */
809 *low_threshold = high_output;
810 /* btm high temperature correspondes to low voltage threshold */
811 *high_threshold = low_output;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800812
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700813 pr_debug("high_volt:%d, low_volt:%d\n", *high_threshold,
814 *low_threshold);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800815 return 0;
816}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700817EXPORT_SYMBOL(qpnp_adc_btm_scaler);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800818
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700819int32_t qpnp_vadc_check_result(int32_t *data)
820{
821 if (*data < QPNP_VADC_MIN_ADC_CODE)
822 *data = QPNP_VADC_MIN_ADC_CODE;
823 else if (*data > QPNP_VADC_MAX_ADC_CODE)
824 *data = QPNP_VADC_MAX_ADC_CODE;
825
826 return 0;
827}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700828EXPORT_SYMBOL(qpnp_vadc_check_result);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700829
830int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
831 struct qpnp_adc_drv *adc_qpnp)
832{
833 struct device_node *node = spmi->dev.of_node;
834 struct resource *res;
835 struct device_node *child;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800836 struct qpnp_adc_amux *adc_channel_list;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700837 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700838 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700839 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700840
841 if (!node)
842 return -EINVAL;
843
844 for_each_child_of_node(node, child)
845 count_adc_channel_list++;
846
847 if (!count_adc_channel_list) {
848 pr_err("No channel listing\n");
849 return -EINVAL;
850 }
851
852 adc_qpnp->spmi = spmi;
853
854 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
855 GFP_KERNEL);
856 if (!adc_prop) {
857 dev_err(&spmi->dev, "Unable to allocate memory\n");
858 return -ENOMEM;
859 }
860 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800861 ((sizeof(struct qpnp_adc_amux)) * count_adc_channel_list),
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700862 GFP_KERNEL);
863 if (!adc_channel_list) {
864 dev_err(&spmi->dev, "Unable to allocate memory\n");
865 return -ENOMEM;
866 }
867
868 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700869 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700870 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
871 if (!amux_prop) {
872 dev_err(&spmi->dev, "Unable to allocate memory\n");
873 return -ENOMEM;
874 }
875
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700876 adc_qpnp->adc_channels = adc_channel_list;
877 adc_qpnp->amux_prop = amux_prop;
878
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700879 for_each_child_of_node(node, child) {
880 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700881 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700882 const char *calibration_param, *channel_name;
883
884 channel_name = of_get_property(child,
885 "label", NULL) ? : child->name;
886 if (!channel_name) {
887 pr_err("Invalid channel name\n");
888 return -EINVAL;
889 }
890
Siddartha Mohanadoss96be0a02012-12-07 14:38:48 -0800891 rc = of_property_read_u32(child, "reg", &channel_num);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700892 if (rc) {
893 pr_err("Invalid channel num\n");
894 return -EINVAL;
895 }
896 rc = of_property_read_u32(child, "qcom,decimation",
897 &decimation);
898 if (rc) {
899 pr_err("Invalid channel decimation property\n");
900 return -EINVAL;
901 }
902 rc = of_property_read_u32(child,
903 "qcom,pre-div-channel-scaling", &scaling);
904 if (rc) {
905 pr_err("Invalid channel scaling property\n");
906 return -EINVAL;
907 }
908 rc = of_property_read_u32(child,
909 "qcom,scale-function", &post_scaling);
910 if (rc) {
911 pr_err("Invalid channel post scaling property\n");
912 return -EINVAL;
913 }
914 rc = of_property_read_u32(child,
915 "qcom,hw-settle-time", &hw_settle_time);
916 if (rc) {
917 pr_err("Invalid channel hw settle time property\n");
918 return -EINVAL;
919 }
920 rc = of_property_read_u32(child,
921 "qcom,fast-avg-setup", &fast_avg_setup);
922 if (rc) {
923 pr_err("Invalid channel fast average setup\n");
924 return -EINVAL;
925 }
926 calibration_param = of_get_property(child,
927 "qcom,calibration-type", NULL);
928 if (!strncmp(calibration_param, "absolute", 8))
929 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700930 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700931 calib_type = CALIB_RATIOMETRIC;
932 else {
933 pr_err("%s: Invalid calibration property\n", __func__);
934 return -EINVAL;
935 }
936 /* Individual channel properties */
937 adc_channel_list[i].name = (char *)channel_name;
938 adc_channel_list[i].channel_num = channel_num;
939 adc_channel_list[i].chan_path_prescaling = scaling;
940 adc_channel_list[i].adc_decimation = decimation;
941 adc_channel_list[i].adc_scale_fn = post_scaling;
942 adc_channel_list[i].hw_settle_time = hw_settle_time;
943 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
944 i++;
945 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700946
947 /* Get the ADC VDD reference voltage and ADC bit resolution */
948 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
949 &adc_prop->adc_vdd_reference);
950 if (rc) {
951 pr_err("Invalid adc vdd reference property\n");
952 return -EINVAL;
953 }
954 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
955 &adc_prop->bitresolution);
956 if (rc) {
957 pr_err("Invalid adc bit resolution property\n");
958 return -EINVAL;
959 }
960 adc_qpnp->adc_prop = adc_prop;
961
962 /* Get the peripheral address */
963 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
964 if (!res) {
965 pr_err("No base address definition\n");
966 return -EINVAL;
967 }
968
969 adc_qpnp->slave = spmi->sid;
970 adc_qpnp->offset = res->start;
971
972 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800973 adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
974 "eoc-int-en-set");
975 if (adc_qpnp->adc_irq_eoc < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700976 pr_err("Invalid irq\n");
977 return -ENXIO;
978 }
979
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700980 init_completion(&adc_qpnp->adc_rslt_completion);
981
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700982 return 0;
983}
984EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);