USB: ci13xxx_msm: Clear LINK's SW_VBUS state in USBCMD on DISCONNECT
Most platforms typically rely on USB PHY for sess_vld signal inside
the Link Controller. In case VBUS is not fed to PHY, software can
configure LINK to rely on software controlled bit in USBCMD register
(USBCMD_SESS_VLD_CTRL) for sess_valid. LINK pulls DP HIGH when
running in peripheral mode and sess_valid signal is present.
On VBUS DISCONNET, software currently stops LINK without clearing
sess_valid bit. And it is noticed that USB LINK continues to pull
DP high even after stopping if USBCMD_SESS_VLD_CTRL is not cleared.
This results in charger compliance tests failing renegotiation tests
where CDP --> SDP transition is checked by removing and reapplying
VBUS within 100 msec. Failure happens as compliance tester finds
DP at way too high level (~2.8v) during primary detection stage.
CRs-fixed: 633479
Change-Id: I883867e39e4d1a306e5e63ec1da445a3aede1585
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
Signed-off-by: ChandanaKishori Chiluveru <cchilu@codeaurora.org>
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 66bb317..be30b5f 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -62,11 +62,27 @@
struct ci13xxx *udc = _udc;
struct usb_phy *phy = udc->transceiver;
- if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP))
+ if (phy && (phy->flags & ENABLE_DP_MANUAL_PULLUP)) {
+ u32 temp;
+
usb_phy_io_write(phy,
ULPI_MISC_A_VBUSVLDEXT |
ULPI_MISC_A_VBUSVLDEXTSEL,
ULPI_CLR(ULPI_MISC_A));
+
+ /* Notify LINK of VBUS LOW */
+ temp = readl_relaxed(USB_USBCMD);
+ temp &= ~USBCMD_SESS_VLD_CTRL;
+ writel_relaxed(temp, USB_USBCMD);
+
+ /*
+ * Add memory barrier as it is must to complete
+ * above USB PHY and Link register writes before
+ * moving ahead with USB peripheral mode enumeration,
+ * otherwise USB peripheral mode may not work.
+ */
+ mb();
+ }
}
/* Link power management will reduce power consumption by