Commit 751305d9b2fd3e03eaab7808e976241d85ca4353
Committed by
Florian Tobias Schandinat
1 parent
51f4332bb5
Exists in
master
and in
7 other branches
viafb: General power management infrastructure
Multiple devices need S/R hooks (framebuffer, GPIO, camera). Add infrastructure and convert existing framebuffer code to the new model. This patch should create no functional change. Based on earlier work by Jonathan Corbet. Signed-off-by: Daniel Drake <dsd@laptop.org> Acked-by: Jonathan Corbet <corbet@lwn.net> Signed-off-by: Florian Tobias Schandinat <FlorianSchandinat@gmx.de>
Showing 4 changed files with 107 additions and 23 deletions Side-by-side Diff
drivers/video/via/via-core.c
... | ... | @@ -15,6 +15,8 @@ |
15 | 15 | #include <linux/module.h> |
16 | 16 | #include <linux/interrupt.h> |
17 | 17 | #include <linux/platform_device.h> |
18 | +#include <linux/list.h> | |
19 | +#include <linux/pm.h> | |
18 | 20 | |
19 | 21 | /* |
20 | 22 | * The default port config. |
21 | 23 | |
... | ... | @@ -563,7 +565,79 @@ |
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); | |
566 | 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 */ | |
640 | + | |
567 | 641 | static int __devinit via_pci_probe(struct pci_dev *pdev, |
568 | 642 | const struct pci_device_id *ent) |
569 | 643 | { |
... | ... | @@ -572,6 +646,7 @@ |
572 | 646 | ret = pci_enable_device(pdev); |
573 | 647 | if (ret) |
574 | 648 | return ret; |
649 | + | |
575 | 650 | /* |
576 | 651 | * Global device initialization. |
577 | 652 | */ |
... | ... | @@ -651,8 +726,8 @@ |
651 | 726 | .probe = via_pci_probe, |
652 | 727 | .remove = __devexit_p(via_pci_remove), |
653 | 728 | #ifdef CONFIG_PM |
654 | - .suspend = viafb_suspend, | |
655 | - .resume = viafb_resume, | |
729 | + .suspend = via_suspend, | |
730 | + .resume = via_resume, | |
656 | 731 | #endif |
657 | 732 | }; |
658 | 733 |
drivers/video/via/viafbdev.c
... | ... | @@ -1672,31 +1672,19 @@ |
1672 | 1672 | |
1673 | 1673 | |
1674 | 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) { | |
1678 | - acquire_console_sem(); | |
1679 | - fb_set_suspend(viafbinfo, 1); | |
1677 | + acquire_console_sem(); | |
1678 | + fb_set_suspend(viafbinfo, 1); | |
1679 | + viafb_sync(viafbinfo); | |
1680 | + release_console_sem(); | |
1680 | 1681 | |
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 | - | |
1689 | 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 | 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 | 1688 | if (viaparinfo->shared->vdev->engine_mmio) |
1701 | 1689 | viafb_reset_engine(viaparinfo); |
1702 | 1690 | viafb_set_par(viafbinfo); |
1703 | 1691 | |
... | ... | @@ -1704,11 +1692,15 @@ |
1704 | 1692 | viafb_set_par(viafbinfo1); |
1705 | 1693 | fb_set_suspend(viafbinfo, 0); |
1706 | 1694 | |
1707 | -fail: | |
1708 | 1695 | release_console_sem(); |
1709 | 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 | 1704 | #endif |
1713 | 1705 | |
1714 | 1706 | |
... | ... | @@ -1899,6 +1891,10 @@ |
1899 | 1891 | |
1900 | 1892 | viafb_init_proc(viaparinfo->shared); |
1901 | 1893 | viafb_init_dac(IGA2); |
1894 | + | |
1895 | +#ifdef CONFIG_PM | |
1896 | + viafb_pm_register(&viafb_fb_pm_hooks); | |
1897 | +#endif | |
1902 | 1898 | return 0; |
1903 | 1899 | |
1904 | 1900 | out_fb_unreg: |
drivers/video/via/viafbdev.h
include/linux/via-core.h
... | ... | @@ -60,6 +60,21 @@ |
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 | 78 | * This is the global viafb "device" containing stuff needed by |
64 | 79 | * all subdevs. |
65 | 80 | */ |