From 7e7b7790b1d2aa13a17de153173ac0faf99aa62b Mon Sep 17 00:00:00 2001 From: Mayank Rana Date: Wed, 27 May 2020 16:03:54 -0700 Subject: [PATCH] dwc3-msm: Force USB speed as high speed if SS release lane is called DP driver shall call SS release lane API asynchronously when USB is into device mode or host mode or not yet started. This is possible as ADSP firmware notification over UCSI may be delayed and can be running in parallel with altmode functionality. Hence force maximum speed as USB high speed if SS release lane API is called until next USB able disconnect. Change-Id: Iaae8b4e39ec8695e0204b83d9292cd3efa4af310 Signed-off-by: Mayank Rana --- drivers/usb/dwc3/dwc3-msm.c | 64 +++++++++++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index 8fff934f5ffc..03cc12943df9 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -481,6 +481,7 @@ struct dwc3_msm { dma_addr_t dummy_gsi_db_dma; struct usb_role_switch *role_switch; + bool ss_release_called; }; #define USB_HSPHY_3P3_VOL_MIN 3050000 /* uV */ @@ -3702,6 +3703,15 @@ static int dwc3_msm_usb_set_role(struct device *dev, enum usb_role role) return 0; } + if (mdwc->ss_release_called) { + flush_delayed_work(&mdwc->sm_work); + dwc->maximum_speed = USB_SPEED_HIGH; + if (role == USB_ROLE_NONE) { + dwc->maximum_speed = USB_SPEED_UNKNOWN; + mdwc->ss_release_called = false; + } + } + dwc3_ext_event_notify(mdwc); return 0; } @@ -3926,6 +3936,30 @@ static void dwc3_start_stop_host(struct dwc3_msm *mdwc, bool start) dbg_log_string("stop_host_mode completed"); } +static void dwc3_start_stop_device(struct dwc3_msm *mdwc, bool start) +{ + struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3); + + if (start) { + dbg_log_string("start device mode"); + mdwc->id_state = DWC3_ID_FLOAT; + mdwc->vbus_active = true; + } else { + dbg_log_string("stop device mode"); + mdwc->id_state = DWC3_ID_FLOAT; + mdwc->vbus_active = false; + } + + dwc3_ext_event_notify(mdwc); + dbg_event(0xFF, "flush_work", 0); + flush_work(&mdwc->resume_work); + drain_workqueue(mdwc->sm_usb_wq); + if (start) + dbg_log_string("device mode restarted"); + else + dbg_log_string("stop_device_mode completed"); +} + int dwc3_msm_release_ss_lane(struct device *dev) { struct dwc3_msm *mdwc = dev_get_drvdata(dev); @@ -3943,18 +3977,28 @@ int dwc3_msm_release_ss_lane(struct device *dev) } dbg_event(0xFF, "ss_lane_release", 0); - if (mdwc->id_state != DWC3_ID_GROUND) { - dbg_log_string("USB host mode is not active"); - return 0; + /* flush any pending work */ + flush_work(&mdwc->resume_work); + drain_workqueue(mdwc->sm_usb_wq); + + mdwc->ss_release_called = true; + if (mdwc->id_state == DWC3_ID_GROUND) { + /* stop USB host mode */ + dwc3_start_stop_host(mdwc, false); + /* restart USB host mode into high speed */ + dwc->maximum_speed = USB_SPEED_HIGH; + dwc3_start_stop_host(mdwc, true); + } else if (mdwc->vbus_active) { + /* stop USB device mode */ + dwc3_start_stop_device(mdwc, false); + /* restart USB device mode into high speed */ + dwc->maximum_speed = USB_SPEED_HIGH; + dwc3_start_stop_device(mdwc, true); + } else { + dbg_log_string("USB is not active.\n"); + dwc->maximum_speed = USB_SPEED_HIGH; } - /* stop USB host mode */ - dwc3_start_stop_host(mdwc, false); - - /* restart USB host mode into high speed */ - dwc->maximum_speed = USB_SPEED_HIGH; - dwc3_start_stop_host(mdwc, true); - return 0; } EXPORT_SYMBOL(dwc3_msm_release_ss_lane);