power: pm8921-bms: change power on ocv if soc < 0
When a phone boots up with a weak battery the ocv (open circuit voltage)
is so low that we end up in a -ve soc.
If a charger is plugged in, it takes a while for that -ve soc to reach
0. Until then the reported soc is returned 0. (note the driver
never reports a -ve soc). This creates an impression that it takes very
long to go from 0% to 1%.
Change this by bumping up the pon ocv a bit such that soc is reported
exact 0.
Change-Id: I3244723845920c9538dff7e72dab253fd4aa7e2b
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 4de5752..b69ad11 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -1515,24 +1515,6 @@
pr_debug("shutdown_soc = %d\n", chip->shutdown_soc);
}
-void pm8921_bms_invalidate_shutdown_soc(void)
-{
- pr_debug("Invalidating shutdown soc - the battery was removed\n");
- mutex_lock(&soc_invalidation_mutex);
- shutdown_soc_invalid = 1;
- last_soc = -EINVAL;
- if (the_chip) {
- /* reset to pon ocv undoing what the adjusting did */
- if (the_chip->pon_ocv_uv) {
- the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
- pr_debug("resetting ocv to pon_ocv = %d\n",
- the_chip->pon_ocv_uv);
- }
- }
- mutex_unlock(&soc_invalidation_mutex);
-}
-EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
-
static void find_ocv_for_soc(struct pm8921_bms_chip *chip,
int batt_temp,
int chargecycles,
@@ -1575,45 +1557,27 @@
*rc_uah = (int)rc;
}
-static void adjust_rc_and_uuc_for_shutdown_soc(
+static void adjust_rc_and_uuc_for_specific_soc(
struct pm8921_bms_chip *chip,
int batt_temp,
int chargecycles,
+ int soc,
int fcc_uah,
int uuc_uah,
int cc_uah,
- int remaining_charge_uah,
+ int rc_uah,
int rbatt,
+ int *ret_ocv,
int *ret_rc,
int *ret_uuc,
int *ret_rbatt)
{
int new_rbatt;
int ocv_uv;
- int shutdown_soc;
- int rc_uah;
int soc_rbatt;
int iavg_ua, iavg_ma;
int num_tries = 0;
- mutex_lock(&soc_invalidation_mutex);
- shutdown_soc = chip->shutdown_soc;
- /*
- * value of zero means the shutdown soc should not be used, the battery
- * was removed for extended period, the coincell capacitor could have
- * drained
- * shutdown_soc_invalid means the shutdown soc should not be used,
- * the battery was removed for a small period
- */
- if (shutdown_soc == 0 || shutdown_soc_invalid) {
- rc_uah = remaining_charge_uah;
- goto out;
- }
-
- /* value of 0xFF means shutdown soc was 0% */
- if (shutdown_soc == 0xFF)
- shutdown_soc = 0;
-
pm8921_bms_get_battery_current(&iavg_ua);
iavg_ma = iavg_ua / 1000;
if (iavg_ma < 0)
@@ -1623,13 +1587,13 @@
find_ocv_for_soc(chip, batt_temp, chargecycles,
fcc_uah, uuc_uah, cc_uah,
- shutdown_soc,
+ soc,
&rc_uah, &ocv_uv);
soc_rbatt = div_s64((rc_uah - cc_uah) * 100, fcc_uah);
new_rbatt = get_rbatt(chip, soc_rbatt, batt_temp);
- pr_debug("for s_soc = %d rc_uah = %d ocv_uv = %d, soc_rbatt = %d rbatt = %d\n",
- shutdown_soc, rc_uah, ocv_uv, soc_rbatt, new_rbatt);
+ pr_debug("for f_soc = %d rc_uah = %d ocv_uv = %d, soc_rbatt = %d rbatt = %d\n",
+ soc, rc_uah, ocv_uv, soc_rbatt, new_rbatt);
if (abs(new_rbatt - rbatt) > 20 && num_tries < 10) {
rbatt = new_rbatt;
uuc_uah = calculate_uuc_uah_at_given_current(chip,
@@ -1642,15 +1606,12 @@
goto recalculate_ocv;
}
pr_debug("DONE for s_soc = %d rc_uah = %d ocv_uv = %d, rbatt = %d\n",
- shutdown_soc, rc_uah, ocv_uv, new_rbatt);
+ soc, rc_uah, ocv_uv, new_rbatt);
- chip->pon_ocv_uv = chip->last_ocv_uv;
- chip->last_ocv_uv = ocv_uv;
-out:
+ *ret_ocv = ocv_uv;
*ret_rbatt = rbatt;
*ret_rc = rc_uah;
*ret_uuc = uuc_uah;
- mutex_unlock(&soc_invalidation_mutex);
}
#define SOC_CATCHUP_SEC_MAX 600
@@ -1750,9 +1711,11 @@
int rbatt;
int iavg_ua;
int delta_time_us;
+ int new_ocv;
int new_rc_uah;
int new_ucc_uah;
int new_rbatt;
+ int shutdown_soc;
calculate_soc_params(chip, raw, batt_temp, chargecycles,
&fcc_uah,
@@ -1778,9 +1741,39 @@
(fcc_uah - unusable_charge_uah));
}
+ if (delta_time_us == 0 && soc < 0) {
+ /*
+ * first time calcualtion and the pon ocv is too low resulting
+ * in a bad soc. Adjust ocv such that we get 0 soc
+ */
+ pr_debug("soc is %d, adjusting pon ocv to make it 0\n", soc);
+ adjust_rc_and_uuc_for_specific_soc(
+ chip,
+ batt_temp, chargecycles,
+ 0,
+ fcc_uah, unusable_charge_uah,
+ cc_uah, remaining_charge_uah,
+ rbatt,
+ &new_ocv,
+ &new_rc_uah, &new_ucc_uah,
+ &new_rbatt);
+ chip->last_ocv_uv = new_ocv;
+ remaining_charge_uah = new_rc_uah;
+ unusable_charge_uah = new_ucc_uah;
+ rbatt = new_rbatt;
+
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
+ soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+ (fcc_uah - unusable_charge_uah));
+ pr_debug("DONE for O soc is %d, pon ocv adjusted to %duV\n",
+ soc, chip->last_ocv_uv);
+ }
+
if (soc > 100)
soc = 100;
- pr_debug("before adjusting calculated SOC = %d%%\n", soc);
if (bms_fake_battery != -EINVAL) {
pr_debug("Returning Fake SOC = %d%%\n", bms_fake_battery);
@@ -1802,28 +1795,49 @@
soc = 0;
}
- if (delta_time_us == 0 && is_shutdown_soc_within_limits(chip, soc)) {
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc = chip->shutdown_soc;
+ /* value of 0xFF means shutdown soc was 0% */
+ if (shutdown_soc == 0xFF)
+ shutdown_soc = 0;
+
+ if (delta_time_us == 0 && soc != shutdown_soc
+ && is_shutdown_soc_within_limits(chip, soc)) {
/*
* soc for the first time - use shutdown soc
* to adjust pon ocv since it is a small percent away from
* the real soc
*/
- adjust_rc_and_uuc_for_shutdown_soc(
+ pr_debug("soc = %d before forcing shutdown_soc = %d\n",
+ soc, shutdown_soc);
+ adjust_rc_and_uuc_for_specific_soc(
chip,
batt_temp, chargecycles,
+ shutdown_soc,
fcc_uah, unusable_charge_uah,
cc_uah, remaining_charge_uah,
rbatt,
+ &new_ocv,
&new_rc_uah, &new_ucc_uah,
&new_rbatt);
+ chip->pon_ocv_uv = chip->last_ocv_uv;
+ chip->last_ocv_uv = new_ocv;
remaining_charge_uah = new_rc_uah;
unusable_charge_uah = new_ucc_uah;
rbatt = new_rbatt;
+ remaining_usable_charge_uah = remaining_charge_uah
+ - cc_uah
+ - unusable_charge_uah;
+
soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
(fcc_uah - unusable_charge_uah));
+
+ pr_debug("DONE for shutdown_soc = %d soc is %d, adjusted ocv to %duV\n",
+ shutdown_soc, soc, chip->last_ocv_uv);
}
+ mutex_unlock(&soc_invalidation_mutex);
calculated_soc = adjust_soc(chip, soc, batt_temp,
rbatt, fcc_uah, unusable_charge_uah, cc_uah);
@@ -1953,6 +1967,50 @@
return last_soc;
}
+void pm8921_bms_invalidate_shutdown_soc(void)
+{
+ int calculate_soc = 0;
+ struct pm8921_bms_chip *chip = the_chip;
+ int batt_temp, rc;
+ struct pm8xxx_adc_chan_result result;
+ struct pm8921_soc_params raw;
+ int soc;
+
+ pr_debug("Invalidating shutdown soc - the battery was removed\n");
+ mutex_lock(&soc_invalidation_mutex);
+ shutdown_soc_invalid = 1;
+ last_soc = -EINVAL;
+ if (the_chip) {
+ /* reset to pon ocv undoing what the adjusting did */
+ if (the_chip->pon_ocv_uv) {
+ the_chip->last_ocv_uv = the_chip->pon_ocv_uv;
+ calculate_soc = 1;
+ pr_debug("resetting ocv to pon_ocv = %d\n",
+ the_chip->pon_ocv_uv);
+ }
+ }
+ mutex_unlock(&soc_invalidation_mutex);
+ if (!calculate_soc)
+ return;
+
+ rc = pm8xxx_adc_read(chip->batt_temp_channel, &result);
+ if (rc) {
+ pr_err("error reading adc channel = %d, rc = %d\n",
+ chip->batt_temp_channel, rc);
+ return;
+ }
+ pr_debug("batt_temp phy = %lld meas = 0x%llx\n", result.physical,
+ result.measurement);
+ batt_temp = (int)result.physical;
+
+ mutex_lock(&chip->last_ocv_uv_mutex);
+ read_soc_params_raw(chip, &raw);
+
+ soc = calculate_state_of_charge(chip, &raw,
+ batt_temp, last_chargecycles);
+ mutex_unlock(&chip->last_ocv_uv_mutex);
+}
+EXPORT_SYMBOL(pm8921_bms_invalidate_shutdown_soc);
#define MIN_DELTA_625_UV 1000
static void calib_hkadc(struct pm8921_bms_chip *chip)
{