From f8f8647cb846d1d864f4b07fb090b97a31aac2f9 Mon Sep 17 00:00:00 2001 From: Jishnu Prakash Date: Mon, 10 May 2021 15:16:21 +0530 Subject: [PATCH] iio: qcom-spmi-adc5: Update ADC5 Gen3 support for PM5100 Add scaling functions for batt_therm, batt_id and usb_in_i ADC channels for PM5100. Also add usb_sns_v_div_16 and vin_div_16 channels to list of supported channels and correct default prescaling value for vbat_sns channel and full scale ADC current. Change-Id: I86b86c319bff6df583efab8cc4c877218a79fe56 Signed-off-by: Jishnu Prakash [quic_subbaram@quicinc.com: Fixed merge conflicts in qcom-vadc-common.h due to location change and in 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-gen3.c | 8 +- drivers/iio/adc/qcom-vadc-common.c | 160 +++++++++++++++++++++++ include/linux/iio/adc/qcom-vadc-common.h | 18 ++- 3 files changed, 181 insertions(+), 5 deletions(-) diff --git a/drivers/iio/adc/qcom-spmi-adc5-gen3.c b/drivers/iio/adc/qcom-spmi-adc5-gen3.c index f25b1f4fa751..310f802e1abc 100644 --- a/drivers/iio/adc/qcom-spmi-adc5-gen3.c +++ b/drivers/iio/adc/qcom-spmi-adc5-gen3.c @@ -1323,12 +1323,16 @@ static const struct adc5_channels adc5_chans_pmic[ADC5_MAX_CHANNEL] = { SCALE_HW_CALIB_DEFAULT) [ADC5_GEN3_VPH_PWR] = ADC5_CHAN_VOLT("vph_pwr", 1, SCALE_HW_CALIB_DEFAULT) - [ADC5_GEN3_VBAT_SNS_QBG] = ADC5_CHAN_VOLT("vbat_sns", 3, + [ADC5_GEN3_VBAT_SNS_QBG] = ADC5_CHAN_VOLT("vbat_sns", 1, SCALE_HW_CALIB_DEFAULT) [ADC5_GEN3_AMUX3_THM] = ADC5_CHAN_TEMP("smb_temp", 0, SCALE_HW_CALIB_PM7_SMB_TEMP) [ADC5_GEN3_CHG_TEMP] = ADC5_CHAN_TEMP("chg_temp", 0, SCALE_HW_CALIB_PM7_CHG_TEMP) + [ADC5_GEN3_USB_SNS_V_16] = ADC5_CHAN_TEMP("usb_sns_v_div_16", 3, + SCALE_HW_CALIB_DEFAULT) + [ADC5_GEN3_VIN_DIV16_MUX] = ADC5_CHAN_TEMP("vin_div_16", 3, + SCALE_HW_CALIB_DEFAULT) [ADC5_GEN3_IIN_FB] = ADC5_CHAN_CUR("iin_fb", 4, SCALE_HW_CALIB_CUR) [ADC5_GEN3_ICHG_SMB] = ADC5_CHAN_CUR("ichg_smb", 5, @@ -1511,7 +1515,7 @@ static int adc5_get_dt_channel_data(struct adc5_chip *adc, static const struct adc5_data adc5_gen3_data_pmic = { .name = "pm-adc5-gen3", .full_scale_code_volt = 0x70e4, - .full_scale_code_cur = 0x2710, + .full_scale_code_cur = 0x2ee0, .adc_chans = adc5_chans_pmic, .decimation = (unsigned int [ADC5_DECIMATION_SAMPLES_MAX]) {85, 340, 1360}, diff --git a/drivers/iio/adc/qcom-vadc-common.c b/drivers/iio/adc/qcom-vadc-common.c index d88e530021f7..75af6bb3d49b 100644 --- a/drivers/iio/adc/qcom-vadc-common.c +++ b/drivers/iio/adc/qcom-vadc-common.c @@ -520,6 +520,82 @@ static const struct vadc_map_pt adcmap7_100k[] = { { 2420, 130048 } }; +/* + * Resistance to temperature table for batt_therm. + */ +static const struct vadc_map_pt adcmap_gen3_batt_therm_100k[] = { + { 5319890, -400 }, + { 4555860, -380 }, + { 3911780, -360 }, + { 3367320, -340 }, + { 2905860, -320 }, + { 2513730, -300 }, + { 2179660, -280 }, + { 1894360, -260 }, + { 1650110, -240 }, + { 1440520, -220 }, + { 1260250, -200 }, + { 1104850, -180 }, + { 970600, -160 }, + { 854370, -140 }, + { 753530, -120 }, + { 665860, -100 }, + { 589490, -80 }, + { 522830, -60 }, + { 464540, -40 }, + { 413470, -20 }, + { 368640, 0 }, + { 329220, 20 }, + { 294490, 40 }, + { 263850, 60 }, + { 236770, 80 }, + { 212790, 100 }, + { 191530, 120 }, + { 172640, 140 }, + { 155840, 160 }, + { 140880, 180 }, + { 127520, 200 }, + { 115590, 220 }, + { 104910, 240 }, + { 95350, 260 }, + { 86760, 280 }, + { 79050, 300 }, + { 72110, 320 }, + { 65860, 340 }, + { 60220, 360 }, + { 55130, 380 }, + { 50520, 400 }, + { 46350, 420 }, + { 42570, 440 }, + { 39140, 460 }, + { 36030, 480 }, + { 33190, 500 }, + { 30620, 520 }, + { 28260, 540 }, + { 26120, 560 }, + { 24160, 580 }, + { 22370, 600 }, + { 20730, 620 }, + { 19230, 640 }, + { 17850, 660 }, + { 16580, 680 }, + { 15420, 700 }, + { 14350, 720 }, + { 13370, 740 }, + { 12470, 760 }, + { 11630, 780 }, + { 10860, 800 }, + { 10150, 820 }, + { 9490, 840 }, + { 8880, 860 }, + { 8320, 880 }, + { 7800, 900 }, + { 7310, 920 }, + { 6860, 940 }, + { 6450, 960 }, + { 6060, 980 } +}; + static const struct u32_fract adc5_prescale_ratios[] = { { .numerator = 1, .denominator = 1 }, { .numerator = 1, .denominator = 3 }, @@ -595,6 +671,18 @@ static int qcom_vadc_scale_hw_pm2250_s3_die_temp( const struct u32_fract *prescale, const struct adc5_data *data, u16 adc_code, int *result_mdec); +static int qcom_adc5_gen3_scale_hw_calib_batt_therm_100( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_mdec); +static int qcom_adc5_gen3_scale_hw_calib_batt_id_100( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_mdec); +static int qcom_adc5_gen3_scale_hw_calib_usb_in_current( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_mdec); static int qcom_vadc_scale_hw_chg5_temp( const struct u32_fract *prescale, const struct adc5_data *data, @@ -634,6 +722,9 @@ static struct qcom_adc5_scale_type scale_adc5_fn[] = { [SCALE_HW_CALIB_PM5_SMB_TEMP] = {qcom_vadc_scale_hw_smb_temp}, [SCALE_HW_CALIB_PM5_SMB1398_TEMP] = {qcom_vadc_scale_hw_smb1398_temp}, [SCALE_HW_CALIB_PM2250_S3_DIE_TEMP] = {qcom_vadc_scale_hw_pm2250_s3_die_temp}, + [SCALE_HW_CALIB_PM5_GEN3_BATT_THERM_100K] = {qcom_adc5_gen3_scale_hw_calib_batt_therm_100}, + [SCALE_HW_CALIB_PM5_GEN3_BATT_ID_100K] = {qcom_adc5_gen3_scale_hw_calib_batt_id_100}, + [SCALE_HW_CALIB_PM5_GEN3_USB_IN_I] = {qcom_adc5_gen3_scale_hw_calib_usb_in_current}, [SCALE_HW_CALIB_PM7_SMB_TEMP] = {qcom_vadc_scale_hw_pm7_smb_temp}, [SCALE_HW_CALIB_PM7_CHG_TEMP] = {qcom_vadc_scale_hw_pm7_chg_temp}, }; @@ -1127,6 +1218,75 @@ static int qcom_vadc_scale_hw_pm2250_s3_die_temp( return 0; } +static int qcom_adc5_gen3_scale_hw_calib_batt_therm_100( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_mdec) +{ + s64 resistance = 0; + int ret, result = 0; + + if (adc_code >= RATIO_MAX_ADC7) + return -EINVAL; + + /* (ADC code * R_PULLUP (100Kohm)) / (full_scale_code - ADC code)*/ + resistance = (s64) adc_code * R_PU_100K; + resistance = div64_s64(resistance, (RATIO_MAX_ADC7 - adc_code)); + + ret = qcom_vadc_map_voltage_temp(adcmap_gen3_batt_therm_100k, + ARRAY_SIZE(adcmap_gen3_batt_therm_100k), + resistance, &result); + if (ret) + return ret; + + *result_mdec = result; + + return 0; +} + +static int qcom_adc5_gen3_scale_hw_calib_batt_id_100( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_mdec) +{ + s64 resistance = 0; + + if (adc_code >= RATIO_MAX_ADC7) + return -EINVAL; + + /* (ADC code * R_PULLUP (100Kohm)) / (full_scale_code - ADC code)*/ + resistance = (s64) adc_code * R_PU_100K; + resistance = div64_s64(resistance, (RATIO_MAX_ADC7 - adc_code)); + + *result_mdec = (int)resistance; + + return 0; +}; + +static int qcom_adc5_gen3_scale_hw_calib_usb_in_current( + const struct u32_fract *prescale, + const struct adc5_data *data, + u16 adc_code, int *result_ua) +{ + s64 voltage = 0, result = 0; + bool positive = true; + + if (adc_code & ADC5_USR_DATA_CHECK) { + adc_code = ~adc_code + 1; + positive = false; + } + + voltage = (s64)(s16) adc_code * 1000000; + voltage = div64_s64(voltage, PMIC5_GEN3_USB_IN_I_SCALE_FACTOR); + result = div64_s64(voltage * prescale->denominator, prescale->numerator); + *result_ua = (int)result; + + if (!positive) + *result_ua = -(int)result; + + return 0; +}; + static int qcom_vadc_scale_hw_chg5_temp( 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 6c5f7ed4cf64..cd11b5aba4bc 100644 --- a/include/linux/iio/adc/qcom-vadc-common.h +++ b/include/linux/iio/adc/qcom-vadc-common.h @@ -61,6 +61,8 @@ #define R_PU_100K 100000 #define RATIO_MAX_ADC7 BIT(14) +#define PMIC5_GEN3_USB_IN_I_SCALE_FACTOR 9248 + #define ADC_VDD_REF 1875000 /* @@ -161,13 +163,13 @@ struct adc_tm_client_info { * charger temperature. * SCALE_HW_CALIB_PM5_SMB_TEMP: Returns result in millidegrees for PMIC5 * SMB1390 temperature. - * SCALE_HW_CALIB_BATT_THERM_100K: Returns battery thermistor voltage in + * SCALE_HW_CALIB_BATT_THERM_100K: Returns battery thermistor temperature in * decidegC using 100k pullup. The hardware applies offset/slope to adc * code. - * SCALE_HW_CALIB_BATT_THERM_30K: Returns battery thermistor voltage in + * SCALE_HW_CALIB_BATT_THERM_30K: Returns battery thermistor temperature in * decidegC using 30k pullup. The hardware applies offset/slope to adc * code. - * SCALE_HW_CALIB_BATT_THERM_400K: Returns battery thermistor voltage in + * SCALE_HW_CALIB_BATT_THERM_400K: Returns battery thermistor temperature in * decidegC using 400k pullup. The hardware applies offset/slope to adc * code. * SCALE_HW_CALIB_PM5_SMB1398_TEMP: Returns result in millidegrees for PMIC5 @@ -184,6 +186,13 @@ struct adc_tm_client_info { * S3 die temperature channel on PM2250. * SCALE_HW_CALIB_PM5_CUR: Returns result in microamperes for PMIC5 channels * that use voltage scaling. + * SCALE_HW_CALIB_PM5_GEN3_BATT_THERM_100K: Returns battery thermistor + * temperature in decidegC using 100k pullup. The hardware applies + * offset/slope to adc code. + * SCALE_HW_CALIB_PM5_GEN3_BATT_ID_100K: Returns battery ID resistance + * in ohms using 100k pullup. The hardware applies offset/slope to + * adc code. + * SCALE_HW_CALIB_PM5_GEN3_USB_IN_I: Returns USB input current in microamperes. */ enum vadc_scale_fn_type { SCALE_DEFAULT = 0, @@ -209,6 +218,9 @@ enum vadc_scale_fn_type { SCALE_HW_CALIB_CUR_RAW, SCALE_HW_CALIB_PM2250_S3_DIE_TEMP, SCALE_HW_CALIB_PM5_CUR, + SCALE_HW_CALIB_PM5_GEN3_BATT_THERM_100K, + SCALE_HW_CALIB_PM5_GEN3_BATT_ID_100K, + SCALE_HW_CALIB_PM5_GEN3_USB_IN_I, SCALE_HW_CALIB_INVALID, };