diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5dceb41ead3..d97d5480d93 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2808,6 +2808,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg) int usb_remote_wakeup(struct usb_device *udev) { int status = 0; + struct usb_hcd *hcd = bus_to_hcd(udev->bus); if (udev->state == USB_STATE_SUSPENDED) { dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-"); @@ -2816,7 +2817,11 @@ int usb_remote_wakeup(struct usb_device *udev) /* Let the drivers do their thing, then... */ usb_autosuspend_device(udev); } + } else { + dev_dbg(&udev->dev, "usb not suspended\n"); + clear_bit(HCD_FLAG_WAKEUP_PENDING, &hcd->flags); } + return status; } @@ -3152,7 +3157,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * value. */ for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) { - if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) { + if (USE_NEW_SCHEME(retry_counter) && + !(hcd->driver->flags & HCD_USB3) && + !(hcd->driver->flags & HCD_OLD_ENUM)) { struct usb_device_descriptor *buf; int r = 0; @@ -3252,7 +3259,9 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1, * - read ep0 maxpacket even for high and low speed, */ msleep(10); - if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) + if (USE_NEW_SCHEME(retry_counter) && + !(hcd->driver->flags & HCD_USB3) && + !(hcd->driver->flags & HCD_OLD_ENUM)) break; } diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index caf86caf68f..3098fbe1635 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c @@ -823,7 +823,7 @@ static int ehci_hub_control ( u32 __iomem *status_reg = &ehci->regs->port_status[ (wIndex & 0xff) - 1]; u32 __iomem *hostpc_reg = NULL; - u32 temp, temp1, status; + u32 temp, temp1, status, cmd = 0; unsigned long flags; int retval = 0; unsigned selector; @@ -1202,7 +1202,32 @@ static int ehci_hub_control ( ehci->reset_done [wIndex] = jiffies + msecs_to_jiffies (50); } + + if (ehci->reset_sof_bug && (temp & PORT_RESET)) { + cmd = ehci_readl(ehci, &ehci->regs->command); + cmd &= ~CMD_RUN; + ehci_writel(ehci, cmd, &ehci->regs->command); + if (handshake(ehci, &ehci->regs->status, + STS_HALT, STS_HALT, 16 * 125)) + ehci_info(ehci, + "controller halt failed\n"); + } ehci_writel(ehci, temp, status_reg); + if (ehci->reset_sof_bug && (temp & PORT_RESET) + && hcd->driver->enable_ulpi_control) { + hcd->driver->enable_ulpi_control(hcd, + PORT_RESET); + spin_unlock_irqrestore(&ehci->lock, flags); + usleep_range(50000, 55000); + if (handshake(ehci, status_reg, + PORT_RESET, 0, 10 * 1000)) + ehci_info(ehci, + "failed to clear reset\n"); + spin_lock_irqsave(&ehci->lock, flags); + hcd->driver->disable_ulpi_control(hcd); + cmd |= CMD_RUN; + ehci_writel(ehci, cmd, &ehci->regs->command); + } break; /* For downstream facing ports (these): one hub port is put diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c index 1c38bc90fee..a95198ca3c2 100644 --- a/drivers/usb/host/ehci-msm-hsic.c +++ b/drivers/usb/host/ehci-msm-hsic.c @@ -328,6 +328,29 @@ reg_enable_err: } +static int ulpi_read(struct msm_hsic_hcd *mehci, u32 reg) +{ + struct usb_hcd *hcd = hsic_to_hcd(mehci); + unsigned long timeout; + + /* initiate read operation */ + writel_relaxed(ULPI_RUN | ULPI_READ | ULPI_ADDR(reg), + USB_ULPI_VIEWPORT); + + /* wait for completion */ + timeout = jiffies + usecs_to_jiffies(ULPI_IO_TIMEOUT_USEC); + while (readl_relaxed(USB_ULPI_VIEWPORT) & ULPI_RUN) { + if (time_after(jiffies, timeout)) { + dev_err(mehci->dev, "ulpi_read: timeout %08x\n", + readl_relaxed(USB_ULPI_VIEWPORT)); + return -ETIMEDOUT; + } + udelay(1); + } + + return ULPI_DATA_READ(readl_relaxed(USB_ULPI_VIEWPORT)); +} + static int ulpi_write(struct msm_hsic_hcd *mehci, u32 val, u32 reg) { struct usb_hcd *hcd = hsic_to_hcd(mehci); @@ -354,6 +377,37 @@ static int ulpi_write(struct msm_hsic_hcd *mehci, u32 val, u32 reg) return 0; } +#define HSIC_DBG1 0X38 +#define ULPI_MANUAL_ENABLE BIT(4) +#define ULPI_LINESTATE_DATA BIT(5) +#define ULPI_LINESTATE_STROBE BIT(6) +static void ehci_msm_enable_ulpi_control(struct usb_hcd *hcd, u32 linestate) +{ + struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); + int val; + + switch (linestate) { + case PORT_RESET: + val = ulpi_read(mehci, HSIC_DBG1); + val |= ULPI_MANUAL_ENABLE; + val &= ~(ULPI_LINESTATE_DATA | ULPI_LINESTATE_STROBE); + ulpi_write(mehci, val, HSIC_DBG1); + break; + default: + pr_info("%s: Unknown linestate:%0x\n", __func__, linestate); + } +} + +static void ehci_msm_disable_ulpi_control(struct usb_hcd *hcd) +{ + struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd); + int val; + + val = ulpi_read(mehci, HSIC_DBG1); + val &= ~ULPI_MANUAL_ENABLE; + ulpi_write(mehci, val, HSIC_DBG1); +} + static int msm_hsic_config_gpios(struct msm_hsic_hcd *mehci, int gpio_en) { int rc = 0; @@ -788,7 +842,7 @@ static struct hc_driver msm_hsic_driver = { * generic hardware linkage */ .irq = msm_hsic_irq, - .flags = HCD_USB2 | HCD_MEMORY, + .flags = HCD_USB2 | HCD_MEMORY | HCD_OLD_ENUM, .reset = ehci_hsic_reset, .start = ehci_run, @@ -825,6 +879,9 @@ static struct hc_driver msm_hsic_driver = { .bus_resume = ehci_hsic_bus_resume, .log_urb_complete = dbg_log_event, + + .enable_ulpi_control = ehci_msm_enable_ulpi_control, + .disable_ulpi_control = ehci_msm_disable_ulpi_control, }; static int msm_hsic_init_clocks(struct msm_hsic_hcd *mehci, u32 init) @@ -1187,6 +1244,7 @@ static int __devinit ehci_hsic_msm_probe(struct platform_device *pdev) mehci->dev = &pdev->dev; mehci->ehci.susp_sof_bug = 1; + mehci->ehci.reset_sof_bug = 1; mehci->ehci.max_log2_irq_thresh = 6; diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 72cf6416245..fc0ed611de1 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -152,6 +152,7 @@ struct ehci_hcd { /* one per controller */ unsigned has_synopsys_hc_bug:1; /* Synopsys HC */ unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */ unsigned susp_sof_bug:1; /*Chip Idea HC*/ + unsigned reset_sof_bug:1; /*Chip Idea HC*/ /* required for usb32 quirk */ #define OHCI_CTRL_HCFS (3 << 6) diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index d9ec3326cd7..eabe4e89e66 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -212,6 +212,7 @@ struct hc_driver { #define HCD_MEMORY 0x0001 /* HC regs use memory (else I/O) */ #define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */ #define HCD_SHARED 0x0004 /* Two (or more) usb_hcds share HW */ +#define HCD_OLD_ENUM 0x0008 /* HC supports short enumeration */ #define HCD_USB11 0x0010 /* USB 1.1 */ #define HCD_USB2 0x0020 /* USB 2.0 */ #define HCD_USB3 0x0040 /* USB 3.0 */ @@ -348,6 +349,8 @@ struct hc_driver { /* to log completion events*/ void (*log_urb_complete)(struct urb *urb, char * event, unsigned extra); + void (*enable_ulpi_control)(struct usb_hcd *hcd, u32 linestate); + void (*disable_ulpi_control)(struct usb_hcd *hcd); }; extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);