So on issuing 'echo host >mode': *) We need to FORCE_HOST, make sure the pulldowns stay enabled, do other mandatory configs wrt for example powersaving mode - refer to SPRUF98, and start VBUS supply boost if that is what we want (quite usually it is. Except for externally powered host mode, i.e. host mode while charging, using a Y-cable) Then we can poll for HOSTDISCON flag changing state, which signals us one of the D lines was pulled up. I have to speculate a little what's correct sequence from then, probably we check whether D+ or D- was pulled up (we can read out from PHY's debug register iirc), and set LowSpeed / FullSpeed accordingly Then we set SESSION bit Now we are ready to pass control to the logical driver talking to the connected peripheral, i.e. start ENUM, aka force software statemachine into hostmode Whenever the logical aka protocol driver detects a disconnect of peripheral, either by timeout, or by HOSTDISCON changing state, it needs to reset SESSION, and we go back to *).
if (testmode & MUSB_TEST_FORCE_HOST) { u8 r,reg; void __iomem *mbase = musb->mregs; musb_force_term(musb->mregs,MUSB_TERM_HOST_HIGHSPEED); r = musb_ulpi_readb(mbase, ISP1704_DEBUG); DBG(1,"Linestate %x\n",r); switch(r) { case 2: musb->port1_status |= USB_PORT_STAT_LOW_SPEED; reg = musb_readb(mbase, MUSB_TESTMODE); reg &= ~MUSB_TEST_FORCE_FS; reg &= ~MUSB_TEST_FORCE_HS; musb_writeb(mbase, MUSB_TESTMODE, reg); reg = musb_readb(mbase, MUSB_POWER); reg &= ~MUSB_POWER_HSENAB; musb_writeb(mbase, MUSB_POWER, reg); musb_force_term(musb->mregs,MUSB_TERM_HOST_LOWSPEED); break; case 1: /*High or full speed*/ reg = musb_readb(mbase, MUSB_TESTMODE); if(reg & MUSB_TEST_FORCE_HS) { /*High speed*/ reg &= ~MUSB_TEST_FORCE_FS; musb_writeb(mbase, MUSB_TESTMODE, reg); reg = musb_readb(mbase, MUSB_POWER); reg |= MUSB_POWER_HSENAB; musb_writeb(mbase, MUSB_POWER, reg); } else { /*Full speed*/ reg |= MUSB_TEST_FORCE_FS; musb_writeb(mbase, MUSB_TESTMODE, reg); reg = musb_readb(mbase, MUSB_POWER); reg &= ~MUSB_POWER_HSENAB; musb_writeb(mbase, MUSB_POWER, reg); } musb_force_term(mbase,MUSB_TERM_HOST_FULLSPEED); break; case 0: case 3: /*invalid*/ WARNING("Invalid line state of %d\n",r); break; } } else { /* high vs full speed is just a guess until after reset */ if (devctl & MUSB_DEVCTL_LSDEV) musb->port1_status |= USB_PORT_STAT_LOW_SPEED; }