summaryrefslogtreecommitdiff
path: root/drivers/usb/core/hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r--drivers/usb/core/hub.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b19cbfcd51da..d89645f8f680 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -37,6 +37,15 @@
#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>
+#endif
+
struct usb_hub {
struct device *intfdev; /* the "interface" device */
struct usb_device *hdev;
@@ -884,6 +893,17 @@ static int hub_configure(struct usb_hub *hub,
goto fail;
}
+ /*
+ * The second USB-port of the S3C2443 is generating interrupts, although
+ * it's configured for the USB-device controller, and not for the USB-host.
+ * This seems to be a hardware BUG.
+ * (Luis Galdos)
+ */
+#if (defined(CONFIG_MACH_CC9M2443JS) || defined(CONFIG_MACH_CCW9M2443JS)) && defined(CONFIG_USB_GADGET_S3C2443)
+ /* Only use one port by the internal Root-Hub (devnum = 1) */
+ if (hdev->devnum == 1)
+ hub->descriptor->bNbrPorts = 1;
+#endif
hdev->maxchild = hub->descriptor->bNbrPorts;
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
(hdev->maxchild == 1) ? "" : "s");
@@ -1140,6 +1160,14 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
"hub nested too deep\n");
return -E2BIG;
}
+
+ /* With OTG enabled, suspending root hub results in gadget not
+ * working because gadget uses the same root hub. We disable
+ * this feature when OTG is selected.
+ */
+#if defined(CONFIG_PM) && defined(CONFIG_USB_EHCI_ARC_OTG)
+ hdev->autosuspend_disabled = 1;
+#endif
#ifdef CONFIG_USB_OTG_BLACKLIST_HUB
if (hdev->parent) {
@@ -2631,6 +2659,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) {
+ HW_USBPHY_CTRL_SET(
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT
+ );
+ }
+ }
+ }
+#endif
+
if (retval)
goto fail;
@@ -2755,6 +2796,34 @@ 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*/
+ HW_USBPHY_CTRL_CLR(
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT);
+ }
+ }
+ }
+#endif
+
+
if (hub->has_indicators) {
set_port_led(hub, port1, HUB_LED_AUTO);
hub->indicator[port1-1] = INDICATOR_AUTO;
@@ -2833,6 +2902,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
return;
}
+
for (i = 0; i < SET_CONFIG_TRIES; i++) {
/* reallocate for each attempt, since references