summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/core/hub.c52
1 files changed, 52 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 5acf9757b09a..b3f934af7f22 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -37,6 +37,16 @@
#endif
#endif
+#ifdef CONFIG_ARCH_STMP3XXX
+#define STMP3XXX_USB_HOST_HACK
+#endif
+
+#ifdef STMP3XXX_USB_HOST_HACK
+#include <linux/fsl_devices.h>
+#include <mach/regs-usbphy.h>
+#include <mach/platform.h>
+#endif
+
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
@@ -2704,6 +2714,19 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
break;
}
}
+
+#ifdef STMP3XXX_USB_HOST_HACK
+ { /*Must enable HOSTDISCONDETECT after second reset*/
+ if (port1 == 1) {
+ if (udev->speed == USB_SPEED_HIGH) {
+ stmp3xxx_setl(
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ REGS_USBPHY_BASE + HW_USBPHY_CTRL);
+ }
+ }
+ }
+#endif
+
if (retval)
goto fail;
@@ -2831,6 +2854,35 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
"port %d, status %04x, change %04x, %s\n",
port1, portstatus, portchange, portspeed (portstatus));
+#ifdef STMP3XXX_USB_HOST_HACK
+ {
+ /*
+ * FIXME: the USBPHY of STMP3xxx SoC has bug. The usb port power
+ * is never enabled during standard ehci reset procedure if the
+ * external device once passed plug/unplug procedure. This work-
+ * around resets and reinitiates USBPHY before the ehci port reset
+ * sequence started.
+ */
+ struct device *dev = hcd->self.controller;
+ struct fsl_usb2_platform_data *pdata;
+
+ pdata = (struct fsl_usb2_platform_data *)dev->platform_data;
+ if (dev->parent && dev->type) {
+ if (port1 == 1 && pdata->platform_init)
+ pdata->platform_init(NULL);
+ }
+ if (port1 == 1) {
+ if (!(portstatus&USB_PORT_STAT_CONNECTION)) {
+ /* Must clear HOSTDISCONDETECT when disconnect*/
+ stmp3xxx_clearl(
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
+ REGS_USBPHY_BASE + HW_USBPHY_CTRL);
+ }
+ }
+ }
+#endif
+
+
if (hub->has_indicators) {
set_port_led(hub, port1, HUB_LED_AUTO);
hub->indicator[port1-1] = INDICATOR_AUTO;