Hi Sandeep, On Thu, Jul 09, 2020 at 12:40:15AM +0530, Sandeep Maheswaram wrote: > Avoiding phy powerdown in host mode so that it can be wake up by devices. > Added need_phy_for_wakeup flag to distinugush resume path and hs_phy_flags > to check connection status and set phy mode and configure interrupts. > > Signed-off-by: Sandeep Maheswaram <sanm@xxxxxxxxxxxxxx> > --- > drivers/usb/dwc3/core.c | 47 ++++++++++++++++++++++++++++++++++++++++------- > drivers/usb/dwc3/core.h | 2 ++ > 2 files changed, 42 insertions(+), 7 deletions(-) > > diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c > index 25c686a7..eb7c225 100644 > --- a/drivers/usb/dwc3/core.c > +++ b/drivers/usb/dwc3/core.c > @@ -31,12 +31,14 @@ > #include <linux/usb/gadget.h> > #include <linux/usb/of.h> > #include <linux/usb/otg.h> > +#include <linux/usb/hcd.h> > > #include "core.h" > #include "gadget.h" > #include "io.h" > > #include "debug.h" > +#include "../host/xhci.h" > > #define DWC3_DEFAULT_AUTOSUSPEND_DELAY 5000 /* ms */ > > @@ -1627,10 +1629,36 @@ static int dwc3_core_init_for_resume(struct dwc3 *dwc) > return ret; > } > > +static void dwc3_set_phy_speed_flags(struct dwc3 *dwc) > +{ > + > + int i, num_ports; > + u32 reg; > + struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci); > + struct xhci_hcd *xhci_hcd = hcd_to_xhci(hcd); > + > + dwc->hs_phy_flags &= ~(PHY_MODE_USB_HOST_HS | PHY_MODE_USB_HOST_LS); Where is hs_phy_flags initialized? As far as I can tell it isn't, hence when dwc3_set_phy_speed_flags() is executed the first time it is 0 (from devm_kzalloc()), and after the '&=' it is still 0. The next time it will have whatever value it was set to in the below loop, which is then cleared by the '&='. It seems you could as well just write 'dwc->hs_phy_flags = 0', which is clearer, unless the field is used in some other way that isn't obvious to me. > + > + reg = readl(&xhci_hcd->cap_regs->hcs_params1); > + > + num_ports = HCS_MAX_PORTS(reg); > + for (i = 0; i < num_ports; i++) { > + reg = readl(&xhci_hcd->op_regs->port_status_base + i * 0x04); > + if (reg & PORT_PE) { > + if (DEV_HIGHSPEED(reg) || DEV_FULLSPEED(reg)) > + dwc->hs_phy_flags |= PHY_MODE_USB_HOST_HS; > + else if (DEV_LOWSPEED(reg)) > + dwc->hs_phy_flags |= PHY_MODE_USB_HOST_LS; Is another entry for DEV_SUPERSPEED needed? > + } > + } > + phy_set_mode(dwc->usb2_generic_phy, dwc->hs_phy_flags); > +} > + > static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) > { > unsigned long flags; > u32 reg; > + struct usb_hcd *hcd = platform_get_drvdata(dwc->xhci); > > switch (dwc->current_dr_role) { > case DWC3_GCTL_PRTCAP_DEVICE: > @@ -1643,9 +1671,12 @@ static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg) > dwc3_core_exit(dwc); > break; > case DWC3_GCTL_PRTCAP_HOST: > + dwc3_set_phy_speed_flags(dwc); > if (!PMSG_IS_AUTO(msg)) { > - dwc3_core_exit(dwc); > - break; > + if (usb_wakeup_enabled_descendants(hcd->self.root_hub)) > + dwc->need_phy_for_wakeup = true; > + else > + dwc->need_phy_for_wakeup = false; > } > > /* Let controller to suspend HSPHY before PHY driver suspends */ > @@ -1705,11 +1736,13 @@ static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg) > break; > case DWC3_GCTL_PRTCAP_HOST: > if (!PMSG_IS_AUTO(msg)) { > - ret = dwc3_core_init_for_resume(dwc); > - if (ret) > - return ret; > - dwc3_set_prtcap(dwc, DWC3_GCTL_PRTCAP_HOST); > - break; > + if (!dwc->need_phy_for_wakeup) { > + ret = dwc3_core_init_for_resume(dwc); Before this patch we had the combo dwc3_core_exit() / dwc3_core_init_for_resume(), now it is only dwc3_core_init_for_resume() for !dwc->need_phy_for_wakeup. Doesn't this cause trouble with enable counts, e.g. with clk_bulk_prepare_enable() being called in dwc3_core_init_for_resume(), without the corresponding clk_bulk_disable_unprepare() calls in dwc3_core_exit()?