Browse Source

usb: phy: msm: Manual PHY and LINK controller VBUS change notification

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>
Ivan T. Ivanov 10 năm trước cách đây
mục cha
commit
44e42ae3a3

+ 4 - 0
Documentation/devicetree/bindings/usb/msm-hsusb.txt

@@ -69,6 +69,10 @@ Optional properties:
                 (no, min, max) where each value represents either a voltage
                 (no, min, max) where each value represents either a voltage
                 in microvolts or a value corresponding to voltage corner.
                 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
 - extcon:       phandles to external connector devices. First phandle
                 should point to external connector, which provide "USB"
                 should point to external connector, which provide "USB"
                 cable events, the second should point to external connector
                 cable events, the second should point to external connector

+ 26 - 0
drivers/usb/phy/phy-msm-usb.c

@@ -240,8 +240,14 @@ static void ulpi_init(struct msm_otg *motg)
 static int msm_phy_notify_disconnect(struct usb_phy *phy,
 static int msm_phy_notify_disconnect(struct usb_phy *phy,
 				   enum usb_device_speed speed)
 				   enum usb_device_speed speed)
 {
 {
+	struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
 	int val;
 	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
 	 * Put the transceiver in non-driving mode. Otherwise host
 	 * may not detect soft-disconnection.
 	 * 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);
 		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)
 	if (motg->phy_number)
 		writel(readl(USB_PHY_CTRL2) | BIT(16), USB_PHY_CTRL2);
 		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->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_id = ERR_PTR(-ENODEV);
 	ext_vbus = ERR_PTR(-ENODEV);
 	ext_vbus = ERR_PTR(-ENODEV);
 	if (of_property_read_bool(node, "extcon")) {
 	if (of_property_read_bool(node, "extcon")) {

+ 5 - 0
include/linux/usb/msm_hsusb.h

@@ -150,6 +150,9 @@ struct msm_usb_cable {
  * @chg_type: The type of charger attached.
  * @chg_type: The type of charger attached.
  * @dcd_retires: The retry count used to track Data contact
  * @dcd_retires: The retry count used to track Data contact
  *               detection process.
  *               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
  * @vbus: VBUS signal state trakining, using extcon framework
  * @id: ID 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;
 	struct reset_control *link_rst;
 	int vdd_levels[3];
 	int vdd_levels[3];
 
 
+	bool manual_pullup;
+
 	struct msm_usb_cable vbus;
 	struct msm_usb_cable vbus;
 	struct msm_usb_cable id;
 	struct msm_usb_cable id;
 };
 };

+ 9 - 0
include/linux/usb/msm_hsusb_hw.h

@@ -21,6 +21,8 @@
 
 
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBBURST         (MSM_USB_BASE + 0x0090)
 #define USB_AHBMODE          (MSM_USB_BASE + 0x0098)
 #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_CAPLENGTH        (MSM_USB_BASE + 0x0100) /* 8 bit */
 
 
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
 #define USB_USBCMD           (MSM_USB_BASE + 0x0140)
@@ -30,6 +32,9 @@
 #define USB_PHY_CTRL         (MSM_USB_BASE + 0x0240)
 #define USB_PHY_CTRL         (MSM_USB_BASE + 0x0240)
 #define USB_PHY_CTRL2        (MSM_USB_BASE + 0x0278)
 #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 USBCMD_RESET   2
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
 #define USB_USBINTR          (MSM_USB_BASE + 0x0148)
 
 
@@ -50,6 +55,10 @@
 #define ULPI_PWR_CLK_MNG_REG	0x88
 #define ULPI_PWR_CLK_MNG_REG	0x88
 #define OTG_COMP_DISABLE	BIT(0)
 #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 ASYNC_INTR_CTRL         (1 << 29) /* Enable async interrupt */
 #define ULPI_STP_CTRL           (1 << 30) /* Block communication with PHY */
 #define ULPI_STP_CTRL           (1 << 30) /* Block communication with PHY */
 #define PHY_RETEN               (1 << 1) /* PHY retention enable/disable */
 #define PHY_RETEN               (1 << 1) /* PHY retention enable/disable */