Commit dc7c0b6a6d28b0de231728de963ed53a9cee85cf
Exists in
master
and in
4 other branches
Merge branch 'viafb-next' of git://github.com/schandinat/linux-2.6
Showing 5 changed files Side-by-side Diff
drivers/video/via/via-core.c
... | ... | @@ -15,6 +15,9 @@ |
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> | |
20 | +#include <asm/olpc.h> | |
18 | 21 | |
19 | 22 | /* |
20 | 23 | * The default port config. |
... | ... | @@ -29,6 +32,19 @@ |
29 | 32 | }; |
30 | 33 | |
31 | 34 | /* |
35 | + * The OLPC XO-1.5 puts the camera power and reset lines onto | |
36 | + * GPIO 2C. | |
37 | + */ | |
38 | +static const struct via_port_cfg olpc_adap_configs[] = { | |
39 | + [VIA_PORT_26] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x26 }, | |
40 | + [VIA_PORT_31] = { VIA_PORT_I2C, VIA_MODE_I2C, VIASR, 0x31 }, | |
41 | + [VIA_PORT_25] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x25 }, | |
42 | + [VIA_PORT_2C] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x2c }, | |
43 | + [VIA_PORT_3D] = { VIA_PORT_GPIO, VIA_MODE_GPIO, VIASR, 0x3d }, | |
44 | + { 0, 0, 0, 0 } | |
45 | +}; | |
46 | + | |
47 | +/* | |
32 | 48 | * We currently only support one viafb device (will there ever be |
33 | 49 | * more than one?), so just declare it globally here. |
34 | 50 | */ |
35 | 51 | |
... | ... | @@ -575,7 +591,79 @@ |
575 | 591 | } |
576 | 592 | } |
577 | 593 | |
594 | +/* | |
595 | + * Power management functions | |
596 | + */ | |
597 | +#ifdef CONFIG_PM | |
598 | +static LIST_HEAD(viafb_pm_hooks); | |
599 | +static DEFINE_MUTEX(viafb_pm_hooks_lock); | |
578 | 600 | |
601 | +void viafb_pm_register(struct viafb_pm_hooks *hooks) | |
602 | +{ | |
603 | + INIT_LIST_HEAD(&hooks->list); | |
604 | + | |
605 | + mutex_lock(&viafb_pm_hooks_lock); | |
606 | + list_add_tail(&hooks->list, &viafb_pm_hooks); | |
607 | + mutex_unlock(&viafb_pm_hooks_lock); | |
608 | +} | |
609 | +EXPORT_SYMBOL_GPL(viafb_pm_register); | |
610 | + | |
611 | +void viafb_pm_unregister(struct viafb_pm_hooks *hooks) | |
612 | +{ | |
613 | + mutex_lock(&viafb_pm_hooks_lock); | |
614 | + list_del(&hooks->list); | |
615 | + mutex_unlock(&viafb_pm_hooks_lock); | |
616 | +} | |
617 | +EXPORT_SYMBOL_GPL(viafb_pm_unregister); | |
618 | + | |
619 | +static int via_suspend(struct pci_dev *pdev, pm_message_t state) | |
620 | +{ | |
621 | + struct viafb_pm_hooks *hooks; | |
622 | + | |
623 | + if (state.event != PM_EVENT_SUSPEND) | |
624 | + return 0; | |
625 | + /* | |
626 | + * "I've occasionally hit a few drivers that caused suspend | |
627 | + * failures, and each and every time it was a driver bug, and | |
628 | + * the right thing to do was to just ignore the error and suspend | |
629 | + * anyway - returning an error code and trying to undo the suspend | |
630 | + * is not what anybody ever really wants, even if our model | |
631 | + *_allows_ for it." | |
632 | + * -- Linus Torvalds, Dec. 7, 2009 | |
633 | + */ | |
634 | + mutex_lock(&viafb_pm_hooks_lock); | |
635 | + list_for_each_entry_reverse(hooks, &viafb_pm_hooks, list) | |
636 | + hooks->suspend(hooks->private); | |
637 | + mutex_unlock(&viafb_pm_hooks_lock); | |
638 | + | |
639 | + pci_save_state(pdev); | |
640 | + pci_disable_device(pdev); | |
641 | + pci_set_power_state(pdev, pci_choose_state(pdev, state)); | |
642 | + return 0; | |
643 | +} | |
644 | + | |
645 | +static int via_resume(struct pci_dev *pdev) | |
646 | +{ | |
647 | + struct viafb_pm_hooks *hooks; | |
648 | + | |
649 | + /* Get the bus side powered up */ | |
650 | + pci_set_power_state(pdev, PCI_D0); | |
651 | + pci_restore_state(pdev); | |
652 | + if (pci_enable_device(pdev)) | |
653 | + return 0; | |
654 | + | |
655 | + pci_set_master(pdev); | |
656 | + | |
657 | + /* Now bring back any subdevs */ | |
658 | + mutex_lock(&viafb_pm_hooks_lock); | |
659 | + list_for_each_entry(hooks, &viafb_pm_hooks, list) | |
660 | + hooks->resume(hooks->private); | |
661 | + mutex_unlock(&viafb_pm_hooks_lock); | |
662 | + | |
663 | + return 0; | |
664 | +} | |
665 | +#endif /* CONFIG_PM */ | |
666 | + | |
579 | 667 | static int __devinit via_pci_probe(struct pci_dev *pdev, |
580 | 668 | const struct pci_device_id *ent) |
581 | 669 | { |
... | ... | @@ -584,6 +672,7 @@ |
584 | 672 | ret = pci_enable_device(pdev); |
585 | 673 | if (ret) |
586 | 674 | return ret; |
675 | + | |
587 | 676 | /* |
588 | 677 | * Global device initialization. |
589 | 678 | */ |
... | ... | @@ -591,6 +680,9 @@ |
591 | 680 | global_dev.pdev = pdev; |
592 | 681 | global_dev.chip_type = ent->driver_data; |
593 | 682 | global_dev.port_cfg = adap_configs; |
683 | + if (machine_is_olpc()) | |
684 | + global_dev.port_cfg = olpc_adap_configs; | |
685 | + | |
594 | 686 | spin_lock_init(&global_dev.reg_lock); |
595 | 687 | ret = via_pci_setup_mmio(&global_dev); |
596 | 688 | if (ret) |
... | ... | @@ -663,8 +755,8 @@ |
663 | 755 | .probe = via_pci_probe, |
664 | 756 | .remove = __devexit_p(via_pci_remove), |
665 | 757 | #ifdef CONFIG_PM |
666 | - .suspend = viafb_suspend, | |
667 | - .resume = viafb_resume, | |
758 | + .suspend = via_suspend, | |
759 | + .resume = via_resume, | |
668 | 760 | #endif |
669 | 761 | }; |
670 | 762 |
drivers/video/via/via-gpio.c
... | ... | @@ -172,6 +172,28 @@ |
172 | 172 | via_write_reg_mask(VIASR, gpio->vg_port_index, 0, 0x02); |
173 | 173 | } |
174 | 174 | |
175 | +#ifdef CONFIG_PM | |
176 | + | |
177 | +static int viafb_gpio_suspend(void *private) | |
178 | +{ | |
179 | + return 0; | |
180 | +} | |
181 | + | |
182 | +static int viafb_gpio_resume(void *private) | |
183 | +{ | |
184 | + int i; | |
185 | + | |
186 | + for (i = 0; i < gpio_config.gpio_chip.ngpio; i += 2) | |
187 | + viafb_gpio_enable(gpio_config.active_gpios[i]); | |
188 | + return 0; | |
189 | +} | |
190 | + | |
191 | +static struct viafb_pm_hooks viafb_gpio_pm_hooks = { | |
192 | + .suspend = viafb_gpio_suspend, | |
193 | + .resume = viafb_gpio_resume | |
194 | +}; | |
195 | +#endif /* CONFIG_PM */ | |
196 | + | |
175 | 197 | /* |
176 | 198 | * Look up a specific gpio and return the number it was assigned. |
177 | 199 | */ |
... | ... | @@ -236,6 +258,9 @@ |
236 | 258 | printk(KERN_ERR "viafb: failed to add gpios (%d)\n", ret); |
237 | 259 | gpio_config.gpio_chip.ngpio = 0; |
238 | 260 | } |
261 | +#ifdef CONFIG_PM | |
262 | + viafb_pm_register(&viafb_gpio_pm_hooks); | |
263 | +#endif | |
239 | 264 | return ret; |
240 | 265 | } |
241 | 266 | |
... | ... | @@ -244,6 +269,10 @@ |
244 | 269 | { |
245 | 270 | unsigned long flags; |
246 | 271 | int ret = 0, i; |
272 | + | |
273 | +#ifdef CONFIG_PM | |
274 | + viafb_pm_unregister(&viafb_gpio_pm_hooks); | |
275 | +#endif | |
247 | 276 | |
248 | 277 | /* |
249 | 278 | * Get unregistered. |
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 | */ |