pinctrl: at91-pio4: handle suspend to ram
authorAlexandre Belloni <alexandre.belloni@free-electrons.com>
Thu, 6 Apr 2017 13:36:23 +0000 (15:36 +0200)
committerLinus Walleij <linus.walleij@linaro.org>
Fri, 7 Apr 2017 12:32:51 +0000 (14:32 +0200)
When suspending to RAM, the power to the core is cut and the register
values are lost. Save and restore more registers than just IMR.

Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
drivers/pinctrl/pinctrl-at91-pio4.c

index 28bbc1bb9e6c4c959c39c9711a170251ad77e274..dc8591543deede05dda815d3dbaf654e31b5b798 100644 (file)
@@ -126,7 +126,11 @@ struct atmel_pioctrl {
        struct irq_domain       *irq_domain;
        int                     *irqs;
        unsigned                *pm_wakeup_sources;
-       unsigned                *pm_suspend_backup;
+       struct {
+               u32             imr;
+               u32             odsr;
+               u32             cfgr[ATMEL_PIO_NPINS_PER_BANK];
+       } *pm_suspend_backup;
        struct device           *dev;
        struct device_node      *node;
 };
@@ -830,17 +834,26 @@ static int __maybe_unused atmel_pctrl_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev);
-       int i;
+       int i, j;
 
        /*
         * For each bank, save IMR to restore it later and disable all GPIO
         * interrupts excepting the ones marked as wakeup sources.
         */
        for (i = 0; i < atmel_pioctrl->nbanks; i++) {
-               atmel_pioctrl->pm_suspend_backup[i] =
+               atmel_pioctrl->pm_suspend_backup[i].imr =
                        atmel_gpio_read(atmel_pioctrl, i, ATMEL_PIO_IMR);
                atmel_gpio_write(atmel_pioctrl, i, ATMEL_PIO_IDR,
                                 ~atmel_pioctrl->pm_wakeup_sources[i]);
+               atmel_pioctrl->pm_suspend_backup[i].odsr =
+                       atmel_gpio_read(atmel_pioctrl, i, ATMEL_PIO_ODSR);
+               for (j = 0; j < ATMEL_PIO_NPINS_PER_BANK; j++) {
+                       atmel_gpio_write(atmel_pioctrl, i,
+                                        ATMEL_PIO_MSKR, BIT(j));
+                       atmel_pioctrl->pm_suspend_backup[i].cfgr[j] =
+                               atmel_gpio_read(atmel_pioctrl, i,
+                                               ATMEL_PIO_CFGR);
+               }
        }
 
        return 0;
@@ -850,11 +863,20 @@ static int __maybe_unused atmel_pctrl_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct atmel_pioctrl *atmel_pioctrl = platform_get_drvdata(pdev);
-       int i;
+       int i, j;
 
-       for (i = 0; i < atmel_pioctrl->nbanks; i++)
+       for (i = 0; i < atmel_pioctrl->nbanks; i++) {
                atmel_gpio_write(atmel_pioctrl, i, ATMEL_PIO_IER,
-                                atmel_pioctrl->pm_suspend_backup[i]);
+                                atmel_pioctrl->pm_suspend_backup[i].imr);
+               atmel_gpio_write(atmel_pioctrl, i, ATMEL_PIO_SODR,
+                                atmel_pioctrl->pm_suspend_backup[i].odsr);
+               for (j = 0; j < ATMEL_PIO_NPINS_PER_BANK; j++) {
+                       atmel_gpio_write(atmel_pioctrl, i,
+                                        ATMEL_PIO_MSKR, BIT(j));
+                       atmel_gpio_write(atmel_pioctrl, i, ATMEL_PIO_CFGR,
+                                        atmel_pioctrl->pm_suspend_backup[i].cfgr[j]);
+               }
+       }
 
        return 0;
 }