blob: f908181f893997ffaa70967ba6e687dc85f2f901 [file] [log] [blame]
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -07001/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
2 *
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
302static int32_t qpnp_adc_map_linear(const struct qpnp_vadc_map_pt *pts,
303 uint32_t tablesize, int32_t input, int64_t *output)
304{
305 bool descending = 1;
306 uint32_t i = 0;
307
308 if ((pts == NULL) || (output == NULL))
309 return -EINVAL;
310
311 /* Check if table is descending or ascending */
312 if (tablesize > 1) {
313 if (pts[0].x < pts[1].x)
314 descending = 0;
315 }
316
317 while (i < tablesize) {
318 if ((descending == 1) && (pts[i].x < input)) {
319 /* table entry is less than measured
320 value and table is descending, stop */
321 break;
322 } else if ((descending == 0) &&
323 (pts[i].x > input)) {
324 /* table entry is greater than measured
325 value and table is ascending, stop */
326 break;
327 } else {
328 i++;
329 }
330 }
331
332 if (i == 0)
333 *output = pts[0].y;
334 else if (i == tablesize)
335 *output = pts[tablesize-1].y;
336 else {
337 /* result is between search_index and search_index-1 */
338 /* interpolate linearly */
339 *output = (((int32_t) ((pts[i].y - pts[i-1].y)*
340 (input - pts[i-1].x))/
341 (pts[i].x - pts[i-1].x))+
342 pts[i-1].y);
343 }
344
345 return 0;
346}
347
348static int32_t qpnp_adc_map_batt_therm(const struct qpnp_vadc_map_pt *pts,
349 uint32_t tablesize, int32_t input, int64_t *output)
350{
351 bool descending = 1;
352 uint32_t i = 0;
353
354 if ((pts == NULL) || (output == NULL))
355 return -EINVAL;
356
357 /* Check if table is descending or ascending */
358 if (tablesize > 1) {
359 if (pts[0].y < pts[1].y)
360 descending = 0;
361 }
362
363 while (i < tablesize) {
364 if ((descending == 1) && (pts[i].y < input)) {
365 /* table entry is less than measured
366 value and table is descending, stop */
367 break;
368 } else if ((descending == 0) && (pts[i].y > input)) {
369 /* table entry is greater than measured
370 value and table is ascending, stop */
371 break;
372 } else {
373 i++;
374 }
375 }
376
377 if (i == 0) {
378 *output = pts[0].x;
379 } else if (i == tablesize) {
380 *output = pts[tablesize-1].x;
381 } else {
382 /* result is between search_index and search_index-1 */
383 /* interpolate linearly */
384 *output = (((int32_t) ((pts[i].x - pts[i-1].x)*
385 (input - pts[i-1].y))/
386 (pts[i].y - pts[i-1].y))+
387 pts[i-1].x);
388 }
389
390 return 0;
391}
392
393static int64_t qpnp_adc_scale_ratiometric_calib(int32_t adc_code,
394 const struct qpnp_adc_properties *adc_properties,
395 const struct qpnp_vadc_chan_properties *chan_properties)
396{
397 int64_t adc_voltage = 0;
398 bool negative_offset = 0;
399
400 if (!chan_properties || !chan_properties->offset_gain_numerator ||
401 !chan_properties->offset_gain_denominator || !adc_properties)
402 return -EINVAL;
403
404 adc_voltage = (adc_code -
405 chan_properties->adc_graph[CALIB_RATIOMETRIC].adc_gnd)
406 * adc_properties->adc_vdd_reference;
407 if (adc_voltage < 0) {
408 negative_offset = 1;
409 adc_voltage = -adc_voltage;
410 }
411 do_div(adc_voltage,
412 chan_properties->adc_graph[CALIB_RATIOMETRIC].dy);
413 if (negative_offset)
414 adc_voltage = -adc_voltage;
415
416 return adc_voltage;
417}
418
419int32_t qpnp_adc_scale_pmic_therm(int32_t adc_code,
420 const struct qpnp_adc_properties *adc_properties,
421 const struct qpnp_vadc_chan_properties *chan_properties,
422 struct qpnp_vadc_result *adc_chan_result)
423{
424 int64_t pmic_voltage = 0;
425 bool negative_offset = 0;
426
427 if (!chan_properties || !chan_properties->offset_gain_numerator ||
428 !chan_properties->offset_gain_denominator || !adc_properties
429 || !adc_chan_result)
430 return -EINVAL;
431
432 pmic_voltage = (adc_code -
433 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
434 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
435 if (pmic_voltage < 0) {
436 negative_offset = 1;
437 pmic_voltage = -pmic_voltage;
438 }
439 do_div(pmic_voltage,
440 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
441 if (negative_offset)
442 pmic_voltage = -pmic_voltage;
443 pmic_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
444
445 if (pmic_voltage > 0) {
446 /* 2mV/K */
447 adc_chan_result->measurement = pmic_voltage*
448 chan_properties->offset_gain_denominator;
449
450 do_div(adc_chan_result->measurement,
451 chan_properties->offset_gain_numerator * 2);
452 } else {
453 adc_chan_result->measurement = 0;
454 }
455 /* Change to .001 deg C */
456 adc_chan_result->measurement -= KELVINMIL_DEGMIL;
457 adc_chan_result->physical = (int32_t)adc_chan_result->measurement;
458
459 return 0;
460}
461EXPORT_SYMBOL_GPL(qpnp_adc_scale_pmic_therm);
462
463/* Scales the ADC code to 0.001 degrees C using the map
464 * table for the XO thermistor.
465 */
466int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
467 const struct qpnp_adc_properties *adc_properties,
468 const struct qpnp_vadc_chan_properties *chan_properties,
469 struct qpnp_vadc_result *adc_chan_result)
470{
471 int64_t xo_thm = 0;
472
473 if (!chan_properties || !chan_properties->offset_gain_numerator ||
474 !chan_properties->offset_gain_denominator || !adc_properties
475 || !adc_chan_result)
476 return -EINVAL;
477
478 xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
479 adc_properties, chan_properties);
480 xo_thm <<= 4;
481 qpnp_adc_map_linear(adcmap_ntcg_104ef_104fb,
482 ARRAY_SIZE(adcmap_ntcg_104ef_104fb),
483 xo_thm, &adc_chan_result->physical);
484
485 return 0;
486}
487EXPORT_SYMBOL_GPL(qpnp_adc_tdkntcg_therm);
488
489int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
490 const struct qpnp_adc_properties *adc_properties,
491 const struct qpnp_vadc_chan_properties *chan_properties,
492 struct qpnp_vadc_result *adc_chan_result)
493{
494 int64_t bat_voltage = 0;
495
496 bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
497 adc_properties, chan_properties);
498
499 return qpnp_adc_map_batt_therm(
500 adcmap_btm_threshold,
501 ARRAY_SIZE(adcmap_btm_threshold),
502 bat_voltage,
503 &adc_chan_result->physical);
504}
505EXPORT_SYMBOL_GPL(qpnp_adc_scale_batt_therm);
506
507int32_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
580int32_t qpnp_vadc_check_result(int32_t *data)
581{
582 if (*data < QPNP_VADC_MIN_ADC_CODE)
583 *data = QPNP_VADC_MIN_ADC_CODE;
584 else if (*data > QPNP_VADC_MAX_ADC_CODE)
585 *data = QPNP_VADC_MAX_ADC_CODE;
586
587 return 0;
588}
589EXPORT_SYMBOL_GPL(qpnp_vadc_check_result);
590
591int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
592 struct qpnp_adc_drv *adc_qpnp)
593{
594 struct device_node *node = spmi->dev.of_node;
595 struct resource *res;
596 struct device_node *child;
597 struct qpnp_vadc_amux *adc_channel_list;
598 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700599 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700600 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700601
602 if (!node)
603 return -EINVAL;
604
605 for_each_child_of_node(node, child)
606 count_adc_channel_list++;
607
608 if (!count_adc_channel_list) {
609 pr_err("No channel listing\n");
610 return -EINVAL;
611 }
612
613 adc_qpnp->spmi = spmi;
614
615 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
616 GFP_KERNEL);
617 if (!adc_prop) {
618 dev_err(&spmi->dev, "Unable to allocate memory\n");
619 return -ENOMEM;
620 }
621 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700622 sizeof(struct qpnp_vadc_amux) * count_adc_channel_list,
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700623 GFP_KERNEL);
624 if (!adc_channel_list) {
625 dev_err(&spmi->dev, "Unable to allocate memory\n");
626 return -ENOMEM;
627 }
628
629 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700630 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700631 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
632 if (!amux_prop) {
633 dev_err(&spmi->dev, "Unable to allocate memory\n");
634 return -ENOMEM;
635 }
636
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700637 adc_qpnp->adc_channels = adc_channel_list;
638 adc_qpnp->amux_prop = amux_prop;
639
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700640 for_each_child_of_node(node, child) {
641 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700642 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700643 const char *calibration_param, *channel_name;
644
645 channel_name = of_get_property(child,
646 "label", NULL) ? : child->name;
647 if (!channel_name) {
648 pr_err("Invalid channel name\n");
649 return -EINVAL;
650 }
651
652 rc = of_property_read_u32(child, "qcom,channel-num",
653 &channel_num);
654 if (rc) {
655 pr_err("Invalid channel num\n");
656 return -EINVAL;
657 }
658 rc = of_property_read_u32(child, "qcom,decimation",
659 &decimation);
660 if (rc) {
661 pr_err("Invalid channel decimation property\n");
662 return -EINVAL;
663 }
664 rc = of_property_read_u32(child,
665 "qcom,pre-div-channel-scaling", &scaling);
666 if (rc) {
667 pr_err("Invalid channel scaling property\n");
668 return -EINVAL;
669 }
670 rc = of_property_read_u32(child,
671 "qcom,scale-function", &post_scaling);
672 if (rc) {
673 pr_err("Invalid channel post scaling property\n");
674 return -EINVAL;
675 }
676 rc = of_property_read_u32(child,
677 "qcom,hw-settle-time", &hw_settle_time);
678 if (rc) {
679 pr_err("Invalid channel hw settle time property\n");
680 return -EINVAL;
681 }
682 rc = of_property_read_u32(child,
683 "qcom,fast-avg-setup", &fast_avg_setup);
684 if (rc) {
685 pr_err("Invalid channel fast average setup\n");
686 return -EINVAL;
687 }
688 calibration_param = of_get_property(child,
689 "qcom,calibration-type", NULL);
690 if (!strncmp(calibration_param, "absolute", 8))
691 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700692 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700693 calib_type = CALIB_RATIOMETRIC;
694 else {
695 pr_err("%s: Invalid calibration property\n", __func__);
696 return -EINVAL;
697 }
698 /* Individual channel properties */
699 adc_channel_list[i].name = (char *)channel_name;
700 adc_channel_list[i].channel_num = channel_num;
701 adc_channel_list[i].chan_path_prescaling = scaling;
702 adc_channel_list[i].adc_decimation = decimation;
703 adc_channel_list[i].adc_scale_fn = post_scaling;
704 adc_channel_list[i].hw_settle_time = hw_settle_time;
705 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
706 i++;
707 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700708
709 /* Get the ADC VDD reference voltage and ADC bit resolution */
710 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
711 &adc_prop->adc_vdd_reference);
712 if (rc) {
713 pr_err("Invalid adc vdd reference property\n");
714 return -EINVAL;
715 }
716 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
717 &adc_prop->bitresolution);
718 if (rc) {
719 pr_err("Invalid adc bit resolution property\n");
720 return -EINVAL;
721 }
722 adc_qpnp->adc_prop = adc_prop;
723
724 /* Get the peripheral address */
725 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
726 if (!res) {
727 pr_err("No base address definition\n");
728 return -EINVAL;
729 }
730
731 adc_qpnp->slave = spmi->sid;
732 adc_qpnp->offset = res->start;
733
734 /* Register the ADC peripheral interrupt */
735 adc_qpnp->adc_irq = spmi_get_irq(spmi, 0, 0);
736 if (adc_qpnp->adc_irq < 0) {
737 pr_err("Invalid irq\n");
738 return -ENXIO;
739 }
740
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700741 init_completion(&adc_qpnp->adc_rslt_completion);
742
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700743 mutex_init(&adc_qpnp->adc_lock);
744
745 return 0;
746}
747EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);