google_battery: BD: reset trickle defend 5 minutes from disconnect

Bug: 173461492
Change-Id: I9b689e6980418a78da83460f718236a49d7fee0f
Signed-off-by: Ken Tsou <[email protected]>
Signed-off-by: AleX Pelosi <[email protected]>
(cherry picked from commit d00d7fb5dd5b25d9d62746e363d38c8826af7c42)
diff --git a/google_battery.c b/google_battery.c
index ea63be6..9618d0e 100644
--- a/google_battery.c
+++ b/google_battery.c
@@ -47,6 +47,7 @@
 #define DEFAULT_BATT_UPDATE_INTERVAL		30000
 #define DEFAULT_BATT_DRV_RL_SOC_THRESHOLD	97
 #define DEFAULT_BD_TRICKLE_RL_SOC_THRESHOLD	90
+#define DEFAULT_BD_TRICKLE_RESET_SEC		(5 * 60)
 #define DEFAULT_HIGH_TEMP_UPDATE_THRESHOLD	550
 
 #define MSC_ERROR_UPDATE_INTERVAL		5000
@@ -142,6 +143,7 @@
 	ktime_t rl_last_update;
 
 	/* connected or disconnected */
+	ktime_t disconnect_time;
 	int buck_enabled;
 
 	/* recharge logic */
@@ -153,6 +155,7 @@
 	int bd_trickle_recharge_soc;
 	int bd_trickle_cnt;
 	bool bd_trickle_dry_run;
+	u32 bd_trickle_reset_sec;
 
 	/* buff */
 	char ssoc_state_cstr[SSOC_STATE_BUF_SZ];
@@ -894,10 +897,7 @@
  */
 static void batt_rl_reset(struct batt_drv *batt_drv)
 {
-	struct batt_ssoc_state *ssoc_state = &batt_drv->ssoc_state;
-
-	ssoc_state->rl_status = BATT_RL_STATUS_NONE;
-	ssoc_state->bd_trickle_cnt = 0;
+	batt_drv->ssoc_state.rl_status = BATT_RL_STATUS_NONE;
 }
 
 /*
@@ -2546,6 +2546,31 @@
 	return overheat ? 0 : qnum_fromint(batt_drv->ssoc_state.ssoc_delta);
 }
 
+/* TODO: handle the whole state buck_enable state */
+static void ssoc_change_state(struct batt_ssoc_state *ssoc_state, bool ben)
+{
+	const ktime_t now = get_boot_sec();
+
+	if (!ben) {
+		ssoc_state->disconnect_time = now;
+	} else if (ssoc_state->disconnect_time) {
+		const u32 trickle_reset = ssoc_state->bd_trickle_reset_sec;
+		const long long elap = now - ssoc_state->disconnect_time;
+
+		if (trickle_reset && elap > trickle_reset)
+			ssoc_state->bd_trickle_cnt = 0;
+
+		pr_debug("MSC_BD: bd_trickle_cnt=%d dsc_time=%lld elap=%lld\n",
+			 ssoc_state->bd_trickle_cnt,
+			 ssoc_state->disconnect_time,
+			 elap);
+
+		ssoc_state->disconnect_time = 0;
+	}
+
+	ssoc_state->buck_enabled = ben;
+}
+
 /* called holding chg_lock */
 static int batt_chg_logic(struct batt_drv *batt_drv)
 {
@@ -2594,7 +2619,8 @@
 		if (err < 0)
 			pr_err("Cannot set the BATT_CE_CTRL.\n");
 
-		batt_drv->ssoc_state.buck_enabled = 0;
+		/* TODO: move earlier and include the change to the curve */
+		ssoc_change_state(&batt_drv->ssoc_state, 0);
 		changed = true;
 
 		goto msc_logic_done;
@@ -2630,7 +2656,8 @@
 		mod_delayed_work(system_wq, &batt_drv->batt_work,
 				 BATT_WORK_FAST_RETRY_MS);
 
-		batt_drv->ssoc_state.buck_enabled = 1;
+		/* TODO: move earlier and include the change to the curve */
+		ssoc_change_state(&batt_drv->ssoc_state, 1);
 		changed = true;
 	}
 
@@ -3978,6 +4005,38 @@
 static DEVICE_ATTR(bd_trickle_dry_run, 0660,
 		   show_bd_trickle_dry_run, set_bd_trickle_dry_run);
 
+static ssize_t show_bd_trickle_reset_sec(struct device *dev,
+					 struct device_attribute *attr,
+					 char *buf)
+{
+	struct power_supply *psy = container_of(dev, struct power_supply, dev);
+	struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n",
+			 batt_drv->ssoc_state.bd_trickle_reset_sec);
+}
+
+static ssize_t set_bd_trickle_reset_sec(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct power_supply *psy = container_of(dev, struct power_supply, dev);
+	struct batt_drv *batt_drv = power_supply_get_drvdata(psy);
+	unsigned int val;
+	int ret = 0;
+
+	ret = kstrtouint(buf, 0, &val);
+	if (ret < 0)
+		return ret;
+
+	batt_drv->ssoc_state.bd_trickle_reset_sec = val;
+
+	return count;
+}
+
+static DEVICE_ATTR(bd_trickle_reset_sec, 0660,
+		   show_bd_trickle_reset_sec, set_bd_trickle_reset_sec);
+
 static ssize_t batt_show_time_to_ac(struct device *dev,
 				    struct device_attribute *attr, char *buf)
 {
@@ -4138,6 +4197,10 @@
 	if (ret)
 		dev_err(&batt_drv->psy->dev, "Failed to create bd_trickle_dry_run\n");
 
+	ret = device_create_file(&batt_drv->psy->dev, &dev_attr_bd_trickle_reset_sec);
+	if (ret)
+		dev_err(&batt_drv->psy->dev, "Failed to create bd_trickle_reset_sec\n");
+
 	ret = device_create_file(&batt_drv->psy->dev, &dev_attr_pairing_state);
 	if (ret)
 		dev_err(&batt_drv->psy->dev, "Failed to create pairing_state\n");
@@ -5135,6 +5198,12 @@
 
 	batt_drv->ssoc_state.bd_trickle_dry_run = false;
 
+	ret = of_property_read_u32(node, "google,bd-trickle-reset-sec",
+				   &batt_drv->ssoc_state.bd_trickle_reset_sec);
+	if (ret < 0)
+		batt_drv->ssoc_state.bd_trickle_reset_sec =
+				DEFAULT_BD_TRICKLE_RESET_SEC;
+
 	ret = of_property_read_u32(node, "google,ssoc-delta",
 				   &batt_drv->ssoc_state.ssoc_delta);
 	if (ret < 0)