[PATCH 1/1] mfd: omap-usb-host: Fix USB device detection problems on OMAP4 Panda

From: Roger Quadros
Date: Fri Nov 29 2013 - 08:02:24 EST


With u-boot 2013.10, USB devices are sometimes not detected
on OMAP4 Panda. To make us independent of what bootloader does
with the USB Host module, we must RESET it to get it to a known
good state. This patch Soft RESETs the USB Host module.

Reported-by: Tomi Valkeinen <tomi.valkeinen@xxxxxx>
Cc: <stable@xxxxxxxxxxxxxxx> # 3.10+
Signed-off-by: Roger Quadros <rogerq@xxxxxx>
---
drivers/mfd/omap-usb-host.c | 115 +++++++++++++++++++++++++++++++++++++++++---
1 file changed, 109 insertions(+), 6 deletions(-)

diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 142650f..d4bd464 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -43,14 +43,18 @@
/* UHH Register Set */
#define OMAP_UHH_REVISION (0x00)
#define OMAP_UHH_SYSCONFIG (0x10)
-#define OMAP_UHH_SYSCONFIG_MIDLEMODE (1 << 12)
+#define OMAP_UHH_SYSCONFIG_MIDLEMASK (3 << 12)
+#define OMAP_UHH_SYSCONFIG_MIDLESHIFT (12)
#define OMAP_UHH_SYSCONFIG_CACTIVITY (1 << 8)
-#define OMAP_UHH_SYSCONFIG_SIDLEMODE (1 << 3)
+#define OMAP_UHH_SYSCONFIG_SIDLEMASK (3 << 3)
+#define OMAP_UHH_SYSCONFIG_SIDLESHIFT (3)
#define OMAP_UHH_SYSCONFIG_ENAWAKEUP (1 << 2)
#define OMAP_UHH_SYSCONFIG_SOFTRESET (1 << 1)
#define OMAP_UHH_SYSCONFIG_AUTOIDLE (1 << 0)

#define OMAP_UHH_SYSSTATUS (0x14)
+#define OMAP_UHH_SYSSTATUS_RESETDONE (1 << 0)
+
#define OMAP_UHH_HOSTCONFIG (0x40)
#define OMAP_UHH_HOSTCONFIG_ULPI_BYPASS (1 << 0)
#define OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS (1 << 0)
@@ -66,10 +70,10 @@
#define OMAP4_UHH_HOSTCONFIG_APP_START_CLK (1 << 31)

/* OMAP4-specific defines */
-#define OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR (3 << 2)
-#define OMAP4_UHH_SYSCONFIG_NOIDLE (1 << 2)
-#define OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR (3 << 4)
-#define OMAP4_UHH_SYSCONFIG_NOSTDBY (1 << 4)
+#define OMAP4_UHH_SYSCONFIG_MIDLEMASK (3 << 2)
+#define OMAP4_UHH_SYSCONFIG_MIDLESHIFT (2)
+#define OMAP4_UHH_SYSCONFIG_SIDLEMASK (3 << 4)
+#define OMAP4_UHH_SYSCONFIG_SIDLESHIFT (4)
#define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0)

#define OMAP4_P1_MODE_CLEAR (3 << 16)
@@ -81,6 +85,12 @@

#define OMAP_UHH_DEBUG_CSR (0x44)

+/* MIDLE modes */
+#define OMAP_UHH_SYSCONFIG_MIDLE_NOSTANDBY (1)
+
+/* SIDLE modes */
+#define OMAP_UHH_SYSCONFIG_SIDLE_NOIDLE (1)
+
/* Values of UHH_REVISION - Note: these are not given in the TRM */
#define OMAP_USBHS_REV1 0x00000010 /* OMAP3 */
#define OMAP_USBHS_REV2 0x50700100 /* OMAP4 */
@@ -474,6 +484,97 @@ static unsigned omap_usbhs_rev2_hostconfig(struct usbhs_hcd_omap *omap,
return reg;
}

+static void omap_usbhs_rev1_reset(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ u32 reg;
+ unsigned long timeout;
+
+ reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
+
+ /* Soft Reset */
+ usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG,
+ reg | OMAP_UHH_SYSCONFIG_SOFTRESET);
+
+ timeout = jiffies + msecs_to_jiffies(100);
+ while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS)
+ & OMAP_UHH_SYSSTATUS_RESETDONE)) {
+ cpu_relax();
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(dev, "Soft RESET operation timed out\n");
+ break;
+ }
+ }
+
+ /* Set No-Standby */
+ reg &= ~OMAP_UHH_SYSCONFIG_MIDLEMASK;
+ reg |= OMAP_UHH_SYSCONFIG_MIDLE_NOSTANDBY
+ << OMAP_UHH_SYSCONFIG_MIDLESHIFT;
+
+ /* Set No-Idle */
+ reg &= ~OMAP_UHH_SYSCONFIG_SIDLEMASK;
+ reg |= OMAP_UHH_SYSCONFIG_SIDLE_NOIDLE
+ << OMAP_UHH_SYSCONFIG_SIDLESHIFT;
+
+ usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
+}
+
+static void omap_usbhs_rev2_reset(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+ u32 reg;
+ unsigned long timeout;
+
+ reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG);
+
+ /* Soft Reset */
+ usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG,
+ reg | OMAP4_UHH_SYSCONFIG_SOFTRESET);
+
+ /* OMAP4: Need to wait before SYSCONFIG can be accessed */
+ udelay(2);
+ timeout = jiffies + msecs_to_jiffies(100);
+
+ /* SOFTRESET bit clears when RESET completes */
+ while (usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG)
+ & OMAP4_UHH_SYSCONFIG_SOFTRESET) {
+ cpu_relax();
+
+ if (time_after(jiffies, timeout)) {
+ dev_err(dev, "Soft RESET operation timed out\n");
+ break;
+ }
+ }
+
+ /* Set No-Standby */
+ reg &= ~OMAP4_UHH_SYSCONFIG_MIDLEMASK;
+ reg |= OMAP_UHH_SYSCONFIG_MIDLE_NOSTANDBY
+ << OMAP4_UHH_SYSCONFIG_MIDLESHIFT;
+
+ /* Set No-Idle */
+ reg &= ~OMAP4_UHH_SYSCONFIG_SIDLEMASK;
+ reg |= OMAP_UHH_SYSCONFIG_SIDLE_NOIDLE
+ << OMAP4_UHH_SYSCONFIG_SIDLESHIFT;
+
+ usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg);
+}
+
+static void omap_usbhs_softreset(struct device *dev)
+{
+ struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
+
+ switch (omap->usbhs_rev) {
+ case OMAP_USBHS_REV1:
+ omap_usbhs_rev1_reset(dev);
+ break;
+
+ default: /* Rev 2 onwards */
+ omap_usbhs_rev2_reset(dev);
+ break;
+ }
+}
+
static void omap_usbhs_init(struct device *dev)
{
struct usbhs_hcd_omap *omap = dev_get_drvdata(dev);
@@ -483,6 +584,8 @@ static void omap_usbhs_init(struct device *dev)

pm_runtime_get_sync(dev);

+ omap_usbhs_softreset(dev);
+
reg = usbhs_read(omap->uhh_base, OMAP_UHH_HOSTCONFIG);
/* setup ULPI bypass and burst configurations */
reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN
--
1.8.3.2

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