blob: db491e20d3d8d66cf2b95918936dddfc8b7fdf25 [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 Mohanadoss71218f22013-04-23 16:24:14 -0700376 int rc = 0, sign = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800377
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 Mohanadoss71218f22013-04-23 16:24:14 -0700387 low_output = (low_output - QPNP_ADC_625_UV) * btm_param.dy;
388 if (low_output < 0) {
389 sign = 1;
390 low_output = -low_output;
391 }
392 do_div(low_output, QPNP_ADC_625_UV);
393 if (sign)
394 low_output = -low_output;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700395 low_output += btm_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800396
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700397 sign = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800398 /* Convert to Kelvin and account for voltage to be written as 2mV/K */
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700399 high_output = (param->high_temp + KELVINMIL_DEGMIL) * 2;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800400 /* Convert to voltage threshold */
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700401 high_output = (high_output - QPNP_ADC_625_UV) * btm_param.dy;
402 if (high_output < 0) {
403 sign = 1;
404 high_output = -high_output;
405 }
406 do_div(high_output, QPNP_ADC_625_UV);
407 if (sign)
408 high_output = -high_output;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700409 high_output += btm_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800410
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700411 *low_threshold = (uint32_t) low_output;
412 *high_threshold = (uint32_t) high_output;
413 pr_debug("high_temp:%d, low_temp:%d\n", param->high_temp,
414 param->low_temp);
415 pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
416 *low_threshold);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800417
418 return 0;
419}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700420EXPORT_SYMBOL(qpnp_adc_scale_millidegc_pmic_voltage_thr);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800421
422/* Scales the ADC code to degC using the mapping
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700423 * table for the XO thermistor.
424 */
425int32_t qpnp_adc_tdkntcg_therm(int32_t adc_code,
426 const struct qpnp_adc_properties *adc_properties,
427 const struct qpnp_vadc_chan_properties *chan_properties,
428 struct qpnp_vadc_result *adc_chan_result)
429{
430 int64_t xo_thm = 0;
431
432 if (!chan_properties || !chan_properties->offset_gain_numerator ||
433 !chan_properties->offset_gain_denominator || !adc_properties
434 || !adc_chan_result)
435 return -EINVAL;
436
437 xo_thm = qpnp_adc_scale_ratiometric_calib(adc_code,
438 adc_properties, chan_properties);
Siddartha Mohanadoss0dc06942012-12-23 17:10:10 -0800439
440 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
441 ARRAY_SIZE(adcmap_100k_104ef_104fb),
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700442 xo_thm, &adc_chan_result->physical);
443
444 return 0;
445}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700446EXPORT_SYMBOL(qpnp_adc_tdkntcg_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700447
448int32_t qpnp_adc_scale_batt_therm(int32_t adc_code,
449 const struct qpnp_adc_properties *adc_properties,
450 const struct qpnp_vadc_chan_properties *chan_properties,
451 struct qpnp_vadc_result *adc_chan_result)
452{
453 int64_t bat_voltage = 0;
454
455 bat_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
456 adc_properties, chan_properties);
457
Siddartha Mohanadoss4a27b1c2012-11-16 09:34:41 -0800458 return qpnp_adc_map_temp_voltage(
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700459 adcmap_btm_threshold,
460 ARRAY_SIZE(adcmap_btm_threshold),
461 bat_voltage,
462 &adc_chan_result->physical);
463}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700464EXPORT_SYMBOL(qpnp_adc_scale_batt_therm);
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700465
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700466int32_t qpnp_adc_scale_therm_pu1(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 therm_voltage = 0;
472
473 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
474 adc_properties, chan_properties);
475
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800476 qpnp_adc_map_voltage_temp(adcmap_150k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700477 ARRAY_SIZE(adcmap_150k_104ef_104fb),
478 therm_voltage, &adc_chan_result->physical);
479
480 return 0;
481}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700482EXPORT_SYMBOL(qpnp_adc_scale_therm_pu1);
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700483
484int32_t qpnp_adc_scale_therm_pu2(int32_t adc_code,
485 const struct qpnp_adc_properties *adc_properties,
486 const struct qpnp_vadc_chan_properties *chan_properties,
487 struct qpnp_vadc_result *adc_chan_result)
488{
489 int64_t therm_voltage = 0;
490
491 therm_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
492 adc_properties, chan_properties);
493
Siddartha Mohanadosse84f8e62012-11-16 09:34:41 -0800494 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700495 ARRAY_SIZE(adcmap_100k_104ef_104fb),
496 therm_voltage, &adc_chan_result->physical);
497
498 return 0;
499}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700500EXPORT_SYMBOL(qpnp_adc_scale_therm_pu2);
Siddartha Mohanadosse77edf12012-09-13 14:26:32 -0700501
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800502int32_t qpnp_adc_tm_scale_voltage_therm_pu2(uint32_t reg, int64_t *result)
503{
504 int64_t adc_voltage = 0;
505 struct qpnp_vadc_linear_graph param1;
506 int negative_offset;
507
508 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
509
510 adc_voltage = (reg - param1.adc_gnd) * param1.adc_vref;
511 if (adc_voltage < 0) {
512 negative_offset = 1;
513 adc_voltage = -adc_voltage;
514 }
515
516 do_div(adc_voltage, param1.dy);
517
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800518 qpnp_adc_map_voltage_temp(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800519 ARRAY_SIZE(adcmap_100k_104ef_104fb),
520 adc_voltage, result);
521 if (negative_offset)
522 adc_voltage = -adc_voltage;
523
524 return 0;
525}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700526EXPORT_SYMBOL(qpnp_adc_tm_scale_voltage_therm_pu2);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800527
528int32_t qpnp_adc_tm_scale_therm_voltage_pu2(struct qpnp_adc_tm_config *param)
529{
530 struct qpnp_vadc_linear_graph param1;
531 int rc;
532
533 qpnp_get_vadc_gain_and_offset(&param1, CALIB_RATIOMETRIC);
534
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800535 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800536 ARRAY_SIZE(adcmap_100k_104ef_104fb),
537 param->low_thr_temp, &param->low_thr_voltage);
538 if (rc)
539 return rc;
540
541 param->low_thr_voltage *= param1.dy;
542 do_div(param->low_thr_voltage, param1.adc_vref);
543 param->low_thr_voltage += param1.adc_gnd;
544
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800545 rc = qpnp_adc_map_temp_voltage(adcmap_100k_104ef_104fb,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800546 ARRAY_SIZE(adcmap_100k_104ef_104fb),
547 param->high_thr_temp, &param->high_thr_voltage);
548 if (rc)
549 return rc;
550
551 param->high_thr_voltage *= param1.dy;
552 do_div(param->high_thr_voltage, param1.adc_vref);
553 param->high_thr_voltage += param1.adc_gnd;
554
555 return 0;
556}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700557EXPORT_SYMBOL(qpnp_adc_tm_scale_therm_voltage_pu2);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800558
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700559int32_t qpnp_adc_scale_batt_id(int32_t adc_code,
560 const struct qpnp_adc_properties *adc_properties,
561 const struct qpnp_vadc_chan_properties *chan_properties,
562 struct qpnp_vadc_result *adc_chan_result)
563{
564 int64_t batt_id_voltage = 0;
565
566 batt_id_voltage = qpnp_adc_scale_ratiometric_calib(adc_code,
567 adc_properties, chan_properties);
568 adc_chan_result->physical = batt_id_voltage;
569 adc_chan_result->physical = adc_chan_result->measurement;
570
571 return 0;
572}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700573EXPORT_SYMBOL(qpnp_adc_scale_batt_id);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700574
575int32_t qpnp_adc_scale_default(int32_t adc_code,
576 const struct qpnp_adc_properties *adc_properties,
577 const struct qpnp_vadc_chan_properties *chan_properties,
578 struct qpnp_vadc_result *adc_chan_result)
579{
580 bool negative_rawfromoffset = 0, negative_offset = 0;
581 int64_t scale_voltage = 0;
582
583 if (!chan_properties || !chan_properties->offset_gain_numerator ||
584 !chan_properties->offset_gain_denominator || !adc_properties
585 || !adc_chan_result)
586 return -EINVAL;
587
588 scale_voltage = (adc_code -
589 chan_properties->adc_graph[CALIB_ABSOLUTE].adc_gnd)
590 * chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
591 if (scale_voltage < 0) {
592 negative_offset = 1;
593 scale_voltage = -scale_voltage;
594 }
595 do_div(scale_voltage,
596 chan_properties->adc_graph[CALIB_ABSOLUTE].dy);
597 if (negative_offset)
598 scale_voltage = -scale_voltage;
599 scale_voltage += chan_properties->adc_graph[CALIB_ABSOLUTE].dx;
600
601 if (scale_voltage < 0) {
602 if (adc_properties->bipolar) {
603 scale_voltage = -scale_voltage;
604 negative_rawfromoffset = 1;
605 } else {
606 scale_voltage = 0;
607 }
608 }
609
610 adc_chan_result->measurement = scale_voltage *
611 chan_properties->offset_gain_denominator;
612
613 /* do_div only perform positive integer division! */
614 do_div(adc_chan_result->measurement,
615 chan_properties->offset_gain_numerator);
616
617 if (negative_rawfromoffset)
618 adc_chan_result->measurement = -adc_chan_result->measurement;
619
620 /*
621 * Note: adc_chan_result->measurement is in the unit of
622 * adc_properties.adc_reference. For generic channel processing,
623 * channel measurement is a scale/ratio relative to the adc
624 * reference input
625 */
626 adc_chan_result->physical = adc_chan_result->measurement;
627
628 return 0;
629}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700630EXPORT_SYMBOL(qpnp_adc_scale_default);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700631
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800632int32_t qpnp_adc_usb_scaler(struct qpnp_adc_tm_btm_param *param,
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800633 uint32_t *low_threshold, uint32_t *high_threshold)
634{
635 struct qpnp_vadc_linear_graph usb_param;
636
Siddartha Mohanadossa9525b62013-01-29 20:06:33 -0800637 qpnp_get_vadc_gain_and_offset(&usb_param, CALIB_RATIOMETRIC);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800638
639 *low_threshold = param->low_thr * usb_param.dy;
640 do_div(*low_threshold, usb_param.adc_vref);
641 *low_threshold += usb_param.adc_gnd;
642
643 *high_threshold = param->high_thr * usb_param.dy;
644 do_div(*high_threshold, usb_param.adc_vref);
645 *high_threshold += usb_param.adc_gnd;
646
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800647 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
648 param->low_thr);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800649 return 0;
650}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700651EXPORT_SYMBOL(qpnp_adc_usb_scaler);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800652
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800653int32_t qpnp_adc_vbatt_rscaler(struct qpnp_adc_tm_btm_param *param,
654 uint32_t *low_threshold, uint32_t *high_threshold)
655{
656 struct qpnp_vadc_linear_graph vbatt_param;
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700657 int rc = 0, sign = 0;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700658 int64_t low_thr = 0, high_thr = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800659
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700660 rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
661 if (rc < 0)
662 return rc;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800663
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700664 low_thr = (((param->low_thr/3) - QPNP_ADC_625_UV) *
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700665 vbatt_param.dy);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700666 if (low_thr < 0) {
667 sign = 1;
668 low_thr = -low_thr;
669 }
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700670 do_div(low_thr, QPNP_ADC_625_UV);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700671 if (sign)
672 low_thr = -low_thr;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700673 *low_threshold = low_thr + vbatt_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800674
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700675 sign = 0;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700676 high_thr = (((param->high_thr/3) - QPNP_ADC_625_UV) *
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700677 vbatt_param.dy);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700678 if (high_thr < 0) {
679 sign = 1;
680 high_thr = -high_thr;
681 }
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700682 do_div(high_thr, QPNP_ADC_625_UV);
Siddartha Mohanadoss71218f22013-04-23 16:24:14 -0700683 if (sign)
684 high_thr = -high_thr;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700685 *high_threshold = high_thr + vbatt_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800686
687 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
688 param->low_thr);
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700689 pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
690 *low_threshold);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800691 return 0;
692}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700693EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800694
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800695int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
696 uint32_t *low_threshold, uint32_t *high_threshold)
697{
698 struct qpnp_vadc_linear_graph btm_param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700699 int64_t low_output = 0, high_output = 0;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800700 int rc = 0;
701
702 qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
703
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700704 pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
705 param->low_temp);
706 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800707 adcmap_btm_threshold,
708 ARRAY_SIZE(adcmap_btm_threshold),
709 (param->low_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700710 &low_output);
711 if (rc) {
712 pr_debug("low_temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800713 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700714 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800715
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700716 pr_debug("low_output:%lld\n", low_output);
717 low_output *= btm_param.dy;
718 do_div(low_output, btm_param.adc_vref);
719 low_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800720
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700721 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800722 adcmap_btm_threshold,
723 ARRAY_SIZE(adcmap_btm_threshold),
724 (param->high_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700725 &high_output);
726 if (rc) {
727 pr_debug("high temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800728 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700729 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800730
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700731 pr_debug("high_output:%lld\n", high_output);
732 high_output *= btm_param.dy;
733 do_div(high_output, btm_param.adc_vref);
734 high_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800735
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700736 /* btm low temperature correspondes to high voltage threshold */
737 *low_threshold = high_output;
738 /* btm high temperature correspondes to low voltage threshold */
739 *high_threshold = low_output;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800740
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700741 pr_debug("high_volt:%d, low_volt:%d\n", *high_threshold,
742 *low_threshold);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800743 return 0;
744}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700745EXPORT_SYMBOL(qpnp_adc_btm_scaler);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800746
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700747int32_t qpnp_vadc_check_result(int32_t *data)
748{
749 if (*data < QPNP_VADC_MIN_ADC_CODE)
750 *data = QPNP_VADC_MIN_ADC_CODE;
751 else if (*data > QPNP_VADC_MAX_ADC_CODE)
752 *data = QPNP_VADC_MAX_ADC_CODE;
753
754 return 0;
755}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700756EXPORT_SYMBOL(qpnp_vadc_check_result);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700757
758int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
759 struct qpnp_adc_drv *adc_qpnp)
760{
761 struct device_node *node = spmi->dev.of_node;
762 struct resource *res;
763 struct device_node *child;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800764 struct qpnp_adc_amux *adc_channel_list;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700765 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700766 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700767 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700768
769 if (!node)
770 return -EINVAL;
771
772 for_each_child_of_node(node, child)
773 count_adc_channel_list++;
774
775 if (!count_adc_channel_list) {
776 pr_err("No channel listing\n");
777 return -EINVAL;
778 }
779
780 adc_qpnp->spmi = spmi;
781
782 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
783 GFP_KERNEL);
784 if (!adc_prop) {
785 dev_err(&spmi->dev, "Unable to allocate memory\n");
786 return -ENOMEM;
787 }
788 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800789 ((sizeof(struct qpnp_adc_amux)) * count_adc_channel_list),
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700790 GFP_KERNEL);
791 if (!adc_channel_list) {
792 dev_err(&spmi->dev, "Unable to allocate memory\n");
793 return -ENOMEM;
794 }
795
796 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700797 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700798 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
799 if (!amux_prop) {
800 dev_err(&spmi->dev, "Unable to allocate memory\n");
801 return -ENOMEM;
802 }
803
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700804 adc_qpnp->adc_channels = adc_channel_list;
805 adc_qpnp->amux_prop = amux_prop;
806
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700807 for_each_child_of_node(node, child) {
808 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700809 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700810 const char *calibration_param, *channel_name;
811
812 channel_name = of_get_property(child,
813 "label", NULL) ? : child->name;
814 if (!channel_name) {
815 pr_err("Invalid channel name\n");
816 return -EINVAL;
817 }
818
Siddartha Mohanadoss96be0a02012-12-07 14:38:48 -0800819 rc = of_property_read_u32(child, "reg", &channel_num);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700820 if (rc) {
821 pr_err("Invalid channel num\n");
822 return -EINVAL;
823 }
824 rc = of_property_read_u32(child, "qcom,decimation",
825 &decimation);
826 if (rc) {
827 pr_err("Invalid channel decimation property\n");
828 return -EINVAL;
829 }
830 rc = of_property_read_u32(child,
831 "qcom,pre-div-channel-scaling", &scaling);
832 if (rc) {
833 pr_err("Invalid channel scaling property\n");
834 return -EINVAL;
835 }
836 rc = of_property_read_u32(child,
837 "qcom,scale-function", &post_scaling);
838 if (rc) {
839 pr_err("Invalid channel post scaling property\n");
840 return -EINVAL;
841 }
842 rc = of_property_read_u32(child,
843 "qcom,hw-settle-time", &hw_settle_time);
844 if (rc) {
845 pr_err("Invalid channel hw settle time property\n");
846 return -EINVAL;
847 }
848 rc = of_property_read_u32(child,
849 "qcom,fast-avg-setup", &fast_avg_setup);
850 if (rc) {
851 pr_err("Invalid channel fast average setup\n");
852 return -EINVAL;
853 }
854 calibration_param = of_get_property(child,
855 "qcom,calibration-type", NULL);
856 if (!strncmp(calibration_param, "absolute", 8))
857 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700858 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700859 calib_type = CALIB_RATIOMETRIC;
860 else {
861 pr_err("%s: Invalid calibration property\n", __func__);
862 return -EINVAL;
863 }
864 /* Individual channel properties */
865 adc_channel_list[i].name = (char *)channel_name;
866 adc_channel_list[i].channel_num = channel_num;
867 adc_channel_list[i].chan_path_prescaling = scaling;
868 adc_channel_list[i].adc_decimation = decimation;
869 adc_channel_list[i].adc_scale_fn = post_scaling;
870 adc_channel_list[i].hw_settle_time = hw_settle_time;
871 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
872 i++;
873 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700874
875 /* Get the ADC VDD reference voltage and ADC bit resolution */
876 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
877 &adc_prop->adc_vdd_reference);
878 if (rc) {
879 pr_err("Invalid adc vdd reference property\n");
880 return -EINVAL;
881 }
882 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
883 &adc_prop->bitresolution);
884 if (rc) {
885 pr_err("Invalid adc bit resolution property\n");
886 return -EINVAL;
887 }
888 adc_qpnp->adc_prop = adc_prop;
889
890 /* Get the peripheral address */
891 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
892 if (!res) {
893 pr_err("No base address definition\n");
894 return -EINVAL;
895 }
896
897 adc_qpnp->slave = spmi->sid;
898 adc_qpnp->offset = res->start;
899
900 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800901 adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
902 "eoc-int-en-set");
903 if (adc_qpnp->adc_irq_eoc < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700904 pr_err("Invalid irq\n");
905 return -ENXIO;
906 }
907
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700908 init_completion(&adc_qpnp->adc_rslt_completion);
909
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700910 mutex_init(&adc_qpnp->adc_lock);
911
912 return 0;
913}
914EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);