diff options
author | Vamsi Krishna Samavedam <vskrishn@codeaurora.org> | 2016-08-08 17:53:48 -0700 |
---|---|---|
committer | Vamsi Krishna Samavedam <vskrishn@codeaurora.org> | 2016-08-30 12:22:35 -0700 |
commit | 299063819e84815164f8111cb33b45ce74942444 (patch) | |
tree | b54ef51b634ba94b511f90c739fa686f550d3e84 | |
parent | ab26d098793adbf90b77d414663e34ac0c7315f6 (diff) |
usb: phy: qusb: Set clamp_dig_n signal based on usb status
Analog and digital power rails connected to the phy can be turned
on/off in any order. This may result in random leakage in the phy
as it expects certain power rails to be on/off in certain order.
Avoid random leakage on qusb2 phy by
1. Disable pll when phy is suspended/disconnected.
2. Reset and assert clamp dig_n signal to put dp/dm lines in high
impedance state.
Change-Id: I1bafa7f824af8bbb3f67a71b81bf23b0a9c7164e
Signed-off-by: Vamsi Krishna Samavedam <vskrishn@codeaurora.org>
-rw-r--r-- | Documentation/devicetree/bindings/usb/msm-phy.txt | 3 | ||||
-rw-r--r-- | drivers/usb/phy/phy-msm-qusb-v2.c | 52 |
2 files changed, 48 insertions, 7 deletions
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt index dd9c13b4b5ff..bcb866a83412 100644 --- a/Documentation/devicetree/bindings/usb/msm-phy.txt +++ b/Documentation/devicetree/bindings/usb/msm-phy.txt @@ -185,6 +185,9 @@ Optional properties: via the QSCRATCH interface. "emu_phy_base" : phy base address used for programming emulation target phy. "ref_clk_addr" : ref_clk bcr address used for on/off ref_clk before reset. + "tcsr_clamp_dig_n" : To enable/disable digital clamp to the phy. When + de-asserted, it will prevent random leakage from qusb2 phy resulting from + out of sequence turn on/off of 1p8, 3p3 and DVDD regulators. - clocks: a list of phandles to the PHY clocks. Use as per Documentation/devicetree/bindings/clock/clock-bindings.txt - clock-names: Names of the clocks in 1-1 correspondence with the "clocks" diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c index 23a4ac11af36..6b2e33ecb58a 100644 --- a/drivers/usb/phy/phy-msm-qusb-v2.c +++ b/drivers/usb/phy/phy-msm-qusb-v2.c @@ -65,6 +65,8 @@ #define LINESTATE_DP BIT(0) #define LINESTATE_DM BIT(1) +#define QUSB2PHY_PLL_ANALOG_CONTROLS_ONE 0x0 + unsigned int phy_tune2; module_param(phy_tune2, uint, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(phy_tune2, "QUSB PHY v2 TUNE2"); @@ -73,6 +75,7 @@ struct qusb_phy { struct usb_phy phy; void __iomem *base; void __iomem *tune2_efuse_reg; + void __iomem *tcsr_clamp_dig_n; struct clk *ref_clk_src; struct clk *ref_clk; @@ -554,6 +557,11 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) /* Bus suspend case */ if (qphy->cable_connected || (qphy->phy.flags & PHY_HOST_MODE)) { + + /* enable clock bypass */ + writel_relaxed(0x90, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); + /* Disable all interrupts */ writel_relaxed(0x00, qphy->base + QUSB2PHY_INTR_CTRL); @@ -584,15 +592,20 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) wmb(); qusb_phy_enable_clocks(qphy, false); } else { /* Cable disconnect case */ - /* Disable all interrupts */ - writel_relaxed(0x00, - qphy->base + QUSB2PHY_INTR_CTRL); - /* Put PHY into non-driving mode */ - writel_relaxed(0x23, - qphy->base + QUSB2PHY_PWR_CTRL1); + clk_reset(qphy->phy_reset, CLK_RESET_ASSERT); + usleep_range(100, 150); + clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); - /* Makes sure that above write goes through */ + /* enable clock bypass */ + writel_relaxed(0x90, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); + + writel_relaxed(0x0, qphy->tcsr_clamp_dig_n); + /* + * clamp needs asserted before + * power/clocks can be turned off + */ wmb(); qusb_phy_enable_clocks(qphy, false); @@ -604,6 +617,11 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) if (qphy->cable_connected || (qphy->phy.flags & PHY_HOST_MODE)) { qusb_phy_enable_clocks(qphy, true); + + /* disable clock bypass */ + writel_relaxed(0x80, + qphy->base + QUSB2PHY_PLL_ANALOG_CONTROLS_ONE); + /* Clear all interrupts on resume */ writel_relaxed(0x00, qphy->base + QUSB2PHY_INTR_CTRL); @@ -611,6 +629,16 @@ static int qusb_phy_set_suspend(struct usb_phy *phy, int suspend) /* Makes sure that above write goes through */ wmb(); } else { /* Cable connect case */ + writel_relaxed(0x1, qphy->tcsr_clamp_dig_n); + + /* + * clamp needs de-asserted before + * power/clocks can be turned on + */ + wmb(); + + clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT); + qusb_phy_enable_power(qphy, true, true); qusb_phy_enable_clocks(qphy, true); } @@ -735,6 +763,16 @@ static int qusb_phy_probe(struct platform_device *pdev) } res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "tcsr_clamp_dig_n_1p8"); + if (res) { + qphy->tcsr_clamp_dig_n = devm_ioremap_resource(dev, res); + if (IS_ERR(qphy->tcsr_clamp_dig_n)) { + dev_dbg(dev, "couldn't ioremap tcsr_clamp_dig_n\n"); + return PTR_ERR(qphy->tcsr_clamp_dig_n); + } + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "tune2_efuse_addr"); if (res) { qphy->tune2_efuse_reg = devm_ioremap_nocache(dev, res->start, |