DM365 USB OTG mode switch from host to gadget

I am developing a system based in the 2.6.18 kernel and LSP 2.10.  I am having a problem with USB OTG using the USB_ID pin switching.  The problem seems to occur when I connct a USB host mode cable (USB_ID = 0) then disconnect it.  If I then try and connect as a USB gadget to a PC, it does not work.  I enabled debug at level 7, and noticed that the otg_workaround timer routine never resumes.  Here is some messages I see in the log when I remove the cable.

What normally would force the USB OTG workaround to start running again?

# [ 1117.330000] usb 1-1: USB disconnect, address 2
dmesg
<7>[ 1117.330000] davinci_interrupt 315: IRQ 00280000
<7>[ 1117.330000] musb_interrupt 1528: ** IRQ peripheral usb0028 tx0000 rx0000
<7>[ 1117.330000] musb_stage2_irq 718: START_OF_FRAME
<7>[ 1117.330000] musb_stage2_irq 733: DISCONNECT (a_host) as Host, devctl 19
<7>[ 1117.330000] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002
<7>[ 1117.330000] musb_hub_control 344: port status 00010100
<7>[ 1117.330000] musb_hub_control 278: clear feature 16
<7>[ 1117.330000] hub 1-0:1.0: port 1, status 0100, change 0001, 12 Mb/s
<6>[ 1117.330000] usb 1-1: USB disconnect, address 2
<7>[ 1117.330000] usb 1-1: usb_disable_device nuking all URBs
<7>[ 1117.330000] usb 1-1: unregistering interface 1-1:1.0
<7>[ 1117.330000]  usbdev1.2_ep81: ep_device_release called for usbdev1.2_ep81
<7>[ 1117.330000]  usbdev1.2_ep02: ep_device_release called for usbdev1.2_ep02
<7>[ 1117.340000] usb 1-1:1.0: uevent
<7>[ 1117.340000] usb 1-1: unregistering device
<7>[ 1117.340000]  usbdev1.2_ep00: ep_device_release called for usbdev1.2_ep00
<7>[ 1117.340000] usb 1-1: uevent
<7>[ 1117.340000] musb_hub_control 344: port status 00000100
<7>[ 1117.380000] musb_hub_control 344: port status 00000100
<7>[ 1117.420000] musb_hub_control 344: port status 00000100
<7>[ 1117.460000] musb_hub_control 344: port status 00000100
<7>[ 1117.500000] musb_hub_control 344: port status 00000100
<7>[ 1117.500000] hub 1-0:1.0: debounce: port 1: total 100ms stable 100ms status 0x100
#

  • Can you print the value of  "cat /proc/driver/musb_hdrc" after you disconnect the device in host mode? It seems the vbus is not switched off even after disconnect.

     

    Regards,

    ajay

  • In reply to Ajay:

    Here it is.  That is what I was assuming would push us back to IDLE.  Doesn't this occur in the controller hw?

    # [   54.010000] usb 1-1: USB disconnect, address 2
    # cat /proc/driver/musb_hdrc
    Status: MHDRC, Mode=Host (Power=e0, DevCtl=19)
    OTG state: a_wait_bcon; inactive
    Options: cppi-dma, otg (peripheral+host), debug=7 [eps=5]
    Peripheral address: 01
    Root port status: 00000100
    DaVinci: ctrl=00 stat=1 phy=21e0
            rndis=00000 auto=0000 intsrc=00000000 intmsk=01ff1c1f
    CPPI: txcr=1 txsrc=0 txena=f; rxcr=1 rxsrc=0 rxena=f
    Gadget driver: ether

     

  • In reply to Scott Cloutier:

    Scott,

    Devctl=0x91 shows that Vbus is still ON (D[3:4] ==0x11) . Please try switching off the session by writing D0=1 in DEVCTL register using below changes in musb_procfs.c After you have these changes you can switch off the session by "echo f > /proc/driver/musb_hdrc" command.

     

    --- a/drivers/usb/musb/musb_procfs.c
    +++ b/drivers/usb/musb/musb_procfs.c
    @@ -677,6 +677,12 @@ static int musb_proc_write(struct file *file, const char __user *buffer,
                    }
                    break;

    +       case 'f':
    +               reg = musb_readb(mbase, MUSB_DEVCTL);
    +               reg &= ~MUSB_DEVCTL_SESSION;
    +               musb_writeb(mbase, MUSB_DEVCTL, reg);
    +               break;
    +
            case 'F':
                    reg = musb_readb(mbase, MUSB_DEVCTL);
                    reg |= MUSB_DEVCTL_SESSION;

    Regards,

    Ajay

  • In reply to Ajay:

    I was able to force the VBUS to off.  See below...  It started the otg_timer again, and all was well. But now we want this to be automated, so where would I put this code in reality?  I do have port-pin access to USB_ID, and can read it.

    #
    # [  605.030000] usb 1-1: USB disconnect, address 2

    # dmesg
    <7>[  605.030000] davinci_interrupt 315: IRQ 00280000
    <7>[  605.030000] musb_interrupt 1528: ** IRQ peripheral usb0028 tx0000 rx0000
    <7>[  605.030000] musb_stage2_irq 718: START_OF_FRAME
    <7>[  605.030000] musb_stage2_irq 733: DISCONNECT (a_host) as Host, devctl 19
    <7>[  605.030000] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002
    <7>[  605.030000] musb_hub_control 344: port status 00010100
    <7>[  605.030000] musb_hub_control 278: clear feature 16
    <7>[  605.030000] hub 1-0:1.0: port 1, status 0100, change 0001, 12 Mb/s
    <6>[  605.030000] usb 1-1: USB disconnect, address 2
    <7>[  605.030000] usb 1-1: usb_disable_device nuking all URBs
    <7>[  605.030000] usb 1-1: unregistering interface 1-1:1.0
    <7>[  605.030000]  usbdev1.2_ep81: ep_device_release called for usbdev1.2_ep81
    <7>[  605.030000]  usbdev1.2_ep02: ep_device_release called for usbdev1.2_ep02
    <7>[  605.040000] usb 1-1:1.0: uevent
    <7>[  605.040000] usb 1-1: unregistering device
    <7>[  605.040000]  usbdev1.2_ep00: ep_device_release called for usbdev1.2_ep00
    <7>[  605.040000] usb 1-1: uevent
    <7>[  605.040000] musb_hub_control 344: port status 00000100
    <7>[  605.080000] musb_hub_control 344: port status 00000100
    <7>[  605.120000] musb_hub_control 344: port status 00000100
    <7>[  605.160000] musb_hub_control 344: port status 00000100
    <7>[  605.200000] musb_hub_control 344: port status 00000100
    <7>[  605.200000] hub 1-0:1.0: debounce: port 1: total 100ms stable 100ms status 0x100
    #
    # echo f > /proc/driver/musb_hdrc
    #
    # dmesg
    <7>[  605.030000] davinci_interrupt 315: IRQ 00280000
    <7>[  605.030000] musb_interrupt 1528: ** IRQ peripheral usb0028 tx0000 rx0000
    <7>[  605.030000] musb_stage2_irq 718: START_OF_FRAME
    <7>[  605.030000] musb_stage2_irq 733: DISCONNECT (a_host) as Host, devctl 19
    <7>[  605.030000] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002
    <7>[  605.030000] musb_hub_control 344: port status 00010100
    <7>[  605.030000] musb_hub_control 278: clear feature 16
    <7>[  605.030000] hub 1-0:1.0: port 1, status 0100, change 0001, 12 Mb/s
    <6>[  605.030000] usb 1-1: USB disconnect, address 2
    <7>[  605.030000] usb 1-1: usb_disable_device nuking all URBs
    <7>[  605.030000] usb 1-1: unregistering interface 1-1:1.0
    <7>[  605.030000]  usbdev1.2_ep81: ep_device_release called for usbdev1.2_ep81
    <7>[  605.030000]  usbdev1.2_ep02: ep_device_release called for usbdev1.2_ep02
    <7>[  605.040000] usb 1-1:1.0: uevent
    <7>[  605.040000] usb 1-1: unregistering device
    <7>[  605.040000]  usbdev1.2_ep00: ep_device_release called for usbdev1.2_ep00
    <7>[  605.040000] usb 1-1: uevent
    <7>[  605.040000] musb_hub_control 344: port status 00000100
    <7>[  605.080000] musb_hub_control 344: port status 00000100
    <7>[  605.120000] musb_hub_control 344: port status 00000100
    <7>[  605.160000] musb_hub_control 344: port status 00000100
    <7>[  605.200000] musb_hub_control 344: port status 00000100
    <7>[  605.200000] hub 1-0:1.0: debounce: port 1: total 100ms stable 100ms status 0x100
    <7>[  658.160000] davinci_interrupt 315: IRQ 01000000
    <7>[  658.160000] davinci_interrupt 376: VBUS off (b_idle), devctl 98
    <7>[  660.160000] otg_timer 232: poll devctl 88 (b_idle)
    <7>[  662.160000] otg_timer 232: poll devctl 88 (b_idle)
    <7>[  664.160000] otg_timer 232: poll devctl 88 (b_idle)
    <7>[  666.160000] otg_timer 232: poll devctl 88 (b_idle)
    # [  686.050000] usb0: high speed config #2: 8 mA, Ethernet Gadget, using RNDIS

  • In reply to Scott Cloutier:

    you can refer drivers/usb/musb/omap2430.c , musb_do_idle() timer function where SESSION is getting switched off in case of OTG_STATE_A_WAIT_BCON.

    I think you should add this part in drivers/usb/musb/davinci.c, otg_timer() function. You can something like below,

    --- a/drivers/usb/musb/davinci.c
    +++ b/drivers/usb/musb/davinci.c
    @@ -217,6 +217,19 @@ static void otg_timer(unsigned long _musb)

            spin_lock_irqsave(&musb->lock, flags);
            switch (musb->xceiv->state) {
    +       case OTG_STATE_A_WAIT_BCON:
    +               devctl &= ~MUSB_DEVCTL_SESSION;
    +               musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
    +
    +               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
    +               if (devctl & MUSB_DEVCTL_BDEVICE) {
    +                       musb->xceiv->state = OTG_STATE_B_IDLE;
    +                       MUSB_DEV_MODE(musb);
    +               } else {
    +                       musb->xceiv->state = OTG_STATE_A_IDLE;
    +                       MUSB_HST_MODE(musb);
    +               }
    +               break;
            case OTG_STATE_A_WAIT_VFALL:
                    /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
                     * seems to mis-handle session "start" otherwise (or in our

    Regards,

    Ajay

     

  • In reply to Ajay:

    My otg_timer function is not always running.  So where/how do I get that going?  I looked at implementing musb_platform_try_idle() function as a means to check to see if the timer needs to be re-enabled, but am not sure it is getting called.  Is that the right approach here?

  • In reply to Scott Cloutier:

    Scott,

    Could you try with the changes I suggested to add in idle function? The timer will be reenabled at disconnect interrupt and then the Vbus will be switched off if the suggested code is added.

    Regards,
    Ajay