static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); int err = 0; EHCI_DBG("%s() BEGIN\n", __func__); #ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ tegra->boost_requested = false; if (tegra->boost_enable && pm_qos_request_active(&tegra->boost_cpu_freq_req)) pm_qos_update_request(&tegra->boost_cpu_freq_req, PM_QOS_DEFAULT_VALUE); tegra->cpu_boost_in_work = false; #endif mutex_lock(&tegra->sync_lock); tegra->bus_suspended_fail = false; err = ehci_bus_suspend(hcd); if (err) tegra->bus_suspended_fail = true; else usb_phy_set_suspend(get_usb_phy(tegra->phy), 1); mutex_unlock(&tegra->sync_lock); EHCI_DBG("%s() END\n", __func__); return err; }
static int tegra_ehci_bus_resume(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); int err = 0; EHCI_DBG("%s() BEGIN\n", __func__); mutex_lock(&tegra->sync_lock); usb_phy_set_suspend(get_usb_phy(tegra->phy), 0); err = ehci_bus_resume(hcd); mutex_unlock(&tegra->sync_lock); EHCI_DBG("%s() END\n", __func__); return err; }
static irqreturn_t tegra_ehci_irq(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_hcd *ehci = hcd_to_ehci(hcd); irqreturn_t irq_status; spin_lock(&ehci->lock); irq_status = tegra_usb_phy_irq(tegra->phy); if (irq_status == IRQ_NONE) { spin_unlock(&ehci->lock); return irq_status; } if (tegra_usb_phy_pmc_wakeup(tegra->phy)) { ehci_dbg(ehci, "pmc wakeup detected\n"); usb_hcd_resume_root_hub(hcd); spin_unlock(&ehci->lock); return irq_status; } spin_unlock(&ehci->lock); EHCI_DBG("%s() cmd = 0x%x, int_sts = 0x%x, portsc = 0x%x\n", __func__, ehci_readl(ehci, &ehci->regs->command), ehci_readl(ehci, &ehci->regs->status), ehci_readl(ehci, &ehci->regs->port_status[0])); irq_status = ehci_irq(hcd); if (ehci->controller_remote_wakeup) { ehci->controller_remote_wakeup = false; tegra_usb_phy_pre_resume(tegra->phy, true); tegra->port_resuming = 1; } return irq_status; }
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); int err = 0; EHCI_DBG("%s() BEGIN\n", __func__); mutex_lock(&tegra->sync_lock); tegra->bus_suspended_fail = false; err = ehci_bus_suspend(hcd); if (err) tegra->bus_suspended_fail = true; else usb_phy_set_suspend(get_usb_phy(tegra->phy), 1); mutex_unlock(&tegra->sync_lock); EHCI_DBG("%s() END\n", __func__); return err; }
static int tegra_ehci_bus_resume(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); int err = 0; EHCI_DBG("%s() BEGIN\n", __func__); #ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ pm_qos_update_request(&tegra->boost_cpu_freq_req, (s32)CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ * 1000); tegra->cpu_boost_in_work = false; #endif mutex_lock(&tegra->sync_lock); usb_phy_set_suspend(get_usb_phy(tegra->phy), 0); err = ehci_bus_resume(hcd); mutex_unlock(&tegra->sync_lock); EHCI_DBG("%s() END\n", __func__); return err; }
static int tegra_ehci_bus_resume(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); int err = 0; EHCI_DBG("%s() BEGIN\n", __func__); #ifdef CONFIG_TEGRA_EHCI_BOOST_CPU_FREQ tegra->boost_requested = true; if (pm_qos_request_active(&tegra->boost_cpu_freq_req) && tegra->boost_enable) { schedule_delayed_work(&tegra->boost_cpu_freq_work, 4000); tegra->cpu_boost_in_work = true; } #endif mutex_lock(&tegra->sync_lock); usb_phy_set_suspend(get_usb_phy(tegra->phy), 0); err = ehci_bus_resume(hcd); mutex_unlock(&tegra->sync_lock); EHCI_DBG("%s() END\n", __func__); return err; }
static int tegra_ehci_bus_suspend(struct usb_hcd *hcd) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_hcd *ehci = hcd_to_ehci(hcd); int err = 0; EHCI_DBG("%s() BEGIN\n", __func__); pr_info("%s::resetdone = %ld:tegra->port_resuming =%d\n", __func__, ehci->reset_done[0], tegra->port_resuming); mutex_lock(&tegra->sync_lock); tegra->bus_suspended_fail = false; err = ehci_bus_suspend(hcd); if (err) { if(tegra->port_resuming) pr_info("%s: bus_suspended aborted because of resume. err=(%d):resetdone = %ld:tegra->port_resuming =%d\n", __func__, err, ehci->reset_done[0], tegra->port_resuming); else pr_info("%s: bus_suspended_fail err=(%d):resetdone = %ld\n", __func__, err, ehci->reset_done[0]); tegra->bus_suspended_fail = true; } else tegra_usb_phy_suspend(tegra->phy); mutex_unlock(&tegra->sync_lock); EHCI_DBG("%s() END\n", __func__); return err; }
static int tegra_ehci_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength ) { struct tegra_ehci_hcd *tegra = dev_get_drvdata(hcd->self.controller); struct ehci_hcd *ehci = hcd_to_ehci(hcd); int retval = 0; u32 __iomem *status_reg; if (!tegra_usb_phy_hw_accessible(tegra->phy)) { if (buf) memset(buf, 0, wLength); return retval; } /* Do tegra phy specific actions based on the type request */ switch (typeReq) { case GetPortStatus: if (tegra->port_resuming) { u32 cmd; int delay = ehci->reset_done[wIndex-1] - jiffies; /* Sometimes it seems we get called too soon... In that case, wait.*/ if (delay > 0) { ehci_dbg(ehci, "GetPortStatus called too soon, waiting %dms...\n", delay); mdelay(jiffies_to_msecs(delay)); } status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1]; /* Ensure the port PORT_SUSPEND and PORT_RESUME has cleared */ if (handshake(ehci, status_reg, (PORT_SUSPEND | PORT_RESUME), 0, 25000)) { EHCI_DBG("%s: timeout waiting for SUSPEND to clear\n", __func__); } tegra_usb_phy_post_resume(tegra->phy); tegra->port_resuming = 0; /* If run bit is not set by now enable it */ cmd = ehci_readl(ehci, &ehci->regs->command); if (!(cmd & CMD_RUN)) { cmd |= CMD_RUN; ehci->command |= CMD_RUN; ehci_writel(ehci, cmd, &ehci->regs->command); } /* Now we can safely re-enable irqs */ ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable); } break; case ClearPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) { tegra_usb_phy_pre_resume(tegra->phy, false); tegra->port_resuming = 1; } else if (wValue == USB_PORT_FEAT_ENABLE) { u32 temp; temp = ehci_readl(ehci, &ehci->regs->port_status[0]) & ~PORT_RWC_BITS; ehci_writel(ehci, temp & ~PORT_PE, &ehci->regs->port_status[0]); return retval; } break; case SetPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) tegra_usb_phy_pre_suspend(tegra->phy); break; } /* handle ehci hub control request */ retval = ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength); /* do tegra phy specific actions based on the type request */ if (!retval) { switch (typeReq) { case SetPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) { tegra_usb_phy_post_suspend(tegra->phy); } else if (wValue == USB_PORT_FEAT_RESET) { if (wIndex == 1) tegra_usb_phy_bus_reset(tegra->phy); } else if (wValue == USB_PORT_FEAT_POWER) { if (wIndex == 1) tegra_usb_phy_port_power(tegra->phy); } break; case ClearPortFeature: if (wValue == USB_PORT_FEAT_SUSPEND) { /* tegra USB controller needs 25 ms to resume the port */ ehci->reset_done[wIndex-1] = jiffies + msecs_to_jiffies(25); } break; } } return retval; }