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

Commit 996a9d26 authored by Fabio Baltieri's avatar Fabio Baltieri Committed by Felipe Balbi
Browse files

usb: musb: ux500: implement musb_set_vbus



Add ux500_musb_set_vbus() implementation for ux500.

This is based on the version originally developed inside ST-Ericsson.

Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarFabio Baltieri <fabio.baltieri@linaro.org>

[ balbi@ti.com: fix a build error due to
	missing otg_state_string() ]

Signed-off-by: default avatarFelipe Balbi <balbi@ti.com>
parent 399e0f4f
Loading
Loading
Loading
Loading
+64 −0
Original line number Diff line number Diff line
@@ -36,6 +36,68 @@ struct ux500_glue {
};
#define glue_to_musb(g)	platform_get_drvdata(g->musb)

static void ux500_musb_set_vbus(struct musb *musb, int is_on)
{
	u8            devctl;
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	/* HDRC controls CPEN, but beware current surges during device
	 * connect.  They can trigger transient overcurrent conditions
	 * that must be ignored.
	 */

	devctl = musb_readb(musb->mregs, MUSB_DEVCTL);

	if (is_on) {
		if (musb->xceiv->state == OTG_STATE_A_IDLE) {
			/* start the session */
			devctl |= MUSB_DEVCTL_SESSION;
			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
			/*
			 * Wait for the musb to set as A device to enable the
			 * VBUS
			 */
			while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) {

				if (time_after(jiffies, timeout)) {
					dev_err(musb->controller,
					"configured as A device timeout");
					break;
				}
			}

		} else {
			musb->is_active = 1;
			musb->xceiv->otg->default_a = 1;
			musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
			devctl |= MUSB_DEVCTL_SESSION;
			MUSB_HST_MODE(musb);
		}
	} else {
		musb->is_active = 0;

		/* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and jumping
		 * right to B_IDLE...
		 */
		musb->xceiv->otg->default_a = 0;
		devctl &= ~MUSB_DEVCTL_SESSION;
		MUSB_DEV_MODE(musb);
	}
	musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);

	/*
	 * Devctl values will be updated after vbus goes below
	 * session_valid. The time taken depends on the capacitance
	 * on VBUS line. The max discharge time can be upto 1 sec
	 * as per the spec. Typically on our platform, it is 200ms
	 */
	if (!is_on)
		mdelay(200);

	dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
		usb_otg_state_string(musb->xceiv->state),
		musb_readb(musb->mregs, MUSB_DEVCTL));
}

static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
{
	unsigned long   flags;
@@ -79,6 +141,8 @@ static int ux500_musb_exit(struct musb *musb)
static const struct musb_platform_ops ux500_ops = {
	.init		= ux500_musb_init,
	.exit		= ux500_musb_exit,

	.set_vbus	= ux500_musb_set_vbus,
};

static int ux500_probe(struct platform_device *pdev)