power: pm8921-bms: limit voltage correction
The "adjust_soc" algorithm where we change the open circuit voltage
(ocv) in steps so that the state of charge (soc) starts approaching
the estimated soc, causes nonlinearity in the soc curves if an incorrect
resistance value is fed to the algorithm.
As battery ages and temperature changes, it is hard to estimate the
exact battery resistance.
So to fix the nonlinearity, limit the amount by which the ocv is
changed. Make it proportional to the current, i.e. change ocv by
small amounts in light load and let it change by proportionally
large amounts in heavy load situations.
Also, make the point where the soc is adjusted configurable via platform
data instead of forcing it to 25%.
Change-Id: Idc141e6bf3172dab278afe1900f5a1f9cdd624dd
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064-pmic.c b/arch/arm/mach-msm/board-8064-pmic.c
index 518579a..1f39d3f 100644
--- a/arch/arm/mach-msm/board-8064-pmic.c
+++ b/arch/arm/mach-msm/board-8064-pmic.c
@@ -394,6 +394,7 @@
.v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
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 384b1cf..c16f55d 100644
--- a/arch/arm/mach-msm/board-8930-pmic.c
+++ b/arch/arm/mach-msm/board-8930-pmic.c
@@ -345,6 +345,7 @@
.v_cutoff = 3400,
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
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 98140b4..46d317b 100644
--- a/arch/arm/mach-msm/board-8960-pmic.c
+++ b/arch/arm/mach-msm/board-8960-pmic.c
@@ -426,6 +426,7 @@
.max_voltage_uv = MAX_VOLTAGE_MV * 1000,
.rconn_mohm = 18,
.shutdown_soc_valid_limit = 20,
+ .adjust_soc_low_threshold = 25,
};
#define PM8921_LC_LED_MAX_CURRENT 4 /* I = 4mA */
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index f26ecd9..5ddca3e 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -142,6 +142,7 @@
int ignore_shutdown_soc;
int prev_iavg_ua;
int prev_uuc_iavg_ma;
+ int adjust_soc_low_threshold;
};
/*
@@ -1440,6 +1441,7 @@
int soc_new = 0;
int m = 0;
int rc = 0;
+ int delta_ocv_uv_limit = 0;
rc = pm8921_bms_get_simultaneous_battery_voltage_and_current(
&ibat_ua,
@@ -1452,6 +1454,9 @@
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;
pc_est = calculate_pc(chip, ocv_est_uv, batt_temp, last_chargecycles);
soc_est = div_s64((s64)fcc_uah * pc_est - uuc_uah*100,
@@ -1469,7 +1474,8 @@
* and cause a bad user experience
*/
if (soc_est == soc
- || (is_between(45, 25, soc_est) && is_between(50, 20, soc))
+ || (is_between(45, chip->adjust_soc_low_threshold, soc_est)
+ && is_between(50, chip->adjust_soc_low_threshold - 5, soc))
|| soc >= 90)
goto out;
@@ -1504,6 +1510,18 @@
delta_ocv_uv = div_s64((soc - soc_est) * (s64)m * 1000,
n * (pc - pc_new));
+
+ if (abs(delta_ocv_uv) > delta_ocv_uv_limit) {
+ pr_debug("limiting delta ocv %d limit = %d\n", delta_ocv_uv,
+ delta_ocv_uv_limit);
+
+ if (delta_ocv_uv > 0)
+ delta_ocv_uv = delta_ocv_uv_limit;
+ else
+ delta_ocv_uv = -1 * delta_ocv_uv_limit;
+ pr_debug("new delta ocv = %d\n", delta_ocv_uv);
+ }
+
chip->last_ocv_uv -= delta_ocv_uv;
if (chip->last_ocv_uv >= chip->max_voltage_uv)
@@ -3038,6 +3056,10 @@
chip->start_percent = -EINVAL;
chip->end_percent = -EINVAL;
chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
+ chip->adjust_soc_low_threshold = pdata->adjust_soc_low_threshold;
+ if (chip->adjust_soc_low_threshold >= 45)
+ chip->adjust_soc_low_threshold = 45;
+
chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
rc = set_battery_data(chip);
if (rc) {
diff --git a/include/linux/mfd/pm8xxx/pm8921-bms.h b/include/linux/mfd/pm8xxx/pm8921-bms.h
index 070b4a9..d1438d1 100644
--- a/include/linux/mfd/pm8xxx/pm8921-bms.h
+++ b/include/linux/mfd/pm8xxx/pm8921-bms.h
@@ -132,6 +132,7 @@
int enable_fcc_learning;
int shutdown_soc_valid_limit;
int ignore_shutdown_soc;
+ int adjust_soc_low_threshold;
};
#if defined(CONFIG_PM8921_BMS) || defined(CONFIG_PM8921_BMS_MODULE)