power: qpnp-fg-gen3: make TTF monotonic by limiting slope

Currently if there is a spike in system load or a thermal event which
causes the battery current to change dramatically then the TTF can jump.

While a battery is charging the TTF should be monotonically decreasing.

Track the TTF starting with the first estimate and set hard bounds of -2
and -0.1 on the slope. The negative slope ensures the TTF is
monotonically decreasing and the hard bounds on the slope smooth out
significant changes in the TTF.

Change-Id: I68a934599ff25bc5a9eb67b372b28a723532a540
Signed-off-by: Nicholas Troast <ntroast@codeaurora.org>
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
diff --git a/drivers/power/supply/qcom/qpnp-fg-gen3.c b/drivers/power/supply/qcom/qpnp-fg-gen3.c
index 1fd6bd8..8586a22 100644
--- a/drivers/power/supply/qcom/qpnp-fg-gen3.c
+++ b/drivers/power/supply/qcom/qpnp-fg-gen3.c
@@ -2226,6 +2226,8 @@
 	mutex_lock(&chip->ttf.lock);
 	fg_circ_buf_clr(&chip->ttf.ibatt);
 	fg_circ_buf_clr(&chip->ttf.vbatt);
+	chip->ttf.last_ttf = 0;
+	chip->ttf.last_ms = 0;
 	mutex_unlock(&chip->ttf.lock);
 	schedule_delayed_work(&chip->ttf_work, msecs_to_jiffies(delay_ms));
 }
@@ -2825,8 +2827,9 @@
 	int rc, ibatt_avg, vbatt_avg, rbatt, msoc, full_soc, act_cap_mah,
 		i_cc2cv = 0, soc_cc2cv, tau, divisor, iterm, ttf_mode,
 		i, soc_per_step, msoc_this_step, msoc_next_step,
-		ibatt_this_step, t_predicted_this_step,
+		ibatt_this_step, t_predicted_this_step, ttf_slope,
 		t_predicted_cv, t_predicted = 0;
+	s64 delta_ms;
 
 	if (chip->bp.float_volt_uv <= 0) {
 		pr_err("battery profile is not loaded\n");
@@ -2860,6 +2863,8 @@
 	if (chip->ttf.mode != ttf_mode) {
 		fg_circ_buf_clr(&chip->ttf.ibatt);
 		fg_circ_buf_clr(&chip->ttf.vbatt);
+		chip->ttf.last_ttf = 0;
+		chip->ttf.last_ms = 0;
 		chip->ttf.mode = ttf_mode;
 	}
 
@@ -3007,11 +3012,33 @@
 	fg_dbg(chip, FG_TTF, "t_predicted_cv=%d\n", t_predicted_cv);
 	t_predicted += t_predicted_cv;
 
+	fg_dbg(chip, FG_TTF, "t_predicted_prefilter=%d\n", t_predicted);
+	if (chip->ttf.last_ms != 0) {
+		delta_ms = ktime_ms_delta(ktime_get_boottime(),
+					  ms_to_ktime(chip->ttf.last_ms));
+		if (delta_ms > 10000) {
+			ttf_slope = div64_s64(
+				(s64)(t_predicted - chip->ttf.last_ttf) *
+				MICRO_UNIT, delta_ms);
+			if (ttf_slope > -100)
+				ttf_slope = -100;
+			else if (ttf_slope < -2000)
+				ttf_slope = -2000;
+
+			t_predicted = div_s64(
+				(s64)ttf_slope * delta_ms, MICRO_UNIT) +
+				chip->ttf.last_ttf;
+			fg_dbg(chip, FG_TTF, "ttf_slope=%d\n", ttf_slope);
+		} else {
+			t_predicted = chip->ttf.last_ttf;
+		}
+	}
+
 	/* clamp the ttf to 0 */
 	if (t_predicted < 0)
 		t_predicted = 0;
 
-	fg_dbg(chip, FG_TTF, "t_predicted=%d\n", t_predicted);
+	fg_dbg(chip, FG_TTF, "t_predicted_postfilter=%d\n", t_predicted);
 	*val = t_predicted;
 	return 0;
 }
@@ -3239,6 +3266,7 @@
 	struct fg_chip *chip = container_of(work, struct fg_chip,
 					    ttf_work.work);
 	int rc, ibatt_now, vbatt_now, ttf;
+	ktime_t ktime_now;
 
 	mutex_lock(&chip->ttf.lock);
 	if (chip->charge_status != POWER_SUPPLY_STATUS_CHARGING &&
@@ -3275,6 +3303,15 @@
 			mutex_unlock(&chip->ttf.lock);
 			return;
 		}
+
+		/* update the TTF reference point every minute */
+		ktime_now = ktime_get_boottime();
+		if (ktime_ms_delta(ktime_now,
+				   ms_to_ktime(chip->ttf.last_ms)) > 60000 ||
+				   chip->ttf.last_ms == 0) {
+			chip->ttf.last_ttf = ttf;
+			chip->ttf.last_ms = ktime_to_ms(ktime_now);
+		}
 	}
 
 	/* recurse every 10 seconds */