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
[] = {
50 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt
*pts
,
51 u32 tablesize
, s32 input
, s64
*output
)
59 /* Check if table is descending or ascending */
61 if (pts
[0].x
< pts
[1].x
)
65 while (i
< tablesize
) {
66 if ((descending
) && (pts
[i
].x
< input
)) {
67 /* table entry is less than measured*/
68 /* value and table is descending, stop */
70 } else if ((!descending
) &&
72 /* table entry is greater than measured*/
73 /*value and table is ascending, stop */
81 } else if (i
== tablesize
) {
82 *output
= pts
[tablesize
- 1].y
;
84 /* result is between search_index and search_index-1 */
85 /* interpolate linearly */
86 *output
= (((s32
)((pts
[i
].y
- pts
[i
- 1].y
) *
87 (input
- pts
[i
- 1].x
)) /
88 (pts
[i
].x
- pts
[i
- 1].x
)) +
95 static void qcom_vadc_scale_calib(const struct vadc_linear_graph
*calib_graph
,
100 *scale_voltage
= (adc_code
- calib_graph
->gnd
);
101 *scale_voltage
*= calib_graph
->dx
;
102 *scale_voltage
= div64_s64(*scale_voltage
, calib_graph
->dy
);
104 *scale_voltage
+= calib_graph
->dx
;
106 if (*scale_voltage
< 0)
110 static int qcom_vadc_scale_volt(const struct vadc_linear_graph
*calib_graph
,
111 const struct vadc_prescale_ratio
*prescale
,
112 bool absolute
, u16 adc_code
,
115 s64 voltage
= 0, result
= 0;
117 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
119 voltage
= voltage
* prescale
->den
;
120 result
= div64_s64(voltage
, prescale
->num
);
126 static int qcom_vadc_scale_therm(const struct vadc_linear_graph
*calib_graph
,
127 const struct vadc_prescale_ratio
*prescale
,
128 bool absolute
, u16 adc_code
,
131 s64 voltage
= 0, result
= 0;
134 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
137 voltage
= div64_s64(voltage
, 1000);
139 ret
= qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb
,
140 ARRAY_SIZE(adcmap_100k_104ef_104fb
),
146 *result_mdec
= result
;
151 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph
*calib_graph
,
152 const struct vadc_prescale_ratio
*prescale
,
154 u16 adc_code
, int *result_mdec
)
157 u64 temp
; /* Temporary variable for do_div */
159 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
162 temp
= voltage
* prescale
->den
;
163 do_div(temp
, prescale
->num
* 2);
169 voltage
-= KELVINMIL_CELSIUSMIL
;
170 *result_mdec
= voltage
;
175 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph
*calib_graph
,
176 const struct vadc_prescale_ratio
*prescale
,
178 u16 adc_code
, int *result_mdec
)
180 s64 voltage
= 0, result
= 0;
182 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
184 voltage
= voltage
* prescale
->den
;
185 voltage
= div64_s64(voltage
, prescale
->num
);
186 voltage
= ((PMI_CHG_SCALE_1
) * (voltage
* 2));
187 voltage
= (voltage
+ PMI_CHG_SCALE_2
);
188 result
= div64_s64(voltage
, 1000000);
189 *result_mdec
= result
;
194 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype
,
195 const struct vadc_linear_graph
*calib_graph
,
196 const struct vadc_prescale_ratio
*prescale
,
198 u16 adc_code
, int *result
)
202 return qcom_vadc_scale_volt(calib_graph
, prescale
,
205 case SCALE_THERM_100K_PULLUP
:
207 return qcom_vadc_scale_therm(calib_graph
, prescale
,
210 case SCALE_PMIC_THERM
:
211 return qcom_vadc_scale_die_temp(calib_graph
, prescale
,
214 case SCALE_PMI_CHG_TEMP
:
215 return qcom_vadc_scale_chg_temp(calib_graph
, prescale
,
222 EXPORT_SYMBOL(qcom_vadc_scale
);
224 int qcom_vadc_decimation_from_dt(u32 value
)
226 if (!is_power_of_2(value
) || value
< VADC_DECIMATION_MIN
||
227 value
> VADC_DECIMATION_MAX
)
230 return __ffs64(value
/ VADC_DECIMATION_MIN
);
232 EXPORT_SYMBOL(qcom_vadc_decimation_from_dt
);
234 MODULE_LICENSE("GPL v2");
235 MODULE_DESCRIPTION("Qualcomm ADC common functionality");