[V4,4/7] usb: gadget: udc: renesas_usb3: Use usb_role_switch framework
diff mbox series

Message ID 1555407487-35394-5-git-send-email-biju.das@bp.renesas.com
State New
Headers show
Series
  • Add USB3.0 and TI HD3SS3220 driver support
Related show

Commit Message

Biju Das April 16, 2019, 9:38 a.m. UTC
RZ/G2E cat874 board is capable of detecting cable connect and disconnect
events. Add support for renesas_usb3 to receive connect and disconnect
events and support dual-role switch using usb-role-switch framework.

Signed-off-by: Biju Das <biju.das@bp.renesas.com>
---
 V3-->V4
   * No Change
 V2-->V3
   * Incorporated Shimoda-san's review comment
     (https://patchwork.kernel.org/patch/10852507/)
   * Used renesas,usb-role-switch property for differentiating USB
     role switch associated with Type-C port controller driver.
 V1-->V2
   * Driver uses usb role clas for handling dual role switch and handling
     connect/disconnect events instead of extcon.
---
 drivers/usb/gadget/udc/renesas_usb3.c | 126 ++++++++++++++++++++++++++++------
 1 file changed, 104 insertions(+), 22 deletions(-)

Comments

Yoshihiro Shimoda April 23, 2019, 2:27 a.m. UTC | #1
Hi Biju-san,

Thank you for the patch!

> From: Biju Das, Sent: Tuesday, April 16, 2019 6:38 PM
> 
> RZ/G2E cat874 board is capable of detecting cable connect and disconnect
> events. Add support for renesas_usb3 to receive connect and disconnect
> events and support dual-role switch using usb-role-switch framework.
> 
> Signed-off-by: Biju Das <biju.das@bp.renesas.com>
> ---
>  V3-->V4
>    * No Change
>  V2-->V3
>    * Incorporated Shimoda-san's review comment
>      (https://patchwork.kernel.org/patch/10852507/)
>    * Used renesas,usb-role-switch property for differentiating USB
>      role switch associated with Type-C port controller driver.
>  V1-->V2
>    * Driver uses usb role clas for handling dual role switch and handling
>      connect/disconnect events instead of extcon.
<snip>

> +static void usb3_check_vbus(struct renesas_usb3 *usb3)
> +{
> +	if (usb3->workaround_for_vbus) {
> +		if (usb3->usb_role_switch_property) {
> +			if (usb3->connection_state == USB_ROLE_DEVICE) {
> +				usb3_mode_config(usb3, false, false);

I should have pointed it out the previous version though,
why does this usb3_mode_config() calling need?
My guess is:
 - renesas_usb3_start() calls renesas_usb3_init_controller().
 -- renesas_usb3_init_controller() calls usb3_check_id() and then usb_check_vbus().
 --- usb_check_id() calls usb3_mode_config(usb3, true, true) and then the HW acts as host mode.
 ----> So, you'd like the HW to acts as peripheral mode when the connection_state is USB_ROLE_DEVICE,
       you added that the usb3_check_vbus() calls usb3_mode_config(usb3, false, false).

Is my guess correct? If so, I'd like to add such code into usb3_check_id() like below:

	if ((usb3->extcon_host && !usb3->forced_b_device) ||
	    (usb3->usb_role_switch_property &&
	     usb3->connection_state == USB_ROLE_HOST))
		usb3_mode_config(usb3, true, true);
	else
		usb3_mode_config(usb3, false, false);

What do you think?

Best regards,
Yoshihiro Shimoda
Biju Das April 23, 2019, 9:07 a.m. UTC | #2
Hi Shimoda-San,

Thanks for the feedback.

> Subject: RE: [PATCH V4 4/7] usb: gadget: udc: renesas_usb3: Use
> usb_role_switch framework
> 
> Hi Biju-san,
> 
> Thank you for the patch!
> 
> > From: Biju Das, Sent: Tuesday, April 16, 2019 6:38 PM
> >
> > RZ/G2E cat874 board is capable of detecting cable connect and
> > disconnect events. Add support for renesas_usb3 to receive connect and
> > disconnect events and support dual-role switch using usb-role-switch
> framework.
> >
> > Signed-off-by: Biju Das <biju.das@bp.renesas.com>
> > ---
> >  V3-->V4
> >    * No Change
> >  V2-->V3
> >    * Incorporated Shimoda-san's review comment
> >      (https://patchwork.kernel.org/patch/10852507/)
> >    * Used renesas,usb-role-switch property for differentiating USB
> >      role switch associated with Type-C port controller driver.
> >  V1-->V2
> >    * Driver uses usb role clas for handling dual role switch and handling
> >      connect/disconnect events instead of extcon.
> <snip>
> 
> > +static void usb3_check_vbus(struct renesas_usb3 *usb3) {
> > +	if (usb3->workaround_for_vbus) {
> > +		if (usb3->usb_role_switch_property) {
> > +			if (usb3->connection_state == USB_ROLE_DEVICE) {
> > +				usb3_mode_config(usb3, false, false);
> 
> I should have pointed it out the previous version though, why does this
> usb3_mode_config() calling need?
> My guess is:
>  - renesas_usb3_start() calls renesas_usb3_init_controller().
>  -- renesas_usb3_init_controller() calls usb3_check_id() and then
> usb_check_vbus().
>  --- usb_check_id() calls usb3_mode_config(usb3, true, true) and then the
> HW acts as host mode.
>  ----> So, you'd like the HW to acts as peripheral mode when the
> connection_state is USB_ROLE_DEVICE,
>        you added that the usb3_check_vbus() calls usb3_mode_config(usb3,
> false, false).
> 
> Is my guess correct? If so, I'd like to add such code into usb3_check_id() like
> below:

Yes, it is almost correct. The scenario I am trying is

[1] USB type C  cable connected to a Host Machine(TI chip identifies as Device connection. But we haven't installed Gadget module for Device operation)

[2] After that trying to install gadget module. In this case,  it calls usb_check_id() as mentioned above
and configure it as Host mode.

> 	if ((usb3->extcon_host && !usb3->forced_b_device) ||
> 	    (usb3->usb_role_switch_property &&
> 	     usb3->connection_state == USB_ROLE_HOST))
> 		usb3_mode_config(usb3, true, true);
> 	else
> 		usb3_mode_config(usb3, false, false);
> 
> What do you think?

Since as per [1], usb3->extcon_host=1 and !usb3->forced_b_device ==1  ,  The above code always enter into Host Mode configuration.

To make it work,  I need to update  " usb3->forced_b_device" based on connection_state from TI chip. So the new code look like

1) There is no change in usb_check_id() call.

if (usb3->extcon_host && !usb3->forced_b_device)
    usb3_mode_config(usb3, true, true);
   else
    usb3_mode_config(usb3, false, false);

2) Update "usb3->forced_b_device" variable  based on connection_state.

@@ -2370,6 +2376,7 @@ static void handle_ext_role_switch_states(struct device *dev,
                usb3_vbus_out(usb3, false);
                break;
        case USB_ROLE_DEVICE:
+               usb3->forced_b_device = true;
                if (usb3->connection_state == USB_ROLE_NONE) {
                        usb3->connection_state = USB_ROLE_DEVICE;
                        usb3_set_mode(usb3, false);
@@ -2384,6 +2391,7 @@ static void handle_ext_role_switch_states(struct device *dev,
                usb3_vbus_out(usb3, false);
                break;
        case USB_ROLE_HOST:
+               usb3->forced_b_device = false;

Can you please confirm are you ok with this changes? Or do you prefer the previous one?

Note:- 
 I have done only sanity testing with this changes.

Regards,
Biju
Yoshihiro Shimoda April 23, 2019, 11 a.m. UTC | #3
Hi Biju-san,

> From: Biju Das, Sent: Tuesday, April 23, 2019 6:08 PM
> 
> Hi Shimoda-San,
> 
> Thanks for the feedback.
> 
> > Subject: RE: [PATCH V4 4/7] usb: gadget: udc: renesas_usb3: Use
> > usb_role_switch framework
> >
> > Hi Biju-san,
> >
> > Thank you for the patch!
> >
> > > From: Biju Das, Sent: Tuesday, April 16, 2019 6:38 PM
> > >
> > > RZ/G2E cat874 board is capable of detecting cable connect and
> > > disconnect events. Add support for renesas_usb3 to receive connect and
> > > disconnect events and support dual-role switch using usb-role-switch
> > framework.
> > >
> > > Signed-off-by: Biju Das <biju.das@bp.renesas.com>
> > > ---
> > >  V3-->V4
> > >    * No Change
> > >  V2-->V3
> > >    * Incorporated Shimoda-san's review comment
> > >      (https://patchwork.kernel.org/patch/10852507/)
> > >    * Used renesas,usb-role-switch property for differentiating USB
> > >      role switch associated with Type-C port controller driver.
> > >  V1-->V2
> > >    * Driver uses usb role clas for handling dual role switch and handling
> > >      connect/disconnect events instead of extcon.
> > <snip>
> >
> > > +static void usb3_check_vbus(struct renesas_usb3 *usb3) {
> > > +	if (usb3->workaround_for_vbus) {
> > > +		if (usb3->usb_role_switch_property) {
> > > +			if (usb3->connection_state == USB_ROLE_DEVICE) {
> > > +				usb3_mode_config(usb3, false, false);
> >
> > I should have pointed it out the previous version though, why does this
> > usb3_mode_config() calling need?
> > My guess is:
> >  - renesas_usb3_start() calls renesas_usb3_init_controller().
> >  -- renesas_usb3_init_controller() calls usb3_check_id() and then
> > usb_check_vbus().
> >  --- usb_check_id() calls usb3_mode_config(usb3, true, true) and then the
> > HW acts as host mode.
> >  ----> So, you'd like the HW to acts as peripheral mode when the
> > connection_state is USB_ROLE_DEVICE,
> >        you added that the usb3_check_vbus() calls usb3_mode_config(usb3,
> > false, false).
> >
> > Is my guess correct? If so, I'd like to add such code into usb3_check_id() like
> > below:
> 
> Yes, it is almost correct. The scenario I am trying is
> 
> [1] USB type C  cable connected to a Host Machine(TI chip identifies as Device connection. But we haven't installed Gadget
> module for Device operation)
> 
> [2] After that trying to install gadget module. In this case,  it calls usb_check_id() as mentioned above
> and configure it as Host mode.

Thank you for the explanation.

> > 	if ((usb3->extcon_host && !usb3->forced_b_device) ||
> > 	    (usb3->usb_role_switch_property &&
> > 	     usb3->connection_state == USB_ROLE_HOST))
> > 		usb3_mode_config(usb3, true, true);
> > 	else
> > 		usb3_mode_config(usb3, false, false);
> >
> > What do you think?
> 
> Since as per [1], usb3->extcon_host=1 and !usb3->forced_b_device ==1  ,  The above code always enter into Host Mode
> configuration.

Oops. Thank you for the pointed it out.

> To make it work,  I need to update  " usb3->forced_b_device" based on connection_state from TI chip. So the new code look
> like

Since the forced_b_device is related to debug purpose (controlled by debugfs), I don't want to use the value for type-c.

> 1) There is no change in usb_check_id() call.
> 
> if (usb3->extcon_host && !usb3->forced_b_device)
>     usb3_mode_config(usb3, true, true);
>    else
>     usb3_mode_config(usb3, false, false);
> 
> 2) Update "usb3->forced_b_device" variable  based on connection_state.
> 
> @@ -2370,6 +2376,7 @@ static void handle_ext_role_switch_states(struct device *dev,
>                 usb3_vbus_out(usb3, false);
>                 break;
>         case USB_ROLE_DEVICE:
> +               usb3->forced_b_device = true;
>                 if (usb3->connection_state == USB_ROLE_NONE) {
>                         usb3->connection_state = USB_ROLE_DEVICE;
>                         usb3_set_mode(usb3, false);
> @@ -2384,6 +2391,7 @@ static void handle_ext_role_switch_states(struct device *dev,
>                 usb3_vbus_out(usb3, false);
>                 break;
>         case USB_ROLE_HOST:
> +               usb3->forced_b_device = false;
> 
> Can you please confirm are you ok with this changes? Or do you prefer the previous one?

I'd like to change usb3_check_id() somehow.
How about the following conditions? In type-c environment,
since usb3->usb_role_switch_property is true, it should be OK for it.

	if ((!usb3->usb_role_switch_property &&
	     usb3->extcon_host && !usb3->forced_b_device) ||
	    (usb3->usb_role_switch_property &&
	     usb3->connection_state == USB_ROLE_HOST))
		usb3_mode_config(usb3, true, true);
	else
		usb3_mode_config(usb3, false, false);

Best regards,
Yoshihiro Shimoda

> Note:-
>  I have done only sanity testing with this changes.
> 
> Regards,
> Biju
> 
> 
> 
> 
> 
>
Biju Das April 23, 2019, 3:06 p.m. UTC | #4
Hi Shimoda-San,

Thanks for the feedback.

> Subject: RE: [PATCH V4 4/7] usb: gadget: udc: renesas_usb3: Use
> usb_role_switch framework
> 
> Hi Biju-san,
> 
> > From: Biju Das, Sent: Tuesday, April 23, 2019 6:08 PM
> >
> > Hi Shimoda-San,
> >
> > Thanks for the feedback.
> >
> > > Subject: RE: [PATCH V4 4/7] usb: gadget: udc: renesas_usb3: Use
> > > usb_role_switch framework
> > >
> > > Hi Biju-san,
> > >
> > > Thank you for the patch!
> > >
> > > > From: Biju Das, Sent: Tuesday, April 16, 2019 6:38 PM
> > > >
> > > > RZ/G2E cat874 board is capable of detecting cable connect and
> > > > disconnect events. Add support for renesas_usb3 to receive connect
> > > > and disconnect events and support dual-role switch using
> > > > usb-role-switch
> > > framework.
> > > >
> > > > Signed-off-by: Biju Das <biju.das@bp.renesas.com>
> > > > ---
> > > >  V3-->V4
> > > >    * No Change
> > > >  V2-->V3
> > > >    * Incorporated Shimoda-san's review comment
> > > >      (https://patchwork.kernel.org/patch/10852507/)
> > > >    * Used renesas,usb-role-switch property for differentiating USB
> > > >      role switch associated with Type-C port controller driver.
> > > >  V1-->V2
> > > >    * Driver uses usb role clas for handling dual role switch and handling
> > > >      connect/disconnect events instead of extcon.
> > > <snip>
> > >
> > > > +static void usb3_check_vbus(struct renesas_usb3 *usb3) {
> > > > +	if (usb3->workaround_for_vbus) {
> > > > +		if (usb3->usb_role_switch_property) {
> > > > +			if (usb3->connection_state == USB_ROLE_DEVICE) {
> > > > +				usb3_mode_config(usb3, false, false);
> > >
> > > I should have pointed it out the previous version though, why does
> > > this
> > > usb3_mode_config() calling need?
> > > My guess is:
> > >  - renesas_usb3_start() calls renesas_usb3_init_controller().
> > >  -- renesas_usb3_init_controller() calls usb3_check_id() and then
> > > usb_check_vbus().
> > >  --- usb_check_id() calls usb3_mode_config(usb3, true, true) and
> > > then the HW acts as host mode.
> > >  ----> So, you'd like the HW to acts as peripheral mode when the
> > > connection_state is USB_ROLE_DEVICE,
> > >        you added that the usb3_check_vbus() calls
> > > usb3_mode_config(usb3, false, false).
> > >
> > > Is my guess correct? If so, I'd like to add such code into
> > > usb3_check_id() like
> > > below:
> >
> > Yes, it is almost correct. The scenario I am trying is
> >
> > [1] USB type C  cable connected to a Host Machine(TI chip identifies
> > as Device connection. But we haven't installed Gadget module for
> > Device operation)
> >
> > [2] After that trying to install gadget module. In this case,  it
> > calls usb_check_id() as mentioned above and configure it as Host mode.
> 
> Thank you for the explanation.
> 
> > > 	if ((usb3->extcon_host && !usb3->forced_b_device) ||
> > > 	    (usb3->usb_role_switch_property &&
> > > 	     usb3->connection_state == USB_ROLE_HOST))
> > > 		usb3_mode_config(usb3, true, true);
> > > 	else
> > > 		usb3_mode_config(usb3, false, false);
> > >
> > > What do you think?
> >
> > Since as per [1], usb3->extcon_host=1 and !usb3->forced_b_device ==1
> > ,  The above code always enter into Host Mode configuration.
> 
> Oops. Thank you for the pointed it out.
> 
> > To make it work,  I need to update  " usb3->forced_b_device" based on
> > connection_state from TI chip. So the new code look like
> 
> Since the forced_b_device is related to debug purpose (controlled by
> debugfs), I don't want to use the value for type-c.
> 
> > 1) There is no change in usb_check_id() call.
> >
> > if (usb3->extcon_host && !usb3->forced_b_device)
> >     usb3_mode_config(usb3, true, true);
> >    else
> >     usb3_mode_config(usb3, false, false);
> >
> > 2) Update "usb3->forced_b_device" variable  based on connection_state.
> >
> > @@ -2370,6 +2376,7 @@ static void handle_ext_role_switch_states(struct
> device *dev,
> >                 usb3_vbus_out(usb3, false);
> >                 break;
> >         case USB_ROLE_DEVICE:
> > +               usb3->forced_b_device = true;
> >                 if (usb3->connection_state == USB_ROLE_NONE) {
> >                         usb3->connection_state = USB_ROLE_DEVICE;
> >                         usb3_set_mode(usb3, false); @@ -2384,6 +2391,7
> > @@ static void handle_ext_role_switch_states(struct device *dev,
> >                 usb3_vbus_out(usb3, false);
> >                 break;
> >         case USB_ROLE_HOST:
> > +               usb3->forced_b_device = false;
> >
> > Can you please confirm are you ok with this changes? Or do you prefer the
> previous one?
> 
> I'd like to change usb3_check_id() somehow.
> How about the following conditions? In type-c environment, since usb3-
> >usb_role_switch_property is true, it should be OK for it.
> 
> 	if ((!usb3->usb_role_switch_property &&
> 	     usb3->extcon_host && !usb3->forced_b_device) ||
> 	    (usb3->usb_role_switch_property &&
> 	     usb3->connection_state == USB_ROLE_HOST))
> 		usb3_mode_config(usb3, true, true);
> 	else
> 		usb3_mode_config(usb3, false, false);
> 

OK. I will send V5 with this changes.

Regards,
Biju

Patch
diff mbox series

diff --git a/drivers/usb/gadget/udc/renesas_usb3.c b/drivers/usb/gadget/udc/renesas_usb3.c
index 7dc2485..efee047 100644
--- a/drivers/usb/gadget/udc/renesas_usb3.c
+++ b/drivers/usb/gadget/udc/renesas_usb3.c
@@ -351,6 +351,8 @@  struct renesas_usb3 {
 	int disabled_count;
 
 	struct usb_request *ep0_req;
+
+	enum usb_role connection_state;
 	u16 test_mode;
 	u8 ep0_buf[USB3_EP0_BUF_SIZE];
 	bool softconnect;
@@ -359,6 +361,7 @@  struct renesas_usb3 {
 	bool extcon_usb;		/* check vbus and set EXTCON_USB */
 	bool forced_b_device;
 	bool start_to_connect;
+	bool usb_role_switch_property;
 };
 
 #define gadget_to_renesas_usb3(_gadget)	\
@@ -644,22 +647,6 @@  static void usb3_disconnect(struct renesas_usb3 *usb3)
 		usb3->driver->disconnect(&usb3->gadget);
 }
 
-static void usb3_check_vbus(struct renesas_usb3 *usb3)
-{
-	if (usb3->workaround_for_vbus) {
-		usb3_connect(usb3);
-	} else {
-		usb3->extcon_usb = !!(usb3_read(usb3, USB3_USB_STA) &
-							USB_STA_VBUS_STA);
-		if (usb3->extcon_usb)
-			usb3_connect(usb3);
-		else
-			usb3_disconnect(usb3);
-
-		schedule_work(&usb3->extcon_work);
-	}
-}
-
 static void renesas_usb3_role_work(struct work_struct *work)
 {
 	struct renesas_usb3 *usb3 =
@@ -699,8 +686,11 @@  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_by_role_sw(usb3, host);
-	usb3_vbus_out(usb3, a_dev);
+	if (!usb3->usb_role_switch_property ||
+	    usb3->connection_state != USB_ROLE_NONE) {
+		usb3_set_mode_by_role_sw(usb3, host);
+		usb3_vbus_out(usb3, a_dev);
+	}
 	/* for A-Peripheral or forced B-device mode */
 	if ((!host && a_dev) || usb3->start_to_connect)
 		usb3_connect(usb3);
@@ -724,6 +714,28 @@  static void usb3_check_id(struct renesas_usb3 *usb3)
 	schedule_work(&usb3->extcon_work);
 }
 
+static void usb3_check_vbus(struct renesas_usb3 *usb3)
+{
+	if (usb3->workaround_for_vbus) {
+		if (usb3->usb_role_switch_property) {
+			if (usb3->connection_state == USB_ROLE_DEVICE) {
+				usb3_mode_config(usb3, false, false);
+				usb3_connect(usb3);
+			}
+		} else
+			usb3_connect(usb3);
+	} else {
+		usb3->extcon_usb = !!(usb3_read(usb3, USB3_USB_STA) &
+							USB_STA_VBUS_STA);
+		if (usb3->extcon_usb)
+			usb3_connect(usb3);
+		else
+			usb3_disconnect(usb3);
+
+		schedule_work(&usb3->extcon_work);
+	}
+}
+
 static void renesas_usb3_init_controller(struct renesas_usb3 *usb3)
 {
 	usb3_init_axi_bridge(usb3);
@@ -2343,14 +2355,65 @@  static enum usb_role renesas_usb3_role_switch_get(struct device *dev)
 	return cur_role;
 }
 
-static int renesas_usb3_role_switch_set(struct device *dev,
-					enum usb_role role)
+static void handle_ext_role_switch_states(struct device *dev,
+					    enum usb_role role)
+{
+	struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+	struct device *host = usb3->host_dev;
+	enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
+
+	switch (role) {
+	case USB_ROLE_NONE:
+		usb3->connection_state = USB_ROLE_NONE;
+		if (usb3->driver)
+			usb3_disconnect(usb3);
+		usb3_vbus_out(usb3, false);
+		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)
+				usb3_connect(usb3);
+		} else if (cur_role == USB_ROLE_HOST)  {
+			device_release_driver(host);
+			usb3_set_mode(usb3, false);
+			if (usb3->driver)
+				usb3_connect(usb3);
+		}
+		usb3_vbus_out(usb3, false);
+		break;
+	case USB_ROLE_HOST:
+		if (usb3->connection_state == USB_ROLE_NONE) {
+			if (usb3->driver)
+				usb3_disconnect(usb3);
+
+			usb3->connection_state = USB_ROLE_HOST;
+			usb3_set_mode(usb3, true);
+			usb3_vbus_out(usb3, true);
+			if (device_attach(host) < 0)
+				dev_err(dev, "device_attach(host) failed\n");
+		} else if (cur_role == USB_ROLE_DEVICE) {
+			usb3_disconnect(usb3);
+			/* Must set the mode before device_attach of the host */
+			usb3_set_mode(usb3, true);
+			/* This device_attach() might sleep */
+			if (device_attach(host) < 0)
+				dev_err(dev, "device_attach(host) failed\n");
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void handle_role_switch_states(struct device *dev,
+					    enum usb_role role)
 {
 	struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
 	struct device *host = usb3->host_dev;
 	enum usb_role cur_role = renesas_usb3_role_switch_get(dev);
 
-	pm_runtime_get_sync(dev);
 	if (cur_role == USB_ROLE_HOST && role == USB_ROLE_DEVICE) {
 		device_release_driver(host);
 		usb3_set_mode(usb3, false);
@@ -2361,6 +2424,20 @@  static int renesas_usb3_role_switch_set(struct device *dev,
 		if (device_attach(host) < 0)
 			dev_err(dev, "device_attach(host) failed\n");
 	}
+}
+
+static int renesas_usb3_role_switch_set(struct device *dev,
+					enum usb_role role)
+{
+	struct renesas_usb3 *usb3 = dev_get_drvdata(dev);
+
+	pm_runtime_get_sync(dev);
+
+	if (usb3->usb_role_switch_property)
+		handle_ext_role_switch_states(dev, role);
+	else
+		handle_role_switch_states(dev, role);
+
 	pm_runtime_put(dev);
 
 	return 0;
@@ -2650,7 +2727,7 @@  static const unsigned int renesas_usb3_cable[] = {
 	EXTCON_NONE,
 };
 
-static const struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
+static struct usb_role_switch_desc renesas_usb3_role_switch_desc = {
 	.set = renesas_usb3_role_switch_set,
 	.get = renesas_usb3_role_switch_get,
 	.allow_userspace_control = true,
@@ -2741,6 +2818,11 @@  static int renesas_usb3_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto err_dev_create;
 
+	if (device_property_read_bool(&pdev->dev, "renesas,usb-role-switch")) {
+		usb3->usb_role_switch_property = true;
+		renesas_usb3_role_switch_desc.fwnode = dev_fwnode(&pdev->dev);
+	}
+
 	INIT_WORK(&usb3->role_work, renesas_usb3_role_work);
 	usb3->role_sw = usb_role_switch_register(&pdev->dev,
 					&renesas_usb3_role_switch_desc);