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: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Fabio Baltieri <fabio.baltieri@linaro.org> [ balbi@ti.com: fix a build error due to missing otg_state_string() ] Signed-off-by: Felipe Balbi <balbi@ti.com>
This commit is contained in:
Родитель
399e0f4f00
Коммит
996a9d26d3
|
@ -36,6 +36,68 @@ struct ux500_glue {
|
||||||
};
|
};
|
||||||
#define glue_to_musb(g) platform_get_drvdata(g->musb)
|
#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)
|
static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -79,6 +141,8 @@ static int ux500_musb_exit(struct musb *musb)
|
||||||
static const struct musb_platform_ops ux500_ops = {
|
static const struct musb_platform_ops ux500_ops = {
|
||||||
.init = ux500_musb_init,
|
.init = ux500_musb_init,
|
||||||
.exit = ux500_musb_exit,
|
.exit = ux500_musb_exit,
|
||||||
|
|
||||||
|
.set_vbus = ux500_musb_set_vbus,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int ux500_probe(struct platform_device *pdev)
|
static int ux500_probe(struct platform_device *pdev)
|
||||||
|
|
Загрузка…
Ссылка в новой задаче