Пример #1
0
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;
}
Пример #2
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;
}