diff options
-rw-r--r-- | drivers/video/via/via-core.c | 79 | ||||
-rw-r--r-- | drivers/video/via/viafbdev.c | 34 | ||||
-rw-r--r-- | drivers/video/via/viafbdev.h | 2 | ||||
-rw-r--r-- | include/linux/via-core.h | 15 |
4 files changed, 107 insertions, 23 deletions
diff --git a/drivers/video/via/via-core.c b/drivers/video/via/via-core.c index 31e30338e893..42be3d955887 100644 --- a/drivers/video/via/via-core.c +++ b/drivers/video/via/via-core.c | |||
@@ -15,6 +15,8 @@ | |||
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/interrupt.h> | 16 | #include <linux/interrupt.h> |
17 | #include <linux/platform_device.h> | 17 | #include <linux/platform_device.h> |
18 | #include <linux/list.h> | ||
19 | #include <linux/pm.h> | ||
18 | 20 | ||
19 | /* | 21 | /* |
20 | * The default port config. | 22 | * The default port config. |
@@ -563,6 +565,78 @@ static void via_teardown_subdevs(void) | |||
563 | } | 565 | } |
564 | } | 566 | } |
565 | 567 | ||
568 | /* | ||
569 | * Power management functions | ||
570 | */ | ||
571 | #ifdef CONFIG_PM | ||
572 | static LIST_HEAD(viafb_pm_hooks); | ||
573 | static DEFINE_MUTEX(viafb_pm_hooks_lock); | ||
574 | |||
575 | void viafb_pm_register(struct viafb_pm_hooks *hooks) | ||
576 | { | ||
577 | INIT_LIST_HEAD(&hooks->list); | ||
578 | |||
579 | mutex_lock(&viafb_pm_hooks_lock); | ||
580 | list_add_tail(&hooks->list, &viafb_pm_hooks); | ||
581 | mutex_unlock(&viafb_pm_hooks_lock); | ||
582 | } | ||
583 | EXPORT_SYMBOL_GPL(viafb_pm_register); | ||
584 | |||
585 | void viafb_pm_unregister(struct viafb_pm_hooks *hooks) | ||
586 | { | ||
587 | mutex_lock(&viafb_pm_hooks_lock); | ||
588 | list_del(&hooks->list); | ||
589 | mutex_unlock(&viafb_pm_hooks_lock); | ||
590 | } | ||
591 | EXPORT_SYMBOL_GPL(viafb_pm_unregister); | ||
592 | |||
593 | static int via_suspend(struct pci_dev *pdev, pm_message_t state) | ||
594 | { | ||
595 | struct viafb_pm_hooks *hooks; | ||
596 | |||
597 | if (state.event != PM_EVENT_SUSPEND) | ||
598 | return 0; | ||
599 | /* | ||
600 | * "I've occasionally hit a few drivers that caused suspend | ||
601 | * failures, and each and every time it was a driver bug, and | ||
602 | * the right thing to do was to just ignore the error and suspend | ||
603 | * anyway - returning an error code and trying to undo the suspend | ||
604 | * is not what anybody ever really wants, even if our model | ||
605 | *_allows_ for it." | ||
606 | * -- Linus Torvalds, Dec. 7, 2009 | ||
607 | */ | ||
608 | mutex_lock(&viafb_pm_hooks_lock); | ||
609 | list_for_each_entry_reverse(hooks, &viafb_pm_hooks, list) | ||
610 | hooks->suspend(hooks->private); | ||
611 | mutex_unlock(&viafb_pm_hooks_lock); | ||
612 | |||
613 | pci_save_state(pdev); | ||
614 | pci_disable_device(pdev); | ||
615 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int via_resume(struct pci_dev *pdev) | ||
620 | { | ||
621 | struct viafb_pm_hooks *hooks; | ||
622 | |||
623 | /* Get the bus side powered up */ | ||
624 | pci_set_power_state(pdev, PCI_D0); | ||
625 | pci_restore_state(pdev); | ||
626 | if (pci_enable_device(pdev)) | ||
627 | return 0; | ||
628 | |||
629 | pci_set_master(pdev); | ||
630 | |||
631 | /* Now bring back any subdevs */ | ||
632 | mutex_lock(&viafb_pm_hooks_lock); | ||
633 | list_for_each_entry(hooks, &viafb_pm_hooks, list) | ||
634 | hooks->resume(hooks->private); | ||
635 | mutex_unlock(&viafb_pm_hooks_lock); | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | #endif /* CONFIG_PM */ | ||
566 | 640 | ||
567 | static int __devinit via_pci_probe(struct pci_dev *pdev, | 641 | static int __devinit via_pci_probe(struct pci_dev *pdev, |
568 | const struct pci_device_id *ent) | 642 | const struct pci_device_id *ent) |
@@ -572,6 +646,7 @@ static int __devinit via_pci_probe(struct pci_dev *pdev, | |||
572 | ret = pci_enable_device(pdev); | 646 | ret = pci_enable_device(pdev); |
573 | if (ret) | 647 | if (ret) |
574 | return ret; | 648 | return ret; |
649 | |||
575 | /* | 650 | /* |
576 | * Global device initialization. | 651 | * Global device initialization. |
577 | */ | 652 | */ |
@@ -651,8 +726,8 @@ static struct pci_driver via_driver = { | |||
651 | .probe = via_pci_probe, | 726 | .probe = via_pci_probe, |
652 | .remove = __devexit_p(via_pci_remove), | 727 | .remove = __devexit_p(via_pci_remove), |
653 | #ifdef CONFIG_PM | 728 | #ifdef CONFIG_PM |
654 | .suspend = viafb_suspend, | 729 | .suspend = via_suspend, |
655 | .resume = viafb_resume, | 730 | .resume = via_resume, |
656 | #endif | 731 | #endif |
657 | }; | 732 | }; |
658 | 733 | ||
diff --git a/drivers/video/via/viafbdev.c b/drivers/video/via/viafbdev.c index d298cfccd6fc..289edd519527 100644 --- a/drivers/video/via/viafbdev.c +++ b/drivers/video/via/viafbdev.c | |||
@@ -1672,31 +1672,19 @@ static int parse_mode(const char *str, u32 *xres, u32 *yres) | |||
1672 | 1672 | ||
1673 | 1673 | ||
1674 | #ifdef CONFIG_PM | 1674 | #ifdef CONFIG_PM |
1675 | int viafb_suspend(struct pci_dev *pdev, pm_message_t state) | 1675 | static int viafb_suspend(void *unused) |
1676 | { | 1676 | { |
1677 | if (state.event == PM_EVENT_SUSPEND) { | 1677 | acquire_console_sem(); |
1678 | acquire_console_sem(); | 1678 | fb_set_suspend(viafbinfo, 1); |
1679 | fb_set_suspend(viafbinfo, 1); | 1679 | viafb_sync(viafbinfo); |
1680 | 1680 | release_console_sem(); | |
1681 | viafb_sync(viafbinfo); | ||
1682 | |||
1683 | pci_save_state(pdev); | ||
1684 | pci_disable_device(pdev); | ||
1685 | pci_set_power_state(pdev, pci_choose_state(pdev, state)); | ||
1686 | release_console_sem(); | ||
1687 | } | ||
1688 | 1681 | ||
1689 | return 0; | 1682 | return 0; |
1690 | } | 1683 | } |
1691 | 1684 | ||
1692 | int viafb_resume(struct pci_dev *pdev) | 1685 | static int viafb_resume(void *unused) |
1693 | { | 1686 | { |
1694 | acquire_console_sem(); | 1687 | acquire_console_sem(); |
1695 | pci_set_power_state(pdev, PCI_D0); | ||
1696 | pci_restore_state(pdev); | ||
1697 | if (pci_enable_device(pdev)) | ||
1698 | goto fail; | ||
1699 | pci_set_master(pdev); | ||
1700 | if (viaparinfo->shared->vdev->engine_mmio) | 1688 | if (viaparinfo->shared->vdev->engine_mmio) |
1701 | viafb_reset_engine(viaparinfo); | 1689 | viafb_reset_engine(viaparinfo); |
1702 | viafb_set_par(viafbinfo); | 1690 | viafb_set_par(viafbinfo); |
@@ -1704,11 +1692,15 @@ int viafb_resume(struct pci_dev *pdev) | |||
1704 | viafb_set_par(viafbinfo1); | 1692 | viafb_set_par(viafbinfo1); |
1705 | fb_set_suspend(viafbinfo, 0); | 1693 | fb_set_suspend(viafbinfo, 0); |
1706 | 1694 | ||
1707 | fail: | ||
1708 | release_console_sem(); | 1695 | release_console_sem(); |
1709 | return 0; | 1696 | return 0; |
1710 | } | 1697 | } |
1711 | 1698 | ||
1699 | static struct viafb_pm_hooks viafb_fb_pm_hooks = { | ||
1700 | .suspend = viafb_suspend, | ||
1701 | .resume = viafb_resume | ||
1702 | }; | ||
1703 | |||
1712 | #endif | 1704 | #endif |
1713 | 1705 | ||
1714 | 1706 | ||
@@ -1899,6 +1891,10 @@ int __devinit via_fb_pci_probe(struct viafb_dev *vdev) | |||
1899 | 1891 | ||
1900 | viafb_init_proc(viaparinfo->shared); | 1892 | viafb_init_proc(viaparinfo->shared); |
1901 | viafb_init_dac(IGA2); | 1893 | viafb_init_dac(IGA2); |
1894 | |||
1895 | #ifdef CONFIG_PM | ||
1896 | viafb_pm_register(&viafb_fb_pm_hooks); | ||
1897 | #endif | ||
1902 | return 0; | 1898 | return 0; |
1903 | 1899 | ||
1904 | out_fb_unreg: | 1900 | out_fb_unreg: |
diff --git a/drivers/video/via/viafbdev.h b/drivers/video/via/viafbdev.h index 4960e3da6645..d66f963e930e 100644 --- a/drivers/video/via/viafbdev.h +++ b/drivers/video/via/viafbdev.h | |||
@@ -108,6 +108,4 @@ void via_fb_pci_remove(struct pci_dev *pdev); | |||
108 | /* Temporary */ | 108 | /* Temporary */ |
109 | int viafb_init(void); | 109 | int viafb_init(void); |
110 | void viafb_exit(void); | 110 | void viafb_exit(void); |
111 | int viafb_suspend(struct pci_dev *pdev, pm_message_t state); | ||
112 | int viafb_resume(struct pci_dev *pdev); | ||
113 | #endif /* __VIAFBDEV_H__ */ | 111 | #endif /* __VIAFBDEV_H__ */ |
diff --git a/include/linux/via-core.h b/include/linux/via-core.h index 7ffb521e1a7a..a4327a0c8efc 100644 --- a/include/linux/via-core.h +++ b/include/linux/via-core.h | |||
@@ -60,6 +60,21 @@ struct via_port_cfg { | |||
60 | }; | 60 | }; |
61 | 61 | ||
62 | /* | 62 | /* |
63 | * Allow subdevs to register suspend/resume hooks. | ||
64 | */ | ||
65 | #ifdef CONFIG_PM | ||
66 | struct viafb_pm_hooks { | ||
67 | struct list_head list; | ||
68 | int (*suspend)(void *private); | ||
69 | int (*resume)(void *private); | ||
70 | void *private; | ||
71 | }; | ||
72 | |||
73 | void viafb_pm_register(struct viafb_pm_hooks *hooks); | ||
74 | void viafb_pm_unregister(struct viafb_pm_hooks *hooks); | ||
75 | #endif /* CONFIG_PM */ | ||
76 | |||
77 | /* | ||
63 | * This is the global viafb "device" containing stuff needed by | 78 | * This is the global viafb "device" containing stuff needed by |
64 | * all subdevs. | 79 | * all subdevs. |
65 | */ | 80 | */ |