From 982bc860811c9816e5ab135a75065211aacceef9 Mon Sep 17 00:00:00 2001 From: Vamsi Krishna Samavedam Date: Mon, 19 Sep 2016 14:50:34 -0700 Subject: [PATCH] usb: phy: qusb: Reset clock mux to avoid leakage on vdd rail Reset the clock mux when cable is disconnected and suspended to avoid leakage on vdd rail. Also, add missing clock reset when usb cable connect is notified. Change-Id: If5485379934a222f19f5dd20b8d4f44769470e8d Signed-off-by: Vamsi Krishna Samavedam --- drivers/usb/phy/phy-msm-qusb-v2.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 4ecdc350fbd4..5a768ee4d061 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -63,6 +63,7 @@ #define LINESTATE_DM BIT(1) #define QUSB2PHY_PLL_ANALOG_CONTROLS_ONE 0x0 +#define QUSB2PHY_PLL_ANALOG_CONTROLS_TWO 0x4 unsigned int phy_tune1; module_param(phy_tune1, uint, S_IRUGO | S_IWUSR); @@ -541,6 +542,7 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) { struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy); u32 linestate = 0, intr_mask = 0; + static u8 analog_ctrl_two; int ret; if (qphy->suspended && suspend) { @@ -554,6 +556,14 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) if (qphy->cable_connected || (qphy->phy.flags & PHY_HOST_MODE)) { + /* store clock settings like cmos/cml */ + analog_ctrl_two = + readl_relaxed(qphy->base + + QUSB2PHY_PLL_ANALOG_CONTROLS_TWO); + + writel_relaxed(0x1b, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_TWO); + /* enable clock bypass */ writel_relaxed(0x90, qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); @@ -599,6 +609,9 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) dev_err(phy->dev, "%s: phy_reset deassert failed\n", __func__); + writel_relaxed(0x1b, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_TWO); + /* enable clock bypass */ writel_relaxed(0x90, qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); @@ -620,6 +633,10 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) (qphy->phy.flags & PHY_HOST_MODE)) { qusb_phy_enable_clocks(qphy, true); + /* restore the default clock settings */ + writel_relaxed(analog_ctrl_two, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_TWO); + /* disable clock bypass */ writel_relaxed(0x80, qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); @@ -639,12 +656,17 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) */ wmb(); + qusb_phy_enable_power(qphy, true, true); + ret = reset_control_assert(qphy->phy_reset); + if (ret) + dev_err(phy->dev, "%s: phy_reset assert failed\n", + __func__); + usleep_range(100, 150); ret = reset_control_deassert(qphy->phy_reset); if (ret) dev_err(phy->dev, "%s: phy_reset deassert failed\n", __func__); - qusb_phy_enable_power(qphy, true, true); qusb_phy_enable_clocks(qphy, true); } qphy->suspended = false;