From 23397aa1ac8d49d8411e13e1253bf9d89618ee0f Mon Sep 17 00:00:00 2001 From: Shengfei Xu Date: Wed, 7 May 2025 17:32:59 +0800 Subject: [PATCH] power: supply: rk817_battery: Add auto-stage switching for TS crossflow Added automatic stage switching functionality for the TS crossflow current source. To mitigate the impact of contact resistance and enhance the sampling accuracy of the thermistor voltage, the current strategy prioritizes using higher current ranges of the TS constant current source while remaining within the ADC's sampling range. The system now employs software-based monitoring of the thermistor's voltage to dynamically adjust the current source's output stage. Change-Id: I92e9165280c932b987b85530a9b6792c6b817187 Signed-off-by: Shengfei Xu --- drivers/power/supply/rk817_battery.c | 95 +++++++++++++++++++++++++--- 1 file changed, 85 insertions(+), 10 deletions(-) diff --git a/drivers/power/supply/rk817_battery.c b/drivers/power/supply/rk817_battery.c index 953b6d8da6ea..ad2871c53c7b 100644 --- a/drivers/power/supply/rk817_battery.c +++ b/drivers/power/supply/rk817_battery.c @@ -130,6 +130,9 @@ module_param_named(dbg_level, dbg_enable, int, 0644); /* OCV Table Percentage Accuracy: 5.000% */ #define OCV_TABLE_STEP 5000 +#define TS_MAX_VOL 1100 +#define TS_MIN_VOL 500 + enum ts_fun { TS_FUN_SOURCE_CURRENT, TS_FUN_VOLTAGE_INPUT, @@ -223,7 +226,7 @@ enum rk817_battery_fields { RELAX_CUR1_H, RELAX_CUR1_L, RELAX_CUR2_H, RELAX_CUR2_L, CHRG_BAT_TAB2, CHRG_INCC_ZERO, CHRG_BATHIAUTO_EN, - PWRON_VOL_H, PWRON_VOL_L, + VOL_ADC_TSCUR_SEL_SWITCH, PWRON_VOL_H, PWRON_VOL_L, PWRON_CUR_H, PWRON_CUR_L, OFF_CNT, Q_INIT_H3, Q_INIT_H2, Q_INIT_L1, Q_INIT_L0, @@ -326,6 +329,7 @@ static const struct reg_field rk817_battery_reg_fields[] = { [CHRG_INCC_ZERO] = REG_FIELD(0x62, 6, 6), [CHRG_BATHIAUTO_EN] = REG_FIELD(0x62, 5, 5), + [VOL_ADC_TSCUR_SEL_SWITCH] = REG_FIELD(0x66, 7, 7), [PWRON_VOL_H] = REG_FIELD(0x6B, 0, 7), [PWRON_VOL_L] = REG_FIELD(0x6C, 0, 7), [PWRON_CUR_H] = REG_FIELD(0x6D, 0, 7), @@ -1416,10 +1420,21 @@ static void rk817_bat_init_ts_detect(struct rk817_battery_device *battery) rk817_bat_enable_charge(battery); } -static void rk817_bat_temperature_chrg(struct rk817_battery_device *battery, int temp) +static void rk817_bat_temperature_chrg(struct rk817_battery_device *battery, int now_temp) { int i, up_temp, down_temp; - int now_temp = temp; + int num; + + if (!battery->pdata->tc_count) + return; + + num = battery->pdata->tc_count; + if ((now_temp < battery->pdata->tc_table[0].temp_down) || + (now_temp > battery->pdata->tc_table[num - 1].temp_up)) + rk817_bat_disable_charge(battery); + else if ((now_temp > battery->pdata->tc_table[0].temp_down + 2) && + (now_temp < battery->pdata->tc_table[num - 1].temp_up - 2)) + rk817_bat_enable_charge(battery); for (i = 0; i < battery->pdata->tc_count; i++) { up_temp = battery->pdata->tc_table[i].temp_up; @@ -1452,7 +1467,7 @@ static void rk817_bat_temperature_chrg(struct rk817_battery_device *battery, int battery->pdata->tc_table[i].chrg_voltage, battery->pdata->tc_table[i].chrg_voltage_index); } else - rk817_bat_enable_charge(battery); + rk817_bat_disable_charge(battery); battery->charge_index = i; } @@ -1469,21 +1484,81 @@ static int rk817_bat_get_bat_ts(struct rk817_battery_device *battery) return temp_value; } +static int rk817_bat_tscure_sel_switch(struct rk817_battery_device *battery, int tsvol) +{ + int current_gear = battery->pdata->ntc_factor; + int new_gear = current_gear; + int i, index = -1; + /* Define gear sequence and corresponding parameters */ + const struct { + int gear; + int sel_switch; + int flow_out; + } gear_table[] = { + {40, 0, FLOW_OUT_30uA}, + {30, 0, FLOW_OUT_20uA}, + {20, 0, FLOW_OUT_10uA}, + {10, 0, FLOW_OUT_10uA} /* Last gear */ + }; + + /* find current gear index */ + for (i = 0; i < ARRAY_SIZE(gear_table); i++) { + if (gear_table[i].gear == current_gear) { + index = i; + break; + } + } + + /* invalid current gear */ + if (index < 0) + return -EINVAL; + + /* gear switching logic */ + if (tsvol > TS_MAX_VOL) { + /* Move to lower gear */ + if (index < ARRAY_SIZE(gear_table) - 1) { + new_gear = gear_table[index + 1].gear; + rk817_bat_field_write(battery, + VOL_ADC_TSCUR_SEL, + gear_table[index + 1].flow_out); + } + } else if (tsvol < TS_MIN_VOL) { + /* Move to higher gear */ + if (index > 0) { + new_gear = gear_table[index - 1].gear; + rk817_bat_field_write(battery, + VOL_ADC_TSCUR_SEL, + gear_table[index - 1].flow_out); + } + } + + /* Update gear only if changed */ + if (new_gear != current_gear) { + battery->pdata->ntc_factor = new_gear; + DBG("%s: Gear changed from %d to %d\n", __func__, current_gear, new_gear); + } + + return 0; +} + static int rk817_bat_get_ntc_res(struct rk817_battery_device *battery) { int temp_value, res; - int adc_to_vol; int bat_current; + int tsvol; temp_value = rk817_bat_get_bat_ts(battery); - adc_to_vol = temp_value * 1200 / 65536; + tsvol = temp_value * 1200 / 65536; bat_current = rk817_bat_get_avg_current(battery); - res = (adc_to_vol * 1000 - bat_current * battery->pdata->contact_res) / + res = (tsvol * 1000 - bat_current * battery->pdata->contact_res) / battery->pdata->ntc_factor; - DBG("NTC: ADC: value: 0x%x, adc2vol:%d, res: %d, contact_res: %d\n", - temp_value, adc_to_vol, res, battery->pdata->contact_res); + DBG("NTC: ADC: value: 0x%x, adc2vol:%d, res: %d, contact_res: %d, current: %d, ntc_factor: %duA\n", + temp_value, tsvol, res, battery->pdata->contact_res, + bat_current, battery->pdata->ntc_factor); + + rk817_bat_tscure_sel_switch(battery, tsvol); return res; } @@ -1552,7 +1627,7 @@ static void rk817_bat_calculate_contact_res(struct rk817_battery_device *battery return; if (battery->pdata->contact_res) return; - if ((battery->temperature < 150) || (battery->temperature > 450)) + if ((battery->temperature < 150) || (battery->temperature > 350)) return; if ((battery->ts_info.ts40uA_update == 1) && (battery->ts_info.ts10uA_update == 0))