power: pm8921-bms: use shutdown soc if it is within limits

When a strong battery is removed, it was seen that the battery voltage
lines on the phone take about five to six seconds to go below 2.1volts
where the pmic resets all the battery backed registers.

If a new battery is plugged in within this time the driver will force
the shutdown soc on this battery which is incorrect.

Compare the shutdown soc with the calculated soc and if they are
different than a configurable limit, simply discard the shutdown soc
and use the calculated soc.

Change-Id: I02e7c78eb5e9df0127ce7e78b0bd9792a8141039
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index 9d024d8..4de5752 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -133,6 +133,7 @@
 	struct delayed_work	shutdown_soc_work;
 	struct delayed_work	calculate_soc_delayed_work;
 	struct timespec		t_soc_queried;
+	int			shutdown_soc_valid_limit;
 };
 
 /*
@@ -1711,6 +1712,28 @@
 	chip->shutdown_soc_timer_expired = 1;
 }
 
+static bool is_shutdown_soc_within_limits(struct pm8921_bms_chip *chip, int soc)
+{
+	int shutdown_soc;
+
+	if (chip->shutdown_soc == 0 || shutdown_soc_invalid) {
+		pr_debug("NOT forcing shutdown soc = %d\n", chip->shutdown_soc);
+		return 0;
+	}
+
+	shutdown_soc = chip->shutdown_soc;
+	if (shutdown_soc == 0xFF)
+		shutdown_soc = 0;
+
+	if (abs(shutdown_soc - soc) > chip->shutdown_soc_valid_limit) {
+		pr_debug("rejecting shutdown soc = %d, soc = %d, limit = %d\n",
+			shutdown_soc, soc, chip->shutdown_soc_valid_limit);
+		shutdown_soc_invalid = 1;
+		return 0;
+	}
+
+	return 1;
+}
 /*
  * Remaining Usable Charge = remaining_charge (charge at ocv instance)
  *				- coloumb counter charge
@@ -1740,25 +1763,6 @@
 						&iavg_ua,
 						&delta_time_us);
 
-	if (delta_time_us == 0) {
-		/*
-		 * soc for the first time - use shutdown soc
-		 * to adjust pon ocv
-		 */
-		adjust_rc_and_uuc_for_shutdown_soc(
-						chip,
-						batt_temp, chargecycles,
-						fcc_uah, unusable_charge_uah,
-						cc_uah, remaining_charge_uah,
-						rbatt,
-						&new_rc_uah, &new_ucc_uah,
-						&new_rbatt);
-
-		remaining_charge_uah = new_rc_uah;
-		unusable_charge_uah = new_ucc_uah;
-		rbatt = new_rbatt;
-	}
-
 	/* calculate remaining usable charge */
 	remaining_usable_charge_uah = remaining_charge_uah
 					- cc_uah
@@ -1798,8 +1802,31 @@
 		soc = 0;
 	}
 
-	calculated_soc = adjust_soc(chip, soc, batt_temp, rbatt,
-					fcc_uah, unusable_charge_uah, cc_uah);
+	if (delta_time_us == 0 && 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(
+						chip,
+						batt_temp, chargecycles,
+						fcc_uah, unusable_charge_uah,
+						cc_uah, remaining_charge_uah,
+						rbatt,
+						&new_rc_uah, &new_ucc_uah,
+						&new_rbatt);
+
+		remaining_charge_uah = new_rc_uah;
+		unusable_charge_uah = new_ucc_uah;
+		rbatt = new_rbatt;
+
+		soc = DIV_ROUND_CLOSEST((remaining_usable_charge_uah * 100),
+					(fcc_uah - unusable_charge_uah));
+	}
+
+	calculated_soc = adjust_soc(chip, soc, batt_temp,
+			rbatt, fcc_uah, unusable_charge_uah, cc_uah);
 
 	pr_debug("calculated SOC = %d\n", calculated_soc);
 	return calculated_soc;
@@ -2863,6 +2890,7 @@
 	chip->rconn_mohm = pdata->rconn_mohm;
 	chip->start_percent = -EINVAL;
 	chip->end_percent = -EINVAL;
+	chip->shutdown_soc_valid_limit = pdata->shutdown_soc_valid_limit;
 	rc = set_battery_data(chip);
 	if (rc) {
 		pr_err("%s bad battery data %d\n", __func__, rc);