summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-at91/pm.c15
-rw-r--r--drivers/pinctrl/pinctrl-at91.c79
-rw-r--r--include/soc/at91/pm.h16
3 files changed, 36 insertions, 74 deletions
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index df6d673e83d5..a695710142db 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -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;
}
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 0b78fd48fd02..631a6289c2b6 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -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
index 7a41e53a3ffa..000000000000
--- a/include/soc/at91/pm.h
+++ /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 */