17facc2f9Seric miao /* 27facc2f9Seric miao * linux/arch/arm/mach-pxa/mfp-pxa2xx.c 37facc2f9Seric miao * 47facc2f9Seric miao * PXA2xx pin mux configuration support 57facc2f9Seric miao * 67facc2f9Seric miao * The GPIOs on PXA2xx can be configured as one of many alternate 77facc2f9Seric miao * functions, this is by concept samilar to the MFP configuration 87facc2f9Seric miao * on PXA3xx, what's more important, the low power pin state and 97facc2f9Seric miao * wakeup detection are also supported by the same framework. 107facc2f9Seric miao * 117facc2f9Seric miao * This program is free software; you can redistribute it and/or modify 127facc2f9Seric miao * it under the terms of the GNU General Public License version 2 as 137facc2f9Seric miao * published by the Free Software Foundation. 147facc2f9Seric miao */ 157facc2f9Seric miao 167facc2f9Seric miao #include <linux/module.h> 177facc2f9Seric miao #include <linux/kernel.h> 187facc2f9Seric miao #include <linux/init.h> 197facc2f9Seric miao #include <linux/sysdev.h> 207facc2f9Seric miao 21a09e64fbSRussell King #include <mach/hardware.h> 22a09e64fbSRussell King #include <mach/pxa-regs.h> 23a09e64fbSRussell King #include <mach/pxa2xx-regs.h> 24a09e64fbSRussell King #include <mach/mfp-pxa2xx.h> 257facc2f9Seric miao 267facc2f9Seric miao #include "generic.h" 277facc2f9Seric miao 285a3d9651SEric Miao #define gpio_to_bank(gpio) ((gpio) >> 5) 295a3d9651SEric Miao 305a3d9651SEric Miao #define PGSR(x) __REG2(0x40F00020, (x) << 2) 315a3d9651SEric Miao #define __GAFR(u, x) __REG2((u) ? 0x40E00058 : 0x40E00054, (x) << 3) 325a3d9651SEric Miao #define GAFR_L(x) __GAFR(0, x) 335a3d9651SEric Miao #define GAFR_U(x) __GAFR(1, x) 347facc2f9Seric miao 357facc2f9Seric miao #define PWER_WE35 (1 << 24) 367facc2f9Seric miao 37c0a596d6Seric miao struct gpio_desc { 387facc2f9Seric miao unsigned valid : 1; 397facc2f9Seric miao unsigned can_wakeup : 1; 407facc2f9Seric miao unsigned keypad_gpio : 1; 417facc2f9Seric miao unsigned int mask; /* bit mask in PWER or PKWR */ 42*99687114SRobert Jarzmik unsigned int mux_mask; /* bit mask of muxed gpio bits, 0 if no mux */ 437facc2f9Seric miao unsigned long config; 44c0a596d6Seric miao }; 457facc2f9Seric miao 46c0a596d6Seric miao static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1]; 475a3d9651SEric Miao static int gpio_nr; 48c0a596d6Seric miao 495a3d9651SEric Miao static unsigned long gpdr_lpm[4]; 50566b450cSEric Miao 51c0a596d6Seric miao static int __mfp_config_gpio(unsigned gpio, unsigned long c) 527facc2f9Seric miao { 537facc2f9Seric miao unsigned long gafr, mask = GPIO_bit(gpio); 545a3d9651SEric Miao int bank = gpio_to_bank(gpio); 555a3d9651SEric Miao int uorl = !!(gpio & 0x10); /* GAFRx_U or GAFRx_L ? */ 565a3d9651SEric Miao int shft = (gpio & 0xf) << 1; 575a3d9651SEric Miao int fn = MFP_AF(c); 585a3d9651SEric Miao int dir = c & MFP_DIR_OUT; 597facc2f9Seric miao 607facc2f9Seric miao if (fn > 3) 617facc2f9Seric miao return -EINVAL; 627facc2f9Seric miao 635a3d9651SEric Miao /* alternate function and direction at run-time */ 645a3d9651SEric Miao gafr = (uorl == 0) ? GAFR_L(bank) : GAFR_U(bank); 655a3d9651SEric Miao gafr = (gafr & ~(0x3 << shft)) | (fn << shft); 667facc2f9Seric miao 675a3d9651SEric Miao if (uorl == 0) 685a3d9651SEric Miao GAFR_L(bank) = gafr; 695a3d9651SEric Miao else 705a3d9651SEric Miao GAFR_U(bank) = gafr; 715a3d9651SEric Miao 725a3d9651SEric Miao if (dir == MFP_DIR_OUT) 737facc2f9Seric miao GPDR(gpio) |= mask; 747facc2f9Seric miao else 757facc2f9Seric miao GPDR(gpio) &= ~mask; 767facc2f9Seric miao 775a3d9651SEric Miao /* alternate function and direction at low power mode */ 785a3d9651SEric Miao switch (c & MFP_LPM_STATE_MASK) { 795a3d9651SEric Miao case MFP_LPM_DRIVE_HIGH: 805a3d9651SEric Miao PGSR(bank) |= mask; 815a3d9651SEric Miao dir = MFP_DIR_OUT; 825a3d9651SEric Miao break; 835a3d9651SEric Miao case MFP_LPM_DRIVE_LOW: 845a3d9651SEric Miao PGSR(bank) &= ~mask; 855a3d9651SEric Miao dir = MFP_DIR_OUT; 865a3d9651SEric Miao break; 875a3d9651SEric Miao case MFP_LPM_DEFAULT: 885a3d9651SEric Miao break; 895a3d9651SEric Miao default: 905a3d9651SEric Miao /* warning and fall through, treat as MFP_LPM_DEFAULT */ 915a3d9651SEric Miao pr_warning("%s: GPIO%d: unsupported low power mode\n", 925a3d9651SEric Miao __func__, gpio); 935a3d9651SEric Miao break; 945a3d9651SEric Miao } 955a3d9651SEric Miao 965a3d9651SEric Miao if (dir == MFP_DIR_OUT) 975a3d9651SEric Miao gpdr_lpm[bank] |= mask; 985a3d9651SEric Miao else 995a3d9651SEric Miao gpdr_lpm[bank] &= ~mask; 1007facc2f9Seric miao 101c0a596d6Seric miao /* give early warning if MFP_LPM_CAN_WAKEUP is set on the 102c0a596d6Seric miao * configurations of those pins not able to wakeup 103c0a596d6Seric miao */ 104c0a596d6Seric miao if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) { 1057facc2f9Seric miao pr_warning("%s: GPIO%d unable to wakeup\n", 1067facc2f9Seric miao __func__, gpio); 1077facc2f9Seric miao return -EINVAL; 1087facc2f9Seric miao } 1097facc2f9Seric miao 1105a3d9651SEric Miao if ((c & MFP_LPM_CAN_WAKEUP) && (dir == MFP_DIR_OUT)) { 111c0a596d6Seric miao pr_warning("%s: output GPIO%d unable to wakeup\n", 112c0a596d6Seric miao __func__, gpio); 113c0a596d6Seric miao return -EINVAL; 1147facc2f9Seric miao } 1157facc2f9Seric miao 1167facc2f9Seric miao return 0; 1177facc2f9Seric miao } 1187facc2f9Seric miao 1190fedb0caSEric Miao static inline int __mfp_validate(int mfp) 1200fedb0caSEric Miao { 1210fedb0caSEric Miao int gpio = mfp_to_gpio(mfp); 1220fedb0caSEric Miao 1230fedb0caSEric Miao if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) { 1240fedb0caSEric Miao pr_warning("%s: GPIO%d is invalid pin\n", __func__, gpio); 1250fedb0caSEric Miao return -1; 1260fedb0caSEric Miao } 1270fedb0caSEric Miao 1280fedb0caSEric Miao return gpio; 1290fedb0caSEric Miao } 1300fedb0caSEric Miao 1317facc2f9Seric miao void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num) 1327facc2f9Seric miao { 1337facc2f9Seric miao unsigned long flags; 1347facc2f9Seric miao unsigned long *c; 1357facc2f9Seric miao int i, gpio; 1367facc2f9Seric miao 1377facc2f9Seric miao for (i = 0, c = mfp_cfgs; i < num; i++, c++) { 1387facc2f9Seric miao 1390fedb0caSEric Miao gpio = __mfp_validate(MFP_PIN(*c)); 1400fedb0caSEric Miao if (gpio < 0) 1417facc2f9Seric miao continue; 1427facc2f9Seric miao 1437facc2f9Seric miao local_irq_save(flags); 1447facc2f9Seric miao 1457facc2f9Seric miao gpio_desc[gpio].config = *c; 1467facc2f9Seric miao __mfp_config_gpio(gpio, *c); 1477facc2f9Seric miao 1487facc2f9Seric miao local_irq_restore(flags); 1497facc2f9Seric miao } 1507facc2f9Seric miao } 1517facc2f9Seric miao 152566b450cSEric Miao void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm) 153566b450cSEric Miao { 1545a3d9651SEric Miao unsigned long flags, c; 155566b450cSEric Miao int gpio; 156566b450cSEric Miao 157566b450cSEric Miao gpio = __mfp_validate(mfp); 158566b450cSEric Miao if (gpio < 0) 159566b450cSEric Miao return; 160566b450cSEric Miao 161566b450cSEric Miao local_irq_save(flags); 1625a3d9651SEric Miao 1635a3d9651SEric Miao c = gpio_desc[gpio].config; 1645a3d9651SEric Miao c = (c & ~MFP_LPM_STATE_MASK) | lpm; 1655a3d9651SEric Miao __mfp_config_gpio(gpio, c); 1665a3d9651SEric Miao 167566b450cSEric Miao local_irq_restore(flags); 168566b450cSEric Miao } 169566b450cSEric Miao 170c0a596d6Seric miao int gpio_set_wake(unsigned int gpio, unsigned int on) 171c0a596d6Seric miao { 172c0a596d6Seric miao struct gpio_desc *d; 173*99687114SRobert Jarzmik unsigned long c, mux_taken; 174c0a596d6Seric miao 175c0a596d6Seric miao if (gpio > mfp_to_gpio(MFP_PIN_GPIO127)) 176c0a596d6Seric miao return -EINVAL; 177c0a596d6Seric miao 178c0a596d6Seric miao d = &gpio_desc[gpio]; 179c0a596d6Seric miao c = d->config; 180c0a596d6Seric miao 181c0a596d6Seric miao if (!d->valid) 182c0a596d6Seric miao return -EINVAL; 183c0a596d6Seric miao 184c0a596d6Seric miao if (d->keypad_gpio) 185c0a596d6Seric miao return -EINVAL; 186c0a596d6Seric miao 187*99687114SRobert Jarzmik mux_taken = (PWER & d->mux_mask) & (~d->mask); 188*99687114SRobert Jarzmik if (on && mux_taken) 189*99687114SRobert Jarzmik return -EBUSY; 190*99687114SRobert Jarzmik 191c0a596d6Seric miao if (d->can_wakeup && (c & MFP_LPM_CAN_WAKEUP)) { 192c0a596d6Seric miao if (on) { 193*99687114SRobert Jarzmik PWER = (PWER & ~d->mux_mask) | d->mask; 194c0a596d6Seric miao 195c0a596d6Seric miao if (c & MFP_LPM_EDGE_RISE) 196c0a596d6Seric miao PRER |= d->mask; 197c0a596d6Seric miao else 198c0a596d6Seric miao PRER &= ~d->mask; 199c0a596d6Seric miao 200c0a596d6Seric miao if (c & MFP_LPM_EDGE_FALL) 201c0a596d6Seric miao PFER |= d->mask; 202c0a596d6Seric miao else 203c0a596d6Seric miao PFER &= ~d->mask; 204c0a596d6Seric miao } else { 205c0a596d6Seric miao PWER &= ~d->mask; 206c0a596d6Seric miao PRER &= ~d->mask; 207c0a596d6Seric miao PFER &= ~d->mask; 208c0a596d6Seric miao } 209c0a596d6Seric miao } 210c0a596d6Seric miao return 0; 211c0a596d6Seric miao } 212c0a596d6Seric miao 2137facc2f9Seric miao #ifdef CONFIG_PXA25x 2145a3d9651SEric Miao static void __init pxa25x_mfp_init(void) 2157facc2f9Seric miao { 2167facc2f9Seric miao int i; 2177facc2f9Seric miao 2187facc2f9Seric miao for (i = 0; i <= 84; i++) 2197facc2f9Seric miao gpio_desc[i].valid = 1; 2207facc2f9Seric miao 2217facc2f9Seric miao for (i = 0; i <= 15; i++) { 2227facc2f9Seric miao gpio_desc[i].can_wakeup = 1; 2237facc2f9Seric miao gpio_desc[i].mask = GPIO_bit(i); 2247facc2f9Seric miao } 2257facc2f9Seric miao 2265a3d9651SEric Miao gpio_nr = 85; 2277facc2f9Seric miao } 2285a3d9651SEric Miao #else 2295a3d9651SEric Miao static inline void pxa25x_mfp_init(void) {} 2307facc2f9Seric miao #endif /* CONFIG_PXA25x */ 2317facc2f9Seric miao 2327facc2f9Seric miao #ifdef CONFIG_PXA27x 233c0a596d6Seric miao static int pxa27x_pkwr_gpio[] = { 2347facc2f9Seric miao 13, 16, 17, 34, 36, 37, 38, 39, 90, 91, 93, 94, 2357facc2f9Seric miao 95, 96, 97, 98, 99, 100, 101, 102 2367facc2f9Seric miao }; 2377facc2f9Seric miao 238c0a596d6Seric miao int keypad_set_wake(unsigned int on) 239c0a596d6Seric miao { 240c0a596d6Seric miao unsigned int i, gpio, mask = 0; 241c0a596d6Seric miao 242c0a596d6Seric miao if (!on) { 243c0a596d6Seric miao PKWR = 0; 244c0a596d6Seric miao return 0; 245c0a596d6Seric miao } 246c0a596d6Seric miao 247c0a596d6Seric miao for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { 248c0a596d6Seric miao 249c0a596d6Seric miao gpio = pxa27x_pkwr_gpio[i]; 250c0a596d6Seric miao 251c0a596d6Seric miao if (gpio_desc[gpio].config & MFP_LPM_CAN_WAKEUP) 252c0a596d6Seric miao mask |= gpio_desc[gpio].mask; 253c0a596d6Seric miao } 254c0a596d6Seric miao 255c0a596d6Seric miao PKWR = mask; 256c0a596d6Seric miao return 0; 257c0a596d6Seric miao } 258c0a596d6Seric miao 259*99687114SRobert Jarzmik #define PWER_WEMUX2_GPIO38 (1 << 16) 260*99687114SRobert Jarzmik #define PWER_WEMUX2_GPIO53 (2 << 16) 261*99687114SRobert Jarzmik #define PWER_WEMUX2_GPIO40 (3 << 16) 262*99687114SRobert Jarzmik #define PWER_WEMUX2_GPIO36 (4 << 16) 263*99687114SRobert Jarzmik #define PWER_WEMUX2_MASK (7 << 16) 264*99687114SRobert Jarzmik #define PWER_WEMUX3_GPIO31 (1 << 19) 265*99687114SRobert Jarzmik #define PWER_WEMUX3_GPIO113 (2 << 19) 266*99687114SRobert Jarzmik #define PWER_WEMUX3_MASK (3 << 19) 267*99687114SRobert Jarzmik 268*99687114SRobert Jarzmik #define INIT_GPIO_DESC_MUXED(mux, gpio) \ 269*99687114SRobert Jarzmik do { \ 270*99687114SRobert Jarzmik gpio_desc[(gpio)].can_wakeup = 1; \ 271*99687114SRobert Jarzmik gpio_desc[(gpio)].mask = PWER_ ## mux ## _GPIO ##gpio; \ 272*99687114SRobert Jarzmik gpio_desc[(gpio)].mux_mask = PWER_ ## mux ## _MASK; \ 273*99687114SRobert Jarzmik } while (0) 274*99687114SRobert Jarzmik 2755a3d9651SEric Miao static void __init pxa27x_mfp_init(void) 2767facc2f9Seric miao { 2777facc2f9Seric miao int i, gpio; 2787facc2f9Seric miao 2797facc2f9Seric miao for (i = 0; i <= 120; i++) { 2807facc2f9Seric miao /* skip GPIO2, 5, 6, 7, 8, they are not 2817facc2f9Seric miao * valid pins allow configuration 2827facc2f9Seric miao */ 2835a3d9651SEric Miao if (i == 2 || i == 5 || i == 6 || i == 7 || i == 8) 2847facc2f9Seric miao continue; 2857facc2f9Seric miao 2867facc2f9Seric miao gpio_desc[i].valid = 1; 2877facc2f9Seric miao } 2887facc2f9Seric miao 2897facc2f9Seric miao /* Keypad GPIOs */ 2907facc2f9Seric miao for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { 2917facc2f9Seric miao gpio = pxa27x_pkwr_gpio[i]; 2927facc2f9Seric miao gpio_desc[gpio].can_wakeup = 1; 2937facc2f9Seric miao gpio_desc[gpio].keypad_gpio = 1; 2947facc2f9Seric miao gpio_desc[gpio].mask = 1 << i; 2957facc2f9Seric miao } 2967facc2f9Seric miao 2977facc2f9Seric miao /* Overwrite GPIO13 as a PWER wakeup source */ 2987facc2f9Seric miao for (i = 0; i <= 15; i++) { 2997facc2f9Seric miao /* skip GPIO2, 5, 6, 7, 8 */ 3007facc2f9Seric miao if (GPIO_bit(i) & 0x1e4) 3017facc2f9Seric miao continue; 3027facc2f9Seric miao 3037facc2f9Seric miao gpio_desc[i].can_wakeup = 1; 3047facc2f9Seric miao gpio_desc[i].mask = GPIO_bit(i); 3057facc2f9Seric miao } 3067facc2f9Seric miao 3077facc2f9Seric miao gpio_desc[35].can_wakeup = 1; 3087facc2f9Seric miao gpio_desc[35].mask = PWER_WE35; 3097facc2f9Seric miao 310*99687114SRobert Jarzmik INIT_GPIO_DESC_MUXED(WEMUX3, 31); 311*99687114SRobert Jarzmik INIT_GPIO_DESC_MUXED(WEMUX3, 113); 312*99687114SRobert Jarzmik INIT_GPIO_DESC_MUXED(WEMUX2, 38); 313*99687114SRobert Jarzmik INIT_GPIO_DESC_MUXED(WEMUX2, 53); 314*99687114SRobert Jarzmik INIT_GPIO_DESC_MUXED(WEMUX2, 40); 315*99687114SRobert Jarzmik INIT_GPIO_DESC_MUXED(WEMUX2, 36); 3165a3d9651SEric Miao gpio_nr = 121; 3175a3d9651SEric Miao } 3185a3d9651SEric Miao #else 3195a3d9651SEric Miao static inline void pxa27x_mfp_init(void) {} 3205a3d9651SEric Miao #endif /* CONFIG_PXA27x */ 3215a3d9651SEric Miao 3225a3d9651SEric Miao #ifdef CONFIG_PM 3235a3d9651SEric Miao static unsigned long saved_gafr[2][4]; 3245a3d9651SEric Miao static unsigned long saved_gpdr[4]; 3255a3d9651SEric Miao 3265a3d9651SEric Miao static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state) 3275a3d9651SEric Miao { 3285a3d9651SEric Miao int i; 3295a3d9651SEric Miao 3305a3d9651SEric Miao for (i = 0; i <= gpio_to_bank(gpio_nr); i++) { 3315a3d9651SEric Miao 3325a3d9651SEric Miao saved_gafr[0][i] = GAFR_L(i); 3335a3d9651SEric Miao saved_gafr[1][i] = GAFR_U(i); 3345a3d9651SEric Miao saved_gpdr[i] = GPDR(i * 32); 3355a3d9651SEric Miao 3365a3d9651SEric Miao GPDR(i * 32) = gpdr_lpm[i]; 3375a3d9651SEric Miao } 3387facc2f9Seric miao return 0; 3397facc2f9Seric miao } 3405a3d9651SEric Miao 3415a3d9651SEric Miao static int pxa2xx_mfp_resume(struct sys_device *d) 3425a3d9651SEric Miao { 3435a3d9651SEric Miao int i; 3445a3d9651SEric Miao 3455a3d9651SEric Miao for (i = 0; i <= gpio_to_bank(gpio_nr); i++) { 3465a3d9651SEric Miao GAFR_L(i) = saved_gafr[0][i]; 3475a3d9651SEric Miao GAFR_U(i) = saved_gafr[1][i]; 3485a3d9651SEric Miao GPDR(i * 32) = saved_gpdr[i]; 3495a3d9651SEric Miao } 3505a3d9651SEric Miao PSSR = PSSR_RDH | PSSR_PH; 3515a3d9651SEric Miao return 0; 3525a3d9651SEric Miao } 3535a3d9651SEric Miao #else 3545a3d9651SEric Miao #define pxa2xx_mfp_suspend NULL 3555a3d9651SEric Miao #define pxa2xx_mfp_resume NULL 3565a3d9651SEric Miao #endif 3575a3d9651SEric Miao 3585a3d9651SEric Miao struct sysdev_class pxa2xx_mfp_sysclass = { 3595a3d9651SEric Miao .name = "mfp", 3605a3d9651SEric Miao .suspend = pxa2xx_mfp_suspend, 3615a3d9651SEric Miao .resume = pxa2xx_mfp_resume, 3625a3d9651SEric Miao }; 3635a3d9651SEric Miao 3645a3d9651SEric Miao static int __init pxa2xx_mfp_init(void) 3655a3d9651SEric Miao { 3665a3d9651SEric Miao int i; 3675a3d9651SEric Miao 368e7f3c600SEric Miao if (!cpu_is_pxa2xx()) 369e7f3c600SEric Miao return 0; 370e7f3c600SEric Miao 3715a3d9651SEric Miao if (cpu_is_pxa25x()) 3725a3d9651SEric Miao pxa25x_mfp_init(); 3735a3d9651SEric Miao 3745a3d9651SEric Miao if (cpu_is_pxa27x()) 3755a3d9651SEric Miao pxa27x_mfp_init(); 3765a3d9651SEric Miao 3775a3d9651SEric Miao /* initialize gafr_run[], pgsr_lpm[] from existing values */ 3785a3d9651SEric Miao for (i = 0; i <= gpio_to_bank(gpio_nr); i++) 3795a3d9651SEric Miao gpdr_lpm[i] = GPDR(i * 32); 3805a3d9651SEric Miao 3815a3d9651SEric Miao return sysdev_class_register(&pxa2xx_mfp_sysclass); 3825a3d9651SEric Miao } 3835a3d9651SEric Miao postcore_initcall(pxa2xx_mfp_init); 384