1 // SPDX-License-Identifier: GPL-2.0
3 #include <linux/kernel.h>
4 #include <linux/bitops.h>
5 #include <linux/fixp-arith.h>
6 #include <linux/iio/adc/qcom-vadc-common.h>
7 #include <linux/math64.h>
8 #include <linux/log2.h>
10 #include <linux/module.h>
11 #include <linux/units.h>
14 * struct vadc_map_pt - Map the graph representation for ADC channel
15 * @x: Represent the ADC digitized code.
16 * @y: Represent the physical data which can be temperature, voltage,
24 /* Voltage to temperature */
25 static const struct vadc_map_pt adcmap_100k_104ef_104fb
[] = {
63 * Voltage to temperature table for 100k pull up for NTCG104EF104 with
66 static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref
[] = {
103 static const struct vadc_map_pt adcmap7_die_temp
[] = {
119 * Resistance to temperature table for 100k pull up for NTCG104EF104.
121 static const struct vadc_map_pt adcmap7_100k
[] = {
292 static const struct u32_fract adc5_prescale_ratios
[] = {
293 { .numerator
= 1, .denominator
= 1 },
294 { .numerator
= 1, .denominator
= 3 },
295 { .numerator
= 1, .denominator
= 4 },
296 { .numerator
= 1, .denominator
= 6 },
297 { .numerator
= 1, .denominator
= 20 },
298 { .numerator
= 1, .denominator
= 8 },
299 { .numerator
= 10, .denominator
= 81 },
300 { .numerator
= 1, .denominator
= 10 },
301 { .numerator
= 1, .denominator
= 16 },
304 static int qcom_vadc_scale_hw_calib_volt(
305 const struct u32_fract
*prescale
,
306 const struct adc5_data
*data
,
307 u16 adc_code
, int *result_uv
);
308 static int qcom_vadc_scale_hw_calib_therm(
309 const struct u32_fract
*prescale
,
310 const struct adc5_data
*data
,
311 u16 adc_code
, int *result_mdec
);
312 static int qcom_vadc7_scale_hw_calib_therm(
313 const struct u32_fract
*prescale
,
314 const struct adc5_data
*data
,
315 u16 adc_code
, int *result_mdec
);
316 static int qcom_vadc_scale_hw_smb_temp(
317 const struct u32_fract
*prescale
,
318 const struct adc5_data
*data
,
319 u16 adc_code
, int *result_mdec
);
320 static int qcom_vadc_scale_hw_chg5_temp(
321 const struct u32_fract
*prescale
,
322 const struct adc5_data
*data
,
323 u16 adc_code
, int *result_mdec
);
324 static int qcom_vadc_scale_hw_calib_die_temp(
325 const struct u32_fract
*prescale
,
326 const struct adc5_data
*data
,
327 u16 adc_code
, int *result_mdec
);
328 static int qcom_vadc7_scale_hw_calib_die_temp(
329 const struct u32_fract
*prescale
,
330 const struct adc5_data
*data
,
331 u16 adc_code
, int *result_mdec
);
333 static struct qcom_adc5_scale_type scale_adc5_fn
[] = {
334 [SCALE_HW_CALIB_DEFAULT
] = {qcom_vadc_scale_hw_calib_volt
},
335 [SCALE_HW_CALIB_THERM_100K_PULLUP
] = {qcom_vadc_scale_hw_calib_therm
},
336 [SCALE_HW_CALIB_XOTHERM
] = {qcom_vadc_scale_hw_calib_therm
},
337 [SCALE_HW_CALIB_THERM_100K_PU_PM7
] = {
338 qcom_vadc7_scale_hw_calib_therm
},
339 [SCALE_HW_CALIB_PMIC_THERM
] = {qcom_vadc_scale_hw_calib_die_temp
},
340 [SCALE_HW_CALIB_PMIC_THERM_PM7
] = {
341 qcom_vadc7_scale_hw_calib_die_temp
},
342 [SCALE_HW_CALIB_PM5_CHG_TEMP
] = {qcom_vadc_scale_hw_chg5_temp
},
343 [SCALE_HW_CALIB_PM5_SMB_TEMP
] = {qcom_vadc_scale_hw_smb_temp
},
346 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt
*pts
,
347 u32 tablesize
, s32 input
, int *output
)
354 while (i
< tablesize
&& pts
[i
].x
> input
)
359 } else if (i
== tablesize
) {
360 *output
= pts
[tablesize
- 1].y
;
362 /* interpolate linearly */
363 *output
= fixp_linear_interpolate(pts
[i
- 1].x
, pts
[i
- 1].y
,
371 static s32
qcom_vadc_map_temp_voltage(const struct vadc_map_pt
*pts
,
372 u32 tablesize
, int input
)
377 * Table must be sorted, find the interval of 'y' which contains value
378 * 'input' and map it to proper 'x' value
380 while (i
< tablesize
&& pts
[i
].y
< input
)
386 return pts
[tablesize
- 1].x
;
388 /* interpolate linearly */
389 return fixp_linear_interpolate(pts
[i
- 1].y
, pts
[i
- 1].x
,
390 pts
[i
].y
, pts
[i
].x
, input
);
393 static void qcom_vadc_scale_calib(const struct vadc_linear_graph
*calib_graph
,
398 *scale_voltage
= (adc_code
- calib_graph
->gnd
);
399 *scale_voltage
*= calib_graph
->dx
;
400 *scale_voltage
= div64_s64(*scale_voltage
, calib_graph
->dy
);
402 *scale_voltage
+= calib_graph
->dx
;
404 if (*scale_voltage
< 0)
408 static int qcom_vadc_scale_volt(const struct vadc_linear_graph
*calib_graph
,
409 const struct u32_fract
*prescale
,
410 bool absolute
, u16 adc_code
,
413 s64 voltage
= 0, result
= 0;
415 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
417 voltage
*= prescale
->denominator
;
418 result
= div64_s64(voltage
, prescale
->numerator
);
424 static int qcom_vadc_scale_therm(const struct vadc_linear_graph
*calib_graph
,
425 const struct u32_fract
*prescale
,
426 bool absolute
, u16 adc_code
,
432 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
435 voltage
= div64_s64(voltage
, 1000);
437 ret
= qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb
,
438 ARRAY_SIZE(adcmap_100k_104ef_104fb
),
439 voltage
, result_mdec
);
446 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph
*calib_graph
,
447 const struct u32_fract
*prescale
,
449 u16 adc_code
, int *result_mdec
)
452 u64 temp
; /* Temporary variable for do_div */
454 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
457 temp
= voltage
* prescale
->denominator
;
458 do_div(temp
, prescale
->numerator
* 2);
464 *result_mdec
= milli_kelvin_to_millicelsius(voltage
);
469 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph
*calib_graph
,
470 const struct u32_fract
*prescale
,
472 u16 adc_code
, int *result_mdec
)
474 s64 voltage
= 0, result
= 0;
476 qcom_vadc_scale_calib(calib_graph
, adc_code
, absolute
, &voltage
);
478 voltage
*= prescale
->denominator
;
479 voltage
= div64_s64(voltage
, prescale
->numerator
);
480 voltage
= ((PMI_CHG_SCALE_1
) * (voltage
* 2));
481 voltage
= (voltage
+ PMI_CHG_SCALE_2
);
482 result
= div64_s64(voltage
, 1000000);
483 *result_mdec
= result
;
488 /* convert voltage to ADC code, using 1.875V reference */
489 static u16
qcom_vadc_scale_voltage_code(s32 voltage
,
490 const struct u32_fract
*prescale
,
491 const u32 full_scale_code_volt
,
495 s64 adc_vdd_ref_mv
= 1875; /* reference voltage */
497 volt
*= prescale
->numerator
* factor
* full_scale_code_volt
;
498 volt
= div64_s64(volt
, (s64
)prescale
->denominator
* adc_vdd_ref_mv
* 1000);
503 static int qcom_vadc_scale_code_voltage_factor(u16 adc_code
,
504 const struct u32_fract
*prescale
,
505 const struct adc5_data
*data
,
508 s64 voltage
, temp
, adc_vdd_ref_mv
= 1875;
511 * The normal data range is between 0V to 1.875V. On cases where
512 * we read low voltage values, the ADC code can go beyond the
513 * range and the scale result is incorrect so we clamp the values
514 * for the cases where the code represents a value below 0V
516 if (adc_code
> VADC5_MAX_CODE
)
519 /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
520 voltage
= (s64
) adc_code
* adc_vdd_ref_mv
* 1000;
521 voltage
= div64_s64(voltage
, data
->full_scale_code_volt
);
523 voltage
*= prescale
->denominator
;
524 temp
= prescale
->numerator
* factor
;
525 voltage
= div64_s64(voltage
, temp
);
530 return (int) voltage
;
533 static int qcom_vadc7_scale_hw_calib_therm(
534 const struct u32_fract
*prescale
,
535 const struct adc5_data
*data
,
536 u16 adc_code
, int *result_mdec
)
538 s64 resistance
= adc_code
;
541 if (adc_code
>= RATIO_MAX_ADC7
)
544 /* (ADC code * R_PULLUP (100Kohm)) / (full_scale_code - ADC code)*/
545 resistance
*= R_PU_100K
;
546 resistance
= div64_s64(resistance
, RATIO_MAX_ADC7
- adc_code
);
548 ret
= qcom_vadc_map_voltage_temp(adcmap7_100k
,
549 ARRAY_SIZE(adcmap7_100k
),
550 resistance
, &result
);
554 *result_mdec
= result
;
559 static int qcom_vadc_scale_hw_calib_volt(
560 const struct u32_fract
*prescale
,
561 const struct adc5_data
*data
,
562 u16 adc_code
, int *result_uv
)
564 *result_uv
= qcom_vadc_scale_code_voltage_factor(adc_code
,
570 static int qcom_vadc_scale_hw_calib_therm(
571 const struct u32_fract
*prescale
,
572 const struct adc5_data
*data
,
573 u16 adc_code
, int *result_mdec
)
577 voltage
= qcom_vadc_scale_code_voltage_factor(adc_code
,
578 prescale
, data
, 1000);
580 /* Map voltage to temperature from look-up table */
581 return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref
,
582 ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref
),
583 voltage
, result_mdec
);
586 static int qcom_vadc_scale_hw_calib_die_temp(
587 const struct u32_fract
*prescale
,
588 const struct adc5_data
*data
,
589 u16 adc_code
, int *result_mdec
)
591 *result_mdec
= qcom_vadc_scale_code_voltage_factor(adc_code
,
593 *result_mdec
= milli_kelvin_to_millicelsius(*result_mdec
);
598 static int qcom_vadc7_scale_hw_calib_die_temp(
599 const struct u32_fract
*prescale
,
600 const struct adc5_data
*data
,
601 u16 adc_code
, int *result_mdec
)
606 voltage
= qcom_vadc_scale_code_voltage_factor(adc_code
,
609 return qcom_vadc_map_voltage_temp(adcmap7_die_temp
, ARRAY_SIZE(adcmap7_die_temp
),
610 voltage
, result_mdec
);
613 static int qcom_vadc_scale_hw_smb_temp(
614 const struct u32_fract
*prescale
,
615 const struct adc5_data
*data
,
616 u16 adc_code
, int *result_mdec
)
618 *result_mdec
= qcom_vadc_scale_code_voltage_factor(adc_code
* 100,
619 prescale
, data
, PMIC5_SMB_TEMP_SCALE_FACTOR
);
620 *result_mdec
= PMIC5_SMB_TEMP_CONSTANT
- *result_mdec
;
625 static int qcom_vadc_scale_hw_chg5_temp(
626 const struct u32_fract
*prescale
,
627 const struct adc5_data
*data
,
628 u16 adc_code
, int *result_mdec
)
630 *result_mdec
= qcom_vadc_scale_code_voltage_factor(adc_code
,
632 *result_mdec
= PMIC5_CHG_TEMP_SCALE_FACTOR
- *result_mdec
;
637 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype
,
638 const struct vadc_linear_graph
*calib_graph
,
639 const struct u32_fract
*prescale
,
641 u16 adc_code
, int *result
)
645 return qcom_vadc_scale_volt(calib_graph
, prescale
,
648 case SCALE_THERM_100K_PULLUP
:
650 return qcom_vadc_scale_therm(calib_graph
, prescale
,
653 case SCALE_PMIC_THERM
:
654 return qcom_vadc_scale_die_temp(calib_graph
, prescale
,
657 case SCALE_PMI_CHG_TEMP
:
658 return qcom_vadc_scale_chg_temp(calib_graph
, prescale
,
665 EXPORT_SYMBOL(qcom_vadc_scale
);
667 u16
qcom_adc_tm5_temp_volt_scale(unsigned int prescale_ratio
,
668 u32 full_scale_code_volt
, int temp
)
670 const struct u32_fract
*prescale
= &adc5_prescale_ratios
[prescale_ratio
];
673 voltage
= qcom_vadc_map_temp_voltage(adcmap_100k_104ef_104fb_1875_vref
,
674 ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref
),
676 return qcom_vadc_scale_voltage_code(voltage
, prescale
, full_scale_code_volt
, 1000);
678 EXPORT_SYMBOL(qcom_adc_tm5_temp_volt_scale
);
680 u16
qcom_adc_tm5_gen2_temp_res_scale(int temp
)
684 resistance
= qcom_vadc_map_temp_voltage(adcmap7_100k
,
685 ARRAY_SIZE(adcmap7_100k
), temp
);
687 return div64_s64(resistance
* RATIO_MAX_ADC7
, resistance
+ R_PU_100K
);
689 EXPORT_SYMBOL(qcom_adc_tm5_gen2_temp_res_scale
);
691 int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype
,
692 unsigned int prescale_ratio
,
693 const struct adc5_data
*data
,
694 u16 adc_code
, int *result
)
696 const struct u32_fract
*prescale
= &adc5_prescale_ratios
[prescale_ratio
];
698 if (!(scaletype
>= SCALE_HW_CALIB_DEFAULT
&&
699 scaletype
< SCALE_HW_CALIB_INVALID
)) {
700 pr_err("Invalid scale type %d\n", scaletype
);
704 return scale_adc5_fn
[scaletype
].scale_fn(prescale
, data
,
707 EXPORT_SYMBOL(qcom_adc5_hw_scale
);
709 int qcom_adc5_prescaling_from_dt(u32 numerator
, u32 denominator
)
713 for (pre
= 0; pre
< ARRAY_SIZE(adc5_prescale_ratios
); pre
++)
714 if (adc5_prescale_ratios
[pre
].numerator
== numerator
&&
715 adc5_prescale_ratios
[pre
].denominator
== denominator
)
718 if (pre
== ARRAY_SIZE(adc5_prescale_ratios
))
723 EXPORT_SYMBOL(qcom_adc5_prescaling_from_dt
);
725 int qcom_adc5_hw_settle_time_from_dt(u32 value
,
726 const unsigned int *hw_settle
)
730 for (i
= 0; i
< VADC_HW_SETTLE_SAMPLES_MAX
; i
++) {
731 if (value
== hw_settle
[i
])
737 EXPORT_SYMBOL(qcom_adc5_hw_settle_time_from_dt
);
739 int qcom_adc5_avg_samples_from_dt(u32 value
)
741 if (!is_power_of_2(value
) || value
> ADC5_AVG_SAMPLES_MAX
)
746 EXPORT_SYMBOL(qcom_adc5_avg_samples_from_dt
);
748 int qcom_adc5_decimation_from_dt(u32 value
, const unsigned int *decimation
)
752 for (i
= 0; i
< ADC5_DECIMATION_SAMPLES_MAX
; i
++) {
753 if (value
== decimation
[i
])
759 EXPORT_SYMBOL(qcom_adc5_decimation_from_dt
);
761 int qcom_vadc_decimation_from_dt(u32 value
)
763 if (!is_power_of_2(value
) || value
< VADC_DECIMATION_MIN
||
764 value
> VADC_DECIMATION_MAX
)
767 return __ffs64(value
/ VADC_DECIMATION_MIN
);
769 EXPORT_SYMBOL(qcom_vadc_decimation_from_dt
);
771 MODULE_LICENSE("GPL v2");
772 MODULE_DESCRIPTION("Qualcomm ADC common functionality");