static int ci_ehci_bus_suspend(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int port; u32 tmp; int ret = orig_bus_suspend(hcd); if (ret) return ret; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status[port]; u32 portsc = ehci_readl(ehci, reg); if (portsc & PORT_CONNECT) { /* * For chipidea, the resume signal will be ended * automatically, so for remote wakeup case, the * usbcmd.rs may not be set before the resume has * ended if other resume paths consumes too much * time (~24ms), in that case, the SOF will not * send out within 3ms after resume ends, then the * high speed device will enter full speed mode. */ tmp = ehci_readl(ehci, &ehci->regs->command); tmp |= CMD_RUN; ehci_writel(ehci, tmp, &ehci->regs->command); /* * It needs a short delay between set RS bit and PHCD. */ usleep_range(150, 200); break; } } return 0; }
static int ci_ehci_bus_suspend(struct usb_hcd *hcd) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); int port; u32 tmp; struct device *dev = hcd->self.controller; struct ci_hdrc *ci = dev_get_drvdata(dev); int ret = orig_bus_suspend(hcd); if (ret) return ret; port = HCS_N_PORTS(ehci->hcs_params); while (port--) { u32 __iomem *reg = &ehci->regs->port_status[port]; u32 portsc = ehci_readl(ehci, reg); if (portsc & PORT_CONNECT) { /* * For chipidea, the resume signal will be ended * automatically, so for remote wakeup case, the * usbcmd.rs may not be set before the resume has * ended if other resume paths consumes too much * time (~24ms), in that case, the SOF will not * send out within 3ms after resume ends, then the * high speed device will enter full speed mode. */ tmp = ehci_readl(ehci, &ehci->regs->command); tmp |= CMD_RUN; ehci_writel(ehci, tmp, &ehci->regs->command); /* * It needs a short delay between set RS bit and PHCD. */ usleep_range(150, 200); /* * If a transaction is in progress, there may be a delay in * suspending the port. Poll until the port is suspended. */ if (ehci_handshake(ehci, reg, PORT_SUSPEND, PORT_SUSPEND, 5000)) ehci_err(ehci, "timeout waiting for SUSPEND\n"); if (ci->platdata->flags & CI_HDRC_IMX_IS_HSIC) ci_ehci_override_wakeup_flag(ehci, reg, PORT_WKDISC_E | PORT_WKCONN_E, false); if (hcd->usb_phy && test_bit(port, &ehci->bus_suspended) && (ehci_port_speed(ehci, portsc) == USB_PORT_STAT_HIGH_SPEED)) /* * notify the USB PHY, it is for global * suspend case. */ usb_phy_notify_suspend(hcd->usb_phy, USB_SPEED_HIGH); break; } } return 0; }