Commit ca88fc2e authored by Daniel Mack's avatar Daniel Mack Committed by Felipe Balbi

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: default avatarDaniel Mack <zonque@gmail.com>
Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 1e42d20c
......@@ -848,6 +848,10 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
}
/* handle babble condition */
if (int_usb & MUSB_INTR_BABBLE)
schedule_work(&musb->recover_work);
#if 0
/* REVISIT ... this would be for multiplexing periodic endpoints, or
* supporting transfer phasing to prevent exceeding ISO bandwidth
......@@ -1746,6 +1750,34 @@ static void musb_irq_work(struct work_struct *data)
}
}
/* Recover from babble interrupt conditions */
static void musb_recover_work(struct work_struct *data)
{
struct musb *musb = container_of(data, struct musb, recover_work);
int status;
musb_platform_reset(musb);
usb_phy_vbus_off(musb->xceiv);
udelay(100);
usb_phy_vbus_on(musb->xceiv);
udelay(100);
/*
* When a babble condition occurs, the musb controller removes the
* session bit and the endpoint config is lost.
*/
if (musb->dyn_fifo)
status = ep_config_from_table(musb);
else
status = ep_config_from_hw(musb);
/* start the session again */
if (status == 0)
musb_start(musb);
}
/* --------------------------------------------------------------------------
* Init support
*/
......@@ -1913,6 +1945,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
/* Init IRQ workqueue before request_irq */
INIT_WORK(&musb->irq_work, musb_irq_work);
INIT_WORK(&musb->recover_work, musb_recover_work);
INIT_DELAYED_WORK(&musb->deassert_reset_work, musb_deassert_reset);
INIT_DELAYED_WORK(&musb->finish_resume_work, musb_host_finish_resume);
......@@ -2008,6 +2041,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
fail3:
cancel_work_sync(&musb->irq_work);
cancel_work_sync(&musb->recover_work);
cancel_delayed_work_sync(&musb->finish_resume_work);
cancel_delayed_work_sync(&musb->deassert_reset_work);
if (musb->dma_controller)
......@@ -2073,6 +2107,7 @@ static int musb_remove(struct platform_device *pdev)
dma_controller_destroy(musb->dma_controller);
cancel_work_sync(&musb->irq_work);
cancel_work_sync(&musb->recover_work);
cancel_delayed_work_sync(&musb->finish_resume_work);
cancel_delayed_work_sync(&musb->deassert_reset_work);
musb_free(musb);
......
......@@ -297,6 +297,7 @@ struct musb {
irqreturn_t (*isr)(int, void *);
struct work_struct irq_work;
struct work_struct recover_work;
struct delayed_work deassert_reset_work;
struct delayed_work finish_resume_work;
u16 hwvers;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment