Merge with rsync://rsync.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
[sfrench/cifs-2.6.git] / drivers / usb / host / ohci-pci.c
index 7ce1d9ef0289ed3bba31b89b035d7f7a8a9e9d09..1bfe96f4d0453083f3dad29a0e102dbb3e4fd0ac 100644 (file)
  * This file is licenced under the GPL.
  */
  
-#include <linux/jiffies.h>
-
-#ifdef CONFIG_PPC_PMAC
-#include <asm/machdep.h>
-#include <asm/pmac_feature.h>
-#include <asm/pci-bridge.h>
-#include <asm/prom.h>
-#endif
-
 #ifndef CONFIG_PCI
 #error "This file is PCI bus glue.  CONFIG_PCI must be defined."
 #endif
@@ -44,7 +35,10 @@ ohci_pci_start (struct usb_hcd *hcd)
        struct ohci_hcd *ohci = hcd_to_ohci (hcd);
        int             ret;
 
-       if(hcd->self.controller && hcd->self.controller->bus == &pci_bus_type) {
+       /* REVISIT this whole block should move to reset(), which handles
+        * all the other one-time init.
+        */
+       if (hcd->self.controller) {
                struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
                /* AMD 756, for most chips (early revs), corrupts register
@@ -54,7 +48,8 @@ ohci_pci_start (struct usb_hcd *hcd)
                                && pdev->device == 0x740c) {
                        ohci->flags = OHCI_QUIRK_AMD756;
                        ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-                       // also somewhat erratum 10 (suspend/resume issues)
+                       /* also erratum 10 (suspend/resume issues) */
+                       device_init_wakeup(&hcd->self.root_hub->dev, 0);
                }
 
                /* FIXME for some of the early AMD 760 southbridges, OHCI
@@ -97,6 +92,13 @@ ohci_pci_start (struct usb_hcd *hcd)
                        ohci_dbg (ohci,
                                "enabled Compaq ZFMicro chipset quirk\n");
                }
+
+               /* RWC may not be set for add-in PCI cards, since boot
+                * firmware probably ignored them.  This transfers PCI
+                * PM wakeup capabilities (once the PCI layer is fixed).
+                */
+               if (device_may_wakeup(&pdev->dev))
+                       ohci->hc_control |= OHCI_CTRL_RWC;
        }
 
        /* NOTE: there may have already been a first reset, to
@@ -114,40 +116,36 @@ ohci_pci_start (struct usb_hcd *hcd)
 
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 {
-       /* root hub was already suspended */
-
-       /* FIXME these PMAC things get called in the wrong places.  ASIC
-        * clocks should be turned off AFTER entering D3, and on BEFORE
-        * trying to enter D0.  Evidently the PCI layer doesn't currently
-        * provide the right sort of platform hooks for this ...
+       struct ohci_hcd *ohci = hcd_to_ohci (hcd);
+       unsigned long   flags;
+       int             rc = 0;
+
+       /* Root hub was already suspended. Disable irq emission and
+        * mark HW unaccessible, bail out if RH has been resumed. Use
+        * the spinlock to properly synchronize with possible pending
+        * RH suspend or resume activity.
+        *
+        * This is still racy as hcd->state is manipulated outside of
+        * any locks =P But that will be a different fix.
         */
-#ifdef CONFIG_PPC_PMAC
-       if (_machine == _MACH_Pmac) {
-               struct device_node      *of_node;
-               /* Disable USB PAD & cell clock */
-               of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
-               if (of_node)
-                       pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
+       spin_lock_irqsave (&ohci->lock, flags);
+       if (hcd->state != HC_STATE_SUSPENDED) {
+               rc = -EINVAL;
+               goto bail;
        }
-#endif /* CONFIG_PPC_PMAC */
-       return 0;
+       ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+       (void)ohci_readl(ohci, &ohci->regs->intrdisable);
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+ bail:
+       spin_unlock_irqrestore (&ohci->lock, flags);
+
+       return rc;
 }
 
 
 static int ohci_pci_resume (struct usb_hcd *hcd)
 {
-#ifdef CONFIG_PPC_PMAC
-       if (_machine == _MACH_Pmac) {
-               struct device_node *of_node;
-
-               /* Re-enable USB PAD & cell clock */
-               of_node = pci_device_to_OF_node (to_pci_dev(hcd->self.controller));
-               if (of_node)
-                       pmac_call_feature (PMAC_FTR_USB_ENABLE, of_node, 0, 1);
-       }
-#endif /* CONFIG_PPC_PMAC */
-
+       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
        usb_hcd_resume_root_hub(hcd);
        return 0;
 }
@@ -218,7 +216,6 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
 static struct pci_driver ohci_pci_driver = {
        .name =         (char *) hcd_name,
        .id_table =     pci_ids,
-       .owner =        THIS_MODULE,
 
        .probe =        usb_hcd_pci_probe,
        .remove =       usb_hcd_pci_remove,