diff options
author | Daniel Mack <zonque@gmail.com> | 2014-04-02 07:58:28 -0400 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2014-04-21 15:07:28 -0400 |
commit | ca88fc2ef0d790a1da37804219102336f7622b97 (patch) | |
tree | 6fba0f43345cda2e2a4463ec6cc3f3a38c8e8125 | |
parent | 1e42d20c88f2f56c0d81363d7b0f1d3762037f53 (diff) |
usb: musb: add a work_struct to recover from babble errors
Handle BABBLE interrupt error conditions from a work struct handler.
This indirection is necessary as we can't be certain that the phy
functions don't sleep.
Platform layer implementation may pass a babble error down to the core
in order to handle it.
Signed-off-by: Daniel Mack <zonque@gmail.com>
Signed-off-by: Felipe Balbi <balbi@ti.com>
-rw-r--r-- | drivers/usb/musb/musb_core.c | 35 | ||||
-rw-r--r-- | drivers/usb/musb/musb_core.h | 1 |
2 files changed, 36 insertions, 0 deletions
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c index 07576907e2c6..61da471b7aed 100644 --- a/drivers/usb/musb/musb_core.c +++ b/drivers/usb/musb/musb_core.c | |||
@@ -848,6 +848,10 @@ b_host: | |||
848 | } | 848 | } |
849 | } | 849 | } |
850 | 850 | ||
851 | /* handle babble condition */ | ||
852 | if (int_usb & MUSB_INTR_BABBLE) | ||
853 | schedule_work(&musb->recover_work); | ||
854 | |||
851 | #if 0 | 855 | #if 0 |
852 | /* REVISIT ... this would be for multiplexing periodic endpoints, or | 856 | /* REVISIT ... this would be for multiplexing periodic endpoints, or |
853 | * supporting transfer phasing to prevent exceeding ISO bandwidth | 857 | * supporting transfer phasing to prevent exceeding ISO bandwidth |
@@ -1746,6 +1750,34 @@ static void musb_irq_work(struct work_struct *data) | |||
1746 | } | 1750 | } |
1747 | } | 1751 | } |
1748 | 1752 | ||
1753 | /* Recover from babble interrupt conditions */ | ||
1754 | static void musb_recover_work(struct work_struct *data) | ||
1755 | { | ||
1756 | struct musb *musb = container_of(data, struct musb, recover_work); | ||
1757 | int status; | ||
1758 | |||
1759 | musb_platform_reset(musb); | ||
1760 | |||
1761 | usb_phy_vbus_off(musb->xceiv); | ||
1762 | udelay(100); | ||
1763 | |||
1764 | usb_phy_vbus_on(musb->xceiv); | ||
1765 | udelay(100); | ||
1766 | |||
1767 | /* | ||
1768 | * When a babble condition occurs, the musb controller removes the | ||
1769 | * session bit and the endpoint config is lost. | ||
1770 | */ | ||
1771 | if (musb->dyn_fifo) | ||
1772 | status = ep_config_from_table(musb); | ||
1773 | else | ||
1774 | status = ep_config_from_hw(musb); | ||
1775 | |||
1776 | /* start the session again */ | ||
1777 | if (status == 0) | ||
1778 | musb_start(musb); | ||
1779 | } | ||
1780 | |||
1749 | /* -------------------------------------------------------------------------- | 1781 | /* -------------------------------------------------------------------------- |
1750 | * Init support | 1782 | * Init support |
1751 | */ | 1783 | */ |
@@ -1913,6 +1945,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl) | |||
1913 | 1945 | ||
1914 | /* Init IRQ workqueue before request_irq */ | 1946 | /* Init IRQ workqueue before request_irq */ |
1915 | INIT_WORK(&musb->irq_work, musb_irq_work); | 1947 | INIT_WORK(&musb->irq_work, musb_irq_work); |
1948 | INIT_WORK(&musb->recover_work, musb_recover_work); | ||
1916 | INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); | 1949 | INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset); |
1917 | INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); | 1950 | INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume); |
1918 | 1951 | ||
@@ -2008,6 +2041,7 @@ fail4: | |||
2008 | 2041 | ||
2009 | fail3: | 2042 | fail3: |
2010 | cancel_work_sync(&musb->irq_work); | 2043 | cancel_work_sync(&musb->irq_work); |
2044 | cancel_work_sync(&musb->recover_work); | ||
2011 | cancel_delayed_work_sync(&musb->finish_resume_work); | 2045 | cancel_delayed_work_sync(&musb->finish_resume_work); |
2012 | cancel_delayed_work_sync(&musb->deassert_reset_work); | 2046 | cancel_delayed_work_sync(&musb->deassert_reset_work); |
2013 | if (musb->dma_controller) | 2047 | if (musb->dma_controller) |
@@ -2073,6 +2107,7 @@ static int musb_remove(struct platform_device *pdev) | |||
2073 | dma_controller_destroy(musb->dma_controller); | 2107 | dma_controller_destroy(musb->dma_controller); |
2074 | 2108 | ||
2075 | cancel_work_sync(&musb->irq_work); | 2109 | cancel_work_sync(&musb->irq_work); |
2110 | cancel_work_sync(&musb->recover_work); | ||
2076 | cancel_delayed_work_sync(&musb->finish_resume_work); | 2111 | cancel_delayed_work_sync(&musb->finish_resume_work); |
2077 | cancel_delayed_work_sync(&musb->deassert_reset_work); | 2112 | cancel_delayed_work_sync(&musb->deassert_reset_work); |
2078 | musb_free(musb); | 2113 | musb_free(musb); |
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index 5514e4c82932..47e88747e3a7 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h | |||
@@ -297,6 +297,7 @@ struct musb { | |||
297 | 297 | ||
298 | irqreturn_t (*isr)(int, void *); | 298 | irqreturn_t (*isr)(int, void *); |
299 | struct work_struct irq_work; | 299 | struct work_struct irq_work; |
300 | struct work_struct recover_work; | ||
300 | struct delayed_work deassert_reset_work; | 301 | struct delayed_work deassert_reset_work; |
301 | struct delayed_work finish_resume_work; | 302 | struct delayed_work finish_resume_work; |
302 | u16 hwvers; | 303 | u16 hwvers; |