aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/musb/musb_core.c25
-rw-r--r--drivers/usb/musb/musb_core.h3
-rw-r--r--drivers/usb/musb/musb_host.h2
-rw-r--r--drivers/usb/musb/musb_virthub.c65
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
1816static 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
1991fail3: 2008fail3:
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);
1995fail2_5: 2014fail2_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
51struct musb; 52struct musb;
52struct musb_hw_ep; 53struct 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);
94extern void musb_host_poke_root_hub(struct musb *musb); 94extern void musb_host_poke_root_hub(struct musb *musb);
95extern void musb_port_suspend(struct musb *musb, bool do_suspend); 95extern void musb_port_suspend(struct musb *musb, bool do_suspend);
96extern void musb_port_reset(struct musb *musb, bool do_reset); 96extern void musb_port_reset(struct musb *musb, bool do_reset);
97extern void musb_host_finish_resume(struct work_struct *work);
97#else 98#else
98static inline struct musb *hcd_to_musb(struct usb_hcd *hcd) 99static 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) {}
125static inline void musb_host_poke_root_hub(struct musb *musb) {} 126static inline void musb_host_poke_root_hub(struct musb *musb) {}
126static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {} 127static inline void musb_port_suspend(struct musb *musb, bool do_suspend) {}
127static inline void musb_port_reset(struct musb *musb) {} 128static inline void musb_port_reset(struct musb *musb) {}
129static inline void musb_host_finish_resume(struct work_struct *work) {}
128#endif 130#endif
129 131
130struct usb_hcd; 132struct 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
47void 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
47void musb_port_suspend(struct musb *musb, bool do_suspend) 78void 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);