]>
Commit | Line | Data |
---|---|---|
ea8fbba7 JS |
1 | /* |
2 | * Memory Setup stuff - taken from blob memsetup.S | |
3 | * | |
4 | * Copyright (C) 2009 Jens Scharsig (js_at_ng@scharsoft.de) | |
5 | * | |
6 | * Copyright (C) 2005 HP Labs | |
7 | * | |
1a459660 | 8 | * SPDX-License-Identifier: GPL-2.0+ |
ea8fbba7 JS |
9 | */ |
10 | ||
372f2783 RM |
11 | /* |
12 | * WARNING: | |
13 | * | |
14 | * As the code is right now, it expects all PIO ports A,B,C,... | |
15 | * to be evenly spaced in the memory map: | |
16 | * ATMEL_BASE_PIOA + port * sizeof at91pio_t | |
17 | * This might not necessaryly be true in future Atmel SoCs. | |
18 | * This code should be fixed to use a pointer array to the ports. | |
19 | */ | |
20 | ||
ea8fbba7 JS |
21 | #include <config.h> |
22 | #include <common.h> | |
86592f60 | 23 | #include <asm/io.h> |
ea8fbba7 JS |
24 | #include <asm/sizes.h> |
25 | #include <asm/arch/hardware.h> | |
ea8fbba7 JS |
26 | #include <asm/arch/at91_pio.h> |
27 | ||
28 | int at91_set_pio_pullup(unsigned port, unsigned pin, int use_pullup) | |
29 | { | |
372f2783 | 30 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
31 | u32 mask; |
32 | ||
372f2783 | 33 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
34 | mask = 1 << pin; |
35 | if (use_pullup) | |
36 | writel(1 << pin, &pio->port[port].puer); | |
37 | else | |
38 | writel(1 << pin, &pio->port[port].pudr); | |
39 | writel(mask, &pio->port[port].per); | |
40 | } | |
41 | return 0; | |
42 | } | |
43 | ||
44 | /* | |
45 | * mux the pin to the "GPIO" peripheral role. | |
46 | */ | |
47 | int at91_set_pio_periph(unsigned port, unsigned pin, int use_pullup) | |
48 | { | |
372f2783 | 49 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
50 | u32 mask; |
51 | ||
372f2783 | 52 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
53 | mask = 1 << pin; |
54 | writel(mask, &pio->port[port].idr); | |
55 | at91_set_pio_pullup(port, pin, use_pullup); | |
56 | writel(mask, &pio->port[port].per); | |
57 | } | |
58 | return 0; | |
59 | } | |
60 | ||
61 | /* | |
62 | * mux the pin to the "A" internal peripheral role. | |
63 | */ | |
64 | int at91_set_a_periph(unsigned port, unsigned pin, int use_pullup) | |
65 | { | |
372f2783 | 66 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
67 | u32 mask; |
68 | ||
372f2783 | 69 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
70 | mask = 1 << pin; |
71 | writel(mask, &pio->port[port].idr); | |
72 | at91_set_pio_pullup(port, pin, use_pullup); | |
2b3b1c66 BS |
73 | #if defined(CPU_HAS_PIO3) |
74 | writel(readl(&pio->port[port].abcdsr1) & ~mask, | |
75 | &pio->port[port].abcdsr1); | |
76 | writel(readl(&pio->port[port].abcdsr2) & ~mask, | |
77 | &pio->port[port].abcdsr2); | |
78 | #else | |
ea8fbba7 | 79 | writel(mask, &pio->port[port].asr); |
2b3b1c66 | 80 | #endif |
ea8fbba7 JS |
81 | writel(mask, &pio->port[port].pdr); |
82 | } | |
83 | return 0; | |
84 | } | |
85 | ||
86 | /* | |
87 | * mux the pin to the "B" internal peripheral role. | |
88 | */ | |
89 | int at91_set_b_periph(unsigned port, unsigned pin, int use_pullup) | |
90 | { | |
372f2783 | 91 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
92 | u32 mask; |
93 | ||
372f2783 | 94 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
95 | mask = 1 << pin; |
96 | writel(mask, &pio->port[port].idr); | |
97 | at91_set_pio_pullup(port, pin, use_pullup); | |
2b3b1c66 BS |
98 | #if defined(CPU_HAS_PIO3) |
99 | writel(readl(&pio->port[port].abcdsr1) | mask, | |
100 | &pio->port[port].abcdsr1); | |
101 | writel(readl(&pio->port[port].abcdsr2) & ~mask, | |
102 | &pio->port[port].abcdsr2); | |
103 | #else | |
ea8fbba7 | 104 | writel(mask, &pio->port[port].bsr); |
2b3b1c66 | 105 | #endif |
ea8fbba7 JS |
106 | writel(mask, &pio->port[port].pdr); |
107 | } | |
108 | return 0; | |
109 | } | |
110 | ||
2b3b1c66 BS |
111 | #if defined(CPU_HAS_PIO3) |
112 | /* | |
113 | * mux the pin to the "C" internal peripheral role. | |
114 | */ | |
115 | int at91_set_c_periph(unsigned port, unsigned pin, int use_pullup) | |
116 | { | |
117 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; | |
118 | u32 mask; | |
119 | ||
120 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { | |
121 | mask = 1 << pin; | |
122 | writel(mask, &pio->port[port].idr); | |
123 | at91_set_pio_pullup(port, pin, use_pullup); | |
124 | writel(readl(&pio->port[port].abcdsr1) & ~mask, | |
125 | &pio->port[port].abcdsr1); | |
126 | writel(readl(&pio->port[port].abcdsr2) | mask, | |
127 | &pio->port[port].abcdsr2); | |
128 | writel(mask, &pio->port[port].pdr); | |
129 | } | |
130 | return 0; | |
131 | } | |
132 | ||
133 | /* | |
134 | * mux the pin to the "D" internal peripheral role. | |
135 | */ | |
136 | int at91_set_d_periph(unsigned port, unsigned pin, int use_pullup) | |
137 | { | |
138 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; | |
139 | u32 mask; | |
140 | ||
141 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { | |
142 | mask = 1 << pin; | |
143 | writel(mask, &pio->port[port].idr); | |
144 | at91_set_pio_pullup(port, pin, use_pullup); | |
145 | writel(readl(&pio->port[port].abcdsr1) | mask, | |
146 | &pio->port[port].abcdsr1); | |
147 | writel(readl(&pio->port[port].abcdsr2) | mask, | |
148 | &pio->port[port].abcdsr2); | |
149 | writel(mask, &pio->port[port].pdr); | |
150 | } | |
151 | return 0; | |
152 | } | |
153 | #endif | |
154 | ||
ea8fbba7 JS |
155 | /* |
156 | * mux the pin to the gpio controller (instead of "A" or "B" peripheral), and | |
157 | * configure it for an input. | |
158 | */ | |
159 | int at91_set_pio_input(unsigned port, u32 pin, int use_pullup) | |
160 | { | |
372f2783 | 161 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
162 | u32 mask; |
163 | ||
372f2783 | 164 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
165 | mask = 1 << pin; |
166 | writel(mask, &pio->port[port].idr); | |
167 | at91_set_pio_pullup(port, pin, use_pullup); | |
168 | writel(mask, &pio->port[port].odr); | |
169 | writel(mask, &pio->port[port].per); | |
170 | } | |
171 | return 0; | |
172 | } | |
173 | ||
174 | /* | |
175 | * mux the pin to the gpio controller (instead of "A" or "B" peripheral), | |
176 | * and configure it for an output. | |
177 | */ | |
178 | int at91_set_pio_output(unsigned port, u32 pin, int value) | |
179 | { | |
372f2783 | 180 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
181 | u32 mask; |
182 | ||
372f2783 | 183 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
184 | mask = 1 << pin; |
185 | writel(mask, &pio->port[port].idr); | |
186 | writel(mask, &pio->port[port].pudr); | |
187 | if (value) | |
188 | writel(mask, &pio->port[port].sodr); | |
189 | else | |
190 | writel(mask, &pio->port[port].codr); | |
191 | writel(mask, &pio->port[port].oer); | |
192 | writel(mask, &pio->port[port].per); | |
193 | } | |
194 | return 0; | |
195 | } | |
196 | ||
197 | /* | |
198 | * enable/disable the glitch filter. mostly used with IRQ handling. | |
199 | */ | |
200 | int at91_set_pio_deglitch(unsigned port, unsigned pin, int is_on) | |
201 | { | |
372f2783 | 202 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
203 | u32 mask; |
204 | ||
372f2783 | 205 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 | 206 | mask = 1 << pin; |
2b3b1c66 BS |
207 | if (is_on) { |
208 | #if defined(CPU_HAS_PIO3) | |
209 | writel(mask, &pio->port[port].ifscdr); | |
210 | #endif | |
ea8fbba7 | 211 | writel(mask, &pio->port[port].ifer); |
2b3b1c66 | 212 | } else { |
ea8fbba7 | 213 | writel(mask, &pio->port[port].ifdr); |
2b3b1c66 BS |
214 | } |
215 | } | |
216 | return 0; | |
217 | } | |
218 | ||
219 | #if defined(CPU_HAS_PIO3) | |
220 | /* | |
221 | * enable/disable the debounce filter. | |
222 | */ | |
223 | int at91_set_pio_debounce(unsigned port, unsigned pin, int is_on, int div) | |
224 | { | |
225 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; | |
226 | u32 mask; | |
227 | ||
228 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { | |
229 | mask = 1 << pin; | |
230 | if (is_on) { | |
231 | writel(mask, &pio->port[port].ifscer); | |
232 | writel(div & PIO_SCDR_DIV, &pio->port[port].scdr); | |
233 | writel(mask, &pio->port[port].ifer); | |
234 | } else { | |
235 | writel(mask, &pio->port[port].ifdr); | |
236 | } | |
237 | } | |
238 | return 0; | |
239 | } | |
240 | ||
241 | /* | |
242 | * enable/disable the pull-down. | |
243 | * If pull-up already enabled while calling the function, we disable it. | |
244 | */ | |
245 | int at91_set_pio_pulldown(unsigned port, unsigned pin, int is_on) | |
246 | { | |
247 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; | |
248 | u32 mask; | |
249 | ||
250 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { | |
251 | mask = 1 << pin; | |
252 | writel(mask, &pio->port[port].pudr); | |
253 | if (is_on) | |
254 | writel(mask, &pio->port[port].ppder); | |
255 | else | |
256 | writel(mask, &pio->port[port].ppddr); | |
257 | } | |
258 | return 0; | |
259 | } | |
260 | ||
261 | /* | |
262 | * disable Schmitt trigger | |
263 | */ | |
264 | int at91_set_pio_disable_schmitt_trig(unsigned port, unsigned pin) | |
265 | { | |
266 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; | |
267 | u32 mask; | |
268 | ||
269 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { | |
270 | mask = 1 << pin; | |
271 | writel(readl(&pio->port[port].schmitt) | mask, | |
272 | &pio->port[port].schmitt); | |
ea8fbba7 JS |
273 | } |
274 | return 0; | |
275 | } | |
2b3b1c66 | 276 | #endif |
ea8fbba7 JS |
277 | |
278 | /* | |
279 | * enable/disable the multi-driver. This is only valid for output and | |
280 | * allows the output pin to run as an open collector output. | |
281 | */ | |
282 | int at91_set_pio_multi_drive(unsigned port, unsigned pin, int is_on) | |
283 | { | |
372f2783 | 284 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
285 | u32 mask; |
286 | ||
372f2783 | 287 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
288 | mask = 1 << pin; |
289 | if (is_on) | |
290 | writel(mask, &pio->port[port].mder); | |
291 | else | |
292 | writel(mask, &pio->port[port].mddr); | |
293 | } | |
294 | return 0; | |
295 | } | |
296 | ||
297 | /* | |
298 | * assuming the pin is muxed as a gpio output, set its value. | |
299 | */ | |
300 | int at91_set_pio_value(unsigned port, unsigned pin, int value) | |
301 | { | |
372f2783 | 302 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; |
ea8fbba7 JS |
303 | u32 mask; |
304 | ||
372f2783 | 305 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
306 | mask = 1 << pin; |
307 | if (value) | |
308 | writel(mask, &pio->port[port].sodr); | |
309 | else | |
310 | writel(mask, &pio->port[port].codr); | |
311 | } | |
312 | return 0; | |
313 | } | |
314 | ||
315 | /* | |
316 | * read the pin's value (works even if it's not muxed as a gpio). | |
317 | */ | |
318 | int at91_get_pio_value(unsigned port, unsigned pin) | |
319 | { | |
372f2783 RM |
320 | u32 pdsr = 0; |
321 | at91_pio_t *pio = (at91_pio_t *) ATMEL_BASE_PIOA; | |
ea8fbba7 JS |
322 | u32 mask; |
323 | ||
372f2783 | 324 | if ((port < ATMEL_PIO_PORTS) && (pin < 32)) { |
ea8fbba7 JS |
325 | mask = 1 << pin; |
326 | pdsr = readl(&pio->port[port].pdsr) & mask; | |
327 | } | |
328 | return pdsr != 0; | |
329 | } |