From 8a0a137997448690a642e2325fe73242788b26fe Mon Sep 17 00:00:00 2001 From: Yu Chen Date: Tue, 25 Feb 2020 17:52:59 +0000 Subject: usb: dwc3: Registering a role switch in the DRD code. The Type-C drivers use USB role switch API to inform the system about the negotiated data role, so registering a role switch in the DRD code in order to support platforms with USB Type-C connectors. Cc: Greg Kroah-Hartman Cc: Rob Herring Cc: Mark Rutland CC: ShuFan Lee Cc: Heikki Krogerus Cc: Suzuki K Poulose Cc: Chunfeng Yun Cc: Yu Chen Cc: Felipe Balbi Cc: Hans de Goede Cc: Andy Shevchenko Cc: Jun Li Cc: Valentin Schneider Cc: Guillaume Gardet Cc: Jack Pham Cc: Bryan O'Donoghue Cc: linux-usb@vger.kernel.org Cc: devicetree@vger.kernel.org Suggested-by: Heikki Krogerus Tested-by: Bryan O'Donoghue Signed-off-by: Yu Chen Signed-off-by: John Stultz Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/drd.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-) (limited to 'drivers/usb/dwc3/drd.c') diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index c946d64142ad..331c6e997f0c 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -476,6 +476,73 @@ static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc) return edev; } +#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH) +#define ROLE_SWITCH 1 +static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role) +{ + struct dwc3 *dwc = dev_get_drvdata(dev); + 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: + mode = DWC3_GCTL_PRTCAP_DEVICE; + break; + } + + dwc3_set_mode(dwc, 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); + switch (dwc->current_dr_role) { + case DWC3_GCTL_PRTCAP_HOST: + role = USB_ROLE_HOST; + break; + case DWC3_GCTL_PRTCAP_DEVICE: + role = USB_ROLE_DEVICE; + break; + case DWC3_GCTL_PRTCAP_OTG: + role = dwc->current_otg_role; + break; + default: + role = USB_ROLE_DEVICE; + break; + } + spin_unlock_irqrestore(&dwc->lock, flags); + return role; +} + +static int dwc3_setup_role_switch(struct dwc3 *dwc) +{ + struct usb_role_switch_desc dwc3_role_switch = {NULL}; + + dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); + dwc3_role_switch.set = dwc3_usb_role_switch_set; + dwc3_role_switch.get = dwc3_usb_role_switch_get; + dwc->role_sw = usb_role_switch_register(dwc->dev, &dwc3_role_switch); + if (IS_ERR(dwc->role_sw)) + return PTR_ERR(dwc->role_sw); + + dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + return 0; +} +#else +#define ROLE_SWITCH 0 +#define dwc3_setup_role_switch(x) 0 +#endif + int dwc3_drd_init(struct dwc3 *dwc) { int ret, irq; @@ -484,7 +551,12 @@ int dwc3_drd_init(struct dwc3 *dwc) if (IS_ERR(dwc->edev)) return PTR_ERR(dwc->edev); - if (dwc->edev) { + if (ROLE_SWITCH && + device_property_read_bool(dwc->dev, "usb-role-switch")) { + ret = dwc3_setup_role_switch(dwc); + if (ret < 0) + return ret; + } 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 +603,9 @@ void dwc3_drd_exit(struct dwc3 *dwc) { unsigned long flags; + if (dwc->role_sw) + usb_role_switch_unregister(dwc->role_sw); + if (dwc->edev) extcon_unregister_notifier(dwc->edev, EXTCON_USB_HOST, &dwc->edev_nb); -- cgit v1.2.3 From 98ed256a4dbad8f20226a4f414c1a60a4a558aec Mon Sep 17 00:00:00 2001 From: John Stultz Date: Tue, 25 Feb 2020 17:53:01 +0000 Subject: usb: dwc3: Add support for role-switch-default-mode binding Support the new role-switch-default-mode binding for configuring the default role the controller assumes as when the usb role is USB_ROLE_NONE This patch was split out from a larger patch originally by Yu Chen Cc: Greg Kroah-Hartman Cc: Rob Herring Cc: Mark Rutland CC: ShuFan Lee Cc: Heikki Krogerus Cc: Suzuki K Poulose Cc: Chunfeng Yun Cc: Yu Chen Cc: Felipe Balbi Cc: Hans de Goede Cc: Andy Shevchenko Cc: Jun Li Cc: Valentin Schneider Cc: Guillaume Gardet Cc: Bryan O'Donoghue Cc: Jack Pham Cc: linux-usb@vger.kernel.org Cc: devicetree@vger.kernel.org Tested-by: Bryan O'Donoghue Signed-off-by: John Stultz Signed-off-by: Felipe Balbi --- drivers/usb/dwc3/drd.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'drivers/usb/dwc3/drd.c') diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c index 331c6e997f0c..db68d48c2267 100644 --- a/drivers/usb/dwc3/drd.c +++ b/drivers/usb/dwc3/drd.c @@ -491,7 +491,10 @@ static int dwc3_usb_role_switch_set(struct device *dev, enum usb_role role) mode = DWC3_GCTL_PRTCAP_DEVICE; break; default: - mode = DWC3_GCTL_PRTCAP_DEVICE; + if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) + mode = DWC3_GCTL_PRTCAP_HOST; + else + mode = DWC3_GCTL_PRTCAP_DEVICE; break; } @@ -517,7 +520,10 @@ static enum usb_role dwc3_usb_role_switch_get(struct device *dev) role = dwc->current_otg_role; break; default: - role = USB_ROLE_DEVICE; + if (dwc->role_switch_default_mode == USB_DR_MODE_HOST) + role = USB_ROLE_HOST; + else + role = USB_ROLE_DEVICE; break; } spin_unlock_irqrestore(&dwc->lock, flags); @@ -527,6 +533,19 @@ static enum usb_role dwc3_usb_role_switch_get(struct device *dev) static int dwc3_setup_role_switch(struct dwc3 *dwc) { struct usb_role_switch_desc dwc3_role_switch = {NULL}; + const char *str; + u32 mode; + int ret; + + ret = device_property_read_string(dwc->dev, "role-switch-default-mode", + &str); + if (ret >= 0 && !strncmp(str, "host", strlen("host"))) { + dwc->role_switch_default_mode = USB_DR_MODE_HOST; + mode = DWC3_GCTL_PRTCAP_HOST; + } else { + dwc->role_switch_default_mode = USB_DR_MODE_PERIPHERAL; + mode = DWC3_GCTL_PRTCAP_DEVICE; + } dwc3_role_switch.fwnode = dev_fwnode(dwc->dev); dwc3_role_switch.set = dwc3_usb_role_switch_set; @@ -535,7 +554,7 @@ static int dwc3_setup_role_switch(struct dwc3 *dwc) if (IS_ERR(dwc->role_sw)) return PTR_ERR(dwc->role_sw); - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + dwc3_set_mode(dwc, mode); return 0; } #else -- cgit v1.2.3