USB: musb: support host/gadget role switching on Blackfin parts
Signed-off-by: Cliff Cai <cliff.cai@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: Felipe Balbi <felipe.balbi@nokia.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
b0f9da7e02
commit
ff927addd6
@@ -170,6 +170,13 @@ static irqreturn_t blackfin_interrupt(int irq, void *__hci)
|
|||||||
retval = musb_interrupt(musb);
|
retval = musb_interrupt(musb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Start sampling ID pin, when plug is removed from MUSB */
|
||||||
|
if (is_otg_enabled(musb) && (musb->xceiv->state == OTG_STATE_B_IDLE
|
||||||
|
|| musb->xceiv->state == OTG_STATE_A_WAIT_BCON)) {
|
||||||
|
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
||||||
|
musb->a_wait_bcon = TIMER_DELAY;
|
||||||
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&musb->lock, flags);
|
spin_unlock_irqrestore(&musb->lock, flags);
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
@@ -180,6 +187,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
|
|||||||
struct musb *musb = (void *)_musb;
|
struct musb *musb = (void *)_musb;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
u16 val;
|
u16 val;
|
||||||
|
static u8 toggle;
|
||||||
|
|
||||||
spin_lock_irqsave(&musb->lock, flags);
|
spin_lock_irqsave(&musb->lock, flags);
|
||||||
switch (musb->xceiv->state) {
|
switch (musb->xceiv->state) {
|
||||||
@@ -187,10 +195,44 @@ static void musb_conn_timer_handler(unsigned long _musb)
|
|||||||
case OTG_STATE_A_WAIT_BCON:
|
case OTG_STATE_A_WAIT_BCON:
|
||||||
/* Start a new session */
|
/* Start a new session */
|
||||||
val = musb_readw(musb->mregs, MUSB_DEVCTL);
|
val = musb_readw(musb->mregs, MUSB_DEVCTL);
|
||||||
|
val &= ~MUSB_DEVCTL_SESSION;
|
||||||
|
musb_writew(musb->mregs, MUSB_DEVCTL, val);
|
||||||
val |= MUSB_DEVCTL_SESSION;
|
val |= MUSB_DEVCTL_SESSION;
|
||||||
musb_writew(musb->mregs, MUSB_DEVCTL, val);
|
musb_writew(musb->mregs, MUSB_DEVCTL, val);
|
||||||
|
/* Check if musb is host or peripheral. */
|
||||||
val = musb_readw(musb->mregs, MUSB_DEVCTL);
|
val = musb_readw(musb->mregs, MUSB_DEVCTL);
|
||||||
|
|
||||||
|
if (!(val & MUSB_DEVCTL_BDEVICE)) {
|
||||||
|
gpio_set_value(musb->config->gpio_vrsel, 1);
|
||||||
|
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
|
||||||
|
} else {
|
||||||
|
gpio_set_value(musb->config->gpio_vrsel, 0);
|
||||||
|
/* Ignore VBUSERROR and SUSPEND IRQ */
|
||||||
|
val = musb_readb(musb->mregs, MUSB_INTRUSBE);
|
||||||
|
val &= ~MUSB_INTR_VBUSERROR;
|
||||||
|
musb_writeb(musb->mregs, MUSB_INTRUSBE, val);
|
||||||
|
|
||||||
|
val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
|
||||||
|
musb_writeb(musb->mregs, MUSB_INTRUSB, val);
|
||||||
|
if (is_otg_enabled(musb))
|
||||||
|
musb->xceiv->state = OTG_STATE_B_IDLE;
|
||||||
|
else
|
||||||
|
musb_writeb(musb->mregs, MUSB_POWER, MUSB_POWER_HSENAB);
|
||||||
|
}
|
||||||
|
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
||||||
|
break;
|
||||||
|
case OTG_STATE_B_IDLE:
|
||||||
|
|
||||||
|
if (!is_peripheral_enabled(musb))
|
||||||
|
break;
|
||||||
|
/* Start a new session. It seems that MUSB needs taking
|
||||||
|
* some time to recognize the type of the plug inserted?
|
||||||
|
*/
|
||||||
|
val = musb_readw(musb->mregs, MUSB_DEVCTL);
|
||||||
|
val |= MUSB_DEVCTL_SESSION;
|
||||||
|
musb_writew(musb->mregs, MUSB_DEVCTL, val);
|
||||||
|
val = musb_readw(musb->mregs, MUSB_DEVCTL);
|
||||||
|
|
||||||
if (!(val & MUSB_DEVCTL_BDEVICE)) {
|
if (!(val & MUSB_DEVCTL_BDEVICE)) {
|
||||||
gpio_set_value(musb->config->gpio_vrsel, 1);
|
gpio_set_value(musb->config->gpio_vrsel, 1);
|
||||||
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
|
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
|
||||||
@@ -205,12 +247,27 @@ static void musb_conn_timer_handler(unsigned long _musb)
|
|||||||
val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
|
val = MUSB_INTR_SUSPEND | MUSB_INTR_VBUSERROR;
|
||||||
musb_writeb(musb->mregs, MUSB_INTRUSB, val);
|
musb_writeb(musb->mregs, MUSB_INTRUSB, val);
|
||||||
|
|
||||||
val = MUSB_POWER_HSENAB;
|
/* Toggle the Soft Conn bit, so that we can response to
|
||||||
|
* the inserting of either A-plug or B-plug.
|
||||||
|
*/
|
||||||
|
if (toggle) {
|
||||||
|
val = musb_readb(musb->mregs, MUSB_POWER);
|
||||||
|
val &= ~MUSB_POWER_SOFTCONN;
|
||||||
musb_writeb(musb->mregs, MUSB_POWER, val);
|
musb_writeb(musb->mregs, MUSB_POWER, val);
|
||||||
|
toggle = 0;
|
||||||
|
} else {
|
||||||
|
val = musb_readb(musb->mregs, MUSB_POWER);
|
||||||
|
val |= MUSB_POWER_SOFTCONN;
|
||||||
|
musb_writeb(musb->mregs, MUSB_POWER, val);
|
||||||
|
toggle = 1;
|
||||||
|
}
|
||||||
|
/* The delay time is set to 1/4 second by default,
|
||||||
|
* shortening it, if accelerating A-plug detection
|
||||||
|
* is needed in OTG mode.
|
||||||
|
*/
|
||||||
|
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY / 4);
|
||||||
}
|
}
|
||||||
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DBG(1, "%s state not handled\n", otg_state_string(musb));
|
DBG(1, "%s state not handled\n", otg_state_string(musb));
|
||||||
break;
|
break;
|
||||||
@@ -222,7 +279,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
|
|||||||
|
|
||||||
void musb_platform_enable(struct musb *musb)
|
void musb_platform_enable(struct musb *musb)
|
||||||
{
|
{
|
||||||
if (is_host_enabled(musb)) {
|
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
|
||||||
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
||||||
musb->a_wait_bcon = TIMER_DELAY;
|
musb->a_wait_bcon = TIMER_DELAY;
|
||||||
}
|
}
|
||||||
@@ -256,7 +313,7 @@ static int bfin_set_power(struct otg_transceiver *x, unsigned mA)
|
|||||||
|
|
||||||
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
|
||||||
{
|
{
|
||||||
if (is_host_enabled(musb))
|
if (!is_otg_enabled(musb) && is_host_enabled(musb))
|
||||||
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
mod_timer(&musb_conn_timer, jiffies + TIMER_DELAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user