summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/phy/phy-msm-qusb-v2.c24
1 files changed, 23 insertions, 1 deletions
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;