1 /* 2 * linux/arch/arm/mach-pxa/mfp-pxa2xx.c 3 * 4 * PXA2xx pin mux configuration support 5 * 6 * The GPIOs on PXA2xx can be configured as one of many alternate 7 * functions, this is by concept samilar to the MFP configuration 8 * on PXA3xx, what's more important, the low power pin state and 9 * wakeup detection are also supported by the same framework. 10 * 11 * This program is free software; you can redistribute it and/or modify 12 * it under the terms of the GNU General Public License version 2 as 13 * published by the Free Software Foundation. 14 */ 15 16 #include <linux/module.h> 17 #include <linux/kernel.h> 18 #include <linux/init.h> 19 #include <linux/sysdev.h> 20 21 #include <asm/arch/hardware.h> 22 #include <asm/arch/pxa-regs.h> 23 #include <asm/arch/pxa2xx-regs.h> 24 #include <asm/arch/mfp-pxa2xx.h> 25 26 #include "generic.h" 27 28 #define PGSR(x) __REG2(0x40F00020, ((x) & 0x60) >> 3) 29 30 #define PWER_WE35 (1 << 24) 31 32 struct gpio_desc { 33 unsigned valid : 1; 34 unsigned can_wakeup : 1; 35 unsigned keypad_gpio : 1; 36 unsigned int mask; /* bit mask in PWER or PKWR */ 37 unsigned long config; 38 }; 39 40 static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1]; 41 42 static int __mfp_config_lpm(unsigned gpio, unsigned long lpm) 43 { 44 unsigned mask = GPIO_bit(gpio); 45 46 /* low power state */ 47 switch (lpm) { 48 case MFP_LPM_DRIVE_HIGH: 49 PGSR(gpio) |= mask; 50 break; 51 case MFP_LPM_DRIVE_LOW: 52 PGSR(gpio) &= ~mask; 53 break; 54 case MFP_LPM_INPUT: 55 break; 56 default: 57 pr_warning("%s: invalid low power state for GPIO%d\n", 58 __func__, gpio); 59 return -EINVAL; 60 } 61 return 0; 62 } 63 64 static int __mfp_config_gpio(unsigned gpio, unsigned long c) 65 { 66 unsigned long gafr, mask = GPIO_bit(gpio); 67 int fn; 68 69 fn = MFP_AF(c); 70 if (fn > 3) 71 return -EINVAL; 72 73 /* alternate function and direction */ 74 gafr = GAFR(gpio) & ~(0x3 << ((gpio & 0xf) * 2)); 75 GAFR(gpio) = gafr | (fn << ((gpio & 0xf) * 2)); 76 77 if (c & MFP_DIR_OUT) 78 GPDR(gpio) |= mask; 79 else 80 GPDR(gpio) &= ~mask; 81 82 if (__mfp_config_lpm(gpio, c & MFP_LPM_STATE_MASK)) 83 return -EINVAL; 84 85 /* give early warning if MFP_LPM_CAN_WAKEUP is set on the 86 * configurations of those pins not able to wakeup 87 */ 88 if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) { 89 pr_warning("%s: GPIO%d unable to wakeup\n", 90 __func__, gpio); 91 return -EINVAL; 92 } 93 94 if ((c & MFP_LPM_CAN_WAKEUP) && (c & MFP_DIR_OUT)) { 95 pr_warning("%s: output GPIO%d unable to wakeup\n", 96 __func__, gpio); 97 return -EINVAL; 98 } 99 100 return 0; 101 } 102 103 static inline int __mfp_validate(int mfp) 104 { 105 int gpio = mfp_to_gpio(mfp); 106 107 if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) { 108 pr_warning("%s: GPIO%d is invalid pin\n", __func__, gpio); 109 return -1; 110 } 111 112 return gpio; 113 } 114 115 void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num) 116 { 117 unsigned long flags; 118 unsigned long *c; 119 int i, gpio; 120 121 for (i = 0, c = mfp_cfgs; i < num; i++, c++) { 122 123 gpio = __mfp_validate(MFP_PIN(*c)); 124 if (gpio < 0) 125 continue; 126 127 local_irq_save(flags); 128 129 gpio_desc[gpio].config = *c; 130 __mfp_config_gpio(gpio, *c); 131 132 local_irq_restore(flags); 133 } 134 } 135 136 void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm) 137 { 138 unsigned long flags; 139 int gpio; 140 141 gpio = __mfp_validate(mfp); 142 if (gpio < 0) 143 return; 144 145 local_irq_save(flags); 146 __mfp_config_lpm(gpio, lpm); 147 local_irq_restore(flags); 148 } 149 150 int gpio_set_wake(unsigned int gpio, unsigned int on) 151 { 152 struct gpio_desc *d; 153 unsigned long c; 154 155 if (gpio > mfp_to_gpio(MFP_PIN_GPIO127)) 156 return -EINVAL; 157 158 d = &gpio_desc[gpio]; 159 c = d->config; 160 161 if (!d->valid) 162 return -EINVAL; 163 164 if (d->keypad_gpio) 165 return -EINVAL; 166 167 if (d->can_wakeup && (c & MFP_LPM_CAN_WAKEUP)) { 168 if (on) { 169 PWER |= d->mask; 170 171 if (c & MFP_LPM_EDGE_RISE) 172 PRER |= d->mask; 173 else 174 PRER &= ~d->mask; 175 176 if (c & MFP_LPM_EDGE_FALL) 177 PFER |= d->mask; 178 else 179 PFER &= ~d->mask; 180 } else { 181 PWER &= ~d->mask; 182 PRER &= ~d->mask; 183 PFER &= ~d->mask; 184 } 185 } 186 return 0; 187 } 188 189 #ifdef CONFIG_PXA25x 190 static int __init pxa25x_mfp_init(void) 191 { 192 int i; 193 194 if (cpu_is_pxa25x()) { 195 for (i = 0; i <= 84; i++) 196 gpio_desc[i].valid = 1; 197 198 for (i = 0; i <= 15; i++) { 199 gpio_desc[i].can_wakeup = 1; 200 gpio_desc[i].mask = GPIO_bit(i); 201 } 202 } 203 204 return 0; 205 } 206 postcore_initcall(pxa25x_mfp_init); 207 #endif /* CONFIG_PXA25x */ 208 209 #ifdef CONFIG_PXA27x 210 static int pxa27x_pkwr_gpio[] = { 211 13, 16, 17, 34, 36, 37, 38, 39, 90, 91, 93, 94, 212 95, 96, 97, 98, 99, 100, 101, 102 213 }; 214 215 int keypad_set_wake(unsigned int on) 216 { 217 unsigned int i, gpio, mask = 0; 218 219 if (!on) { 220 PKWR = 0; 221 return 0; 222 } 223 224 for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { 225 226 gpio = pxa27x_pkwr_gpio[i]; 227 228 if (gpio_desc[gpio].config & MFP_LPM_CAN_WAKEUP) 229 mask |= gpio_desc[gpio].mask; 230 } 231 232 PKWR = mask; 233 return 0; 234 } 235 236 static int __init pxa27x_mfp_init(void) 237 { 238 int i, gpio; 239 240 if (cpu_is_pxa27x()) { 241 for (i = 0; i <= 120; i++) { 242 /* skip GPIO2, 5, 6, 7, 8, they are not 243 * valid pins allow configuration 244 */ 245 if (i == 2 || i == 5 || i == 6 || 246 i == 7 || i == 8) 247 continue; 248 249 gpio_desc[i].valid = 1; 250 } 251 252 /* Keypad GPIOs */ 253 for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { 254 gpio = pxa27x_pkwr_gpio[i]; 255 gpio_desc[gpio].can_wakeup = 1; 256 gpio_desc[gpio].keypad_gpio = 1; 257 gpio_desc[gpio].mask = 1 << i; 258 } 259 260 /* Overwrite GPIO13 as a PWER wakeup source */ 261 for (i = 0; i <= 15; i++) { 262 /* skip GPIO2, 5, 6, 7, 8 */ 263 if (GPIO_bit(i) & 0x1e4) 264 continue; 265 266 gpio_desc[i].can_wakeup = 1; 267 gpio_desc[i].mask = GPIO_bit(i); 268 } 269 270 gpio_desc[35].can_wakeup = 1; 271 gpio_desc[35].mask = PWER_WE35; 272 } 273 274 return 0; 275 } 276 postcore_initcall(pxa27x_mfp_init); 277 #endif /* CONFIG_PXA27x */ 278