[U-Boot] [PATCH 1/2] sunxi: musb: Do not fully reset the controler from sunxi_musb_disable

Hans de Goede hdegoede at redhat.com
Sun Jun 14 12:40:12 CEST 2015


Fully resetting the controller is a too big hammer, and the musb_core will
then afterwards fail to communicate with any endpoints other then 0 as
too much state was cleared.

Instead report vbus low for 200ms which will effectively end the current
session without needing to do a full reset.

This fixes usb mass-storage devices no longer working after a "usb reset"

Signed-off-by: Hans de Goede <hdegoede at redhat.com>
---
 drivers/usb/musb-new/sunxi.c | 52 ++++++++++++++++++++++++++------------------
 1 file changed, 31 insertions(+), 21 deletions(-)

diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index e8a3a23..42c6725 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -157,6 +157,17 @@ static void USBC_ForceIdToHigh(__iomem void *base)
 	musb_writel(base, USBC_REG_o_ISCR, reg_val);
 }
 
+static void USBC_ForceVbusValidToLow(__iomem void *base)
+{
+	u32 reg_val;
+
+	reg_val = musb_readl(base, USBC_REG_o_ISCR);
+	reg_val &= ~(0x03 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+	reg_val |= (0x02 << USBC_BP_ISCR_FORCE_VBUS_VALID);
+	reg_val = USBC_WakeUp_ClearChangeDetect(reg_val);
+	musb_writel(base, USBC_REG_o_ISCR, reg_val);
+}
+
 static void USBC_ForceVbusValidToHigh(__iomem void *base)
 {
 	u32 reg_val;
@@ -205,42 +216,41 @@ static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci)
 	return retval;
 }
 
+/* musb_core does not call enable / disable in a balanced manner <sigh> */
+static bool enabled = false;
+
 static void sunxi_musb_enable(struct musb *musb)
 {
 	pr_debug("%s():\n", __func__);
 
+	if (enabled)
+		return;
+
 	/* select PIO mode */
 	musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0);
 
-	if (is_host_enabled(musb)) {
-		/* port power on */
-		sunxi_usb_phy_power_on(0);
-	}
+	if (is_host_enabled(musb))
+		sunxi_usb_phy_power_on(0); /* port power on */
+
+	USBC_ForceVbusValidToHigh(musb->mregs);
+
+	enabled = true;
 }
 
 static void sunxi_musb_disable(struct musb *musb)
 {
-	struct sunxi_ccm_reg *ccm = (struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
-
 	pr_debug("%s():\n", __func__);
 
-	/* Put the controller back in a pristane state for "usb reset" */
-	if (musb->is_active) {
-		sunxi_usb_phy_exit(0);
-#ifdef CONFIG_SUNXI_GEN_SUN6I
-		clrbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
-#endif
-		clrbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
+	if (!enabled)
+		return;
 
-		mdelay(10);
+	if (is_host_enabled(musb))
+		sunxi_usb_phy_power_off(0); /* port power off */
 
-		setbits_le32(&ccm->ahb_gate0, 1 << AHB_GATE_OFFSET_USB0);
-#ifdef CONFIG_SUNXI_GEN_SUN6I
-		setbits_le32(&ccm->ahb_reset0_cfg, 1 << AHB_GATE_OFFSET_USB0);
-#endif
-		sunxi_usb_phy_init(0);
-		musb->is_active = 0;
-	}
+	USBC_ForceVbusValidToLow(musb->mregs);
+	mdelay(200); /* Wait for the current session to timeout */
+
+	enabled = false;
 }
 
 static int sunxi_musb_init(struct musb *musb)
-- 
2.4.3



More information about the U-Boot mailing list