usb: phy: msm: Manual PHY and LINK controller VBUS change notification
authorIvan T. Ivanov <ivan.ivanov@linaro.org>
Thu, 9 Apr 2015 08:34:33 +0000 (11:34 +0300)
committerFelipe Balbi <balbi@ti.com>
Tue, 28 Apr 2015 16:49:15 +0000 (11:49 -0500)
VBUS is not routed to USB PHY on recent Qualcomm platforms. USB controller
must see VBUS in order to pull-up DP when setting RS bit. Henc configure
USB PHY and LINK registers sense VBUS and enable manual pullup on D+ line.

Cc: Vamsi Krishna <vskrishn@codeaurora.org>
Cc: Mayank Rana <mrana@codeaurora.org>
Signed-off-by: Ivan T. Ivanov <ivan.ivanov@linaro.org>
Signed-off-by: Felipe Balbi <balbi@ti.com>
Documentation/devicetree/bindings/usb/msm-hsusb.txt
drivers/usb/phy/phy-msm-usb.c
include/linux/usb/msm_hsusb.h
include/linux/usb/msm_hsusb_hw.h

index f26bcfac3d8fba4a22b993f507df6f92823ade5d..bd8d9e7530290a91ec161f68f305c180981bf8fe 100644 (file)
@@ -69,6 +69,10 @@ Optional properties:
                 (no, min, max) where each value represents either a voltage
                 in microvolts or a value corresponding to voltage corner.
 
+- qcom,manual-pullup: If present, vbus is not routed to USB controller/phy
+                and controller driver therefore enables pull-up explicitly
+                before starting controller using usbcmd run/stop bit.
+
 - extcon:       phandles to external connector devices. First phandle
                 should point to external connector, which provide "USB"
                 cable events, the second should point to external connector
index ad66c67ce9a57c92461ef991c70b890016646c43..00c49bb1bd29a8ac9a63d6f6a69aea6a71e837d8 100644 (file)
@@ -240,8 +240,14 @@ static void ulpi_init(struct msm_otg *motg)
 static int msm_phy_notify_disconnect(struct usb_phy *phy,
                                   enum usb_device_speed speed)
 {
+       struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
        int val;
 
+       if (motg->manual_pullup) {
+               val = ULPI_MISC_A_VBUSVLDEXT | ULPI_MISC_A_VBUSVLDEXTSEL;
+               usb_phy_io_write(phy, val, ULPI_CLR(ULPI_MISC_A));
+       }
+
        /*
         * Put the transceiver in non-driving mode. Otherwise host
         * may not detect soft-disconnection.
@@ -422,6 +428,24 @@ static int msm_phy_init(struct usb_phy *phy)
                ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
        }
 
+       if (motg->manual_pullup) {
+               val = ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT;
+               ulpi_write(phy, val, ULPI_SET(ULPI_MISC_A));
+
+               val = readl(USB_GENCONFIG_2);
+               val |= GENCONFIG_2_SESS_VLD_CTRL_EN;
+               writel(val, USB_GENCONFIG_2);
+
+               val = readl(USB_USBCMD);
+               val |= USBCMD_SESS_VLD_CTRL;
+               writel(val, USB_USBCMD);
+
+               val = ulpi_read(phy, ULPI_FUNC_CTRL);
+               val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
+               val |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
+               ulpi_write(phy, val, ULPI_FUNC_CTRL);
+       }
+
        if (motg->phy_number)
                writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
 
@@ -1520,6 +1544,8 @@ static int msm_otg_read_dt(struct platform_device *pdev, struct msm_otg *motg)
                motg->vdd_levels[VDD_LEVEL_MAX] = tmp[VDD_LEVEL_MAX];
        }
 
+       motg->manual_pullup = of_property_read_bool(node, "qcom,manual-pullup");
+
        ext_id = ERR_PTR(-ENODEV);
        ext_vbus = ERR_PTR(-ENODEV);
        if (of_property_read_bool(node, "extcon")) {
index c4d956e50d09c00e75112658bfd4246ed8a12d62..e55a1504266ec0333853793fa17e947feac02efd 100644 (file)
@@ -150,6 +150,9 @@ struct msm_usb_cable {
  * @chg_type: The type of charger attached.
  * @dcd_retires: The retry count used to track Data contact
  *               detection process.
+ * @manual_pullup: true if VBUS is not routed to USB controller/phy
+ *     and controller driver therefore enables pull-up explicitly before
+ *     starting controller using usbcmd run/stop bit.
  * @vbus: VBUS signal state trakining, using extcon framework
  * @id: ID signal state trakining, using extcon framework
  */
@@ -181,6 +184,8 @@ struct msm_otg {
        struct reset_control *link_rst;
        int vdd_levels[3];
 
+       bool manual_pullup;
+
        struct msm_usb_cable vbus;
        struct msm_usb_cable id;
 };
index a29f6030afb16713fd411ae777e3678b9fdef323..e159b39f67a2f4645d953e25264bff4aae5eb3bd 100644 (file)
@@ -21,6 +21,8 @@
 
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
+#define USB_GENCONFIG_2      (MSM_USB_BASE + 0x00a0)
+
 #define USB_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
@@ -30,6 +32,9 @@
 #define USB_PHY_CTRL         (MSM_USB_BASE + 0x0240)
 #define USB_PHY_CTRL2        (MSM_USB_BASE + 0x0278)
 
+#define GENCONFIG_2_SESS_VLD_CTRL_EN   BIT(7)
+#define USBCMD_SESS_VLD_CTRL           BIT(25)
+
 #define USBCMD_RESET   2
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
 
 #define ULPI_PWR_CLK_MNG_REG   0x88
 #define OTG_COMP_DISABLE       BIT(0)
 
+#define ULPI_MISC_A                    0x96
+#define ULPI_MISC_A_VBUSVLDEXTSEL      BIT(1)
+#define ULPI_MISC_A_VBUSVLDEXT         BIT(0)
+
 #define ASYNC_INTR_CTRL         (1 << 29) /* Enable async interrupt */
 #define ULPI_STP_CTRL           (1 << 30) /* Block communication with PHY */
 #define PHY_RETEN               (1 << 1) /* PHY retention enable/disable */