diff options
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/musb/musb_core.c | 25 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 3 | ||||
-rw-r--r-- | drivers/usb/musb/musb_host.h | 2 | ||||
-rw-r--r-- | drivers/usb/musb/musb_virthub.c | 65 |
4 files changed, 61 insertions, 34 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 1ecdb94f3812..0e7f4a00ca7b 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c | |||
@@ -478,8 +478,8 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb, | |||
478 | musb->port1_status |= | 478 | musb->port1_status |= |
479 | (USB_PORT_STAT_C_SUSPEND << 16) | 479 | (USB_PORT_STAT_C_SUSPEND << 16) |
480 | | MUSB_PORT_STAT_RESUME; | 480 | | MUSB_PORT_STAT_RESUME; |
481 | musb->rh_timer = jiffies | 481 | schedule_delayed_work( |
482 | + msecs_to_jiffies(20); | 482 | &musb->finish_resume_work, 20); |
483 | 483 | ||
484 | musb->xceiv->state = OTG_STATE_A_HOST; | 484 | musb->xceiv->state = OTG_STATE_A_HOST; |
485 | musb->is_active = 1; | 485 | musb->is_active = 1; |
@@ -1813,6 +1813,21 @@ static void musb_free(struct musb *musb) | |||
1813 | musb_host_free(musb); | 1813 | musb_host_free(musb); |
1814 | } | 1814 | } |
1815 | 1815 | ||
1816 | static void musb_deassert_reset(struct work_struct *work) | ||
1817 | { | ||
1818 | struct musb *musb; | ||
1819 | unsigned long flags; | ||
1820 | |||
1821 | musb = container_of(work, struct musb, deassert_reset_work.work); | ||
1822 | |||
1823 | spin_lock_irqsave(&musb->lock, flags); | ||
1824 | |||
1825 | if (musb->port1_status & USB_PORT_STAT_RESET) | ||
1826 | musb_port_reset(musb, false); | ||
1827 | |||
1828 | spin_unlock_irqrestore(&musb->lock, flags); | ||
1829 | } | ||
1830 | |||
1816 | /* | 1831 | /* |
1817 | * Perform generic per-controller initialization. | 1832 | * Perform generic per-controller initialization. |
1818 | * | 1833 | * |
@@ -1897,6 +1912,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) | |||
1897 | 1912 | ||
1898 | /* Init IRQ workqueue before request_irq */ | 1913 | /* Init IRQ workqueue before request_irq */ |
1899 | INIT_WORK(&musb->irq_work, musb_irq_work); | 1914 | INIT_WORK(&musb->irq_work, musb_irq_work); |
1915 | INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); | ||
1916 | INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); | ||
1900 | 1917 | ||
1901 | /* setup musb parts of the core (especially endpoints) */ | 1918 | /* setup musb parts of the core (especially endpoints) */ |
1902 | status = musb_core_init(plat->config->multipoint | 1919 | status = musb_core_init(plat->config->multipoint |
@@ -1990,6 +2007,8 @@ fail4: | |||
1990 | 2007 | ||
1991 | fail3: | 2008 | fail3: |
1992 | cancel_work_sync(&musb->irq_work); | 2009 | cancel_work_sync(&musb->irq_work); |
2010 | cancel_delayed_work_sync(&musb->finish_resume_work); | ||
2011 | cancel_delayed_work_sync(&musb->deassert_reset_work); | ||
1993 | if (musb->dma_controller) | 2012 | if (musb->dma_controller) |
1994 | dma_controller_destroy(musb->dma_controller); | 2013 | dma_controller_destroy(musb->dma_controller); |
1995 | fail2_5: | 2014 | fail2_5: |
@@ -2053,6 +2072,8 @@ static int musb_remove(struct platform_device *pdev) | |||
2053 | dma_controller_destroy(musb->dma_controller); | 2072 | dma_controller_destroy(musb->dma_controller); |
2054 | 2073 | ||
2055 | cancel_work_sync(&musb->irq_work); | 2074 | cancel_work_sync(&musb->irq_work); |
2075 | cancel_delayed_work_sync(&musb->finish_resume_work); | ||
2076 | cancel_delayed_work_sync(&musb->deassert_reset_work); | ||
2056 | musb_free(musb); | 2077 | musb_free(musb); |
2057 | device_init_wakeup(dev, 0); | 2078 | device_init_wakeup(dev, 0); |
2058 | return 0; | 2079 | return 0; |
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 29f7cd7c7964..7083e82776ff 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h | |||
@@ -47,6 +47,7 @@ | |||
47 | #include <linux/usb/otg.h> | 47 | #include <linux/usb/otg.h> |
48 | #include <linux/usb/musb.h> | 48 | #include <linux/usb/musb.h> |
49 | #include <linux/phy/phy.h> | 49 | #include <linux/phy/phy.h> |
50 | #include <linux/workqueue.h> | ||
50 | 51 | ||
51 | struct musb; | 52 | struct musb; |
52 | struct musb_hw_ep; | 53 | struct musb_hw_ep; |
@@ -295,6 +296,8 @@ struct musb { | |||
295 | 296 | ||
296 | irqreturn_t (*isr)(int, void *); | 297 | irqreturn_t (*isr)(int, void *); |
297 | struct work_struct irq_work; | 298 | struct work_struct irq_work; |
299 | struct delayed_work deassert_reset_work; | ||
300 | struct delayed_work finish_resume_work; | ||
298 | u16 hwvers; | 301 | u16 hwvers; |
299 | 302 | ||
300 | u16 intrrxe; | 303 | u16 intrrxe; |
diff --git a/drivers/usb/musb/musb_host.h b/drivers/usb/musb/musb_host.h index 7436c24af0ff..909ba49ef069 100644 --- a/drivers/usb/musb/musb_host.h +++ b/drivers/usb/musb/musb_host.h | |||
@@ -94,6 +94,7 @@ extern void musb_host_resume_root_hub(struct musb *musb); | |||
94 | extern void musb_host_poke_root_hub(struct musb *musb); | 94 | extern void musb_host_poke_root_hub(struct musb *musb); |
95 | extern void musb_port_suspend(struct musb *musb, bool do_suspend); | 95 | extern void musb_port_suspend(struct musb *musb, bool do_suspend); |
96 | extern void musb_port_reset(struct musb *musb, bool do_reset); | 96 | extern void musb_port_reset(struct musb *musb, bool do_reset); |
97 | extern void musb_host_finish_resume(struct work_struct *work); | ||
97 | #else | 98 | #else |
98 | static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) | 99 | static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) |
99 | { | 100 | { |
@@ -125,6 +126,7 @@ static inline void musb_host_poll_rh_status(struct musb *musb) {} | |||
125 | static inline void musb_host_poke_root_hub(struct musb *musb) {} | 126 | static inline void musb_host_poke_root_hub(struct musb *musb) {} |
126 | static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} | 127 | static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} |
127 | static inline void musb_port_reset(struct musb *musb) {} | 128 | static inline void musb_port_reset(struct musb *musb) {} |
129 | static inline void musb_host_finish_resume(struct work_struct *work) {} | ||
128 | #endif | 130 | #endif |
129 | 131 | ||
130 | struct usb_hcd; | 132 | struct usb_hcd; |
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c index 24e46c0c84b5..ad417fd0e1a7 100644 --- a/drivers/usb/musb/musb_virthub.c +++ b/drivers/usb/musb/musb_virthub.c | |||
@@ -44,6 +44,37 @@ | |||
44 | 44 | ||
45 | #include "musb_core.h" | 45 | #include "musb_core.h" |
46 | 46 | ||
47 | void musb_host_finish_resume(struct work_struct *work) | ||
48 | { | ||
49 | struct musb *musb; | ||
50 | unsigned long flags; | ||
51 | u8 power; | ||
52 | |||
53 | musb = container_of(work, struct musb, deassert_reset_work.work); | ||
54 | |||
55 | spin_lock_irqsave(&musb->lock, flags); | ||
56 | |||
57 | power = musb_readb(musb->mregs, MUSB_POWER); | ||
58 | power &= ~MUSB_POWER_RESUME; | ||
59 | dev_dbg(musb->controller, "root port resume stopped, power %02x\n", | ||
60 | power); | ||
61 | musb_writeb(musb->mregs, MUSB_POWER, power); | ||
62 | |||
63 | /* | ||
64 | * ISSUE: DaVinci (RTL 1.300) disconnects after | ||
65 | * resume of high speed peripherals (but not full | ||
66 | * speed ones). | ||
67 | */ | ||
68 | musb->is_active = 1; | ||
69 | musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME); | ||
70 | musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; | ||
71 | usb_hcd_poll_rh_status(musb->hcd); | ||
72 | /* NOTE: it might really be A_WAIT_BCON ... */ | ||
73 | musb->xceiv->state = OTG_STATE_A_HOST; | ||
74 | |||
75 | spin_unlock_irqrestore(&musb->lock, flags); | ||
76 | } | ||
77 | |||
47 | void musb_port_suspend(struct musb *musb, bool do_suspend) | 78 | void musb_port_suspend(struct musb *musb, bool do_suspend) |
48 | { | 79 | { |
49 | struct usb_otg *otg = musb->xceiv->otg; | 80 | struct usb_otg *otg = musb->xceiv->otg; |
@@ -105,7 +136,7 @@ void musb_port_suspend(struct musb *musb, bool do_suspend) | |||
105 | 136 | ||
106 | /* later, GetPortStatus will stop RESUME signaling */ | 137 | /* later, GetPortStatus will stop RESUME signaling */ |
107 | musb->port1_status |= MUSB_PORT_STAT_RESUME; | 138 | musb->port1_status |= MUSB_PORT_STAT_RESUME; |
108 | musb->rh_timer = jiffies + msecs_to_jiffies(20); | 139 | schedule_delayed_work(&musb->finish_resume_work, 20); |
109 | } | 140 | } |
110 | } | 141 | } |
111 | 142 | ||
@@ -150,7 +181,7 @@ void musb_port_reset(struct musb *musb, bool do_reset) | |||
150 | 181 | ||
151 | musb->port1_status |= USB_PORT_STAT_RESET; | 182 | musb->port1_status |= USB_PORT_STAT_RESET; |
152 | musb->port1_status &= ~USB_PORT_STAT_ENABLE; | 183 | musb->port1_status &= ~USB_PORT_STAT_ENABLE; |
153 | musb->rh_timer = jiffies + msecs_to_jiffies(50); | 184 | schedule_delayed_work(&musb->deassert_reset_work, 50); |
154 | } else { | 185 | } else { |
155 | dev_dbg(musb->controller, "root port reset stopped\n"); | 186 | dev_dbg(musb->controller, "root port reset stopped\n"); |
156 | musb_writeb(mbase, MUSB_POWER, | 187 | musb_writeb(mbase, MUSB_POWER, |
@@ -325,36 +356,6 @@ int musb_hub_control( | |||
325 | if (wIndex != 1) | 356 | if (wIndex != 1) |
326 | goto error; | 357 | goto error; |
327 | 358 | ||
328 | /* finish RESET signaling? */ | ||
329 | if ((musb->port1_status & USB_PORT_STAT_RESET) | ||
330 | && time_after_eq(jiffies, musb->rh_timer)) | ||
331 | musb_port_reset(musb, false); | ||
332 | |||
333 | /* finish RESUME signaling? */ | ||
334 | if ((musb->port1_status & MUSB_PORT_STAT_RESUME) | ||
335 | && time_after_eq(jiffies, musb->rh_timer)) { | ||
336 | u8 power; | ||
337 | |||
338 | power = musb_readb(musb->mregs, MUSB_POWER); | ||
339 | power &= ~MUSB_POWER_RESUME; | ||
340 | dev_dbg(musb->controller, "root port resume stopped, power %02x\n", | ||
341 | power); | ||
342 | musb_writeb(musb->mregs, MUSB_POWER, power); | ||
343 | |||
344 | /* ISSUE: DaVinci (RTL 1.300) disconnects after | ||
345 | * resume of high speed peripherals (but not full | ||
346 | * speed ones). | ||
347 | */ | ||
348 | |||
349 | musb->is_active = 1; | ||
350 | musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | ||
351 | | MUSB_PORT_STAT_RESUME); | ||
352 | musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; | ||
353 | usb_hcd_poll_rh_status(musb->hcd); | ||
354 | /* NOTE: it might really be A_WAIT_BCON ... */ | ||
355 | musb->xceiv->state = OTG_STATE_A_HOST; | ||
356 | } | ||
357 | |||
358 | put_unaligned(cpu_to_le32(musb->port1_status | 359 | put_unaligned(cpu_to_le32(musb->port1_status |
359 | & ~MUSB_PORT_STAT_RESUME), | 360 | & ~MUSB_PORT_STAT_RESUME), |
360 | (__le32 *) buf); | 361 | (__le32 *) buf); |