blob: b3b5643803efd9b472da5b45eb49df3a14f095d3 [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;
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700640 int rc = 0;
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700641 int64_t low_thr = 0, high_thr = 0;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800642
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700643 rc = qpnp_get_vadc_gain_and_offset(&vbatt_param, CALIB_ABSOLUTE);
644 if (rc < 0)
645 return rc;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800646
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700647 low_thr = (((param->low_thr/3) - QPNP_ADC_625_UV) *
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700648 vbatt_param.dy);
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700649 do_div(low_thr, QPNP_ADC_625_UV);
650 *low_threshold = low_thr + vbatt_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800651
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700652 high_thr = (((param->high_thr/3) - QPNP_ADC_625_UV) *
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700653 vbatt_param.dy);
Siddartha Mohanadoss91a1cd62013-04-19 19:34:36 -0700654 do_div(high_thr, QPNP_ADC_625_UV);
655 *high_threshold = high_thr + vbatt_param.adc_gnd;
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800656
657 pr_debug("high_volt:%d, low_volt:%d\n", param->high_thr,
658 param->low_thr);
Siddartha Mohanadossc4140482013-03-28 18:44:54 -0700659 pr_debug("adc_code_high:%x, adc_code_low:%x\n", *high_threshold,
660 *low_threshold);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800661 return 0;
662}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700663EXPORT_SYMBOL(qpnp_adc_vbatt_rscaler);
Siddartha Mohanadossa3e35512013-02-22 17:06:07 -0800664
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800665int32_t qpnp_adc_btm_scaler(struct qpnp_adc_tm_btm_param *param,
666 uint32_t *low_threshold, uint32_t *high_threshold)
667{
668 struct qpnp_vadc_linear_graph btm_param;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700669 int64_t low_output = 0, high_output = 0;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800670 int rc = 0;
671
672 qpnp_get_vadc_gain_and_offset(&btm_param, CALIB_RATIOMETRIC);
673
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700674 pr_debug("warm_temp:%d and cool_temp:%d\n", param->high_temp,
675 param->low_temp);
676 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800677 adcmap_btm_threshold,
678 ARRAY_SIZE(adcmap_btm_threshold),
679 (param->low_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700680 &low_output);
681 if (rc) {
682 pr_debug("low_temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800683 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700684 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800685
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700686 pr_debug("low_output:%lld\n", low_output);
687 low_output *= btm_param.dy;
688 do_div(low_output, btm_param.adc_vref);
689 low_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800690
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700691 rc = qpnp_adc_map_voltage_temp(
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800692 adcmap_btm_threshold,
693 ARRAY_SIZE(adcmap_btm_threshold),
694 (param->high_temp),
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700695 &high_output);
696 if (rc) {
697 pr_debug("high temp mapping failed with %d\n", rc);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800698 return rc;
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700699 }
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800700
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700701 pr_debug("high_output:%lld\n", high_output);
702 high_output *= btm_param.dy;
703 do_div(high_output, btm_param.adc_vref);
704 high_output += btm_param.adc_gnd;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800705
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700706 /* btm low temperature correspondes to high voltage threshold */
707 *low_threshold = high_output;
708 /* btm high temperature correspondes to low voltage threshold */
709 *high_threshold = low_output;
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800710
Siddartha Mohanadossb8109da2013-03-25 09:53:43 -0700711 pr_debug("high_volt:%d, low_volt:%d\n", *high_threshold,
712 *low_threshold);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800713 return 0;
714}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700715EXPORT_SYMBOL(qpnp_adc_btm_scaler);
Siddartha Mohanadossd0f4fd12012-11-20 16:28:40 -0800716
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700717int32_t qpnp_vadc_check_result(int32_t *data)
718{
719 if (*data < QPNP_VADC_MIN_ADC_CODE)
720 *data = QPNP_VADC_MIN_ADC_CODE;
721 else if (*data > QPNP_VADC_MAX_ADC_CODE)
722 *data = QPNP_VADC_MAX_ADC_CODE;
723
724 return 0;
725}
Siddartha Mohanadoss271d00f2013-03-26 18:24:14 -0700726EXPORT_SYMBOL(qpnp_vadc_check_result);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700727
728int32_t qpnp_adc_get_devicetree_data(struct spmi_device *spmi,
729 struct qpnp_adc_drv *adc_qpnp)
730{
731 struct device_node *node = spmi->dev.of_node;
732 struct resource *res;
733 struct device_node *child;
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800734 struct qpnp_adc_amux *adc_channel_list;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700735 struct qpnp_adc_properties *adc_prop;
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700736 struct qpnp_adc_amux_properties *amux_prop;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700737 int count_adc_channel_list = 0, decimation, rc = 0, i = 0;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700738
739 if (!node)
740 return -EINVAL;
741
742 for_each_child_of_node(node, child)
743 count_adc_channel_list++;
744
745 if (!count_adc_channel_list) {
746 pr_err("No channel listing\n");
747 return -EINVAL;
748 }
749
750 adc_qpnp->spmi = spmi;
751
752 adc_prop = devm_kzalloc(&spmi->dev, sizeof(struct qpnp_adc_properties),
753 GFP_KERNEL);
754 if (!adc_prop) {
755 dev_err(&spmi->dev, "Unable to allocate memory\n");
756 return -ENOMEM;
757 }
758 adc_channel_list = devm_kzalloc(&spmi->dev,
Siddartha Mohanadoss31f60962012-11-27 14:11:02 -0800759 ((sizeof(struct qpnp_adc_amux)) * count_adc_channel_list),
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700760 GFP_KERNEL);
761 if (!adc_channel_list) {
762 dev_err(&spmi->dev, "Unable to allocate memory\n");
763 return -ENOMEM;
764 }
765
766 amux_prop = devm_kzalloc(&spmi->dev,
Siddartha Mohanadossc4a6af12012-07-13 18:50:12 -0700767 sizeof(struct qpnp_adc_amux_properties) +
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700768 sizeof(struct qpnp_vadc_chan_properties), GFP_KERNEL);
769 if (!amux_prop) {
770 dev_err(&spmi->dev, "Unable to allocate memory\n");
771 return -ENOMEM;
772 }
773
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700774 adc_qpnp->adc_channels = adc_channel_list;
775 adc_qpnp->amux_prop = amux_prop;
776
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700777 for_each_child_of_node(node, child) {
778 int channel_num, scaling, post_scaling, hw_settle_time;
Siddartha Mohanadossae1da732012-08-08 16:39:02 -0700779 int fast_avg_setup, calib_type, rc;
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700780 const char *calibration_param, *channel_name;
781
782 channel_name = of_get_property(child,
783 "label", NULL) ? : child->name;
784 if (!channel_name) {
785 pr_err("Invalid channel name\n");
786 return -EINVAL;
787 }
788
Siddartha Mohanadoss96be0a02012-12-07 14:38:48 -0800789 rc = of_property_read_u32(child, "reg", &channel_num);
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700790 if (rc) {
791 pr_err("Invalid channel num\n");
792 return -EINVAL;
793 }
794 rc = of_property_read_u32(child, "qcom,decimation",
795 &decimation);
796 if (rc) {
797 pr_err("Invalid channel decimation property\n");
798 return -EINVAL;
799 }
800 rc = of_property_read_u32(child,
801 "qcom,pre-div-channel-scaling", &scaling);
802 if (rc) {
803 pr_err("Invalid channel scaling property\n");
804 return -EINVAL;
805 }
806 rc = of_property_read_u32(child,
807 "qcom,scale-function", &post_scaling);
808 if (rc) {
809 pr_err("Invalid channel post scaling property\n");
810 return -EINVAL;
811 }
812 rc = of_property_read_u32(child,
813 "qcom,hw-settle-time", &hw_settle_time);
814 if (rc) {
815 pr_err("Invalid channel hw settle time property\n");
816 return -EINVAL;
817 }
818 rc = of_property_read_u32(child,
819 "qcom,fast-avg-setup", &fast_avg_setup);
820 if (rc) {
821 pr_err("Invalid channel fast average setup\n");
822 return -EINVAL;
823 }
824 calibration_param = of_get_property(child,
825 "qcom,calibration-type", NULL);
826 if (!strncmp(calibration_param, "absolute", 8))
827 calib_type = CALIB_ABSOLUTE;
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700828 else if (!strncmp(calibration_param, "ratiometric", 11))
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700829 calib_type = CALIB_RATIOMETRIC;
830 else {
831 pr_err("%s: Invalid calibration property\n", __func__);
832 return -EINVAL;
833 }
834 /* Individual channel properties */
835 adc_channel_list[i].name = (char *)channel_name;
836 adc_channel_list[i].channel_num = channel_num;
837 adc_channel_list[i].chan_path_prescaling = scaling;
838 adc_channel_list[i].adc_decimation = decimation;
839 adc_channel_list[i].adc_scale_fn = post_scaling;
840 adc_channel_list[i].hw_settle_time = hw_settle_time;
841 adc_channel_list[i].fast_avg_setup = fast_avg_setup;
842 i++;
843 }
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700844
845 /* Get the ADC VDD reference voltage and ADC bit resolution */
846 rc = of_property_read_u32(node, "qcom,adc-vdd-reference",
847 &adc_prop->adc_vdd_reference);
848 if (rc) {
849 pr_err("Invalid adc vdd reference property\n");
850 return -EINVAL;
851 }
852 rc = of_property_read_u32(node, "qcom,adc-bit-resolution",
853 &adc_prop->bitresolution);
854 if (rc) {
855 pr_err("Invalid adc bit resolution property\n");
856 return -EINVAL;
857 }
858 adc_qpnp->adc_prop = adc_prop;
859
860 /* Get the peripheral address */
861 res = spmi_get_resource(spmi, 0, IORESOURCE_MEM, 0);
862 if (!res) {
863 pr_err("No base address definition\n");
864 return -EINVAL;
865 }
866
867 adc_qpnp->slave = spmi->sid;
868 adc_qpnp->offset = res->start;
869
870 /* Register the ADC peripheral interrupt */
Siddartha Mohanadoss12109952012-11-20 14:57:51 -0800871 adc_qpnp->adc_irq_eoc = spmi_get_irq_byname(spmi, NULL,
872 "eoc-int-en-set");
873 if (adc_qpnp->adc_irq_eoc < 0) {
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700874 pr_err("Invalid irq\n");
875 return -ENXIO;
876 }
877
Siddartha Mohanadoss5ace1102012-08-20 23:18:10 -0700878 init_completion(&adc_qpnp->adc_rslt_completion);
879
Siddartha Mohanadoss7b116e12012-06-05 23:27:46 -0700880 mutex_init(&adc_qpnp->adc_lock);
881
882 return 0;
883}
884EXPORT_SYMBOL(qpnp_adc_get_devicetree_data);