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