musb: enable hostmode on n900 (semi-manual)
authorPaul Fertser <fercerpav@gmail.com>
Fri, 29 Oct 2010 20:33:21 +0000 (00:33 +0400)
committerPaul Fertser <fercerpav@gmail.com>
Fri, 29 Oct 2010 20:59:55 +0000 (00:59 +0400)
Patch with which i had a limited success (my device was rejected during
enumeration because i didn't have the whitelist disabled, but the VID/PID
was properly read).

Do ``cat /proc/driver/musb_hdrc'' to check for DEVCTL state.
Do ``echo host > /sys/devices/platform/musb_hdrc/mode'' to switch it to the
host mode.

Proper DEVCTL state in hostmode with the power on VBUS applied (either
internal, or external) is 0x5D.

Then manually force device enumeration with
``echo F > /proc/driver/musb_hdrc''

Charging with a wallcharger should still work.

drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_procfs.c
drivers/usb/musb/omap2430.c
drivers/usb/otg/twl4030-usb.c

index e172ca6..0a99c70 100644 (file)
@@ -230,6 +230,8 @@ static int musb_charger_detect(struct musb *musb)
         * change it unless you really know what you're doing
         */
 
+       DBG(4, "Some asshole called musb_charger_detect!");
+
        switch(musb->xceiv->state) {
                case OTG_STATE_B_IDLE:
                        /* we always reset transceiver */
index 8915b62..d7c078b 100644 (file)
@@ -651,6 +651,59 @@ static int musb_proc_write(struct file *file, const char __user *buffer,
                reg = musb_readb(mbase, MUSB_DEVCTL);
                reg |= MUSB_DEVCTL_SESSION;
                musb_writeb(mbase, MUSB_DEVCTL, reg);
+
+               /* Pretend there's a session request */
+               musb->ep0_stage = MUSB_EP0_START;
+               musb->xceiv->state = OTG_STATE_A_IDLE;
+               MUSB_HST_MODE(musb);
+               musb_set_vbus(musb, 1);
+
+               /* Connect request */
+               {
+               struct usb_hcd *hcd = musb_to_hcd(musb);
+
+               musb->is_active = 1;
+               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
+
+               musb->ep0_stage = MUSB_EP0_START;
+
+#ifdef CONFIG_USB_MUSB_OTG
+               /* flush endpoints when transitioning from Device Mode */
+               if (is_peripheral_active(musb)) {
+                       /* REVISIT HNP; just force disconnect */
+               }
+               musb_writew(mbase, MUSB_INTRTXE, musb->epmask);
+               musb_writew(mbase, MUSB_INTRRXE, musb->epmask & 0xfffe);
+               musb_writeb(mbase, MUSB_INTRUSBE, 0xf7);
+#endif
+               musb->port1_status &= ~(USB_PORT_STAT_LOW_SPEED
+                                       |USB_PORT_STAT_HIGH_SPEED
+                                       |USB_PORT_STAT_ENABLE
+                                       );
+               musb->port1_status |= USB_PORT_STAT_CONNECTION
+                                       |(USB_PORT_STAT_C_CONNECTION << 16);
+
+               /* high vs full speed is just a guess until after reset */
+               /* if (devctl & MUSB_DEVCTL_LSDEV)
+                       musb->port1_status |= USB_PORT_STAT_LOW_SPEED;*/
+
+               if (hcd->status_urb)
+                       usb_hcd_poll_rh_status(hcd);
+               else
+                       usb_hcd_resume_root_hub(hcd);
+
+               MUSB_HST_MODE(musb);
+
+               /* indicate new connection to OTG machine */
+               switch (musb->xceiv->state) {
+               default:
+                               musb->xceiv->state = OTG_STATE_A_HOST;
+                               hcd->self.is_b_host = 0;
+                       break;
+               }
+               DBG(1, "CONNECT (%s) devctl %02x\n",
+                               otg_state_string(musb), devctl);
+               }
                break;
 
        case 'H':
index 35aab80..c42fade 100644 (file)
@@ -219,9 +219,6 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
        struct usb_bus  *host;
        u8              devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 
-       devctl |= MUSB_DEVCTL_SESSION;
-       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-
        switch (musb_mode) {
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
        case MUSB_HOST:
@@ -229,10 +226,34 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
                host = hcd_to_bus(hcd);
 
                otg_set_host(musb->xceiv, host);
+
+               if (machine_is_nokia_rx51()) {
+                       u8 testmode;
+                       void __iomem *mbase=musb->mregs;
+
+                       musb_platform_resume(musb);
+
+                       devctl |= MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+                       testmode = musb_readb(musb->mregs, MUSB_TESTMODE);
+                       testmode |= MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_FS;
+                       musb_writeb(musb->mregs, MUSB_TESTMODE, testmode);
+               }
                break;
 #endif
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
        case MUSB_PERIPHERAL:
+               if (machine_is_nokia_rx51()) {
+                       musb_platform_resume(musb);
+                       musb_set_vbus(musb, 0);
+
+                       devctl &= ~MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+                       musb_writeb(musb->mregs, MUSB_TESTMODE, 0);
+               }
+
                otg_set_peripheral(musb->xceiv, &musb->g);
                break;
 #endif
index ecffb2a..60bbcf8 100644 (file)
@@ -368,7 +368,10 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
        /* REVISIT this assumes host and peripheral controllers
         * are registered, and that both are active...
         */
+       linkstat = USB_LINK_ID;
 
+       printk(KERN_INFO "%s: linkstat: %d; not messing the state\n", __func__, linkstat);
+#if 0
        spin_lock_irq(&twl->lock);
        twl->linkstat = linkstat;
        if (linkstat == USB_LINK_ID) {
@@ -379,6 +382,7 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
                twl->otg.state = OTG_STATE_B_IDLE;
        }
        spin_unlock_irq(&twl->lock);
+#endif
 
        return linkstat;
 }