i.MX6 USB OTG mode switching without ID pin

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

i.MX6 USB OTG mode switching without ID pin

16,081 Views
KroMignon
Contributor I

How can I change the OTG mode from HOST to Gadget without ID pin ?

On my board, the USB OTG port is connected to a standard A plug, so I don't have an ID pin.

How can I force my OTG port to switch from Host to Gadget and vice et versa by software ?

How can I selection, in Gadget mode, which Gadget driver is used?

Best regards

Fabrice

Labels (3)
Tags (4)
13 Replies

6,165 Views
jiujinhong
Contributor IV

Hi,

You can use below patch to support otg switch in SW only, the hardware use USB A for OTG.

From 87f295ccaf081b4ef06218fc8028d3c3d075ede7 Mon Sep 17 00:00:00 2001
From: hongjiujin <hongjiujin@xxx.com>
Date: Tue, 2 Jan 2018 10:39:04 +0800
Subject: [PATCH] imx6: chipidea

The hardware didn't use OTG_ID pin in design and use USB A for OTG.
Chipidea will initialize otg to HOST once boot completed, which read OTGSC_IDIE.
So we implement otg role switch in SW only(/sys/kernel/debug/ci_hdrc.0/otgswitch).
---
 debug.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 110 insertions(+)

diff --git a/debug.c b/debug.c
index a4f7db2..b215674 100644
--- a/debug.c
+++ b/debug.c
@@ -16,6 +16,7 @@
 #include "udc.h"
 #include "bits.h"
 #include "otg.h"
+#include "host.h"
 
 /**
  * ci_device_show: prints information about device capabilities and status
@@ -343,6 +344,110 @@ static const struct file_operations ci_role_fops = {
     .release    = single_release,
 };
 
+#define CI_VBUS_STABLE_TIMEOUT_MS 100
+
+void handle_otg_switch(struct ci_hdrc *ci, enum ci_role role)
+{
+    int ret = 0;
+
+    if (role != ci->role) {
+        dev_dbg(ci->dev, "switching from %s to %s\n",
+            ci_role(ci)->name, ci->roles[role]->name);
+
+        while (ci_hdrc_host_has_device(ci)) {
+            enable_irq(ci->irq);
+            usleep_range(10000, 15000);
+            disable_irq_nosync(ci->irq);
+        }
+
+        ci_role_stop(ci);
+
+        if (role == CI_ROLE_GADGET) {
+            /* wait vbus lower than OTGSC_BSV */
+            ret = hw_wait_reg(ci, OP_OTGSC, OTGSC_BSV, 0,
+                    CI_VBUS_STABLE_TIMEOUT_MS);
+        }
+        else if (ci->vbus_active)
+            /*
+             * If the role switch happens(e.g. during
+             * system sleep), and we lose vbus drop
+             * event, disconnect gadget for it before
+             * start host.
+             */
+               usb_gadget_vbus_disconnect(&ci->gadget);
+
+        ci_role_start(ci, role);
+        /*
+         * If the role switch happens(e.g. during system
+         * sleep) and vbus keeps on afterwards, we connect
+         * gadget as vbus connect event lost.
+         */
+        if (ret == -ETIMEDOUT)
+            usb_gadget_vbus_connect(&ci->gadget);
+    }
+}
+
+static int ci_otgswitch_show(struct seq_file *s, void *data)
+{
+    struct ci_hdrc *ci = s->private;
+
+    seq_printf(s, "%s\n", ci_role(ci)->name);
+
+    return 0;
+}
+
+static ssize_t ci_otgswitch_write(struct file *file, const char __user *ubuf,
+                 size_t count, loff_t *ppos)
+{
+    struct seq_file *s = file->private_data;
+    struct ci_hdrc *ci = s->private;
+    enum ci_role role;
+    char buf[8];
+    int ret;
+
+    if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+    return -EFAULT;
+
+    for (role = CI_ROLE_HOST; role < CI_ROLE_END; role++)
+     if (ci->roles[role] &&
+        !strncmp(buf, ci->roles[role]->name,
+        strlen(ci->roles[role]->name)))
+        break;
+
+     if (role == CI_ROLE_END || role == ci->role)
+        return -EINVAL;
+
+    pm_runtime_get_sync(ci->dev);
+    disable_irq(ci->irq);
+
+    if (role == CI_ROLE_HOST) {
+        ci->fsm.id = 0;
+
+    } else if (role == CI_ROLE_GADGET) {
+        ci->fsm.id = 1;
+    }
+
+    handle_otg_switch(ci, role);
+    enable_irq(ci->irq);
+    pm_runtime_put_sync(ci->dev);
+
+    return ret ? ret : count;
+}
+
+
+static int ci_otgswitch_open(struct inode *inode, struct file *file)
+{
+    return single_open(file, ci_otgswitch_show, inode->i_private);
+}
+
+static const struct file_operations ci_otgswitch_fops = {
+    .open        = ci_otgswitch_open,
+    .write        = ci_otgswitch_write,
+    .read        = seq_read,
+    .llseek        = seq_lseek,
+    .release    = single_release,
+};
+
 static int ci_registers_show(struct seq_file *s, void *unused)
 {
     struct ci_hdrc *ci = s->private;
@@ -433,6 +538,11 @@ int dbg_create_files(struct ci_hdrc *ci)
     if (!dent)
         goto err;
 
+    dent = debugfs_create_file("otgswitch", S_IRUGO | S_IWUSR, ci->debugfs, ci,
+                   &ci_otgswitch_fops);
+    if (!dent)
+        goto err;
+
     dent = debugfs_create_file("registers", S_IRUGO, ci->debugfs, ci,
                 &ci_registers_fops);
 
--
2.7.4

0 Kudos

6,165 Views
kyleyost
Contributor I

I've applied the patch to the linux version 4.9.11 and when I compile I get the following error: hw_wait_reg implicit function declaration. Do you know what file this is defined or did this change with the updated linux from 4.1.15.

If I comment out the function I can compile and load onto the device. It functions as gadget whereas I can mount and umount as a mass storage device without problem. I then switch to host and the device will work.  I then switch back to gadget and the mass storage device will no longer be detected by PC.

Terminal Output when it works

Mass Storage Function, version: 2009/09/11

LUN: removable file: (no medium)

LUN file: /dev/mmcblk1p3

Number of LUNs=1

g_mass_storage: Mass Storage Gadget, version: 2009/09/11

g_mass_storage: userspace failed to provide iSerialNumber

g_mass_storage: g_mass_storage ready

g_mass_storage gadget: high-speed config #1: Linux File-Backed Storage

Terminal Output after switching to host then back to gadget

Mass Storage Function, version: 2009/09/11

LUN: removable file: (no medium)

LUN file: /dev/mmcblk1p3

Number of LUNs=1

g_mass_storage: Mass Storage Gadget, version: 2009/09/11

g_mass_storage: userspace failed to provide iSerialNumber

g_mass_storage: g_mass_storage ready

**(when I try to plug in the usb cable to pc I never get the message of detection like the last line shown previous)

0 Kudos

6,165 Views
jiujinhong
Contributor IV

Hi Kyle,

my patch take ci_handle_id_switch as reference, so you can take ci_handle_id_switch in your linux driver code. :smileyhappy:

0 Kudos

6,165 Views
DavisRoman
Contributor III

Hi Jiu Jin hong,

Thank you for your patch. I'm also trying to find a way to switch the OTG_ID pin in userspace as our hardware does not have the OTG_ID pin connected.

So, after compiling and installing your patch onto my board, it seems to give me an error when I try to use it.

root@target:/sys/kernel/debug/ci_hdrc.0# ll
total 0
-r--r--r-- 1 root root 0 Dec 31 1969 device
-rw-r--r-- 1 root root 0 Dec 21 22:37 otgswitch
-rw-r--r-- 1 root root 0 Dec 31 1969 port_test
-r--r--r-- 1 root root 0 Dec 31 1969 qheads
-r--r--r-- 1 root root 0 Dec 31 1969 registers
-r--r--r-- 1 root root 0 Dec 31 1969 requests
-rw-r--r-- 1 root root 0 Dec 31 1969 role
root@target:/sys/kernel/debug/ci_hdrc.0# cat role
gadget
root@target:/sys/kernel/debug/ci_hdrc.0# echo 1 > otgswitch
-sh: echo: write error: Invalid argument
root@target:/sys/kernel/debug/ci_hdrc.0# echo 0 > otgswitch
-sh: echo: write error: Invalid argument
root@target:/sys/kernel/debug/ci_hdrc.0# cat role
gadget
root@target:/sys/kernel/debug/ci_hdrc.0#

 

Any idea what the problem could be?

Thank you,


Davis

0 Kudos

6,164 Views
jiujinhong
Contributor IV

echo gadget > otgswtich

echo host > otgswitch

0 Kudos

6,164 Views
bobosv
Contributor II

If USB_OTG_ID pin is unconnected, you can control the level by modifying the PUS bits in Pad control register,

Setting PUS to 00, (pull down) -> Host mode

Setting PUS to 01, (pull up)     -> device mode

0 Kudos

6,163 Views
jiujinhong
Contributor IV

Hi Bo,

my hardware didn't connect OTG_ID too, if set PUS to 01, doesn't make any sense.

0 Kudos

6,164 Views
BiyongSUN
NXP Employee
NXP Employee

It is Linux USB stack defines the roling switching. 

Documentation/devicetree/binding/usb/generic.txt

You can ask your software engineer to check the device tree binding guide to enable Generic USB Properties srp and hnp. Of course, the device connect to this port also need to support the protocol to do switching.

If the hardware design already know about the device connect to this port is host or device. simply use the  dr_mode to  force it to host or peripheral.

0 Kudos

6,164 Views
jiujinhong
Contributor IV

dts srp/hnp is disable default, if force dts dr_mode to "peripheral"  in otg node, it make sense.  my hardware dind't attach OTG_ID and no plan to support this.

if echo peripheral > /sys/kernel/debug/ci_hdrc.0/role, doesn't make any sense as code expected(debug.c), still need to debug if debugfs receive cmd para successfully.

thanks, biyong

0 Kudos

6,164 Views
BiyongSUN
NXP Employee
NXP Employee

if you use the BSP release  L4.1.15, please check the Documentation\usb\chipidea.txt

0 Kudos

6,164 Views
jiujinhong
Contributor IV

Hi Biyong,

1. I have enable below in DTS.

&usbotg {
 10     vbus-supply = <&reg_usb_otg_vbus>;
  9     pinctrl-names = "default";
  8     pinctrl-0 = <&pinctrl_usbotg>;
  7     disable-over-current;
  6     /* srp-disable;
  5     hnp-disable;
  4     adp-disable;
  3     srp-disable;*/
  2     hnp-enable;
  1     srp-enable;
  0     dr_mode = "otg";                                                                                                      
  1     otg-rev = <0x0200>;
  2     status = "okay";
  3 };

2. after booting, chipidea hdrc probe code initialize role to "host"

sabresd_6dq:/ # cd /sys/kernel/debug/ci_hdrc.0/
sabresd_6dq:/sys/kernel/debug/ci_hdrc.0 # cat role
host


sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs # cat a_bus_drop        
1

3. insert usb disk to usb otg (actually hardware use  USB A). it is not stable, continuously  attach and detach.

sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs # [  332.824972] usb 1-1: new high-speed USB device number 4 using ci_hdrc
[  332.975996] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  332.982725] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  332.990095] usb 1-1: Product: Cruzer Blade
[  332.994204] usb 1-1: Manufacturer: SanDisk
[  332.998338] usb 1-1: SerialNumber: 4C530001100915116124
[  333.007254] usb-storage 1-1:1.0: USB Mass Storage device detected
[  333.013696] scsi host2: usb-storage 1-1:1.0
\[  333.345411] usb 1-1: USB disconnect, device number 4
[  333.624965] usb 1-1: new high-speed USB device number 5 using ci_hdrc
[  333.775995] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  333.782730] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  333.790160] usb 1-1: Product: Cruzer Blade
[  333.794270] usb 1-1: Manufacturer: SanDisk
[  333.798589] usb 1-1: SerialNumber: 4C530001100915116124
[  333.807631] usb-storage 1-1:1.0: USB Mass Storage device detected
[  333.814075] scsi host3: usb-storage 1-1:1.0
[  334.153385] usb 1-1: USB disconnect, device number 5
[  334.434965] usb 1-1: new high-speed USB device number 6 using ci_hdrc
[  334.585995] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  334.592724] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  334.600084] usb 1-1: Product: Cruzer Blade
[  334.604193] usb 1-1: Manufacturer: SanDisk
[  334.608329] usb 1-1: SerialNumber: 4C530001100915116124
[  334.617122] usb-storage 1-1:1.0: USB Mass Storage device detected
[  334.623541] scsi host4: usb-storage 1-1:1.0
[  334.961394] usb 1-1: USB disconnect, device number 6
[  335.244965] usb 1-1: new high-speed USB device number 7 using ci_hdrc
[  335.395994] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  335.402723] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  335.410090] usb 1-1: Product: Cruzer Blade
[  335.414199] usb 1-1: Manufacturer: SanDisk
[  335.418335] usb 1-1: SerialNumber: 4C530001100915116124
[  335.427244] usb-storage 1-1:1.0: USB Mass Storage device detected
[  335.433677] scsi host5: usb-storage 1-1:1.0
[  335.769373] usb 1-1: USB disconnect, device number 7
[  336.054960] usb 1-1: new high-speed USB device number 8 using ci_hdrc
[  336.205996] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  336.212740] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  336.220197] usb 1-1: Product: Cruzer Blade
[  336.224308] usb 1-1: Manufacturer: SanDisk
[  336.228451] usb 1-1: SerialNumber: 4C530001100915116124
[  336.237388] usb-storage 1-1:1.0: USB Mass Storage device detected
[  336.243829] scsi host6: usb-storage 1-1:1.0
[  336.577397] usb 1-1: USB disconnect, device number 8
[  336.864964] usb 1-1: new high-speed USB device number 9 using ci_hdrc
[  337.015996] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  337.022757] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  337.029950] usb 1-1: Product: Cruzer Blade
[  337.034066] usb 1-1: Manufacturer: SanDisk
[  337.038508] usb 1-1: SerialNumber: 4C530001100915116124
[  337.047383] usb-storage 1-1:1.0: USB Mass Storage device detected
[  337.053882] scsi host7: usb-storage 1-1:1.0
[  337.385383] usb 1-1: USB disconnect, device number 9
\[  337.664973] usb 1-1: new high-speed USB device number 10 using ci_hdrc
\[  337.815995] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  337.822727] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  337.830097] usb 1-1: Product: Cruzer Blade
[  337.834207] usb 1-1: Manufacturer: SanDisk
[  337.838349] usb 1-1: SerialNumber: 4C530001100915116124
[  337.847381] usb-storage 1-1:1.0: USB Mass Storage device detected
[  337.853840] scsi host8: usb-storage 1-1:1.0
\\[  338.193392] usb 1-1: USB disconnect, device number 10
\\[  338.474967] usb 1-1: new high-speed USB device number 11 using ci_hdrc
\[  338.625993] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  338.632724] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  338.640094] usb 1-1: Product: Cruzer Blade
[  338.644204] usb 1-1: Manufacturer: SanDisk
[  338.648340] usb 1-1: SerialNumber: 4C530001100915116124
[  338.657243] usb-storage 1-1:1.0: USB Mass Storage device detected
[  338.663668] scsi host9: usb-storage 1-1:1.0
[  339.001371] usb 1-1: USB disconnect, device number 11
[  339.284966] usb 1-1: new high-speed USB device number 12 using ci_hdrc
[  339.435994] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  339.442727] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  339.450094] usb 1-1: Product: Cruzer Blade
[  339.454203] usb 1-1: Manufacturer: SanDisk
[  339.458338] usb 1-1: SerialNumber: 4C530001100915116124
[  339.467251] usb-storage 1-1:1.0: USB Mass Storage device detected
[  339.473678] scsi host10: usb-storage 1-1:1.0
[  339.809385] usb 1-1: USB disconnect, device number 12
[  340.104958] usb 1-1: new high-speed USB device number 13 using ci_hdrc
[  340.255995] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  340.262724] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  340.270087] usb 1-1: Product: Cruzer Blade
[  340.274195] usb 1-1: Manufacturer: SanDisk
[  340.278335] usb 1-1: SerialNumber: 4C530001100915116124
[  340.287235] usb-storage 1-1:1.0: USB Mass Storage device detected
[  340.293689] scsi host11: usb-storage 1-1:1.0
[  340.300681] usb 1-1: USB disconnect, device number 13
[  340.307709] usb 1-1: usbfs: USBDEVFS_CONTROL failed cmd UsbService host rqt 128 rq 6 len 254 ret -108

4. after disable a_bus_drop, udisk is stable for probe and enumarate

sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs # echo 0 > a_bus_drop
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs # [  509.274965] usb 1-1: new high-speed USB device number 14 using ci_hdrc
[  509.425914] usb 1-1: New USB device found, idVendor=0781, idProduct=5567
[  509.432644] usb 1-1: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  509.440012] usb 1-1: Product: Cruzer Blade
[  509.444120] usb 1-1: Manufacturer: SanDisk
[  509.448256] usb 1-1: SerialNumber: 4C530001100915116124
[  509.457176] usb-storage 1-1:1.0: USB Mass Storage device detected
[  509.463599] scsi host12: usb-storage 1-1:1.0
[  510.466109] scsi 12:0:0:0: Direct-Access     SanDisk  Cruzer Blade     1.27 PQ: 0 ANSI: 6
[  510.479337] sd 12:0:0:0: [sda] 61318208 512-byte logical blocks: (31.3 GB/29.2 GiB)
[  510.488439] sd 12:0:0:0: [sda] Write Protect is off
[  510.493331] sd 12:0:0:0: [sda] Mode Sense: 43 00 00 00
[  510.499184] sd 12:0:0:0: [sda] Write cache: disabled, read cache: enabled, doesn't support DPO or FUA
[  510.520714]  sda: sda1
[  510.534694] sd 12:0:0:0: [sda] Attached SCSI removable disk
[  511.533580] FAT-fs (sda1): Volume was not properly unmounted. Some data may be corrupt. Please run fsck.

5. change role to gadget, insert USB B cable to USB A port(imx6 otg) and connect with PC. it doesn't work.

sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs # echo 1 > b_bus_req
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs #
sabresd_6dq:/sys/bus/platform/devices/ci_hdrc.0/inputs # cat b_bus_req
1

sabresd_6dq:/sys/kernel/debug/ci_hdrc.0 # echo gadget > role
[  708.403022] ci_hdrc ci_hdrc.0: remove, state 1
[  708.407540] usb usb1: USB disconnect, device number 1
[  708.432621] usb 1-1: USB disconnect, device number 14
[  708.452028] ci_hdrc ci_hdrc.0: USB bus 1 deregistered

Summary:

1) hardware otg bus use USB A port. It seems that our board doesn't support OTG feature, the board never use OTG_ID pin.

2) If force dr_mode to "gadget" in dts, it works.

3) are there other way to make gadget work from host in my case?

4) I found that chipidea will automatically init to OTG in below code. If doesn't enable hnp-enable/srp-enable/dr_mode in dts, it works for host, don't need to disable a_bus_drop. is bsp issue?

  1     if (platdata->dr_mode == USB_DR_MODE_OTG) {
  0         /* We can support HNP and SRP of OTG 2.0 */                                                                       
  1         platdata->ci_otg_caps.otg_rev = 0x0200;
  2         platdata->ci_otg_caps.hnp_support = true;
  3         platdata->ci_otg_caps.srp_support = true;
  4             
  5         /* Update otg capabilities by DT properties */
  6         ret = of_usb_update_otg_caps(dev->of_node,
  7                     &platdata->ci_otg_caps);
  8         if (ret)
  9             return ret;
 10     } 

0 Kudos

6,164 Views
emintolgasivri
Contributor II

Hi

I have fimilar problem.I am using imx7d.otg2 is working but otg1 doesnt work.Both oh them will be host.I use DP,DN and GND pins.Vbus goes to 5V directly.I tried with dr_mode=host and dr_mode=peripheral.but it didnt work.İf I sturtup with otg mode ,I can load image to emmc to use mfgtool.Bu in normal condition otg didnt dedect any device.

My dts is this now.

&usbotg1 {
    vbus-supply = <&reg_usb_otg1_vbus>;
    srp-disable;
    hnp-disable;
    adp-disable;
    disable-over-current;
    dr_mode = "peripheral";
    status = "okay";
};

&usbotg2 {
    vbus-supply = <&reg_usb_otg2_vbus>;
    dr_mode = "host";
    status = "okay";
};

root@imx7dea-ucom:/sys/kernel/debug/ci_hdrc.0# cat role
gadget

Also when device startup I am seeing this

................

bd7181x-rtc bd7181x-rtc: setting system clock to 2000-01-01 12:00:10 UTC (946728010)
usb_otg1_vbus: disabling
can2-3v3: disabling
wlreg_on: disabling

.......................

What is meaning the usb_otg1_vbus: disabling.Vbus goes to 5V directly.

0 Kudos

6,163 Views
SergioSolis
NXP Employee
NXP Employee

Please refer to the following thread, it can help you with your question:

Re: USB OTG to USB HOST

0 Kudos