summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3/drd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3/drd.c')
-rw-r--r--drivers/usb/dwc3/drd.c101
1 files changed, 35 insertions, 66 deletions
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index 2e483448d695..589bbeb27454 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -1,14 +1,14 @@
// SPDX-License-Identifier: GPL-2.0
-/**
+/*
* drd.c - DesignWare USB3 DRD Controller Dual-role support
*
- * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com
+ * Copyright (C) 2017 Texas Instruments Incorporated - https://www.ti.com
*
* Authors: Roger Quadros <rogerq@ti.com>
*/
#include <linux/extcon.h>
-#include <linux/of_graph.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -173,7 +173,7 @@ void dwc3_otg_init(struct dwc3 *dwc)
* block "Initialize GCTL for OTG operation".
*/
/* GCTL.PrtCapDir=2'b11 */
- dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
/* GUSB2PHYCFG0.SusPHY=0 */
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
@@ -331,6 +331,7 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
u32 reg;
int id;
unsigned long flags;
+ int i;
if (dwc->dr_mode != USB_DR_MODE_OTG)
return;
@@ -386,9 +387,12 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
- if (dwc->usb2_generic_phy)
- phy_set_mode(dwc->usb2_generic_phy,
- PHY_MODE_USB_HOST);
+ for (i = 0; i < dwc->num_usb2_ports; i++) {
+ if (dwc->usb2_generic_phy[i]) {
+ phy_set_mode(dwc->usb2_generic_phy[i],
+ PHY_MODE_USB_HOST);
+ }
+ }
}
break;
case DWC3_OTG_ROLE_DEVICE:
@@ -400,9 +404,8 @@ void dwc3_otg_update(struct dwc3 *dwc, bool ignore_idstatus)
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
- if (dwc->usb2_generic_phy)
- phy_set_mode(dwc->usb2_generic_phy,
- PHY_MODE_USB_DEVICE);
+ if (dwc->usb2_generic_phy[0])
+ phy_set_mode(dwc->usb2_generic_phy[0], PHY_MODE_USB_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret)
dev_err(dwc->dev, "failed to initialize peripheral\n");
@@ -438,44 +441,6 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
}
-static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
-{
- struct device *dev = dwc->dev;
- struct device_node *np_phy, *np_conn;
- struct extcon_dev *edev;
- const char *name;
-
- if (device_property_read_bool(dev, "extcon"))
- return extcon_get_edev_by_phandle(dev, 0);
-
- /*
- * Device tree platforms should get extcon via phandle.
- * On ACPI platforms, we get the name from a device property.
- * This device property is for kernel internal use only and
- * is expected to be set by the glue code.
- */
- if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
- edev = extcon_get_extcon_dev(name);
- if (!edev)
- return ERR_PTR(-EPROBE_DEFER);
-
- return edev;
- }
-
- np_phy = of_parse_phandle(dev->of_node, "phys", 0);
- np_conn = of_graph_get_remote_node(np_phy, -1, -1);
-
- if (np_conn)
- edev = extcon_find_edev_by_node(np_conn);
- else
- edev = NULL;
-
- of_node_put(np_conn);
- of_node_put(np_phy);
-
- return edev;
-}
-
#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
#define ROLE_SWITCH 1
static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
@@ -499,6 +464,7 @@ static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
break;
}
+ dwc3_pre_set_role(dwc, role);
dwc3_set_mode(dwc, mode);
return 0;
}
@@ -534,29 +500,38 @@ static enum usb_role dwc3_usb_role_switch_get(struct usb_role_switch *sw)
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;
+ dwc->role_switch_default_mode = usb_get_role_switch_default_mode(dwc->dev);
+ if (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_set_mode(dwc, mode);
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;
dwc3_role_switch.driver_data = dwc;
+ dwc3_role_switch.allow_userspace_control = true;
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, mode);
+ if (dwc->dev->of_node) {
+ /* populate connector entry */
+ int ret = devm_of_platform_populate(dwc->dev);
+
+ if (ret) {
+ usb_role_switch_unregister(dwc->role_sw);
+ dwc->role_sw = NULL;
+ dev_err(dwc->dev, "DWC3 platform devices creation failed: %i\n", ret);
+ return ret;
+ }
+ }
+
return 0;
}
#else
@@ -568,16 +543,11 @@ int dwc3_drd_init(struct dwc3 *dwc)
{
int ret, irq;
- dwc->edev = dwc3_get_extcon(dwc);
- if (IS_ERR(dwc->edev))
- return PTR_ERR(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) {
+ device_property_read_bool(dwc->dev, "usb-role-switch"))
+ return dwc3_setup_role_switch(dwc);
+
+ if (dwc->edev) {
dwc->edev_nb.notifier_call = dwc3_drd_notifier;
ret = extcon_register_notifier(dwc->edev, EXTCON_USB_HOST,
&dwc->edev_nb);
@@ -588,8 +558,7 @@ int dwc3_drd_init(struct dwc3 *dwc)
dwc3_drd_update(dwc);
} else {
- dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG);
- dwc->current_dr_role = DWC3_GCTL_PRTCAP_OTG;
+ dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_OTG, true);
/* use OTG block to get ID event */
irq = dwc3_otg_get_irq(dwc);