treewide: remove redundant IS_ERR() before error code check
[linux/fpc-iii.git] / drivers / iio / adc / qcom-vadc-common.c
blob2bb78d1c4daa63b8d52fd5697d701de1771f2296
1 // SPDX-License-Identifier: GPL-2.0
2 #include <linux/bug.h>
3 #include <linux/kernel.h>
4 #include <linux/bitops.h>
5 #include <linux/math64.h>
6 #include <linux/log2.h>
7 #include <linux/err.h>
8 #include <linux/module.h>
9 #include <linux/units.h>
11 #include "qcom-vadc-common.h"
13 /* Voltage to temperature */
14 static const struct vadc_map_pt adcmap_100k_104ef_104fb[] = {
15 {1758, -40},
16 {1742, -35},
17 {1719, -30},
18 {1691, -25},
19 {1654, -20},
20 {1608, -15},
21 {1551, -10},
22 {1483, -5},
23 {1404, 0},
24 {1315, 5},
25 {1218, 10},
26 {1114, 15},
27 {1007, 20},
28 {900, 25},
29 {795, 30},
30 {696, 35},
31 {605, 40},
32 {522, 45},
33 {448, 50},
34 {383, 55},
35 {327, 60},
36 {278, 65},
37 {237, 70},
38 {202, 75},
39 {172, 80},
40 {146, 85},
41 {125, 90},
42 {107, 95},
43 {92, 100},
44 {79, 105},
45 {68, 110},
46 {59, 115},
47 {51, 120},
48 {44, 125}
52 * Voltage to temperature table for 100k pull up for NTCG104EF104 with
53 * 1.875V reference.
55 static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
56 { 1831, -40000 },
57 { 1814, -35000 },
58 { 1791, -30000 },
59 { 1761, -25000 },
60 { 1723, -20000 },
61 { 1675, -15000 },
62 { 1616, -10000 },
63 { 1545, -5000 },
64 { 1463, 0 },
65 { 1370, 5000 },
66 { 1268, 10000 },
67 { 1160, 15000 },
68 { 1049, 20000 },
69 { 937, 25000 },
70 { 828, 30000 },
71 { 726, 35000 },
72 { 630, 40000 },
73 { 544, 45000 },
74 { 467, 50000 },
75 { 399, 55000 },
76 { 340, 60000 },
77 { 290, 65000 },
78 { 247, 70000 },
79 { 209, 75000 },
80 { 179, 80000 },
81 { 153, 85000 },
82 { 130, 90000 },
83 { 112, 95000 },
84 { 96, 100000 },
85 { 82, 105000 },
86 { 71, 110000 },
87 { 62, 115000 },
88 { 53, 120000 },
89 { 46, 125000 },
92 static int qcom_vadc_scale_hw_calib_volt(
93 const struct vadc_prescale_ratio *prescale,
94 const struct adc5_data *data,
95 u16 adc_code, int *result_uv);
96 static int qcom_vadc_scale_hw_calib_therm(
97 const struct vadc_prescale_ratio *prescale,
98 const struct adc5_data *data,
99 u16 adc_code, int *result_mdec);
100 static int qcom_vadc_scale_hw_smb_temp(
101 const struct vadc_prescale_ratio *prescale,
102 const struct adc5_data *data,
103 u16 adc_code, int *result_mdec);
104 static int qcom_vadc_scale_hw_chg5_temp(
105 const struct vadc_prescale_ratio *prescale,
106 const struct adc5_data *data,
107 u16 adc_code, int *result_mdec);
108 static int qcom_vadc_scale_hw_calib_die_temp(
109 const struct vadc_prescale_ratio *prescale,
110 const struct adc5_data *data,
111 u16 adc_code, int *result_mdec);
113 static struct qcom_adc5_scale_type scale_adc5_fn[] = {
114 [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
115 [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
116 [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
117 [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp},
118 [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp},
119 [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp},
122 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
123 u32 tablesize, s32 input, int *output)
125 bool descending = 1;
126 u32 i = 0;
128 if (!pts)
129 return -EINVAL;
131 /* Check if table is descending or ascending */
132 if (tablesize > 1) {
133 if (pts[0].x < pts[1].x)
134 descending = 0;
137 while (i < tablesize) {
138 if ((descending) && (pts[i].x < input)) {
139 /* table entry is less than measured*/
140 /* value and table is descending, stop */
141 break;
142 } else if ((!descending) &&
143 (pts[i].x > input)) {
144 /* table entry is greater than measured*/
145 /*value and table is ascending, stop */
146 break;
148 i++;
151 if (i == 0) {
152 *output = pts[0].y;
153 } else if (i == tablesize) {
154 *output = pts[tablesize - 1].y;
155 } else {
156 /* result is between search_index and search_index-1 */
157 /* interpolate linearly */
158 *output = (((s32)((pts[i].y - pts[i - 1].y) *
159 (input - pts[i - 1].x)) /
160 (pts[i].x - pts[i - 1].x)) +
161 pts[i - 1].y);
164 return 0;
167 static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
168 u16 adc_code,
169 bool absolute,
170 s64 *scale_voltage)
172 *scale_voltage = (adc_code - calib_graph->gnd);
173 *scale_voltage *= calib_graph->dx;
174 *scale_voltage = div64_s64(*scale_voltage, calib_graph->dy);
175 if (absolute)
176 *scale_voltage += calib_graph->dx;
178 if (*scale_voltage < 0)
179 *scale_voltage = 0;
182 static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
183 const struct vadc_prescale_ratio *prescale,
184 bool absolute, u16 adc_code,
185 int *result_uv)
187 s64 voltage = 0, result = 0;
189 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
191 voltage = voltage * prescale->den;
192 result = div64_s64(voltage, prescale->num);
193 *result_uv = result;
195 return 0;
198 static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
199 const struct vadc_prescale_ratio *prescale,
200 bool absolute, u16 adc_code,
201 int *result_mdec)
203 s64 voltage = 0;
204 int ret;
206 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
208 if (absolute)
209 voltage = div64_s64(voltage, 1000);
211 ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
212 ARRAY_SIZE(adcmap_100k_104ef_104fb),
213 voltage, result_mdec);
214 if (ret)
215 return ret;
217 *result_mdec *= 1000;
219 return 0;
222 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
223 const struct vadc_prescale_ratio *prescale,
224 bool absolute,
225 u16 adc_code, int *result_mdec)
227 s64 voltage = 0;
228 u64 temp; /* Temporary variable for do_div */
230 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
232 if (voltage > 0) {
233 temp = voltage * prescale->den;
234 do_div(temp, prescale->num * 2);
235 voltage = temp;
236 } else {
237 voltage = 0;
240 *result_mdec = milli_kelvin_to_millicelsius(voltage);
242 return 0;
245 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
246 const struct vadc_prescale_ratio *prescale,
247 bool absolute,
248 u16 adc_code, int *result_mdec)
250 s64 voltage = 0, result = 0;
252 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
254 voltage = voltage * prescale->den;
255 voltage = div64_s64(voltage, prescale->num);
256 voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
257 voltage = (voltage + PMI_CHG_SCALE_2);
258 result = div64_s64(voltage, 1000000);
259 *result_mdec = result;
261 return 0;
264 static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
265 const struct vadc_prescale_ratio *prescale,
266 const struct adc5_data *data,
267 unsigned int factor)
269 s64 voltage, temp, adc_vdd_ref_mv = 1875;
272 * The normal data range is between 0V to 1.875V. On cases where
273 * we read low voltage values, the ADC code can go beyond the
274 * range and the scale result is incorrect so we clamp the values
275 * for the cases where the code represents a value below 0V
277 if (adc_code > VADC5_MAX_CODE)
278 adc_code = 0;
280 /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
281 voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
282 voltage = div64_s64(voltage, data->full_scale_code_volt);
283 if (voltage > 0) {
284 voltage *= prescale->den;
285 temp = prescale->num * factor;
286 voltage = div64_s64(voltage, temp);
287 } else {
288 voltage = 0;
291 return (int) voltage;
294 static int qcom_vadc_scale_hw_calib_volt(
295 const struct vadc_prescale_ratio *prescale,
296 const struct adc5_data *data,
297 u16 adc_code, int *result_uv)
299 *result_uv = qcom_vadc_scale_code_voltage_factor(adc_code,
300 prescale, data, 1);
302 return 0;
305 static int qcom_vadc_scale_hw_calib_therm(
306 const struct vadc_prescale_ratio *prescale,
307 const struct adc5_data *data,
308 u16 adc_code, int *result_mdec)
310 int voltage;
312 voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
313 prescale, data, 1000);
315 /* Map voltage to temperature from look-up table */
316 return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
317 ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
318 voltage, result_mdec);
321 static int qcom_vadc_scale_hw_calib_die_temp(
322 const struct vadc_prescale_ratio *prescale,
323 const struct adc5_data *data,
324 u16 adc_code, int *result_mdec)
326 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
327 prescale, data, 2);
328 *result_mdec = milli_kelvin_to_millicelsius(*result_mdec);
330 return 0;
333 static int qcom_vadc_scale_hw_smb_temp(
334 const struct vadc_prescale_ratio *prescale,
335 const struct adc5_data *data,
336 u16 adc_code, int *result_mdec)
338 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code * 100,
339 prescale, data, PMIC5_SMB_TEMP_SCALE_FACTOR);
340 *result_mdec = PMIC5_SMB_TEMP_CONSTANT - *result_mdec;
342 return 0;
345 static int qcom_vadc_scale_hw_chg5_temp(
346 const struct vadc_prescale_ratio *prescale,
347 const struct adc5_data *data,
348 u16 adc_code, int *result_mdec)
350 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
351 prescale, data, 4);
352 *result_mdec = PMIC5_CHG_TEMP_SCALE_FACTOR - *result_mdec;
354 return 0;
357 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
358 const struct vadc_linear_graph *calib_graph,
359 const struct vadc_prescale_ratio *prescale,
360 bool absolute,
361 u16 adc_code, int *result)
363 switch (scaletype) {
364 case SCALE_DEFAULT:
365 return qcom_vadc_scale_volt(calib_graph, prescale,
366 absolute, adc_code,
367 result);
368 case SCALE_THERM_100K_PULLUP:
369 case SCALE_XOTHERM:
370 return qcom_vadc_scale_therm(calib_graph, prescale,
371 absolute, adc_code,
372 result);
373 case SCALE_PMIC_THERM:
374 return qcom_vadc_scale_die_temp(calib_graph, prescale,
375 absolute, adc_code,
376 result);
377 case SCALE_PMI_CHG_TEMP:
378 return qcom_vadc_scale_chg_temp(calib_graph, prescale,
379 absolute, adc_code,
380 result);
381 default:
382 return -EINVAL;
385 EXPORT_SYMBOL(qcom_vadc_scale);
387 int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
388 const struct vadc_prescale_ratio *prescale,
389 const struct adc5_data *data,
390 u16 adc_code, int *result)
392 if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
393 scaletype < SCALE_HW_CALIB_INVALID)) {
394 pr_err("Invalid scale type %d\n", scaletype);
395 return -EINVAL;
398 return scale_adc5_fn[scaletype].scale_fn(prescale, data,
399 adc_code, result);
401 EXPORT_SYMBOL(qcom_adc5_hw_scale);
403 int qcom_vadc_decimation_from_dt(u32 value)
405 if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
406 value > VADC_DECIMATION_MAX)
407 return -EINVAL;
409 return __ffs64(value / VADC_DECIMATION_MIN);
411 EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
413 MODULE_LICENSE("GPL v2");
414 MODULE_DESCRIPTION("Qualcomm ADC common functionality");