Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0a596d6 authored by eric miao's avatar eric miao Committed by Russell King
Browse files

[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: default avatareric miao <eric.miao@marvell.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 9b02b2df
Loading
Loading
Loading
Loading
+74 −19
Original line number Diff line number Diff line
@@ -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;
+5 −18
Original line number Diff line number Diff line
@@ -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;
	uint32_t mask = 0;

			if (GFER(gpio) | gpio_bit)
				PFER |= gpio_bit;
			else
				PFER &= ~gpio_bit;
		}
		goto set_pwer;
	}
	if (gpio >= 0 && gpio < 85)
		return gpio_set_wake(gpio, on);

	if (irq == IRQ_RTCAlrm) {
		mask = PWER_RTC;
+5 −26
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -428,4 +428,5 @@
#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 */
+6 −5
Original line number Diff line number Diff line
@@ -24,13 +24,13 @@
#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)) |\
@@ -128,4 +128,5 @@
#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 */