This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

AM3358: USB mode switching

Part Number: AM3358

Long story short, we have a product with a PMIC layout issue that prevents us from simply using the dual role mode to mimic USB OTG on AM3358.

I'm am in need of a way to dynamically change roles based on system inputs, IE usb interrupt from PMIC, USB ID pin, etc.  I'm not overly concerned there, but getting the hardware to switch is more my issue.

I am still researching, possibly using device tree overlays.

I may be able to detect in u-boot and react, but I would prefer a dynamic operation once into the kernel.  We have usespace applications running that can react accordingly, but I'm open to suggestions on how to react.

Thanks

Matt

  • Hi Matt,

    The AM3358 USB controller is capable to switch mode by software without the input of USB ID pin, using the USBxMODE register, but the kernel driver doesn't implement this function, the main reason is about user error - it is possible the user forgot to switch MUSB from host to device mode then connected it to another USB host, which caused VBUS contention and violating the USB Specs. So manual mode switching is not supported.

  • Hi Bin

    I'm not really looking to NOT use the ID pin, I would love to.  However if I simply use dual role mode, we get power interruption and running resets due to the PMIC thinking we have switched to battery during the USB probing.  It's a board issue we have too many products already in the field with so I can't simply rely on dual role.

    So in theory I could modify the MUSB driver to gain the functionality to switch?

    I've been looking over the driver already and have found the parts were the host vs gadget setup is done when in dual role.

    I was just hoping there was a way to poke the driver or the hardware to make it switch vs probing.

    Matt

  • Matt,

    Can you please explain in what exact the scenario you want the mode switch to happen? Do you need to switch between host and device mode after the MUSB drivers are loaded? or the mode is set by the time to load the MUSB drivers? If latter, how the mode is determined?

  • Bin

    The current configuration has the USB set as a peripheral device via devicetree.  We do suffer from not detecting a hot plug of the USB cable when on "AC" power via the PMIC and we boot up with no USB attached. I can poke the driver to fix that however.

    The situation we would like to move to if possible....

    check the status of AC and USB power present on the PMIC (at boot most likely), then chose to enable host or peripheral based on those.

    If there is a means to look at the ID pin state I will gladly do so. There is a TDP4S214 controlled by the DRVVBUS for our USB port, as we were planning to use dual role but got into trouble with the PMIC.

    I have no issues loading or unload drivers to handle the switch, we currently load a different gadget driver based on the system status. I have started building the MUSB as a module to experiment.

    We will force the user to reboot the device to change roles if that is the easiest, as the exposure overall will be low.  Maybe 5% of total annual product will use the host mode, most users simply use the device as a peripheral.

    But ideally I would like to be able to detect a change on VBUS/ID and unload drivers switch roles and reload drivers.  We can do that from user space or kernel, but I'm not expecting it to be automatic at this point.

    I'm also attempting device tree overlays to make the switch, but have so far been unsuccessful.

    I'm open to checking the status within u-boot as well and picking a different device tree if it comes to that.

    It's a requirement for us, but such a small use case that I'm willing to make the customer jump through a couple hoops to get there :)

  • Matt,

    Here is how the driver works currently.

    If dr_mode is set to 'otg' in device tree, the driver controls the usb mode based on the ID pin status at runtime;

    If dr_mode is set to 'peripheral' in device tree, the driver initialize the usb controller to only work in device mode;

    if dr_mode is set to 'host' in device tree, the driver initialize the usb controller to only work in host mode.

    These are mainly done in musb_init_controller() in musb_core.c. Please check the code section of "switch (musb->port_mode)".

    musb->port_mode is from plat->mode in musb_init_controller().

    plat->mode is initialized in dsps_create_musb_pdev() in musb_dsps.c, by the line

            pdata.mode = musb_get_mode(dev);

    which reads the mode setting from device tree.

    So if you can determine the usb mode based on the PMIC status in dsps_create_musb_pdev(), then override pdata.mode variable as in the line above, then you can bypass the device tree setting and initialize the usb controller to either host or device mode based on PMIC.

    Hope this is what you need.

  • Bin

    This will work wonderfully.  I'm patching the driver to accept a module parameter to choose port mode explicitly.  I will update on my success with it.

    Final piece, is there any way to expose or read the current state of the ID PIN?

    Thanks for the help

    Matt

  • Matt,

    I am glad we found a solution!

    Matthew Harlan said:
    Final piece, is there any way to expose or read the current state of the ID PIN?

    No, there is no interrupt event or register bit to report the state of the USB ID pin on AM335x. The controller checks the pin state internally.

  • Hi Bin, 

    Do I need to address the configuration of the usb_phy at all?  I'm finding that it's driver is attempting to read the dr_mode for the usb controller from the devicetree when it loads.  So if I manually load the musb driver without my parameters, it will properly load but with the dual role which is the default in the am33xx.dtsi

    If i try to pass in my mode override I do not get proper operation.  The phy is still being loaded by default at boot, where as I am manually loading my musb_dsps module.  I think we're on the right path, but not quite there :)  

    Perhaps I need to override in the phy module as well?

    Any thoughts?

    Matt

  • Matt,

    Yes the musb phy driver does read dr_mode from device tree, but as long as dr_mode is NOT set to 'host' in device tree, the phy driver shouldn't affect your driver hack with module parameter, even it is loaded automatically as kernel booting.

    Can you please provide details how your mode override doesn't get proper operation?

  • Hi Bin

    I was able to get things to function finally.

    Leaving the dr_mode as peripheral in our device tree seemed to make things happiest.  I also had to ensure I manually remove any other modules that we loaded for either a gadget or a hosted device if we needed to change.

  • Matt,

    Matthew Harlan said:
    I was able to get things to function finally.

    Great!

    Matthew Harlan said:
      I also had to ensure I manually remove any other modules that we loaded for either a gadget or a hosted device if we needed to change.

    What are those modules?