aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTony Lindgren <tony@atomide.com>2016-11-16 14:21:24 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-11-17 10:25:39 -0500
commit2bff3916fda9145587c0312b6f5c43d82504980c (patch)
tree6c0c568449f914ed75b945d03754aea2adf6dccc
parentea2f35c01d5ea72b43b9b4fb4c5b9417a9eb2fb8 (diff)
usb: musb: Fix PM for hub disconnect
With a USB hub disconnected, devctl can be 0x19 for about a second on am335x and will stay forever on at least omap3. And we get no further interrupts when devctl session bit clears. This keeps PM runtime active. Let's fix the issue by polling devctl until the session bit clears or times out. We can do this by making musb->irq_work into delayed_work. And with the polling implemented, we can now also have the quirk for invalid VBUS it to avoid disconnecting too early while VBUS is ramping up. Fixes: 467d5c980709 ("usb: musb: Implement session bit based runtime PM for musb-core") Fixes: 65b3f50ed6fa ("usb: musb: Add PM runtime support for MUSB DSPS Tested-by: Ladislav Michl <ladis@linux-mips.org> Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Tony Lindgren <tony@atomide.com> Signed-off-by: Bin Liu <b-liu@ti.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/musb/musb_core.c29
-rw-r--r--drivers/usb/musb/musb_core.h4
-rw-r--r--drivers/usb/musb/musb_gadget.c6
-rw-r--r--drivers/usb/musb/tusb6010.c6
4 files changed, 27 insertions, 18 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 384de6cd26f5..c3e172e15ec3 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -986,7 +986,7 @@ b_host:
986 } 986 }
987#endif 987#endif
988 988
989 schedule_work(&musb->irq_work); 989 schedule_delayed_work(&musb->irq_work, 0);
990 990
991 return handled; 991 return handled;
992} 992}
@@ -1855,14 +1855,23 @@ static void musb_pm_runtime_check_session(struct musb *musb)
1855 MUSB_DEVCTL_HR; 1855 MUSB_DEVCTL_HR;
1856 switch (devctl & ~s) { 1856 switch (devctl & ~s) {
1857 case MUSB_QUIRK_B_INVALID_VBUS_91: 1857 case MUSB_QUIRK_B_INVALID_VBUS_91:
1858 if (!musb->session && !musb->quirk_invalid_vbus) { 1858 if (musb->quirk_retries--) {
1859 musb->quirk_invalid_vbus = true;
1860 musb_dbg(musb, 1859 musb_dbg(musb,
1861 "First invalid vbus, assume no session"); 1860 "Poll devctl on invalid vbus, assume no session");
1861 schedule_delayed_work(&musb->irq_work,
1862 msecs_to_jiffies(1000));
1863
1862 return; 1864 return;
1863 } 1865 }
1864 break;
1865 case MUSB_QUIRK_A_DISCONNECT_19: 1866 case MUSB_QUIRK_A_DISCONNECT_19:
1867 if (musb->quirk_retries--) {
1868 musb_dbg(musb,
1869 "Poll devctl on possible host mode disconnect");
1870 schedule_delayed_work(&musb->irq_work,
1871 msecs_to_jiffies(1000));
1872
1873 return;
1874 }
1866 if (!musb->session) 1875 if (!musb->session)
1867 break; 1876 break;
1868 musb_dbg(musb, "Allow PM on possible host mode disconnect"); 1877 musb_dbg(musb, "Allow PM on possible host mode disconnect");
@@ -1886,9 +1895,9 @@ static void musb_pm_runtime_check_session(struct musb *musb)
1886 if (error < 0) 1895 if (error < 0)
1887 dev_err(musb->controller, "Could not enable: %i\n", 1896 dev_err(musb->controller, "Could not enable: %i\n",
1888 error); 1897 error);
1898 musb->quirk_retries = 3;
1889 } else { 1899 } else {
1890 musb_dbg(musb, "Allow PM with no session: %02x", devctl); 1900 musb_dbg(musb, "Allow PM with no session: %02x", devctl);
1891 musb->quirk_invalid_vbus = false;
1892 pm_runtime_mark_last_busy(musb->controller); 1901 pm_runtime_mark_last_busy(musb->controller);
1893 pm_runtime_put_autosuspend(musb->controller); 1902 pm_runtime_put_autosuspend(musb->controller);
1894 } 1903 }
@@ -1899,7 +1908,7 @@ static void musb_pm_runtime_check_session(struct musb *musb)
1899/* Only used to provide driver mode change events */ 1908/* Only used to provide driver mode change events */
1900static void musb_irq_work(struct work_struct *data) 1909static void musb_irq_work(struct work_struct *data)
1901{ 1910{
1902 struct musb *musb = container_of(data, struct musb, irq_work); 1911 struct musb *musb = container_of(data, struct musb, irq_work.work);
1903 1912
1904 musb_pm_runtime_check_session(musb); 1913 musb_pm_runtime_check_session(musb);
1905 1914
@@ -2288,7 +2297,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
2288 musb_generic_disable(musb); 2297 musb_generic_disable(musb);
2289 2298
2290 /* Init IRQ workqueue before request_irq */ 2299 /* Init IRQ workqueue before request_irq */
2291 INIT_WORK(&musb->irq_work, musb_irq_work); 2300 INIT_DELAYED_WORK(&musb->irq_work, musb_irq_work);
2292 INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); 2301 INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
2293 INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); 2302 INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume);
2294 2303
@@ -2385,7 +2394,7 @@ fail4:
2385 musb_host_cleanup(musb); 2394 musb_host_cleanup(musb);
2386 2395
2387fail3: 2396fail3:
2388 cancel_work_sync(&musb->irq_work); 2397 cancel_delayed_work_sync(&musb->irq_work);
2389 cancel_delayed_work_sync(&musb->finish_resume_work); 2398 cancel_delayed_work_sync(&musb->finish_resume_work);
2390 cancel_delayed_work_sync(&musb->deassert_reset_work); 2399 cancel_delayed_work_sync(&musb->deassert_reset_work);
2391 if (musb->dma_controller) 2400 if (musb->dma_controller)
@@ -2452,7 +2461,7 @@ static int musb_remove(struct platform_device *pdev)
2452 */ 2461 */
2453 musb_exit_debugfs(musb); 2462 musb_exit_debugfs(musb);
2454 2463
2455 cancel_work_sync(&musb->irq_work); 2464 cancel_delayed_work_sync(&musb->irq_work);
2456 cancel_delayed_work_sync(&musb->finish_resume_work); 2465 cancel_delayed_work_sync(&musb->finish_resume_work);
2457 cancel_delayed_work_sync(&musb->deassert_reset_work); 2466 cancel_delayed_work_sync(&musb->deassert_reset_work);
2458 pm_runtime_get_sync(musb->controller); 2467 pm_runtime_get_sync(musb->controller);
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 15b1f93c7037..91817d77d59c 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -310,7 +310,7 @@ struct musb {
310 struct musb_context_registers context; 310 struct musb_context_registers context;
311 311
312 irqreturn_t (*isr)(int, void *); 312 irqreturn_t (*isr)(int, void *);
313 struct work_struct irq_work; 313 struct delayed_work irq_work;
314 struct delayed_work deassert_reset_work; 314 struct delayed_work deassert_reset_work;
315 struct delayed_work finish_resume_work; 315 struct delayed_work finish_resume_work;
316 struct delayed_work gadget_work; 316 struct delayed_work gadget_work;
@@ -381,7 +381,7 @@ struct musb {
381 381
382 int port_mode; /* MUSB_PORT_MODE_* */ 382 int port_mode; /* MUSB_PORT_MODE_* */
383 bool session; 383 bool session;
384 bool quirk_invalid_vbus; 384 unsigned long quirk_retries;
385 bool is_host; 385 bool is_host;
386 386
387 int a_wait_bcon; /* VBUS timeout in msecs */ 387 int a_wait_bcon; /* VBUS timeout in msecs */
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 910f50967627..a55173c9e564 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1114,7 +1114,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
1114 musb_ep->dma ? "dma, " : "", 1114 musb_ep->dma ? "dma, " : "",
1115 musb_ep->packet_sz); 1115 musb_ep->packet_sz);
1116 1116
1117 schedule_work(&musb->irq_work); 1117 schedule_delayed_work(&musb->irq_work, 0);
1118 1118
1119fail: 1119fail:
1120 spin_unlock_irqrestore(&musb->lock, flags); 1120 spin_unlock_irqrestore(&musb->lock, flags);
@@ -1158,7 +1158,7 @@ static int musb_gadget_disable(struct usb_ep *ep)
1158 musb_ep->desc = NULL; 1158 musb_ep->desc = NULL;
1159 musb_ep->end_point.desc = NULL; 1159 musb_ep->end_point.desc = NULL;
1160 1160
1161 schedule_work(&musb->irq_work); 1161 schedule_delayed_work(&musb->irq_work, 0);
1162 1162
1163 spin_unlock_irqrestore(&(musb->lock), flags); 1163 spin_unlock_irqrestore(&(musb->lock), flags);
1164 1164
@@ -1994,7 +1994,7 @@ static int musb_gadget_stop(struct usb_gadget *g)
1994 */ 1994 */
1995 1995
1996 /* Force check of devctl register for PM runtime */ 1996 /* Force check of devctl register for PM runtime */
1997 schedule_work(&musb->irq_work); 1997 schedule_delayed_work(&musb->irq_work, 0);
1998 1998
1999 pm_runtime_mark_last_busy(musb->controller); 1999 pm_runtime_mark_last_busy(musb->controller);
2000 pm_runtime_put_autosuspend(musb->controller); 2000 pm_runtime_put_autosuspend(musb->controller);
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index df7c9f46be54..e85cc8e4e7a9 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -724,7 +724,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
724 dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", 724 dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
725 usb_otg_state_string(musb->xceiv->otg->state), otg_stat); 725 usb_otg_state_string(musb->xceiv->otg->state), otg_stat);
726 idle_timeout = jiffies + (1 * HZ); 726 idle_timeout = jiffies + (1 * HZ);
727 schedule_work(&musb->irq_work); 727 schedule_delayed_work(&musb->irq_work, 0);
728 728
729 } else /* A-dev state machine */ { 729 } else /* A-dev state machine */ {
730 dev_dbg(musb->controller, "vbus change, %s, otg %03x\n", 730 dev_dbg(musb->controller, "vbus change, %s, otg %03x\n",
@@ -814,7 +814,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
814 break; 814 break;
815 } 815 }
816 } 816 }
817 schedule_work(&musb->irq_work); 817 schedule_delayed_work(&musb->irq_work, 0);
818 818
819 return idle_timeout; 819 return idle_timeout;
820} 820}
@@ -864,7 +864,7 @@ static irqreturn_t tusb_musb_interrupt(int irq, void *__hci)
864 musb_writel(tbase, TUSB_PRCM_WAKEUP_CLEAR, reg); 864 musb_writel(tbase, TUSB_PRCM_WAKEUP_CLEAR, reg);
865 if (reg & ~TUSB_PRCM_WNORCS) { 865 if (reg & ~TUSB_PRCM_WNORCS) {
866 musb->is_active = 1; 866 musb->is_active = 1;
867 schedule_work(&musb->irq_work); 867 schedule_delayed_work(&musb->irq_work, 0);
868 } 868 }
869 dev_dbg(musb->controller, "wake %sactive %02x\n", 869 dev_dbg(musb->controller, "wake %sactive %02x\n",
870 musb->is_active ? "" : "in", reg); 870 musb->is_active ? "" : "in", reg);