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