aboutsummaryrefslogtreecommitdiffstats
path: root/arch/cris/arch-v32/mach-fs/pinmux.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/cris/arch-v32/mach-fs/pinmux.c')
-rw-r--r--arch/cris/arch-v32/mach-fs/pinmux.c309
1 files changed, 309 insertions, 0 deletions
diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c
new file mode 100644
index 000000000000..d722ad9ae626
--- /dev/null
+++ b/arch/cris/arch-v32/mach-fs/pinmux.c
@@ -0,0 +1,309 @@
1/*
2 * Allocator for I/O pins. All pins are allocated to GPIO at bootup.
3 * Unassigned pins and GPIO pins can be allocated to a fixed interface
4 * or the I/O processor instead.
5 *
6 * Copyright (c) 2004-2007 Axis Communications AB.
7 */
8
9#include <linux/init.h>
10#include <linux/errno.h>
11#include <linux/kernel.h>
12#include <linux/string.h>
13#include <linux/spinlock.h>
14#include <hwregs/reg_map.h>
15#include <hwregs/reg_rdwr.h>
16#include <pinmux.h>
17#include <hwregs/pinmux_defs.h>
18
19#undef DEBUG
20
21#define PORT_PINS 18
22#define PORTS 4
23
24static char pins[PORTS][PORT_PINS];
25static DEFINE_SPINLOCK(pinmux_lock);
26
27static void crisv32_pinmux_set(int port);
28
29int crisv32_pinmux_init(void)
30{
31 static int initialized;
32
33 if (!initialized) {
34 reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa);
35 initialized = 1;
36 REG_WR_INT(pinmux, regi_pinmux, rw_hwprot, 0);
37 pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 =
38 pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes;
39 REG_WR(pinmux, regi_pinmux, rw_pa, pa);
40 crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio);
41 crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio);
42 crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio);
43 crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio);
44 }
45
46 return 0;
47}
48
49int
50crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode)
51{
52 int i;
53 unsigned long flags;
54
55 crisv32_pinmux_init();
56
57 if (port > PORTS)
58 return -EINVAL;
59
60 spin_lock_irqsave(&pinmux_lock, flags);
61
62 for (i = first_pin; i <= last_pin; i++) {
63 if ((pins[port][i] != pinmux_none)
64 && (pins[port][i] != pinmux_gpio)
65 && (pins[port][i] != mode)) {
66 spin_unlock_irqrestore(&pinmux_lock, flags);
67#ifdef DEBUG
68 panic("Pinmux alloc failed!\n");
69#endif
70 return -EPERM;
71 }
72 }
73
74 for (i = first_pin; i <= last_pin; i++)
75 pins[port][i] = mode;
76
77 crisv32_pinmux_set(port);
78
79 spin_unlock_irqrestore(&pinmux_lock, flags);
80
81 return 0;
82}
83
84int crisv32_pinmux_alloc_fixed(enum fixed_function function)
85{
86 int ret = -EINVAL;
87 char saved[sizeof pins];
88 unsigned long flags;
89
90 spin_lock_irqsave(&pinmux_lock, flags);
91
92 /* Save internal data for recovery */
93 memcpy(saved, pins, sizeof pins);
94
95 crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */
96
97 reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
98
99 switch (function) {
100 case pinmux_ser1:
101 ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed);
102 hwprot.ser1 = regk_pinmux_yes;
103 break;
104 case pinmux_ser2:
105 ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed);
106 hwprot.ser2 = regk_pinmux_yes;
107 break;
108 case pinmux_ser3:
109 ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed);
110 hwprot.ser3 = regk_pinmux_yes;
111 break;
112 case pinmux_sser0:
113 ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed);
114 ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
115 hwprot.sser0 = regk_pinmux_yes;
116 break;
117 case pinmux_sser1:
118 ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
119 hwprot.sser1 = regk_pinmux_yes;
120 break;
121 case pinmux_ata0:
122 ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed);
123 ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed);
124 hwprot.ata0 = regk_pinmux_yes;
125 break;
126 case pinmux_ata1:
127 ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed);
128 ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed);
129 hwprot.ata1 = regk_pinmux_yes;
130 break;
131 case pinmux_ata2:
132 ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed);
133 ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed);
134 hwprot.ata2 = regk_pinmux_yes;
135 break;
136 case pinmux_ata3:
137 ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed);
138 ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed);
139 hwprot.ata2 = regk_pinmux_yes;
140 break;
141 case pinmux_ata:
142 ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed);
143 ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed);
144 hwprot.ata = regk_pinmux_yes;
145 break;
146 case pinmux_eth1:
147 ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed);
148 hwprot.eth1 = regk_pinmux_yes;
149 hwprot.eth1_mgm = regk_pinmux_yes;
150 break;
151 case pinmux_timer:
152 ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed);
153 hwprot.timer = regk_pinmux_yes;
154 spin_unlock_irqrestore(&pinmux_lock, flags);
155 return ret;
156 }
157
158 if (!ret)
159 REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
160 else
161 memcpy(pins, saved, sizeof pins);
162
163 spin_unlock_irqrestore(&pinmux_lock, flags);
164
165 return ret;
166}
167
168void crisv32_pinmux_set(int port)
169{
170 int i;
171 int gpio_val = 0;
172 int iop_val = 0;
173
174 for (i = 0; i < PORT_PINS; i++) {
175 if (pins[port][i] == pinmux_gpio)
176 gpio_val |= (1 << i);
177 else if (pins[port][i] == pinmux_iop)
178 iop_val |= (1 << i);
179 }
180
181 REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8 * port,
182 gpio_val);
183 REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8 * port,
184 iop_val);
185
186#ifdef DEBUG
187 crisv32_pinmux_dump();
188#endif
189}
190
191int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin)
192{
193 int i;
194 unsigned long flags;
195
196 crisv32_pinmux_init();
197
198 if (port > PORTS)
199 return -EINVAL;
200
201 spin_lock_irqsave(&pinmux_lock, flags);
202
203 for (i = first_pin; i <= last_pin; i++)
204 pins[port][i] = pinmux_none;
205
206 crisv32_pinmux_set(port);
207 spin_unlock_irqrestore(&pinmux_lock, flags);
208
209 return 0;
210}
211
212int crisv32_pinmux_dealloc_fixed(enum fixed_function function)
213{
214 int ret = -EINVAL;
215 char saved[sizeof pins];
216 unsigned long flags;
217
218 spin_lock_irqsave(&pinmux_lock, flags);
219
220 /* Save internal data for recovery */
221 memcpy(saved, pins, sizeof pins);
222
223 crisv32_pinmux_init(); /* Must be done before we read rw_hwprot */
224
225 reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot);
226
227 switch (function) {
228 case pinmux_ser1:
229 ret = crisv32_pinmux_dealloc(PORT_C, 4, 7);
230 hwprot.ser1 = regk_pinmux_no;
231 break;
232 case pinmux_ser2:
233 ret = crisv32_pinmux_dealloc(PORT_C, 8, 11);
234 hwprot.ser2 = regk_pinmux_no;
235 break;
236 case pinmux_ser3:
237 ret = crisv32_pinmux_dealloc(PORT_C, 12, 15);
238 hwprot.ser3 = regk_pinmux_no;
239 break;
240 case pinmux_sser0:
241 ret = crisv32_pinmux_dealloc(PORT_C, 0, 3);
242 ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16);
243 hwprot.sser0 = regk_pinmux_no;
244 break;
245 case pinmux_sser1:
246 ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);
247 hwprot.sser1 = regk_pinmux_no;
248 break;
249 case pinmux_ata0:
250 ret = crisv32_pinmux_dealloc(PORT_D, 5, 7);
251 ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17);
252 hwprot.ata0 = regk_pinmux_no;
253 break;
254 case pinmux_ata1:
255 ret = crisv32_pinmux_dealloc(PORT_D, 0, 4);
256 ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17);
257 hwprot.ata1 = regk_pinmux_no;
258 break;
259 case pinmux_ata2:
260 ret = crisv32_pinmux_dealloc(PORT_C, 11, 15);
261 ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3);
262 hwprot.ata2 = regk_pinmux_no;
263 break;
264 case pinmux_ata3:
265 ret = crisv32_pinmux_dealloc(PORT_C, 8, 10);
266 ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2);
267 hwprot.ata2 = regk_pinmux_no;
268 break;
269 case pinmux_ata:
270 ret = crisv32_pinmux_dealloc(PORT_B, 0, 15);
271 ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15);
272 hwprot.ata = regk_pinmux_no;
273 break;
274 case pinmux_eth1:
275 ret = crisv32_pinmux_dealloc(PORT_E, 0, 17);
276 hwprot.eth1 = regk_pinmux_no;
277 hwprot.eth1_mgm = regk_pinmux_no;
278 break;
279 case pinmux_timer:
280 ret = crisv32_pinmux_dealloc(PORT_C, 16, 16);
281 hwprot.timer = regk_pinmux_no;
282 spin_unlock_irqrestore(&pinmux_lock, flags);
283 return ret;
284 }
285
286 if (!ret)
287 REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot);
288 else
289 memcpy(pins, saved, sizeof pins);
290
291 spin_unlock_irqrestore(&pinmux_lock, flags);
292
293 return ret;
294}
295
296void crisv32_pinmux_dump(void)
297{
298 int i, j;
299
300 crisv32_pinmux_init();
301
302 for (i = 0; i < PORTS; i++) {
303 printk(KERN_DEBUG "Port %c\n", 'B' + i);
304 for (j = 0; j < PORT_PINS; j++)
305 printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]);
306 }
307}
308
309__initcall(crisv32_pinmux_init);