summaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authoreric miao <eric.miao@marvell.com>2008-03-11 02:46:28 +0100
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-04-19 12:29:05 +0200
commitc0a596d6a138ea281bed4ff3018c07c45dd245a2 (patch)
treeab3c25663433bf8c3f16026d969f9722d4ecff92 /arch/arm
parent[ARM] pxa: use new pin configuration mechanism for lubbock (diff)
downloadlinux-c0a596d6a138ea281bed4ff3018c07c45dd245a2.tar.xz
linux-c0a596d6a138ea281bed4ff3018c07c45dd245a2.zip
[ARM] pxa: allow dynamic enable/disable of GPIO wakeup for pxa{25x,27x}
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>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.c93
-rw-r--r--arch/arm/mach-pxa/pxa25x.c23
-rw-r--r--arch/arm/mach-pxa/pxa27x.c31
3 files changed, 84 insertions, 63 deletions
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index f85f681c0393..22097a1707cc 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -28,15 +28,17 @@
#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;
diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
index 653a3b63d073..c486c3055cfb 100644
--- a/arch/arm/mach-pxa/pxa25x.c
+++ b/arch/arm/mach-pxa/pxa25x.c
@@ -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;
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index 87ade40865f1..b230af22ae05 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -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