[PATCH 1/1] ehci-mxc: Fix mx31 OTG host initialisation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On mx31 the OTG host initialisation fail if you need to have
an ULPI transfert to initialize the PHY.

In order to be able to communicate with the PHY a complete reset
of the usb host is needed. After the PHY initialization the host
usb configuration registers need to be rewritten to avoid a host
controller lockup.

Signed-off-by: Philippe Rétornaz <philippe.retornaz@xxxxxxx>
---
 drivers/usb/host/ehci-mxc.c |   68 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 544ccfd..39d28da 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -29,6 +29,11 @@
 #define PORTSC_OFFSET		0x184
 #define USBMODE_OFFSET		0x1a8
 #define USBMODE_CM_HOST		3
+#define USBCMD_OFFSET		0x140
+#define USBCMD_RS		(1 << 0)
+#define USBCMD_RST		(1 << 1)
+#define USBSTS_OFFSET		0x144
+#define USBSTS_HCH		(1 << 12)
 
 struct ehci_mxc_priv {
 	struct clk *usbclk, *ahbclk;
@@ -120,6 +125,7 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
 	int irq, ret, temp;
 	struct ehci_mxc_priv *priv;
 	struct device *dev = &pdev->dev;
+	int i;
 
 	dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
 
@@ -204,6 +210,51 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_init;
 
+	/* i.Mx31 OTG host has a bug, if you don't do a reset, then ULPI
+	 * transfert timeout. */
+	if (cpu_is_mx31() && pdev->id == 0) {
+		/* Wait for the controller to go idle */
+		for (i = 0; i < 10000; i++) {
+			if (readl(hcd->regs + USBSTS_OFFSET) & USBSTS_HCH)
+				break;
+			udelay(1);
+		}
+		if (i == 10000) {
+			dev_err(dev, "Timeout while stopping USB controller\n");
+			goto err_init;
+		}
+
+		/* Stop the usb controller */
+		temp = readl(hcd->regs + USBCMD_OFFSET);
+		writel(temp & (~USBCMD_RS), hcd->regs + USBCMD_OFFSET);
+
+		for (i = 0; i < 10000; i++) {
+			if (!(readl(hcd->regs + USBCMD_OFFSET) & USBCMD_RS))
+				break;
+			udelay(1);
+		}
+
+		if (i == 10000) {
+			dev_err(dev, "Timeout while stopping USB controller\n");
+			goto err_init;
+		}
+
+		/* Reset the usb controller */
+		temp = readl(hcd->regs + USBCMD_OFFSET);
+		writel(temp | USBCMD_RST, hcd->regs + USBCMD_OFFSET);
+
+		for (i = 0; i < 10000; i++) {
+			if (!(readl(hcd->regs + USBCMD_OFFSET) & USBCMD_RST))
+				break;
+			udelay(1);
+		}
+
+		if (i == 10000) {
+			dev_err(dev, "Timeout while reseting USB controller\n");
+			goto err_init;
+		}
+	}
+
 	/* Initialize the transceiver */
 	if (pdata->otg) {
 		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
@@ -213,6 +264,23 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
 			dev_err(dev, "unable to enable vbus on transceiver\n");
 	}
 
+	/* i.Mx31 OTG host has a bug, if you do an ULPI transfert then the host
+	 * controller stay busy. Rewriting the register is enough to make it
+	 * working */
+	if (cpu_is_mx31() && pdev->id == 0) {
+		/* set USBMODE to host mode */
+		temp = readl(hcd->regs + USBMODE_OFFSET);
+		writel(temp | USBMODE_CM_HOST, hcd->regs + USBMODE_OFFSET);
+
+		/* set up the PORTSCx register */
+		writel(pdata->portsc, hcd->regs + PORTSC_OFFSET);
+
+		/* setup USBCONTROL. */
+		ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
+		if (ret < 0)
+			goto err_init;
+	}
+
 	priv->hcd = hcd;
 	platform_set_drvdata(pdev, priv);
 
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux