diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/at32ap7000.c')
-rw-r--r-- | arch/avr32/mach-at32ap/at32ap7000.c | 876 |
1 files changed, 876 insertions, 0 deletions
diff --git a/arch/avr32/mach-at32ap/at32ap7000.c b/arch/avr32/mach-at32ap/at32ap7000.c new file mode 100644 index 000000000000..37982b60398e --- /dev/null +++ b/arch/avr32/mach-at32ap/at32ap7000.c | |||
@@ -0,0 +1,876 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2005-2006 Atmel Corporation | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | #include <linux/clk.h> | ||
9 | #include <linux/init.h> | ||
10 | #include <linux/platform_device.h> | ||
11 | |||
12 | #include <asm/io.h> | ||
13 | |||
14 | #include <asm/arch/board.h> | ||
15 | #include <asm/arch/portmux.h> | ||
16 | #include <asm/arch/sm.h> | ||
17 | |||
18 | #include "clock.h" | ||
19 | #include "pio.h" | ||
20 | #include "sm.h" | ||
21 | |||
22 | #define PBMEM(base) \ | ||
23 | { \ | ||
24 | .start = base, \ | ||
25 | .end = base + 0x3ff, \ | ||
26 | .flags = IORESOURCE_MEM, \ | ||
27 | } | ||
28 | #define IRQ(num) \ | ||
29 | { \ | ||
30 | .start = num, \ | ||
31 | .end = num, \ | ||
32 | .flags = IORESOURCE_IRQ, \ | ||
33 | } | ||
34 | #define NAMED_IRQ(num, _name) \ | ||
35 | { \ | ||
36 | .start = num, \ | ||
37 | .end = num, \ | ||
38 | .name = _name, \ | ||
39 | .flags = IORESOURCE_IRQ, \ | ||
40 | } | ||
41 | |||
42 | #define DEFINE_DEV(_name, _id) \ | ||
43 | static struct platform_device _name##_id##_device = { \ | ||
44 | .name = #_name, \ | ||
45 | .id = _id, \ | ||
46 | .resource = _name##_id##_resource, \ | ||
47 | .num_resources = ARRAY_SIZE(_name##_id##_resource), \ | ||
48 | } | ||
49 | #define DEFINE_DEV_DATA(_name, _id) \ | ||
50 | static struct platform_device _name##_id##_device = { \ | ||
51 | .name = #_name, \ | ||
52 | .id = _id, \ | ||
53 | .dev = { \ | ||
54 | .platform_data = &_name##_id##_data, \ | ||
55 | }, \ | ||
56 | .resource = _name##_id##_resource, \ | ||
57 | .num_resources = ARRAY_SIZE(_name##_id##_resource), \ | ||
58 | } | ||
59 | |||
60 | #define DEV_CLK(_name, devname, bus, _index) \ | ||
61 | static struct clk devname##_##_name = { \ | ||
62 | .name = #_name, \ | ||
63 | .dev = &devname##_device.dev, \ | ||
64 | .parent = &bus##_clk, \ | ||
65 | .mode = bus##_clk_mode, \ | ||
66 | .get_rate = bus##_clk_get_rate, \ | ||
67 | .index = _index, \ | ||
68 | } | ||
69 | |||
70 | enum { | ||
71 | PIOA, | ||
72 | PIOB, | ||
73 | PIOC, | ||
74 | PIOD, | ||
75 | }; | ||
76 | |||
77 | enum { | ||
78 | FUNC_A, | ||
79 | FUNC_B, | ||
80 | }; | ||
81 | |||
82 | unsigned long at32ap7000_osc_rates[3] = { | ||
83 | [0] = 32768, | ||
84 | /* FIXME: these are ATSTK1002-specific */ | ||
85 | [1] = 20000000, | ||
86 | [2] = 12000000, | ||
87 | }; | ||
88 | |||
89 | static unsigned long osc_get_rate(struct clk *clk) | ||
90 | { | ||
91 | return at32ap7000_osc_rates[clk->index]; | ||
92 | } | ||
93 | |||
94 | static unsigned long pll_get_rate(struct clk *clk, unsigned long control) | ||
95 | { | ||
96 | unsigned long div, mul, rate; | ||
97 | |||
98 | if (!(control & SM_BIT(PLLEN))) | ||
99 | return 0; | ||
100 | |||
101 | div = SM_BFEXT(PLLDIV, control) + 1; | ||
102 | mul = SM_BFEXT(PLLMUL, control) + 1; | ||
103 | |||
104 | rate = clk->parent->get_rate(clk->parent); | ||
105 | rate = (rate + div / 2) / div; | ||
106 | rate *= mul; | ||
107 | |||
108 | return rate; | ||
109 | } | ||
110 | |||
111 | static unsigned long pll0_get_rate(struct clk *clk) | ||
112 | { | ||
113 | u32 control; | ||
114 | |||
115 | control = sm_readl(&system_manager, PM_PLL0); | ||
116 | |||
117 | return pll_get_rate(clk, control); | ||
118 | } | ||
119 | |||
120 | static unsigned long pll1_get_rate(struct clk *clk) | ||
121 | { | ||
122 | u32 control; | ||
123 | |||
124 | control = sm_readl(&system_manager, PM_PLL1); | ||
125 | |||
126 | return pll_get_rate(clk, control); | ||
127 | } | ||
128 | |||
129 | /* | ||
130 | * The AT32AP7000 has five primary clock sources: One 32kHz | ||
131 | * oscillator, two crystal oscillators and two PLLs. | ||
132 | */ | ||
133 | static struct clk osc32k = { | ||
134 | .name = "osc32k", | ||
135 | .get_rate = osc_get_rate, | ||
136 | .users = 1, | ||
137 | .index = 0, | ||
138 | }; | ||
139 | static struct clk osc0 = { | ||
140 | .name = "osc0", | ||
141 | .get_rate = osc_get_rate, | ||
142 | .users = 1, | ||
143 | .index = 1, | ||
144 | }; | ||
145 | static struct clk osc1 = { | ||
146 | .name = "osc1", | ||
147 | .get_rate = osc_get_rate, | ||
148 | .index = 2, | ||
149 | }; | ||
150 | static struct clk pll0 = { | ||
151 | .name = "pll0", | ||
152 | .get_rate = pll0_get_rate, | ||
153 | .parent = &osc0, | ||
154 | }; | ||
155 | static struct clk pll1 = { | ||
156 | .name = "pll1", | ||
157 | .get_rate = pll1_get_rate, | ||
158 | .parent = &osc0, | ||
159 | }; | ||
160 | |||
161 | /* | ||
162 | * The main clock can be either osc0 or pll0. The boot loader may | ||
163 | * have chosen one for us, so we don't really know which one until we | ||
164 | * have a look at the SM. | ||
165 | */ | ||
166 | static struct clk *main_clock; | ||
167 | |||
168 | /* | ||
169 | * Synchronous clocks are generated from the main clock. The clocks | ||
170 | * must satisfy the constraint | ||
171 | * fCPU >= fHSB >= fPB | ||
172 | * i.e. each clock must not be faster than its parent. | ||
173 | */ | ||
174 | static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift) | ||
175 | { | ||
176 | return main_clock->get_rate(main_clock) >> shift; | ||
177 | }; | ||
178 | |||
179 | static void cpu_clk_mode(struct clk *clk, int enabled) | ||
180 | { | ||
181 | struct at32_sm *sm = &system_manager; | ||
182 | unsigned long flags; | ||
183 | u32 mask; | ||
184 | |||
185 | spin_lock_irqsave(&sm->lock, flags); | ||
186 | mask = sm_readl(sm, PM_CPU_MASK); | ||
187 | if (enabled) | ||
188 | mask |= 1 << clk->index; | ||
189 | else | ||
190 | mask &= ~(1 << clk->index); | ||
191 | sm_writel(sm, PM_CPU_MASK, mask); | ||
192 | spin_unlock_irqrestore(&sm->lock, flags); | ||
193 | } | ||
194 | |||
195 | static unsigned long cpu_clk_get_rate(struct clk *clk) | ||
196 | { | ||
197 | unsigned long cksel, shift = 0; | ||
198 | |||
199 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
200 | if (cksel & SM_BIT(CPUDIV)) | ||
201 | shift = SM_BFEXT(CPUSEL, cksel) + 1; | ||
202 | |||
203 | return bus_clk_get_rate(clk, shift); | ||
204 | } | ||
205 | |||
206 | static void hsb_clk_mode(struct clk *clk, int enabled) | ||
207 | { | ||
208 | struct at32_sm *sm = &system_manager; | ||
209 | unsigned long flags; | ||
210 | u32 mask; | ||
211 | |||
212 | spin_lock_irqsave(&sm->lock, flags); | ||
213 | mask = sm_readl(sm, PM_HSB_MASK); | ||
214 | if (enabled) | ||
215 | mask |= 1 << clk->index; | ||
216 | else | ||
217 | mask &= ~(1 << clk->index); | ||
218 | sm_writel(sm, PM_HSB_MASK, mask); | ||
219 | spin_unlock_irqrestore(&sm->lock, flags); | ||
220 | } | ||
221 | |||
222 | static unsigned long hsb_clk_get_rate(struct clk *clk) | ||
223 | { | ||
224 | unsigned long cksel, shift = 0; | ||
225 | |||
226 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
227 | if (cksel & SM_BIT(HSBDIV)) | ||
228 | shift = SM_BFEXT(HSBSEL, cksel) + 1; | ||
229 | |||
230 | return bus_clk_get_rate(clk, shift); | ||
231 | } | ||
232 | |||
233 | static void pba_clk_mode(struct clk *clk, int enabled) | ||
234 | { | ||
235 | struct at32_sm *sm = &system_manager; | ||
236 | unsigned long flags; | ||
237 | u32 mask; | ||
238 | |||
239 | spin_lock_irqsave(&sm->lock, flags); | ||
240 | mask = sm_readl(sm, PM_PBA_MASK); | ||
241 | if (enabled) | ||
242 | mask |= 1 << clk->index; | ||
243 | else | ||
244 | mask &= ~(1 << clk->index); | ||
245 | sm_writel(sm, PM_PBA_MASK, mask); | ||
246 | spin_unlock_irqrestore(&sm->lock, flags); | ||
247 | } | ||
248 | |||
249 | static unsigned long pba_clk_get_rate(struct clk *clk) | ||
250 | { | ||
251 | unsigned long cksel, shift = 0; | ||
252 | |||
253 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
254 | if (cksel & SM_BIT(PBADIV)) | ||
255 | shift = SM_BFEXT(PBASEL, cksel) + 1; | ||
256 | |||
257 | return bus_clk_get_rate(clk, shift); | ||
258 | } | ||
259 | |||
260 | static void pbb_clk_mode(struct clk *clk, int enabled) | ||
261 | { | ||
262 | struct at32_sm *sm = &system_manager; | ||
263 | unsigned long flags; | ||
264 | u32 mask; | ||
265 | |||
266 | spin_lock_irqsave(&sm->lock, flags); | ||
267 | mask = sm_readl(sm, PM_PBB_MASK); | ||
268 | if (enabled) | ||
269 | mask |= 1 << clk->index; | ||
270 | else | ||
271 | mask &= ~(1 << clk->index); | ||
272 | sm_writel(sm, PM_PBB_MASK, mask); | ||
273 | spin_unlock_irqrestore(&sm->lock, flags); | ||
274 | } | ||
275 | |||
276 | static unsigned long pbb_clk_get_rate(struct clk *clk) | ||
277 | { | ||
278 | unsigned long cksel, shift = 0; | ||
279 | |||
280 | cksel = sm_readl(&system_manager, PM_CKSEL); | ||
281 | if (cksel & SM_BIT(PBBDIV)) | ||
282 | shift = SM_BFEXT(PBBSEL, cksel) + 1; | ||
283 | |||
284 | return bus_clk_get_rate(clk, shift); | ||
285 | } | ||
286 | |||
287 | static struct clk cpu_clk = { | ||
288 | .name = "cpu", | ||
289 | .get_rate = cpu_clk_get_rate, | ||
290 | .users = 1, | ||
291 | }; | ||
292 | static struct clk hsb_clk = { | ||
293 | .name = "hsb", | ||
294 | .parent = &cpu_clk, | ||
295 | .get_rate = hsb_clk_get_rate, | ||
296 | }; | ||
297 | static struct clk pba_clk = { | ||
298 | .name = "pba", | ||
299 | .parent = &hsb_clk, | ||
300 | .mode = hsb_clk_mode, | ||
301 | .get_rate = pba_clk_get_rate, | ||
302 | .index = 1, | ||
303 | }; | ||
304 | static struct clk pbb_clk = { | ||
305 | .name = "pbb", | ||
306 | .parent = &hsb_clk, | ||
307 | .mode = hsb_clk_mode, | ||
308 | .get_rate = pbb_clk_get_rate, | ||
309 | .users = 1, | ||
310 | .index = 2, | ||
311 | }; | ||
312 | |||
313 | /* -------------------------------------------------------------------- | ||
314 | * Generic Clock operations | ||
315 | * -------------------------------------------------------------------- */ | ||
316 | |||
317 | static void genclk_mode(struct clk *clk, int enabled) | ||
318 | { | ||
319 | u32 control; | ||
320 | |||
321 | BUG_ON(clk->index > 7); | ||
322 | |||
323 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
324 | if (enabled) | ||
325 | control |= SM_BIT(CEN); | ||
326 | else | ||
327 | control &= ~SM_BIT(CEN); | ||
328 | sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control); | ||
329 | } | ||
330 | |||
331 | static unsigned long genclk_get_rate(struct clk *clk) | ||
332 | { | ||
333 | u32 control; | ||
334 | unsigned long div = 1; | ||
335 | |||
336 | BUG_ON(clk->index > 7); | ||
337 | |||
338 | if (!clk->parent) | ||
339 | return 0; | ||
340 | |||
341 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
342 | if (control & SM_BIT(DIVEN)) | ||
343 | div = 2 * (SM_BFEXT(DIV, control) + 1); | ||
344 | |||
345 | return clk->parent->get_rate(clk->parent) / div; | ||
346 | } | ||
347 | |||
348 | static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply) | ||
349 | { | ||
350 | u32 control; | ||
351 | unsigned long parent_rate, actual_rate, div; | ||
352 | |||
353 | BUG_ON(clk->index > 7); | ||
354 | |||
355 | if (!clk->parent) | ||
356 | return 0; | ||
357 | |||
358 | parent_rate = clk->parent->get_rate(clk->parent); | ||
359 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
360 | |||
361 | if (rate > 3 * parent_rate / 4) { | ||
362 | actual_rate = parent_rate; | ||
363 | control &= ~SM_BIT(DIVEN); | ||
364 | } else { | ||
365 | div = (parent_rate + rate) / (2 * rate) - 1; | ||
366 | control = SM_BFINS(DIV, div, control) | SM_BIT(DIVEN); | ||
367 | actual_rate = parent_rate / (2 * (div + 1)); | ||
368 | } | ||
369 | |||
370 | printk("clk %s: new rate %lu (actual rate %lu)\n", | ||
371 | clk->name, rate, actual_rate); | ||
372 | |||
373 | if (apply) | ||
374 | sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, | ||
375 | control); | ||
376 | |||
377 | return actual_rate; | ||
378 | } | ||
379 | |||
380 | int genclk_set_parent(struct clk *clk, struct clk *parent) | ||
381 | { | ||
382 | u32 control; | ||
383 | |||
384 | BUG_ON(clk->index > 7); | ||
385 | |||
386 | printk("clk %s: new parent %s (was %s)\n", | ||
387 | clk->name, parent->name, | ||
388 | clk->parent ? clk->parent->name : "(null)"); | ||
389 | |||
390 | control = sm_readl(&system_manager, PM_GCCTRL + 4 * clk->index); | ||
391 | |||
392 | if (parent == &osc1 || parent == &pll1) | ||
393 | control |= SM_BIT(OSCSEL); | ||
394 | else if (parent == &osc0 || parent == &pll0) | ||
395 | control &= ~SM_BIT(OSCSEL); | ||
396 | else | ||
397 | return -EINVAL; | ||
398 | |||
399 | if (parent == &pll0 || parent == &pll1) | ||
400 | control |= SM_BIT(PLLSEL); | ||
401 | else | ||
402 | control &= ~SM_BIT(PLLSEL); | ||
403 | |||
404 | sm_writel(&system_manager, PM_GCCTRL + 4 * clk->index, control); | ||
405 | clk->parent = parent; | ||
406 | |||
407 | return 0; | ||
408 | } | ||
409 | |||
410 | /* -------------------------------------------------------------------- | ||
411 | * System peripherals | ||
412 | * -------------------------------------------------------------------- */ | ||
413 | static struct resource sm_resource[] = { | ||
414 | PBMEM(0xfff00000), | ||
415 | NAMED_IRQ(19, "eim"), | ||
416 | NAMED_IRQ(20, "pm"), | ||
417 | NAMED_IRQ(21, "rtc"), | ||
418 | }; | ||
419 | struct platform_device at32_sm_device = { | ||
420 | .name = "sm", | ||
421 | .id = 0, | ||
422 | .resource = sm_resource, | ||
423 | .num_resources = ARRAY_SIZE(sm_resource), | ||
424 | }; | ||
425 | DEV_CLK(pclk, at32_sm, pbb, 0); | ||
426 | |||
427 | static struct resource intc0_resource[] = { | ||
428 | PBMEM(0xfff00400), | ||
429 | }; | ||
430 | struct platform_device at32_intc0_device = { | ||
431 | .name = "intc", | ||
432 | .id = 0, | ||
433 | .resource = intc0_resource, | ||
434 | .num_resources = ARRAY_SIZE(intc0_resource), | ||
435 | }; | ||
436 | DEV_CLK(pclk, at32_intc0, pbb, 1); | ||
437 | |||
438 | static struct clk ebi_clk = { | ||
439 | .name = "ebi", | ||
440 | .parent = &hsb_clk, | ||
441 | .mode = hsb_clk_mode, | ||
442 | .get_rate = hsb_clk_get_rate, | ||
443 | .users = 1, | ||
444 | }; | ||
445 | static struct clk hramc_clk = { | ||
446 | .name = "hramc", | ||
447 | .parent = &hsb_clk, | ||
448 | .mode = hsb_clk_mode, | ||
449 | .get_rate = hsb_clk_get_rate, | ||
450 | .users = 1, | ||
451 | }; | ||
452 | |||
453 | static struct resource smc0_resource[] = { | ||
454 | PBMEM(0xfff03400), | ||
455 | }; | ||
456 | DEFINE_DEV(smc, 0); | ||
457 | DEV_CLK(pclk, smc0, pbb, 13); | ||
458 | DEV_CLK(mck, smc0, hsb, 0); | ||
459 | |||
460 | static struct platform_device pdc_device = { | ||
461 | .name = "pdc", | ||
462 | .id = 0, | ||
463 | }; | ||
464 | DEV_CLK(hclk, pdc, hsb, 4); | ||
465 | DEV_CLK(pclk, pdc, pba, 16); | ||
466 | |||
467 | static struct clk pico_clk = { | ||
468 | .name = "pico", | ||
469 | .parent = &cpu_clk, | ||
470 | .mode = cpu_clk_mode, | ||
471 | .get_rate = cpu_clk_get_rate, | ||
472 | .users = 1, | ||
473 | }; | ||
474 | |||
475 | /* -------------------------------------------------------------------- | ||
476 | * PIO | ||
477 | * -------------------------------------------------------------------- */ | ||
478 | |||
479 | static struct resource pio0_resource[] = { | ||
480 | PBMEM(0xffe02800), | ||
481 | IRQ(13), | ||
482 | }; | ||
483 | DEFINE_DEV(pio, 0); | ||
484 | DEV_CLK(mck, pio0, pba, 10); | ||
485 | |||
486 | static struct resource pio1_resource[] = { | ||
487 | PBMEM(0xffe02c00), | ||
488 | IRQ(14), | ||
489 | }; | ||
490 | DEFINE_DEV(pio, 1); | ||
491 | DEV_CLK(mck, pio1, pba, 11); | ||
492 | |||
493 | static struct resource pio2_resource[] = { | ||
494 | PBMEM(0xffe03000), | ||
495 | IRQ(15), | ||
496 | }; | ||
497 | DEFINE_DEV(pio, 2); | ||
498 | DEV_CLK(mck, pio2, pba, 12); | ||
499 | |||
500 | static struct resource pio3_resource[] = { | ||
501 | PBMEM(0xffe03400), | ||
502 | IRQ(16), | ||
503 | }; | ||
504 | DEFINE_DEV(pio, 3); | ||
505 | DEV_CLK(mck, pio3, pba, 13); | ||
506 | |||
507 | void __init at32_add_system_devices(void) | ||
508 | { | ||
509 | system_manager.eim_first_irq = NR_INTERNAL_IRQS; | ||
510 | |||
511 | platform_device_register(&at32_sm_device); | ||
512 | platform_device_register(&at32_intc0_device); | ||
513 | platform_device_register(&smc0_device); | ||
514 | platform_device_register(&pdc_device); | ||
515 | |||
516 | platform_device_register(&pio0_device); | ||
517 | platform_device_register(&pio1_device); | ||
518 | platform_device_register(&pio2_device); | ||
519 | platform_device_register(&pio3_device); | ||
520 | } | ||
521 | |||
522 | /* -------------------------------------------------------------------- | ||
523 | * USART | ||
524 | * -------------------------------------------------------------------- */ | ||
525 | |||
526 | static struct resource usart0_resource[] = { | ||
527 | PBMEM(0xffe00c00), | ||
528 | IRQ(7), | ||
529 | }; | ||
530 | DEFINE_DEV(usart, 0); | ||
531 | DEV_CLK(usart, usart0, pba, 4); | ||
532 | |||
533 | static struct resource usart1_resource[] = { | ||
534 | PBMEM(0xffe01000), | ||
535 | IRQ(7), | ||
536 | }; | ||
537 | DEFINE_DEV(usart, 1); | ||
538 | DEV_CLK(usart, usart1, pba, 4); | ||
539 | |||
540 | static struct resource usart2_resource[] = { | ||
541 | PBMEM(0xffe01400), | ||
542 | IRQ(8), | ||
543 | }; | ||
544 | DEFINE_DEV(usart, 2); | ||
545 | DEV_CLK(usart, usart2, pba, 5); | ||
546 | |||
547 | static struct resource usart3_resource[] = { | ||
548 | PBMEM(0xffe01800), | ||
549 | IRQ(9), | ||
550 | }; | ||
551 | DEFINE_DEV(usart, 3); | ||
552 | DEV_CLK(usart, usart3, pba, 6); | ||
553 | |||
554 | static inline void configure_usart0_pins(void) | ||
555 | { | ||
556 | portmux_set_func(PIOA, 8, FUNC_B); /* RXD */ | ||
557 | portmux_set_func(PIOA, 9, FUNC_B); /* TXD */ | ||
558 | } | ||
559 | |||
560 | static inline void configure_usart1_pins(void) | ||
561 | { | ||
562 | portmux_set_func(PIOA, 17, FUNC_A); /* RXD */ | ||
563 | portmux_set_func(PIOA, 18, FUNC_A); /* TXD */ | ||
564 | } | ||
565 | |||
566 | static inline void configure_usart2_pins(void) | ||
567 | { | ||
568 | portmux_set_func(PIOB, 26, FUNC_B); /* RXD */ | ||
569 | portmux_set_func(PIOB, 27, FUNC_B); /* TXD */ | ||
570 | } | ||
571 | |||
572 | static inline void configure_usart3_pins(void) | ||
573 | { | ||
574 | portmux_set_func(PIOB, 18, FUNC_B); /* RXD */ | ||
575 | portmux_set_func(PIOB, 17, FUNC_B); /* TXD */ | ||
576 | } | ||
577 | |||
578 | static struct platform_device *setup_usart(unsigned int id) | ||
579 | { | ||
580 | struct platform_device *pdev; | ||
581 | |||
582 | switch (id) { | ||
583 | case 0: | ||
584 | pdev = &usart0_device; | ||
585 | configure_usart0_pins(); | ||
586 | break; | ||
587 | case 1: | ||
588 | pdev = &usart1_device; | ||
589 | configure_usart1_pins(); | ||
590 | break; | ||
591 | case 2: | ||
592 | pdev = &usart2_device; | ||
593 | configure_usart2_pins(); | ||
594 | break; | ||
595 | case 3: | ||
596 | pdev = &usart3_device; | ||
597 | configure_usart3_pins(); | ||
598 | break; | ||
599 | default: | ||
600 | pdev = NULL; | ||
601 | break; | ||
602 | } | ||
603 | |||
604 | return pdev; | ||
605 | } | ||
606 | |||
607 | struct platform_device *__init at32_add_device_usart(unsigned int id) | ||
608 | { | ||
609 | struct platform_device *pdev; | ||
610 | |||
611 | pdev = setup_usart(id); | ||
612 | if (pdev) | ||
613 | platform_device_register(pdev); | ||
614 | |||
615 | return pdev; | ||
616 | } | ||
617 | |||
618 | struct platform_device *at91_default_console_device; | ||
619 | |||
620 | void __init at32_setup_serial_console(unsigned int usart_id) | ||
621 | { | ||
622 | at91_default_console_device = setup_usart(usart_id); | ||
623 | } | ||
624 | |||
625 | /* -------------------------------------------------------------------- | ||
626 | * Ethernet | ||
627 | * -------------------------------------------------------------------- */ | ||
628 | |||
629 | static struct eth_platform_data macb0_data; | ||
630 | static struct resource macb0_resource[] = { | ||
631 | PBMEM(0xfff01800), | ||
632 | IRQ(25), | ||
633 | }; | ||
634 | DEFINE_DEV_DATA(macb, 0); | ||
635 | DEV_CLK(hclk, macb0, hsb, 8); | ||
636 | DEV_CLK(pclk, macb0, pbb, 6); | ||
637 | |||
638 | struct platform_device *__init | ||
639 | at32_add_device_eth(unsigned int id, struct eth_platform_data *data) | ||
640 | { | ||
641 | struct platform_device *pdev; | ||
642 | |||
643 | switch (id) { | ||
644 | case 0: | ||
645 | pdev = &macb0_device; | ||
646 | |||
647 | portmux_set_func(PIOC, 3, FUNC_A); /* TXD0 */ | ||
648 | portmux_set_func(PIOC, 4, FUNC_A); /* TXD1 */ | ||
649 | portmux_set_func(PIOC, 7, FUNC_A); /* TXEN */ | ||
650 | portmux_set_func(PIOC, 8, FUNC_A); /* TXCK */ | ||
651 | portmux_set_func(PIOC, 9, FUNC_A); /* RXD0 */ | ||
652 | portmux_set_func(PIOC, 10, FUNC_A); /* RXD1 */ | ||
653 | portmux_set_func(PIOC, 13, FUNC_A); /* RXER */ | ||
654 | portmux_set_func(PIOC, 15, FUNC_A); /* RXDV */ | ||
655 | portmux_set_func(PIOC, 16, FUNC_A); /* MDC */ | ||
656 | portmux_set_func(PIOC, 17, FUNC_A); /* MDIO */ | ||
657 | |||
658 | if (!data->is_rmii) { | ||
659 | portmux_set_func(PIOC, 0, FUNC_A); /* COL */ | ||
660 | portmux_set_func(PIOC, 1, FUNC_A); /* CRS */ | ||
661 | portmux_set_func(PIOC, 2, FUNC_A); /* TXER */ | ||
662 | portmux_set_func(PIOC, 5, FUNC_A); /* TXD2 */ | ||
663 | portmux_set_func(PIOC, 6, FUNC_A); /* TXD3 */ | ||
664 | portmux_set_func(PIOC, 11, FUNC_A); /* RXD2 */ | ||
665 | portmux_set_func(PIOC, 12, FUNC_A); /* RXD3 */ | ||
666 | portmux_set_func(PIOC, 14, FUNC_A); /* RXCK */ | ||
667 | portmux_set_func(PIOC, 18, FUNC_A); /* SPD */ | ||
668 | } | ||
669 | break; | ||
670 | |||
671 | default: | ||
672 | return NULL; | ||
673 | } | ||
674 | |||
675 | memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data)); | ||
676 | platform_device_register(pdev); | ||
677 | |||
678 | return pdev; | ||
679 | } | ||
680 | |||
681 | /* -------------------------------------------------------------------- | ||
682 | * SPI | ||
683 | * -------------------------------------------------------------------- */ | ||
684 | static struct resource spi0_resource[] = { | ||
685 | PBMEM(0xffe00000), | ||
686 | IRQ(3), | ||
687 | }; | ||
688 | DEFINE_DEV(spi, 0); | ||
689 | DEV_CLK(mck, spi0, pba, 0); | ||
690 | |||
691 | struct platform_device *__init at32_add_device_spi(unsigned int id) | ||
692 | { | ||
693 | struct platform_device *pdev; | ||
694 | |||
695 | switch (id) { | ||
696 | case 0: | ||
697 | pdev = &spi0_device; | ||
698 | portmux_set_func(PIOA, 0, FUNC_A); /* MISO */ | ||
699 | portmux_set_func(PIOA, 1, FUNC_A); /* MOSI */ | ||
700 | portmux_set_func(PIOA, 2, FUNC_A); /* SCK */ | ||
701 | portmux_set_func(PIOA, 3, FUNC_A); /* NPCS0 */ | ||
702 | portmux_set_func(PIOA, 4, FUNC_A); /* NPCS1 */ | ||
703 | portmux_set_func(PIOA, 5, FUNC_A); /* NPCS2 */ | ||
704 | break; | ||
705 | |||
706 | default: | ||
707 | return NULL; | ||
708 | } | ||
709 | |||
710 | platform_device_register(pdev); | ||
711 | return pdev; | ||
712 | } | ||
713 | |||
714 | /* -------------------------------------------------------------------- | ||
715 | * LCDC | ||
716 | * -------------------------------------------------------------------- */ | ||
717 | static struct lcdc_platform_data lcdc0_data; | ||
718 | static struct resource lcdc0_resource[] = { | ||
719 | { | ||
720 | .start = 0xff000000, | ||
721 | .end = 0xff000fff, | ||
722 | .flags = IORESOURCE_MEM, | ||
723 | }, | ||
724 | IRQ(1), | ||
725 | }; | ||
726 | DEFINE_DEV_DATA(lcdc, 0); | ||
727 | DEV_CLK(hclk, lcdc0, hsb, 7); | ||
728 | static struct clk lcdc0_pixclk = { | ||
729 | .name = "pixclk", | ||
730 | .dev = &lcdc0_device.dev, | ||
731 | .mode = genclk_mode, | ||
732 | .get_rate = genclk_get_rate, | ||
733 | .set_rate = genclk_set_rate, | ||
734 | .set_parent = genclk_set_parent, | ||
735 | .index = 7, | ||
736 | }; | ||
737 | |||
738 | struct platform_device *__init | ||
739 | at32_add_device_lcdc(unsigned int id, struct lcdc_platform_data *data) | ||
740 | { | ||
741 | struct platform_device *pdev; | ||
742 | |||
743 | switch (id) { | ||
744 | case 0: | ||
745 | pdev = &lcdc0_device; | ||
746 | portmux_set_func(PIOC, 19, FUNC_A); /* CC */ | ||
747 | portmux_set_func(PIOC, 20, FUNC_A); /* HSYNC */ | ||
748 | portmux_set_func(PIOC, 21, FUNC_A); /* PCLK */ | ||
749 | portmux_set_func(PIOC, 22, FUNC_A); /* VSYNC */ | ||
750 | portmux_set_func(PIOC, 23, FUNC_A); /* DVAL */ | ||
751 | portmux_set_func(PIOC, 24, FUNC_A); /* MODE */ | ||
752 | portmux_set_func(PIOC, 25, FUNC_A); /* PWR */ | ||
753 | portmux_set_func(PIOC, 26, FUNC_A); /* DATA0 */ | ||
754 | portmux_set_func(PIOC, 27, FUNC_A); /* DATA1 */ | ||
755 | portmux_set_func(PIOC, 28, FUNC_A); /* DATA2 */ | ||
756 | portmux_set_func(PIOC, 29, FUNC_A); /* DATA3 */ | ||
757 | portmux_set_func(PIOC, 30, FUNC_A); /* DATA4 */ | ||
758 | portmux_set_func(PIOC, 31, FUNC_A); /* DATA5 */ | ||
759 | portmux_set_func(PIOD, 0, FUNC_A); /* DATA6 */ | ||
760 | portmux_set_func(PIOD, 1, FUNC_A); /* DATA7 */ | ||
761 | portmux_set_func(PIOD, 2, FUNC_A); /* DATA8 */ | ||
762 | portmux_set_func(PIOD, 3, FUNC_A); /* DATA9 */ | ||
763 | portmux_set_func(PIOD, 4, FUNC_A); /* DATA10 */ | ||
764 | portmux_set_func(PIOD, 5, FUNC_A); /* DATA11 */ | ||
765 | portmux_set_func(PIOD, 6, FUNC_A); /* DATA12 */ | ||
766 | portmux_set_func(PIOD, 7, FUNC_A); /* DATA13 */ | ||
767 | portmux_set_func(PIOD, 8, FUNC_A); /* DATA14 */ | ||
768 | portmux_set_func(PIOD, 9, FUNC_A); /* DATA15 */ | ||
769 | portmux_set_func(PIOD, 10, FUNC_A); /* DATA16 */ | ||
770 | portmux_set_func(PIOD, 11, FUNC_A); /* DATA17 */ | ||
771 | portmux_set_func(PIOD, 12, FUNC_A); /* DATA18 */ | ||
772 | portmux_set_func(PIOD, 13, FUNC_A); /* DATA19 */ | ||
773 | portmux_set_func(PIOD, 14, FUNC_A); /* DATA20 */ | ||
774 | portmux_set_func(PIOD, 15, FUNC_A); /* DATA21 */ | ||
775 | portmux_set_func(PIOD, 16, FUNC_A); /* DATA22 */ | ||
776 | portmux_set_func(PIOD, 17, FUNC_A); /* DATA23 */ | ||
777 | |||
778 | clk_set_parent(&lcdc0_pixclk, &pll0); | ||
779 | clk_set_rate(&lcdc0_pixclk, clk_get_rate(&pll0)); | ||
780 | break; | ||
781 | |||
782 | default: | ||
783 | return NULL; | ||
784 | } | ||
785 | |||
786 | memcpy(pdev->dev.platform_data, data, | ||
787 | sizeof(struct lcdc_platform_data)); | ||
788 | |||
789 | platform_device_register(pdev); | ||
790 | return pdev; | ||
791 | } | ||
792 | |||
793 | struct clk *at32_clock_list[] = { | ||
794 | &osc32k, | ||
795 | &osc0, | ||
796 | &osc1, | ||
797 | &pll0, | ||
798 | &pll1, | ||
799 | &cpu_clk, | ||
800 | &hsb_clk, | ||
801 | &pba_clk, | ||
802 | &pbb_clk, | ||
803 | &at32_sm_pclk, | ||
804 | &at32_intc0_pclk, | ||
805 | &ebi_clk, | ||
806 | &hramc_clk, | ||
807 | &smc0_pclk, | ||
808 | &smc0_mck, | ||
809 | &pdc_hclk, | ||
810 | &pdc_pclk, | ||
811 | &pico_clk, | ||
812 | &pio0_mck, | ||
813 | &pio1_mck, | ||
814 | &pio2_mck, | ||
815 | &pio3_mck, | ||
816 | &usart0_usart, | ||
817 | &usart1_usart, | ||
818 | &usart2_usart, | ||
819 | &usart3_usart, | ||
820 | &macb0_hclk, | ||
821 | &macb0_pclk, | ||
822 | &spi0_mck, | ||
823 | &lcdc0_hclk, | ||
824 | &lcdc0_pixclk, | ||
825 | }; | ||
826 | unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list); | ||
827 | |||
828 | void __init at32_portmux_init(void) | ||
829 | { | ||
830 | at32_init_pio(&pio0_device); | ||
831 | at32_init_pio(&pio1_device); | ||
832 | at32_init_pio(&pio2_device); | ||
833 | at32_init_pio(&pio3_device); | ||
834 | } | ||
835 | |||
836 | void __init at32_clock_init(void) | ||
837 | { | ||
838 | struct at32_sm *sm = &system_manager; | ||
839 | u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0; | ||
840 | int i; | ||
841 | |||
842 | if (sm_readl(sm, PM_MCCTRL) & SM_BIT(PLLSEL)) | ||
843 | main_clock = &pll0; | ||
844 | else | ||
845 | main_clock = &osc0; | ||
846 | |||
847 | if (sm_readl(sm, PM_PLL0) & SM_BIT(PLLOSC)) | ||
848 | pll0.parent = &osc1; | ||
849 | if (sm_readl(sm, PM_PLL1) & SM_BIT(PLLOSC)) | ||
850 | pll1.parent = &osc1; | ||
851 | |||
852 | /* | ||
853 | * Turn on all clocks that have at least one user already, and | ||
854 | * turn off everything else. We only do this for module | ||
855 | * clocks, and even though it isn't particularly pretty to | ||
856 | * check the address of the mode function, it should do the | ||
857 | * trick... | ||
858 | */ | ||
859 | for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) { | ||
860 | struct clk *clk = at32_clock_list[i]; | ||
861 | |||
862 | if (clk->mode == &cpu_clk_mode) | ||
863 | cpu_mask |= 1 << clk->index; | ||
864 | else if (clk->mode == &hsb_clk_mode) | ||
865 | hsb_mask |= 1 << clk->index; | ||
866 | else if (clk->mode == &pba_clk_mode) | ||
867 | pba_mask |= 1 << clk->index; | ||
868 | else if (clk->mode == &pbb_clk_mode) | ||
869 | pbb_mask |= 1 << clk->index; | ||
870 | } | ||
871 | |||
872 | sm_writel(sm, PM_CPU_MASK, cpu_mask); | ||
873 | sm_writel(sm, PM_HSB_MASK, hsb_mask); | ||
874 | sm_writel(sm, PM_PBA_MASK, pba_mask); | ||
875 | sm_writel(sm, PM_PBB_MASK, pbb_mask); | ||
876 | } | ||