summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ohci-hub.c
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2008-04-04 00:03:17 +0200
committerGreg Kroah-Hartman <gregkh@suse.de>2008-04-25 06:16:48 +0200
commit43bbb7e015c4380064796c5868b536437b165615 (patch)
tree6f4b8e184904917677ce00f600ebf3c8839f47f0 /drivers/usb/host/ohci-hub.c
parentUSB: clarify usage of hcd->suspend/resume methods (diff)
downloadlinux-43bbb7e015c4380064796c5868b536437b165615.tar.xz
linux-43bbb7e015c4380064796c5868b536437b165615.zip
USB: OHCI: host-controller resumes leave root hub suspended
Drivers in the ohci-hcd family should perform certain tasks whenever their controller device is resumed. These include checking for loss of power during suspend, turning on port power, and enabling interrupt requests. Until now these jobs have been carried out when the root hub is resumed, not when the controller is. Many drivers work around the resulting awkwardness by automatically resuming their root hub whenever the controller is resumed. But this is wasteful and unnecessary. To simplify the situation, this patch (as1066) adds a new core routine, ohci_finish_controller_resume(), which can be used by all the OHCI-variant drivers. They can call the new routine instead of resuming their root hubs. And ohci-pci.c can call it instead of using its own special-purpose handler. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb/host/ohci-hub.c')
-rw-r--r--drivers/usb/host/ohci-hub.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index c638e6b33c43..28d6d775eb5f 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -326,6 +326,49 @@ static int ohci_bus_resume (struct usb_hcd *hcd)
return rc;
}
+/* Carry out the final steps of resuming the controller device */
+static void ohci_finish_controller_resume(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int port;
+ bool need_reinit = false;
+
+ /* See if the controller is already running or has been reset */
+ ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
+ if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
+ need_reinit = true;
+ } else {
+ switch (ohci->hc_control & OHCI_CTRL_HCFS) {
+ case OHCI_USB_OPER:
+ case OHCI_USB_RESET:
+ need_reinit = true;
+ }
+ }
+
+ /* If needed, reinitialize and suspend the root hub */
+ if (need_reinit) {
+ spin_lock_irq(&ohci->lock);
+ hcd->state = HC_STATE_RESUMING;
+ ohci_rh_resume(ohci);
+ hcd->state = HC_STATE_QUIESCING;
+ ohci_rh_suspend(ohci, 0);
+ hcd->state = HC_STATE_SUSPENDED;
+ spin_unlock_irq(&ohci->lock);
+ }
+
+ /* Normally just turn on port power and enable interrupts */
+ else {
+ ohci_dbg(ohci, "powerup ports\n");
+ for (port = 0; port < ohci->num_ports; port++)
+ ohci_writel(ohci, RH_PS_PPS,
+ &ohci->regs->roothub.portstatus[port]);
+
+ ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrenable);
+ ohci_readl(ohci, &ohci->regs->intrenable);
+ msleep(20);
+ }
+}
+
/* Carry out polling-, autostop-, and autoresume-related state changes */
static int ohci_root_hub_state_changes(struct ohci_hcd *ohci, int changed,
int any_connected)