19 #include <linux/kernel.h>
20 #include <linux/module.h>
21 #include <linux/pci.h>
28 #ifdef CONFIG_PPC_PMAC
29 #include <asm/machdep.h>
31 #include <asm/pci-bridge.h>
40 #ifdef CONFIG_PM_SLEEP
48 #define CL_UHCI PCI_CLASS_SERIAL_USB_UHCI
49 #define CL_OHCI PCI_CLASS_SERIAL_USB_OHCI
50 #define CL_EHCI PCI_CLASS_SERIAL_USB_EHCI
52 enum companion_action {
53 SET_HS_COMPANION, CLEAR_HS_COMPANION, WAIT_FOR_COMPANIONS
56 static void companion_common(
struct pci_dev *pdev,
struct usb_hcd *hcd,
57 enum companion_action
action)
60 struct usb_hcd *companion_hcd;
69 if (companion->
bus != pdev->
bus ||
73 companion_hcd = pci_get_drvdata(companion);
85 if ((pdev->
class == CL_OHCI || pdev->
class == CL_UHCI) &&
86 companion->
class == CL_EHCI) {
88 dev_dbg(&companion->
dev,
"HS companion for %s\n",
89 dev_name(&pdev->
dev));
90 hcd->self.hs_companion = &companion_hcd->self;
92 }
else if (pdev->
class == CL_EHCI &&
93 (companion->
class == CL_OHCI ||
94 companion->
class == CL_UHCI)) {
96 case SET_HS_COMPANION:
98 dev_name(&companion->
dev));
99 companion_hcd->self.hs_companion = &hcd->self;
101 case CLEAR_HS_COMPANION:
102 companion_hcd->self.hs_companion =
NULL;
104 case WAIT_FOR_COMPANIONS:
113 static void set_hs_companion(
struct pci_dev *pdev,
struct usb_hcd *hcd)
117 companion_common(pdev, hcd, SET_HS_COMPANION);
121 static void clear_hs_companion(
struct pci_dev *pdev,
struct usb_hcd *hcd)
127 if (pdev->
class == CL_OHCI || pdev->
class == CL_UHCI)
128 hcd->self.hs_companion =
NULL;
132 companion_common(pdev, hcd, CLEAR_HS_COMPANION);
136 static void wait_for_companions(
struct pci_dev *pdev,
struct usb_hcd *hcd)
142 if (pdev->
class == CL_EHCI)
143 companion_common(pdev, hcd, WAIT_FOR_COMPANIONS);
148 static inline void set_hs_companion(
struct pci_dev *
d,
struct usb_hcd *
h) {}
149 static inline void clear_hs_companion(
struct pci_dev *
d,
struct usb_hcd *
h) {}
150 static inline void wait_for_companions(
struct pci_dev *
d,
struct usb_hcd *
h) {}
193 if (!dev->
irq && (driver->flags & HCD_MASK) != HCD_USB3) {
195 "Found HC with no IRQ. Check BIOS/PCI %s setup!\n",
207 if (driver->flags & HCD_MEMORY) {
212 driver->description)) {
213 dev_dbg(&dev->
dev,
"controller already in use\n");
215 goto clear_companion;
218 if (hcd->regs ==
NULL) {
236 driver->description))
239 if (region == PCI_ROM_RESOURCE) {
240 dev_dbg(&dev->
dev,
"no i/o regions available\n");
242 goto clear_companion;
250 goto unmap_registers;
251 set_hs_companion(dev, hcd);
254 pm_runtime_put_noidle(&dev->
dev);
258 if (driver->flags & HCD_MEMORY) {
265 clear_hs_companion(dev, hcd);
269 dev_err(&dev->
dev,
"init %s fail, %d\n", pci_name(dev), retval);
293 hcd = pci_get_drvdata(dev);
298 pm_runtime_get_noresume(&dev->
dev);
309 if (hcd->driver->flags & HCD_MEMORY) {
315 clear_hs_companion(dev, hcd);
329 hcd = pci_get_drvdata(dev);
333 if (
test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) &&
334 hcd->driver->shutdown) {
335 hcd->driver->shutdown(hcd);
343 #ifdef CONFIG_PPC_PMAC
347 if (machine_is(powermac)) {
350 of_node = pci_device_to_OF_node(pci_dev);
352 pmac_call_feature(PMAC_FTR_USB_ENABLE,
359 static inline void powermac_set_asic(
struct pci_dev *pci_dev,
int enable)
364 static int check_root_hub_suspended(
struct device *
dev)
367 struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
369 if (HCD_RH_RUNNING(hcd)) {
370 dev_warn(dev,
"Root hub is not suspended\n");
373 if (hcd->shared_hcd) {
374 hcd = hcd->shared_hcd;
375 if (HCD_RH_RUNNING(hcd)) {
376 dev_warn(dev,
"Secondary root hub is not suspended\n");
383 #if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
384 static int suspend_common(
struct device *dev,
bool do_wakeup)
387 struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
395 retval = check_root_hub_suspended(dev);
399 if (hcd->driver->pci_suspend && !HCD_DEAD(hcd)) {
403 if (do_wakeup && HCD_WAKEUP_PENDING(hcd))
405 if (do_wakeup && hcd->shared_hcd &&
406 HCD_WAKEUP_PENDING(hcd->shared_hcd))
408 retval = hcd->driver->pci_suspend(hcd, do_wakeup);
412 if ((retval == 0 && do_wakeup && HCD_WAKEUP_PENDING(hcd)) ||
413 (retval == 0 && do_wakeup && hcd->shared_hcd &&
414 HCD_WAKEUP_PENDING(hcd->shared_hcd))) {
415 if (hcd->driver->pci_resume)
416 hcd->driver->pci_resume(hcd,
false);
427 if (!hcd->msix_enabled)
439 static int resume_common(
struct device *dev,
int event)
442 struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
445 if (HCD_RH_RUNNING(hcd) ||
447 HCD_RH_RUNNING(hcd->shared_hcd))) {
448 dev_dbg(dev,
"can't resume, not suspended!\n");
454 dev_err(dev,
"can't re-enable after resume, %d!\n", retval);
460 if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
462 wait_for_companions(pci_dev, hcd);
464 retval = hcd->driver->pci_resume(hcd,
467 dev_err(dev,
"PCI post-resume error %d!\n", retval);
477 #ifdef CONFIG_PM_SLEEP
479 static int hcd_pci_suspend(
struct device *dev)
481 return suspend_common(dev, device_may_wakeup(dev));
484 static int hcd_pci_suspend_noirq(
struct device *dev)
487 struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
490 retval = check_root_hub_suspended(dev);
502 dev_dbg(dev,
"wakeup: %d\n", device_may_wakeup(dev));
508 if (retval == -
EIO) {
509 dev_dbg(dev,
"--> PCI D0 legacy\n");
511 }
else if (retval == 0) {
519 powermac_set_asic(pci_dev, 0);
523 static int hcd_pci_resume_noirq(
struct device *dev)
527 powermac_set_asic(pci_dev, 1);
534 static int hcd_pci_resume(
struct device *dev)
539 static int hcd_pci_restore(
struct device *dev)
546 #define hcd_pci_suspend NULL
547 #define hcd_pci_suspend_noirq NULL
548 #define hcd_pci_resume_noirq NULL
549 #define hcd_pci_resume NULL
550 #define hcd_pci_restore NULL
554 #ifdef CONFIG_PM_RUNTIME
556 static int hcd_pci_runtime_suspend(
struct device *dev)
560 retval = suspend_common(dev,
true);
563 dev_dbg(dev,
"hcd_pci_runtime_suspend: %d\n", retval);
567 static int hcd_pci_runtime_resume(
struct device *dev)
573 dev_dbg(dev,
"hcd_pci_runtime_resume: %d\n", retval);
579 #define hcd_pci_runtime_suspend NULL
580 #define hcd_pci_runtime_resume NULL
584 const struct dev_pm_ops usb_hcd_pci_pm_ops = {
586 .suspend_noirq = hcd_pci_suspend_noirq,
587 .resume_noirq = hcd_pci_resume_noirq,
588 .resume = hcd_pci_resume,
589 .freeze = check_root_hub_suspended,
590 .freeze_noirq = check_root_hub_suspended,
593 .poweroff = hcd_pci_suspend,
594 .poweroff_noirq = hcd_pci_suspend_noirq,
595 .restore_noirq = hcd_pci_resume_noirq,
596 .restore = hcd_pci_restore,
597 .runtime_suspend = hcd_pci_runtime_suspend,
598 .runtime_resume = hcd_pci_runtime_resume,