diff options
Diffstat (limited to 'drivers/usb/core/hub.c')
-rw-r--r-- | drivers/usb/core/hub.c | 97 |
1 files changed, 97 insertions, 0 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 71f86c60d83c..4abdddcff459 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -37,6 +37,24 @@ #endif #endif +#ifdef CONFIG_ARCH_STMP3XXX +#define STMP3XXX_USB_HOST_HACK +#endif + +#ifdef CONFIG_ARCH_MXS +#define MXS_USB_HOST_HACK + +#include <linux/fsl_devices.h> +extern void fsl_platform_set_usb_phy_dis(struct fsl_usb2_platform_data *pdata, + bool enable); +#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; @@ -1160,6 +1178,11 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) return -E2BIG; } + /* Defaultly disable autosuspend for hub and reley on sys + * to enable it. + */ + hdev->autosuspend_disabled = 1; + #ifdef CONFIG_USB_OTG_BLACKLIST_HUB if (hdev->parent) { dev_warn(&intf->dev, "ignoring external hub\n"); @@ -2696,6 +2719,33 @@ 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 + +#ifdef MXS_USB_HOST_HACK + { /*Must enable HOSTDISCONDETECT after second reset*/ + if (port1 == 1) { + if (udev->speed == USB_SPEED_HIGH) { + struct device *dev = hcd->self.controller; + struct fsl_usb2_platform_data *pdata; + pdata = (struct fsl_usb2_platform_data *) + dev->platform_data; + fsl_platform_set_usb_phy_dis(pdata, 1); + } + } + } +#endif + if (retval) goto fail; @@ -2823,6 +2873,53 @@ 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 + +#ifdef MXS_USB_HOST_HACK + { + 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*/ + fsl_platform_set_usb_phy_dis(pdata, 0); + } + } + } +#endif + if (hub->has_indicators) { set_port_led(hub, port1, HUB_LED_AUTO); hub->indicator[port1-1] = INDICATOR_AUTO; |