|
36 | 36 | #include <linux/pinctrl/pinconf.h>
|
37 | 37 | #include <linux/pinctrl/pinconf-generic.h>
|
38 | 38 |
|
| 39 | +#include "core.h" |
39 | 40 | #include "pinctrl-utils.h"
|
40 | 41 | #include "pinctrl-amd.h"
|
41 | 42 |
|
@@ -725,6 +726,69 @@ static const struct pinconf_ops amd_pinconf_ops = {
|
725 | 726 | .pin_config_group_set = amd_pinconf_group_set,
|
726 | 727 | };
|
727 | 728 |
|
| 729 | +#ifdef CONFIG_PM_SLEEP |
| 730 | +static bool amd_gpio_should_save(struct amd_gpio *gpio_dev, unsigned int pin) |
| 731 | +{ |
| 732 | + const struct pin_desc *pd = pin_desc_get(gpio_dev->pctrl, pin); |
| 733 | + |
| 734 | + if (!pd) |
| 735 | + return false; |
| 736 | + |
| 737 | + /* |
| 738 | + * Only restore the pin if it is actually in use by the kernel (or |
| 739 | + * by userspace). |
| 740 | + */ |
| 741 | + if (pd->mux_owner || pd->gpio_owner || |
| 742 | + gpiochip_line_is_irq(&gpio_dev->gc, pin)) |
| 743 | + return true; |
| 744 | + |
| 745 | + return false; |
| 746 | +} |
| 747 | + |
| 748 | +int amd_gpio_suspend(struct device *dev) |
| 749 | +{ |
| 750 | + struct platform_device *pdev = to_platform_device(dev); |
| 751 | + struct amd_gpio *gpio_dev = platform_get_drvdata(pdev); |
| 752 | + struct pinctrl_desc *desc = gpio_dev->pctrl->desc; |
| 753 | + int i; |
| 754 | + |
| 755 | + for (i = 0; i < desc->npins; i++) { |
| 756 | + int pin = desc->pins[i].number; |
| 757 | + |
| 758 | + if (!amd_gpio_should_save(gpio_dev, pin)) |
| 759 | + continue; |
| 760 | + |
| 761 | + gpio_dev->saved_regs[i] = readl(gpio_dev->base + pin*4); |
| 762 | + } |
| 763 | + |
| 764 | + return 0; |
| 765 | +} |
| 766 | + |
| 767 | +int amd_gpio_resume(struct device *dev) |
| 768 | +{ |
| 769 | + struct platform_device *pdev = to_platform_device(dev); |
| 770 | + struct amd_gpio *gpio_dev = platform_get_drvdata(pdev); |
| 771 | + struct pinctrl_desc *desc = gpio_dev->pctrl->desc; |
| 772 | + int i; |
| 773 | + |
| 774 | + for (i = 0; i < desc->npins; i++) { |
| 775 | + int pin = desc->pins[i].number; |
| 776 | + |
| 777 | + if (!amd_gpio_should_save(gpio_dev, pin)) |
| 778 | + continue; |
| 779 | + |
| 780 | + writel(gpio_dev->saved_regs[i], gpio_dev->base + pin*4); |
| 781 | + } |
| 782 | + |
| 783 | + return 0; |
| 784 | +} |
| 785 | + |
| 786 | +static const struct dev_pm_ops amd_gpio_pm_ops = { |
| 787 | + SET_LATE_SYSTEM_SLEEP_PM_OPS(amd_gpio_suspend, |
| 788 | + amd_gpio_resume) |
| 789 | +}; |
| 790 | +#endif |
| 791 | + |
728 | 792 | static struct pinctrl_desc amd_pinctrl_desc = {
|
729 | 793 | .pins = kerncz_pins,
|
730 | 794 | .npins = ARRAY_SIZE(kerncz_pins),
|
@@ -764,6 +828,14 @@ static int amd_gpio_probe(struct platform_device *pdev)
|
764 | 828 | return irq_base;
|
765 | 829 | }
|
766 | 830 |
|
| 831 | +#ifdef CONFIG_PM_SLEEP |
| 832 | + gpio_dev->saved_regs = devm_kcalloc(&pdev->dev, amd_pinctrl_desc.npins, |
| 833 | + sizeof(*gpio_dev->saved_regs), |
| 834 | + GFP_KERNEL); |
| 835 | + if (!gpio_dev->saved_regs) |
| 836 | + return -ENOMEM; |
| 837 | +#endif |
| 838 | + |
767 | 839 | gpio_dev->pdev = pdev;
|
768 | 840 | gpio_dev->gc.direction_input = amd_gpio_direction_input;
|
769 | 841 | gpio_dev->gc.direction_output = amd_gpio_direction_output;
|
@@ -853,6 +925,9 @@ static struct platform_driver amd_gpio_driver = {
|
853 | 925 | .driver = {
|
854 | 926 | .name = "amd_gpio",
|
855 | 927 | .acpi_match_table = ACPI_PTR(amd_gpio_acpi_match),
|
| 928 | +#ifdef CONFIG_PM_SLEEP |
| 929 | + .pm = &amd_gpio_pm_ops, |
| 930 | +#endif |
856 | 931 | },
|
857 | 932 | .probe = amd_gpio_probe,
|
858 | 933 | .remove = amd_gpio_remove,
|
|
0 commit comments