aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-orion/gpio.c
diff options
context:
space:
mode:
authorLennert Buytenhek <buytenh@wantstofly.org>2008-10-19 19:51:03 -0400
committerNicolas Pitre <nico@cam.org>2008-12-20 12:21:02 -0500
commit9569dae75f6f6987e79fa26cf6da3fc24006c996 (patch)
treeb5982f41aea6ccee37af54fc8f7750aaff7e0bff /arch/arm/plat-orion/gpio.c
parent6fd7c7fe72a46dfd227fe8db0c7b6863af90a982 (diff)
[ARM] Orion: share GPIO handling code
Split off Orion GPIO handling code into plat-orion/, and add support for multiple sets of (32) GPIO pins. Signed-off-by: Lennert Buytenhek <buytenh@marvell.com> Signed-off-by: Nicolas Pitre <nico@marvell.com>
Diffstat (limited to 'arch/arm/plat-orion/gpio.c')
-rw-r--r--arch/arm/plat-orion/gpio.c239
1 files changed, 239 insertions, 0 deletions
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
new file mode 100644
index 000000000000..d86fc085e489
--- /dev/null
+++ b/arch/arm/plat-orion/gpio.c
@@ -0,0 +1,239 @@
1/*
2 * arch/arm/plat-orion/gpio.c
3 *
4 * Marvell Orion SoC GPIO handling.
5 *
6 * This file is licensed under the terms of the GNU General Public
7 * License version 2. This program is licensed "as is" without any
8 * warranty of any kind, whether express or implied.
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/spinlock.h>
15#include <linux/bitops.h>
16#include <linux/io.h>
17#include <asm/gpio.h>
18
19static DEFINE_SPINLOCK(gpio_lock);
20static const char *gpio_label[GPIO_MAX]; /* non null for allocated GPIOs */
21static unsigned long gpio_valid[BITS_TO_LONGS(GPIO_MAX)];
22
23static inline void __set_direction(unsigned pin, int input)
24{
25 u32 u;
26
27 u = readl(GPIO_IO_CONF(pin));
28 if (input)
29 u |= 1 << (pin & 31);
30 else
31 u &= ~(1 << (pin & 31));
32 writel(u, GPIO_IO_CONF(pin));
33}
34
35static void __set_level(unsigned pin, int high)
36{
37 u32 u;
38
39 u = readl(GPIO_OUT(pin));
40 if (high)
41 u |= 1 << (pin & 31);
42 else
43 u &= ~(1 << (pin & 31));
44 writel(u, GPIO_OUT(pin));
45}
46
47
48/*
49 * GENERIC_GPIO primitives.
50 */
51int gpio_direction_input(unsigned pin)
52{
53 unsigned long flags;
54
55 if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
56 pr_debug("%s: invalid GPIO %d\n", __func__, pin);
57 return -EINVAL;
58 }
59
60 spin_lock_irqsave(&gpio_lock, flags);
61
62 /*
63 * Some callers might not have used gpio_request(),
64 * so flag this pin as requested now.
65 */
66 if (gpio_label[pin] == NULL)
67 gpio_label[pin] = "?";
68
69 /*
70 * Configure GPIO direction.
71 */
72 __set_direction(pin, 1);
73
74 spin_unlock_irqrestore(&gpio_lock, flags);
75
76 return 0;
77}
78EXPORT_SYMBOL(gpio_direction_input);
79
80int gpio_direction_output(unsigned pin, int value)
81{
82 unsigned long flags;
83 u32 u;
84
85 if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
86 pr_debug("%s: invalid GPIO %d\n", __func__, pin);
87 return -EINVAL;
88 }
89
90 spin_lock_irqsave(&gpio_lock, flags);
91
92 /*
93 * Some callers might not have used gpio_request(),
94 * so flag this pin as requested now.
95 */
96 if (gpio_label[pin] == NULL)
97 gpio_label[pin] = "?";
98
99 /*
100 * Disable blinking.
101 */
102 u = readl(GPIO_BLINK_EN(pin));
103 u &= ~(1 << (pin & 31));
104 writel(u, GPIO_BLINK_EN(pin));
105
106 /*
107 * Configure GPIO output value.
108 */
109 __set_level(pin, value);
110
111 /*
112 * Configure GPIO direction.
113 */
114 __set_direction(pin, 0);
115
116 spin_unlock_irqrestore(&gpio_lock, flags);
117
118 return 0;
119}
120EXPORT_SYMBOL(gpio_direction_output);
121
122int gpio_get_value(unsigned pin)
123{
124 int val;
125
126 if (readl(GPIO_IO_CONF(pin)) & (1 << (pin & 31)))
127 val = readl(GPIO_DATA_IN(pin)) ^ readl(GPIO_IN_POL(pin));
128 else
129 val = readl(GPIO_OUT(pin));
130
131 return (val >> (pin & 31)) & 1;
132}
133EXPORT_SYMBOL(gpio_get_value);
134
135void gpio_set_value(unsigned pin, int value)
136{
137 unsigned long flags;
138 u32 u;
139
140 spin_lock_irqsave(&gpio_lock, flags);
141
142 /*
143 * Disable blinking.
144 */
145 u = readl(GPIO_BLINK_EN(pin));
146 u &= ~(1 << (pin & 31));
147 writel(u, GPIO_BLINK_EN(pin));
148
149 /*
150 * Configure GPIO output value.
151 */
152 __set_level(pin, value);
153
154 spin_unlock_irqrestore(&gpio_lock, flags);
155}
156EXPORT_SYMBOL(gpio_set_value);
157
158int gpio_request(unsigned pin, const char *label)
159{
160 unsigned long flags;
161 int ret;
162
163 if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
164 pr_debug("%s: invalid GPIO %d\n", __func__, pin);
165 return -EINVAL;
166 }
167
168 spin_lock_irqsave(&gpio_lock, flags);
169 if (gpio_label[pin] == NULL) {
170 gpio_label[pin] = label ? label : "?";
171 ret = 0;
172 } else {
173 pr_debug("%s: GPIO %d already used as %s\n",
174 __func__, pin, gpio_label[pin]);
175 ret = -EBUSY;
176 }
177 spin_unlock_irqrestore(&gpio_lock, flags);
178
179 return ret;
180}
181EXPORT_SYMBOL(gpio_request);
182
183void gpio_free(unsigned pin)
184{
185 if (pin >= GPIO_MAX || !test_bit(pin, gpio_valid)) {
186 pr_debug("%s: invalid GPIO %d\n", __func__, pin);
187 return;
188 }
189
190 if (gpio_label[pin] == NULL)
191 pr_warning("%s: GPIO %d already freed\n", __func__, pin);
192 else
193 gpio_label[pin] = NULL;
194}
195EXPORT_SYMBOL(gpio_free);
196
197
198/*
199 * Orion-specific GPIO API extensions.
200 */
201void __init orion_gpio_set_unused(unsigned pin)
202{
203 /*
204 * Configure as output, drive low.
205 */
206 __set_level(pin, 0);
207 __set_direction(pin, 0);
208}
209
210void __init orion_gpio_set_valid(unsigned pin, int valid)
211{
212 if (valid)
213 __set_bit(pin, gpio_valid);
214 else
215 __clear_bit(pin, gpio_valid);
216}
217
218void orion_gpio_set_blink(unsigned pin, int blink)
219{
220 unsigned long flags;
221 u32 u;
222
223 spin_lock_irqsave(&gpio_lock, flags);
224
225 /*
226 * Set output value to zero.
227 */
228 __set_level(pin, 0);
229
230 u = readl(GPIO_BLINK_EN(pin));
231 if (blink)
232 u |= 1 << (pin & 31);
233 else
234 u &= ~(1 << (pin & 31));
235 writel(u, GPIO_BLINK_EN(pin));
236
237 spin_unlock_irqrestore(&gpio_lock, flags);
238}
239EXPORT_SYMBOL(orion_gpio_set_blink);