blob: b52df4488152a7d3d7b2f23cd278fd520382b97b [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
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700215 if (pts == NULL)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700216 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
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700261 if (pts == NULL)
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700262 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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700368EXPORT_SYMBOL(qpnp_adc_scale_pmic_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700369
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;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700375 int64_t low_output = 0, high_output = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800376 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 */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700385 low_output = (param->low_temp + KELVINMIL_DEGMIL) * 2;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800386 /* Convert to voltage threshold */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700387 low_output *= btm_param.dy;
388 do_div(low_output, btm_param.adc_vref);
389 low_output += btm_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800390
391 /* Convert to Kelvin and account for voltage to be written as 2mV/K */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700392 high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800393 /* Convert to voltage threshold */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700394 high_output *= btm_param.dy;
395 do_div(high_output, btm_param.adc_vref);
396 high_output += btm_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800397
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700398 *low_threshold = low_output;
399 *high_threshold = high_output;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800400
401 return 0;
402}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700403EXPORT_SYMBOL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800404
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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700429EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700430
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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700447EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700448
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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700465EXPORT_SYMBOL(qpnp_adc_scale_therm_pu1);
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700466
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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700483EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2);
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700484
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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700509EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800510
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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700540EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800541
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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700556EXPORT_SYMBOL(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}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700613EXPORT_SYMBOL(qpnp_adc_scale_default);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700614
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800615int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800616 uint32_t *low_threshold, uint32_t *high_threshold)
617{
618 struct qpnp_vadc_linear_graph usb_param;
619
Siddartha Mohanadossa9525b62013-01-29 20:06:33 -0800620 qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_RATIOMETRIC);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800621
622 *low_threshold = param->low_thr * usb_param.dy;
623 do_div(*low_threshold, usb_param.adc_vref);
624 *low_threshold += usb_param.adc_gnd;
625
626 *high_threshold = param->high_thr * usb_param.dy;
627 do_div(*high_threshold, usb_param.adc_vref);
628 *high_threshold += usb_param.adc_gnd;
629
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800630 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
631 param->low_thr);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800632 return 0;
633}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700634EXPORT_SYMBOL(qpnp_adc_usb_scaler);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800635
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800636int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
637 uint32_t *low_threshold, uint32_t *high_threshold)
638{
639 struct qpnp_vadc_linear_graph vbatt_param;
640
641 qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
642
643 *low_threshold = param->low_thr * vbatt_param.dy;
644 do_div(*low_threshold, vbatt_param.adc_vref);
645 *low_threshold += vbatt_param.adc_gnd;
646
647 *high_threshold = param->high_thr * vbatt_param.dy;
648 do_div(*high_threshold, vbatt_param.adc_vref);
649 *high_threshold += vbatt_param.adc_gnd;
650
651 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
652 param->low_thr);
653 return 0;
654}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700655EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800656
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800657int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
658 uint32_t *low_threshold, uint32_t *high_threshold)
659{
660 struct qpnp_vadc_linear_graph btm_param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700661 int64_t low_output = 0, high_output = 0;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800662 int rc = 0;
663
664 qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
665
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700666 pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
667 param->low_temp);
668 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800669 adcmap_btm_threshold,
670 ARRAY_SIZE(adcmap_btm_threshold),
671 (param->low_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700672 &low_output);
673 if (rc) {
674 pr_debug("low_temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800675 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700676 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800677
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700678 pr_debug("low_output:%lld\n", low_output);
679 low_output *= btm_param.dy;
680 do_div(low_output, btm_param.adc_vref);
681 low_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800682
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700683 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800684 adcmap_btm_threshold,
685 ARRAY_SIZE(adcmap_btm_threshold),
686 (param->high_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700687 &high_output);
688 if (rc) {
689 pr_debug("high temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800690 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700691 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800692
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700693 pr_debug("high_output:%lld\n", high_output);
694 high_output *= btm_param.dy;
695 do_div(high_output, btm_param.adc_vref);
696 high_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800697
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700698 /* btm low temperature correspondes to high voltage threshold */
699 *low_threshold = high_output;
700 /* btm high temperature correspondes to low voltage threshold */
701 *high_threshold = low_output;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800702
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700703 pr_debug("high_volt:%d, low_volt:%d\n", *high_threshold,
704 *low_threshold);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800705 return 0;
706}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700707EXPORT_SYMBOL(qpnp_adc_btm_scaler);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800708
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700709int32_t qpnp_vadc_check_result(int32_t *data)
710{
711 if (*data < QPNP_VADC_MIN_ADC_CODE)
712 *data = QPNP_VADC_MIN_ADC_CODE;
713 else if (*data > QPNP_VADC_MAX_ADC_CODE)
714 *data = QPNP_VADC_MAX_ADC_CODE;
715
716 return 0;
717}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700718EXPORT_SYMBOL(qpnp_vadc_check_result);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700719
720int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
721 struct qpnp_adc_drv *adc_qpnp)
722{
723 struct device_node *node = spmi->dev.of_node;
724 struct resource *res;
725 struct device_node *child;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800726 struct qpnp_adc_amux *adc_channel_list;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700727 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700728 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700729 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700730
731 if (!node)
732 return -EINVAL;
733
734 for_each_child_of_node(node, child)
735 count_adc_channel_list++;
736
737 if (!count_adc_channel_list) {
738 pr_err("No channel listing\n");
739 return -EINVAL;
740 }
741
742 adc_qpnp->spmi = spmi;
743
744 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
745 GFP_KERNEL);
746 if (!adc_prop) {
747 dev_err(&spmi->dev, "Unable to allocate memory\n");
748 return -ENOMEM;
749 }
750 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800751 ((sizeof(struct qpnp_adc_amux)) * count_adc_channel_list),
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700752 GFP_KERNEL);
753 if (!adc_channel_list) {
754 dev_err(&spmi->dev, "Unable to allocate memory\n");
755 return -ENOMEM;
756 }
757
758 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700759 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700760 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
761 if (!amux_prop) {
762 dev_err(&spmi->dev, "Unable to allocate memory\n");
763 return -ENOMEM;
764 }
765
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700766 adc_qpnp->adc_channels = adc_channel_list;
767 adc_qpnp->amux_prop = amux_prop;
768
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700769 for_each_child_of_node(node, child) {
770 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700771 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700772 const char *calibration_param, *channel_name;
773
774 channel_name = of_get_property(child,
775 "label", NULL) ? : child->name;
776 if (!channel_name) {
777 pr_err("Invalid channel name\n");
778 return -EINVAL;
779 }
780
Siddartha Mohanadoss96be0a02012-12-07 14:38:48 -0800781 rc = of_property_read_u32(child, "reg", &channel_num);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700782 if (rc) {
783 pr_err("Invalid channel num\n");
784 return -EINVAL;
785 }
786 rc = of_property_read_u32(child, "qcom,decimation",
787 &decimation);
788 if (rc) {
789 pr_err("Invalid channel decimation property\n");
790 return -EINVAL;
791 }
792 rc = of_property_read_u32(child,
793 "qcom,pre-div-channel-scaling", &scaling);
794 if (rc) {
795 pr_err("Invalid channel scaling property\n");
796 return -EINVAL;
797 }
798 rc = of_property_read_u32(child,
799 "qcom,scale-function", &post_scaling);
800 if (rc) {
801 pr_err("Invalid channel post scaling property\n");
802 return -EINVAL;
803 }
804 rc = of_property_read_u32(child,
805 "qcom,hw-settle-time", &hw_settle_time);
806 if (rc) {
807 pr_err("Invalid channel hw settle time property\n");
808 return -EINVAL;
809 }
810 rc = of_property_read_u32(child,
811 "qcom,fast-avg-setup", &fast_avg_setup);
812 if (rc) {
813 pr_err("Invalid channel fast average setup\n");
814 return -EINVAL;
815 }
816 calibration_param = of_get_property(child,
817 "qcom,calibration-type", NULL);
818 if (!strncmp(calibration_param, "absolute", 8))
819 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700820 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700821 calib_type = CALIB_RATIOMETRIC;
822 else {
823 pr_err("%s: Invalid calibration property\n", __func__);
824 return -EINVAL;
825 }
826 /* Individual channel properties */
827 adc_channel_list[i].name = (char *)channel_name;
828 adc_channel_list[i].channel_num = channel_num;
829 adc_channel_list[i].chan_path_prescaling = scaling;
830 adc_channel_list[i].adc_decimation = decimation;
831 adc_channel_list[i].adc_scale_fn = post_scaling;
832 adc_channel_list[i].hw_settle_time = hw_settle_time;
833 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
834 i++;
835 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700836
837 /* Get the ADC VDD reference voltage and ADC bit resolution */
838 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
839 &adc_prop->adc_vdd_reference);
840 if (rc) {
841 pr_err("Invalid adc vdd reference property\n");
842 return -EINVAL;
843 }
844 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
845 &adc_prop->bitresolution);
846 if (rc) {
847 pr_err("Invalid adc bit resolution property\n");
848 return -EINVAL;
849 }
850 adc_qpnp->adc_prop = adc_prop;
851
852 /* Get the peripheral address */
853 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
854 if (!res) {
855 pr_err("No base address definition\n");
856 return -EINVAL;
857 }
858
859 adc_qpnp->slave = spmi->sid;
860 adc_qpnp->offset = res->start;
861
862 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800863 adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
864 "eoc-int-en-set");
865 if (adc_qpnp->adc_irq_eoc < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700866 pr_err("Invalid irq\n");
867 return -ENXIO;
868 }
869
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700870 init_completion(&adc_qpnp->adc_rslt_completion);
871
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700872 mutex_init(&adc_qpnp->adc_lock);
873
874 return 0;
875}
876EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);