From 7d34ffa6c3e52b166a495c181fce7b5aa90a2811 Mon Sep 17 00:00:00 2001 From: Manu Gautam Date: Mon, 3 Dec 2018 14:38:23 +0530 Subject: [PATCH] usb: dwc3-msm: Ensure hardware is reset during role change Introduce additional WAIT_FOR_LPM input flag to ensure USB enters low power mode after stop_peripheral or stop_host. This makes sure that USB hardware is reset after LPM for cases where quick transition to host mode happens while its child was still preventing dwc3 to enter low power mode. In the absence of h/w reset after stop_peripheral, host mode doesn't work. Change-Id: I67e4fcdc11a3337e3e90b4ca8f461e328a6e8ecf Signed-off-by: Manu Gautam --- drivers/usb/dwc3/dwc3-msm.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index bd96854ca17b..37adbbff73b3 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -174,6 +174,7 @@ enum plug_orientation { #define ID 0 #define B_SESS_VLD 1 #define B_SUSPEND 2 +#define WAIT_FOR_LPM 3 #define PM_QOS_SAMPLE_SEC 2 #define PM_QOS_THRESHOLD 400 @@ -2214,7 +2215,13 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation) } dev_info(mdwc->dev, "DWC3 in low power mode\n"); + + /* kick_sm if it is waiting for lpm sequence to finish */ + if (test_and_clear_bit(WAIT_FOR_LPM, &mdwc->inputs)) + schedule_delayed_work(&mdwc->sm_work, 0); + mutex_unlock(&mdwc->suspend_resume_mutex); + return 0; } @@ -3724,6 +3731,9 @@ static int dwc3_otg_start_host(struct dwc3_msm *mdwc, int on) if (!mdwc->host_only_mode) dwc3_post_host_reset_core_init(dwc); + /* wait for LPM, to ensure h/w is reset after stop_host */ + set_bit(WAIT_FOR_LPM, &mdwc->inputs); + pm_runtime_mark_last_busy(mdwc->dev); pm_runtime_put_sync_autosuspend(mdwc->dev); dbg_event(0xFF, "StopHost psync", @@ -3804,6 +3814,9 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on) usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER); dwc3_override_vbus_status(mdwc, false); dwc3_usb3_phy_suspend(dwc, false); + + /* wait for LPM, to ensure h/w is reset after stop_peripheral */ + set_bit(WAIT_FOR_LPM, &mdwc->inputs); } pm_runtime_put_sync(mdwc->dev); @@ -3920,6 +3933,11 @@ static void dwc3_otg_sm_work(struct work_struct *w) pm_runtime_enable(mdwc->dev); /* fall-through */ case DRD_STATE_IDLE: + if (test_bit(WAIT_FOR_LPM, &mdwc->inputs)) { + dev_dbg(mdwc->dev, "still not in lpm, wait.\n"); + break; + } + if (!test_bit(ID, &mdwc->inputs)) { dev_dbg(mdwc->dev, "!id\n"); mdwc->drd_state = DRD_STATE_HOST_IDLE;