Merge "power: qpnp-qg: Ignore the shutdown SOC based on certain conditions"
diff --git a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
index 83f964d..1e49e96 100644
--- a/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
+++ b/Documentation/devicetree/bindings/power/supply/qcom/qpnp-qg.txt
@@ -308,6 +308,20 @@
 	Definition: Boolean property to support external-rsense based
 		    configuration.
 
+- qcom,shutdown-temp-diff
+	Usage:      optional
+	Value type: <u32>
+	Definition: The allowed battery temperature in deci-degree difference
+		    between shutdown and power-on to continue with the shutdown
+		    SOC. If not specified the default value is 6 degrees C (60).
+
+- qcom,shutdown-soc-threshold
+	Usage:      optional
+	Value type: <u32>
+	Definition: The SOC difference allowed between PON and SHUTDOWN SOC
+		    for the shutdown SOC to be used. If the difference is
+		    beyond this value the PON SOC is used.
+
 ==========================================================
 Second Level Nodes - Peripherals managed by QGAUGE driver
 ==========================================================
diff --git a/drivers/power/supply/qcom/qg-core.h b/drivers/power/supply/qcom/qg-core.h
index b0ff18c..4f0773b 100644
--- a/drivers/power/supply/qcom/qg-core.h
+++ b/drivers/power/supply/qcom/qg-core.h
@@ -50,11 +50,13 @@
 	int			delta_soc;
 	int			rbat_conn_mohm;
 	int			ignore_shutdown_soc_secs;
+	int			shutdown_temp_diff;
 	int			cold_temp_threshold;
 	int			esr_qual_i_ua;
 	int			esr_qual_v_uv;
 	int			esr_disable_soc;
 	int			esr_min_ibat_ua;
+	int			shutdown_soc_threshold;
 	bool			hold_soc_while_full;
 	bool			linearize_soc;
 	bool			cl_disable;
diff --git a/drivers/power/supply/qcom/qpnp-qg.c b/drivers/power/supply/qcom/qpnp-qg.c
index 855e31d..97256be 100644
--- a/drivers/power/supply/qcom/qpnp-qg.c
+++ b/drivers/power/supply/qcom/qpnp-qg.c
@@ -2514,7 +2514,6 @@
 	return 0;
 }
 
-
 static struct ocv_all ocv[] = {
 	[S7_PON_OCV] = { 0, 0, "S7_PON_OCV"},
 	[S3_GOOD_OCV] = { 0, 0, "S3_GOOD_OCV"},
@@ -2528,7 +2527,7 @@
 	int rc = 0, batt_temp = 0, i;
 	bool use_pon_ocv = true;
 	unsigned long rtc_sec = 0;
-	u32 ocv_uv = 0, soc = 0, shutdown[SDAM_MAX] = {0};
+	u32 ocv_uv = 0, soc = 0, pon_soc = 0, shutdown[SDAM_MAX] = {0};
 	char ocv_type[20] = "NONE";
 
 	if (!chip->profile_loaded) {
@@ -2536,6 +2535,24 @@
 		return 0;
 	}
 
+	/* read all OCVs */
+	for (i = S7_PON_OCV; i < PON_OCV_MAX; i++) {
+		rc = qg_read_ocv(chip, &ocv[i].ocv_uv,
+					&ocv[i].ocv_raw, i);
+		if (rc < 0)
+			pr_err("Failed to read %s OCV rc=%d\n",
+					ocv[i].ocv_type, rc);
+		else
+			qg_dbg(chip, QG_DEBUG_PON, "%s OCV=%d\n",
+					ocv[i].ocv_type, ocv[i].ocv_uv);
+	}
+
+	rc = qg_get_battery_temp(chip, &batt_temp);
+	if (rc) {
+		pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
+		goto done;
+	}
+
 	rc = get_rtc_time(&rtc_sec);
 	if (rc < 0) {
 		pr_err("Failed to read RTC time rc=%d\n", rc);
@@ -2548,47 +2565,50 @@
 		goto use_pon_ocv;
 	}
 
-	qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs, time_now=%ldsecs\n",
+	rc = lookup_soc_ocv(&pon_soc, ocv[S7_PON_OCV].ocv_uv, batt_temp, false);
+	if (rc < 0) {
+		pr_err("Failed to lookup S7_PON SOC rc=%d\n", rc);
+		goto done;
+	}
+
+	qg_dbg(chip, QG_DEBUG_PON, "Shutdown: Valid=%d SOC=%d OCV=%duV time=%dsecs temp=%d, time_now=%ldsecs temp_now=%d S7_soc=%d\n",
 			shutdown[SDAM_VALID],
 			shutdown[SDAM_SOC],
 			shutdown[SDAM_OCV_UV],
 			shutdown[SDAM_TIME_SEC],
-			rtc_sec);
+			shutdown[SDAM_TEMP],
+			rtc_sec, batt_temp,
+			pon_soc);
 	/*
 	 * Use the shutdown SOC if
-	 * 1. The device was powered off for < ignore_shutdown_time
-	 * 2. SDAM read is a success & SDAM data is valid
+	 * 1. SDAM read is a success & SDAM data is valid
+	 * 2. The device was powered off for < ignore_shutdown_time
+	 * 2. Batt temp has not changed more than shutdown_temp_diff
 	 */
-	if (shutdown[SDAM_VALID] && is_between(0,
-			chip->dt.ignore_shutdown_soc_secs,
-			(rtc_sec - shutdown[SDAM_TIME_SEC]))) {
-		use_pon_ocv = false;
-		ocv_uv = shutdown[SDAM_OCV_UV];
-		soc = shutdown[SDAM_SOC];
-		strlcpy(ocv_type, "SHUTDOWN_SOC", 20);
-		qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
-	}
+	if (!shutdown[SDAM_VALID])
+		goto use_pon_ocv;
+
+	if (!is_between(0, chip->dt.ignore_shutdown_soc_secs,
+			(rtc_sec - shutdown[SDAM_TIME_SEC])))
+		goto use_pon_ocv;
+
+	if (!is_between(0, chip->dt.shutdown_temp_diff,
+			abs(shutdown[SDAM_TEMP] -  batt_temp)))
+		goto use_pon_ocv;
+
+	if ((chip->dt.shutdown_soc_threshold != -EINVAL) &&
+			!is_between(0, chip->dt.shutdown_soc_threshold,
+			abs(pon_soc - shutdown[SDAM_SOC])))
+		goto use_pon_ocv;
+
+	use_pon_ocv = false;
+	ocv_uv = shutdown[SDAM_OCV_UV];
+	soc = shutdown[SDAM_SOC];
+	strlcpy(ocv_type, "SHUTDOWN_SOC", 20);
+	qg_dbg(chip, QG_DEBUG_PON, "Using SHUTDOWN_SOC @ PON\n");
 
 use_pon_ocv:
 	if (use_pon_ocv == true) {
-		rc = qg_get_battery_temp(chip, &batt_temp);
-		if (rc) {
-			pr_err("Failed to read BATT_TEMP at PON rc=%d\n", rc);
-			goto done;
-		}
-
-		/* read all OCVs */
-		for (i = S7_PON_OCV; i < PON_OCV_MAX; i++) {
-			rc = qg_read_ocv(chip, &ocv[i].ocv_uv,
-						&ocv[i].ocv_raw, i);
-			if (rc < 0)
-				pr_err("Failed to read %s OCV rc=%d\n",
-						ocv[i].ocv_type, rc);
-			else
-				qg_dbg(chip, QG_DEBUG_PON, "%s OCV=%d\n",
-					ocv[i].ocv_type, ocv[i].ocv_uv);
-		}
-
 		if (ocv[S3_LAST_OCV].ocv_raw == FIFO_V_RESET_VAL) {
 			if (!ocv[SDAM_PON_OCV].ocv_uv) {
 				strlcpy(ocv_type, "S7_PON_SOC", 20);
@@ -3074,6 +3094,7 @@
 #define DEFAULT_CL_MAX_DEC_DECIPERC	20
 #define DEFAULT_CL_MIN_LIM_DECIPERC	500
 #define DEFAULT_CL_MAX_LIM_DECIPERC	100
+#define DEFAULT_SHUTDOWN_TEMP_DIFF	60	/* 6 degC */
 #define DEFAULT_ESR_QUAL_CURRENT_UA	130000
 #define DEFAULT_ESR_QUAL_VBAT_UV	7000
 #define DEFAULT_ESR_DISABLE_SOC		1000
@@ -3259,6 +3280,12 @@
 	else
 		chip->dt.ignore_shutdown_soc_secs = temp;
 
+	rc = of_property_read_u32(node, "qcom,shutdown-temp-diff", &temp);
+	if (rc < 0)
+		chip->dt.shutdown_temp_diff = DEFAULT_SHUTDOWN_TEMP_DIFF;
+	else
+		chip->dt.shutdown_temp_diff = temp;
+
 	chip->dt.hold_soc_while_full = of_property_read_bool(node,
 					"qcom,hold-soc-while-full");
 
@@ -3302,6 +3329,12 @@
 	else
 		chip->dt.esr_min_ibat_ua = (int)temp;
 
+	rc = of_property_read_u32(node, "qcom,shutdown_soc_threshold", &temp);
+	if (rc < 0)
+		chip->dt.shutdown_soc_threshold = -EINVAL;
+	else
+		chip->dt.shutdown_soc_threshold = temp;
+
 	chip->dt.qg_ext_sense = of_property_read_bool(node, "qcom,qg-ext-sns");
 
 	/* Capacity learning params*/