diff options
Diffstat (limited to 'drivers/usb/host/ehci.h')
-rw-r--r-- | drivers/usb/host/ehci.h | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index b11798d17ae5..fb7054ccf4fc 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -120,6 +120,16 @@ struct ehci_hcd { /* one per controller */ unsigned has_fsl_port_bug:1; /* FreeScale */ unsigned big_endian_mmio:1; unsigned big_endian_desc:1; + unsigned has_amcc_usb23:1; + + /* required for usb32 quirk */ + #define OHCI_CTRL_HCFS (3 << 6) + #define OHCI_USB_OPER (2 << 6) + #define OHCI_USB_SUSPEND (3 << 6) + + #define OHCI_HCCTRL_OFFSET 0x4 + #define OHCI_HCCTRL_LEN 0x4 + __hc32 *ohci_hcctrl_reg; u8 sbrn; /* packed release number */ @@ -183,16 +193,14 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) * the async ring; just the I/O watchdog. Note that if a * SHRINK were pending, OFF would never be requested. */ - enum ehci_timer_action oldactions = ehci->actions; + if (timer_pending(&ehci->watchdog) + && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF)) + & ehci->actions)) + return; if (!test_and_set_bit (action, &ehci->actions)) { unsigned long t; - if (timer_pending(&ehci->watchdog) - && ((BIT(TIMER_ASYNC_SHRINK) | BIT(TIMER_ASYNC_OFF)) - & oldactions)) - return; - switch (action) { case TIMER_IO_WATCHDOG: t = EHCI_IO_JIFFIES; @@ -208,7 +216,7 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action) t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1; break; } - mod_timer(&ehci->watchdog, round_jiffies(t + jiffies)); + mod_timer(&ehci->watchdog, t + jiffies); } } @@ -638,6 +646,30 @@ static inline void ehci_writel(const struct ehci_hcd *ehci, #endif } +/* + * On certain ppc-44x SoC there is a HW issue, that could only worked around with + * explicit suspend/operate of OHCI. This function hereby makes sense only on that arch. + * Other common bits are dependant on has_amcc_usb23 quirk flag. + */ +#ifdef CONFIG_44x +static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational) +{ + u32 hc_control; + + hc_control = (readl_be(ehci->ohci_hcctrl_reg) & ~OHCI_CTRL_HCFS); + if (operational) + hc_control |= OHCI_USB_OPER; + else + hc_control |= OHCI_USB_SUSPEND; + + writel_be(hc_control, ehci->ohci_hcctrl_reg); + (void) readl_be(ehci->ohci_hcctrl_reg); +} +#else +static inline void set_ohci_hcfs(struct ehci_hcd *ehci, int operational) +{ } +#endif + /*-------------------------------------------------------------------------*/ /* |