diff options
Diffstat (limited to 'arch/arm/mach-pxa/mfp-pxa2xx.c')
-rw-r--r-- | arch/arm/mach-pxa/mfp-pxa2xx.c | 225 |
1 files changed, 152 insertions, 73 deletions
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c index 925575f10acf..2061c00c8ead 100644 --- a/arch/arm/mach-pxa/mfp-pxa2xx.c +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c | |||
@@ -25,7 +25,12 @@ | |||
25 | 25 | ||
26 | #include "generic.h" | 26 | #include "generic.h" |
27 | 27 | ||
28 | #define PGSR(x) __REG2(0x40F00020, ((x) & 0x60) >> 3) | 28 | #define gpio_to_bank(gpio) ((gpio) >> 5) |
29 | |||
30 | #define PGSR(x) __REG2(0x40F00020, (x) << 2) | ||
31 | #define __GAFR(u, x) __REG2((u) ? 0x40E00058 : 0x40E00054, (x) << 3) | ||
32 | #define GAFR_L(x) __GAFR(0, x) | ||
33 | #define GAFR_U(x) __GAFR(1, x) | ||
29 | 34 | ||
30 | #define PWER_WE35 (1 << 24) | 35 | #define PWER_WE35 (1 << 24) |
31 | 36 | ||
@@ -38,49 +43,59 @@ struct gpio_desc { | |||
38 | }; | 43 | }; |
39 | 44 | ||
40 | static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1]; | 45 | static struct gpio_desc gpio_desc[MFP_PIN_GPIO127 + 1]; |
46 | static int gpio_nr; | ||
41 | 47 | ||
42 | static int __mfp_config_lpm(unsigned gpio, unsigned long lpm) | 48 | static unsigned long gpdr_lpm[4]; |
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 | 49 | ||
64 | static int __mfp_config_gpio(unsigned gpio, unsigned long c) | 50 | static int __mfp_config_gpio(unsigned gpio, unsigned long c) |
65 | { | 51 | { |
66 | unsigned long gafr, mask = GPIO_bit(gpio); | 52 | unsigned long gafr, mask = GPIO_bit(gpio); |
67 | int fn; | 53 | int bank = gpio_to_bank(gpio); |
54 | int uorl = !!(gpio & 0x10); /* GAFRx_U or GAFRx_L ? */ | ||
55 | int shft = (gpio & 0xf) << 1; | ||
56 | int fn = MFP_AF(c); | ||
57 | int dir = c & MFP_DIR_OUT; | ||
68 | 58 | ||
69 | fn = MFP_AF(c); | ||
70 | if (fn > 3) | 59 | if (fn > 3) |
71 | return -EINVAL; | 60 | return -EINVAL; |
72 | 61 | ||
73 | /* alternate function and direction */ | 62 | /* alternate function and direction at run-time */ |
74 | gafr = GAFR(gpio) & ~(0x3 << ((gpio & 0xf) * 2)); | 63 | gafr = (uorl == 0) ? GAFR_L(bank) : GAFR_U(bank); |
75 | GAFR(gpio) = gafr | (fn << ((gpio & 0xf) * 2)); | 64 | gafr = (gafr & ~(0x3 << shft)) | (fn << shft); |
76 | 65 | ||
77 | if (c & MFP_DIR_OUT) | 66 | if (uorl == 0) |
67 | GAFR_L(bank) = gafr; | ||
68 | else | ||
69 | GAFR_U(bank) = gafr; | ||
70 | |||
71 | if (dir == MFP_DIR_OUT) | ||
78 | GPDR(gpio) |= mask; | 72 | GPDR(gpio) |= mask; |
79 | else | 73 | else |
80 | GPDR(gpio) &= ~mask; | 74 | GPDR(gpio) &= ~mask; |
81 | 75 | ||
82 | if (__mfp_config_lpm(gpio, c & MFP_LPM_STATE_MASK)) | 76 | /* alternate function and direction at low power mode */ |
83 | return -EINVAL; | 77 | switch (c & MFP_LPM_STATE_MASK) { |
78 | case MFP_LPM_DRIVE_HIGH: | ||
79 | PGSR(bank) |= mask; | ||
80 | dir = MFP_DIR_OUT; | ||
81 | break; | ||
82 | case MFP_LPM_DRIVE_LOW: | ||
83 | PGSR(bank) &= ~mask; | ||
84 | dir = MFP_DIR_OUT; | ||
85 | break; | ||
86 | case MFP_LPM_DEFAULT: | ||
87 | break; | ||
88 | default: | ||
89 | /* warning and fall through, treat as MFP_LPM_DEFAULT */ | ||
90 | pr_warning("%s: GPIO%d: unsupported low power mode\n", | ||
91 | __func__, gpio); | ||
92 | break; | ||
93 | } | ||
94 | |||
95 | if (dir == MFP_DIR_OUT) | ||
96 | gpdr_lpm[bank] |= mask; | ||
97 | else | ||
98 | gpdr_lpm[bank] &= ~mask; | ||
84 | 99 | ||
85 | /* give early warning if MFP_LPM_CAN_WAKEUP is set on the | 100 | /* give early warning if MFP_LPM_CAN_WAKEUP is set on the |
86 | * configurations of those pins not able to wakeup | 101 | * configurations of those pins not able to wakeup |
@@ -91,7 +106,7 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c) | |||
91 | return -EINVAL; | 106 | return -EINVAL; |
92 | } | 107 | } |
93 | 108 | ||
94 | if ((c & MFP_LPM_CAN_WAKEUP) && (c & MFP_DIR_OUT)) { | 109 | if ((c & MFP_LPM_CAN_WAKEUP) && (dir == MFP_DIR_OUT)) { |
95 | pr_warning("%s: output GPIO%d unable to wakeup\n", | 110 | pr_warning("%s: output GPIO%d unable to wakeup\n", |
96 | __func__, gpio); | 111 | __func__, gpio); |
97 | return -EINVAL; | 112 | return -EINVAL; |
@@ -135,7 +150,7 @@ void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num) | |||
135 | 150 | ||
136 | void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm) | 151 | void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm) |
137 | { | 152 | { |
138 | unsigned long flags; | 153 | unsigned long flags, c; |
139 | int gpio; | 154 | int gpio; |
140 | 155 | ||
141 | gpio = __mfp_validate(mfp); | 156 | gpio = __mfp_validate(mfp); |
@@ -143,7 +158,11 @@ void pxa2xx_mfp_set_lpm(int mfp, unsigned long lpm) | |||
143 | return; | 158 | return; |
144 | 159 | ||
145 | local_irq_save(flags); | 160 | local_irq_save(flags); |
146 | __mfp_config_lpm(gpio, lpm); | 161 | |
162 | c = gpio_desc[gpio].config; | ||
163 | c = (c & ~MFP_LPM_STATE_MASK) | lpm; | ||
164 | __mfp_config_gpio(gpio, c); | ||
165 | |||
147 | local_irq_restore(flags); | 166 | local_irq_restore(flags); |
148 | } | 167 | } |
149 | 168 | ||
@@ -187,23 +206,22 @@ int gpio_set_wake(unsigned int gpio, unsigned int on) | |||
187 | } | 206 | } |
188 | 207 | ||
189 | #ifdef CONFIG_PXA25x | 208 | #ifdef CONFIG_PXA25x |
190 | static int __init pxa25x_mfp_init(void) | 209 | static void __init pxa25x_mfp_init(void) |
191 | { | 210 | { |
192 | int i; | 211 | int i; |
193 | 212 | ||
194 | if (cpu_is_pxa25x()) { | 213 | for (i = 0; i <= 84; i++) |
195 | for (i = 0; i <= 84; i++) | 214 | gpio_desc[i].valid = 1; |
196 | gpio_desc[i].valid = 1; | ||
197 | 215 | ||
198 | for (i = 0; i <= 15; i++) { | 216 | for (i = 0; i <= 15; i++) { |
199 | gpio_desc[i].can_wakeup = 1; | 217 | gpio_desc[i].can_wakeup = 1; |
200 | gpio_desc[i].mask = GPIO_bit(i); | 218 | gpio_desc[i].mask = GPIO_bit(i); |
201 | } | ||
202 | } | 219 | } |
203 | 220 | ||
204 | return 0; | 221 | gpio_nr = 85; |
205 | } | 222 | } |
206 | postcore_initcall(pxa25x_mfp_init); | 223 | #else |
224 | static inline void pxa25x_mfp_init(void) {} | ||
207 | #endif /* CONFIG_PXA25x */ | 225 | #endif /* CONFIG_PXA25x */ |
208 | 226 | ||
209 | #ifdef CONFIG_PXA27x | 227 | #ifdef CONFIG_PXA27x |
@@ -233,45 +251,106 @@ int keypad_set_wake(unsigned int on) | |||
233 | return 0; | 251 | return 0; |
234 | } | 252 | } |
235 | 253 | ||
236 | static int __init pxa27x_mfp_init(void) | 254 | static void __init pxa27x_mfp_init(void) |
237 | { | 255 | { |
238 | int i, gpio; | 256 | int i, gpio; |
239 | 257 | ||
240 | if (cpu_is_pxa27x()) { | 258 | for (i = 0; i <= 120; i++) { |
241 | for (i = 0; i <= 120; i++) { | 259 | /* skip GPIO2, 5, 6, 7, 8, they are not |
242 | /* skip GPIO2, 5, 6, 7, 8, they are not | 260 | * valid pins allow configuration |
243 | * valid pins allow configuration | 261 | */ |
244 | */ | 262 | if (i == 2 || i == 5 || i == 6 || i == 7 || i == 8) |
245 | if (i == 2 || i == 5 || i == 6 || | 263 | continue; |
246 | i == 7 || i == 8) | ||
247 | continue; | ||
248 | 264 | ||
249 | gpio_desc[i].valid = 1; | 265 | gpio_desc[i].valid = 1; |
250 | } | 266 | } |
251 | 267 | ||
252 | /* Keypad GPIOs */ | 268 | /* Keypad GPIOs */ |
253 | for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { | 269 | for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { |
254 | gpio = pxa27x_pkwr_gpio[i]; | 270 | gpio = pxa27x_pkwr_gpio[i]; |
255 | gpio_desc[gpio].can_wakeup = 1; | 271 | gpio_desc[gpio].can_wakeup = 1; |
256 | gpio_desc[gpio].keypad_gpio = 1; | 272 | gpio_desc[gpio].keypad_gpio = 1; |
257 | gpio_desc[gpio].mask = 1 << i; | 273 | gpio_desc[gpio].mask = 1 << i; |
258 | } | 274 | } |
259 | 275 | ||
260 | /* Overwrite GPIO13 as a PWER wakeup source */ | 276 | /* Overwrite GPIO13 as a PWER wakeup source */ |
261 | for (i = 0; i <= 15; i++) { | 277 | for (i = 0; i <= 15; i++) { |
262 | /* skip GPIO2, 5, 6, 7, 8 */ | 278 | /* skip GPIO2, 5, 6, 7, 8 */ |
263 | if (GPIO_bit(i) & 0x1e4) | 279 | if (GPIO_bit(i) & 0x1e4) |
264 | continue; | 280 | continue; |
265 | 281 | ||
266 | gpio_desc[i].can_wakeup = 1; | 282 | gpio_desc[i].can_wakeup = 1; |
267 | gpio_desc[i].mask = GPIO_bit(i); | 283 | gpio_desc[i].mask = GPIO_bit(i); |
268 | } | 284 | } |
285 | |||
286 | gpio_desc[35].can_wakeup = 1; | ||
287 | gpio_desc[35].mask = PWER_WE35; | ||
288 | |||
289 | gpio_nr = 121; | ||
290 | } | ||
291 | #else | ||
292 | static inline void pxa27x_mfp_init(void) {} | ||
293 | #endif /* CONFIG_PXA27x */ | ||
294 | |||
295 | #ifdef CONFIG_PM | ||
296 | static unsigned long saved_gafr[2][4]; | ||
297 | static unsigned long saved_gpdr[4]; | ||
269 | 298 | ||
270 | gpio_desc[35].can_wakeup = 1; | 299 | static int pxa2xx_mfp_suspend(struct sys_device *d, pm_message_t state) |
271 | gpio_desc[35].mask = PWER_WE35; | 300 | { |
301 | int i; | ||
302 | |||
303 | for (i = 0; i <= gpio_to_bank(gpio_nr); i++) { | ||
304 | |||
305 | saved_gafr[0][i] = GAFR_L(i); | ||
306 | saved_gafr[1][i] = GAFR_U(i); | ||
307 | saved_gpdr[i] = GPDR(i * 32); | ||
308 | |||
309 | GPDR(i * 32) = gpdr_lpm[i]; | ||
272 | } | 310 | } |
311 | return 0; | ||
312 | } | ||
273 | 313 | ||
314 | static int pxa2xx_mfp_resume(struct sys_device *d) | ||
315 | { | ||
316 | int i; | ||
317 | |||
318 | for (i = 0; i <= gpio_to_bank(gpio_nr); i++) { | ||
319 | GAFR_L(i) = saved_gafr[0][i]; | ||
320 | GAFR_U(i) = saved_gafr[1][i]; | ||
321 | GPDR(i * 32) = saved_gpdr[i]; | ||
322 | } | ||
323 | PSSR = PSSR_RDH | PSSR_PH; | ||
274 | return 0; | 324 | return 0; |
275 | } | 325 | } |
276 | postcore_initcall(pxa27x_mfp_init); | 326 | #else |
277 | #endif /* CONFIG_PXA27x */ | 327 | #define pxa2xx_mfp_suspend NULL |
328 | #define pxa2xx_mfp_resume NULL | ||
329 | #endif | ||
330 | |||
331 | struct sysdev_class pxa2xx_mfp_sysclass = { | ||
332 | .name = "mfp", | ||
333 | .suspend = pxa2xx_mfp_suspend, | ||
334 | .resume = pxa2xx_mfp_resume, | ||
335 | }; | ||
336 | |||
337 | static int __init pxa2xx_mfp_init(void) | ||
338 | { | ||
339 | int i; | ||
340 | |||
341 | if (!cpu_is_pxa2xx()) | ||
342 | return 0; | ||
343 | |||
344 | if (cpu_is_pxa25x()) | ||
345 | pxa25x_mfp_init(); | ||
346 | |||
347 | if (cpu_is_pxa27x()) | ||
348 | pxa27x_mfp_init(); | ||
349 | |||
350 | /* initialize gafr_run[], pgsr_lpm[] from existing values */ | ||
351 | for (i = 0; i <= gpio_to_bank(gpio_nr); i++) | ||
352 | gpdr_lpm[i] = GPDR(i * 32); | ||
353 | |||
354 | return sysdev_class_register(&pxa2xx_mfp_sysclass); | ||
355 | } | ||
356 | postcore_initcall(pxa2xx_mfp_init); | ||