aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3/core.c
diff options
context:
space:
mode:
authorRoger Quadros <rogerq@ti.com>2017-04-05 13:39:31 +0300
committerFelipe Balbi <felipe.balbi@linux.intel.com>2017-04-11 10:58:31 +0300
commit9840354ff429d4a392a96dff5ab6b5df609b8dc1 (patch)
tree27cfaad3e008de499e821bf9ddf0d824345b06c0 /drivers/usb/dwc3/core.c
parentusb: dwc3: core: make dwc3_set_mode() work properly (diff)
downloadlinux-dev-9840354ff429d4a392a96dff5ab6b5df609b8dc1.tar.xz
linux-dev-9840354ff429d4a392a96dff5ab6b5df609b8dc1.zip
usb: dwc3: Add dual-role support
If dr_mode is "otg" then support dual role mode of operation. Currently this mode is only supported when an extcon handle is present in the dwc3 device tree node. This is needed to get the ID status events of the port. We're using a workqueue to manage the dual-role state transitions as the extcon notifier (dwc3_drd_notifier) is called in an atomic context by extcon_sync() and this doesn't go well with usb_del_gadget_udc() causing a lockdep and softirq warning. Signed-off-by: Roger Quadros <rogerq@ti.com> Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/dwc3/core.c')
-rw-r--r--drivers/usb/dwc3/core.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 458e7c6cc002..455d89a1cd6d 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -921,7 +921,12 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
break;
case USB_DR_MODE_OTG:
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
+ ret = dwc3_drd_init(dwc);
+ if (ret) {
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "failed to initialize dual-role\n");
+ return ret;
+ }
break;
default:
dev_err(dev, "Unsupported mode of operation %d\n", dwc->dr_mode);
@@ -941,9 +946,7 @@ static void dwc3_core_exit_mode(struct dwc3 *dwc)
dwc3_host_exit(dwc);
break;
case USB_DR_MODE_OTG:
- dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
- dwc3_gadget_exit(dwc);
- flush_work(&dwc->drd_work);
+ dwc3_drd_exit(dwc);
break;
default:
/* do nothing */