From f90d42fefa4244f30d281970b457532bb953a30f Mon Sep 17 00:00:00 2001 From: Subbaraman Narayanamurthy Date: Fri, 11 Sep 2020 12:55:05 -0700 Subject: [PATCH] iio: qcom-spmi-adc5: add support to read current channels Add support to read current channels on PM8350B and SMB139x charge pumps. IIN_FB - Input current drawn by main charger (PM8350B) ICHG_FB - Charging current from main charger (PM8350B) IIN_SMB - Input current drawn by one of SMB139x ICHG_SMB - Charging current from one of SMB139x Since, most of these channels needs prescale ratios post reading ADC code and before scaling, add the necessary prescale ratios. Change-Id: Id9b866f684d574813904a5fd8e658f59b1d7bcbf Signed-off-by: Subbaraman Narayanamurthy [quic_subbaram@quicinc.com: Fixed merge conflicts in qcom-vadc-common.h due to location change and common code moved to qcom-vadc-common.c] Signed-off-by: Subbaraman Narayanamurthy [quic_collinsd@quicinc.com: changed struct vadc_prescale_ratio to struct u32_fract and changed prescale "num" and "den" to "numerator" and "denominator" respectively] Signed-off-by: David Collins --- drivers/iio/adc/qcom-spmi-adc5.c | 13 ++++++ drivers/iio/adc/qcom-vadc-common.c | 55 ++++++++++++++++++++++++ include/linux/iio/adc/qcom-vadc-common.h | 6 +++ 3 files changed, 74 insertions(+) diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index 9ed8000ce6c4..e910eb2ef076 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -555,6 +555,11 @@ struct adc5_channels { BIT(IIO_CHAN_INFO_PROCESSED), \ _pre, _scale) \ +#define ADC5_CHAN_CUR(_dname, _pre, _scale) \ + ADC5_CHAN(_dname, IIO_CURRENT, \ + BIT(IIO_CHAN_INFO_PROCESSED), \ + _pre, _scale) \ + static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = { [ADC5_REF_GND] = ADC5_CHAN_VOLT("ref_gnd", 0, SCALE_HW_CALIB_DEFAULT) @@ -620,6 +625,14 @@ static const struct adc5_channels adc7_chans_pmic[ADC5_MAX_CHANNEL] = { SCALE_HW_CALIB_PM7_SMB_TEMP) [ADC7_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 0, SCALE_HW_CALIB_PM7_CHG_TEMP) + [ADC7_IIN_FB] = ADC5_CHAN_CUR("iin_fb", 9, + SCALE_HW_CALIB_CUR) + [ADC7_ICHG_SMB] = ADC5_CHAN_CUR("ichg_smb", 10, + SCALE_HW_CALIB_CUR) + [ADC7_IIN_SMB] = ADC5_CHAN_CUR("iin_smb", 11, + SCALE_HW_CALIB_CUR) + [ADC7_ICHG_FB] = ADC5_CHAN_CUR("ichg_fb", 12, + SCALE_HW_CALIB_CUR_RAW) [ADC7_DIE_TEMP] = ADC5_CHAN_TEMP("die_temp", 0, SCALE_HW_CALIB_PMIC_THERM_PM7) [ADC7_AMUX_THM1_100K_PU] = ADC5_CHAN_TEMP("amux_thm1_pu2", 0, diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index ace40258dac5..6c47d028a50c 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -530,12 +530,26 @@ static const struct u32_fract adc5_prescale_ratios[] = { { .numerator = 10, .denominator = 81 }, { .numerator = 1, .denominator = 10 }, { .numerator = 1, .denominator = 16 }, + /* Prescale ratios for current channels below */ + { .numerator = 32, .denominator = 100 }, /* IIN_FB */ + { .numerator = 14, .denominator = 100 }, /* ICHG_SMB */ + { .numerator = 28, .denominator = 100 }, /* IIN_SMB */ + { .numerator = 1000, .denominator = 305185 }, /* ICHG_FB */ + { .numerator = 1000, .denominator = 610370 }, /* ICHG_FB_2X */ }; static int qcom_vadc_scale_hw_calib_volt( const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_uv); +static int qcom_vadc_scale_hw_calib_current( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_ua); +static int qcom_vadc_scale_hw_calib_current_raw( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_ua); static int qcom_vadc_scale_hw_calib_therm( const struct u32_fract *prescale, const struct adc5_data *data, @@ -587,6 +601,8 @@ static int qcom_vadc7_scale_hw_calib_die_temp( static struct qcom_adc5_scale_type scale_adc5_fn[] = { [SCALE_HW_CALIB_DEFAULT] = {qcom_vadc_scale_hw_calib_volt}, + [SCALE_HW_CALIB_CUR] = {qcom_vadc_scale_hw_calib_current}, + [SCALE_HW_CALIB_CUR_RAW] = {qcom_vadc_scale_hw_calib_current_raw}, [SCALE_HW_CALIB_THERM_100K_PULLUP] = {qcom_vadc_scale_hw_calib_therm}, [SCALE_HW_CALIB_BATT_THERM_100K] = { qcom_vadc_scale_hw_calib_batt_therm_100}, @@ -820,6 +836,45 @@ static int qcom_vadc7_scale_hw_calib_therm( return 0; } +static int qcom_vadc_scale_hw_calib_current_raw( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_ua) +{ + s64 temp; + + if (!prescale->numerator) + return -EINVAL; + + temp = div_s64((s64)(s16)adc_code * prescale->denominator, + prescale->numerator); + *result_ua = (int) temp; + pr_debug("raw adc_code: %#x result_ua: %d\n", adc_code, *result_ua); + + return 0; +} + +static int qcom_vadc_scale_hw_calib_current( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_ua) +{ + u32 adc_vdd_ref_mv = 1875; + s64 voltage; + + if (!prescale->numerator) + return -EINVAL; + + /* (ADC code * vref_vadc (1.875V)) / full_scale_code */ + voltage = (s64)(s16) adc_code * adc_vdd_ref_mv * 1000; + voltage = div_s64(voltage, data->full_scale_code_volt); + voltage = div_s64(voltage * prescale->denominator, prescale->numerator); + *result_ua = (int) voltage; + pr_debug("adc_code: %#x result_ua: %d\n", adc_code, *result_ua); + + return 0; +} + static int qcom_vadc_scale_hw_calib_volt( const struct u32_fract *prescale, const struct adc5_data *data, diff --git a/include/linux/iio/adc/qcom-vadc-common.h b/include/linux/iio/adc/qcom-vadc-common.h index 4f1af5aeb25e..3ed870a1eb6b 100644 --- a/include/linux/iio/adc/qcom-vadc-common.h +++ b/include/linux/iio/adc/qcom-vadc-common.h @@ -122,6 +122,10 @@ struct vadc_linear_graph { * SMB139x temperature. * SCALE_HW_CALIB_PM7_CHG_TEMP: Returns result in millidegrees for PMIC7 * charger temperature. + * SCALE_HW_CALIB_CUR: Returns result in microamperes for PMIC7 channels that + * use voltage scaling. + * SCALE_HW_CALIB_CUR_RAW: Returns result in microamperes for PMIC7 channels + * that use raw ADC code. */ enum vadc_scale_fn_type { SCALE_DEFAULT = 0, @@ -143,6 +147,8 @@ enum vadc_scale_fn_type { SCALE_HW_CALIB_PM5_SMB1398_TEMP, SCALE_HW_CALIB_PM7_SMB_TEMP, SCALE_HW_CALIB_PM7_CHG_TEMP, + SCALE_HW_CALIB_CUR, + SCALE_HW_CALIB_CUR_RAW, SCALE_HW_CALIB_INVALID, };