dwc3-msm: Allow USB LPM with data role swap from dfp to ufp

Current code checks IN_P3 status (i.e. USB is into U3 or not) with
dwc3_prepare_suspend() API using in_host_mode or vbus_active flag.
With data role swap transition (e.g. dfp -> ufp case), in_host_mode
flag sets to false and vbus_active flag sets to true due to quick
calling of stop host and start peripheral mode from policy engine.
This results into USB doesn't go into LPM with stop host mode (i.e.
USB LPM is aborted due to vbus_active flag seen as true) which
results into no USB enumeration in start peripheral mode. Current
code doesn't perform block reset while stopping USB host mode
functionality. Hence to invoke USB core and PHYs related reset and
init functionality allow USB LPM by replacing vbus_active check with
in_device_mode flag which provides status of USB controller's data
role while going into USB LPM. Start peripheral mode brings USB
out of LPM which performs POR functionality.

Change-Id: I2bbb804bce5f910826ba30a3dda4317bbdb2e1f1
Signed-off-by: Mayank Rana <mrana@codeaurora.org>
Signed-off-by: Ajay Agarwal <ajaya@codeaurora.org>
This commit is contained in:
Mayank Rana 2017-12-13 17:27:23 -08:00 committed by Ajay Agarwal
parent 58a9174f20
commit 21caf80630

View file

@ -202,6 +202,7 @@ struct dwc3_msm {
struct power_supply *usb_psy;
struct work_struct vbus_draw_work;
bool in_host_mode;
bool in_device_mode;
enum usb_device_speed max_rh_port_speed;
unsigned int tx_fifo_size;
bool vbus_active;
@ -1934,7 +1935,7 @@ static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc)
unsigned long timeout;
u32 reg = 0;
if ((mdwc->in_host_mode || mdwc->vbus_active)
if ((mdwc->in_host_mode || mdwc->in_device_mode)
&& dwc3_msm_is_superspeed(mdwc) && !mdwc->in_restart) {
if (!atomic_read(&mdwc->in_p3)) {
dev_err(mdwc->dev, "Not in P3,aborting LPM sequence\n");
@ -2017,8 +2018,6 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation)
int ret, i;
struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm));
mutex_lock(&mdwc->suspend_resume_mutex);
if (atomic_read(&dwc->in_lpm)) {
dev_dbg(mdwc->dev, "%s: Already suspended\n", __func__);
@ -2134,8 +2133,8 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation)
clk_disable_unprepare(mdwc->xo_clk);
/* Perform controller power collapse */
if ((!mdwc->in_host_mode && (!mdwc->vbus_active || mdwc->in_restart)) ||
hibernation) {
if ((!mdwc->in_host_mode && (!mdwc->in_device_mode || mdwc->in_restart))
|| hibernation) {
mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE;
dev_dbg(mdwc->dev, "%s: power collapse\n", __func__);
dwc3_msm_config_gdsc(mdwc, 0);
@ -2168,7 +2167,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation)
* using HS_PHY_IRQ or SS_PHY_IRQ. Hence enable wakeup only in
* case of host bus suspend and device bus suspend.
*/
if (mdwc->vbus_active || mdwc->in_host_mode) {
if (mdwc->in_device_mode || mdwc->in_host_mode) {
if (!mdwc->no_wakeup_src_in_hostmode)
enable_irq_wake(mdwc->hs_phy_irq);
enable_irq(mdwc->hs_phy_irq);
@ -2181,6 +2180,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc, bool hibernation)
}
dev_info(mdwc->dev, "DWC3 in low power mode\n");
dbg_event(0xFF, "Ctl Sus", atomic_read(&dwc->in_lpm));
mutex_unlock(&mdwc->suspend_resume_mutex);
return 0;
}
@ -3725,6 +3725,7 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
dwc3_msm_block_reset(mdwc, false);
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
mdwc->in_device_mode = true;
usb_gadget_vbus_connect(&dwc->gadget);
#ifdef CONFIG_SMP
mdwc->pm_qos_req_dma.type = PM_QOS_REQ_AFFINE_IRQ;
@ -3743,6 +3744,7 @@ static int dwc3_otg_start_peripheral(struct dwc3_msm *mdwc, int on)
msm_dwc3_perf_vote_update(mdwc, false);
pm_qos_remove_request(&mdwc->pm_qos_req_dma);
mdwc->in_device_mode = false;
usb_gadget_vbus_disconnect(&dwc->gadget);
usb_phy_notify_disconnect(mdwc->hs_phy, USB_SPEED_HIGH);
usb_phy_notify_disconnect(mdwc->ss_phy, USB_SPEED_SUPER);