diff options
author | Michael Hennerich <michael.hennerich@analog.com> | 2007-08-28 04:47:46 -0400 |
---|---|---|
committer | Bryan Wu <bryan.wu@analog.com> | 2007-08-28 04:47:46 -0400 |
commit | d2b11a468a49716debd96532552a72b6078f1cf5 (patch) | |
tree | b30d94732f9d01b823e60975147b284aead495d9 /arch/blackfin/mach-bf548 | |
parent | 2296fb7ff04531dd8d50394da24f49302ecf103b (diff) |
Blackfin arch: Merge GPIO/Peripheral Resource Allocation back into a single file
Signed-off-by: Michael Hennerich <michale.hennerich@analog.com>
Signed-off-by: Bryan Wu <bryan.wu@analog.com>
Diffstat (limited to 'arch/blackfin/mach-bf548')
-rw-r--r-- | arch/blackfin/mach-bf548/Makefile | 2 | ||||
-rw-r--r-- | arch/blackfin/mach-bf548/gpio.c | 392 |
2 files changed, 1 insertions, 393 deletions
diff --git a/arch/blackfin/mach-bf548/Makefile b/arch/blackfin/mach-bf548/Makefile index 060ad78ebf1d..7e7c9c8ac5b2 100644 --- a/arch/blackfin/mach-bf548/Makefile +++ b/arch/blackfin/mach-bf548/Makefile | |||
@@ -4,6 +4,6 @@ | |||
4 | 4 | ||
5 | extra-y := head.o | 5 | extra-y := head.o |
6 | 6 | ||
7 | obj-y := ints-priority.o dma.o gpio.o | 7 | obj-y := ints-priority.o dma.o |
8 | 8 | ||
9 | obj-$(CONFIG_CPU_FREQ) += cpu.o | 9 | obj-$(CONFIG_CPU_FREQ) += cpu.o |
diff --git a/arch/blackfin/mach-bf548/gpio.c b/arch/blackfin/mach-bf548/gpio.c deleted file mode 100644 index 390dd8c12430..000000000000 --- a/arch/blackfin/mach-bf548/gpio.c +++ /dev/null | |||
@@ -1,392 +0,0 @@ | |||
1 | /* | ||
2 | * File: arch/blackfin/mach-bf548/gpio.c | ||
3 | * Based on: | ||
4 | * Author: Michael Hennerich (hennerich@blackfin.uclinux.org) | ||
5 | * | ||
6 | * Created: | ||
7 | * Description: GPIO Abstraction Layer | ||
8 | * | ||
9 | * Modified: | ||
10 | * Copyright 2007 Analog Devices Inc. | ||
11 | * | ||
12 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License as published by | ||
16 | * the Free Software Foundation; either version 2 of the License, or | ||
17 | * (at your option) any later version. | ||
18 | * | ||
19 | * This program is distributed in the hope that it will be useful, | ||
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | * GNU General Public License for more details. | ||
23 | * | ||
24 | * You should have received a copy of the GNU General Public License | ||
25 | * along with this program; if not, see the file COPYING, or write | ||
26 | * to the Free Software Foundation, Inc., | ||
27 | * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
28 | */ | ||
29 | |||
30 | #include <linux/module.h> | ||
31 | #include <linux/err.h> | ||
32 | #include <asm/blackfin.h> | ||
33 | #include <asm/gpio.h> | ||
34 | #include <asm/portmux.h> | ||
35 | #include <linux/irq.h> | ||
36 | |||
37 | static struct gpio_port_t *gpio_array[gpio_bank(MAX_BLACKFIN_GPIOS)] = { | ||
38 | (struct gpio_port_t *)PORTA_FER, | ||
39 | (struct gpio_port_t *)PORTB_FER, | ||
40 | (struct gpio_port_t *)PORTC_FER, | ||
41 | (struct gpio_port_t *)PORTD_FER, | ||
42 | (struct gpio_port_t *)PORTE_FER, | ||
43 | (struct gpio_port_t *)PORTF_FER, | ||
44 | (struct gpio_port_t *)PORTG_FER, | ||
45 | (struct gpio_port_t *)PORTH_FER, | ||
46 | (struct gpio_port_t *)PORTI_FER, | ||
47 | (struct gpio_port_t *)PORTJ_FER, | ||
48 | }; | ||
49 | |||
50 | static unsigned short reserved_gpio_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; | ||
51 | static unsigned short reserved_peri_map[gpio_bank(MAX_BLACKFIN_GPIOS)]; | ||
52 | |||
53 | #define MAX_RESOURCES 256 | ||
54 | #define RESOURCE_LABEL_SIZE 16 | ||
55 | |||
56 | struct str_ident { | ||
57 | char name[RESOURCE_LABEL_SIZE]; | ||
58 | } *str_ident; | ||
59 | |||
60 | inline int check_gpio(unsigned short gpio) | ||
61 | { | ||
62 | if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 | ||
63 | || gpio == GPIO_PH14 || gpio == GPIO_PH15 | ||
64 | || gpio == GPIO_PJ14 || gpio == GPIO_PJ15 | ||
65 | || gpio > MAX_BLACKFIN_GPIOS) | ||
66 | return -EINVAL; | ||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | inline void portmux_setup(unsigned short portno, unsigned short function) | ||
71 | { | ||
72 | u32 pmux; | ||
73 | |||
74 | pmux = gpio_array[gpio_bank(portno)]->port_mux; | ||
75 | |||
76 | pmux &= ~(0x3 << (2 * gpio_sub_n(portno))); | ||
77 | pmux |= (function & 0x3) << (2 * gpio_sub_n(portno)); | ||
78 | |||
79 | gpio_array[gpio_bank(portno)]->port_mux = pmux; | ||
80 | } | ||
81 | |||
82 | inline u16 get_portmux(unsigned short portno) | ||
83 | { | ||
84 | u32 pmux; | ||
85 | |||
86 | pmux = gpio_array[gpio_bank(portno)]->port_mux; | ||
87 | |||
88 | return (pmux >> (2 * gpio_sub_n(portno)) & 0x3); | ||
89 | } | ||
90 | |||
91 | static void port_setup(unsigned short gpio, unsigned short usage) | ||
92 | { | ||
93 | if (usage == GPIO_USAGE) { | ||
94 | gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); | ||
95 | } else | ||
96 | gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); | ||
97 | SSYNC(); | ||
98 | } | ||
99 | |||
100 | static int __init bfin_gpio_init(void) | ||
101 | { | ||
102 | |||
103 | str_ident = kcalloc(MAX_RESOURCES, | ||
104 | sizeof(struct str_ident), GFP_KERNEL); | ||
105 | if (str_ident == NULL) | ||
106 | return -ENOMEM; | ||
107 | |||
108 | memset(str_ident, 0, MAX_RESOURCES * sizeof(struct str_ident)); | ||
109 | |||
110 | printk(KERN_INFO "Blackfin GPIO Controller\n"); | ||
111 | |||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | arch_initcall(bfin_gpio_init); | ||
116 | |||
117 | static void set_label(unsigned short ident, const char *label) | ||
118 | { | ||
119 | |||
120 | if (label && str_ident) { | ||
121 | strncpy(str_ident[ident].name, label, | ||
122 | RESOURCE_LABEL_SIZE); | ||
123 | str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; | ||
124 | } | ||
125 | } | ||
126 | |||
127 | static char *get_label(unsigned short ident) | ||
128 | { | ||
129 | if (!str_ident) | ||
130 | return "UNKNOWN"; | ||
131 | |||
132 | return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); | ||
133 | } | ||
134 | |||
135 | static int cmp_label(unsigned short ident, const char *label) | ||
136 | { | ||
137 | if (label && str_ident) | ||
138 | return strncmp(str_ident[ident].name, | ||
139 | label, strlen(label)); | ||
140 | else | ||
141 | return -EINVAL; | ||
142 | } | ||
143 | |||
144 | int peripheral_request(unsigned short per, const char *label) | ||
145 | { | ||
146 | unsigned long flags; | ||
147 | unsigned short ident = P_IDENT(per); | ||
148 | |||
149 | /* | ||
150 | * Don't cares are pins with only one dedicated function | ||
151 | */ | ||
152 | |||
153 | if (per & P_DONTCARE) | ||
154 | return 0; | ||
155 | |||
156 | if (!(per & P_DEFINED)) | ||
157 | return -ENODEV; | ||
158 | |||
159 | if (check_gpio(ident) < 0) | ||
160 | return -EINVAL; | ||
161 | |||
162 | local_irq_save(flags); | ||
163 | |||
164 | if (unlikely(reserved_gpio_map[gpio_bank(ident)] & gpio_bit(ident))) { | ||
165 | printk(KERN_ERR | ||
166 | "%s: Peripheral %d is already reserved as GPIO by %s !\n", | ||
167 | __FUNCTION__, ident, get_label(ident)); | ||
168 | dump_stack(); | ||
169 | local_irq_restore(flags); | ||
170 | return -EBUSY; | ||
171 | } | ||
172 | |||
173 | if (unlikely(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident))) { | ||
174 | |||
175 | u16 funct = get_portmux(ident); | ||
176 | |||
177 | /* | ||
178 | * Pin functions like AMC address strobes my | ||
179 | * be requested and used by several drivers | ||
180 | */ | ||
181 | |||
182 | if (!((per & P_MAYSHARE) && (funct == P_FUNCT2MUX(per)))) { | ||
183 | |||
184 | /* | ||
185 | * Allow that the identical pin function can | ||
186 | * be requested from the same driver twice | ||
187 | */ | ||
188 | |||
189 | if (cmp_label(ident, label) == 0) | ||
190 | goto anyway; | ||
191 | |||
192 | printk(KERN_ERR | ||
193 | "%s: Peripheral %d function %d is already reserved by %s !\n", | ||
194 | __FUNCTION__, ident, P_FUNCT2MUX(per), get_label(ident)); | ||
195 | dump_stack(); | ||
196 | local_irq_restore(flags); | ||
197 | return -EBUSY; | ||
198 | } | ||
199 | } | ||
200 | |||
201 | anyway: | ||
202 | reserved_peri_map[gpio_bank(ident)] |= gpio_bit(ident); | ||
203 | |||
204 | portmux_setup(ident, P_FUNCT2MUX(per)); | ||
205 | port_setup(ident, PERIPHERAL_USAGE); | ||
206 | |||
207 | local_irq_restore(flags); | ||
208 | set_label(ident, label); | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | EXPORT_SYMBOL(peripheral_request); | ||
213 | |||
214 | int peripheral_request_list(unsigned short per[], const char *label) | ||
215 | { | ||
216 | u16 cnt; | ||
217 | int ret; | ||
218 | |||
219 | for (cnt = 0; per[cnt] != 0; cnt++) { | ||
220 | |||
221 | ret = peripheral_request(per[cnt], label); | ||
222 | |||
223 | if (ret < 0) { | ||
224 | for ( ; cnt > 0; cnt--) { | ||
225 | peripheral_free(per[cnt - 1]); | ||
226 | } | ||
227 | return ret; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | |||
232 | return 0; | ||
233 | } | ||
234 | EXPORT_SYMBOL(peripheral_request_list); | ||
235 | |||
236 | void peripheral_free(unsigned short per) | ||
237 | { | ||
238 | unsigned long flags; | ||
239 | unsigned short ident = P_IDENT(per); | ||
240 | |||
241 | if (per & P_DONTCARE) | ||
242 | return; | ||
243 | |||
244 | if (!(per & P_DEFINED)) | ||
245 | return; | ||
246 | |||
247 | if (check_gpio(ident) < 0) | ||
248 | return; | ||
249 | |||
250 | local_irq_save(flags); | ||
251 | |||
252 | if (unlikely(!(reserved_peri_map[gpio_bank(ident)] & gpio_bit(ident)))) { | ||
253 | local_irq_restore(flags); | ||
254 | return; | ||
255 | } | ||
256 | |||
257 | if (!(per & P_MAYSHARE)) { | ||
258 | port_setup(ident, GPIO_USAGE); | ||
259 | } | ||
260 | |||
261 | reserved_peri_map[gpio_bank(ident)] &= ~gpio_bit(ident); | ||
262 | |||
263 | local_irq_restore(flags); | ||
264 | } | ||
265 | EXPORT_SYMBOL(peripheral_free); | ||
266 | |||
267 | void peripheral_free_list(unsigned short per[]) | ||
268 | { | ||
269 | u16 cnt; | ||
270 | |||
271 | for (cnt = 0; per[cnt] != 0; cnt++) { | ||
272 | peripheral_free(per[cnt]); | ||
273 | } | ||
274 | |||
275 | } | ||
276 | EXPORT_SYMBOL(peripheral_free_list); | ||
277 | |||
278 | /*********************************************************** | ||
279 | * | ||
280 | * FUNCTIONS: Blackfin GPIO Driver | ||
281 | * | ||
282 | * INPUTS/OUTPUTS: | ||
283 | * gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS | ||
284 | * | ||
285 | * | ||
286 | * DESCRIPTION: Blackfin GPIO Driver API | ||
287 | * | ||
288 | * CAUTION: | ||
289 | ************************************************************* | ||
290 | * MODIFICATION HISTORY : | ||
291 | **************************************************************/ | ||
292 | |||
293 | int gpio_request(unsigned short gpio, const char *label) | ||
294 | { | ||
295 | unsigned long flags; | ||
296 | |||
297 | if (check_gpio(gpio) < 0) | ||
298 | return -EINVAL; | ||
299 | |||
300 | local_irq_save(flags); | ||
301 | |||
302 | if (unlikely(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))) { | ||
303 | printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", | ||
304 | gpio, get_label(gpio)); | ||
305 | dump_stack(); | ||
306 | local_irq_restore(flags); | ||
307 | return -EBUSY; | ||
308 | } | ||
309 | |||
310 | if (unlikely(reserved_peri_map[gpio_bank(gpio)] & gpio_bit(gpio))) { | ||
311 | printk(KERN_ERR | ||
312 | "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", | ||
313 | gpio, get_label(gpio)); | ||
314 | dump_stack(); | ||
315 | local_irq_restore(flags); | ||
316 | return -EBUSY; | ||
317 | } | ||
318 | |||
319 | reserved_gpio_map[gpio_bank(gpio)] |= gpio_bit(gpio); | ||
320 | |||
321 | local_irq_restore(flags); | ||
322 | |||
323 | port_setup(gpio, GPIO_USAGE); | ||
324 | set_label(gpio, label); | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | EXPORT_SYMBOL(gpio_request); | ||
329 | |||
330 | void gpio_free(unsigned short gpio) | ||
331 | { | ||
332 | unsigned long flags; | ||
333 | |||
334 | if (check_gpio(gpio) < 0) | ||
335 | return; | ||
336 | |||
337 | local_irq_save(flags); | ||
338 | |||
339 | if (unlikely(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio)))) { | ||
340 | printk(KERN_ERR "bfin-gpio: GPIO %d wasn't reserved!\n", gpio); | ||
341 | dump_stack(); | ||
342 | local_irq_restore(flags); | ||
343 | return; | ||
344 | } | ||
345 | |||
346 | reserved_gpio_map[gpio_bank(gpio)] &= ~gpio_bit(gpio); | ||
347 | |||
348 | local_irq_restore(flags); | ||
349 | } | ||
350 | EXPORT_SYMBOL(gpio_free); | ||
351 | |||
352 | void gpio_direction_input(unsigned short gpio) | ||
353 | { | ||
354 | unsigned long flags; | ||
355 | |||
356 | BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); | ||
357 | |||
358 | local_irq_save(flags); | ||
359 | gpio_array[gpio_bank(gpio)]->port_dir_clear = gpio_bit(gpio); | ||
360 | gpio_array[gpio_bank(gpio)]->port_inen |= gpio_bit(gpio); | ||
361 | local_irq_restore(flags); | ||
362 | } | ||
363 | EXPORT_SYMBOL(gpio_direction_input); | ||
364 | |||
365 | void gpio_direction_output(unsigned short gpio) | ||
366 | { | ||
367 | unsigned long flags; | ||
368 | |||
369 | BUG_ON(!(reserved_gpio_map[gpio_bank(gpio)] & gpio_bit(gpio))); | ||
370 | |||
371 | local_irq_save(flags); | ||
372 | gpio_array[gpio_bank(gpio)]->port_inen &= ~gpio_bit(gpio); | ||
373 | gpio_array[gpio_bank(gpio)]->port_dir_set = gpio_bit(gpio); | ||
374 | local_irq_restore(flags); | ||
375 | } | ||
376 | EXPORT_SYMBOL(gpio_direction_output); | ||
377 | |||
378 | void gpio_set_value(unsigned short gpio, unsigned short arg) | ||
379 | { | ||
380 | if (arg) | ||
381 | gpio_array[gpio_bank(gpio)]->port_set = gpio_bit(gpio); | ||
382 | else | ||
383 | gpio_array[gpio_bank(gpio)]->port_clear = gpio_bit(gpio); | ||
384 | |||
385 | } | ||
386 | EXPORT_SYMBOL(gpio_set_value); | ||
387 | |||
388 | unsigned short gpio_get_value(unsigned short gpio) | ||
389 | { | ||
390 | return (1 & (gpio_array[gpio_bank(gpio)]->port_data >> gpio_sub_n(gpio))); | ||
391 | } | ||
392 | EXPORT_SYMBOL(gpio_get_value); | ||