[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>
This commit is contained in:
Родитель
9b02b2df00
Коммит
c0a596d6a1
|
@ -28,15 +28,17 @@
|
||||||
|
|
||||||
#define PWER_WE35 (1 << 24)
|
#define PWER_WE35 (1 << 24)
|
||||||
|
|
||||||
static struct {
|
struct gpio_desc {
|
||||||
unsigned valid : 1;
|
unsigned valid : 1;
|
||||||
unsigned can_wakeup : 1;
|
unsigned can_wakeup : 1;
|
||||||
unsigned keypad_gpio : 1;
|
unsigned keypad_gpio : 1;
|
||||||
unsigned int mask; /* bit mask in PWER or PKWR */
|
unsigned int mask; /* bit mask in PWER or PKWR */
|
||||||
unsigned long config;
|
unsigned long config;
|
||||||
} gpio_desc[MFP_PIN_GPIO127 + 1];
|
};
|
||||||
|
|
||||||
static inline int __mfp_config_gpio(unsigned gpio, unsigned long c)
|
static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1];
|
||||||
|
|
||||||
|
static int __mfp_config_gpio(unsigned gpio, unsigned long c)
|
||||||
{
|
{
|
||||||
unsigned long gafr, mask = GPIO_bit(gpio);
|
unsigned long gafr, mask = GPIO_bit(gpio);
|
||||||
int fn;
|
int fn;
|
||||||
|
@ -70,26 +72,19 @@ static inline int __mfp_config_gpio(unsigned gpio, unsigned long c)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* wakeup enabling */
|
/* give early warning if MFP_LPM_CAN_WAKEUP is set on the
|
||||||
if ((c & MFP_LPM_WAKEUP_ENABLE) == 0)
|
* configurations of those pins not able to wakeup
|
||||||
return 0;
|
*/
|
||||||
|
if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) {
|
||||||
if (!gpio_desc[gpio].can_wakeup || c & MFP_DIR_OUT) {
|
|
||||||
pr_warning("%s: GPIO%d unable to wakeup\n",
|
pr_warning("%s: GPIO%d unable to wakeup\n",
|
||||||
__func__, gpio);
|
__func__, gpio);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gpio_desc[gpio].keypad_gpio)
|
if ((c & MFP_LPM_CAN_WAKEUP) && (c & MFP_DIR_OUT)) {
|
||||||
PKWR |= gpio_desc[gpio].mask;
|
pr_warning("%s: output GPIO%d unable to wakeup\n",
|
||||||
else {
|
__func__, gpio);
|
||||||
PWER |= gpio_desc[gpio].mask;
|
return -EINVAL;
|
||||||
|
|
||||||
if (c & MFP_LPM_EDGE_RISE)
|
|
||||||
PRER |= gpio_desc[gpio].mask;
|
|
||||||
|
|
||||||
if (c & MFP_LPM_EDGE_FALL)
|
|
||||||
PFER |= gpio_desc[gpio].mask;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
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
|
#ifdef CONFIG_PXA25x
|
||||||
static int __init pxa25x_mfp_init(void)
|
static int __init pxa25x_mfp_init(void)
|
||||||
{
|
{
|
||||||
|
@ -141,11 +175,32 @@ postcore_initcall(pxa25x_mfp_init);
|
||||||
#endif /* CONFIG_PXA25x */
|
#endif /* CONFIG_PXA25x */
|
||||||
|
|
||||||
#ifdef CONFIG_PXA27x
|
#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,
|
13, 16, 17, 34, 36, 37, 38, 39, 90, 91, 93, 94,
|
||||||
95, 96, 97, 98, 99, 100, 101, 102
|
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)
|
static int __init pxa27x_mfp_init(void)
|
||||||
{
|
{
|
||||||
int i, gpio;
|
int i, gpio;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include <asm/hardware.h>
|
#include <asm/hardware.h>
|
||||||
#include <asm/arch/irqs.h>
|
#include <asm/arch/irqs.h>
|
||||||
#include <asm/arch/pxa-regs.h>
|
#include <asm/arch/pxa-regs.h>
|
||||||
|
#include <asm/arch/mfp-pxa25x.h>
|
||||||
#include <asm/arch/pm.h>
|
#include <asm/arch/pm.h>
|
||||||
#include <asm/arch/dma.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)
|
static int pxa25x_set_wake(unsigned int irq, unsigned int on)
|
||||||
{
|
{
|
||||||
int gpio = IRQ_TO_GPIO(irq);
|
int gpio = IRQ_TO_GPIO(irq);
|
||||||
uint32_t gpio_bit, mask = 0;
|
uint32_t mask = 0;
|
||||||
|
|
||||||
if (gpio >= 0 && gpio <= 15) {
|
if (gpio >= 0 && gpio < 85)
|
||||||
gpio_bit = GPIO_bit(gpio);
|
return gpio_set_wake(gpio, on);
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (irq == IRQ_RTCAlrm) {
|
if (irq == IRQ_RTCAlrm) {
|
||||||
mask = PWER_RTC;
|
mask = PWER_RTC;
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include <asm/arch/irqs.h>
|
#include <asm/arch/irqs.h>
|
||||||
#include <asm/arch/pxa-regs.h>
|
#include <asm/arch/pxa-regs.h>
|
||||||
#include <asm/arch/pxa2xx-regs.h>
|
#include <asm/arch/pxa2xx-regs.h>
|
||||||
|
#include <asm/arch/mfp-pxa27x.h>
|
||||||
#include <asm/arch/ohci.h>
|
#include <asm/arch/ohci.h>
|
||||||
#include <asm/arch/pm.h>
|
#include <asm/arch/pm.h>
|
||||||
#include <asm/arch/dma.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
|
/* PXA27x: Various gpios can issue wakeup events. This logic only
|
||||||
* handles the simple cases, not the WEMUX2 and WEMUX3 options
|
* 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)
|
static int pxa27x_set_wake(unsigned int irq, unsigned int on)
|
||||||
{
|
{
|
||||||
int gpio = IRQ_TO_GPIO(irq);
|
int gpio = IRQ_TO_GPIO(irq);
|
||||||
uint32_t mask;
|
uint32_t mask;
|
||||||
|
|
||||||
if ((gpio >= 0 && gpio <= 15) || (gpio == 35)) {
|
if (gpio >= 0 && gpio < 128)
|
||||||
if (WAKEMASK(gpio) == 0)
|
return gpio_set_wake(gpio, on);
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
mask = WAKEMASK(gpio);
|
if (irq == IRQ_KEYPAD)
|
||||||
|
return keypad_set_wake(on);
|
||||||
if (on) {
|
|
||||||
if (GRER(gpio) | GPIO_bit(gpio))
|
|
||||||
PRER |= mask;
|
|
||||||
else
|
|
||||||
PRER &= ~mask;
|
|
||||||
|
|
||||||
if (GFER(gpio) | GPIO_bit(gpio))
|
|
||||||
PFER |= mask;
|
|
||||||
else
|
|
||||||
PFER &= ~mask;
|
|
||||||
}
|
|
||||||
goto set_pwer;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (irq) {
|
switch (irq) {
|
||||||
case IRQ_RTCAlrm:
|
case IRQ_RTCAlrm:
|
||||||
|
@ -329,7 +309,6 @@ static int pxa27x_set_wake(unsigned int irq, unsigned int on)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
set_pwer:
|
|
||||||
if (on)
|
if (on)
|
||||||
PWER |= mask;
|
PWER |= mask;
|
||||||
else
|
else
|
||||||
|
|
|
@ -428,4 +428,5 @@
|
||||||
#define GPIO112_nMSINS MFP_CFG_IN(GPIO112, AF2)
|
#define GPIO112_nMSINS MFP_CFG_IN(GPIO112, AF2)
|
||||||
#define GPIO32_MSSCLK MFP_CFG_OUT(GPIO32, AF1, DRIVE_LOW)
|
#define GPIO32_MSSCLK MFP_CFG_OUT(GPIO32, AF1, DRIVE_LOW)
|
||||||
|
|
||||||
|
extern int keypad_set_wake(unsigned int on);
|
||||||
#endif /* __ASM_ARCH_MFP_PXA27X_H */
|
#endif /* __ASM_ARCH_MFP_PXA27X_H */
|
||||||
|
|
|
@ -24,13 +24,13 @@
|
||||||
#define MFP_DIR_MASK (0x1 << 23)
|
#define MFP_DIR_MASK (0x1 << 23)
|
||||||
#define MFP_DIR(x) (((x) >> 23) & 0x1)
|
#define MFP_DIR(x) (((x) >> 23) & 0x1)
|
||||||
|
|
||||||
#define MFP_LPM_WAKEUP_ENABLE (0x1 << 24)
|
#define MFP_LPM_CAN_WAKEUP (0x1 << 24)
|
||||||
#define WAKEUP_ON_EDGE_RISE (MFP_LPM_WAKEUP_ENABLE | MFP_LPM_EDGE_RISE)
|
#define WAKEUP_ON_EDGE_RISE (MFP_LPM_CAN_WAKEUP | MFP_LPM_EDGE_RISE)
|
||||||
#define WAKEUP_ON_EDGE_FALL (MFP_LPM_WAKEUP_ENABLE | MFP_LPM_EDGE_FALL)
|
#define WAKEUP_ON_EDGE_FALL (MFP_LPM_CAN_WAKEUP | MFP_LPM_EDGE_FALL)
|
||||||
#define WAKEUP_ON_EDGE_BOTH (MFP_LPM_WAKEUP_ENABLE | MFP_LPM_EDGE_BOTH)
|
#define WAKEUP_ON_EDGE_BOTH (MFP_LPM_CAN_WAKEUP | MFP_LPM_EDGE_BOTH)
|
||||||
|
|
||||||
/* specifically for enabling wakeup on keypad GPIOs */
|
/* 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) \
|
#define MFP_CFG_IN(pin, af) \
|
||||||
((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DIR_MASK)) |\
|
((MFP_CFG_DEFAULT & ~(MFP_AF_MASK | MFP_DIR_MASK)) |\
|
||||||
|
@ -128,4 +128,5 @@
|
||||||
#define GPIO84_GPIO MFP_CFG_IN(GPIO84, AF0)
|
#define GPIO84_GPIO MFP_CFG_IN(GPIO84, AF0)
|
||||||
|
|
||||||
extern void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num);
|
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 */
|
#endif /* __ASM_ARCH_MFP_PXA2XX_H */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче