summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDevdutt Patnaik <dpatnaik@codeaurora.org>2016-06-28 16:52:31 -0700
committerHemant Kumar <hemantk@codeaurora.org>2016-07-19 15:40:12 -0700
commit4e2ea2e9dce2d94fea932b939da79302a1a27cfd (patch)
tree049a63a6fd47cde19dfe5fe6b85b9c7698c144fc
parent400520a6e2f06cc7c45e386e769a85d4aded565b (diff)
usb: phy: qusb: Add support for host mode phy init seq
Update QUSB2 HS PHY init sequence in host mode to fix enumeration issues due to port reset operation failure. Change-Id: I95daf3e3a833f9daeac6190daa33191f9db8cf26 Signed-off-by: Devdutt Patnaik <dpatnaik@codeaurora.org>
-rw-r--r--Documentation/devicetree/bindings/usb/msm-phy.txt2
-rw-r--r--drivers/usb/phy/phy-msm-qusb-v2.c51
2 files changed, 53 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/usb/msm-phy.txt b/Documentation/devicetree/bindings/usb/msm-phy.txt
index 35bb94b2ef70..83bccb7b5b31 100644
--- a/Documentation/devicetree/bindings/usb/msm-phy.txt
+++ b/Documentation/devicetree/bindings/usb/msm-phy.txt
@@ -172,6 +172,8 @@ Optional properties:
control in device mode. The reg-names property is required if the
reg property is specified.
- qcom,qusb-phy-init-seq: QUSB PHY initialization sequence with value,reg pair.
+ - qcom,qusb-phy-host-init-seq: QUSB PHY initialization sequence for host mode
+ with value,reg pair.
- qcom,emu-init-seq : emulation initialization sequence with value,reg pair.
- qcom,phy-pll-reset-seq : emulation PLL reset sequence with value,reg pair.
- qcom,emu-dcm-reset-seq : emulation DCM reset sequence with value,reg pair.
diff --git a/drivers/usb/phy/phy-msm-qusb-v2.c b/drivers/usb/phy/phy-msm-qusb-v2.c
index 1bc6b6ba4517..8b9bd10ce217 100644
--- a/drivers/usb/phy/phy-msm-qusb-v2.c
+++ b/drivers/usb/phy/phy-msm-qusb-v2.c
@@ -87,6 +87,8 @@ struct qusb_phy {
int vdd_levels[3]; /* none, low, high */
int init_seq_len;
int *qusb_phy_init_seq;
+ int host_init_seq_len;
+ int *qusb_phy_host_init_seq;
u32 tune2_val;
int tune2_efuse_bit_pos;
@@ -374,6 +376,35 @@ static void qusb_phy_write_seq(void __iomem *base, u32 *seq, int cnt,
}
}
+static void qusb_phy_host_init(struct usb_phy *phy)
+{
+ u8 reg;
+ struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
+
+ dev_dbg(phy->dev, "%s\n", __func__);
+
+ /* Perform phy reset */
+ clk_reset(qphy->phy_reset, CLK_RESET_ASSERT);
+ usleep_range(100, 150);
+ clk_reset(qphy->phy_reset, CLK_RESET_DEASSERT);
+
+ qusb_phy_write_seq(qphy->base, qphy->qusb_phy_host_init_seq,
+ qphy->host_init_seq_len, 0);
+
+ /* Ensure above write is completed before turning ON ref clk */
+ wmb();
+
+ /* Require to get phy pll lock successfully */
+ usleep_range(150, 160);
+
+ reg = readb_relaxed(qphy->base + QUSB2PHY_PLL_COMMON_STATUS_ONE);
+ dev_dbg(phy->dev, "QUSB2PHY_PLL_COMMON_STATUS_ONE:%x\n", reg);
+ if (!(reg & CORE_READY_STATUS)) {
+ dev_err(phy->dev, "QUSB PHY PLL LOCK fails:%x\n", reg);
+ WARN_ON(1);
+ }
+}
+
static int qusb_phy_init(struct usb_phy *phy)
{
struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
@@ -603,6 +634,9 @@ static int qusb_phy_notify_connect(struct usb_phy *phy,
dev_dbg(phy->dev, " cable_connected=%d\n", qphy->cable_connected);
+ if (qphy->qusb_phy_host_init_seq && qphy->phy.flags & PHY_HOST_MODE)
+ qusb_phy_host_init(phy);
+
/* Set OTG VBUS Valid from HSPHY to controller */
qusb_write_readback(qphy->qscratch_base, HS_PHY_CTRL_REG,
UTMI_OTG_VBUS_VALID,
@@ -866,6 +900,23 @@ static int qusb_phy_probe(struct platform_device *pdev)
}
}
+ qphy->host_init_seq_len = of_property_count_elems_of_size(dev->of_node,
+ "qcom,qusb-phy-host-init-seq",
+ sizeof(*qphy->qusb_phy_host_init_seq));
+ if (qphy->host_init_seq_len > 0) {
+ qphy->qusb_phy_host_init_seq = devm_kcalloc(dev,
+ qphy->host_init_seq_len,
+ sizeof(*qphy->qusb_phy_host_init_seq),
+ GFP_KERNEL);
+ if (qphy->qusb_phy_host_init_seq)
+ of_property_read_u32_array(dev->of_node,
+ "qcom,qusb-phy-host-init-seq",
+ qphy->qusb_phy_host_init_seq,
+ qphy->host_init_seq_len);
+ else
+ return -ENOMEM;
+ }
+
ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
(u32 *) qphy->vdd_levels,
ARRAY_SIZE(qphy->vdd_levels));