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>
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[] = {
52 * Voltage to temperature table for 100k pull up for NTCG104EF104 with
55 static const struct vadc_map_pt adcmap_100k_104ef_104fb_1875_vref[] = {
92 static const struct vadc_map_pt adcmap7_die_temp[] = {
108 * Resistance to temperature table for 100k pull up for NTCG104EF104.
110 static const struct vadc_map_pt adcmap7_100k[] = {
281 static const struct vadc_prescale_ratio adc5_prescale_ratios[] = {
282 {.num = 1, .den = 1},
283 {.num = 1, .den = 3},
284 {.num = 1, .den = 4},
285 {.num = 1, .den = 6},
286 {.num = 1, .den = 20},
287 {.num = 1, .den = 8},
288 {.num = 10, .den = 81},
289 {.num = 1, .den = 10},
290 {.num = 1, .den = 16}
293 static int qcom_vadc_scale_hw_calib_volt(
294 const struct vadc_prescale_ratio *prescale,
295 const struct adc5_data *data,
296 u16 adc_code, int *result_uv);
297 static int qcom_vadc_scale_hw_calib_therm(
298 const struct vadc_prescale_ratio *prescale,
299 const struct adc5_data *data,
300 u16 adc_code, int *result_mdec);
301 static int qcom_vadc7_scale_hw_calib_therm(
302 const struct vadc_prescale_ratio *prescale,
303 const struct adc5_data *data,
304 u16 adc_code, int *result_mdec);
305 static int qcom_vadc_scale_hw_smb_temp(
306 const struct vadc_prescale_ratio *prescale,
307 const struct adc5_data *data,
308 u16 adc_code, int *result_mdec);
309 static int qcom_vadc_scale_hw_chg5_temp(
310 const struct vadc_prescale_ratio *prescale,
311 const struct adc5_data *data,
312 u16 adc_code, int *result_mdec);
313 static int qcom_vadc_scale_hw_calib_die_temp(
314 const struct vadc_prescale_ratio *prescale,
315 const struct adc5_data *data,
316 u16 adc_code, int *result_mdec);
317 static int qcom_vadc7_scale_hw_calib_die_temp(
318 const struct vadc_prescale_ratio *prescale,
319 const struct adc5_data *data,
320 u16 adc_code, int *result_mdec);
322 static struct qcom_adc5_scale_type scale_adc5_fn[] = {
323 [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt},
324 [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm},
325 [SCALE_HW_CALIB_XOTHERM] = {qcom_vadc_scale_hw_calib_therm},
326 [SCALE_HW_CALIB_THERM_100K_PU_PM7] = {
327 qcom_vadc7_scale_hw_calib_therm},
328 [SCALE_HW_CALIB_PMIC_THERM] = {qcom_vadc_scale_hw_calib_die_temp},
329 [SCALE_HW_CALIB_PMIC_THERM_PM7] = {
330 qcom_vadc7_scale_hw_calib_die_temp},
331 [SCALE_HW_CALIB_PM5_CHG_TEMP] = {qcom_vadc_scale_hw_chg5_temp},
332 [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp},
335 static int qcom_vadc_map_voltage_temp(const struct vadc_map_pt *pts,
336 u32 tablesize, s32 input, int *output)
344 /* Check if table is descending or ascending */
346 if (pts[0].x < pts[1].x)
350 while (i < tablesize) {
351 if ((descending) && (pts[i].x < input)) {
352 /* table entry is less than measured*/
353 /* value and table is descending, stop */
355 } else if ((!descending) &&
356 (pts[i].x > input)) {
357 /* table entry is greater than measured*/
358 /*value and table is ascending, stop */
366 } else if (i == tablesize) {
367 *output = pts[tablesize - 1].y;
369 /* result is between search_index and search_index-1 */
370 /* interpolate linearly */
371 *output = (((s32)((pts[i].y - pts[i - 1].y) *
372 (input - pts[i - 1].x)) /
373 (pts[i].x - pts[i - 1].x)) +
380 static void qcom_vadc_scale_calib(const struct vadc_linear_graph *calib_graph,
385 *scale_voltage = (adc_code - calib_graph->gnd);
386 *scale_voltage *= calib_graph->dx;
387 *scale_voltage = div64_s64(*scale_voltage, calib_graph->dy);
389 *scale_voltage += calib_graph->dx;
391 if (*scale_voltage < 0)
395 static int qcom_vadc_scale_volt(const struct vadc_linear_graph *calib_graph,
396 const struct vadc_prescale_ratio *prescale,
397 bool absolute, u16 adc_code,
400 s64 voltage = 0, result = 0;
402 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
404 voltage = voltage * prescale->den;
405 result = div64_s64(voltage, prescale->num);
411 static int qcom_vadc_scale_therm(const struct vadc_linear_graph *calib_graph,
412 const struct vadc_prescale_ratio *prescale,
413 bool absolute, u16 adc_code,
419 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
422 voltage = div64_s64(voltage, 1000);
424 ret = qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb,
425 ARRAY_SIZE(adcmap_100k_104ef_104fb),
426 voltage, result_mdec);
430 *result_mdec *= 1000;
435 static int qcom_vadc_scale_die_temp(const struct vadc_linear_graph *calib_graph,
436 const struct vadc_prescale_ratio *prescale,
438 u16 adc_code, int *result_mdec)
441 u64 temp; /* Temporary variable for do_div */
443 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
446 temp = voltage * prescale->den;
447 do_div(temp, prescale->num * 2);
453 *result_mdec = milli_kelvin_to_millicelsius(voltage);
458 static int qcom_vadc_scale_chg_temp(const struct vadc_linear_graph *calib_graph,
459 const struct vadc_prescale_ratio *prescale,
461 u16 adc_code, int *result_mdec)
463 s64 voltage = 0, result = 0;
465 qcom_vadc_scale_calib(calib_graph, adc_code, absolute, &voltage);
467 voltage = voltage * prescale->den;
468 voltage = div64_s64(voltage, prescale->num);
469 voltage = ((PMI_CHG_SCALE_1) * (voltage * 2));
470 voltage = (voltage + PMI_CHG_SCALE_2);
471 result = div64_s64(voltage, 1000000);
472 *result_mdec = result;
477 static int qcom_vadc_scale_code_voltage_factor(u16 adc_code,
478 const struct vadc_prescale_ratio *prescale,
479 const struct adc5_data *data,
482 s64 voltage, temp, adc_vdd_ref_mv = 1875;
485 * The normal data range is between 0V to 1.875V. On cases where
486 * we read low voltage values, the ADC code can go beyond the
487 * range and the scale result is incorrect so we clamp the values
488 * for the cases where the code represents a value below 0V
490 if (adc_code > VADC5_MAX_CODE)
493 /* (ADC code * vref_vadc (1.875V)) / full_scale_code */
494 voltage = (s64) adc_code * adc_vdd_ref_mv * 1000;
495 voltage = div64_s64(voltage, data->full_scale_code_volt);
497 voltage *= prescale->den;
498 temp = prescale->num * factor;
499 voltage = div64_s64(voltage, temp);
504 return (int) voltage;
507 static int qcom_vadc7_scale_hw_calib_therm(
508 const struct vadc_prescale_ratio *prescale,
509 const struct adc5_data *data,
510 u16 adc_code, int *result_mdec)
512 s64 resistance = adc_code;
515 if (adc_code >= RATIO_MAX_ADC7)
518 /* (ADC code * R_PULLUP (100Kohm)) / (full_scale_code - ADC code)*/
519 resistance *= R_PU_100K;
520 resistance = div64_s64(resistance, RATIO_MAX_ADC7 - adc_code);
522 ret = qcom_vadc_map_voltage_temp(adcmap7_100k,
523 ARRAY_SIZE(adcmap7_100k),
524 resistance, &result);
528 *result_mdec = result;
533 static int qcom_vadc_scale_hw_calib_volt(
534 const struct vadc_prescale_ratio *prescale,
535 const struct adc5_data *data,
536 u16 adc_code, int *result_uv)
538 *result_uv = qcom_vadc_scale_code_voltage_factor(adc_code,
544 static int qcom_vadc_scale_hw_calib_therm(
545 const struct vadc_prescale_ratio *prescale,
546 const struct adc5_data *data,
547 u16 adc_code, int *result_mdec)
551 voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
552 prescale, data, 1000);
554 /* Map voltage to temperature from look-up table */
555 return qcom_vadc_map_voltage_temp(adcmap_100k_104ef_104fb_1875_vref,
556 ARRAY_SIZE(adcmap_100k_104ef_104fb_1875_vref),
557 voltage, result_mdec);
560 static int qcom_vadc_scale_hw_calib_die_temp(
561 const struct vadc_prescale_ratio *prescale,
562 const struct adc5_data *data,
563 u16 adc_code, int *result_mdec)
565 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
567 *result_mdec = milli_kelvin_to_millicelsius(*result_mdec);
572 static int qcom_vadc7_scale_hw_calib_die_temp(
573 const struct vadc_prescale_ratio *prescale,
574 const struct adc5_data *data,
575 u16 adc_code, int *result_mdec)
578 int voltage, vtemp0, temp, i;
580 voltage = qcom_vadc_scale_code_voltage_factor(adc_code,
583 if (adcmap7_die_temp[0].x > voltage) {
584 *result_mdec = DIE_TEMP_ADC7_SCALE_1;
588 if (adcmap7_die_temp[ARRAY_SIZE(adcmap7_die_temp) - 1].x <= voltage) {
589 *result_mdec = DIE_TEMP_ADC7_MAX;
593 for (i = 0; i < ARRAY_SIZE(adcmap7_die_temp); i++)
594 if (adcmap7_die_temp[i].x > voltage)
597 vtemp0 = adcmap7_die_temp[i - 1].x;
598 voltage = voltage - vtemp0;
599 temp = div64_s64(voltage * DIE_TEMP_ADC7_SCALE_FACTOR,
600 adcmap7_die_temp[i - 1].y);
601 temp += DIE_TEMP_ADC7_SCALE_1 + (DIE_TEMP_ADC7_SCALE_2 * (i - 1));
607 static int qcom_vadc_scale_hw_smb_temp(
608 const struct vadc_prescale_ratio *prescale,
609 const struct adc5_data *data,
610 u16 adc_code, int *result_mdec)
612 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code * 100,
613 prescale, data, PMIC5_SMB_TEMP_SCALE_FACTOR);
614 *result_mdec = PMIC5_SMB_TEMP_CONSTANT - *result_mdec;
619 static int qcom_vadc_scale_hw_chg5_temp(
620 const struct vadc_prescale_ratio *prescale,
621 const struct adc5_data *data,
622 u16 adc_code, int *result_mdec)
624 *result_mdec = qcom_vadc_scale_code_voltage_factor(adc_code,
626 *result_mdec = PMIC5_CHG_TEMP_SCALE_FACTOR - *result_mdec;
631 int qcom_vadc_scale(enum vadc_scale_fn_type scaletype,
632 const struct vadc_linear_graph *calib_graph,
633 const struct vadc_prescale_ratio *prescale,
635 u16 adc_code, int *result)
639 return qcom_vadc_scale_volt(calib_graph, prescale,
642 case SCALE_THERM_100K_PULLUP:
644 return qcom_vadc_scale_therm(calib_graph, prescale,
647 case SCALE_PMIC_THERM:
648 return qcom_vadc_scale_die_temp(calib_graph, prescale,
651 case SCALE_PMI_CHG_TEMP:
652 return qcom_vadc_scale_chg_temp(calib_graph, prescale,
659 EXPORT_SYMBOL(qcom_vadc_scale);
661 int qcom_adc5_hw_scale(enum vadc_scale_fn_type scaletype,
662 unsigned int prescale_ratio,
663 const struct adc5_data *data,
664 u16 adc_code, int *result)
666 const struct vadc_prescale_ratio *prescale = &adc5_prescale_ratios[prescale_ratio];
668 if (!(scaletype >= SCALE_HW_CALIB_DEFAULT &&
669 scaletype < SCALE_HW_CALIB_INVALID)) {
670 pr_err("Invalid scale type %d\n", scaletype);
674 return scale_adc5_fn[scaletype].scale_fn(prescale, data,
677 EXPORT_SYMBOL(qcom_adc5_hw_scale);
679 int qcom_adc5_prescaling_from_dt(u32 num, u32 den)
683 for (pre = 0; pre < ARRAY_SIZE(adc5_prescale_ratios); pre++)
684 if (adc5_prescale_ratios[pre].num == num &&
685 adc5_prescale_ratios[pre].den == den)
688 if (pre == ARRAY_SIZE(adc5_prescale_ratios))
693 EXPORT_SYMBOL(qcom_adc5_prescaling_from_dt);
695 int qcom_adc5_hw_settle_time_from_dt(u32 value,
696 const unsigned int *hw_settle)
700 for (i = 0; i < VADC_HW_SETTLE_SAMPLES_MAX; i++) {
701 if (value == hw_settle[i])
707 EXPORT_SYMBOL(qcom_adc5_hw_settle_time_from_dt);
709 int qcom_adc5_avg_samples_from_dt(u32 value)
711 if (!is_power_of_2(value) || value > ADC5_AVG_SAMPLES_MAX)
716 EXPORT_SYMBOL(qcom_adc5_avg_samples_from_dt);
718 int qcom_adc5_decimation_from_dt(u32 value, const unsigned int *decimation)
722 for (i = 0; i < ADC5_DECIMATION_SAMPLES_MAX; i++) {
723 if (value == decimation[i])
729 EXPORT_SYMBOL(qcom_adc5_decimation_from_dt);
731 int qcom_vadc_decimation_from_dt(u32 value)
733 if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
734 value > VADC_DECIMATION_MAX)
737 return __ffs64(value / VADC_DECIMATION_MIN);
739 EXPORT_SYMBOL(qcom_vadc_decimation_from_dt);
741 MODULE_LICENSE("GPL v2");
742 MODULE_DESCRIPTION("Qualcomm ADC common functionality");