1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/kernel.h>
4 #include <linux/bitops.h>
5 #include <linux/math64.h>
6 #include <linux/log2.h>
8 #include <linux/module.h>
10 #include "qcom-vadc-common.h"
12 /* Voltage to temperature */
13 static const struct vadc_map_pt adcmap_100k_104ef_104fb
[] = {
51 * Voltage to temperature table for 100k pull up for NTCG104EF104 with
54 static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref
[] = {
91 static int qcom_vadc_scale_hw_calib_volt(
92 const struct vadc_prescale_ratio
*prescale
,
93 const struct adc5_data
*data
,
94 u16 adc_code
, int *result_uv
);
95 static int qcom_vadc_scale_hw_calib_therm(
96 const struct vadc_prescale_ratio
*prescale
,
97 const struct adc5_data
*data
,
98 u16 adc_code
, int *result_mdec
);
99 static int qcom_vadc_scale_hw_smb_temp(
100 const struct vadc_prescale_ratio
*prescale
,
101 const struct adc5_data
*data
,
102 u16 adc_code
, int *result_mdec
);
103 static int qcom_vadc_scale_hw_chg5_temp(
104 const struct vadc_prescale_ratio
*prescale
,
105 const struct adc5_data
*data
,
106 u16 adc_code
, int *result_mdec
);
107 static int qcom_vadc_scale_hw_calib_die_temp(
108 const struct vadc_prescale_ratio
*prescale
,
109 const struct adc5_data
*data
,
110 u16 adc_code
, int *result_mdec
);
112 static struct qcom_adc5_scale_type scale_adc5_fn
[] = {
113 [SCALE_HW_CALIB_DEFAULT
] = {qcom_vadc_scale_hw_calib_volt
},
114 [SCALE_HW_CALIB_THERM_100K_PULLUP
] = {qcom_vadc_scale_hw_calib_therm
},
115 [SCALE_HW_CALIB_XOTHERM
] = {qcom_vadc_scale_hw_calib_therm
},
116 [SCALE_HW_CALIB_PMIC_THERM
] = {qcom_vadc_scale_hw_calib_die_temp
},
117 [SCALE_HW_CALIB_PM5_CHG_TEMP
] = {qcom_vadc_scale_hw_chg5_temp
},
118 [SCALE_HW_CALIB_PM5_SMB_TEMP
] = {qcom_vadc_scale_hw_smb_temp
},
121 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt
*pts
,
122 u32 tablesize
, s32 input
, int *output
)
130 /* Check if table is descending or ascending */
132 if (pts
[0].x
< pts
[1].x
)
136 while (i
< tablesize
) {
137 if ((descending
) && (pts
[i
].x
< input
)) {
138 /* table entry is less than measured*/
139 /* value and table is descending, stop */
141 } else if ((!descending
) &&
142 (pts
[i
].x
> input
)) {
143 /* table entry is greater than measured*/
144 /*value and table is ascending, stop */
152 } else if (i
== tablesize
) {
153 *output
= pts
[tablesize
- 1].y
;
155 /* result is between search_index and search_index-1 */
156 /* interpolate linearly */
157 *output
= (((s32
)((pts
[i
].y
- pts
[i
- 1].y
) *
158 (input
- pts
[i
- 1].x
)) /
159 (pts
[i
].x
- pts
[i
- 1].x
)) +
166 static void qcom_vadc_scale_calib(const struct vadc_linear_graph
*calib_graph
,
171 *scale_voltage
= (adc_code
- calib_graph
->gnd
);
172 *scale_voltage
*= calib_graph
->dx
;
173 *scale_voltage
= div64_s64(*scale_voltage
, calib_graph
->dy
);
175 *scale_voltage
+= calib_graph
->dx
;
177 if (*scale_voltage
< 0)
181 static int qcom_vadc_scale_volt(const struct vadc_linear_graph
*calib_graph
,
182 const struct vadc_prescale_ratio
*prescale
,
183 bool absolute
, u16 adc_code
,
186 s64 voltage
= 0, result
= 0;
188 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
190 voltage
= voltage
* prescale
->den
;
191 result
= div64_s64(voltage
, prescale
->num
);
197 static int qcom_vadc_scale_therm(const struct vadc_linear_graph
*calib_graph
,
198 const struct vadc_prescale_ratio
*prescale
,
199 bool absolute
, u16 adc_code
,
205 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
208 voltage
= div64_s64(voltage
, 1000);
210 ret
= qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb
,
211 ARRAY_SIZE(adcmap_100k_104ef_104fb
),
212 voltage
, result_mdec
);
216 *result_mdec
*= 1000;
221 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph
*calib_graph
,
222 const struct vadc_prescale_ratio
*prescale
,
224 u16 adc_code
, int *result_mdec
)
227 u64 temp
; /* Temporary variable for do_div */
229 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
232 temp
= voltage
* prescale
->den
;
233 do_div(temp
, prescale
->num
* 2);
239 voltage
-= KELVINMIL_CELSIUSMIL
;
240 *result_mdec
= voltage
;
245 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph
*calib_graph
,
246 const struct vadc_prescale_ratio
*prescale
,
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
;
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
,
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
)
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
);
284 voltage
*= prescale
->den
;
285 temp
= prescale
->num
* factor
;
286 voltage
= div64_s64(voltage
, temp
);
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
,
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
)
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
,
328 *result_mdec
-= KELVINMIL_CELSIUSMIL
;
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
;
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
,
352 *result_mdec
= PMIC5_CHG_TEMP_SCALE_FACTOR
- *result_mdec
;
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
,
361 u16 adc_code
, int *result
)
365 return qcom_vadc_scale_volt(calib_graph
, prescale
,
368 case SCALE_THERM_100K_PULLUP
:
370 return qcom_vadc_scale_therm(calib_graph
, prescale
,
373 case SCALE_PMIC_THERM
:
374 return qcom_vadc_scale_die_temp(calib_graph
, prescale
,
377 case SCALE_PMI_CHG_TEMP
:
378 return qcom_vadc_scale_chg_temp(calib_graph
, prescale
,
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
);
398 return scale_adc5_fn
[scaletype
].scale_fn(prescale
, data
,
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
)
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");