Commit 751305d9b2fd3e03eaab7808e976241d85ca4353

Authored by Daniel Drake
Committed by Florian Tobias Schandinat
1 parent 51f4332bb5

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
... ... @@ -108,7 +108,5 @@
108 108 /* Temporary */
109 109 int viafb_init(void);
110 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 111 #endif /* __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 */