blob: 2fdf791524be9971aca0127548899dec812658b8 [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 Mohanadosse84f8e62012-11-16 09:34:41 -0800133/* Voltage to temperature */
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700134static const struct qpnp_vadc_map_pt adcmap_100k_104ef_104fb[] = {
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800135 {1758, -40},
136 {1742, -35},
137 {1719, -30},
138 {1691, -25},
139 {1654, -20},
140 {1608, -15},
141 {1551, -10},
142 {1483, -5},
143 {1404, 0},
144 {1315, 5},
145 {1218, 10},
146 {1114, 15},
147 {1007, 20},
148 {900, 25},
149 {795, 30},
150 {696, 35},
151 {605, 40},
152 {522, 45},
153 {448, 50},
154 {383, 55},
155 {327, 60},
156 {278, 65},
157 {237, 70},
158 {202, 75},
159 {172, 80},
160 {146, 85},
161 {125, 90},
162 {107, 95},
163 {92, 100},
164 {79, 105},
165 {68, 110},
166 {59, 115},
167 {51, 120},
168 {44, 125}
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700169};
170
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800171/* Voltage to temperature */
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700172static const struct qpnp_vadc_map_pt adcmap_150k_104ef_104fb[] = {
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800173 {1738, -40},
174 {1714, -35},
175 {1682, -30},
176 {1641, -25},
177 {1589, -20},
178 {1526, -15},
179 {1451, -10},
180 {1363, -5},
181 {1266, 0},
182 {1159, 5},
183 {1048, 10},
184 {936, 15},
185 {825, 20},
186 {720, 25},
187 {622, 30},
188 {533, 35},
189 {454, 40},
190 {385, 45},
191 {326, 50},
192 {275, 55},
193 {232, 60},
194 {195, 65},
195 {165, 70},
196 {139, 75},
197 {118, 80},
198 {100, 85},
199 {85, 90},
200 {73, 95},
201 {62, 100},
202 {53, 105},
203 {46, 110},
204 {40, 115},
205 {34, 120},
206 {30, 125}
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700207};
208
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800209static int32_t qpnp_adc_map_voltage_temp(const struct qpnp_vadc_map_pt *pts,
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700210 uint32_t tablesize, int32_t input, int64_t *output)
211{
212 bool descending = 1;
213 uint32_t i = 0;
214
215 if ((pts == NULL) || (output == NULL))
216 return -EINVAL;
217
218 /* Check if table is descending or ascending */
219 if (tablesize > 1) {
220 if (pts[0].x < pts[1].x)
221 descending = 0;
222 }
223
224 while (i < tablesize) {
225 if ((descending == 1) && (pts[i].x < input)) {
226 /* table entry is less than measured
227 value and table is descending, stop */
228 break;
229 } else if ((descending == 0) &&
230 (pts[i].x > input)) {
231 /* table entry is greater than measured
232 value and table is ascending, stop */
233 break;
234 } else {
235 i++;
236 }
237 }
238
239 if (i == 0)
240 *output = pts[0].y;
241 else if (i == tablesize)
242 *output = pts[tablesize-1].y;
243 else {
244 /* result is between search_index and search_index-1 */
245 /* interpolate linearly */
246 *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
247 (input - pts[i-1].x))/
248 (pts[i].x - pts[i-1].x))+
249 pts[i-1].y);
250 }
251
252 return 0;
253}
254
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800255static int32_t qpnp_adc_map_temp_voltage(const struct qpnp_vadc_map_pt *pts,
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700256 uint32_t tablesize, int32_t input, int64_t *output)
257{
258 bool descending = 1;
259 uint32_t i = 0;
260
261 if ((pts == NULL) || (output == NULL))
262 return -EINVAL;
263
264 /* Check if table is descending or ascending */
265 if (tablesize > 1) {
266 if (pts[0].y < pts[1].y)
267 descending = 0;
268 }
269
270 while (i < tablesize) {
271 if ((descending == 1) && (pts[i].y < input)) {
272 /* table entry is less than measured
273 value and table is descending, stop */
274 break;
275 } else if ((descending == 0) && (pts[i].y > input)) {
276 /* table entry is greater than measured
277 value and table is ascending, stop */
278 break;
279 } else {
280 i++;
281 }
282 }
283
284 if (i == 0) {
285 *output = pts[0].x;
286 } else if (i == tablesize) {
287 *output = pts[tablesize-1].x;
288 } else {
289 /* result is between search_index and search_index-1 */
290 /* interpolate linearly */
291 *output = (((int32_t) ((pts[i].x - pts[i-1].x)*
292 (input - pts[i-1].y))/
293 (pts[i].y - pts[i-1].y))+
294 pts[i-1].x);
295 }
296
297 return 0;
298}
299
300static int64_t qpnp_adc_scale_ratiometric_calib(int32_t adc_code,
301 const struct qpnp_adc_properties *adc_properties,
302 const struct qpnp_vadc_chan_properties *chan_properties)
303{
304 int64_t adc_voltage = 0;
305 bool negative_offset = 0;
306
307 if (!chan_properties || !chan_properties->offset_gain_numerator ||
308 !chan_properties->offset_gain_denominator || !adc_properties)
309 return -EINVAL;
310
311 adc_voltage = (adc_code -
312 chan_properties->adc_graph[CALIB_RATIOMETRIC].adc_gnd)
313 * adc_properties->adc_vdd_reference;
314 if (adc_voltage < 0) {
315 negative_offset = 1;
316 adc_voltage = -adc_voltage;
317 }
318 do_div(adc_voltage,
319 chan_properties->adc_graph[CALIB_RATIOMETRIC].dy);
320 if (negative_offset)
321 adc_voltage = -adc_voltage;
322
323 return adc_voltage;
324}
325
326int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
327 const struct qpnp_adc_properties *adc_properties,
328 const struct qpnp_vadc_chan_properties *chan_properties,
329 struct qpnp_vadc_result *adc_chan_result)
330{
331 int64_t pmic_voltage = 0;
332 bool negative_offset = 0;
333
334 if (!chan_properties || !chan_properties->offset_gain_numerator ||
335 !chan_properties->offset_gain_denominator || !adc_properties
336 || !adc_chan_result)
337 return -EINVAL;
338
339 pmic_voltage = (adc_code -
340 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
341 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
342 if (pmic_voltage < 0) {
343 negative_offset = 1;
344 pmic_voltage = -pmic_voltage;
345 }
346 do_div(pmic_voltage,
347 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
348 if (negative_offset)
349 pmic_voltage = -pmic_voltage;
350 pmic_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
351
352 if (pmic_voltage > 0) {
353 /* 2mV/K */
354 adc_chan_result->measurement = pmic_voltage*
355 chan_properties->offset_gain_denominator;
356
357 do_div(adc_chan_result->measurement,
358 chan_properties->offset_gain_numerator * 2);
359 } else {
360 adc_chan_result->measurement = 0;
361 }
362 /* Change to .001 deg C */
363 adc_chan_result->measurement -= KELVINMIL_DEGMIL;
364 adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
365
366 return 0;
367}
368EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
369
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800370int32_t qpnp_adc_scale_millidegc_pmic_voltage_thr(
371 struct qpnp_adc_tm_btm_param *param,
372 uint32_t *low_threshold, uint32_t *high_threshold)
373{
374 struct qpnp_vadc_linear_graph btm_param;
375 int64_t *low_output = 0, *high_output = 0;
376 int rc = 0;
377
378 rc = qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_ABSOLUTE);
379 if (rc < 0) {
380 pr_err("Could not acquire gain and offset\n");
381 return rc;
382 }
383
384 /* Convert to Kelvin and account for voltage to be written as 2mV/K */
385 *low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
386 /* Convert to voltage threshold */
387 *low_output *= btm_param.dy;
388 do_div(*low_output, btm_param.adc_vref);
389 *low_output += btm_param.adc_gnd;
390
391 /* Convert to Kelvin and account for voltage to be written as 2mV/K */
392 *high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
393 /* Convert to voltage threshold */
394 *high_output *= btm_param.dy;
395 do_div(*high_output, btm_param.adc_vref);
396 *high_output += btm_param.adc_gnd;
397
398 low_threshold = (uint32_t *) low_output;
399 high_threshold = (uint32_t *) high_output;
400
401 return 0;
402}
403EXPORT_SYMBOL_GPL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
404
405/* Scales the ADC code to degC using the mapping
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700406 * table for the XO thermistor.
407 */
408int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
409 const struct qpnp_adc_properties *adc_properties,
410 const struct qpnp_vadc_chan_properties *chan_properties,
411 struct qpnp_vadc_result *adc_chan_result)
412{
413 int64_t xo_thm = 0;
414
415 if (!chan_properties || !chan_properties->offset_gain_numerator ||
416 !chan_properties->offset_gain_denominator || !adc_properties
417 || !adc_chan_result)
418 return -EINVAL;
419
420 xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
421 adc_properties, chan_properties);
Siddartha Mohanadoss0dc06942012-12-23 17:10:10 -0800422
423 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
424 ARRAY_SIZE(adcmap_100k_104ef_104fb),
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700425 xo_thm, &adc_chan_result->physical);
426
427 return 0;
428}
429EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
430
431int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
432 const struct qpnp_adc_properties *adc_properties,
433 const struct qpnp_vadc_chan_properties *chan_properties,
434 struct qpnp_vadc_result *adc_chan_result)
435{
436 int64_t bat_voltage = 0;
437
438 bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
439 adc_properties, chan_properties);
440
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800441 return qpnp_adc_map_temp_voltage(
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700442 adcmap_btm_threshold,
443 ARRAY_SIZE(adcmap_btm_threshold),
444 bat_voltage,
445 &adc_chan_result->physical);
446}
447EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
448
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700449int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
450 const struct qpnp_adc_properties *adc_properties,
451 const struct qpnp_vadc_chan_properties *chan_properties,
452 struct qpnp_vadc_result *adc_chan_result)
453{
454 int64_t therm_voltage = 0;
455
456 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
457 adc_properties, chan_properties);
458
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800459 qpnp_adc_map_voltage_temp(adcmap_150k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700460 ARRAY_SIZE(adcmap_150k_104ef_104fb),
461 therm_voltage, &adc_chan_result->physical);
462
463 return 0;
464}
465EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu1);
466
467int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
468 const struct qpnp_adc_properties *adc_properties,
469 const struct qpnp_vadc_chan_properties *chan_properties,
470 struct qpnp_vadc_result *adc_chan_result)
471{
472 int64_t therm_voltage = 0;
473
474 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
475 adc_properties, chan_properties);
476
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800477 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700478 ARRAY_SIZE(adcmap_100k_104ef_104fb),
479 therm_voltage, &adc_chan_result->physical);
480
481 return 0;
482}
483EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
484
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800485int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
486{
487 int64_t adc_voltage = 0;
488 struct qpnp_vadc_linear_graph param1;
489 int negative_offset;
490
491 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
492
493 adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
494 if (adc_voltage < 0) {
495 negative_offset = 1;
496 adc_voltage = -adc_voltage;
497 }
498
499 do_div(adc_voltage, param1.dy);
500
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800501 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800502 ARRAY_SIZE(adcmap_100k_104ef_104fb),
503 adc_voltage, result);
504 if (negative_offset)
505 adc_voltage = -adc_voltage;
506
507 return 0;
508}
509EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
510
511int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
512{
513 struct qpnp_vadc_linear_graph param1;
514 int rc;
515
516 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
517
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800518 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800519 ARRAY_SIZE(adcmap_100k_104ef_104fb),
520 param->low_thr_temp, &param->low_thr_voltage);
521 if (rc)
522 return rc;
523
524 param->low_thr_voltage *= param1.dy;
525 do_div(param->low_thr_voltage, param1.adc_vref);
526 param->low_thr_voltage += param1.adc_gnd;
527
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800528 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800529 ARRAY_SIZE(adcmap_100k_104ef_104fb),
530 param->high_thr_temp, &param->high_thr_voltage);
531 if (rc)
532 return rc;
533
534 param->high_thr_voltage *= param1.dy;
535 do_div(param->high_thr_voltage, param1.adc_vref);
536 param->high_thr_voltage += param1.adc_gnd;
537
538 return 0;
539}
540EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
541
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700542int32_t qpnp_adc_scale_batt_id(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 batt_id_voltage = 0;
548
549 batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
550 adc_properties, chan_properties);
551 adc_chan_result->physical = batt_id_voltage;
552 adc_chan_result->physical = adc_chan_result->measurement;
553
554 return 0;
555}
556EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700557
558int32_t qpnp_adc_scale_default(int32_t adc_code,
559 const struct qpnp_adc_properties *adc_properties,
560 const struct qpnp_vadc_chan_properties *chan_properties,
561 struct qpnp_vadc_result *adc_chan_result)
562{
563 bool negative_rawfromoffset = 0, negative_offset = 0;
564 int64_t scale_voltage = 0;
565
566 if (!chan_properties || !chan_properties->offset_gain_numerator ||
567 !chan_properties->offset_gain_denominator || !adc_properties
568 || !adc_chan_result)
569 return -EINVAL;
570
571 scale_voltage = (adc_code -
572 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
573 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
574 if (scale_voltage < 0) {
575 negative_offset = 1;
576 scale_voltage = -scale_voltage;
577 }
578 do_div(scale_voltage,
579 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
580 if (negative_offset)
581 scale_voltage = -scale_voltage;
582 scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
583
584 if (scale_voltage < 0) {
585 if (adc_properties->bipolar) {
586 scale_voltage = -scale_voltage;
587 negative_rawfromoffset = 1;
588 } else {
589 scale_voltage = 0;
590 }
591 }
592
593 adc_chan_result->measurement = scale_voltage *
594 chan_properties->offset_gain_denominator;
595
596 /* do_div only perform positive integer division! */
597 do_div(adc_chan_result->measurement,
598 chan_properties->offset_gain_numerator);
599
600 if (negative_rawfromoffset)
601 adc_chan_result->measurement = -adc_chan_result->measurement;
602
603 /*
604 * Note: adc_chan_result->measurement is in the unit of
605 * adc_properties.adc_reference. For generic channel processing,
606 * channel measurement is a scale/ratio relative to the adc
607 * reference input
608 */
609 adc_chan_result->physical = adc_chan_result->measurement;
610
611 return 0;
612}
613EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
614
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800615/* Converts millivolts to ADC high/low threshold code */
616int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800617 uint32_t *low_threshold, uint32_t *high_threshold)
618{
619 struct qpnp_vadc_linear_graph usb_param;
620
Siddartha Mohanadossa9525b62013-01-29 20:06:33 -0800621 qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_RATIOMETRIC);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800622
623 *low_threshold = param->low_thr * usb_param.dy;
624 do_div(*low_threshold, usb_param.adc_vref);
625 *low_threshold += usb_param.adc_gnd;
626
627 *high_threshold = param->high_thr * usb_param.dy;
628 do_div(*high_threshold, usb_param.adc_vref);
629 *high_threshold += usb_param.adc_gnd;
630
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800631 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
632 param->low_thr);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800633 return 0;
634}
635EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
636
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800637int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
638 uint32_t *low_threshold, uint32_t *high_threshold)
639{
640 struct qpnp_vadc_linear_graph vbatt_param;
641
642 qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
643
644 *low_threshold = param->low_thr * vbatt_param.dy;
645 do_div(*low_threshold, vbatt_param.adc_vref);
646 *low_threshold += vbatt_param.adc_gnd;
647
648 *high_threshold = param->high_thr * vbatt_param.dy;
649 do_div(*high_threshold, vbatt_param.adc_vref);
650 *high_threshold += vbatt_param.adc_gnd;
651
652 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
653 param->low_thr);
654 return 0;
655}
656EXPORT_SYMBOL_GPL(qpnp_adc_vbatt_rscaler);
657
658/* Converts decidegreesC to voltage based on the mapping table */
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800659int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
660 uint32_t *low_threshold, uint32_t *high_threshold)
661{
662 struct qpnp_vadc_linear_graph btm_param;
663 int64_t *low_output = 0, *high_output = 0;
664 int rc = 0;
665
666 qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
667
668 rc = qpnp_adc_map_temp_voltage(
669 adcmap_btm_threshold,
670 ARRAY_SIZE(adcmap_btm_threshold),
671 (param->low_temp),
672 low_output);
673 if (rc)
674 return rc;
675
676 *low_output *= btm_param.dy;
677 do_div(*low_output, btm_param.adc_vref);
678 *low_output += btm_param.adc_gnd;
679
680 rc = qpnp_adc_map_temp_voltage(
681 adcmap_btm_threshold,
682 ARRAY_SIZE(adcmap_btm_threshold),
683 (param->high_temp),
684 high_output);
685 if (rc)
686 return rc;
687
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800688 pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
689 param->low_temp);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800690 *high_output *= btm_param.dy;
691 do_div(*high_output, btm_param.adc_vref);
692 *high_output += btm_param.adc_gnd;
693
694 low_threshold = (uint32_t *) low_output;
695 high_threshold = (uint32_t *) high_output;
696
697 return 0;
698}
699EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
700
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700701int32_t qpnp_vadc_check_result(int32_t *data)
702{
703 if (*data < QPNP_VADC_MIN_ADC_CODE)
704 *data = QPNP_VADC_MIN_ADC_CODE;
705 else if (*data > QPNP_VADC_MAX_ADC_CODE)
706 *data = QPNP_VADC_MAX_ADC_CODE;
707
708 return 0;
709}
710EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
711
712int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
713 struct qpnp_adc_drv *adc_qpnp)
714{
715 struct device_node *node = spmi->dev.of_node;
716 struct resource *res;
717 struct device_node *child;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800718 struct qpnp_adc_amux *adc_channel_list;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700719 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700720 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700721 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700722
723 if (!node)
724 return -EINVAL;
725
726 for_each_child_of_node(node, child)
727 count_adc_channel_list++;
728
729 if (!count_adc_channel_list) {
730 pr_err("No channel listing\n");
731 return -EINVAL;
732 }
733
734 adc_qpnp->spmi = spmi;
735
736 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
737 GFP_KERNEL);
738 if (!adc_prop) {
739 dev_err(&spmi->dev, "Unable to allocate memory\n");
740 return -ENOMEM;
741 }
742 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800743 ((sizeof(struct qpnp_adc_amux)) * count_adc_channel_list),
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700744 GFP_KERNEL);
745 if (!adc_channel_list) {
746 dev_err(&spmi->dev, "Unable to allocate memory\n");
747 return -ENOMEM;
748 }
749
750 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700751 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700752 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
753 if (!amux_prop) {
754 dev_err(&spmi->dev, "Unable to allocate memory\n");
755 return -ENOMEM;
756 }
757
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700758 adc_qpnp->adc_channels = adc_channel_list;
759 adc_qpnp->amux_prop = amux_prop;
760
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700761 for_each_child_of_node(node, child) {
762 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700763 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700764 const char *calibration_param, *channel_name;
765
766 channel_name = of_get_property(child,
767 "label", NULL) ? : child->name;
768 if (!channel_name) {
769 pr_err("Invalid channel name\n");
770 return -EINVAL;
771 }
772
Siddartha Mohanadoss96be0a02012-12-07 14:38:48 -0800773 rc = of_property_read_u32(child, "reg", &channel_num);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700774 if (rc) {
775 pr_err("Invalid channel num\n");
776 return -EINVAL;
777 }
778 rc = of_property_read_u32(child, "qcom,decimation",
779 &decimation);
780 if (rc) {
781 pr_err("Invalid channel decimation property\n");
782 return -EINVAL;
783 }
784 rc = of_property_read_u32(child,
785 "qcom,pre-div-channel-scaling", &scaling);
786 if (rc) {
787 pr_err("Invalid channel scaling property\n");
788 return -EINVAL;
789 }
790 rc = of_property_read_u32(child,
791 "qcom,scale-function", &post_scaling);
792 if (rc) {
793 pr_err("Invalid channel post scaling property\n");
794 return -EINVAL;
795 }
796 rc = of_property_read_u32(child,
797 "qcom,hw-settle-time", &hw_settle_time);
798 if (rc) {
799 pr_err("Invalid channel hw settle time property\n");
800 return -EINVAL;
801 }
802 rc = of_property_read_u32(child,
803 "qcom,fast-avg-setup", &fast_avg_setup);
804 if (rc) {
805 pr_err("Invalid channel fast average setup\n");
806 return -EINVAL;
807 }
808 calibration_param = of_get_property(child,
809 "qcom,calibration-type", NULL);
810 if (!strncmp(calibration_param, "absolute", 8))
811 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700812 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700813 calib_type = CALIB_RATIOMETRIC;
814 else {
815 pr_err("%s: Invalid calibration property\n", __func__);
816 return -EINVAL;
817 }
818 /* Individual channel properties */
819 adc_channel_list[i].name = (char *)channel_name;
820 adc_channel_list[i].channel_num = channel_num;
821 adc_channel_list[i].chan_path_prescaling = scaling;
822 adc_channel_list[i].adc_decimation = decimation;
823 adc_channel_list[i].adc_scale_fn = post_scaling;
824 adc_channel_list[i].hw_settle_time = hw_settle_time;
825 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
826 i++;
827 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700828
829 /* Get the ADC VDD reference voltage and ADC bit resolution */
830 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
831 &adc_prop->adc_vdd_reference);
832 if (rc) {
833 pr_err("Invalid adc vdd reference property\n");
834 return -EINVAL;
835 }
836 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
837 &adc_prop->bitresolution);
838 if (rc) {
839 pr_err("Invalid adc bit resolution property\n");
840 return -EINVAL;
841 }
842 adc_qpnp->adc_prop = adc_prop;
843
844 /* Get the peripheral address */
845 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
846 if (!res) {
847 pr_err("No base address definition\n");
848 return -EINVAL;
849 }
850
851 adc_qpnp->slave = spmi->sid;
852 adc_qpnp->offset = res->start;
853
854 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800855 adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
856 "eoc-int-en-set");
857 if (adc_qpnp->adc_irq_eoc < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700858 pr_err("Invalid irq\n");
859 return -ENXIO;
860 }
861
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700862 init_completion(&adc_qpnp->adc_rslt_completion);
863
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700864 mutex_init(&adc_qpnp->adc_lock);
865
866 return 0;
867}
868EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);