[ARM] pxa: allow dynamic enable/disable of GPIO wakeup for pxa{25x,27x}
authoreric miao <eric.miao@marvell.com>
Tue, 11 Mar 2008 01:46:28 +0000 (09:46 +0800)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Sat, 19 Apr 2008 10:29:05 +0000 (11:29 +0100)
Changes include:

1. rename MFP_LPM_WAKEUP_ENABLE into MFP_LPM_CAN_WAKEUP to indicate
   the board capability of this pin to wakeup the system

2. add gpio_set_wake() and keypad_set_wake() to allow dynamically
   enable/disable wakeup from GPIOs and keypad GPIO

   * these functions are currently kept in mfp-pxa2xx.c due to their
     dependency to the MFP configuration

3. pxa2xx_mfp_config() only gives early warning if MFP_LPM_CAN_WAKEUP
   is set on incorrect pins

So that the GPIO's wakeup capability is now decided by the following:

   a) processor's capability: (only those GPIOs which have dedicated
      bits within PWER/PRER/PFER can wakeup the system), this is
      initialized by pxa{25x,27x}_init_mfp()

   b) board design decides:
      - whether the pin is designed to wakeup the system (some of
        the GPIOs are configured as other functions, which is not
        intended to be a wakeup source), by OR'ing the pin config
        with MFP_LPM_CAN_WAKEUP

      - which edge the pin is designed to wakeup the system, this
        may depends on external peripherals/connections, which is
        totally board specific; this is indicated by MFP_LPM_EDGE_*

   c) the corresponding device's (most likely the gpio_keys.c) wakeup
      attribute:

Signed-off-by: eric miao <eric.miao@marvell.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
arch/arm/mach-pxa/mfp-pxa2xx.c
arch/arm/mach-pxa/pxa25x.c
arch/arm/mach-pxa/pxa27x.c
include/asm-arm/arch-pxa/mfp-pxa27x.h
include/asm-arm/arch-pxa/mfp-pxa2xx.h

index f85f681..22097a1 100644 (file)
 
 #define PWER_WE35      (1 << 24)
 
-static struct {
+struct gpio_desc {
        unsigned        valid           : 1;
        unsigned        can_wakeup      : 1;
        unsigned        keypad_gpio     : 1;
        unsigned int    mask; /* bit mask in PWER or PKWR */
        unsigned long   config;
-} gpio_desc[MFP_PIN_GPIO127 + 1];
+};
+
+static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1];
 
-static inline int __mfp_config_gpio(unsigned gpio, unsigned long c)
+static int __mfp_config_gpio(unsigned gpio, unsigned long c)
 {
        unsigned long gafr, mask = GPIO_bit(gpio);
        int fn;
@@ -70,26 +72,19 @@ static inline int __mfp_config_gpio(unsigned gpio, unsigned long c)
                return -EINVAL;
        }
 
-       /* wakeup enabling */
-       if ((c & MFP_LPM_WAKEUP_ENABLE) == 0)
-               return 0;
-
-       if (!gpio_desc[gpio].can_wakeup || c & MFP_DIR_OUT) {
+       /* give early warning if MFP_LPM_CAN_WAKEUP is set on the
+        * configurations of those pins not able to wakeup
+        */
+       if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) {
                pr_warning("%s: GPIO%d unable to wakeup\n",
                                __func__, gpio);
                return -EINVAL;
        }
 
-       if (gpio_desc[gpio].keypad_gpio)
-               PKWR |= gpio_desc[gpio].mask;
-       else {
-               PWER |= gpio_desc[gpio].mask;
-
-               if (c & MFP_LPM_EDGE_RISE)
-                       PRER |= gpio_desc[gpio].mask;
-
-               if (c & MFP_LPM_EDGE_FALL)
-                       PFER |= gpio_desc[gpio].mask;
+       if ((c & MFP_LPM_CAN_WAKEUP) && (c & MFP_DIR_OUT)) {
+               pr_warning("%s: output GPIO%d unable to wakeup\n",
+                               __func__, gpio);
+               return -EINVAL;
        }
 
        return 0;
@@ -120,6 +115,45 @@ void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num)
        }
 }
 
+int gpio_set_wake(unsigned int gpio, unsigned int on)
+{
+       struct gpio_desc *d;
+       unsigned long c;
+
+       if (gpio > mfp_to_gpio(MFP_PIN_GPIO127))
+               return -EINVAL;
+
+       d = &gpio_desc[gpio];
+       c = d->config;
+
+       if (!d->valid)
+               return -EINVAL;
+
+       if (d->keypad_gpio)
+               return -EINVAL;
+
+       if (d->can_wakeup && (c & MFP_LPM_CAN_WAKEUP)) {
+               if (on) {
+                       PWER |= d->mask;
+
+                       if (c & MFP_LPM_EDGE_RISE)
+                               PRER |= d->mask;
+                       else
+                               PRER &= ~d->mask;
+
+                       if (c & MFP_LPM_EDGE_FALL)
+                               PFER |= d->mask;
+                       else
+                               PFER &= ~d->mask;
+               } else {
+                       PWER &= ~d->mask;
+                       PRER &= ~d->mask;
+                       PFER &= ~d->mask;
+               }
+       }
+       return 0;
+}
+
 #ifdef CONFIG_PXA25x
 static int __init pxa25x_mfp_init(void)
 {
@@ -141,11 +175,32 @@ postcore_initcall(pxa25x_mfp_init);
 #endif /* CONFIG_PXA25x */
 
 #ifdef CONFIG_PXA27x
-static int pxa27x_pkwr_gpio[] __initdata = {
+static int pxa27x_pkwr_gpio[] = {
        13, 16, 17, 34, 36, 37, 38, 39, 90, 91, 93, 94,
        95, 96, 97, 98, 99, 100, 101, 102
 };
 
+int keypad_set_wake(unsigned int on)
+{
+       unsigned int i, gpio, mask = 0;
+
+       if (!on) {
+               PKWR = 0;
+               return 0;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) {
+
+               gpio = pxa27x_pkwr_gpio[i];
+
+               if (gpio_desc[gpio].config & MFP_LPM_CAN_WAKEUP)
+                       mask |= gpio_desc[gpio].mask;
+       }
+
+       PKWR = mask;
+       return 0;
+}
+
 static int __init pxa27x_mfp_init(void)
 {
        int i, gpio;
index 653a3b6..c486c30 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/hardware.h>
 #include <asm/arch/irqs.h>
 #include <asm/arch/pxa-regs.h>
+#include <asm/arch/mfp-pxa25x.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/dma.h>
 
@@ -230,24 +231,10 @@ static inline void pxa25x_init_pm(void) {}
 static int pxa25x_set_wake(unsigned int irq, unsigned int on)
 {
        int gpio = IRQ_TO_GPIO(irq);
-       uint32_t gpio_bit, mask = 0;
-
-       if (gpio >= 0 && gpio <= 15) {
-               gpio_bit = GPIO_bit(gpio);
-               mask = gpio_bit;
-               if (on) {
-                       if (GRER(gpio) | gpio_bit)
-                               PRER |= gpio_bit;
-                       else
-                               PRER &= ~gpio_bit;
-
-                       if (GFER(gpio) | gpio_bit)
-                               PFER |= gpio_bit;
-                       else
-                               PFER &= ~gpio_bit;
-               }
-               goto set_pwer;
-       }
+       uint32_t mask = 0;
+
+       if (gpio >= 0 && gpio < 85)
+               return gpio_set_wake(gpio, on);
 
        if (irq == IRQ_RTCAlrm) {
                mask = PWER_RTC;
index 87ade40..b230af2 100644 (file)
@@ -23,6 +23,7 @@
 #include <asm/arch/irqs.h>
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/pxa2xx-regs.h>
+#include <asm/arch/mfp-pxa27x.h>
 #include <asm/arch/ohci.h>
 #include <asm/arch/pm.h>
 #include <asm/arch/dma.h>
@@ -286,37 +287,16 @@ static inline void pxa27x_init_pm(void) {}
 /* PXA27x:  Various gpios can issue wakeup events.  This logic only
  * handles the simple cases, not the WEMUX2 and WEMUX3 options
  */
-#define PXA27x_GPIO_NOWAKE_MASK \
-        ((1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 2))
-#define WAKEMASK(gpio) \
-        (((gpio) <= 15) \
-                 ? ((1 << (gpio)) & ~PXA27x_GPIO_NOWAKE_MASK) \
-                 : ((gpio == 35) ? (1 << 24) : 0))
-
 static int pxa27x_set_wake(unsigned int irq, unsigned int on)
 {
        int gpio = IRQ_TO_GPIO(irq);
        uint32_t mask;
 
-       if ((gpio >= 0 && gpio <= 15) || (gpio == 35)) {
-               if (WAKEMASK(gpio) == 0)
-                       return -EINVAL;
-
-               mask = WAKEMASK(gpio);
-
-               if (on) {
-                       if (GRER(gpio) | GPIO_bit(gpio))
-                               PRER |= mask;
-                       else
-                               PRER &= ~mask;
+       if (gpio >= 0 && gpio < 128)
+               return gpio_set_wake(gpio, on);
 
-                       if (GFER(gpio) | GPIO_bit(gpio))
-                               PFER |= mask;
-                       else
-                               PFER &= ~mask;
-               }
-               goto set_pwer;
-       }
+       if (irq == IRQ_KEYPAD)
+               return keypad_set_wake(on);
 
        switch (irq) {
        case IRQ_RTCAlrm:
@@ -329,7 +309,6 @@ static int pxa27x_set_wake(unsigned int irq, unsigned int on)
                return -EINVAL;
        }
 
-set_pwer:
        if (on)
                PWER |= mask;
        else
index 65dfaa9..eb6eaa1 100644 (file)
 #define GPIO112_nMSINS         MFP_CFG_IN(GPIO112, AF2)
 #define GPIO32_MSSCLK          MFP_CFG_OUT(GPIO32, AF1, DRIVE_LOW)
 
+extern int keypad_set_wake(unsigned int on);
 #endif /* __ASM_ARCH_MFP_PXA27X_H */
index bec6acf..db8d890 100644 (file)
 #define MFP_DIR_MASK           (0x1 << 23)
 #define MFP_DIR(x)             (((x) >> 23) & 0x1)
 
-#define MFP_LPM_WAKEUP_ENABLE  (0x1 << 24)
-#define WAKEUP_ON_EDGE_RISE    (MFP_LPM_WAKEUP_ENABLE | MFP_LPM_EDGE_RISE)
-#define WAKEUP_ON_EDGE_FALL    (MFP_LPM_WAKEUP_ENABLE | MFP_LPM_EDGE_FALL)
-#define WAKEUP_ON_EDGE_BOTH    (MFP_LPM_WAKEUP_ENABLE | MFP_LPM_EDGE_BOTH)
+#define MFP_LPM_CAN_WAKEUP     (0x1 << 24)
+#define WAKEUP_ON_EDGE_RISE    (MFP_LPM_CAN_WAKEUP | MFP_LPM_EDGE_RISE)
+#define WAKEUP_ON_EDGE_FALL    (MFP_LPM_CAN_WAKEUP | MFP_LPM_EDGE_FALL)
+#define WAKEUP_ON_EDGE_BOTH    (MFP_LPM_CAN_WAKEUP | MFP_LPM_EDGE_BOTH)
 
 /* specifically for enabling wakeup on keypad GPIOs */
-#define WAKEUP_ON_LEVEL_HIGH   (MFP_LPM_WAKEUP_ENABLE)
+#define WAKEUP_ON_LEVEL_HIGH   (MFP_LPM_CAN_WAKEUP)
 
 #define MFP_CFG_IN(pin, af)            \
        ((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DIR_MASK)) |\
 #define GPIO84_GPIO    MFP_CFG_IN(GPIO84, AF0)
 
 extern void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num);
+extern int gpio_set_wake(unsigned int gpio, unsigned int on);
 #endif /* __ASM_ARCH_MFP_PXA2XX_H */