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, 5 Nov 2010 22:10:04 +0000 (01:10 +0300)
With this i'm able to use my LS, FS and HS devices. For this bme should
obviously be stopped.

Do ``cat /proc/driver/musb_hdrc'' to check for DEVCTL state.

Do ``echo hostf > /sys/devices/platform/musb_hdrc/mode'' to switch it to
the host mode in FULL speed; do ``echo hostl >
/sys/devices/platform/musb_hdrc/mode'' to switch it to the host mode in
LOW speed; do ``echo hosth > /sys/devices/platform/musb_hdrc/mode'' for
HIGH speed.

Then apply VBUS and force enumeration.

Proper DEVCTL state in hostmode with the power on VBUS applied (either
internal, or external) is 0x5D for full/high speed, 0x3D for low speed.

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

``echo peripheral > /sys/devices/platform/musb_hdrc/mode'' to switch it
back (do not forget to start bme afterwards).

You might need to wait for some time before a new attempt to force the
hostmode, calling ``lsusb'' usually helps to bring it back to the
default state.

drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_procfs.c
drivers/usb/musb/omap2430.c

index e172ca6..896b1dc 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 */
@@ -570,10 +572,9 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
        irqreturn_t handled = IRQ_NONE;
        void __iomem *mbase = musb->mregs;
        u8 r;
-       u8 testmode = musb_readb(musb->mregs, MUSB_TESTMODE);
 
-       DBG(3, "<== State=%s Testmode=%02x Power=%02x, DevCtl=%02x, int_usb=0x%x\n",
-               otg_state_string(musb), testmode, power, devctl, int_usb);
+       DBG(3, "<== State=%s Power=%02x, DevCtl=%02x, int_usb=0x%x\n",
+               otg_state_string(musb), power, devctl, int_usb);
 
        /* in host mode, the peripheral may issue remote wakeup.
         * in peripheral mode, the host may resume the link.
@@ -2024,12 +2025,16 @@ musb_mode_store(struct device *dev, struct device_attribute *attr,
        int             status;
 
        mutex_lock(&musb->mutex);
-       if (sysfs_streq(buf, "host"))
-               status = musb_platform_set_mode(musb, MUSB_HOST);
+       if (sysfs_streq(buf, "hostl"))
+               status = musb_platform_set_mode(musb, MUSB_HOST, 0);
+       else if (sysfs_streq(buf, "hostf"))
+               status = musb_platform_set_mode(musb, MUSB_HOST, 1);
+       else if (sysfs_streq(buf, "hosth"))
+               status = musb_platform_set_mode(musb, MUSB_HOST, 2);
        else if (sysfs_streq(buf, "peripheral"))
-               status = musb_platform_set_mode(musb, MUSB_PERIPHERAL);
+               status = musb_platform_set_mode(musb, MUSB_PERIPHERAL, 0);
        else if (sysfs_streq(buf, "otg"))
-               status = musb_platform_set_mode(musb, MUSB_OTG);
+               status = musb_platform_set_mode(musb, MUSB_OTG, 0);
        else
                status = -EINVAL;
        mutex_unlock(&musb->mutex);
index dd9de46..0581261 100644 (file)
@@ -591,7 +591,7 @@ extern void musb_platform_disable(struct musb *musb);
 
 extern void musb_hnp_stop(struct musb *musb);
 
-extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode);
+extern int musb_platform_set_mode(struct musb *musb, u8 musb_mode, u8 hostspeed);
 
 #if defined(CONFIG_USB_TUSB6010) || defined(CONFIG_BLACKFIN) || \
        defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX)
index 8915b62..76161d3 100644 (file)
@@ -651,6 +651,60 @@ 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);
+               u8 testmode;
+
+               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);
+
+               testmode = musb_readb(mbase, MUSB_TESTMODE);
+               if (!(testmode & (MUSB_TEST_FORCE_FS | MUSB_TEST_FORCE_HS)))
+                       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..d089e8b 100644 (file)
@@ -213,15 +213,12 @@ static int omap_set_power(struct otg_transceiver *x, unsigned mA)
 
 static int musb_platform_resume(struct musb *musb);
 
-int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
+int musb_platform_set_mode(struct musb *musb, u8 musb_mode, u8 hostspeed)
 {
        struct usb_hcd  *hcd;
        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,36 @@ 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;
+
+                       musb_platform_resume(musb);
+
+                       devctl |= MUSB_DEVCTL_SESSION;
+                       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+
+                       testmode = MUSB_TEST_FORCE_HOST;
+                       if (hostspeed == 1)
+                               testmode |= MUSB_TEST_FORCE_FS;
+                       else if (hostspeed == 2)
+                               testmode |= MUSB_TEST_FORCE_HS;
+                       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