diff mbox

[4/4] usb: gadget: udc: renesas_usb3: add support for usb role swap

Message ID 1490702004-8167-5-git-send-email-yoshihiro.shimoda.uh@renesas.com (mailing list archive)
State Superseded
Delegated to: Geert Uytterhoeven
Headers show

Commit Message

Yoshihiro Shimoda March 28, 2017, 11:53 a.m. UTC
This patch adds support for usb role swap via sysfs "role".

For example:
 1) Connect a usb cable using 2 Salvator-X boards.
  - For A-Device, the cable is connected to CN11 (USB3.0 ch0).
  - For B-Device, the cable is connected to CN9 (USB2.0 ch0).
 2) On A-Device, you input the following command:
  # echo peripheral > /sys/devices/platform/soc/ee020000.usb/role
 3) On B-Device, you input the following command:
  # echo host > /sys/devices/platform/soc/ee080200.usb-phy/role

Then, the A-Device acts as a peripheral and the B-Device acts as
a host. Please note that A-Device must input the following command
if you want the board to act as a host again.
 # echo host > /sys/devices/platform/soc/ee020000.usb/role

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
---
 .../ABI/testing/sysfs-platform-renesas_usb3        |  2 ++
 drivers/usb/gadget/udc/renesas_usb3.c              | 41 +++++++++++++++++++++-
 2 files changed, 42 insertions(+), 1 deletion(-)
diff mbox

Patch

diff --git a/Documentation/ABI/testing/sysfs-platform-renesas_usb3 b/Documentation/ABI/testing/sysfs-platform-renesas_usb3
index f5dace7..1ab919c 100644
--- a/Documentation/ABI/testing/sysfs-platform-renesas_usb3
+++ b/Documentation/ABI/testing/sysfs-platform-renesas_usb3
@@ -7,6 +7,8 @@  Description:
 		The file can show/change the drd mode of usb.
 
 		Write the following string to change the mode:
+		 "host" - switching mode from peripheral to host.
+		 "peripheral" - switching mode from host to peripheral.
 		 "b-device" - switching mode as forced b-device mode.
 
 		Read the file, then it shows the following strings:
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 34ac03c..b552243 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -570,12 +570,29 @@  static void usb3_mode_a_host(struct renesas_usb3 *usb3)
 	usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
 }
 
+static void usb3_mode_a_peri(struct renesas_usb3 *usb3)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&usb3->lock, flags);
+	usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+	usb3_set_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+	usb3_check_vbus(usb3);
+	spin_unlock_irqrestore(&usb3->lock, flags);
+}
+
 static void usb3_mode_b_peri(struct renesas_usb3 *usb3)
 {
 	usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
 	usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
 }
 
+static void usb3_mode_b_host(struct renesas_usb3 *usb3)
+{
+	usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+	usb3_clear_bit(usb3, DRD_CON_VBOUT, USB3_DRD_CON);
+}
+
 static bool usb3_is_a_device(struct renesas_usb3 *usb3)
 {
 	return !(usb3_read(usb3, USB3_USB_OTG_STA) & USB_OTG_IDMON);
@@ -1865,8 +1882,30 @@  static ssize_t role_store(struct device *dev, struct device_attribute *attr,
 		usb3->forced_b_device = true;
 		renesas_usb3_init_forced_b_device(usb3);
 	} else {
+		bool new_mode_is_host;
+
 		usb3->forced_b_device = false;
-		return -EINVAL;
+		if (!strncmp(buf, "host", strlen("host")))
+			new_mode_is_host = true;
+		else if (!strncmp(buf, "peripheral", strlen("peripheral")))
+			new_mode_is_host = false;
+		else
+			return -EINVAL;
+
+		if (new_mode_is_host == usb3_is_host(usb3))
+			return -EINVAL;
+
+		if (new_mode_is_host) {
+			if (usb3_is_a_device(usb3))
+				usb3_mode_a_host(usb3);
+			else
+				usb3_mode_b_host(usb3);
+		} else {
+			if (usb3_is_a_device(usb3))
+				usb3_mode_a_peri(usb3);
+			else
+				usb3_mode_b_peri(usb3);
+		}
 	}
 
 	return count;