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");