[PATCH/RFC v2 5/6] usb: gadget: udc: renesas_usb3: add support for a usb role switch

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds support for a usb role switch driver. And then,
this driver uses the usb role switch APIs instead of hardware
access to initialize usb host side at specific timings.

Signed-off-by: Yoshihiro Shimoda <yoshihiro.shimoda.uh@xxxxxxxxxxx>
---
 drivers/usb/gadget/udc/Kconfig        |  1 +
 drivers/usb/gadget/udc/renesas_usb3.c | 34 ++++++++++++++++++++++++++++------
 2 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index 0875d38..7e4a5dd 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -193,6 +193,7 @@ config USB_RENESAS_USB3
 	tristate 'Renesas USB3.0 Peripheral controller'
 	depends on ARCH_RENESAS || COMPILE_TEST
 	depends on EXTCON && HAS_DMA
+	select USB_ROLE_SWITCH
 	help
 	   Renesas USB3.0 Peripheral controller is a USB peripheral controller
 	   that supports super, high, and full speed USB 3.0 data transfers.
diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 409cde4..5b7b1ce 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -23,6 +23,7 @@
 #include <linux/uaccess.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/role.h>
 
 /* register definitions */
 #define USB3_AXI_INT_STA	0x008
@@ -330,6 +331,7 @@ struct renesas_usb3 {
 
 	struct usb_gadget gadget;
 	struct usb_gadget_driver *driver;
+	struct usb_role_switch *role_sw;	/* Optional */
 	struct extcon_dev *extcon;
 	struct work_struct extcon_work;
 	struct phy *phy;
@@ -454,7 +456,11 @@ static void usb3_disable_pipe_irq(struct renesas_usb3 *usb3, int num)
 
 static bool usb3_is_host(struct renesas_usb3 *usb3)
 {
-	return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON);
+	if (usb3->role_sw)
+		return usb_role_switch_get_role(usb3->role_sw) ==
+						USB_ROLE_HOST ? true : false;
+	else
+		return !(usb3_read(usb3, USB3_DRD_CON) & DRD_CON_PERI_CON);
 }
 
 static void usb3_init_axi_bridge(struct renesas_usb3 *usb3)
@@ -645,10 +651,16 @@ static void usb3_check_vbus(struct renesas_usb3 *usb3)
 
 static void usb3_set_mode(struct renesas_usb3 *usb3, bool host)
 {
-	if (host)
-		usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
-	else
-		usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+	if (usb3->role_sw) {
+		enum usb_role role = host ? USB_ROLE_HOST : USB_ROLE_DEVICE;
+
+		usb_role_switch_set_role(usb3->role_sw, role);
+	} else {
+		if (host)
+			usb3_clear_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+		else
+			usb3_set_bit(usb3, DRD_CON_PERI_CON, USB3_DRD_CON);
+	}
 }
 
 static void usb3_vbus_out(struct renesas_usb3 *usb3, bool enable)
@@ -663,8 +675,8 @@ static void usb3_mode_config(struct renesas_usb3 *usb3, bool host, bool a_dev)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&usb3->lock, flags);
 	usb3_set_mode(usb3, host);
+	spin_lock_irqsave(&usb3->lock, flags);
 	usb3_vbus_out(usb3, a_dev);
 	/* for A-Peripheral or forced B-device mode */
 	if ((!host && a_dev) ||
@@ -2238,6 +2250,10 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
 	/* hook up the driver */
 	usb3->driver = driver;
 
+	usb3->role_sw = usb_role_switch_get_by_graph(usb3_to_dev(usb3), 0, 0);
+	if (IS_ERR_OR_NULL(usb3->role_sw))
+		usb3->role_sw = NULL;
+
 	if (usb3->phy)
 		phy_init(usb3->phy);
 
@@ -2260,6 +2276,8 @@ static int renesas_usb3_stop(struct usb_gadget *gadget)
 	if (usb3->phy)
 		phy_exit(usb3->phy);
 
+	usb_role_switch_put(usb3->role_sw);
+
 	pm_runtime_put(usb3_to_dev(usb3));
 
 	return 0;
@@ -2632,6 +2650,10 @@ static int renesas_usb3_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_add_udc;
 
+	ret = devm_of_platform_populate(&pdev->dev);
+	if (ret < 0)
+		goto err_dev_create;
+
 	ret = device_create_file(&pdev->dev, &dev_attr_role);
 	if (ret < 0)
 		goto err_dev_create;
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]


  Powered by Linux