aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/video/via/via-core.c79
-rw-r--r--drivers/video/via/viafbdev.c34
-rw-r--r--drivers/video/via/viafbdev.h2
-rw-r--r--include/linux/via-core.h15
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
572static LIST_HEAD(viafb_pm_hooks);
573static DEFINE_MUTEX(viafb_pm_hooks_lock);
574
575void 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}
583EXPORT_SYMBOL_GPL(viafb_pm_register);
584
585void 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}
591EXPORT_SYMBOL_GPL(viafb_pm_unregister);
592
593static 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
619static 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
567static int __devinit via_pci_probe(struct pci_dev *pdev, 641static 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
1675int viafb_suspend(struct pci_dev *pdev, pm_message_t state) 1675static 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
1692int viafb_resume(struct pci_dev *pdev) 1685static 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
1707fail:
1708 release_console_sem(); 1695 release_console_sem();
1709 return 0; 1696 return 0;
1710} 1697}
1711 1698
1699static 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
1904out_fb_unreg: 1900out_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 */
109int viafb_init(void); 109int viafb_init(void);
110void viafb_exit(void); 110void viafb_exit(void);
111int viafb_suspend(struct pci_dev *pdev, pm_message_t state);
112int 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
66struct viafb_pm_hooks {
67 struct list_head list;
68 int (*suspend)(void *private);
69 int (*resume)(void *private);
70 void *private;
71};
72
73void viafb_pm_register(struct viafb_pm_hooks *hooks);
74void 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 */