]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/arm/mach-ns9xxx/gpio.c
[ARM] 4590/1: ns9xxx: add gpio handling functions
[linux-2.6-omap-h63xx.git] / arch / arm / mach-ns9xxx / gpio.c
1 /*
2  * arch/arm/mach-ns9xxx/gpio.c
3  *
4  * Copyright (C) 2006 by Digi International Inc.
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License version 2 as published by
9  * the Free Software Foundation.
10  */
11 #include <linux/compiler.h>
12 #include <linux/init.h>
13 #include <linux/spinlock.h>
14 #include <linux/module.h>
15
16 #include <asm/arch-ns9xxx/gpio.h>
17 #include <asm/arch-ns9xxx/processor.h>
18 #include <asm/arch-ns9xxx/regs-bbu.h>
19 #include <asm/bug.h>
20 #include <asm/types.h>
21 #include <asm/bitops.h>
22
23 #if defined(CONFIG_PROCESSOR_NS9360)
24 #define GPIO_MAX 72
25 #elif defined(CONFIG_PROCESSOR_NS9750)
26 #define GPIO_MAX 49
27 #endif
28
29 /* protects BBU_GCONFx and BBU_GCTRLx */
30 static spinlock_t gpio_lock = __SPIN_LOCK_UNLOCKED(gpio_lock);
31
32 /* only access gpiores with atomic ops */
33 static DECLARE_BITMAP(gpiores, GPIO_MAX);
34
35 static inline int ns9xxx_valid_gpio(unsigned gpio)
36 {
37 #if defined(CONFIG_PROCESSOR_NS9360)
38         if (processor_is_ns9360())
39                 return gpio <= 72;
40         else
41 #endif
42 #if defined(CONFIG_PROCESSOR_NS9750)
43         if (processor_is_ns9750())
44                 return gpio <= 49;
45         else
46 #endif
47                 BUG();
48 }
49
50 static inline volatile u32 *ns9xxx_gpio_get_gconfaddr(unsigned gpio)
51 {
52         if (gpio < 56)
53                 return &BBU_GCONFb1(gpio / 8);
54         else
55                 /*
56                  * this could be optimised away on
57                  * ns9750 only builds, but it isn't ...
58                  */
59                 return &BBU_GCONFb2((gpio - 56) / 8);
60 }
61
62 static inline volatile u32 *ns9xxx_gpio_get_gctrladdr(unsigned gpio)
63 {
64         if (gpio < 32)
65                 return &BBU_GCTRL1;
66         else if (gpio < 64)
67                 return &BBU_GCTRL2;
68         else
69                 /* this could be optimised away on ns9750 only builds */
70                 return &BBU_GCTRL3;
71 }
72
73 static inline volatile u32 *ns9xxx_gpio_get_gstataddr(unsigned gpio)
74 {
75         if (gpio < 32)
76                 return &BBU_GSTAT1;
77         else if (gpio < 64)
78                 return &BBU_GSTAT2;
79         else
80                 /* this could be optimised away on ns9750 only builds */
81                 return &BBU_GSTAT3;
82 }
83
84 int gpio_request(unsigned gpio, const char *label)
85 {
86         if (likely(ns9xxx_valid_gpio(gpio)))
87                 return test_and_set_bit(gpio, gpiores) ? -EBUSY : 0;
88         else
89                 return -EINVAL;
90 }
91 EXPORT_SYMBOL(gpio_request);
92
93 void gpio_free(unsigned gpio)
94 {
95         clear_bit(gpio, gpiores);
96         return;
97 }
98 EXPORT_SYMBOL(gpio_free);
99
100 /*
101  * each gpio can serve for 4 different purposes [0..3].  These are called
102  * "functions" and passed in the parameter func.  Functions 0-2 are always some
103  * special things, function 3 is GPIO.  If func == 3 dir specifies input or
104  * output, and with inv you can enable an inverter (independent of func).
105  */
106 static int __ns9xxx_gpio_configure(unsigned gpio, int dir, int inv, int func)
107 {
108         volatile u32 *conf = ns9xxx_gpio_get_gconfaddr(gpio);
109         u32 confval;
110         unsigned long flags;
111
112         spin_lock_irqsave(&gpio_lock, flags);
113
114         confval = *conf;
115         REGSETIM_IDX(confval, BBU_GCONFx, DIR, gpio & 7, dir);
116         REGSETIM_IDX(confval, BBU_GCONFx, INV, gpio & 7, inv);
117         REGSETIM_IDX(confval, BBU_GCONFx, FUNC, gpio & 7, func);
118         *conf = confval;
119
120         spin_unlock_irqrestore(&gpio_lock, flags);
121
122         return 0;
123 }
124
125 int ns9xxx_gpio_configure(unsigned gpio, int inv, int func)
126 {
127         if (likely(ns9xxx_valid_gpio(gpio))) {
128                 if (func == 3) {
129                         printk(KERN_WARNING "use gpio_direction_input "
130                                         "or gpio_direction_output\n");
131                         return -EINVAL;
132                 } else
133                         return __ns9xxx_gpio_configure(gpio, 0, inv, func);
134         } else
135                 return -EINVAL;
136 }
137 EXPORT_SYMBOL(ns9xxx_gpio_configure);
138
139 int gpio_direction_input(unsigned gpio)
140 {
141         if (likely(ns9xxx_valid_gpio(gpio))) {
142                 return __ns9xxx_gpio_configure(gpio, 0, 0, 3);
143         } else
144                 return -EINVAL;
145 }
146 EXPORT_SYMBOL(gpio_direction_input);
147
148 int gpio_direction_output(unsigned gpio, int value)
149 {
150         if (likely(ns9xxx_valid_gpio(gpio))) {
151                 gpio_set_value(gpio, value);
152
153                 return __ns9xxx_gpio_configure(gpio, 1, 0, 3);
154         } else
155                 return -EINVAL;
156 }
157 EXPORT_SYMBOL(gpio_direction_output);
158
159 int gpio_get_value(unsigned gpio)
160 {
161         volatile u32 *stat = ns9xxx_gpio_get_gstataddr(gpio);
162         int ret;
163
164         ret = 1 & (*stat >> (gpio & 31));
165
166         return ret;
167 }
168 EXPORT_SYMBOL(gpio_get_value);
169
170 void gpio_set_value(unsigned gpio, int value)
171 {
172         volatile u32 *ctrl = ns9xxx_gpio_get_gctrladdr(gpio);
173         unsigned long flags;
174
175         spin_lock_irqsave(&gpio_lock, flags);
176
177         if (value)
178                 *ctrl |= 1 << (gpio & 31);
179         else
180                 *ctrl &= ~(1 << (gpio & 31));
181
182         spin_unlock_irqrestore(&gpio_lock, flags);
183 }
184 EXPORT_SYMBOL(gpio_set_value);