blob: 64cc5583ddfb0a5feb89669d00ce853055421a68 [file] [log] [blame]
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001/*
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>
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01009#include <linux/fb.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070010#include <linux/init.h>
11#include <linux/platform_device.h>
David Brownell6b84bbf2007-06-22 19:17:57 -070012#include <linux/dma-mapping.h>
Haavard Skinnemoen41d8ca42007-02-16 13:56:11 +010013#include <linux/spi/spi.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070014
15#include <asm/io.h>
16
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +010017#include <asm/arch/at32ap7000.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070018#include <asm/arch/board.h>
19#include <asm/arch/portmux.h>
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070020
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +010021#include <video/atmel_lcdc.h>
22
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070023#include "clock.h"
Haavard Skinnemoen9c8f8e72007-02-01 16:34:10 +010024#include "hmatrix.h"
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070025#include "pio.h"
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +020026#include "pm.h"
27
28/*
29 * We can reduce the code size a bit by using a constant here. Since
30 * this file is completely chip-specific, it's safe to not use
31 * ioremap. Generic drivers should of course never do this.
32 */
33#define AT32_PM_BASE 0xfff00000
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070034
35#define PBMEM(base) \
36 { \
37 .start = base, \
38 .end = base + 0x3ff, \
39 .flags = IORESOURCE_MEM, \
40 }
41#define IRQ(num) \
42 { \
43 .start = num, \
44 .end = num, \
45 .flags = IORESOURCE_IRQ, \
46 }
47#define NAMED_IRQ(num, _name) \
48 { \
49 .start = num, \
50 .end = num, \
51 .name = _name, \
52 .flags = IORESOURCE_IRQ, \
53 }
54
David Brownell6b84bbf2007-06-22 19:17:57 -070055/* REVISIT these assume *every* device supports DMA, but several
56 * don't ... tc, smc, pio, rtc, watchdog, pwm, ps2, and more.
57 */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070058#define DEFINE_DEV(_name, _id) \
David Brownell6b84bbf2007-06-22 19:17:57 -070059static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070060static struct platform_device _name##_id##_device = { \
61 .name = #_name, \
62 .id = _id, \
63 .dev = { \
David Brownell6b84bbf2007-06-22 19:17:57 -070064 .dma_mask = &_name##_id##_dma_mask, \
65 .coherent_dma_mask = DMA_32BIT_MASK, \
66 }, \
67 .resource = _name##_id##_resource, \
68 .num_resources = ARRAY_SIZE(_name##_id##_resource), \
69}
70#define DEFINE_DEV_DATA(_name, _id) \
71static u64 _name##_id##_dma_mask = DMA_32BIT_MASK; \
72static struct platform_device _name##_id##_device = { \
73 .name = #_name, \
74 .id = _id, \
75 .dev = { \
76 .dma_mask = &_name##_id##_dma_mask, \
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070077 .platform_data = &_name##_id##_data, \
David Brownell6b84bbf2007-06-22 19:17:57 -070078 .coherent_dma_mask = DMA_32BIT_MASK, \
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070079 }, \
80 .resource = _name##_id##_resource, \
81 .num_resources = ARRAY_SIZE(_name##_id##_resource), \
82}
83
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +010084#define select_peripheral(pin, periph, flags) \
85 at32_select_periph(GPIO_PIN_##pin, GPIO_##periph, flags)
86
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070087#define DEV_CLK(_name, devname, bus, _index) \
88static struct clk devname##_##_name = { \
89 .name = #_name, \
90 .dev = &devname##_device.dev, \
91 .parent = &bus##_clk, \
92 .mode = bus##_clk_mode, \
93 .get_rate = bus##_clk_get_rate, \
94 .index = _index, \
95}
96
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +020097static DEFINE_SPINLOCK(pm_lock);
98
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -070099unsigned long at32ap7000_osc_rates[3] = {
100 [0] = 32768,
101 /* FIXME: these are ATSTK1002-specific */
102 [1] = 20000000,
103 [2] = 12000000,
104};
105
106static unsigned long osc_get_rate(struct clk *clk)
107{
108 return at32ap7000_osc_rates[clk->index];
109}
110
111static unsigned long pll_get_rate(struct clk *clk, unsigned long control)
112{
113 unsigned long div, mul, rate;
114
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200115 if (!(control & PM_BIT(PLLEN)))
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700116 return 0;
117
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200118 div = PM_BFEXT(PLLDIV, control) + 1;
119 mul = PM_BFEXT(PLLMUL, control) + 1;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700120
121 rate = clk->parent->get_rate(clk->parent);
122 rate = (rate + div / 2) / div;
123 rate *= mul;
124
125 return rate;
126}
127
128static unsigned long pll0_get_rate(struct clk *clk)
129{
130 u32 control;
131
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200132 control = pm_readl(PLL0);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700133
134 return pll_get_rate(clk, control);
135}
136
137static unsigned long pll1_get_rate(struct clk *clk)
138{
139 u32 control;
140
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200141 control = pm_readl(PLL1);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700142
143 return pll_get_rate(clk, control);
144}
145
146/*
147 * The AT32AP7000 has five primary clock sources: One 32kHz
148 * oscillator, two crystal oscillators and two PLLs.
149 */
150static struct clk osc32k = {
151 .name = "osc32k",
152 .get_rate = osc_get_rate,
153 .users = 1,
154 .index = 0,
155};
156static struct clk osc0 = {
157 .name = "osc0",
158 .get_rate = osc_get_rate,
159 .users = 1,
160 .index = 1,
161};
162static struct clk osc1 = {
163 .name = "osc1",
164 .get_rate = osc_get_rate,
165 .index = 2,
166};
167static struct clk pll0 = {
168 .name = "pll0",
169 .get_rate = pll0_get_rate,
170 .parent = &osc0,
171};
172static struct clk pll1 = {
173 .name = "pll1",
174 .get_rate = pll1_get_rate,
175 .parent = &osc0,
176};
177
178/*
179 * The main clock can be either osc0 or pll0. The boot loader may
180 * have chosen one for us, so we don't really know which one until we
181 * have a look at the SM.
182 */
183static struct clk *main_clock;
184
185/*
186 * Synchronous clocks are generated from the main clock. The clocks
187 * must satisfy the constraint
188 * fCPU >= fHSB >= fPB
189 * i.e. each clock must not be faster than its parent.
190 */
191static unsigned long bus_clk_get_rate(struct clk *clk, unsigned int shift)
192{
193 return main_clock->get_rate(main_clock) >> shift;
194};
195
196static void cpu_clk_mode(struct clk *clk, int enabled)
197{
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700198 unsigned long flags;
199 u32 mask;
200
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200201 spin_lock_irqsave(&pm_lock, flags);
202 mask = pm_readl(CPU_MASK);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700203 if (enabled)
204 mask |= 1 << clk->index;
205 else
206 mask &= ~(1 << clk->index);
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200207 pm_writel(CPU_MASK, mask);
208 spin_unlock_irqrestore(&pm_lock, flags);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700209}
210
211static unsigned long cpu_clk_get_rate(struct clk *clk)
212{
213 unsigned long cksel, shift = 0;
214
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200215 cksel = pm_readl(CKSEL);
216 if (cksel & PM_BIT(CPUDIV))
217 shift = PM_BFEXT(CPUSEL, cksel) + 1;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700218
219 return bus_clk_get_rate(clk, shift);
220}
221
Hans-Christian Egtvedt9e58e182007-06-04 16:10:57 +0200222static long cpu_clk_set_rate(struct clk *clk, unsigned long rate, int apply)
223{
224 u32 control;
225 unsigned long parent_rate, child_div, actual_rate, div;
226
227 parent_rate = clk->parent->get_rate(clk->parent);
228 control = pm_readl(CKSEL);
229
230 if (control & PM_BIT(HSBDIV))
231 child_div = 1 << (PM_BFEXT(HSBSEL, control) + 1);
232 else
233 child_div = 1;
234
235 if (rate > 3 * (parent_rate / 4) || child_div == 1) {
236 actual_rate = parent_rate;
237 control &= ~PM_BIT(CPUDIV);
238 } else {
239 unsigned int cpusel;
240 div = (parent_rate + rate / 2) / rate;
241 if (div > child_div)
242 div = child_div;
243 cpusel = (div > 1) ? (fls(div) - 2) : 0;
244 control = PM_BIT(CPUDIV) | PM_BFINS(CPUSEL, cpusel, control);
245 actual_rate = parent_rate / (1 << (cpusel + 1));
246 }
247
248 pr_debug("clk %s: new rate %lu (actual rate %lu)\n",
249 clk->name, rate, actual_rate);
250
251 if (apply)
252 pm_writel(CKSEL, control);
253
254 return actual_rate;
255}
256
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700257static void hsb_clk_mode(struct clk *clk, int enabled)
258{
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700259 unsigned long flags;
260 u32 mask;
261
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200262 spin_lock_irqsave(&pm_lock, flags);
263 mask = pm_readl(HSB_MASK);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700264 if (enabled)
265 mask |= 1 << clk->index;
266 else
267 mask &= ~(1 << clk->index);
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200268 pm_writel(HSB_MASK, mask);
269 spin_unlock_irqrestore(&pm_lock, flags);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700270}
271
272static unsigned long hsb_clk_get_rate(struct clk *clk)
273{
274 unsigned long cksel, shift = 0;
275
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200276 cksel = pm_readl(CKSEL);
277 if (cksel & PM_BIT(HSBDIV))
278 shift = PM_BFEXT(HSBSEL, cksel) + 1;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700279
280 return bus_clk_get_rate(clk, shift);
281}
282
283static void pba_clk_mode(struct clk *clk, int enabled)
284{
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700285 unsigned long flags;
286 u32 mask;
287
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200288 spin_lock_irqsave(&pm_lock, flags);
289 mask = pm_readl(PBA_MASK);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700290 if (enabled)
291 mask |= 1 << clk->index;
292 else
293 mask &= ~(1 << clk->index);
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200294 pm_writel(PBA_MASK, mask);
295 spin_unlock_irqrestore(&pm_lock, flags);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700296}
297
298static unsigned long pba_clk_get_rate(struct clk *clk)
299{
300 unsigned long cksel, shift = 0;
301
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200302 cksel = pm_readl(CKSEL);
303 if (cksel & PM_BIT(PBADIV))
304 shift = PM_BFEXT(PBASEL, cksel) + 1;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700305
306 return bus_clk_get_rate(clk, shift);
307}
308
309static void pbb_clk_mode(struct clk *clk, int enabled)
310{
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700311 unsigned long flags;
312 u32 mask;
313
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200314 spin_lock_irqsave(&pm_lock, flags);
315 mask = pm_readl(PBB_MASK);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700316 if (enabled)
317 mask |= 1 << clk->index;
318 else
319 mask &= ~(1 << clk->index);
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200320 pm_writel(PBB_MASK, mask);
321 spin_unlock_irqrestore(&pm_lock, flags);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700322}
323
324static unsigned long pbb_clk_get_rate(struct clk *clk)
325{
326 unsigned long cksel, shift = 0;
327
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200328 cksel = pm_readl(CKSEL);
329 if (cksel & PM_BIT(PBBDIV))
330 shift = PM_BFEXT(PBBSEL, cksel) + 1;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700331
332 return bus_clk_get_rate(clk, shift);
333}
334
335static struct clk cpu_clk = {
336 .name = "cpu",
337 .get_rate = cpu_clk_get_rate,
Hans-Christian Egtvedt9e58e182007-06-04 16:10:57 +0200338 .set_rate = cpu_clk_set_rate,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700339 .users = 1,
340};
341static struct clk hsb_clk = {
342 .name = "hsb",
343 .parent = &cpu_clk,
344 .get_rate = hsb_clk_get_rate,
345};
346static struct clk pba_clk = {
347 .name = "pba",
348 .parent = &hsb_clk,
349 .mode = hsb_clk_mode,
350 .get_rate = pba_clk_get_rate,
351 .index = 1,
352};
353static struct clk pbb_clk = {
354 .name = "pbb",
355 .parent = &hsb_clk,
356 .mode = hsb_clk_mode,
357 .get_rate = pbb_clk_get_rate,
358 .users = 1,
359 .index = 2,
360};
361
362/* --------------------------------------------------------------------
363 * Generic Clock operations
364 * -------------------------------------------------------------------- */
365
366static void genclk_mode(struct clk *clk, int enabled)
367{
368 u32 control;
369
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200370 control = pm_readl(GCCTRL(clk->index));
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700371 if (enabled)
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200372 control |= PM_BIT(CEN);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700373 else
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200374 control &= ~PM_BIT(CEN);
375 pm_writel(GCCTRL(clk->index), control);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700376}
377
378static unsigned long genclk_get_rate(struct clk *clk)
379{
380 u32 control;
381 unsigned long div = 1;
382
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200383 control = pm_readl(GCCTRL(clk->index));
384 if (control & PM_BIT(DIVEN))
385 div = 2 * (PM_BFEXT(DIV, control) + 1);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700386
387 return clk->parent->get_rate(clk->parent) / div;
388}
389
390static long genclk_set_rate(struct clk *clk, unsigned long rate, int apply)
391{
392 u32 control;
393 unsigned long parent_rate, actual_rate, div;
394
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700395 parent_rate = clk->parent->get_rate(clk->parent);
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200396 control = pm_readl(GCCTRL(clk->index));
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700397
398 if (rate > 3 * parent_rate / 4) {
399 actual_rate = parent_rate;
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200400 control &= ~PM_BIT(DIVEN);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700401 } else {
402 div = (parent_rate + rate) / (2 * rate) - 1;
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200403 control = PM_BFINS(DIV, div, control) | PM_BIT(DIVEN);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700404 actual_rate = parent_rate / (2 * (div + 1));
405 }
406
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200407 dev_dbg(clk->dev, "clk %s: new rate %lu (actual rate %lu)\n",
408 clk->name, rate, actual_rate);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700409
410 if (apply)
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200411 pm_writel(GCCTRL(clk->index), control);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700412
413 return actual_rate;
414}
415
416int genclk_set_parent(struct clk *clk, struct clk *parent)
417{
418 u32 control;
419
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200420 dev_dbg(clk->dev, "clk %s: new parent %s (was %s)\n",
421 clk->name, parent->name, clk->parent->name);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700422
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200423 control = pm_readl(GCCTRL(clk->index));
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700424
425 if (parent == &osc1 || parent == &pll1)
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200426 control |= PM_BIT(OSCSEL);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700427 else if (parent == &osc0 || parent == &pll0)
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200428 control &= ~PM_BIT(OSCSEL);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700429 else
430 return -EINVAL;
431
432 if (parent == &pll0 || parent == &pll1)
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200433 control |= PM_BIT(PLLSEL);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700434 else
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200435 control &= ~PM_BIT(PLLSEL);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700436
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200437 pm_writel(GCCTRL(clk->index), control);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700438 clk->parent = parent;
439
440 return 0;
441}
442
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +0100443static void __init genclk_init_parent(struct clk *clk)
444{
445 u32 control;
446 struct clk *parent;
447
448 BUG_ON(clk->index > 7);
449
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200450 control = pm_readl(GCCTRL(clk->index));
451 if (control & PM_BIT(OSCSEL))
452 parent = (control & PM_BIT(PLLSEL)) ? &pll1 : &osc1;
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +0100453 else
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200454 parent = (control & PM_BIT(PLLSEL)) ? &pll0 : &osc0;
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +0100455
456 clk->parent = parent;
457}
458
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700459/* --------------------------------------------------------------------
460 * System peripherals
461 * -------------------------------------------------------------------- */
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200462static struct resource at32_pm0_resource[] = {
463 {
464 .start = 0xfff00000,
465 .end = 0xfff0007f,
466 .flags = IORESOURCE_MEM,
467 },
468 IRQ(20),
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700469};
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200470
471static struct resource at32ap700x_rtc0_resource[] = {
472 {
473 .start = 0xfff00080,
474 .end = 0xfff000af,
475 .flags = IORESOURCE_MEM,
476 },
477 IRQ(21),
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700478};
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200479
480static struct resource at32_wdt0_resource[] = {
481 {
482 .start = 0xfff000b0,
483 .end = 0xfff000bf,
484 .flags = IORESOURCE_MEM,
485 },
486};
487
488static struct resource at32_eic0_resource[] = {
489 {
490 .start = 0xfff00100,
491 .end = 0xfff0013f,
492 .flags = IORESOURCE_MEM,
493 },
494 IRQ(19),
495};
496
497DEFINE_DEV(at32_pm, 0);
498DEFINE_DEV(at32ap700x_rtc, 0);
499DEFINE_DEV(at32_wdt, 0);
500DEFINE_DEV(at32_eic, 0);
501
502/*
503 * Peripheral clock for PM, RTC, WDT and EIC. PM will ensure that this
504 * is always running.
505 */
506static struct clk at32_pm_pclk = {
Haavard Skinnemoen188ff652007-03-14 13:23:44 +0100507 .name = "pclk",
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200508 .dev = &at32_pm0_device.dev,
Haavard Skinnemoen188ff652007-03-14 13:23:44 +0100509 .parent = &pbb_clk,
510 .mode = pbb_clk_mode,
511 .get_rate = pbb_clk_get_rate,
512 .users = 1,
513 .index = 0,
514};
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700515
516static struct resource intc0_resource[] = {
517 PBMEM(0xfff00400),
518};
519struct platform_device at32_intc0_device = {
520 .name = "intc",
521 .id = 0,
522 .resource = intc0_resource,
523 .num_resources = ARRAY_SIZE(intc0_resource),
524};
525DEV_CLK(pclk, at32_intc0, pbb, 1);
526
527static struct clk ebi_clk = {
528 .name = "ebi",
529 .parent = &hsb_clk,
530 .mode = hsb_clk_mode,
531 .get_rate = hsb_clk_get_rate,
532 .users = 1,
533};
534static struct clk hramc_clk = {
535 .name = "hramc",
536 .parent = &hsb_clk,
537 .mode = hsb_clk_mode,
538 .get_rate = hsb_clk_get_rate,
539 .users = 1,
Haavard Skinnemoen188ff652007-03-14 13:23:44 +0100540 .index = 3,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700541};
542
Haavard Skinnemoenbc157b72006-09-25 23:32:16 -0700543static struct resource smc0_resource[] = {
544 PBMEM(0xfff03400),
545};
546DEFINE_DEV(smc, 0);
547DEV_CLK(pclk, smc0, pbb, 13);
548DEV_CLK(mck, smc0, hsb, 0);
549
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700550static struct platform_device pdc_device = {
551 .name = "pdc",
552 .id = 0,
553};
554DEV_CLK(hclk, pdc, hsb, 4);
555DEV_CLK(pclk, pdc, pba, 16);
556
557static struct clk pico_clk = {
558 .name = "pico",
559 .parent = &cpu_clk,
560 .mode = cpu_clk_mode,
561 .get_rate = cpu_clk_get_rate,
562 .users = 1,
563};
564
565/* --------------------------------------------------------------------
Haavard Skinnemoen9c8f8e72007-02-01 16:34:10 +0100566 * HMATRIX
567 * -------------------------------------------------------------------- */
568
569static struct clk hmatrix_clk = {
570 .name = "hmatrix_clk",
571 .parent = &pbb_clk,
572 .mode = pbb_clk_mode,
573 .get_rate = pbb_clk_get_rate,
574 .index = 2,
575 .users = 1,
576};
577#define HMATRIX_BASE ((void __iomem *)0xfff00800)
578
579#define hmatrix_readl(reg) \
580 __raw_readl((HMATRIX_BASE) + HMATRIX_##reg)
581#define hmatrix_writel(reg,value) \
582 __raw_writel((value), (HMATRIX_BASE) + HMATRIX_##reg)
583
584/*
585 * Set bits in the HMATRIX Special Function Register (SFR) used by the
586 * External Bus Interface (EBI). This can be used to enable special
587 * features like CompactFlash support, NAND Flash support, etc. on
588 * certain chipselects.
589 */
590static inline void set_ebi_sfr_bits(u32 mask)
591{
592 u32 sfr;
593
594 clk_enable(&hmatrix_clk);
595 sfr = hmatrix_readl(SFR4);
596 sfr |= mask;
597 hmatrix_writel(SFR4, sfr);
598 clk_disable(&hmatrix_clk);
599}
600
601/* --------------------------------------------------------------------
Hans-Christian Egtvedt77609892007-03-12 18:15:16 +0100602 * System Timer/Counter (TC)
603 * -------------------------------------------------------------------- */
604static struct resource at32_systc0_resource[] = {
605 PBMEM(0xfff00c00),
606 IRQ(22),
607};
608struct platform_device at32_systc0_device = {
609 .name = "systc",
610 .id = 0,
611 .resource = at32_systc0_resource,
612 .num_resources = ARRAY_SIZE(at32_systc0_resource),
613};
614DEV_CLK(pclk, at32_systc0, pbb, 3);
615
616/* --------------------------------------------------------------------
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700617 * PIO
618 * -------------------------------------------------------------------- */
619
620static struct resource pio0_resource[] = {
621 PBMEM(0xffe02800),
622 IRQ(13),
623};
624DEFINE_DEV(pio, 0);
625DEV_CLK(mck, pio0, pba, 10);
626
627static struct resource pio1_resource[] = {
628 PBMEM(0xffe02c00),
629 IRQ(14),
630};
631DEFINE_DEV(pio, 1);
632DEV_CLK(mck, pio1, pba, 11);
633
634static struct resource pio2_resource[] = {
635 PBMEM(0xffe03000),
636 IRQ(15),
637};
638DEFINE_DEV(pio, 2);
639DEV_CLK(mck, pio2, pba, 12);
640
641static struct resource pio3_resource[] = {
642 PBMEM(0xffe03400),
643 IRQ(16),
644};
645DEFINE_DEV(pio, 3);
646DEV_CLK(mck, pio3, pba, 13);
647
Haavard Skinnemoen7f9f4672007-01-30 11:16:16 +0100648static struct resource pio4_resource[] = {
649 PBMEM(0xffe03800),
650 IRQ(17),
651};
652DEFINE_DEV(pio, 4);
653DEV_CLK(mck, pio4, pba, 14);
654
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700655void __init at32_add_system_devices(void)
656{
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200657 platform_device_register(&at32_pm0_device);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700658 platform_device_register(&at32_intc0_device);
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +0200659 platform_device_register(&at32ap700x_rtc0_device);
660 platform_device_register(&at32_wdt0_device);
661 platform_device_register(&at32_eic0_device);
Haavard Skinnemoenbc157b72006-09-25 23:32:16 -0700662 platform_device_register(&smc0_device);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700663 platform_device_register(&pdc_device);
664
Hans-Christian Egtvedt77609892007-03-12 18:15:16 +0100665 platform_device_register(&at32_systc0_device);
666
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700667 platform_device_register(&pio0_device);
668 platform_device_register(&pio1_device);
669 platform_device_register(&pio2_device);
670 platform_device_register(&pio3_device);
Haavard Skinnemoen7f9f4672007-01-30 11:16:16 +0100671 platform_device_register(&pio4_device);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700672}
673
674/* --------------------------------------------------------------------
675 * USART
676 * -------------------------------------------------------------------- */
677
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200678static struct atmel_uart_data atmel_usart0_data = {
679 .use_dma_tx = 1,
680 .use_dma_rx = 1,
681};
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200682static struct resource atmel_usart0_resource[] = {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700683 PBMEM(0xffe00c00),
David Brownella3d912c2007-01-23 20:14:02 -0800684 IRQ(6),
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700685};
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200686DEFINE_DEV_DATA(atmel_usart, 0);
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200687DEV_CLK(usart, atmel_usart0, pba, 4);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700688
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200689static struct atmel_uart_data atmel_usart1_data = {
690 .use_dma_tx = 1,
691 .use_dma_rx = 1,
692};
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200693static struct resource atmel_usart1_resource[] = {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700694 PBMEM(0xffe01000),
695 IRQ(7),
696};
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200697DEFINE_DEV_DATA(atmel_usart, 1);
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200698DEV_CLK(usart, atmel_usart1, pba, 4);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700699
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200700static struct atmel_uart_data atmel_usart2_data = {
701 .use_dma_tx = 1,
702 .use_dma_rx = 1,
703};
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200704static struct resource atmel_usart2_resource[] = {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700705 PBMEM(0xffe01400),
706 IRQ(8),
707};
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200708DEFINE_DEV_DATA(atmel_usart, 2);
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200709DEV_CLK(usart, atmel_usart2, pba, 5);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700710
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200711static struct atmel_uart_data atmel_usart3_data = {
712 .use_dma_tx = 1,
713 .use_dma_rx = 1,
714};
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200715static struct resource atmel_usart3_resource[] = {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700716 PBMEM(0xffe01800),
717 IRQ(9),
718};
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200719DEFINE_DEV_DATA(atmel_usart, 3);
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200720DEV_CLK(usart, atmel_usart3, pba, 6);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700721
722static inline void configure_usart0_pins(void)
723{
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +0100724 select_peripheral(PA(8), PERIPH_B, 0); /* RXD */
725 select_peripheral(PA(9), PERIPH_B, 0); /* TXD */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700726}
727
728static inline void configure_usart1_pins(void)
729{
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +0100730 select_peripheral(PA(17), PERIPH_A, 0); /* RXD */
731 select_peripheral(PA(18), PERIPH_A, 0); /* TXD */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700732}
733
734static inline void configure_usart2_pins(void)
735{
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +0100736 select_peripheral(PB(26), PERIPH_B, 0); /* RXD */
737 select_peripheral(PB(27), PERIPH_B, 0); /* TXD */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700738}
739
740static inline void configure_usart3_pins(void)
741{
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +0100742 select_peripheral(PB(18), PERIPH_B, 0); /* RXD */
743 select_peripheral(PB(17), PERIPH_B, 0); /* TXD */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700744}
745
David Brownella3d912c2007-01-23 20:14:02 -0800746static struct platform_device *__initdata at32_usarts[4];
Haavard Skinnemoenc1945882006-10-04 16:02:10 +0200747
748void __init at32_map_usart(unsigned int hw_id, unsigned int line)
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700749{
750 struct platform_device *pdev;
751
Haavard Skinnemoenc1945882006-10-04 16:02:10 +0200752 switch (hw_id) {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700753 case 0:
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200754 pdev = &atmel_usart0_device;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700755 configure_usart0_pins();
756 break;
757 case 1:
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200758 pdev = &atmel_usart1_device;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700759 configure_usart1_pins();
760 break;
761 case 2:
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200762 pdev = &atmel_usart2_device;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700763 configure_usart2_pins();
764 break;
765 case 3:
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +0200766 pdev = &atmel_usart3_device;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700767 configure_usart3_pins();
768 break;
769 default:
Haavard Skinnemoenc1945882006-10-04 16:02:10 +0200770 return;
Haavard Skinnemoen75d35212006-10-04 16:02:08 +0200771 }
772
773 if (PXSEG(pdev->resource[0].start) == P4SEG) {
774 /* Addresses in the P4 segment are permanently mapped 1:1 */
775 struct atmel_uart_data *data = pdev->dev.platform_data;
776 data->regs = (void __iomem *)pdev->resource[0].start;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700777 }
778
Haavard Skinnemoenc1945882006-10-04 16:02:10 +0200779 pdev->id = line;
780 at32_usarts[line] = pdev;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700781}
782
783struct platform_device *__init at32_add_device_usart(unsigned int id)
784{
Haavard Skinnemoenc1945882006-10-04 16:02:10 +0200785 platform_device_register(at32_usarts[id]);
786 return at32_usarts[id];
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700787}
788
Haavard Skinnemoen73e27982006-10-04 16:02:04 +0200789struct platform_device *atmel_default_console_device;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700790
791void __init at32_setup_serial_console(unsigned int usart_id)
792{
Haavard Skinnemoenc1945882006-10-04 16:02:10 +0200793 atmel_default_console_device = at32_usarts[usart_id];
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700794}
795
796/* --------------------------------------------------------------------
797 * Ethernet
798 * -------------------------------------------------------------------- */
799
800static struct eth_platform_data macb0_data;
801static struct resource macb0_resource[] = {
802 PBMEM(0xfff01800),
803 IRQ(25),
804};
805DEFINE_DEV_DATA(macb, 0);
806DEV_CLK(hclk, macb0, hsb, 8);
807DEV_CLK(pclk, macb0, pbb, 6);
808
Haavard Skinnemoencfcb3a82006-10-30 09:23:12 +0100809static struct eth_platform_data macb1_data;
810static struct resource macb1_resource[] = {
811 PBMEM(0xfff01c00),
812 IRQ(26),
813};
814DEFINE_DEV_DATA(macb, 1);
815DEV_CLK(hclk, macb1, hsb, 9);
816DEV_CLK(pclk, macb1, pbb, 7);
817
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700818struct platform_device *__init
819at32_add_device_eth(unsigned int id, struct eth_platform_data *data)
820{
821 struct platform_device *pdev;
822
823 switch (id) {
824 case 0:
825 pdev = &macb0_device;
826
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +0100827 select_peripheral(PC(3), PERIPH_A, 0); /* TXD0 */
828 select_peripheral(PC(4), PERIPH_A, 0); /* TXD1 */
829 select_peripheral(PC(7), PERIPH_A, 0); /* TXEN */
830 select_peripheral(PC(8), PERIPH_A, 0); /* TXCK */
831 select_peripheral(PC(9), PERIPH_A, 0); /* RXD0 */
832 select_peripheral(PC(10), PERIPH_A, 0); /* RXD1 */
833 select_peripheral(PC(13), PERIPH_A, 0); /* RXER */
834 select_peripheral(PC(15), PERIPH_A, 0); /* RXDV */
835 select_peripheral(PC(16), PERIPH_A, 0); /* MDC */
836 select_peripheral(PC(17), PERIPH_A, 0); /* MDIO */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700837
838 if (!data->is_rmii) {
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +0100839 select_peripheral(PC(0), PERIPH_A, 0); /* COL */
840 select_peripheral(PC(1), PERIPH_A, 0); /* CRS */
841 select_peripheral(PC(2), PERIPH_A, 0); /* TXER */
842 select_peripheral(PC(5), PERIPH_A, 0); /* TXD2 */
843 select_peripheral(PC(6), PERIPH_A, 0); /* TXD3 */
844 select_peripheral(PC(11), PERIPH_A, 0); /* RXD2 */
845 select_peripheral(PC(12), PERIPH_A, 0); /* RXD3 */
846 select_peripheral(PC(14), PERIPH_A, 0); /* RXCK */
847 select_peripheral(PC(18), PERIPH_A, 0); /* SPD */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700848 }
849 break;
850
Haavard Skinnemoencfcb3a82006-10-30 09:23:12 +0100851 case 1:
852 pdev = &macb1_device;
853
854 select_peripheral(PD(13), PERIPH_B, 0); /* TXD0 */
855 select_peripheral(PD(14), PERIPH_B, 0); /* TXD1 */
856 select_peripheral(PD(11), PERIPH_B, 0); /* TXEN */
857 select_peripheral(PD(12), PERIPH_B, 0); /* TXCK */
858 select_peripheral(PD(10), PERIPH_B, 0); /* RXD0 */
859 select_peripheral(PD(6), PERIPH_B, 0); /* RXD1 */
860 select_peripheral(PD(5), PERIPH_B, 0); /* RXER */
861 select_peripheral(PD(4), PERIPH_B, 0); /* RXDV */
862 select_peripheral(PD(3), PERIPH_B, 0); /* MDC */
863 select_peripheral(PD(2), PERIPH_B, 0); /* MDIO */
864
865 if (!data->is_rmii) {
866 select_peripheral(PC(19), PERIPH_B, 0); /* COL */
867 select_peripheral(PC(23), PERIPH_B, 0); /* CRS */
868 select_peripheral(PC(26), PERIPH_B, 0); /* TXER */
869 select_peripheral(PC(27), PERIPH_B, 0); /* TXD2 */
870 select_peripheral(PC(28), PERIPH_B, 0); /* TXD3 */
871 select_peripheral(PC(29), PERIPH_B, 0); /* RXD2 */
872 select_peripheral(PC(30), PERIPH_B, 0); /* RXD3 */
873 select_peripheral(PC(24), PERIPH_B, 0); /* RXCK */
874 select_peripheral(PD(15), PERIPH_B, 0); /* SPD */
875 }
876 break;
877
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700878 default:
879 return NULL;
880 }
881
882 memcpy(pdev->dev.platform_data, data, sizeof(struct eth_platform_data));
883 platform_device_register(pdev);
884
885 return pdev;
886}
887
888/* --------------------------------------------------------------------
889 * SPI
890 * -------------------------------------------------------------------- */
Haavard Skinnemoen3d60ee12007-01-10 20:20:02 +0100891static struct resource atmel_spi0_resource[] = {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700892 PBMEM(0xffe00000),
893 IRQ(3),
894};
Haavard Skinnemoen3d60ee12007-01-10 20:20:02 +0100895DEFINE_DEV(atmel_spi, 0);
896DEV_CLK(spi_clk, atmel_spi0, pba, 0);
897
898static struct resource atmel_spi1_resource[] = {
899 PBMEM(0xffe00400),
900 IRQ(4),
901};
902DEFINE_DEV(atmel_spi, 1);
903DEV_CLK(spi_clk, atmel_spi1, pba, 1);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700904
Haavard Skinnemoen9a596a62007-02-19 10:38:04 +0100905static void __init
Haavard Skinnemoen41d8ca42007-02-16 13:56:11 +0100906at32_spi_setup_slaves(unsigned int bus_num, struct spi_board_info *b,
907 unsigned int n, const u8 *pins)
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700908{
Haavard Skinnemoen41d8ca42007-02-16 13:56:11 +0100909 unsigned int pin, mode;
910
911 for (; n; n--, b++) {
912 b->bus_num = bus_num;
913 if (b->chip_select >= 4)
914 continue;
915 pin = (unsigned)b->controller_data;
916 if (!pin) {
917 pin = pins[b->chip_select];
918 b->controller_data = (void *)pin;
919 }
920 mode = AT32_GPIOF_OUTPUT;
921 if (!(b->mode & SPI_CS_HIGH))
922 mode |= AT32_GPIOF_HIGH;
923 at32_select_gpio(pin, mode);
924 }
925}
926
927struct platform_device *__init
928at32_add_device_spi(unsigned int id, struct spi_board_info *b, unsigned int n)
929{
930 /*
931 * Manage the chipselects as GPIOs, normally using the same pins
932 * the SPI controller expects; but boards can use other pins.
933 */
934 static u8 __initdata spi0_pins[] =
935 { GPIO_PIN_PA(3), GPIO_PIN_PA(4),
936 GPIO_PIN_PA(5), GPIO_PIN_PA(20), };
937 static u8 __initdata spi1_pins[] =
938 { GPIO_PIN_PB(2), GPIO_PIN_PB(3),
939 GPIO_PIN_PB(4), GPIO_PIN_PA(27), };
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700940 struct platform_device *pdev;
941
942 switch (id) {
943 case 0:
Haavard Skinnemoen3d60ee12007-01-10 20:20:02 +0100944 pdev = &atmel_spi0_device;
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +0100945 select_peripheral(PA(0), PERIPH_A, 0); /* MISO */
946 select_peripheral(PA(1), PERIPH_A, 0); /* MOSI */
947 select_peripheral(PA(2), PERIPH_A, 0); /* SCK */
Haavard Skinnemoen41d8ca42007-02-16 13:56:11 +0100948 at32_spi_setup_slaves(0, b, n, spi0_pins);
Haavard Skinnemoen3d60ee12007-01-10 20:20:02 +0100949 break;
950
951 case 1:
952 pdev = &atmel_spi1_device;
953 select_peripheral(PB(0), PERIPH_B, 0); /* MISO */
954 select_peripheral(PB(1), PERIPH_B, 0); /* MOSI */
955 select_peripheral(PB(5), PERIPH_B, 0); /* SCK */
Haavard Skinnemoen41d8ca42007-02-16 13:56:11 +0100956 at32_spi_setup_slaves(1, b, n, spi1_pins);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700957 break;
958
959 default:
960 return NULL;
961 }
962
Haavard Skinnemoen41d8ca42007-02-16 13:56:11 +0100963 spi_register_board_info(b, n);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700964 platform_device_register(pdev);
965 return pdev;
966}
967
968/* --------------------------------------------------------------------
969 * LCDC
970 * -------------------------------------------------------------------- */
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +0100971static struct atmel_lcdfb_info atmel_lcdfb0_data;
972static struct resource atmel_lcdfb0_resource[] = {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700973 {
974 .start = 0xff000000,
975 .end = 0xff000fff,
976 .flags = IORESOURCE_MEM,
977 },
978 IRQ(1),
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +0100979 {
980 /* Placeholder for pre-allocated fb memory */
981 .start = 0x00000000,
982 .end = 0x00000000,
983 .flags = 0,
984 },
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700985};
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +0100986DEFINE_DEV_DATA(atmel_lcdfb, 0);
987DEV_CLK(hck1, atmel_lcdfb0, hsb, 7);
988static struct clk atmel_lcdfb0_pixclk = {
989 .name = "lcdc_clk",
990 .dev = &atmel_lcdfb0_device.dev,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -0700991 .mode = genclk_mode,
992 .get_rate = genclk_get_rate,
993 .set_rate = genclk_set_rate,
994 .set_parent = genclk_set_parent,
995 .index = 7,
996};
997
998struct platform_device *__init
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +0100999at32_add_device_lcdc(unsigned int id, struct atmel_lcdfb_info *data,
1000 unsigned long fbmem_start, unsigned long fbmem_len)
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001001{
1002 struct platform_device *pdev;
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001003 struct atmel_lcdfb_info *info;
1004 struct fb_monspecs *monspecs;
1005 struct fb_videomode *modedb;
1006 unsigned int modedb_size;
1007
1008 /*
1009 * Do a deep copy of the fb data, monspecs and modedb. Make
1010 * sure all allocations are done before setting up the
1011 * portmux.
1012 */
1013 monspecs = kmemdup(data->default_monspecs,
1014 sizeof(struct fb_monspecs), GFP_KERNEL);
1015 if (!monspecs)
1016 return NULL;
1017
1018 modedb_size = sizeof(struct fb_videomode) * monspecs->modedb_len;
1019 modedb = kmemdup(monspecs->modedb, modedb_size, GFP_KERNEL);
1020 if (!modedb)
1021 goto err_dup_modedb;
1022 monspecs->modedb = modedb;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001023
1024 switch (id) {
1025 case 0:
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001026 pdev = &atmel_lcdfb0_device;
Haavard Skinnemoenc3e2a792006-12-04 13:46:52 +01001027 select_peripheral(PC(19), PERIPH_A, 0); /* CC */
1028 select_peripheral(PC(20), PERIPH_A, 0); /* HSYNC */
1029 select_peripheral(PC(21), PERIPH_A, 0); /* PCLK */
1030 select_peripheral(PC(22), PERIPH_A, 0); /* VSYNC */
1031 select_peripheral(PC(23), PERIPH_A, 0); /* DVAL */
1032 select_peripheral(PC(24), PERIPH_A, 0); /* MODE */
1033 select_peripheral(PC(25), PERIPH_A, 0); /* PWR */
1034 select_peripheral(PC(26), PERIPH_A, 0); /* DATA0 */
1035 select_peripheral(PC(27), PERIPH_A, 0); /* DATA1 */
1036 select_peripheral(PC(28), PERIPH_A, 0); /* DATA2 */
1037 select_peripheral(PC(29), PERIPH_A, 0); /* DATA3 */
1038 select_peripheral(PC(30), PERIPH_A, 0); /* DATA4 */
1039 select_peripheral(PC(31), PERIPH_A, 0); /* DATA5 */
1040 select_peripheral(PD(0), PERIPH_A, 0); /* DATA6 */
1041 select_peripheral(PD(1), PERIPH_A, 0); /* DATA7 */
1042 select_peripheral(PD(2), PERIPH_A, 0); /* DATA8 */
1043 select_peripheral(PD(3), PERIPH_A, 0); /* DATA9 */
1044 select_peripheral(PD(4), PERIPH_A, 0); /* DATA10 */
1045 select_peripheral(PD(5), PERIPH_A, 0); /* DATA11 */
1046 select_peripheral(PD(6), PERIPH_A, 0); /* DATA12 */
1047 select_peripheral(PD(7), PERIPH_A, 0); /* DATA13 */
1048 select_peripheral(PD(8), PERIPH_A, 0); /* DATA14 */
1049 select_peripheral(PD(9), PERIPH_A, 0); /* DATA15 */
1050 select_peripheral(PD(10), PERIPH_A, 0); /* DATA16 */
1051 select_peripheral(PD(11), PERIPH_A, 0); /* DATA17 */
1052 select_peripheral(PD(12), PERIPH_A, 0); /* DATA18 */
1053 select_peripheral(PD(13), PERIPH_A, 0); /* DATA19 */
1054 select_peripheral(PD(14), PERIPH_A, 0); /* DATA20 */
1055 select_peripheral(PD(15), PERIPH_A, 0); /* DATA21 */
1056 select_peripheral(PD(16), PERIPH_A, 0); /* DATA22 */
1057 select_peripheral(PD(17), PERIPH_A, 0); /* DATA23 */
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001058
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001059 clk_set_parent(&atmel_lcdfb0_pixclk, &pll0);
1060 clk_set_rate(&atmel_lcdfb0_pixclk, clk_get_rate(&pll0));
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001061 break;
1062
1063 default:
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001064 goto err_invalid_id;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001065 }
1066
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001067 if (fbmem_len) {
1068 pdev->resource[2].start = fbmem_start;
1069 pdev->resource[2].end = fbmem_start + fbmem_len - 1;
1070 pdev->resource[2].flags = IORESOURCE_MEM;
1071 }
1072
1073 info = pdev->dev.platform_data;
1074 memcpy(info, data, sizeof(struct atmel_lcdfb_info));
1075 info->default_monspecs = monspecs;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001076
1077 platform_device_register(pdev);
1078 return pdev;
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001079
1080err_invalid_id:
1081 kfree(modedb);
1082err_dup_modedb:
1083 kfree(monspecs);
1084 return NULL;
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001085}
1086
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +01001087/* --------------------------------------------------------------------
Hans-Christian Egtvedt9cf6cf52007-07-06 14:31:55 +02001088 * SSC
1089 * -------------------------------------------------------------------- */
1090static struct resource ssc0_resource[] = {
1091 PBMEM(0xffe01c00),
1092 IRQ(10),
1093};
1094DEFINE_DEV(ssc, 0);
1095DEV_CLK(pclk, ssc0, pba, 7);
1096
1097static struct resource ssc1_resource[] = {
1098 PBMEM(0xffe02000),
1099 IRQ(11),
1100};
1101DEFINE_DEV(ssc, 1);
1102DEV_CLK(pclk, ssc1, pba, 8);
1103
1104static struct resource ssc2_resource[] = {
1105 PBMEM(0xffe02400),
1106 IRQ(12),
1107};
1108DEFINE_DEV(ssc, 2);
1109DEV_CLK(pclk, ssc2, pba, 9);
1110
1111struct platform_device *__init
1112at32_add_device_ssc(unsigned int id, unsigned int flags)
1113{
1114 struct platform_device *pdev;
1115
1116 switch (id) {
1117 case 0:
1118 pdev = &ssc0_device;
1119 if (flags & ATMEL_SSC_RF)
1120 select_peripheral(PA(21), PERIPH_A, 0); /* RF */
1121 if (flags & ATMEL_SSC_RK)
1122 select_peripheral(PA(22), PERIPH_A, 0); /* RK */
1123 if (flags & ATMEL_SSC_TK)
1124 select_peripheral(PA(23), PERIPH_A, 0); /* TK */
1125 if (flags & ATMEL_SSC_TF)
1126 select_peripheral(PA(24), PERIPH_A, 0); /* TF */
1127 if (flags & ATMEL_SSC_TD)
1128 select_peripheral(PA(25), PERIPH_A, 0); /* TD */
1129 if (flags & ATMEL_SSC_RD)
1130 select_peripheral(PA(26), PERIPH_A, 0); /* RD */
1131 break;
1132 case 1:
1133 pdev = &ssc1_device;
1134 if (flags & ATMEL_SSC_RF)
1135 select_peripheral(PA(0), PERIPH_B, 0); /* RF */
1136 if (flags & ATMEL_SSC_RK)
1137 select_peripheral(PA(1), PERIPH_B, 0); /* RK */
1138 if (flags & ATMEL_SSC_TK)
1139 select_peripheral(PA(2), PERIPH_B, 0); /* TK */
1140 if (flags & ATMEL_SSC_TF)
1141 select_peripheral(PA(3), PERIPH_B, 0); /* TF */
1142 if (flags & ATMEL_SSC_TD)
1143 select_peripheral(PA(4), PERIPH_B, 0); /* TD */
1144 if (flags & ATMEL_SSC_RD)
1145 select_peripheral(PA(5), PERIPH_B, 0); /* RD */
1146 break;
1147 case 2:
1148 pdev = &ssc2_device;
1149 if (flags & ATMEL_SSC_TD)
1150 select_peripheral(PB(13), PERIPH_A, 0); /* TD */
1151 if (flags & ATMEL_SSC_RD)
1152 select_peripheral(PB(14), PERIPH_A, 0); /* RD */
1153 if (flags & ATMEL_SSC_TK)
1154 select_peripheral(PB(15), PERIPH_A, 0); /* TK */
1155 if (flags & ATMEL_SSC_TF)
1156 select_peripheral(PB(16), PERIPH_A, 0); /* TF */
1157 if (flags & ATMEL_SSC_RF)
1158 select_peripheral(PB(17), PERIPH_A, 0); /* RF */
1159 if (flags & ATMEL_SSC_RK)
1160 select_peripheral(PB(18), PERIPH_A, 0); /* RK */
1161 break;
1162 default:
1163 return NULL;
1164 }
1165
1166 platform_device_register(pdev);
1167 return pdev;
1168}
1169
1170/* --------------------------------------------------------------------
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +01001171 * GCLK
1172 * -------------------------------------------------------------------- */
1173static struct clk gclk0 = {
1174 .name = "gclk0",
1175 .mode = genclk_mode,
1176 .get_rate = genclk_get_rate,
1177 .set_rate = genclk_set_rate,
1178 .set_parent = genclk_set_parent,
1179 .index = 0,
1180};
1181static struct clk gclk1 = {
1182 .name = "gclk1",
1183 .mode = genclk_mode,
1184 .get_rate = genclk_get_rate,
1185 .set_rate = genclk_set_rate,
1186 .set_parent = genclk_set_parent,
1187 .index = 1,
1188};
1189static struct clk gclk2 = {
1190 .name = "gclk2",
1191 .mode = genclk_mode,
1192 .get_rate = genclk_get_rate,
1193 .set_rate = genclk_set_rate,
1194 .set_parent = genclk_set_parent,
1195 .index = 2,
1196};
1197static struct clk gclk3 = {
1198 .name = "gclk3",
1199 .mode = genclk_mode,
1200 .get_rate = genclk_get_rate,
1201 .set_rate = genclk_set_rate,
1202 .set_parent = genclk_set_parent,
1203 .index = 3,
1204};
1205static struct clk gclk4 = {
1206 .name = "gclk4",
1207 .mode = genclk_mode,
1208 .get_rate = genclk_get_rate,
1209 .set_rate = genclk_set_rate,
1210 .set_parent = genclk_set_parent,
1211 .index = 4,
1212};
1213
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001214struct clk *at32_clock_list[] = {
1215 &osc32k,
1216 &osc0,
1217 &osc1,
1218 &pll0,
1219 &pll1,
1220 &cpu_clk,
1221 &hsb_clk,
1222 &pba_clk,
1223 &pbb_clk,
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +02001224 &at32_pm_pclk,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001225 &at32_intc0_pclk,
Haavard Skinnemoen9c8f8e72007-02-01 16:34:10 +01001226 &hmatrix_clk,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001227 &ebi_clk,
1228 &hramc_clk,
Haavard Skinnemoenbc157b72006-09-25 23:32:16 -07001229 &smc0_pclk,
1230 &smc0_mck,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001231 &pdc_hclk,
1232 &pdc_pclk,
1233 &pico_clk,
1234 &pio0_mck,
1235 &pio1_mck,
1236 &pio2_mck,
1237 &pio3_mck,
Haavard Skinnemoen7f9f4672007-01-30 11:16:16 +01001238 &pio4_mck,
Hans-Christian Egtvedt77609892007-03-12 18:15:16 +01001239 &at32_systc0_pclk,
Haavard Skinnemoen1e8ea802006-10-04 16:02:03 +02001240 &atmel_usart0_usart,
1241 &atmel_usart1_usart,
1242 &atmel_usart2_usart,
1243 &atmel_usart3_usart,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001244 &macb0_hclk,
1245 &macb0_pclk,
Haavard Skinnemoencfcb3a82006-10-30 09:23:12 +01001246 &macb1_hclk,
1247 &macb1_pclk,
Haavard Skinnemoen3d60ee12007-01-10 20:20:02 +01001248 &atmel_spi0_spi_clk,
1249 &atmel_spi1_spi_clk,
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001250 &atmel_lcdfb0_hck1,
1251 &atmel_lcdfb0_pixclk,
Hans-Christian Egtvedt9cf6cf52007-07-06 14:31:55 +02001252 &ssc0_pclk,
1253 &ssc1_pclk,
1254 &ssc2_pclk,
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +01001255 &gclk0,
1256 &gclk1,
1257 &gclk2,
1258 &gclk3,
1259 &gclk4,
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001260};
1261unsigned int at32_nr_clocks = ARRAY_SIZE(at32_clock_list);
1262
1263void __init at32_portmux_init(void)
1264{
1265 at32_init_pio(&pio0_device);
1266 at32_init_pio(&pio1_device);
1267 at32_init_pio(&pio2_device);
1268 at32_init_pio(&pio3_device);
Haavard Skinnemoen7f9f4672007-01-30 11:16:16 +01001269 at32_init_pio(&pio4_device);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001270}
1271
1272void __init at32_clock_init(void)
1273{
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001274 u32 cpu_mask = 0, hsb_mask = 0, pba_mask = 0, pbb_mask = 0;
1275 int i;
1276
Hans-Christian Egtvedt9e58e182007-06-04 16:10:57 +02001277 if (pm_readl(MCCTRL) & PM_BIT(PLLSEL)) {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001278 main_clock = &pll0;
Hans-Christian Egtvedt9e58e182007-06-04 16:10:57 +02001279 cpu_clk.parent = &pll0;
1280 } else {
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001281 main_clock = &osc0;
Hans-Christian Egtvedt9e58e182007-06-04 16:10:57 +02001282 cpu_clk.parent = &osc0;
1283 }
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001284
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +02001285 if (pm_readl(PLL0) & PM_BIT(PLLOSC))
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001286 pll0.parent = &osc1;
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +02001287 if (pm_readl(PLL1) & PM_BIT(PLLOSC))
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001288 pll1.parent = &osc1;
1289
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +01001290 genclk_init_parent(&gclk0);
1291 genclk_init_parent(&gclk1);
1292 genclk_init_parent(&gclk2);
1293 genclk_init_parent(&gclk3);
1294 genclk_init_parent(&gclk4);
Haavard Skinnemoend0a2b7a2007-03-21 18:08:49 +01001295 genclk_init_parent(&atmel_lcdfb0_pixclk);
Haavard Skinnemoen7a5fe232007-02-16 13:14:33 +01001296
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001297 /*
1298 * Turn on all clocks that have at least one user already, and
1299 * turn off everything else. We only do this for module
1300 * clocks, and even though it isn't particularly pretty to
1301 * check the address of the mode function, it should do the
1302 * trick...
1303 */
1304 for (i = 0; i < ARRAY_SIZE(at32_clock_list); i++) {
1305 struct clk *clk = at32_clock_list[i];
1306
Haavard Skinnemoen188ff652007-03-14 13:23:44 +01001307 if (clk->users == 0)
1308 continue;
1309
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001310 if (clk->mode == &cpu_clk_mode)
1311 cpu_mask |= 1 << clk->index;
1312 else if (clk->mode == &hsb_clk_mode)
1313 hsb_mask |= 1 << clk->index;
1314 else if (clk->mode == &pba_clk_mode)
1315 pba_mask |= 1 << clk->index;
1316 else if (clk->mode == &pbb_clk_mode)
1317 pbb_mask |= 1 << clk->index;
1318 }
1319
Haavard Skinnemoen7a5b8052007-06-04 12:58:30 +02001320 pm_writel(CPU_MASK, cpu_mask);
1321 pm_writel(HSB_MASK, hsb_mask);
1322 pm_writel(PBA_MASK, pba_mask);
1323 pm_writel(PBB_MASK, pbb_mask);
Haavard Skinnemoen5f97f7f2006-09-25 23:32:13 -07001324}