usb: dwc3: core: add pm runtime for drd mode

In kernel 4.4, we use the extcon notification function in dwc3-rockchip.c
to perform the drd mode switch. Kernel 4.19 implements the same
functionality in drd.c and writes the extcon notification function in
core.c. We use the upstream code implementation process and add runtime
suspend and resume.

Change-Id: I934559f77d2d6b0d3e7a7c09b829d679e7b3dc27
Signed-off-by: Jianing Ren <jianing.ren@rock-chips.com>
This commit is contained in:
Jianing Ren
2019-11-01 17:44:29 +08:00
parent 0041c9c328
commit bb4c791a42
2 changed files with 97 additions and 2 deletions

View File

@@ -127,6 +127,9 @@ static void __dwc3_set_mode(struct work_struct *work)
if (!dwc->desired_dr_role)
return;
if (dwc->en_runtime)
goto runtime;
if (dwc->desired_dr_role == dwc->current_dr_role)
return;
@@ -191,6 +194,78 @@ static void __dwc3_set_mode(struct work_struct *work)
break;
}
return;
runtime:
if (extcon_get_state(dwc->edev, EXTCON_USB) ||
extcon_get_state(dwc->edev, EXTCON_USB_HOST)) {
if (dwc->drd_connected)
return;
dwc->current_dr_role = dwc->desired_dr_role;
pm_runtime_get_sync(dwc->dev);
/*
* We should set drd_connected true after runtime_resume to
* enable reset deassert.
*/
dwc->drd_connected = true;
spin_lock_irqsave(&dwc->lock, flags);
dwc3_set_prtcap(dwc, dwc->desired_dr_role);
spin_unlock_irqrestore(&dwc->lock, flags);
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
ret = dwc3_host_init(dwc);
if (ret) {
dev_err(dwc->dev,
"failed to initialize host\n");
} else {
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, true);
phy_set_mode(dwc->usb2_generic_phy,
PHY_MODE_USB_HOST);
phy_set_mode(dwc->usb3_generic_phy,
PHY_MODE_USB_HOST);
phy_calibrate(dwc->usb2_generic_phy);
}
break;
case DWC3_GCTL_PRTCAP_DEVICE:
if (dwc->usb2_phy)
otg_set_vbus(dwc->usb2_phy->otg, false);
phy_set_mode(dwc->usb2_generic_phy,
PHY_MODE_USB_DEVICE);
phy_set_mode(dwc->usb3_generic_phy,
PHY_MODE_USB_DEVICE);
break;
case DWC3_GCTL_PRTCAP_OTG:
break;
default:
break;
}
} else {
switch (dwc->current_dr_role) {
case DWC3_GCTL_PRTCAP_HOST:
dwc3_host_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_DEVICE:
break;
case DWC3_GCTL_PRTCAP_OTG:
break;
default:
dwc->current_dr_role = dwc->desired_dr_role;
return;
}
/*
* We should set drd_connected true before runtime_suspend to
* enable reset assert.
*/
dwc->drd_connected = false;
pm_runtime_put_sync_suspend(dwc->dev);
}
}
void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
@@ -1170,6 +1245,14 @@ static int dwc3_core_init_mode(struct dwc3 *dwc)
break;
case USB_DR_MODE_OTG:
INIT_WORK(&dwc->drd_work, __dwc3_set_mode);
if (dwc->en_runtime) {
ret = dwc3_gadget_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
dev_err(dev, "failed to initialize gadget\n");
return ret;
}
}
ret = dwc3_drd_init(dwc);
if (ret) {
if (ret != -EPROBE_DEFER)
@@ -1496,6 +1579,12 @@ static int dwc3_probe(struct platform_device *pdev)
if (ret)
goto err3;
if (dwc->dr_mode == USB_DR_MODE_OTG &&
of_machine_is_compatible("rockchip,rk3399")) {
pm_runtime_allow(dev);
dwc->en_runtime = true;
}
ret = dwc3_alloc_scratch_buffers(dwc);
if (ret)
goto err3;
@@ -1616,7 +1705,7 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
dwc3_core_exit(dwc);
break;
case DWC3_GCTL_PRTCAP_HOST:
if (!PMSG_IS_AUTO(msg)) {
if (!PMSG_IS_AUTO(msg) || dwc->en_runtime) {
dwc3_core_exit(dwc);
break;
}
@@ -1677,7 +1766,7 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
spin_unlock_irqrestore(&dwc->lock, flags);
break;
case DWC3_GCTL_PRTCAP_HOST:
if (!PMSG_IS_AUTO(msg)) {
if (!PMSG_IS_AUTO(msg) || dwc->en_runtime) {
ret = dwc3_core_init_for_resume(dwc);
if (ret)
return ret;

View File

@@ -1038,6 +1038,10 @@ struct dwc3_scratchpad_array {
* 3 - Reserved
* @dis_metastability_quirk: set to disable metastability quirk.
* @needs_fifo_resize: set if we want to resize TXFIFO.
* @drd_connected: true when usb connected to a host or a device(drd mode),
* false otherwise.
* @en_runtime: true when need runtime PM management. For example, RK3399 need
* reset dwc3 and usb3phy to support typec interface.
* @imod_interval: set the interrupt moderation interval in 250ns
* increments or 0 to disable.
*/
@@ -1228,6 +1232,8 @@ struct dwc3 {
unsigned dis_metastability_quirk:1;
unsigned needs_fifo_resize:1;
unsigned drd_connected:1;
unsigned en_runtime:1;
u16 imod_interval;
};