+#ifdef CONFIG_PM
+
+static int ehci_hub_suspend (struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+ struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
+ int port;
+ int status = 0;
+
+ if (root->dev.power.power_state != 0)
+ return 0;
+ if (time_before (jiffies, ehci->next_statechange))
+ return -EAGAIN;
+
+ port = HCS_N_PORTS (ehci->hcs_params);
+ spin_lock_irq (&ehci->lock);
+
+ /* suspend any active/unsuspended ports, maybe allow wakeup */
+ while (port--) {
+ u32 t1 = readl (&ehci->regs->port_status [port]);
+ u32 t2 = t1;
+
+ if ((t1 & PORT_PE) && !(t1 & PORT_OWNER))
+ t2 |= PORT_SUSPEND;
+ if (ehci->hcd.remote_wakeup)
+ t2 |= PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E;
+ else
+ t2 &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+
+ if (t1 != t2) {
+ ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
+ port + 1, t1, t2);
+ writel (t2, &ehci->regs->port_status [port]);
+ }
+ }
+
+ /* stop schedules, then turn off HC and clean any completed work */
+ if (hcd->state == USB_STATE_RUNNING)
+ ehci_ready (ehci);
+ ehci->command = readl (&ehci->regs->command);
+ writel (ehci->command & ~CMD_RUN, &ehci->regs->command);
+ if (ehci->reclaim)
+ ehci->reclaim_ready = 1;
+ ehci_work(ehci, NULL);
+ (void) handshake (&ehci->regs->status, STS_HALT, STS_HALT, 2000);
+
+ root->dev.power.power_state = 3;
+ ehci->next_statechange = jiffies + msecs_to_jiffies(10);
+ spin_unlock_irq (&ehci->lock);
+ return status;
+}
+
+
+/* caller owns root->serialize, and should reset/reinit on error */
+static int ehci_hub_resume (struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci (hcd);
+ struct usb_device *root = hcd_to_bus (&ehci->hcd)->root_hub;
+ u32 temp;
+ int i;
+
+ if (!root->dev.power.power_state)
+ return 0;
+ if (time_before (jiffies, ehci->next_statechange))
+ return -EAGAIN;
+
+ /* re-init operational registers in case we lost power */
+ if (readl (&ehci->regs->intr_enable) == 0) {
+ writel (INTR_MASK, &ehci->regs->intr_enable);
+ writel (0, &ehci->regs->segment);
+ writel (ehci->periodic_dma, &ehci->regs->frame_list);
+ writel ((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+ /* FIXME will this work even (pci) vAUX was lost? */
+ }
+
+ /* restore CMD_RUN, framelist size, and irq threshold */
+ writel (ehci->command, &ehci->regs->command);
+
+ /* take ports out of suspend */
+ i = HCS_N_PORTS (ehci->hcs_params);
+ while (i--) {
+ temp = readl (&ehci->regs->port_status [i]);
+ temp &= ~(PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E);
+ if (temp & PORT_SUSPEND) {
+ ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
+ temp |= PORT_RESUME;
+ }
+ writel (temp, &ehci->regs->port_status [i]);
+ }
+ i = HCS_N_PORTS (ehci->hcs_params);
+ msleep (20);
+ while (i--) {
+ temp = readl (&ehci->regs->port_status [i]);
+ if ((temp & PORT_SUSPEND) == 0)
+ continue;
+ temp &= ~PORT_RESUME;
+ writel (temp, &ehci->regs->port_status [i]);
+ ehci_vdbg (ehci, "resumed port %d\n", i + 1);
+ }
+ (void) readl (&ehci->regs->command);
+
+ /* maybe re-activate the schedule(s) */
+ temp = 0;
+ if (ehci->async->qh_next.qh)
+ temp |= CMD_ASE;
+ if (ehci->periodic_sched)
+ temp |= CMD_PSE;
+ if (temp)
+ writel (ehci->command | temp, &ehci->regs->command);
+
+ root->dev.power.power_state = 0;
+ ehci->next_statechange = jiffies + msecs_to_jiffies(5);
+ ehci->hcd.state = USB_STATE_RUNNING;
+ return 0;
+}
+
+#else
+
+#define ehci_hub_suspend 0
+#define ehci_hub_resume 0
+
+#endif /* CONFIG_PM */
+
+/*-------------------------------------------------------------------------*/
+