static int tegra_usb_resume(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_hcd *ehci = hcd_to_ehci(hcd); struct ehci_regs __iomem *hw = ehci->regs; unsigned long val; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); tegra_ehci_power_up(hcd); if (tegra->port_speed > TEGRA_USB_PHY_PORT_SPEED_HIGH) { /* Wait for the phy to detect new devices * before we restart the controller */ msleep(10); goto restart; } /* Force the phy to keep data lines in suspend state */ tegra_ehci_phy_restore_start(tegra->phy, tegra->port_speed); /* Enable host mode */ tdi_reset(ehci); /* Enable Port Power */ val = readl(&hw->port_status[0]); val |= PORT_POWER; writel(val, &hw->port_status[0]); udelay(10); /* Check if the phy resume from LP0. When the phy resume from LP0 * USB register will be reset. */ if (!readl(&hw->async_next)) { /* Program the field PTC based on the saved speed mode */ val = readl(&hw->port_status[0]); val &= ~PORT_TEST(~0); if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_HIGH) val |= PORT_TEST_FORCE; else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) val |= PORT_TEST(6); else if (tegra->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) val |= PORT_TEST(7); writel(val, &hw->port_status[0]); udelay(10); /* Disable test mode by setting PTC field to NORMAL_OP */ val = readl(&hw->port_status[0]); val &= ~PORT_TEST(~0); writel(val, &hw->port_status[0]); udelay(10); } /* Poll until CCS is enabled */ if (handshake(ehci, &hw->port_status[0], PORT_CONNECT, PORT_CONNECT, 2000)) { pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); goto restart; } /* Poll until PE is enabled */ if (handshake(ehci, &hw->port_status[0], PORT_PE, PORT_PE, 2000)) { pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); goto restart; } /* Clear the PCI status, to avoid an interrupt taken upon resume */ val = readl(&hw->status); val |= STS_PCD; writel(val, &hw->status); /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ val = readl(&hw->port_status[0]); if ((val & PORT_POWER) && (val & PORT_PE)) { val |= PORT_SUSPEND; writel(val, &hw->port_status[0]); /* Need a 4ms delay before the controller goes to suspend */ mdelay(4); /* Wait until port suspend completes */ if (handshake(ehci, &hw->port_status[0], PORT_SUSPEND, PORT_SUSPEND, 1000)) { pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); goto restart; } } tegra_ehci_phy_restore_end(tegra->phy); return 0; restart: if (tegra->port_speed <= TEGRA_USB_PHY_PORT_SPEED_HIGH) tegra_ehci_phy_restore_end(tegra->phy); tegra_ehci_restart(hcd); return 0; }
static int tegra_usb_resume(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct tegra_ehci_context *context = &tegra->context; struct ehci_regs __iomem *hw = tegra->ehci->regs; unsigned long val; int lp0_resume = 0; set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); tegra_ehci_power_up(ehci_to_hcd(tegra->ehci)); if (!context->valid) { /* Wait for the phy to detect new devices * before we restart the controller */ msleep(10); goto restart; } tegra_ehci_phy_restore_start(tegra->phy, context->port_speed); /* Check if the phy resume from LP0. When the phy resume from LP0 * USB register will be reset. */ if (!readl(&hw->async_next)) lp0_resume = 1; /* Restore register context */ writel(TEGRA_USB_USBMODE_HOST, &hw->reserved[19]); writel(context->otgsc, &hw->reserved[18]); writel(context->txfilltunning, &hw->reserved[2]); writel(context->async_next, &hw->async_next); writel(context->frame_list, &hw->frame_list); writel(context->command, &hw->command); /* Enable Port Power */ val = readl(&hw->port_status[0]); val |= PORT_POWER; writel(val, &hw->port_status[0]); udelay(10); if (lp0_resume) { /* Program the field PTC in PORTSC based on the saved speed mode */ val = readl(&hw->port_status[0]); val &= ~(TEGRA_USB_PORTSC1_PTC(~0)); if (context->port_speed == TEGRA_USB_PHY_PORT_HIGH) val |= TEGRA_USB_PORTSC1_PTC(5); else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_FULL) val |= TEGRA_USB_PORTSC1_PTC(6); else if (context->port_speed == TEGRA_USB_PHY_PORT_SPEED_LOW) val |= TEGRA_USB_PORTSC1_PTC(7); writel(val, &hw->port_status[0]); udelay(10); } /* Disable test mode by setting PTC field to NORMAL_OP */ val = readl(&hw->port_status[0]); val &= ~(TEGRA_USB_PORTSC1_PTC(~0)); writel(val, &hw->port_status[0]); udelay(10); /* Poll until CCS is enabled */ if (handshake(tegra->ehci, &hw->port_status[0], PORT_CONNECT, PORT_CONNECT, 2000)) { pr_err("%s: timeout waiting for PORT_CONNECT\n", __func__); goto restart; } /* Poll until PE is enabled */ if (handshake(tegra->ehci, &hw->port_status[0], PORT_PE, PORT_PE, 2000)) { pr_err("%s: timeout waiting for USB_PORTSC1_PE\n", __func__); goto restart; } /* Clear the PCI status, to avoid an interrupt taken upon resume */ val = readl(&hw->status); val |= STS_PCD; writel(val, &hw->status); /* Put controller in suspend mode by writing 1 to SUSP bit of PORTSC */ val = readl(&hw->port_status[0]); if ((val & PORT_POWER) && (val & PORT_PE)) { val |= PORT_SUSPEND; writel(val, &hw->port_status[0]); /* Wait until port suspend completes */ if (handshake(tegra->ehci, &hw->port_status[0], PORT_SUSPEND, PORT_SUSPEND, 1000)) { pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__); goto restart; } } tegra_ehci_phy_restore_end(tegra->phy); return 0; restart: if (context->valid) tegra_ehci_phy_restore_end(tegra->phy); tegra_ehci_restart(hcd); return 0; }