power: pm8921-bms: fix SOC jumps while entering suspend/resume

The last_soc is being set to -EINVAL when entering suspend. This
causes SOC to jump while coming out of resume.

Instead remember
If we are reporting for the first time after suspend.
The calculated_soc at the time we went to suspend.

Soc should not increase because we cannot suspend while
charging. If the calculated_soc has increased continue reporting
the lower last_soc.

If the calculated soc has dropped check if it has dropped since
suspend. If so decrease the reported soc by the amount it dropped
since suspend.

If the calculated soc has dropped but it has increased since suspend
continue to report the last_soc.

Change-Id: I9040feceaa3e829d11bec0b21e61951f2ed1180b
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
Signed-off-by: Xiaozhe Shi <xiaozhes@codeaurora.org>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 7c49793..4bb44b8 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -177,6 +177,8 @@
 	int			vbatt_cutoff_count;
 	int			low_voltage_detect;
 	int			vbatt_cutoff_retries;
+	bool			first_report_after_suspend;
+	int			calc_soc_at_suspend;
 };
 
 /*
@@ -2495,15 +2497,33 @@
 
 	/* last_soc < soc  ... scale and catch up */
 	if (last_soc != -EINVAL && last_soc < soc && soc != 100)
-			soc = scale_soc_while_chg(chip, delta_time_us,
-							soc, last_soc);
+		soc = scale_soc_while_chg(chip, delta_time_us, soc, last_soc);
 
-	/* restrict soc to 1% change */
-	if (last_soc != -EINVAL) {
-		if (soc < last_soc && soc != 0)
-			soc = last_soc - 1;
-		if (soc > last_soc && soc != 100)
-			soc = last_soc + 1;
+	/* 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)
+				/*
+				 * can't suspend while charging
+				 * don't report the increased the soc
+				 */
+				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;
+			}
+		}
+	} 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;
+		}
 	}
 
 	last_soc = bound_soc(soc);
@@ -3560,12 +3580,8 @@
 
 static int pm8921_bms_suspend(struct device *dev)
 {
-	/*
-	 * set the last reported soc to invalid, so that
-	 * next time we resume we don't want to restrict
-	 * the decrease of soc by only 1%
-	 */
-	last_soc = -EINVAL;
+	the_chip->first_report_after_suspend = true;
+	the_chip->calc_soc_at_suspend = calculated_soc;
 
 	return 0;
 }