blob: ecd4bbb21ba8bc5f6737e2b68358dfc9e71b0b9f [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
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
370/* Scales the ADC code to 0.001 degrees C using the map
371 * table for the XO thermistor.
372 */
373int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
374 const struct qpnp_adc_properties *adc_properties,
375 const struct qpnp_vadc_chan_properties *chan_properties,
376 struct qpnp_vadc_result *adc_chan_result)
377{
378 int64_t xo_thm = 0;
379
380 if (!chan_properties || !chan_properties->offset_gain_numerator ||
381 !chan_properties->offset_gain_denominator || !adc_properties
382 || !adc_chan_result)
383 return -EINVAL;
384
385 xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
386 adc_properties, chan_properties);
Siddartha Mohanadoss0dc06942012-12-23 17:10:10 -0800387
388 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
389 ARRAY_SIZE(adcmap_100k_104ef_104fb),
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700390 xo_thm, &adc_chan_result->physical);
391
392 return 0;
393}
394EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
395
396int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
397 const struct qpnp_adc_properties *adc_properties,
398 const struct qpnp_vadc_chan_properties *chan_properties,
399 struct qpnp_vadc_result *adc_chan_result)
400{
401 int64_t bat_voltage = 0;
402
403 bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
404 adc_properties, chan_properties);
405
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800406 return qpnp_adc_map_temp_voltage(
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700407 adcmap_btm_threshold,
408 ARRAY_SIZE(adcmap_btm_threshold),
409 bat_voltage,
410 &adc_chan_result->physical);
411}
412EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
413
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700414int32_t qpnp_adc_scale_therm_pu1(int32_t adc_code,
415 const struct qpnp_adc_properties *adc_properties,
416 const struct qpnp_vadc_chan_properties *chan_properties,
417 struct qpnp_vadc_result *adc_chan_result)
418{
419 int64_t therm_voltage = 0;
420
421 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
422 adc_properties, chan_properties);
423
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800424 qpnp_adc_map_voltage_temp(adcmap_150k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700425 ARRAY_SIZE(adcmap_150k_104ef_104fb),
426 therm_voltage, &adc_chan_result->physical);
427
428 return 0;
429}
430EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu1);
431
432int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
433 const struct qpnp_adc_properties *adc_properties,
434 const struct qpnp_vadc_chan_properties *chan_properties,
435 struct qpnp_vadc_result *adc_chan_result)
436{
437 int64_t therm_voltage = 0;
438
439 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
440 adc_properties, chan_properties);
441
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800442 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700443 ARRAY_SIZE(adcmap_100k_104ef_104fb),
444 therm_voltage, &adc_chan_result->physical);
445
446 return 0;
447}
448EXPORT_SYMBOL_GPL(qpnp_adc_scale_therm_pu2);
449
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800450int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
451{
452 int64_t adc_voltage = 0;
453 struct qpnp_vadc_linear_graph param1;
454 int negative_offset;
455
456 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
457
458 adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
459 if (adc_voltage < 0) {
460 negative_offset = 1;
461 adc_voltage = -adc_voltage;
462 }
463
464 do_div(adc_voltage, param1.dy);
465
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800466 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800467 ARRAY_SIZE(adcmap_100k_104ef_104fb),
468 adc_voltage, result);
469 if (negative_offset)
470 adc_voltage = -adc_voltage;
471
472 return 0;
473}
474EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_voltage_therm_pu2);
475
476int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
477{
478 struct qpnp_vadc_linear_graph param1;
479 int rc;
480
481 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
482
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800483 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800484 ARRAY_SIZE(adcmap_100k_104ef_104fb),
485 param->low_thr_temp, &param->low_thr_voltage);
486 if (rc)
487 return rc;
488
489 param->low_thr_voltage *= param1.dy;
490 do_div(param->low_thr_voltage, param1.adc_vref);
491 param->low_thr_voltage += param1.adc_gnd;
492
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800493 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800494 ARRAY_SIZE(adcmap_100k_104ef_104fb),
495 param->high_thr_temp, &param->high_thr_voltage);
496 if (rc)
497 return rc;
498
499 param->high_thr_voltage *= param1.dy;
500 do_div(param->high_thr_voltage, param1.adc_vref);
501 param->high_thr_voltage += param1.adc_gnd;
502
503 return 0;
504}
505EXPORT_SYMBOL_GPL(qpnp_adc_tm_scale_therm_voltage_pu2);
506
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700507int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
508 const struct qpnp_adc_properties *adc_properties,
509 const struct qpnp_vadc_chan_properties *chan_properties,
510 struct qpnp_vadc_result *adc_chan_result)
511{
512 int64_t batt_id_voltage = 0;
513
514 batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
515 adc_properties, chan_properties);
516 adc_chan_result->physical = batt_id_voltage;
517 adc_chan_result->physical = adc_chan_result->measurement;
518
519 return 0;
520}
521EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_id);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700522
523int32_t qpnp_adc_scale_default(int32_t adc_code,
524 const struct qpnp_adc_properties *adc_properties,
525 const struct qpnp_vadc_chan_properties *chan_properties,
526 struct qpnp_vadc_result *adc_chan_result)
527{
528 bool negative_rawfromoffset = 0, negative_offset = 0;
529 int64_t scale_voltage = 0;
530
531 if (!chan_properties || !chan_properties->offset_gain_numerator ||
532 !chan_properties->offset_gain_denominator || !adc_properties
533 || !adc_chan_result)
534 return -EINVAL;
535
536 scale_voltage = (adc_code -
537 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
538 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
539 if (scale_voltage < 0) {
540 negative_offset = 1;
541 scale_voltage = -scale_voltage;
542 }
543 do_div(scale_voltage,
544 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
545 if (negative_offset)
546 scale_voltage = -scale_voltage;
547 scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
548
549 if (scale_voltage < 0) {
550 if (adc_properties->bipolar) {
551 scale_voltage = -scale_voltage;
552 negative_rawfromoffset = 1;
553 } else {
554 scale_voltage = 0;
555 }
556 }
557
558 adc_chan_result->measurement = scale_voltage *
559 chan_properties->offset_gain_denominator;
560
561 /* do_div only perform positive integer division! */
562 do_div(adc_chan_result->measurement,
563 chan_properties->offset_gain_numerator);
564
565 if (negative_rawfromoffset)
566 adc_chan_result->measurement = -adc_chan_result->measurement;
567
568 /*
569 * Note: adc_chan_result->measurement is in the unit of
570 * adc_properties.adc_reference. For generic channel processing,
571 * channel measurement is a scale/ratio relative to the adc
572 * reference input
573 */
574 adc_chan_result->physical = adc_chan_result->measurement;
575
576 return 0;
577}
578EXPORT_SYMBOL_GPL(qpnp_adc_scale_default);
579
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800580int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_usbid_param *param,
581 uint32_t *low_threshold, uint32_t *high_threshold)
582{
583 struct qpnp_vadc_linear_graph usb_param;
584
Siddartha Mohanadossa9525b62013-01-29 20:06:33 -0800585 qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_RATIOMETRIC);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800586
587 *low_threshold = param->low_thr * usb_param.dy;
588 do_div(*low_threshold, usb_param.adc_vref);
589 *low_threshold += usb_param.adc_gnd;
590
591 *high_threshold = param->high_thr * usb_param.dy;
592 do_div(*high_threshold, usb_param.adc_vref);
593 *high_threshold += usb_param.adc_gnd;
594
595 return 0;
596}
597EXPORT_SYMBOL_GPL(qpnp_adc_usb_scaler);
598
599int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
600 uint32_t *low_threshold, uint32_t *high_threshold)
601{
602 struct qpnp_vadc_linear_graph btm_param;
603 int64_t *low_output = 0, *high_output = 0;
604 int rc = 0;
605
606 qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
607
608 rc = qpnp_adc_map_temp_voltage(
609 adcmap_btm_threshold,
610 ARRAY_SIZE(adcmap_btm_threshold),
611 (param->low_temp),
612 low_output);
613 if (rc)
614 return rc;
615
616 *low_output *= btm_param.dy;
617 do_div(*low_output, btm_param.adc_vref);
618 *low_output += btm_param.adc_gnd;
619
620 rc = qpnp_adc_map_temp_voltage(
621 adcmap_btm_threshold,
622 ARRAY_SIZE(adcmap_btm_threshold),
623 (param->high_temp),
624 high_output);
625 if (rc)
626 return rc;
627
628 *high_output *= btm_param.dy;
629 do_div(*high_output, btm_param.adc_vref);
630 *high_output += btm_param.adc_gnd;
631
632 low_threshold = (uint32_t *) low_output;
633 high_threshold = (uint32_t *) high_output;
634
635 return 0;
636}
637EXPORT_SYMBOL_GPL(qpnp_adc_btm_scaler);
638
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700639int32_t qpnp_vadc_check_result(int32_t *data)
640{
641 if (*data < QPNP_VADC_MIN_ADC_CODE)
642 *data = QPNP_VADC_MIN_ADC_CODE;
643 else if (*data > QPNP_VADC_MAX_ADC_CODE)
644 *data = QPNP_VADC_MAX_ADC_CODE;
645
646 return 0;
647}
648EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
649
650int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
651 struct qpnp_adc_drv *adc_qpnp)
652{
653 struct device_node *node = spmi->dev.of_node;
654 struct resource *res;
655 struct device_node *child;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800656 struct qpnp_adc_amux *adc_channel_list;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700657 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700658 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700659 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700660
661 if (!node)
662 return -EINVAL;
663
664 for_each_child_of_node(node, child)
665 count_adc_channel_list++;
666
667 if (!count_adc_channel_list) {
668 pr_err("No channel listing\n");
669 return -EINVAL;
670 }
671
672 adc_qpnp->spmi = spmi;
673
674 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
675 GFP_KERNEL);
676 if (!adc_prop) {
677 dev_err(&spmi->dev, "Unable to allocate memory\n");
678 return -ENOMEM;
679 }
680 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800681 ((sizeof(struct qpnp_adc_amux)) * count_adc_channel_list),
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700682 GFP_KERNEL);
683 if (!adc_channel_list) {
684 dev_err(&spmi->dev, "Unable to allocate memory\n");
685 return -ENOMEM;
686 }
687
688 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700689 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700690 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
691 if (!amux_prop) {
692 dev_err(&spmi->dev, "Unable to allocate memory\n");
693 return -ENOMEM;
694 }
695
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700696 adc_qpnp->adc_channels = adc_channel_list;
697 adc_qpnp->amux_prop = amux_prop;
698
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700699 for_each_child_of_node(node, child) {
700 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700701 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700702 const char *calibration_param, *channel_name;
703
704 channel_name = of_get_property(child,
705 "label", NULL) ? : child->name;
706 if (!channel_name) {
707 pr_err("Invalid channel name\n");
708 return -EINVAL;
709 }
710
Siddartha Mohanadoss96be0a02012-12-07 14:38:48 -0800711 rc = of_property_read_u32(child, "reg", &channel_num);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700712 if (rc) {
713 pr_err("Invalid channel num\n");
714 return -EINVAL;
715 }
716 rc = of_property_read_u32(child, "qcom,decimation",
717 &decimation);
718 if (rc) {
719 pr_err("Invalid channel decimation property\n");
720 return -EINVAL;
721 }
722 rc = of_property_read_u32(child,
723 "qcom,pre-div-channel-scaling", &scaling);
724 if (rc) {
725 pr_err("Invalid channel scaling property\n");
726 return -EINVAL;
727 }
728 rc = of_property_read_u32(child,
729 "qcom,scale-function", &post_scaling);
730 if (rc) {
731 pr_err("Invalid channel post scaling property\n");
732 return -EINVAL;
733 }
734 rc = of_property_read_u32(child,
735 "qcom,hw-settle-time", &hw_settle_time);
736 if (rc) {
737 pr_err("Invalid channel hw settle time property\n");
738 return -EINVAL;
739 }
740 rc = of_property_read_u32(child,
741 "qcom,fast-avg-setup", &fast_avg_setup);
742 if (rc) {
743 pr_err("Invalid channel fast average setup\n");
744 return -EINVAL;
745 }
746 calibration_param = of_get_property(child,
747 "qcom,calibration-type", NULL);
748 if (!strncmp(calibration_param, "absolute", 8))
749 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700750 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700751 calib_type = CALIB_RATIOMETRIC;
752 else {
753 pr_err("%s: Invalid calibration property\n", __func__);
754 return -EINVAL;
755 }
756 /* Individual channel properties */
757 adc_channel_list[i].name = (char *)channel_name;
758 adc_channel_list[i].channel_num = channel_num;
759 adc_channel_list[i].chan_path_prescaling = scaling;
760 adc_channel_list[i].adc_decimation = decimation;
761 adc_channel_list[i].adc_scale_fn = post_scaling;
762 adc_channel_list[i].hw_settle_time = hw_settle_time;
763 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
764 i++;
765 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700766
767 /* Get the ADC VDD reference voltage and ADC bit resolution */
768 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
769 &adc_prop->adc_vdd_reference);
770 if (rc) {
771 pr_err("Invalid adc vdd reference property\n");
772 return -EINVAL;
773 }
774 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
775 &adc_prop->bitresolution);
776 if (rc) {
777 pr_err("Invalid adc bit resolution property\n");
778 return -EINVAL;
779 }
780 adc_qpnp->adc_prop = adc_prop;
781
782 /* Get the peripheral address */
783 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
784 if (!res) {
785 pr_err("No base address definition\n");
786 return -EINVAL;
787 }
788
789 adc_qpnp->slave = spmi->sid;
790 adc_qpnp->offset = res->start;
791
792 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800793 adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
794 "eoc-int-en-set");
795 if (adc_qpnp->adc_irq_eoc < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700796 pr_err("Invalid irq\n");
797 return -ENXIO;
798 }
799
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700800 init_completion(&adc_qpnp->adc_rslt_completion);
801
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700802 mutex_init(&adc_qpnp->adc_lock);
803
804 return 0;
805}
806EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);