OSDN Git Service

usb: phy: qusb: Add support for host mode phy init seq
authorDevdutt Patnaik <dpatnaik@codeaurora.org>
Tue, 28 Jun 2016 23:52:31 +0000 (16:52 -0700)
committerHemant Kumar <hemantk@codeaurora.org>
Tue, 19 Jul 2016 22:40:12 +0000 (15:40 -0700)
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>
Documentation/devicetree/bindings/usb/msm-phy.txt
drivers/usb/phy/phy-msm-qusb-v2.c

index 35bb94b..83bccb7 100644 (file)
@@ -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.
index 1bc6b6b..8b9bd10 100644 (file)
@@ -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));