power: pm8921-bms: increase/decrease UUC 1% at a time
We see huge jumps in Unusable Charge (UUC) as temperature, average
load or state of charge (SOC) changes, which results in huge jumps
in the reported capacity.
Increase/Decrease UUC slowly (limit 1%) each time SOC is requested.
This results in linearity improvements.
Change-Id: I82022aa499a53c5ea42e7079e96d3c94dfc0be01
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 5ddca3e..b86a026 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 prev_pc_unusable;
int adjust_soc_low_threshold;
};
@@ -1159,19 +1160,60 @@
static int calculate_uuc_uah_at_given_current(struct pm8921_bms_chip *chip,
int batt_temp, int chargecycles,
- int rbatt, int fcc_uah, int i_ma)
+ int rbatt, int fcc_uah, int i_ma,
+ int *ret_pc_unusable)
{
int unusable_uv, pc_unusable, uuc;
- /* calculate unusable charge with itest */
unusable_uv = (rbatt * i_ma) + (chip->v_cutoff * 1000);
pc_unusable = calculate_pc(chip, unusable_uv, batt_temp, chargecycles);
uuc = (fcc_uah * pc_unusable) / 100;
pr_debug("For i_ma = %d, unusable_uv = %d unusable_pc = %d uuc = %d\n",
i_ma, unusable_uv, pc_unusable, uuc);
+ *ret_pc_unusable = pc_unusable;
return uuc;
}
+static int adjust_uuc(struct pm8921_bms_chip *chip, int fcc_uah,
+ int new_pc_unusable,
+ int new_uuc,
+ int batt_temp,
+ int rbatt,
+ int *iavg_ma)
+{
+ int new_unusable_mv;
+ int batt_temp_degc = batt_temp / 10;
+
+ if (chip->prev_pc_unusable == -EINVAL
+ || abs(chip->prev_pc_unusable - new_pc_unusable) <= 1) {
+ chip->prev_pc_unusable = new_pc_unusable;
+ return new_uuc;
+ }
+
+ /* the uuc is trying to change more than 1% restrict it */
+ if (new_pc_unusable > chip->prev_pc_unusable)
+ chip->prev_pc_unusable++;
+ else
+ chip->prev_pc_unusable--;
+
+ new_uuc = (fcc_uah * chip->prev_pc_unusable) / 100;
+
+ /* also find update the iavg_ma accordingly */
+ new_unusable_mv = interpolate_ocv(chip, batt_temp_degc,
+ chip->prev_pc_unusable);
+ if (new_unusable_mv < chip->v_cutoff)
+ new_unusable_mv = chip->v_cutoff;
+
+ *iavg_ma = (new_unusable_mv - chip->v_cutoff) * 1000 / rbatt;
+ if (*iavg_ma == 0)
+ *iavg_ma = 1;
+ pr_debug("Restricting UUC to %d (%d%%) unusable_mv = %d iavg_ma = %d\n",
+ new_uuc, chip->prev_pc_unusable,
+ new_unusable_mv, *iavg_ma);
+
+ return new_uuc;
+}
+
static void calculate_iavg_ua(struct pm8921_bms_chip *chip, int cc_uah,
int *iavg_ua, int *delta_time_s)
{
@@ -1254,6 +1296,7 @@
static int iavg_index;
static int iavg_num_samples;
static int firsttime = 1;
+ int pc_unusable;
/*
* if we are called first time fill all the
@@ -1294,8 +1337,15 @@
uuc_uah_iavg = calculate_uuc_uah_at_given_current(chip,
batt_temp, chargecycles,
- rbatt, fcc_uah, iavg_ma);
+ rbatt, fcc_uah, iavg_ma,
+ &pc_unusable);
pr_debug("iavg = %d uuc_iavg = %d\n", iavg_ma, uuc_uah_iavg);
+
+ /* restrict the uuc such that it can increase only by one percent */
+ uuc_uah_iavg = adjust_uuc(chip, fcc_uah, pc_unusable, uuc_uah_iavg,
+ batt_temp, rbatt, &iavg_ma);
+
+ /* find out what the avg current should be for this uuc */
chip->prev_uuc_iavg_ma = iavg_ma;
firsttime = 0;
@@ -1693,6 +1743,7 @@
int soc_rbatt;
int iavg_ma;
int num_tries = 0;
+ int pc_unusable;
iavg_ma = chip->prev_uuc_iavg_ma;
@@ -1711,7 +1762,8 @@
rbatt = new_rbatt;
uuc_uah = calculate_uuc_uah_at_given_current(chip,
batt_temp, chargecycles,
- new_rbatt, fcc_uah, iavg_ma);
+ new_rbatt, fcc_uah, iavg_ma,
+ &pc_unusable);
pr_debug("rbatt not settled uuc = %d for rbatt = %d iavg_ma = %d num_tries = %d\n",
uuc_uah, rbatt, iavg_ma, num_tries);
@@ -3060,6 +3112,8 @@
if (chip->adjust_soc_low_threshold >= 45)
chip->adjust_soc_low_threshold = 45;
+ chip->prev_pc_unusable = -EINVAL;
+
chip->ignore_shutdown_soc = pdata->ignore_shutdown_soc;
rc = set_battery_data(chip);
if (rc) {