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
#

  • Genius 9460 points

    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

    If my reply answers your question then please click on the green button "Verify Answer"

  • 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

     

  • Genius 9460 points

    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

    If my reply answers your question then please click on the green button "Verify Answer"

  • 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

  • Genius 9460 points

    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

     

    If my reply answers your question then please click on the green button "Verify Answer"

  • 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?

  • Genius 9460 points

    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

    If my reply answers your question then please click on the green button "Verify Answer"