summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVamsi Krishna Samavedam <vskrishn@codeaurora.org>2016-08-08 17:53:48 -0700
committerVamsi Krishna Samavedam <vskrishn@codeaurora.org>2016-08-30 12:22:35 -0700
commit299063819e84815164f8111cb33b45ce74942444 (patch)
treeb54ef51b634ba94b511f90c739fa686f550d3e84
parentab26d098793adbf90b77d414663e34ac0c7315f6 (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.txt3
-rw-r--r--drivers/usb/phy/phy-msm-qusb-v2.c52
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,