View Single Post
Posts: 243 | Thanked: 172 times | Joined on Sep 2007 @ silicon valley
#966
Originally Posted by joerg_rw View Post
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 *).
An excerpt from my kernel patches, which I posted:

Code:
		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;
		}