]> err.no Git - linux-2.6/blob - arch/blackfin/mach-bf548/gpio.c
Blackfin arch: Fix CCLK and SCLK checks
[linux-2.6] / arch / blackfin / mach-bf548 / gpio.c
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);