usb: phy-msm-qusb-v2: Reset PLL only if not locked on resume

Driver currently unconditionally resets PLL while entering
suspend state. As per hardware databook PLL need not to be
reset across every suspend/resume. Driver should reset it
only if PLL fails to lock on resume which must be checked
using DEBUG_CTRL2 register.

Change-Id: I4cb544dd8ad94af9270746f67ad872ff1b77e2b0
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
diff --git a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
index 9b88356..c53367a 100644
--- a/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
+++ b/arch/arm64/boot/dts/qcom/sdm845-670-usb-common.dtsi
@@ -141,7 +141,9 @@
 			 0x198 /* PLL_BIAS_CONTROL_2 */
 			 0x228 /* QUSB2PHY_SQ_CTRL1 */
 			 0x22c /* QUSB2PHY_SQ_CTRL2 */
-			 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
+			 0x27c /* QUSB2PHY_DEBUG_CTRL1 */
+			 0x280 /* QUSB2PHY_DEBUG_CTRL2 */
+			 0x2a0>; /* QUSB2PHY_STAT5 */
 
 		qcom,qusb-phy-init-seq =
 			/* <value reg_offset> */
@@ -431,7 +433,9 @@
 			 0x198 /* PLL_BIAS_CONTROL_2 */
 			 0x228 /* QUSB2PHY_SQ_CTRL1 */
 			 0x22c /* QUSB2PHY_SQ_CTRL2 */
-			 0x27c>; /* QUSB2PHY_DEBUG_CTRL1 */
+			 0x27c /* QUSB2PHY_DEBUG_CTRL1 */
+			 0x280 /* QUSB2PHY_DEBUG_CTRL2 */
+			 0x2a0>; /* QUSB2PHY_STAT5 */
 
 		qcom,qusb-phy-init-seq =
 			/* <value reg_offset> */
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 6dfca9c..a17974c 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -76,6 +76,12 @@
 /* PERIPH_SS_PHY_REFGEN_NORTH_BG_CTRL register bits */
 #define BANDGAP_BYPASS			BIT(0)
 
+/* DEBUG_CTRL2 register value to program VSTATUS MUX for PHY status */
+#define DEBUG_CTRL2_MUX_PLL_LOCK_STATUS	0x4
+
+/* STAT5 register bits */
+#define VSTATUS_PLL_LOCK_STATUS_MASK	BIT(0)
+
 enum qusb_phy_reg {
 	PORT_TUNE1,
 	PLL_COMMON_STATUS_ONE,
@@ -87,6 +93,8 @@
 	SQ_CTRL1,
 	SQ_CTRL2,
 	DEBUG_CTRL1,
+	DEBUG_CTRL2,
+	STAT5,
 	USB2_PHY_REG_MAX,
 };
 
@@ -470,6 +478,18 @@
 							__func__);
 }
 
+static bool qusb_phy_pll_locked(struct qusb_phy *qphy)
+{
+	u32 val;
+
+	writel_relaxed(DEBUG_CTRL2_MUX_PLL_LOCK_STATUS,
+		       qphy->base + qphy->phy_reg[DEBUG_CTRL2]);
+
+	val = readl_relaxed(qphy->base + qphy->phy_reg[STAT5]);
+
+	return (val & VSTATUS_PLL_LOCK_STATUS_MASK);
+}
+
 static void qusb_phy_host_init(struct usb_phy *phy)
 {
 	u8 reg;
@@ -748,18 +768,12 @@
 			writel_relaxed(intr_mask,
 				qphy->base + qphy->phy_reg[INTR_CTRL]);
 
-			/* hold core PLL into reset */
-			writel_relaxed(CORE_PLL_EN_FROM_RESET |
-				CORE_RESET | CORE_RESET_MUX,
-				qphy->base +
-				qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
-
 			if (linestate & (LINESTATE_DP | LINESTATE_DM)) {
 				/* enable phy auto-resume */
 				writel_relaxed(0x91,
 					qphy->base + qphy->phy_reg[TEST1]);
-				/* flush the previous write before next write */
-				wmb();
+				/* Delay recommended between TEST1 writes */
+				usleep_range(10, 20);
 				writel_relaxed(0x90,
 					qphy->base + qphy->phy_reg[TEST1]);
 			}
@@ -788,12 +802,26 @@
 			writel_relaxed(0x00,
 				qphy->base + qphy->phy_reg[INTR_CTRL]);
 
-			/* bring core PLL out of reset */
-			writel_relaxed(CORE_PLL_EN_FROM_RESET, qphy->base +
-				qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+			/* Reset PLL if needed */
+			if (!qusb_phy_pll_locked(qphy)) {
+				dev_dbg(phy->dev, "%s: reset PLL\n", __func__);
+				/* hold core PLL into reset */
+				writel_relaxed(CORE_PLL_EN_FROM_RESET |
+					CORE_RESET | CORE_RESET_MUX,
+					qphy->base +
+					qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
 
-			/* Makes sure that above write goes through */
-			wmb();
+				/* Wait for PLL to get reset */
+				usleep_range(10, 20);
+
+				/* bring core PLL out of reset */
+				writel_relaxed(CORE_PLL_EN_FROM_RESET,
+					qphy->base +
+					qphy->phy_reg[PLL_CORE_INPUT_OVERRIDE]);
+
+				/* Makes sure that above write goes through */
+				wmb();
+			}
 		} else { /* Cable connect case */
 			qusb_phy_enable_clocks(qphy, true);
 		}