diff options
Diffstat (limited to 'arch/arm/mach-pxa/mfp-pxa2xx.c')
| -rw-r--r-- | arch/arm/mach-pxa/mfp-pxa2xx.c | 161 |
1 files changed, 123 insertions, 38 deletions
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index 2061c00c8ea..ef0426a159d 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c @@ -12,38 +12,43 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ - +#include <linux/gpio.h> +#include <linux/gpio-pxa.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> -#include <linux/sysdev.h> +#include <linux/io.h> +#include <linux/syscore_ops.h> -#include <mach/hardware.h> -#include <mach/pxa-regs.h> #include <mach/pxa2xx-regs.h> #include <mach/mfp-pxa2xx.h> #include "generic.h" -#define gpio_to_bank(gpio) ((gpio) >> 5) - #define PGSR(x) __REG2(0x40F00020, (x) << 2) #define __GAFR(u, x) __REG2((u) ? 0x40E00058 : 0x40E00054, (x) << 3) #define GAFR_L(x) __GAFR(0, x) #define GAFR_U(x) __GAFR(1, x) +#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2)) +#define GPLR(x) __REG2(0x40E00000, BANK_OFF((x) >> 5)) +#define GPDR(x) __REG2(0x40E00000, BANK_OFF((x) >> 5) + 0x0c) +#define GPSR(x) __REG2(0x40E00000, BANK_OFF((x) >> 5) + 0x18) +#define GPCR(x) __REG2(0x40E00000, BANK_OFF((x) >> 5) + 0x24) + #define PWER_WE35 (1 << 24) struct gpio_desc { unsigned valid : 1; unsigned can_wakeup : 1; unsigned keypad_gpio : 1; + unsigned dir_inverted : 1; unsigned int mask; /* bit mask in PWER or PKWR */ + unsigned int mux_mask; /* bit mask of muxed gpio bits, 0 if no mux */ unsigned long config; }; static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1]; -static int gpio_nr; static unsigned long gpdr_lpm[4]; @@ -54,7 +59,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) int uorl = !!(gpio & 0x10); /* GAFRx_U or GAFRx_L ? */ int shft = (gpio & 0xf) << 1; int fn = MFP_AF(c); - int dir = c & MFP_DIR_OUT; + int is_out = (c & MFP_DIR_OUT) ? 1 : 0; if (fn > 3) return -EINVAL; @@ -68,7 +73,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) else GAFR_U(bank) = gafr; - if (dir == MFP_DIR_OUT) + if (is_out ^ gpio_desc[gpio].dir_inverted) GPDR(gpio) |= mask; else GPDR(gpio) &= ~mask; @@ -77,12 +82,13 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) switch (c & MFP_LPM_STATE_MASK) { case MFP_LPM_DRIVE_HIGH: PGSR(bank) |= mask; - dir = MFP_DIR_OUT; + is_out = 1; break; case MFP_LPM_DRIVE_LOW: PGSR(bank) &= ~mask; - dir = MFP_DIR_OUT; + is_out = 1; break; + case MFP_LPM_INPUT: case MFP_LPM_DEFAULT: break; default: @@ -92,7 +98,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) break; } - if (dir == MFP_DIR_OUT) + if (is_out ^ gpio_desc[gpio].dir_inverted) gpdr_lpm[bank] |= mask; else gpdr_lpm[bank] &= ~mask; @@ -106,7 +112,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) return -EINVAL; } - if ((c & MFP_LPM_CAN_WAKEUP) && (dir == MFP_DIR_OUT)) { + if ((c & MFP_LPM_CAN_WAKEUP) && is_out) { pr_warning("%s: output GPIO%d unable to wakeup\n", __func__, gpio); return -EINVAL; @@ -169,7 +175,7 @@ void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm) int gpio_set_wake(unsigned int gpio, unsigned int on) { struct gpio_desc *d; - unsigned long c; + unsigned long c, mux_taken; if (gpio > mfp_to_gpio(MFP_PIN_GPIO127)) return -EINVAL; @@ -180,12 +186,25 @@ int gpio_set_wake(unsigned int gpio, unsigned int on) if (!d->valid) return -EINVAL; - if (d->keypad_gpio) - return -EINVAL; + /* Allow keypad GPIOs to wakeup system when + * configured as generic GPIOs. + */ + if (d->keypad_gpio && (MFP_AF(d->config) == 0) && + (d->config & MFP_LPM_CAN_WAKEUP)) { + if (on) + PKWR |= d->mask; + else + PKWR &= ~d->mask; + return 0; + } + + mux_taken = (PWER & d->mux_mask) & (~d->mask); + if (on && mux_taken) + return -EBUSY; if (d->can_wakeup && (c & MFP_LPM_CAN_WAKEUP)) { if (on) { - PWER |= d->mask; + PWER = (PWER & ~d->mux_mask) | d->mask; if (c & MFP_LPM_EDGE_RISE) PRER |= d->mask; @@ -210,7 +229,13 @@ static void __init pxa25x_mfp_init(void) { int i; - for (i = 0; i <= 84; i++) + /* running before pxa_gpio_probe() */ +#ifdef CONFIG_CPU_PXA26x + pxa_last_gpio = 89; +#else + pxa_last_gpio = 84; +#endif + for (i = 0; i <= pxa_last_gpio; i++) gpio_desc[i].valid = 1; for (i = 0; i <= 15; i++) { @@ -218,7 +243,11 @@ static void __init pxa25x_mfp_init(void) gpio_desc[i].mask = GPIO_bit(i); } - gpio_nr = 85; + /* PXA26x has additional 4 GPIOs (86/87/88/89) which has the + * direction bit inverted in GPDR2. See PXA26x DM 4.1.1. + */ + for (i = 86; i <= pxa_last_gpio; i++) + gpio_desc[i].dir_inverted = 1; } #else static inline void pxa25x_mfp_init(void) {} @@ -233,29 +262,50 @@ static int pxa27x_pkwr_gpio[] = { int keypad_set_wake(unsigned int on) { unsigned int i, gpio, mask = 0; - - if (!on) { - PKWR = 0; - return 0; - } + struct gpio_desc *d; for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { gpio = pxa27x_pkwr_gpio[i]; + d = &gpio_desc[gpio]; + + /* skip if configured as generic GPIO */ + if (MFP_AF(d->config) == 0) + continue; - if (gpio_desc[gpio].config & MFP_LPM_CAN_WAKEUP) + if (d->config & MFP_LPM_CAN_WAKEUP) mask |= gpio_desc[gpio].mask; } - PKWR = mask; + if (on) + PKWR |= mask; + else + PKWR &= ~mask; return 0; } +#define PWER_WEMUX2_GPIO38 (1 << 16) +#define PWER_WEMUX2_GPIO53 (2 << 16) +#define PWER_WEMUX2_GPIO40 (3 << 16) +#define PWER_WEMUX2_GPIO36 (4 << 16) +#define PWER_WEMUX2_MASK (7 << 16) +#define PWER_WEMUX3_GPIO31 (1 << 19) +#define PWER_WEMUX3_GPIO113 (2 << 19) +#define PWER_WEMUX3_MASK (3 << 19) + +#define INIT_GPIO_DESC_MUXED(mux, gpio) \ +do { \ + gpio_desc[(gpio)].can_wakeup = 1; \ + gpio_desc[(gpio)].mask = PWER_ ## mux ## _GPIO ##gpio; \ + gpio_desc[(gpio)].mux_mask = PWER_ ## mux ## _MASK; \ +} while (0) + static void __init pxa27x_mfp_init(void) { int i, gpio; - for (i = 0; i <= 120; i++) { + pxa_last_gpio = 120; /* running before pxa_gpio_probe() */ + for (i = 0; i <= pxa_last_gpio; i++) { /* skip GPIO2, 5, 6, 7, 8, they are not * valid pins allow configuration */ @@ -286,7 +336,12 @@ static void __init pxa27x_mfp_init(void) gpio_desc[35].can_wakeup = 1; gpio_desc[35].mask = PWER_WE35; - gpio_nr = 121; + INIT_GPIO_DESC_MUXED(WEMUX3, 31); + INIT_GPIO_DESC_MUXED(WEMUX3, 113); + INIT_GPIO_DESC_MUXED(WEMUX2, 38); + INIT_GPIO_DESC_MUXED(WEMUX2, 53); + INIT_GPIO_DESC_MUXED(WEMUX2, 40); + INIT_GPIO_DESC_MUXED(WEMUX2, 36); } #else static inline void pxa27x_mfp_init(void) {} @@ -295,41 +350,68 @@ static inline void pxa27x_mfp_init(void) {} #ifdef CONFIG_PM static unsigned long saved_gafr[2][4]; static unsigned long saved_gpdr[4]; +static unsigned long saved_gplr[4]; +static unsigned long saved_pgsr[4]; -static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state) +static int pxa2xx_mfp_suspend(void) { int i; - for (i = 0; i <= gpio_to_bank(gpio_nr); i++) { + /* set corresponding PGSR bit of those marked MFP_LPM_KEEP_OUTPUT */ + for (i = 0; i < pxa_last_gpio; i++) { + if ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) && + (GPDR(i) & GPIO_bit(i))) { + if (GPLR(i) & GPIO_bit(i)) + PGSR(gpio_to_bank(i)) |= GPIO_bit(i); + else + PGSR(gpio_to_bank(i)) &= ~GPIO_bit(i); + } + } + for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) { saved_gafr[0][i] = GAFR_L(i); saved_gafr[1][i] = GAFR_U(i); saved_gpdr[i] = GPDR(i * 32); + saved_gplr[i] = GPLR(i * 32); + saved_pgsr[i] = PGSR(i); + + GPSR(i * 32) = PGSR(i); + GPCR(i * 32) = ~PGSR(i); + } - GPDR(i * 32) = gpdr_lpm[i]; + /* set GPDR bits taking into account MFP_LPM_KEEP_OUTPUT */ + for (i = 0; i < pxa_last_gpio; i++) { + if ((gpdr_lpm[gpio_to_bank(i)] & GPIO_bit(i)) || + ((gpio_desc[i].config & MFP_LPM_KEEP_OUTPUT) && + (saved_gpdr[gpio_to_bank(i)] & GPIO_bit(i)))) + GPDR(i) |= GPIO_bit(i); + else + GPDR(i) &= ~GPIO_bit(i); } + return 0; } -static int pxa2xx_mfp_resume(struct sys_device *d) +static void pxa2xx_mfp_resume(void) { int i; - for (i = 0; i <= gpio_to_bank(gpio_nr); i++) { + for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) { GAFR_L(i) = saved_gafr[0][i]; GAFR_U(i) = saved_gafr[1][i]; + GPSR(i * 32) = saved_gplr[i]; + GPCR(i * 32) = ~saved_gplr[i]; GPDR(i * 32) = saved_gpdr[i]; + PGSR(i) = saved_pgsr[i]; } PSSR = PSSR_RDH | PSSR_PH; - return 0; } #else #define pxa2xx_mfp_suspend NULL #define pxa2xx_mfp_resume NULL #endif -struct sysdev_class pxa2xx_mfp_sysclass = { - .name = "mfp", +struct syscore_ops pxa2xx_mfp_syscore_ops = { .suspend = pxa2xx_mfp_suspend, .resume = pxa2xx_mfp_resume, }; @@ -347,10 +429,13 @@ static int __init pxa2xx_mfp_init(void) if (cpu_is_pxa27x()) pxa27x_mfp_init(); + /* clear RDH bit to enable GPIO receivers after reset/sleep exit */ + PSSR = PSSR_RDH; + /* initialize gafr_run[], pgsr_lpm[] from existing values */ - for (i = 0; i <= gpio_to_bank(gpio_nr); i++) + for (i = 0; i <= gpio_to_bank(pxa_last_gpio); i++) gpdr_lpm[i] = GPDR(i * 32); - return sysdev_class_register(&pxa2xx_mfp_sysclass); + return 0; } postcore_initcall(pxa2xx_mfp_init); |
