power: pm8921-bms: Fine tune SOC reporting during suspend/resume
Report SOC based on the time for which the system was suspended.
Remember -
1. If we recalculated the SOC in resume
2. The last_soc before going into suspend
Two cases arise - if we had a short suspend or if the suspend
was significant to case a drop in SOC. For the former do not
report a change in SOC and for the latter, report the
newly calculated_soc. In either of the cases, soc should not
increase because we cannot suspend while charging.
There is a possibility that the report_soc may be called
before BMS resume (update_power_supply), causing the driver
to report the old SOC. Handle this case by setting state
variables before recalculating the soc in resume.
CRs-Fixed: 482611
Change-Id: Ic21a24a1126800011f5e7e4531c1953436812811
Signed-off-by: Anirudh Ghayal <aghayal@codeaurora.org>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index b1958aa..0032ea8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -178,7 +178,8 @@
int low_voltage_detect;
int vbatt_cutoff_retries;
bool first_report_after_suspend;
- int calc_soc_at_suspend;
+ bool soc_updated_on_resume;
+ int last_soc_at_suspend;
};
/*
@@ -2389,10 +2390,11 @@
rbatt, fcc_uah, unusable_charge_uah, cc_uah);
pr_debug("calculated SOC = %d\n", new_calculated_soc);
- if (new_calculated_soc != calculated_soc)
+ if (new_calculated_soc != calculated_soc) {
+ calculated_soc = new_calculated_soc;
update_power_supply(chip);
+ }
- calculated_soc = new_calculated_soc;
firsttime = 0;
get_current_time(&chip->last_recalc_time);
@@ -2499,30 +2501,28 @@
if (last_soc != -EINVAL && last_soc < soc && soc != 100)
soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
- /* restrict soc to 1% change unless reporting 1st time after suspend */
- if (chip->first_report_after_suspend == true) {
- chip->first_report_after_suspend = false;
- if (last_soc != -EINVAL) {
- if (last_soc < soc)
+ if (last_soc != -EINVAL) {
+ if (chip->first_report_after_suspend) {
+ chip->first_report_after_suspend = false;
+ if (chip->soc_updated_on_resume) {
+ /* coming here after a long suspend */
+ chip->soc_updated_on_resume = false;
+ if (last_soc < soc)
+ /* if soc has falsely increased during
+ * suspend, set the soc_at_suspend
+ */
+ soc = chip->last_soc_at_suspend;
+ } else {
/*
- * can't suspend while charging
- * don't report the increased the soc
+ * suspended for a short time
+ * report the last_soc before suspend
*/
- soc = last_soc;
- else if (last_soc > soc) {
- if (chip->calc_soc_at_suspend > soc)
- soc = last_soc -
- (chip->calc_soc_at_suspend - soc);
- else
- soc = last_soc;
+ soc = chip->last_soc_at_suspend;
}
- }
- } else {
- if (last_soc != -EINVAL) {
- if (soc < last_soc && soc != 0)
- soc = last_soc - 1;
- if (soc > last_soc && soc != 100)
- soc = last_soc + 1;
+ } else if (soc < last_soc && soc != 0) {
+ soc = last_soc - 1;
+ } else if (soc > last_soc && soc != 100) {
+ soc = last_soc + 1;
}
}
@@ -3584,8 +3584,7 @@
cancel_delayed_work_sync(&chip->calculate_soc_delayed_work);
- chip->first_report_after_suspend = true;
- chip->calc_soc_at_suspend = calculated_soc;
+ chip->last_soc_at_suspend = last_soc;
return 0;
}
@@ -3602,6 +3601,7 @@
pr_err("Could not read current time: %d\n", rc);
return 0;
}
+
if (tm_now_sec > chip->last_recalc_time) {
time_since_last_recalc = tm_now_sec -
chip->last_recalc_time;
@@ -3611,8 +3611,11 @@
chip->soc_calc_period) {
chip->last_recalc_time = tm_now_sec;
recalculate_soc(chip);
+ chip->soc_updated_on_resume = true;
}
}
+ chip->first_report_after_suspend = true;
+ update_power_supply(chip);
schedule_delayed_work(&chip->calculate_soc_delayed_work,
msecs_to_jiffies(chip->soc_calc_period));