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
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
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)
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:
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
echo gadget > otgswtich
echo host > otgswitch
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
Hi Bo,
my hardware didn't connect OTG_ID too, if set PUS to 01, doesn't make any sense.
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.
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
if you use the BSP release L4.1.15, please check the Documentation\usb\chipidea.txt
Hi Biyong,
1. I have enable below in DTS.
&usbotg {
10 vbus-supply = <®_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 }
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 = <®_usb_otg1_vbus>;
srp-disable;
hnp-disable;
adp-disable;
disable-over-current;
dr_mode = "peripheral";
status = "okay";
};
&usbotg2 {
vbus-supply = <®_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.
Please refer to the following thread, it can help you with your question: