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>
9 #include "qcom-vadc-common.h"
11 /* Voltage to temperature */
12 static const struct vadc_map_pt adcmap_100k_104ef_104fb
[] = {
49 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt
*pts
,
50 u32 tablesize
, s32 input
, s64
*output
)
58 /* Check if table is descending or ascending */
60 if (pts
[0].x
< pts
[1].x
)
64 while (i
< tablesize
) {
65 if ((descending
) && (pts
[i
].x
< input
)) {
66 /* table entry is less than measured*/
67 /* value and table is descending, stop */
69 } else if ((!descending
) &&
71 /* table entry is greater than measured*/
72 /*value and table is ascending, stop */
80 } else if (i
== tablesize
) {
81 *output
= pts
[tablesize
- 1].y
;
83 /* result is between search_index and search_index-1 */
84 /* interpolate linearly */
85 *output
= (((s32
)((pts
[i
].y
- pts
[i
- 1].y
) *
86 (input
- pts
[i
- 1].x
)) /
87 (pts
[i
].x
- pts
[i
- 1].x
)) +
94 static void qcom_vadc_scale_calib(const struct vadc_linear_graph
*calib_graph
,
99 *scale_voltage
= (adc_code
- calib_graph
->gnd
);
100 *scale_voltage
*= calib_graph
->dx
;
101 *scale_voltage
= div64_s64(*scale_voltage
, calib_graph
->dy
);
103 *scale_voltage
+= calib_graph
->dx
;
105 if (*scale_voltage
< 0)
109 static int qcom_vadc_scale_volt(const struct vadc_linear_graph
*calib_graph
,
110 const struct vadc_prescale_ratio
*prescale
,
111 bool absolute
, u16 adc_code
,
114 s64 voltage
= 0, result
= 0;
116 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
118 voltage
= voltage
* prescale
->den
;
119 result
= div64_s64(voltage
, prescale
->num
);
125 static int qcom_vadc_scale_therm(const struct vadc_linear_graph
*calib_graph
,
126 const struct vadc_prescale_ratio
*prescale
,
127 bool absolute
, u16 adc_code
,
130 s64 voltage
= 0, result
= 0;
133 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
136 voltage
= div64_s64(voltage
, 1000);
138 ret
= qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb
,
139 ARRAY_SIZE(adcmap_100k_104ef_104fb
),
145 *result_mdec
= result
;
150 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph
*calib_graph
,
151 const struct vadc_prescale_ratio
*prescale
,
153 u16 adc_code
, int *result_mdec
)
156 u64 temp
; /* Temporary variable for do_div */
158 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
161 temp
= voltage
* prescale
->den
;
162 do_div(temp
, prescale
->num
* 2);
168 voltage
-= KELVINMIL_CELSIUSMIL
;
169 *result_mdec
= voltage
;
174 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph
*calib_graph
,
175 const struct vadc_prescale_ratio
*prescale
,
177 u16 adc_code
, int *result_mdec
)
179 s64 voltage
= 0, result
= 0;
181 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
183 voltage
= voltage
* prescale
->den
;
184 voltage
= div64_s64(voltage
, prescale
->num
);
185 voltage
= ((PMI_CHG_SCALE_1
) * (voltage
* 2));
186 voltage
= (voltage
+ PMI_CHG_SCALE_2
);
187 result
= div64_s64(voltage
, 1000000);
188 *result_mdec
= result
;
193 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype
,
194 const struct vadc_linear_graph
*calib_graph
,
195 const struct vadc_prescale_ratio
*prescale
,
197 u16 adc_code
, int *result
)
201 return qcom_vadc_scale_volt(calib_graph
, prescale
,
204 case SCALE_THERM_100K_PULLUP
:
206 return qcom_vadc_scale_therm(calib_graph
, prescale
,
209 case SCALE_PMIC_THERM
:
210 return qcom_vadc_scale_die_temp(calib_graph
, prescale
,
213 case SCALE_PMI_CHG_TEMP
:
214 return qcom_vadc_scale_chg_temp(calib_graph
, prescale
,
221 EXPORT_SYMBOL(qcom_vadc_scale
);
223 int qcom_vadc_decimation_from_dt(u32 value
)
225 if (!is_power_of_2(value
) || value
< VADC_DECIMATION_MIN
||
226 value
> VADC_DECIMATION_MAX
)
229 return __ffs64(value
/ VADC_DECIMATION_MIN
);
231 EXPORT_SYMBOL(qcom_vadc_decimation_from_dt
);