pinctrl: at91: move gpio suspend/resume calls to driver's context
authorClaudiu Beznea <claudiu.beznea@microchip.com>
Wed, 31 Aug 2022 13:56:35 +0000 (16:56 +0300)
committerLinus Walleij <linus.walleij@linaro.org>
Fri, 2 Sep 2022 22:19:23 +0000 (00:19 +0200)
Move gpio suspend/resume execution local to driver and let it execute as
close as possible to the moment the machine specific PM code is executed
(by setting it to .noirq member of dev_pm_ops). With this the
at91_pinctrl_gpio_suspend()/at91_pinctrl_gpio_resume() calls were removed
from arch/arm/mach-at91/pm.c and also a header has been removed.
The patch has been checked on sama5d3_xplained, sam9x60ek,
sama5d2_xplained, sama7g5ek boards.

Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
Link: https://lore.kernel.org/r/20220831135636.3176406-3-claudiu.beznea@microchip.com
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
arch/arm/mach-at91/pm.c
drivers/pinctrl/pinctrl-at91.c
include/soc/at91/pm.h [deleted file]

index df6d673..a695710 100644 (file)
@@ -19,8 +19,6 @@
 #include <linux/clk/at91_pmc.h>
 #include <linux/platform_data/atmel.h>
 
-#include <soc/at91/pm.h>
-
 #include <asm/cacheflush.h>
 #include <asm/fncpy.h>
 #include <asm/system_misc.h>
@@ -624,16 +622,6 @@ static int at91_pm_enter(suspend_state_t state)
        if (ret)
                return ret;
 
-#ifdef CONFIG_PINCTRL_AT91
-       /*
-        * FIXME: this is needed to communicate between the pinctrl driver and
-        * the PM implementation in the machine. Possibly part of the PM
-        * implementation should be moved down into the pinctrl driver and get
-        * called as part of the generic suspend/resume path.
-        */
-       at91_pinctrl_gpio_suspend();
-#endif
-
        switch (state) {
        case PM_SUSPEND_MEM:
        case PM_SUSPEND_STANDBY:
@@ -658,9 +646,6 @@ static int at91_pm_enter(suspend_state_t state)
        }
 
 error:
-#ifdef CONFIG_PINCTRL_AT91
-       at91_pinctrl_gpio_resume();
-#endif
        at91_pm_config_quirks(false);
        return 0;
 }
index 0b78fd4..631a628 100644 (file)
@@ -22,8 +22,7 @@
 #include <linux/pinctrl/pinmux.h>
 /* Since we request GPIOs from ourself */
 #include <linux/pinctrl/consumer.h>
-
-#include <soc/at91/pm.h>
+#include <linux/pm.h>
 
 #include "pinctrl-at91.h"
 #include "core.h"
@@ -44,6 +43,9 @@ struct at91_pinctrl_mux_ops;
  * @regbase: PIO bank virtual address
  * @clock: associated clock
  * @ops: at91 pinctrl mux ops
+ * @wakeups: wakeup interrupts
+ * @backups: interrupts disabled in suspend
+ * @id: gpio chip identifier
  */
 struct at91_gpio_chip {
        struct gpio_chip        chip;
@@ -55,6 +57,9 @@ struct at91_gpio_chip {
        void __iomem            *regbase;
        struct clk              *clock;
        const struct at91_pinctrl_mux_ops *ops;
+       u32                     wakeups;
+       u32                     backups;
+       u32                     id;
 };
 
 static struct at91_gpio_chip *gpio_chips[MAX_GPIO_BANKS];
@@ -1627,70 +1632,51 @@ static void gpio_irq_ack(struct irq_data *d)
        /* the interrupt is already cleared before by reading ISR */
 }
 
-static u32 wakeups[MAX_GPIO_BANKS];
-static u32 backups[MAX_GPIO_BANKS];
-
 static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
 {
        struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
-       unsigned        bank = at91_gpio->pioc_idx;
        unsigned mask = 1 << d->hwirq;
 
-       if (unlikely(bank >= MAX_GPIO_BANKS))
-               return -EINVAL;
-
        if (state)
-               wakeups[bank] |= mask;
+               at91_gpio->wakeups |= mask;
        else
-               wakeups[bank] &= ~mask;
+               at91_gpio->wakeups &= ~mask;
 
        irq_set_irq_wake(at91_gpio->pioc_virq, state);
 
        return 0;
 }
 
-void at91_pinctrl_gpio_suspend(void)
+static int at91_gpio_suspend(struct device *dev)
 {
-       int i;
+       struct at91_gpio_chip *at91_chip = dev_get_drvdata(dev);
+       void __iomem *pio = at91_chip->regbase;
 
-       for (i = 0; i < gpio_banks; i++) {
-               void __iomem  *pio;
+       at91_chip->backups = readl_relaxed(pio + PIO_IMR);
+       writel_relaxed(at91_chip->backups, pio + PIO_IDR);
+       writel_relaxed(at91_chip->wakeups, pio + PIO_IER);
 
-               if (!gpio_chips[i])
-                       continue;
-
-               pio = gpio_chips[i]->regbase;
-
-               backups[i] = readl_relaxed(pio + PIO_IMR);
-               writel_relaxed(backups[i], pio + PIO_IDR);
-               writel_relaxed(wakeups[i], pio + PIO_IER);
+       if (!at91_chip->wakeups)
+               clk_disable_unprepare(at91_chip->clock);
+       else
+               printk(KERN_DEBUG "GPIO-%c may wake for %08x\n",
+                      'A' + at91_chip->id, at91_chip->wakeups);
 
-               if (!wakeups[i])
-                       clk_disable_unprepare(gpio_chips[i]->clock);
-               else
-                       printk(KERN_DEBUG "GPIO-%c may wake for %08x\n",
-                              'A'+i, wakeups[i]);
-       }
+       return 0;
 }
 
-void at91_pinctrl_gpio_resume(void)
+static int at91_gpio_resume(struct device *dev)
 {
-       int i;
+       struct at91_gpio_chip *at91_chip = dev_get_drvdata(dev);
+       void __iomem *pio = at91_chip->regbase;
 
-       for (i = 0; i < gpio_banks; i++) {
-               void __iomem  *pio;
-
-               if (!gpio_chips[i])
-                       continue;
+       if (!at91_chip->wakeups)
+               clk_prepare_enable(at91_chip->clock);
 
-               pio = gpio_chips[i]->regbase;
+       writel_relaxed(at91_chip->wakeups, pio + PIO_IDR);
+       writel_relaxed(at91_chip->backups, pio + PIO_IER);
 
-               if (!wakeups[i])
-                       clk_prepare_enable(gpio_chips[i]->clock);
-
-               writel_relaxed(wakeups[i], pio + PIO_IDR);
-               writel_relaxed(backups[i], pio + PIO_IER);
-       }
+       return 0;
 }
 
 static void gpio_irq_handler(struct irq_desc *desc)
@@ -1872,6 +1858,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
        }
 
        at91_chip->chip = at91_gpio_template;
+       at91_chip->id = alias_idx;
 
        chip = &at91_chip->chip;
        chip->label = dev_name(&pdev->dev);
@@ -1917,6 +1904,7 @@ static int at91_gpio_probe(struct platform_device *pdev)
                goto gpiochip_add_err;
 
        gpio_chips[alias_idx] = at91_chip;
+       platform_set_drvdata(pdev, at91_chip);
        gpio_banks = max(gpio_banks, alias_idx + 1);
 
        dev_info(&pdev->dev, "at address %p\n", at91_chip->regbase);
@@ -1932,10 +1920,15 @@ err:
        return ret;
 }
 
+static const struct dev_pm_ops at91_gpio_pm_ops = {
+       SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(at91_gpio_suspend, at91_gpio_resume)
+};
+
 static struct platform_driver at91_gpio_driver = {
        .driver = {
                .name = "gpio-at91",
                .of_match_table = at91_gpio_of_match,
+               .pm = pm_ptr(&at91_gpio_pm_ops),
        },
        .probe = at91_gpio_probe,
 };
diff --git a/include/soc/at91/pm.h b/include/soc/at91/pm.h
deleted file mode 100644 (file)
index 7a41e53..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * Atmel Power Management
- *
- * Copyright (C) 2020 Atmel
- *
- * Author: Lee Jones <lee.jones@linaro.org>
- */
-
-#ifndef __SOC_ATMEL_PM_H
-#define __SOC_ATMEL_PM_H
-
-void at91_pinctrl_gpio_suspend(void);
-void at91_pinctrl_gpio_resume(void);
-
-#endif /* __SOC_ATMEL_PM_H */