Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+35 −0
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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;