]>
Commit | Line | Data |
---|---|---|
51533b61 MS |
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 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> | |
556dcee7 JN |
14 | #include <arch/hwregs/reg_map.h> |
15 | #include <arch/hwregs/reg_rdwr.h> | |
16 | #include <arch/pinmux.h> | |
17 | #include <arch/hwregs/pinmux_defs.h> | |
51533b61 MS |
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 | ||
29 | int | |
30 | crisv32_pinmux_init(void) | |
31 | { | |
32 | static int initialized = 0; | |
33 | ||
34 | if (!initialized) { | |
35 | reg_pinmux_rw_pa pa = REG_RD(pinmux, regi_pinmux, rw_pa); | |
36 | initialized = 1; | |
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 | ||
49 | int | |
50 | crisv32_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 | ||
f25234f1 | 57 | if (port > PORTS || port < 0) |
51533b61 MS |
58 | return -EINVAL; |
59 | ||
60 | spin_lock_irqsave(&pinmux_lock, flags); | |
61 | ||
62 | for (i = first_pin; i <= last_pin; i++) | |
63 | { | |
64 | if ((pins[port][i] != pinmux_none) && (pins[port][i] != pinmux_gpio) && | |
65 | (pins[port][i] != mode)) | |
66 | { | |
67 | spin_unlock_irqrestore(&pinmux_lock, flags); | |
68 | #ifdef DEBUG | |
69 | panic("Pinmux alloc failed!\n"); | |
70 | #endif | |
71 | return -EPERM; | |
72 | } | |
73 | } | |
74 | ||
75 | for (i = first_pin; i <= last_pin; i++) | |
76 | pins[port][i] = mode; | |
77 | ||
78 | crisv32_pinmux_set(port); | |
79 | ||
80 | spin_unlock_irqrestore(&pinmux_lock, flags); | |
81 | ||
82 | return 0; | |
83 | } | |
84 | ||
85 | int | |
86 | crisv32_pinmux_alloc_fixed(enum fixed_function function) | |
87 | { | |
88 | int ret = -EINVAL; | |
89 | char saved[sizeof pins]; | |
90 | unsigned long flags; | |
91 | ||
92 | spin_lock_irqsave(&pinmux_lock, flags); | |
93 | ||
94 | /* Save internal data for recovery */ | |
95 | memcpy(saved, pins, sizeof pins); | |
96 | ||
97 | reg_pinmux_rw_hwprot hwprot = REG_RD(pinmux, regi_pinmux, rw_hwprot); | |
98 | ||
99 | switch(function) | |
100 | { | |
101 | case pinmux_ser1: | |
102 | ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed); | |
103 | hwprot.ser1 = regk_pinmux_yes; | |
104 | break; | |
105 | case pinmux_ser2: | |
106 | ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed); | |
107 | hwprot.ser2 = regk_pinmux_yes; | |
108 | break; | |
109 | case pinmux_ser3: | |
110 | ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed); | |
111 | hwprot.ser3 = regk_pinmux_yes; | |
112 | break; | |
113 | case pinmux_sser0: | |
114 | ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed); | |
115 | ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); | |
116 | hwprot.sser0 = regk_pinmux_yes; | |
117 | break; | |
118 | case pinmux_sser1: | |
119 | ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); | |
120 | hwprot.sser1 = regk_pinmux_yes; | |
121 | break; | |
122 | case pinmux_ata0: | |
123 | ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed); | |
124 | ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed); | |
125 | hwprot.ata0 = regk_pinmux_yes; | |
126 | break; | |
127 | case pinmux_ata1: | |
128 | ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); | |
129 | ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed); | |
130 | hwprot.ata1 = regk_pinmux_yes; | |
131 | break; | |
132 | case pinmux_ata2: | |
133 | ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed); | |
134 | ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed); | |
135 | hwprot.ata2 = regk_pinmux_yes; | |
136 | break; | |
137 | case pinmux_ata3: | |
138 | ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed); | |
139 | ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed); | |
140 | hwprot.ata2 = regk_pinmux_yes; | |
141 | break; | |
142 | case pinmux_ata: | |
143 | ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed); | |
144 | ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed); | |
145 | hwprot.ata = regk_pinmux_yes; | |
146 | break; | |
147 | case pinmux_eth1: | |
148 | ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed); | |
149 | hwprot.eth1 = regk_pinmux_yes; | |
150 | hwprot.eth1_mgm = regk_pinmux_yes; | |
151 | break; | |
152 | case pinmux_timer: | |
153 | ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); | |
154 | hwprot.timer = regk_pinmux_yes; | |
155 | spin_unlock_irqrestore(&pinmux_lock, flags); | |
156 | return ret; | |
157 | } | |
158 | ||
159 | if (!ret) | |
160 | REG_WR(pinmux, regi_pinmux, rw_hwprot, hwprot); | |
161 | else | |
162 | memcpy(pins, saved, sizeof pins); | |
163 | ||
164 | spin_unlock_irqrestore(&pinmux_lock, flags); | |
165 | ||
166 | return ret; | |
167 | } | |
168 | ||
169 | void | |
170 | crisv32_pinmux_set(int port) | |
171 | { | |
172 | int i; | |
173 | int gpio_val = 0; | |
174 | int iop_val = 0; | |
175 | ||
176 | for (i = 0; i < PORT_PINS; i++) | |
177 | { | |
178 | if (pins[port][i] == pinmux_gpio) | |
179 | gpio_val |= (1 << i); | |
180 | else if (pins[port][i] == pinmux_iop) | |
181 | iop_val |= (1 << i); | |
182 | } | |
183 | ||
184 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_gio + 8*port, gpio_val); | |
185 | REG_WRITE(int, regi_pinmux + REG_RD_ADDR_pinmux_rw_pb_iop + 8*port, iop_val); | |
186 | ||
187 | #ifdef DEBUG | |
188 | crisv32_pinmux_dump(); | |
189 | #endif | |
190 | } | |
191 | ||
192 | int | |
193 | crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) | |
194 | { | |
195 | int i; | |
196 | unsigned long flags; | |
197 | ||
198 | crisv32_pinmux_init(); | |
199 | ||
f25234f1 | 200 | if (port > PORTS || port < 0) |
51533b61 MS |
201 | return -EINVAL; |
202 | ||
203 | spin_lock_irqsave(&pinmux_lock, flags); | |
204 | ||
205 | for (i = first_pin; i <= last_pin; i++) | |
206 | pins[port][i] = pinmux_none; | |
207 | ||
208 | crisv32_pinmux_set(port); | |
209 | spin_unlock_irqrestore(&pinmux_lock, flags); | |
210 | ||
211 | return 0; | |
212 | } | |
213 | ||
214 | void | |
215 | crisv32_pinmux_dump(void) | |
216 | { | |
217 | int i, j; | |
218 | ||
219 | crisv32_pinmux_init(); | |
220 | ||
221 | for (i = 0; i < PORTS; i++) | |
222 | { | |
223 | printk("Port %c\n", 'B'+i); | |
224 | for (j = 0; j < PORT_PINS; j++) | |
225 | printk(" Pin %d = %d\n", j, pins[i][j]); | |
226 | } | |
227 | } | |
228 | ||
229 | __initcall(crisv32_pinmux_init); |