2020-04-10 02:47:05 +00:00
|
|
|
From 8595748e58885439c7e18a11a94702378bff3b02 Mon Sep 17 00:00:00 2001
|
|
|
|
From: Li Jun <jun.li@nxp.com>
|
|
|
|
Date: Sun, 27 Jan 2019 19:40:03 +0800
|
|
|
|
Subject: [PATCH] usb: dwc3: drd: add usb role switch class support for dual
|
|
|
|
role swap
|
|
|
|
|
|
|
|
Register a usb_role_switch for dual role swap if the property
|
|
|
|
"usb-role-switch" is present.
|
|
|
|
|
|
|
|
Signed-off-by: Li Jun <jun.li@nxp.com>
|
|
|
|
---
|
|
|
|
drivers/usb/dwc3/core.h | 2 ++
|
|
|
|
drivers/usb/dwc3/drd.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
|
|
|
|
2 files changed, 48 insertions(+), 1 deletion(-)
|
|
|
|
|
|
|
|
--- a/drivers/usb/dwc3/core.h
|
|
|
|
+++ b/drivers/usb/dwc3/core.h
|
|
|
|
@@ -25,6 +25,7 @@
|
|
|
|
#include <linux/usb/ch9.h>
|
|
|
|
#include <linux/usb/gadget.h>
|
|
|
|
#include <linux/usb/otg.h>
|
|
|
|
+#include <linux/usb/role.h>
|
|
|
|
#include <linux/ulpi/interface.h>
|
|
|
|
|
|
|
|
#include <linux/phy/phy.h>
|
2021-01-09 14:10:40 +00:00
|
|
|
@@ -1096,6 +1097,7 @@ struct dwc3 {
|
2020-04-10 02:47:05 +00:00
|
|
|
void __iomem *regs;
|
|
|
|
size_t regs_size;
|
|
|
|
|
|
|
|
+ struct usb_role_switch *role_switch;
|
|
|
|
enum usb_dr_mode dr_mode;
|
|
|
|
u32 current_dr_role;
|
|
|
|
u32 desired_dr_role;
|
|
|
|
--- a/drivers/usb/dwc3/drd.c
|
|
|
|
+++ b/drivers/usb/dwc3/drd.c
|
|
|
|
@@ -476,6 +476,43 @@ static struct extcon_dev *dwc3_get_extco
|
|
|
|
return edev;
|
|
|
|
}
|
|
|
|
|
|
|
|
+static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role)
|
|
|
|
+{
|
|
|
|
+ u32 mode;
|
|
|
|
+
|
|
|
|
+ switch (role) {
|
|
|
|
+ case USB_ROLE_HOST:
|
|
|
|
+ mode = DWC3_GCTL_PRTCAP_HOST;
|
|
|
|
+ break;
|
|
|
|
+ case USB_ROLE_DEVICE:
|
|
|
|
+ mode = DWC3_GCTL_PRTCAP_DEVICE;
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return 0;
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ dwc3_set_mode(dev_get_drvdata(dev), mode);
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static enum usb_role dwc3_usb_role_switch_get(struct device *dev)
|
|
|
|
+{
|
|
|
|
+ struct dwc3 *dwc = dev_get_drvdata(dev);
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ enum usb_role role;
|
|
|
|
+
|
|
|
|
+ spin_lock_irqsave(&dwc->lock, flags);
|
|
|
|
+ role = dwc->current_dr_role;
|
|
|
|
+ spin_unlock_irqrestore(&dwc->lock, flags);
|
|
|
|
+
|
|
|
|
+ return role;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct usb_role_switch_desc dwc3_role_switch = {
|
|
|
|
+ .set = dwc3_usb_role_switch_set,
|
|
|
|
+ .get = dwc3_usb_role_switch_get,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
int dwc3_drd_init(struct dwc3 *dwc)
|
|
|
|
{
|
|
|
|
int ret, irq;
|
|
|
|
@@ -484,7 +521,12 @@ int dwc3_drd_init(struct dwc3 *dwc)
|
|
|
|
if (IS_ERR(dwc->edev))
|
|
|
|
return PTR_ERR(dwc->edev);
|
|
|
|
|
|
|
|
- if (dwc->edev) {
|
|
|
|
+ if (device_property_read_bool(dwc->dev, "usb-role-switch")) {
|
|
|
|
+ dwc->role_switch = usb_role_switch_register(dwc->dev,
|
|
|
|
+ &dwc3_role_switch);
|
|
|
|
+ if (IS_ERR(dwc->role_switch))
|
|
|
|
+ return PTR_ERR(dwc->role_switch);
|
|
|
|
+ } else if (dwc->edev) {
|
|
|
|
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
|
|
|
|
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
|
|
|
|
&dwc->edev_nb);
|
|
|
|
@@ -531,6 +573,9 @@ void dwc3_drd_exit(struct dwc3 *dwc)
|
|
|
|
{
|
|
|
|
unsigned long flags;
|
|
|
|
|
|
|
|
+ if (dwc->role_switch)
|
|
|
|
+ usb_role_switch_unregister(dwc->role_switch);
|
|
|
|
+
|
|
|
|
if (dwc->edev)
|
|
|
|
extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST,
|
|
|
|
&dwc->edev_nb);
|