Merge "gauage:add fg restart procedure to fix soc incorrect when battery full" into android-msm-triton-3.18
diff --git a/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt b/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt
index bfe171b..40251e0 100644
--- a/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt
+++ b/Documentation/devicetree/bindings/power/qpnp-fg-gen3.txt
@@ -177,6 +177,14 @@
 		    Element 0 - Retry value for timer
 		    Element 1 - Maximum value for timer
 
+- qcom,fg-esr-timer-shutdown
+	Usage:      optional
+	Value type: <prop-encoded-array>
+	Definition: Number of cycles between ESR pulses at/after shutdwon. This is
+		    defined when TWM (traditional watch mode) is supported.
+		    Element 0 - Retry value for timer
+		    Element 1 - Maximum value for timer
+
 - qcom,fg-esr-pulse-thresh-ma
 	Usage:      optional
 	Value type: <u32>
@@ -398,6 +406,17 @@
 	Definition: A boolean property when defined uses software based
 		    ESR during charging.
 
+- qcom,fg-disable-esr-pull-dn
+	Usage:      optional
+	Value type: <empty>
+	Definition: A boolean property which disables ESR pull-down.
+		    This is to be used for debug purposes only.
+
+- qcom,fg-sync-sleep-threshold-ma
+	Usage:      optional
+	Value type: <u32>
+	Definition: The minimum battery current for FG to enter into sync-sleep.
+
 ==========================================================
 Second Level Nodes - Peripherals managed by FG Gen3 driver
 ==========================================================
diff --git a/arch/arm/boot/dts/msm8909w-triton/msm8909w-triton-pm660-mtp.dtsi b/arch/arm/boot/dts/msm8909w-triton/msm8909w-triton-pm660-mtp.dtsi
index 1d879a6..c509516 100644
--- a/arch/arm/boot/dts/msm8909w-triton/msm8909w-triton-pm660-mtp.dtsi
+++ b/arch/arm/boot/dts/msm8909w-triton/msm8909w-triton-pm660-mtp.dtsi
@@ -361,4 +361,8 @@
 	qcom,fg-esr-pulse-thresh-ma = <40>;
 	qcom,fg-esr-meas-curr-ma = <60>;
 	qcom,fg-cutoff-current = <50>;
+
+	qcom,fg-esr-timer-shutdown = <2048 2048>;
+	qcom,fg-esr-timer-asleep = <512 512>;
+	qcom,fg-sync-sleep-threshold-ma = <30>;
 };
diff --git a/drivers/power/fg-core.h b/drivers/power/fg-core.h
index 1a9d1c2..f99c9c0 100644
--- a/drivers/power/fg-core.h
+++ b/drivers/power/fg-core.h
@@ -177,6 +177,7 @@
 	FG_SRAM_DELTA_MSOC_THR,
 	FG_SRAM_DELTA_BSOC_THR,
 	FG_SRAM_RECHARGE_SOC_THR,
+	FG_SRAM_SYNC_SLEEP_THR,
 	FG_SRAM_RECHARGE_VBATT_THR,
 	FG_SRAM_KI_COEFF_MED_DISCHG,
 	FG_SRAM_KI_COEFF_HI_DISCHG,
@@ -255,6 +256,7 @@
 	bool	hold_soc_while_full;
 	bool	auto_recharge_soc;
 	bool	use_esr_sw;
+	bool	disable_esr_pull_dn;
 	int	cutoff_volt_mv;
 	int	empty_volt_mv;
 	int	vbatt_low_thr_mv;
@@ -269,6 +271,7 @@
 	int	esr_timer_charging[NUM_ESR_TIMERS];
 	int	esr_timer_awake[NUM_ESR_TIMERS];
 	int	esr_timer_asleep[NUM_ESR_TIMERS];
+	int	esr_timer_shutdown[NUM_ESR_TIMERS];
 	int	rconn_mohms;
 	int	esr_clamp_mohms;
 	int	cl_start_soc;
@@ -292,6 +295,7 @@
 	int	slope_limit_temp;
 	int	esr_pulse_thresh_ma;
 	int	esr_meas_curr_ma;
+	int	sync_sleep_threshold_ma;
 	int	jeita_thresholds[NUM_JEITA_LEVELS];
 	int	ki_coeff_soc[KI_COEFF_SOC_LEVELS];
 	int	ki_coeff_med_dischg[KI_COEFF_SOC_LEVELS];
diff --git a/drivers/power/qpnp-fg-gen3.c b/drivers/power/qpnp-fg-gen3.c
index c68464a..b90da2a 100644
--- a/drivers/power/qpnp-fg-gen3.c
+++ b/drivers/power/qpnp-fg-gen3.c
@@ -66,6 +66,8 @@
 #define RECHARGE_SOC_THR_OFFSET		0
 #define CHG_TERM_CURR_WORD		14
 #define CHG_TERM_CURR_OFFSET		1
+#define SYNC_SLEEP_THR_WORD		14
+#define SYNC_SLEEP_THR_OFFSET		3
 #define EMPTY_VOLT_WORD			15
 #define EMPTY_VOLT_OFFSET		0
 #define VBATT_LOW_WORD			15
@@ -135,6 +137,8 @@
 #define DELTA_MSOC_THR_v2_OFFSET	0
 #define RECHARGE_SOC_THR_v2_WORD	14
 #define RECHARGE_SOC_THR_v2_OFFSET	1
+#define SYNC_SLEEP_THR_v2_WORD		14
+#define SYNC_SLEEP_THR_v2_OFFSET	2
 #define CHG_TERM_CURR_v2_WORD		15
 #define CHG_TERM_BASE_CURR_v2_OFFSET	0
 #define CHG_TERM_CURR_v2_OFFSET		1
@@ -225,6 +229,8 @@
 		2048, 100, 0, fg_encode_default, NULL),
 	PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_WORD, RECHARGE_SOC_THR_OFFSET,
 		1, 256, 100, 0, fg_encode_default, NULL),
+	PARAM(SYNC_SLEEP_THR, SYNC_SLEEP_THR_WORD, SYNC_SLEEP_THR_OFFSET,
+		1, 100000, 390625, 0, fg_encode_default, NULL),
 	PARAM(ESR_TIMER_DISCHG_MAX, ESR_TIMER_DISCHG_MAX_WORD,
 		ESR_TIMER_DISCHG_MAX_OFFSET, 2, 1, 1, 0, fg_encode_default,
 		NULL),
@@ -304,6 +310,8 @@
 	PARAM(RECHARGE_SOC_THR, RECHARGE_SOC_THR_v2_WORD,
 		RECHARGE_SOC_THR_v2_OFFSET, 1, 256, 100, 0, fg_encode_default,
 		NULL),
+	PARAM(SYNC_SLEEP_THR, SYNC_SLEEP_THR_v2_WORD, SYNC_SLEEP_THR_v2_OFFSET,
+		1, 100000, 390625, 0, fg_encode_default, NULL),
 	PARAM(RECHARGE_VBATT_THR, RECHARGE_VBATT_THR_v2_WORD,
 		RECHARGE_VBATT_THR_v2_OFFSET, 1, 1000, 15625, -2000,
 		fg_encode_voltage, NULL),
@@ -3920,7 +3928,7 @@
 		return rc;
 	}
 
-	if (is_debug_batt_id(chip)) {
+	if (is_debug_batt_id(chip) || chip->dt.disable_esr_pull_dn) {
 		val = ESR_NO_PULL_DOWN;
 		rc = fg_masked_write(chip, BATT_INFO_ESR_PULL_DN_CFG(chip),
 			ESR_PULL_DOWN_MODE_MASK, val);
@@ -3942,6 +3950,21 @@
 		}
 	}
 
+	if (chip->dt.sync_sleep_threshold_ma != -EINVAL) {
+		fg_encode(chip->sp, FG_SRAM_SYNC_SLEEP_THR,
+			chip->dt.sync_sleep_threshold_ma, buf);
+		rc = fg_sram_write(chip,
+				chip->sp[FG_SRAM_SYNC_SLEEP_THR].addr_word,
+				chip->sp[FG_SRAM_SYNC_SLEEP_THR].addr_byte, buf,
+				chip->sp[FG_SRAM_SYNC_SLEEP_THR].len,
+				FG_IMA_DEFAULT);
+		if (rc < 0) {
+			pr_err("Error in writing sync_sleep_threshold=%d\n",
+				rc);
+			return rc;
+		}
+	}
+
 	return 0;
 }
 
@@ -4808,6 +4831,13 @@
 		chip->dt.esr_timer_asleep[TIMER_MAX] = -EINVAL;
 	}
 
+	rc = fg_parse_dt_property_u32_array(node, "qcom,fg-esr-timer-shutdown",
+		chip->dt.esr_timer_shutdown, NUM_ESR_TIMERS);
+	if (rc < 0) {
+		chip->dt.esr_timer_shutdown[TIMER_RETRY] = -EINVAL;
+		chip->dt.esr_timer_shutdown[TIMER_MAX] = -EINVAL;
+	}
+
 	chip->cyc_ctr.en = of_property_read_bool(node, "qcom,cycle-counter-en");
 	if (chip->cyc_ctr.en)
 		chip->cyc_ctr.id = 1;
@@ -4969,8 +4999,19 @@
 			chip->dt.esr_meas_curr_ma = temp;
 	}
 
+	chip->dt.sync_sleep_threshold_ma = -EINVAL;
+	rc = of_property_read_u32(node,
+		"qcom,fg-sync-sleep-threshold-ma", &temp);
+	if (!rc) {
+		if (temp >= 0 && temp < 997)
+			chip->dt.sync_sleep_threshold_ma = temp;
+	}
+
 	chip->dt.use_esr_sw = of_property_read_bool(node, "qcom,fg-use-sw-esr");
 
+	chip->dt.disable_esr_pull_dn = of_property_read_bool(node,
+					"qcom,fg-disable-esr-pull-dn");
+
 	return 0;
 }
 
@@ -5256,6 +5297,20 @@
 	return 0;
 }
 
+static void fg_gen3_shutdown(struct spmi_device *spmi)
+{
+	struct fg_chip *chip = dev_get_drvdata(&spmi->dev);
+	int rc;
+
+	rc = fg_set_esr_timer(chip, chip->dt.esr_timer_shutdown[TIMER_RETRY],
+				chip->dt.esr_timer_shutdown[TIMER_MAX], false,
+				FG_IMA_NO_WLOCK);
+	if (rc < 0)
+		pr_err("Error in setting ESR timer at shutdown, rc=%d\n", rc);
+
+	fg_cleanup(chip);
+}
+
 early_param("BuildPhase", get_board_id);
 
 static const struct of_device_id fg_gen3_match_table[] = {
@@ -5272,6 +5327,7 @@
 	},
 	.probe		= fg_gen3_probe,
 	.remove		= fg_gen3_remove,
+	.shutdown	= fg_gen3_shutdown,
 };
 
 static int __init fg_gen3_init(void)
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.c b/drivers/video/msm/mdss/mdp3_ctrl.c
index 6fd4a52..8558bb3 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.c
+++ b/drivers/video/msm/mdss/mdp3_ctrl.c
@@ -152,16 +152,9 @@
 	return blocking_notifier_call_chain(&ses->notifier_head, event, ses);
 }
 
-static void mdp3_dispatch_dma_done(struct kthread_work *work)
+static void __mdp3_dispatch_dma_done(struct mdp3_session_data *session)
 {
-	struct mdp3_session_data *session;
-	int cnt = 0;
-
-	pr_debug("%s\n", __func__);
-	session = container_of(work, struct mdp3_session_data,
-				dma_done_work);
-	if (!session)
-		return;
+	int cnt;
 
 	cnt = atomic_read(&session->dma_done_cnt);
 	MDSS_XLOG(cnt);
@@ -172,6 +165,29 @@
 	}
 }
 
+void mdp3_flush_dma_done(struct mdp3_session_data *session)
+{
+	if (!session)
+		return;
+
+	pr_debug("%s\n", __func__);
+
+	__mdp3_dispatch_dma_done(session);
+}
+
+static void mdp3_dispatch_dma_done(struct kthread_work *work)
+{
+	struct mdp3_session_data *session;
+
+	pr_debug("%s\n", __func__);
+	session = container_of(work, struct mdp3_session_data,
+				dma_done_work);
+	if (!session)
+		return;
+
+	__mdp3_dispatch_dma_done(session);
+}
+
 static void mdp3_dispatch_clk_off(struct work_struct *work)
 {
 	struct mdp3_session_data *session;
@@ -3219,6 +3235,7 @@
 		pr_err("fail to init dma\n");
 		goto init_done;
 	}
+	mdp3_session->dma->session = mdp3_session;
 
 	intf_type = mdp3_ctrl_get_intf_type(mfd);
 	mdp3_session->intf = mdp3_get_display_intf(intf_type);
diff --git a/drivers/video/msm/mdss/mdp3_ctrl.h b/drivers/video/msm/mdss/mdp3_ctrl.h
index 49b327f..ccc7036 100644
--- a/drivers/video/msm/mdss/mdp3_ctrl.h
+++ b/drivers/video/msm/mdss/mdp3_ctrl.h
@@ -96,5 +96,6 @@
 int mdp3_ctrl_reset(struct msm_fb_data_type *mfd);
 int mdp3_get_ion_client(struct msm_fb_data_type *mfd);
 int config_secure_display(struct mdp3_session_data *mdp3_session);
+void mdp3_flush_dma_done(struct mdp3_session_data *mdp3_session);
 
 #endif /* MDP3_CTRL_H */
diff --git a/drivers/video/msm/mdss/mdp3_dma.c b/drivers/video/msm/mdss/mdp3_dma.c
index bb4275f..bc2d757 100644
--- a/drivers/video/msm/mdss/mdp3_dma.c
+++ b/drivers/video/msm/mdss/mdp3_dma.c
@@ -1162,6 +1162,16 @@
 
 	reinit_completion(&dma->dma_comp);
 	dma->vsync_client.handler = NULL;
+
+	/*
+	 * Interrupts are disabled.
+	 * Check for blocked dma done interrupt.
+	 * Flush items waiting for dma done interrupt.
+	 */
+	if (dma->output_config.out_sel == MDP3_DMA_OUTPUT_SEL_DSI_CMD &&
+		atomic_read(&dma->session->dma_done_cnt))
+		mdp3_flush_dma_done(dma->session);
+
 	return ret;
 }
 
diff --git a/drivers/video/msm/mdss/mdp3_dma.h b/drivers/video/msm/mdss/mdp3_dma.h
index 02289a1..68d1309 100644
--- a/drivers/video/msm/mdss/mdp3_dma.h
+++ b/drivers/video/msm/mdss/mdp3_dma.h
@@ -294,6 +294,8 @@
 	struct fb_cmap *gc_cmap;
 	struct fb_cmap *hist_cmap;
 
+	struct mdp3_session_data *session;
+
 	bool (*busy)(void);
 
 	int (*dma_config)(struct mdp3_dma *dma,