usb: gadget: udc: renesas_usb3: Add role switch support for RZ/V2M
authorBiju Das <biju.das.jz@bp.renesas.com>
Sat, 21 Jan 2023 14:58:47 +0000 (14:58 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 25 Jan 2023 14:48:16 +0000 (15:48 +0100)
As RZ/V2M has both HOST and PERI reset module, we need to do reset release
before accessing registers in respective IP module.

This patch adds role switch support for RZ/V2M.

Signed-off-by: Biju Das <biju.das.jz@bp.renesas.com>
Link: https://lore.kernel.org/r/20230121145853.4792-7-biju.das.jz@bp.renesas.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/gadget/udc/renesas_usb3.c

index 8d69450..bee6bce 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/device.h>
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
 #include <linux/extcon-provider.h>
@@ -2366,6 +2367,9 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
 
        usb3 = gadget_to_renesas_usb3(gadget);
 
+       if (usb3->is_rzv2m && usb3_is_a_device(usb3))
+               return -EBUSY;
+
        /* hook up the driver */
        usb3->driver = driver;
 
@@ -2374,6 +2378,10 @@ static int renesas_usb3_start(struct usb_gadget *gadget,
 
        pm_runtime_get_sync(usb3_to_dev(usb3));
 
+       /* Peripheral Reset */
+       if (usb3->is_rzv2m)
+               rzv2m_usb3drd_reset(usb3_to_dev(usb3)->parent, false);
+
        renesas_usb3_init_controller(usb3);
 
        return 0;
@@ -2386,8 +2394,10 @@ static int renesas_usb3_stop(struct usb_gadget *gadget)
        usb3->softconnect = false;
        usb3->gadget.speed = USB_SPEED_UNKNOWN;
        usb3->driver = NULL;
-       renesas_usb3_stop_controller(usb3);
+       if (usb3->is_rzv2m)
+               rzv2m_usb3drd_reset(usb3_to_dev(usb3)->parent, false);
 
+       renesas_usb3_stop_controller(usb3);
        if (usb3->phy)
                phy_exit(usb3->phy);
 
@@ -2447,18 +2457,29 @@ static void handle_ext_role_switch_states(struct device *dev,
        switch (role) {
        case USB_ROLE_NONE:
                usb3->connection_state = USB_ROLE_NONE;
-               if (cur_role == USB_ROLE_HOST)
+               if (!usb3->is_rzv2m && cur_role == USB_ROLE_HOST)
                        device_release_driver(host);
-               if (usb3->driver)
+               if (usb3->driver) {
+                       if (usb3->is_rzv2m)
+                               rzv2m_usb3drd_reset(dev->parent, false);
                        usb3_disconnect(usb3);
+               }
                usb3_vbus_out(usb3, false);
+
+               if (usb3->is_rzv2m) {
+                       rzv2m_usb3drd_reset(dev->parent, true);
+                       device_release_driver(host);
+               }
                break;
        case USB_ROLE_DEVICE:
                if (usb3->connection_state == USB_ROLE_NONE) {
                        usb3->connection_state = USB_ROLE_DEVICE;
                        usb3_set_mode(usb3, false);
-                       if (usb3->driver)
+                       if (usb3->driver) {
+                               if (usb3->is_rzv2m)
+                                       renesas_usb3_init_controller(usb3);
                                usb3_connect(usb3);
+                       }
                } else if (cur_role == USB_ROLE_HOST)  {
                        device_release_driver(host);
                        usb3_set_mode(usb3, false);
@@ -2469,8 +2490,11 @@ static void handle_ext_role_switch_states(struct device *dev,
                break;
        case USB_ROLE_HOST:
                if (usb3->connection_state == USB_ROLE_NONE) {
-                       if (usb3->driver)
+                       if (usb3->driver) {
+                               if (usb3->is_rzv2m)
+                                       rzv2m_usb3drd_reset(dev->parent, false);
                                usb3_disconnect(usb3);
+                       }
 
                        usb3->connection_state = USB_ROLE_HOST;
                        usb3_set_mode(usb3, true);