From 2acc8a93ff9a6c6b3ebb1993b4fb12af483b75ff Mon Sep 17 00:00:00 2001 From: Abhijeet Dharmapurikar Date: Mon, 6 Aug 2012 14:02:51 -0700 Subject: [PATCH] power: pm8921-bms: charging curve adjustments It was observed that while charging the reported soc sometimes reaches 100% before end of charging happens. At other times it does not reach 100% at end of charge and a abrupt jump to 100% soc happens. Fix this by linearly increasing soc based on battery charge current after constant voltage phase is reached. Constant voltage phase is reached when battery voltage reaches the max value. Also once constant voltage phase is reached and the voltage or charge current decreases keep reporting the earlier soc. This could be because of a transient system load. Change-Id: I14c2f42d7897041db038ce85ce1124cf1ef261af Signed-off-by: Abhijeet Dharmapurikar --- arch/arm/mach-msm/board-8064-pmic.c | 17 ++++--- arch/arm/mach-msm/board-8930-pmic.c | 16 +++--- arch/arm/mach-msm/board-8960-pmic.c | 18 ++++--- drivers/power/pm8921-bms.c | 70 +++++++++++++++++++++++++-- include/linux/mfd/pm8xxx/pm8921-bms.h | 1 + 5 files changed, 95 insertions(+), 27 deletions(-) diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c index 1f39d3f2cbfa..0f1ddc09b41c 100644 --- a/arch/arm/mach-msm/board-8064-pmic.c +++ b/arch/arm/mach-msm/board-8064-pmic.c @@ -360,6 +360,7 @@ static int apq8064_pm8921_therm_mitigation[] = { }; #define MAX_VOLTAGE_MV 4200 +#define CHG_TERM_MA 100 static struct pm8921_charger_platform_data apq8064_pm8921_chg_pdata __devinitdata = { .safety_time = 180, @@ -368,7 +369,7 @@ apq8064_pm8921_chg_pdata __devinitdata = { .min_voltage = 3200, .uvd_thresh_voltage = 4050, .resume_voltage_delta = 100, - .term_current = 100, + .term_current = CHG_TERM_MA, .cool_temp = 10, .warm_temp = 40, .temp_check_period = 1, @@ -389,12 +390,14 @@ apq8064_pm8xxx_ccadc_pdata = { static struct pm8921_bms_platform_data apq8064_pm8921_bms_pdata __devinitdata = { - .battery_type = BATT_UNKNOWN, - .r_sense = 10, - .v_cutoff = 3400, - .max_voltage_uv = MAX_VOLTAGE_MV * 1000, - .shutdown_soc_valid_limit = 20, - .adjust_soc_low_threshold = 25, + .battery_type = BATT_UNKNOWN, + .r_sense = 10, + .v_cutoff = 3400, + .max_voltage_uv = MAX_VOLTAGE_MV * 1000, + .rconn_mohm = 18, + .shutdown_soc_valid_limit = 20, + .adjust_soc_low_threshold = 25, + .chg_term_ua = CHG_TERM_MA * 1000, }; static struct pm8921_platform_data diff --git a/arch/arm/mach-msm/board-8930-pmic.c b/arch/arm/mach-msm/board-8930-pmic.c index c16f55dc8c5d..e3479eb092d8 100644 --- a/arch/arm/mach-msm/board-8930-pmic.c +++ b/arch/arm/mach-msm/board-8930-pmic.c @@ -207,6 +207,7 @@ static int pm8921_therm_mitigation[] = { }; #define MAX_VOLTAGE_MV 4200 +#define CHG_TERM_MA 100 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = { .safety_time = 180, .update_time = 60000, @@ -214,7 +215,7 @@ static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = { .min_voltage = 3200, .uvd_thresh_voltage = 4050, .resume_voltage_delta = 100, - .term_current = 100, + .term_current = CHG_TERM_MA, .cool_temp = 10, .warm_temp = 40, .temp_check_period = 1, @@ -340,12 +341,13 @@ static struct pm8xxx_spk_platform_data pm8xxx_spk_pdata = { }; static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = { - .battery_type = BATT_UNKNOWN, - .r_sense = 10, - .v_cutoff = 3400, - .max_voltage_uv = MAX_VOLTAGE_MV * 1000, - .shutdown_soc_valid_limit = 20, - .adjust_soc_low_threshold = 25, + .battery_type = BATT_UNKNOWN, + .r_sense = 10, + .v_cutoff = 3400, + .max_voltage_uv = MAX_VOLTAGE_MV * 1000, + .shutdown_soc_valid_limit = 20, + .adjust_soc_low_threshold = 25, + .chg_term_ua = CHG_TERM_MA * 1000, }; static struct pm8038_platform_data pm8038_platform_data __devinitdata = { diff --git a/arch/arm/mach-msm/board-8960-pmic.c b/arch/arm/mach-msm/board-8960-pmic.c index 46d317b62345..8d75ee97dc83 100644 --- a/arch/arm/mach-msm/board-8960-pmic.c +++ b/arch/arm/mach-msm/board-8960-pmic.c @@ -394,6 +394,7 @@ static int pm8921_therm_mitigation[] = { }; #define MAX_VOLTAGE_MV 4200 +#define CHG_TERM_MA 100 static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = { .safety_time = 180, .update_time = 60000, @@ -401,7 +402,7 @@ static struct pm8921_charger_platform_data pm8921_chg_pdata __devinitdata = { .min_voltage = 3200, .uvd_thresh_voltage = 4050, .resume_voltage_delta = 100, - .term_current = 100, + .term_current = CHG_TERM_MA, .cool_temp = 10, .warm_temp = 40, .temp_check_period = 1, @@ -420,13 +421,14 @@ static struct pm8xxx_misc_platform_data pm8xxx_misc_pdata = { }; static struct pm8921_bms_platform_data pm8921_bms_pdata __devinitdata = { - .battery_type = BATT_UNKNOWN, - .r_sense = 10, - .v_cutoff = 3400, - .max_voltage_uv = MAX_VOLTAGE_MV * 1000, - .rconn_mohm = 18, - .shutdown_soc_valid_limit = 20, - .adjust_soc_low_threshold = 25, + .battery_type = BATT_UNKNOWN, + .r_sense = 10, + .v_cutoff = 3400, + .max_voltage_uv = MAX_VOLTAGE_MV * 1000, + .rconn_mohm = 18, + .shutdown_soc_valid_limit = 20, + .adjust_soc_low_threshold = 25, + .chg_term_ua = CHG_TERM_MA * 1000, }; #define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */ diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c index 88e0948c1974..86cdc5f744f3 100644 --- a/drivers/power/pm8921-bms.c +++ b/drivers/power/pm8921-bms.c @@ -122,6 +122,7 @@ struct pm8921_bms_chip { int cc_reading_at_100; int max_voltage_uv; + int chg_term_ua; int default_rbatt_mohm; int amux_2_trim_delta; uint16_t prev_last_good_ocv_raw; @@ -144,6 +145,10 @@ struct pm8921_bms_chip { int prev_uuc_iavg_ma; int prev_pc_unusable; int adjust_soc_low_threshold; + + int ibat_at_cv_ua; + int soc_at_cv; + int prev_chg_soc; }; /* @@ -1510,6 +1515,53 @@ static int bound_soc(int soc) return soc; } +static int charging_adjustments(struct pm8921_bms_chip *chip, + int soc, int vbat_uv, int ibat_ua) +{ + int chg_soc; + + if (chip->soc_at_cv == -EINVAL) { + /* In constant current charging return the calc soc */ + if (vbat_uv <= chip->max_voltage_uv) + pr_debug("CC CHG SOC %d\n", soc); + + /* Note the CC to CV point */ + if (vbat_uv >= chip->max_voltage_uv) { + chip->soc_at_cv = soc; + chip->prev_chg_soc = soc; + chip->ibat_at_cv_ua = ibat_ua; + pr_debug("CC_TO_CV ibat_ua = %d CHG SOC %d\n", + ibat_ua, soc); + } + return soc; + } + + /* + * battery is in CV phase - begin liner inerpolation of soc based on + * battery charge current + */ + + /* + * if voltage lessened (possibly because of a system load) + * keep reporting the prev chg soc + */ + if (vbat_uv <= chip->max_voltage_uv) { + pr_debug("CC CHG SOC %d\n", chip->prev_chg_soc); + return chip->prev_chg_soc; + } + + chg_soc = linear_interpolate(chip->soc_at_cv, chip->ibat_at_cv_ua, + 100, -100000, + ibat_ua); + + /* always report a higher soc */ + if (chg_soc > chip->prev_chg_soc) + chip->prev_chg_soc = chg_soc; + + pr_debug("CHG SOC %d\n", chip->prev_chg_soc); + return chip->prev_chg_soc; +} + static int last_soc_est = -EINVAL; static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp, int rbatt , int fcc_uah, int uuc_uah, int cc_uah) @@ -1534,9 +1586,6 @@ static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp, } - if (ibat_ua < 0) - goto out; - delta_ocv_uv_limit = DIV_ROUND_CLOSEST(ibat_ua, 1000); ocv_est_uv = vbat_uv + (ibat_ua * rbatt)/1000; @@ -1545,6 +1594,11 @@ static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp, (s64)fcc_uah - uuc_uah); soc_est = bound_soc(soc_est); + if (ibat_ua < 0) { + soc = charging_adjustments(chip, soc, vbat_uv, ibat_ua); + goto out; + } + /* * do not adjust * if soc is same as what bms calculated @@ -1628,10 +1682,10 @@ static int adjust_soc(struct pm8921_bms_chip *chip, int soc, int batt_temp, out: pr_debug("ibat_ua = %d, vbat_uv = %d, ocv_est_uv = %d, pc_est = %d, " "soc_est = %d, n = %d, delta_ocv_uv = %d, last_ocv_uv = %d, " - "pc_new = %d, soc_new = %d\n", + "pc_new = %d, soc_new = %d, rbatt = %d, m = %d\n", ibat_ua, vbat_uv, ocv_est_uv, pc_est, soc_est, n, delta_ocv_uv, chip->last_ocv_uv, - pc_new, soc_new); + pc_new, soc_new, rbatt, m); return soc; } @@ -2402,6 +2456,9 @@ void pm8921_bms_charging_began(void) IBAT_TOL_MASK, IBAT_TOL_DEFAULT); the_chip->charge_time_us = 0; the_chip->catch_up_time_us = 0; + + the_chip->soc_at_cv = -EINVAL; + the_chip->prev_chg_soc = -EINVAL; pr_debug("start_percent = %u%%\n", the_chip->start_percent); } EXPORT_SYMBOL_GPL(pm8921_bms_charging_began); @@ -2507,6 +2564,8 @@ void pm8921_bms_charging_end(int is_battery_full) the_chip->end_percent = -EINVAL; the_chip->charge_time_us = 0; the_chip->catch_up_time_us = 0; + the_chip->soc_at_cv = -EINVAL; + the_chip->prev_chg_soc = -EINVAL; pm_bms_masked_write(the_chip, BMS_TOLERANCES, IBAT_TOL_MASK, IBAT_TOL_NOCHG); } @@ -3107,6 +3166,7 @@ static int __devinit pm8921_bms_probe(struct platform_device *pdev) chip->r_sense = pdata->r_sense; chip->v_cutoff = pdata->v_cutoff; chip->max_voltage_uv = pdata->max_voltage_uv; + chip->chg_term_ua = pdata->chg_term_ua; chip->batt_type = pdata->battery_type; chip->rconn_mohm = pdata->rconn_mohm; chip->start_percent = -EINVAL; diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h index d1438d1c2b3b..a73a2849b6d2 100644 --- a/include/linux/mfd/pm8xxx/pm8921-bms.h +++ b/include/linux/mfd/pm8xxx/pm8921-bms.h @@ -133,6 +133,7 @@ struct pm8921_bms_platform_data { int shutdown_soc_valid_limit; int ignore_shutdown_soc; int adjust_soc_low_threshold; + int chg_term_ua; }; #if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)