diff options
Diffstat (limited to 'arch/arm')
-rw-r--r-- | arch/arm/mach-pxa/Makefile | 4 | ||||
-rw-r--r-- | arch/arm/mach-pxa/mfp-pxa2xx.c | 190 |
2 files changed, 192 insertions, 2 deletions
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile index 10e0c0dce198..df2eb9fcf942 100644 --- a/arch/arm/mach-pxa/Makefile +++ b/arch/arm/mach-pxa/Makefile | |||
@@ -5,8 +5,8 @@ | |||
5 | # Common support (must be linked before board specific support) | 5 | # Common support (must be linked before board specific support) |
6 | obj-y += clock.o devices.o generic.o irq.o dma.o \ | 6 | obj-y += clock.o devices.o generic.o irq.o dma.o \ |
7 | time.o gpio.o | 7 | time.o gpio.o |
8 | obj-$(CONFIG_PXA25x) += pxa25x.o | 8 | obj-$(CONFIG_PXA25x) += pxa25x.o mfp-pxa2xx.o |
9 | obj-$(CONFIG_PXA27x) += pxa27x.o | 9 | obj-$(CONFIG_PXA27x) += pxa27x.o mfp-pxa2xx.o |
10 | obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp-pxa3xx.o smemc.o | 10 | obj-$(CONFIG_PXA3xx) += pxa3xx.o mfp-pxa3xx.o smemc.o |
11 | obj-$(CONFIG_CPU_PXA300) += pxa300.o | 11 | obj-$(CONFIG_CPU_PXA300) += pxa300.o |
12 | obj-$(CONFIG_CPU_PXA320) += pxa320.o | 12 | obj-$(CONFIG_CPU_PXA320) += pxa320.o |
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c new file mode 100644 index 000000000000..f85f681c0393 --- /dev/null +++ b/arch/arm/mach-pxa/mfp-pxa2xx.c | |||
@@ -0,0 +1,190 @@ | |||
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/mfp-pxa2xx.h> | ||
24 | |||
25 | #include "generic.h" | ||
26 | |||
27 | #define PGSR(x) __REG2(0x40F00020, ((x) & 0x60) >> 3) | ||
28 | |||
29 | #define PWER_WE35 (1 << 24) | ||
30 | |||
31 | static struct { | ||
32 | unsigned valid : 1; | ||
33 | unsigned can_wakeup : 1; | ||
34 | unsigned keypad_gpio : 1; | ||
35 | unsigned int mask; /* bit mask in PWER or PKWR */ | ||
36 | unsigned long config; | ||
37 | } gpio_desc[MFP_PIN_GPIO127 + 1]; | ||
38 | |||
39 | static inline int __mfp_config_gpio(unsigned gpio, unsigned long c) | ||
40 | { | ||
41 | unsigned long gafr, mask = GPIO_bit(gpio); | ||
42 | int fn; | ||
43 | |||
44 | fn = MFP_AF(c); | ||
45 | if (fn > 3) | ||
46 | return -EINVAL; | ||
47 | |||
48 | /* alternate function and direction */ | ||
49 | gafr = GAFR(gpio) & ~(0x3 << ((gpio & 0xf) * 2)); | ||
50 | GAFR(gpio) = gafr | (fn << ((gpio & 0xf) * 2)); | ||
51 | |||
52 | if (c & MFP_DIR_OUT) | ||
53 | GPDR(gpio) |= mask; | ||
54 | else | ||
55 | GPDR(gpio) &= ~mask; | ||
56 | |||
57 | /* low power state */ | ||
58 | switch (c & MFP_LPM_STATE_MASK) { | ||
59 | case MFP_LPM_DRIVE_HIGH: | ||
60 | PGSR(gpio) |= mask; | ||
61 | break; | ||
62 | case MFP_LPM_DRIVE_LOW: | ||
63 | PGSR(gpio) &= ~mask; | ||
64 | break; | ||
65 | case MFP_LPM_INPUT: | ||
66 | break; | ||
67 | default: | ||
68 | pr_warning("%s: invalid low power state for GPIO%d\n", | ||
69 | __func__, gpio); | ||
70 | return -EINVAL; | ||
71 | } | ||
72 | |||
73 | /* wakeup enabling */ | ||
74 | if ((c & MFP_LPM_WAKEUP_ENABLE) == 0) | ||
75 | return 0; | ||
76 | |||
77 | if (!gpio_desc[gpio].can_wakeup || c & MFP_DIR_OUT) { | ||
78 | pr_warning("%s: GPIO%d unable to wakeup\n", | ||
79 | __func__, gpio); | ||
80 | return -EINVAL; | ||
81 | } | ||
82 | |||
83 | if (gpio_desc[gpio].keypad_gpio) | ||
84 | PKWR |= gpio_desc[gpio].mask; | ||
85 | else { | ||
86 | PWER |= gpio_desc[gpio].mask; | ||
87 | |||
88 | if (c & MFP_LPM_EDGE_RISE) | ||
89 | PRER |= gpio_desc[gpio].mask; | ||
90 | |||
91 | if (c & MFP_LPM_EDGE_FALL) | ||
92 | PFER |= gpio_desc[gpio].mask; | ||
93 | } | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | void pxa2xx_mfp_config(unsigned long *mfp_cfgs, int num) | ||
99 | { | ||
100 | unsigned long flags; | ||
101 | unsigned long *c; | ||
102 | int i, gpio; | ||
103 | |||
104 | for (i = 0, c = mfp_cfgs; i < num; i++, c++) { | ||
105 | |||
106 | gpio = mfp_to_gpio(MFP_PIN(*c)); | ||
107 | |||
108 | if (!gpio_desc[gpio].valid) { | ||
109 | pr_warning("%s: GPIO%d is invalid pin\n", | ||
110 | __func__, gpio); | ||
111 | continue; | ||
112 | } | ||
113 | |||
114 | local_irq_save(flags); | ||
115 | |||
116 | gpio_desc[gpio].config = *c; | ||
117 | __mfp_config_gpio(gpio, *c); | ||
118 | |||
119 | local_irq_restore(flags); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | #ifdef CONFIG_PXA25x | ||
124 | static int __init pxa25x_mfp_init(void) | ||
125 | { | ||
126 | int i; | ||
127 | |||
128 | if (cpu_is_pxa25x()) { | ||
129 | for (i = 0; i <= 84; i++) | ||
130 | gpio_desc[i].valid = 1; | ||
131 | |||
132 | for (i = 0; i <= 15; i++) { | ||
133 | gpio_desc[i].can_wakeup = 1; | ||
134 | gpio_desc[i].mask = GPIO_bit(i); | ||
135 | } | ||
136 | } | ||
137 | |||
138 | return 0; | ||
139 | } | ||
140 | postcore_initcall(pxa25x_mfp_init); | ||
141 | #endif /* CONFIG_PXA25x */ | ||
142 | |||
143 | #ifdef CONFIG_PXA27x | ||
144 | static int pxa27x_pkwr_gpio[] __initdata = { | ||
145 | 13, 16, 17, 34, 36, 37, 38, 39, 90, 91, 93, 94, | ||
146 | 95, 96, 97, 98, 99, 100, 101, 102 | ||
147 | }; | ||
148 | |||
149 | static int __init pxa27x_mfp_init(void) | ||
150 | { | ||
151 | int i, gpio; | ||
152 | |||
153 | if (cpu_is_pxa27x()) { | ||
154 | for (i = 0; i <= 120; i++) { | ||
155 | /* skip GPIO2, 5, 6, 7, 8, they are not | ||
156 | * valid pins allow configuration | ||
157 | */ | ||
158 | if (i == 2 || i == 5 || i == 6 || | ||
159 | i == 7 || i == 8) | ||
160 | continue; | ||
161 | |||
162 | gpio_desc[i].valid = 1; | ||
163 | } | ||
164 | |||
165 | /* Keypad GPIOs */ | ||
166 | for (i = 0; i < ARRAY_SIZE(pxa27x_pkwr_gpio); i++) { | ||
167 | gpio = pxa27x_pkwr_gpio[i]; | ||
168 | gpio_desc[gpio].can_wakeup = 1; | ||
169 | gpio_desc[gpio].keypad_gpio = 1; | ||
170 | gpio_desc[gpio].mask = 1 << i; | ||
171 | } | ||
172 | |||
173 | /* Overwrite GPIO13 as a PWER wakeup source */ | ||
174 | for (i = 0; i <= 15; i++) { | ||
175 | /* skip GPIO2, 5, 6, 7, 8 */ | ||
176 | if (GPIO_bit(i) & 0x1e4) | ||
177 | continue; | ||
178 | |||
179 | gpio_desc[i].can_wakeup = 1; | ||
180 | gpio_desc[i].mask = GPIO_bit(i); | ||
181 | } | ||
182 | |||
183 | gpio_desc[35].can_wakeup = 1; | ||
184 | gpio_desc[35].mask = PWER_WE35; | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | postcore_initcall(pxa27x_mfp_init); | ||
190 | #endif /* CONFIG_PXA27x */ | ||