aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-stmp3xxx
diff options
context:
space:
mode:
authorVegard Nossum <vegard.nossum@gmail.com>2009-06-15 09:50:49 -0400
committerVegard Nossum <vegard.nossum@gmail.com>2009-06-15 09:50:49 -0400
commit722f2a6c87f34ee0fd0130a8cf45f81e0705594a (patch)
tree50b054df34d2731eb0ba0cf1a6c27e43e7eed428 /arch/arm/plat-stmp3xxx
parent7a0aeb14e18ad59394bd9bbc6e57fb345819e748 (diff)
parent45e3e1935e2857c54783291107d33323b3ef33c8 (diff)
Merge commit 'linus/master' into HEAD
Conflicts: MAINTAINERS Signed-off-by: Vegard Nossum <vegard.nossum@gmail.com>
Diffstat (limited to 'arch/arm/plat-stmp3xxx')
-rw-r--r--arch/arm/plat-stmp3xxx/Kconfig37
-rw-r--r--arch/arm/plat-stmp3xxx/Makefile5
-rw-r--r--arch/arm/plat-stmp3xxx/clock.c1135
-rw-r--r--arch/arm/plat-stmp3xxx/clock.h61
-rw-r--r--arch/arm/plat-stmp3xxx/core.c128
-rw-r--r--arch/arm/plat-stmp3xxx/devices.c389
-rw-r--r--arch/arm/plat-stmp3xxx/dma.c463
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/clkdev.h18
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/cputype.h33
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/debug-macro.S42
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/dma.h153
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/gpio.h28
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/gpmi.h12
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/hardware.h32
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/io.h25
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/memory.h22
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/mmc.h14
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/pinmux.h157
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/pins.h30
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/platform.h68
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h54
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/system.h49
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/timex.h20
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/uncompress.h53
-rw-r--r--arch/arm/plat-stmp3xxx/include/mach/vmalloc.h12
-rw-r--r--arch/arm/plat-stmp3xxx/irq.c51
-rw-r--r--arch/arm/plat-stmp3xxx/pinmux.c552
-rw-r--r--arch/arm/plat-stmp3xxx/timer.c189
28 files changed, 3832 insertions, 0 deletions
diff --git a/arch/arm/plat-stmp3xxx/Kconfig b/arch/arm/plat-stmp3xxx/Kconfig
new file mode 100644
index 000000000000..2cf37c35951b
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/Kconfig
@@ -0,0 +1,37 @@
1if ARCH_STMP3XXX
2
3menu "Freescale STMP3xxx implementations"
4
5choice
6 prompt "Select STMP3xxx chip family"
7
8config ARCH_STMP37XX
9 bool "Freescale SMTP37xx"
10 select CPU_ARM926T
11 ---help---
12 STMP37xx refers to 3700 through 3769 chips
13
14config ARCH_STMP378X
15 bool "Freescale STMP378x"
16 select CPU_ARM926T
17 ---help---
18 STMP378x refers to 3780 through 3789 chips
19
20endchoice
21
22choice
23 prompt "Select STMP3xxx board type"
24
25config MACH_STMP37XX
26 depends on ARCH_STMP37XX
27 bool "Freescale STMP37xx development board"
28
29config MACH_STMP378X
30 depends on ARCH_STMP378X
31 bool "Freescale STMP378x development board"
32
33endchoice
34
35endmenu
36
37endif
diff --git a/arch/arm/plat-stmp3xxx/Makefile b/arch/arm/plat-stmp3xxx/Makefile
new file mode 100644
index 000000000000..31dd518f37a5
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/Makefile
@@ -0,0 +1,5 @@
1#
2# Makefile for the linux kernel.
3#
4# Object file lists.
5obj-y += core.o timer.o irq.o dma.o clock.o pinmux.o devices.o
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c
new file mode 100644
index 000000000000..5d2f19a09e44
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/clock.c
@@ -0,0 +1,1135 @@
1/*
2 * Clock manipulation routines for Freescale STMP37XX/STMP378X
3 *
4 * Author: Vitaly Wool <vital@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#define DEBUG
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/clk.h>
23#include <linux/spinlock.h>
24#include <linux/errno.h>
25#include <linux/err.h>
26#include <linux/delay.h>
27#include <linux/io.h>
28
29#include <asm/mach-types.h>
30#include <asm/clkdev.h>
31#include <mach/platform.h>
32#include <mach/regs-clkctrl.h>
33
34#include "clock.h"
35
36static DEFINE_SPINLOCK(clocks_lock);
37
38static struct clk osc_24M;
39static struct clk pll_clk;
40static struct clk cpu_clk;
41static struct clk hclk;
42
43static int propagate_rate(struct clk *);
44
45static inline int clk_is_busy(struct clk *clk)
46{
47 return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit);
48}
49
50static inline int clk_good(struct clk *clk)
51{
52 return clk && !IS_ERR(clk) && clk->ops;
53}
54
55static int std_clk_enable(struct clk *clk)
56{
57 if (clk->enable_reg) {
58 u32 clk_reg = __raw_readl(clk->enable_reg);
59 if (clk->enable_negate)
60 clk_reg &= ~(1 << clk->enable_shift);
61 else
62 clk_reg |= (1 << clk->enable_shift);
63 __raw_writel(clk_reg, clk->enable_reg);
64 if (clk->enable_wait)
65 udelay(clk->enable_wait);
66 return 0;
67 } else
68 return -EINVAL;
69}
70
71static int std_clk_disable(struct clk *clk)
72{
73 if (clk->enable_reg) {
74 u32 clk_reg = __raw_readl(clk->enable_reg);
75 if (clk->enable_negate)
76 clk_reg |= (1 << clk->enable_shift);
77 else
78 clk_reg &= ~(1 << clk->enable_shift);
79 __raw_writel(clk_reg, clk->enable_reg);
80 return 0;
81 } else
82 return -EINVAL;
83}
84
85static int io_set_rate(struct clk *clk, u32 rate)
86{
87 u32 reg_frac, clkctrl_frac;
88 int i, ret = 0, mask = 0x1f;
89
90 clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate;
91
92 if (clkctrl_frac < 18 || clkctrl_frac > 35) {
93 ret = -EINVAL;
94 goto out;
95 }
96
97 reg_frac = __raw_readl(clk->scale_reg);
98 reg_frac &= ~(mask << clk->scale_shift);
99 __raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift),
100 clk->scale_reg);
101 if (clk->busy_reg) {
102 for (i = 10000; i; i--)
103 if (!clk_is_busy(clk))
104 break;
105 if (!i)
106 ret = -ETIMEDOUT;
107 else
108 ret = 0;
109 }
110out:
111 return ret;
112}
113
114static long io_get_rate(struct clk *clk)
115{
116 long rate = clk->parent->rate * 18;
117 int mask = 0x1f;
118
119 rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
120 clk->rate = rate;
121
122 return rate;
123}
124
125static long per_get_rate(struct clk *clk)
126{
127 long rate = clk->parent->rate;
128 long div;
129 const int mask = 0xff;
130
131 if (clk->enable_reg &&
132 !(__raw_readl(clk->enable_reg) & clk->enable_shift))
133 clk->rate = 0;
134 else {
135 div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
136 if (div)
137 rate /= div;
138 clk->rate = rate;
139 }
140
141 return clk->rate;
142}
143
144static int per_set_rate(struct clk *clk, u32 rate)
145{
146 int ret = -EINVAL;
147 int div = (clk->parent->rate + rate - 1) / rate;
148 u32 reg_frac;
149 const int mask = 0xff;
150 int try = 10;
151 int i = -1;
152
153 if (div == 0 || div > mask)
154 goto out;
155
156 reg_frac = __raw_readl(clk->scale_reg);
157 reg_frac &= ~(mask << clk->scale_shift);
158
159 while (try--) {
160 __raw_writel(reg_frac | (div << clk->scale_shift),
161 clk->scale_reg);
162
163 if (clk->busy_reg) {
164 for (i = 10000; i; i--)
165 if (!clk_is_busy(clk))
166 break;
167 }
168 if (i)
169 break;
170 }
171
172 if (!i)
173 ret = -ETIMEDOUT;
174 else
175 ret = 0;
176
177out:
178 if (ret != 0)
179 printk(KERN_ERR "%s: error %d\n", __func__, ret);
180 return ret;
181}
182
183static long lcdif_get_rate(struct clk *clk)
184{
185 long rate = clk->parent->rate;
186 long div;
187 const int mask = 0xff;
188
189 div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
190 if (div) {
191 rate /= div;
192 div = (__raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC) &
193 BM_CLKCTRL_FRAC_PIXFRAC) >> BP_CLKCTRL_FRAC_PIXFRAC;
194 rate /= div;
195 }
196 clk->rate = rate;
197
198 return rate;
199}
200
201static int lcdif_set_rate(struct clk *clk, u32 rate)
202{
203 int ret = 0;
204 /*
205 * On 3700, we can get most timings exact by modifying ref_pix
206 * and the divider, but keeping the phase timings at 1 (2
207 * phases per cycle).
208 *
209 * ref_pix can be between 480e6*18/35=246.9MHz and 480e6*18/18=480MHz,
210 * which is between 18/(18*480e6)=2.084ns and 35/(18*480e6)=4.050ns.
211 *
212 * ns_cycle >= 2*18e3/(18*480) = 25/6
213 * ns_cycle <= 2*35e3/(18*480) = 875/108
214 *
215 * Multiply the ns_cycle by 'div' to lengthen it until it fits the
216 * bounds. This is the divider we'll use after ref_pix.
217 *
218 * 6 * ns_cycle >= 25 * div
219 * 108 * ns_cycle <= 875 * div
220 */
221 u32 ns_cycle = 1000000 / rate;
222 u32 div, reg_val;
223 u32 lowest_result = (u32) -1;
224 u32 lowest_div = 0, lowest_fracdiv = 0;
225
226 for (div = 1; div < 256; ++div) {
227 u32 fracdiv;
228 u32 ps_result;
229 int lower_bound = 6 * ns_cycle >= 25 * div;
230 int upper_bound = 108 * ns_cycle <= 875 * div;
231 if (!lower_bound)
232 break;
233 if (!upper_bound)
234 continue;
235 /*
236 * Found a matching div. Calculate fractional divider needed,
237 * rounded up.
238 */
239 fracdiv = ((clk->parent->rate / 1000 * 18 / 2) *
240 ns_cycle + 1000 * div - 1) /
241 (1000 * div);
242 if (fracdiv < 18 || fracdiv > 35) {
243 ret = -EINVAL;
244 goto out;
245 }
246 /* Calculate the actual cycle time this results in */
247 ps_result = 6250 * div * fracdiv / 27;
248
249 /* Use the fastest result that doesn't break ns_cycle */
250 if (ps_result <= lowest_result) {
251 lowest_result = ps_result;
252 lowest_div = div;
253 lowest_fracdiv = fracdiv;
254 }
255 }
256
257 if (div >= 256 || lowest_result == (u32) -1) {
258 ret = -EINVAL;
259 goto out;
260 }
261 pr_debug("Programming PFD=%u,DIV=%u ref_pix=%uMHz "
262 "PIXCLK=%uMHz cycle=%u.%03uns\n",
263 lowest_fracdiv, lowest_div,
264 480*18/lowest_fracdiv, 480*18/lowest_fracdiv/lowest_div,
265 lowest_result / 1000, lowest_result % 1000);
266
267 /* Program ref_pix phase fractional divider */
268 reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
269 reg_val &= ~BM_CLKCTRL_FRAC_PIXFRAC;
270 reg_val |= BF(lowest_fracdiv, CLKCTRL_FRAC_PIXFRAC);
271 __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
272
273 /* Ungate PFD */
274 stmp3xxx_clearl(BM_CLKCTRL_FRAC_CLKGATEPIX,
275 REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC);
276
277 /* Program pix divider */
278 reg_val = __raw_readl(clk->scale_reg);
279 reg_val &= ~(BM_CLKCTRL_PIX_DIV | BM_CLKCTRL_PIX_CLKGATE);
280 reg_val |= BF(lowest_div, CLKCTRL_PIX_DIV);
281 __raw_writel(reg_val, clk->scale_reg);
282
283 /* Wait for divider update */
284 if (clk->busy_reg) {
285 int i;
286 for (i = 10000; i; i--)
287 if (!clk_is_busy(clk))
288 break;
289 if (!i) {
290 ret = -ETIMEDOUT;
291 goto out;
292 }
293 }
294
295 /* Switch to ref_pix source */
296 reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
297 reg_val &= ~BM_CLKCTRL_CLKSEQ_BYPASS_PIX;
298 __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ);
299
300out:
301 return ret;
302}
303
304
305static int cpu_set_rate(struct clk *clk, u32 rate)
306{
307 u32 reg_val;
308
309 if (rate < 24000)
310 return -EINVAL;
311 else if (rate == 24000) {
312 /* switch to the 24M source */
313 clk_set_parent(clk, &osc_24M);
314 } else {
315 int i;
316 u32 clkctrl_cpu = 1;
317 u32 c = clkctrl_cpu;
318 u32 clkctrl_frac = 1;
319 u32 val;
320 for ( ; c < 0x40; c++) {
321 u32 f = (pll_clk.rate*18/c + rate/2) / rate;
322 int s1, s2;
323
324 if (f < 18 || f > 35)
325 continue;
326 s1 = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - rate;
327 s2 = pll_clk.rate*18/c/f - rate;
328 pr_debug("%s: s1 %d, s2 %d\n", __func__, s1, s2);
329 if (abs(s1) > abs(s2)) {
330 clkctrl_cpu = c;
331 clkctrl_frac = f;
332 }
333 if (s2 == 0)
334 break;
335 };
336 pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
337 clkctrl_cpu, clkctrl_frac);
338 if (c == 0x40) {
339 int d = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu -
340 rate;
341 if (abs(d) > 100 ||
342 clkctrl_frac < 18 || clkctrl_frac > 35)
343 return -EINVAL;
344 }
345
346 /* 4.6.2 */
347 val = __raw_readl(clk->scale_reg);
348 val &= ~(0x3f << clk->scale_shift);
349 val |= clkctrl_frac;
350 clk_set_parent(clk, &osc_24M);
351 udelay(10);
352 __raw_writel(val, clk->scale_reg);
353 /* ungate */
354 __raw_writel(1<<7, clk->scale_reg + 8);
355 /* write clkctrl_cpu */
356 clk->saved_div = clkctrl_cpu;
357
358 reg_val = __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
359 reg_val &= ~0x3F;
360 reg_val |= clkctrl_cpu;
361 __raw_writel(reg_val, REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
362
363 for (i = 10000; i; i--)
364 if (!clk_is_busy(clk))
365 break;
366 if (!i) {
367 printk(KERN_ERR "couldn't set up CPU divisor\n");
368 return -ETIMEDOUT;
369 }
370 clk_set_parent(clk, &pll_clk);
371 clk->saved_div = 0;
372 udelay(10);
373 }
374 return 0;
375}
376
377static long cpu_get_rate(struct clk *clk)
378{
379 long rate = clk->parent->rate * 18;
380
381 rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
382 rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU) & 0x3f;
383 rate = ((rate + 9) / 10) * 10;
384 clk->rate = rate;
385
386 return rate;
387}
388
389static long cpu_round_rate(struct clk *clk, u32 rate)
390{
391 unsigned long r = 0;
392
393 if (rate <= 24000)
394 r = 24000;
395 else {
396 u32 clkctrl_cpu = 1;
397 u32 clkctrl_frac;
398 do {
399 clkctrl_frac =
400 (pll_clk.rate*18 / clkctrl_cpu + rate/2) / rate;
401 if (clkctrl_frac > 35)
402 continue;
403 if (pll_clk.rate*18 / clkctrl_frac / clkctrl_cpu/10 ==
404 rate / 10)
405 break;
406 } while (pll_clk.rate / 2 >= clkctrl_cpu++ * rate);
407 if (pll_clk.rate / 2 < (clkctrl_cpu - 1) * rate)
408 clkctrl_cpu--;
409 pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
410 clkctrl_cpu, clkctrl_frac);
411 if (clkctrl_frac < 18)
412 clkctrl_frac = 18;
413 if (clkctrl_frac > 35)
414 clkctrl_frac = 35;
415
416 r = pll_clk.rate * 18;
417 r /= clkctrl_frac;
418 r /= clkctrl_cpu;
419 r = 10 * ((r + 9) / 10);
420 }
421 return r;
422}
423
424static long emi_get_rate(struct clk *clk)
425{
426 long rate = clk->parent->rate * 18;
427
428 rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
429 rate /= __raw_readl(REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI) & 0x3f;
430 clk->rate = rate;
431
432 return rate;
433}
434
435static int clkseq_set_parent(struct clk *clk, struct clk *parent)
436{
437 int ret = -EINVAL;
438 int shift = 8;
439
440 /* bypass? */
441 if (parent == &osc_24M)
442 shift = 4;
443
444 if (clk->bypass_reg) {
445#ifdef CONFIG_ARCH_STMP378X
446 u32 hbus_val, cpu_val;
447
448 if (clk == &cpu_clk && shift == 4) {
449 hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
450 HW_CLKCTRL_HBUS);
451 cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
452 HW_CLKCTRL_CPU);
453
454 hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
455 BM_CLKCTRL_HBUS_DIV);
456 clk->saved_div = cpu_val & BM_CLKCTRL_CPU_DIV_CPU;
457 cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
458 cpu_val |= 1;
459
460 if (machine_is_stmp378x()) {
461 __raw_writel(hbus_val,
462 REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
463 __raw_writel(cpu_val,
464 REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
465 hclk.rate = 0;
466 }
467 } else if (clk == &cpu_clk && shift == 8) {
468 hbus_val = __raw_readl(REGS_CLKCTRL_BASE +
469 HW_CLKCTRL_HBUS);
470 cpu_val = __raw_readl(REGS_CLKCTRL_BASE +
471 HW_CLKCTRL_CPU);
472 hbus_val &= ~(BM_CLKCTRL_HBUS_DIV_FRAC_EN |
473 BM_CLKCTRL_HBUS_DIV);
474 hbus_val |= 2;
475 cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
476 if (clk->saved_div)
477 cpu_val |= clk->saved_div;
478 else
479 cpu_val |= 2;
480
481 if (machine_is_stmp378x()) {
482 __raw_writel(hbus_val,
483 REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
484 __raw_writel(cpu_val,
485 REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU);
486 hclk.rate = 0;
487 }
488 }
489#endif
490 __raw_writel(1 << clk->bypass_shift, clk->bypass_reg + shift);
491
492 ret = 0;
493 }
494
495 return ret;
496}
497
498static int hbus_set_rate(struct clk *clk, u32 rate)
499{
500 u8 div = 0;
501 int is_frac = 0;
502 u32 clkctrl_hbus;
503 struct clk *parent = clk->parent;
504
505 pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
506 parent->rate);
507
508 if (rate > parent->rate)
509 return -EINVAL;
510
511 if (((parent->rate + rate/2) / rate) * rate != parent->rate &&
512 parent->rate / rate < 32) {
513 pr_debug("%s: switching to fractional mode\n", __func__);
514 is_frac = 1;
515 }
516
517 if (is_frac)
518 div = (32 * rate + parent->rate / 2) / parent->rate;
519 else
520 div = (parent->rate + rate - 1) / rate;
521 pr_debug("%s: div calculated is %d\n", __func__, div);
522 if (!div || div > 0x1f)
523 return -EINVAL;
524
525 clk_set_parent(&cpu_clk, &osc_24M);
526 udelay(10);
527 clkctrl_hbus = __raw_readl(clk->scale_reg);
528 clkctrl_hbus &= ~0x3f;
529 clkctrl_hbus |= div;
530 clkctrl_hbus |= (is_frac << 5);
531
532 __raw_writel(clkctrl_hbus, clk->scale_reg);
533 if (clk->busy_reg) {
534 int i;
535 for (i = 10000; i; i--)
536 if (!clk_is_busy(clk))
537 break;
538 if (!i) {
539 printk(KERN_ERR "couldn't set up CPU divisor\n");
540 return -ETIMEDOUT;
541 }
542 }
543 clk_set_parent(&cpu_clk, &pll_clk);
544 __raw_writel(clkctrl_hbus, clk->scale_reg);
545 udelay(10);
546 return 0;
547}
548
549static long hbus_get_rate(struct clk *clk)
550{
551 long rate = clk->parent->rate;
552
553 if (__raw_readl(clk->scale_reg) & 0x20) {
554 rate *= __raw_readl(clk->scale_reg) & 0x1f;
555 rate /= 32;
556 } else
557 rate /= __raw_readl(clk->scale_reg) & 0x1f;
558 clk->rate = rate;
559
560 return rate;
561}
562
563static int xbus_set_rate(struct clk *clk, u32 rate)
564{
565 u16 div = 0;
566 u32 clkctrl_xbus;
567
568 pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
569 clk->parent->rate);
570
571 div = (clk->parent->rate + rate - 1) / rate;
572 pr_debug("%s: div calculated is %d\n", __func__, div);
573 if (!div || div > 0x3ff)
574 return -EINVAL;
575
576 clkctrl_xbus = __raw_readl(clk->scale_reg);
577 clkctrl_xbus &= ~0x3ff;
578 clkctrl_xbus |= div;
579 __raw_writel(clkctrl_xbus, clk->scale_reg);
580 if (clk->busy_reg) {
581 int i;
582 for (i = 10000; i; i--)
583 if (!clk_is_busy(clk))
584 break;
585 if (!i) {
586 printk(KERN_ERR "couldn't set up xbus divisor\n");
587 return -ETIMEDOUT;
588 }
589 }
590 return 0;
591}
592
593static long xbus_get_rate(struct clk *clk)
594{
595 long rate = clk->parent->rate;
596
597 rate /= __raw_readl(clk->scale_reg) & 0x3ff;
598 clk->rate = rate;
599
600 return rate;
601}
602
603
604/* Clock ops */
605
606static struct clk_ops std_ops = {
607 .enable = std_clk_enable,
608 .disable = std_clk_disable,
609 .get_rate = per_get_rate,
610 .set_rate = per_set_rate,
611 .set_parent = clkseq_set_parent,
612};
613
614static struct clk_ops min_ops = {
615 .enable = std_clk_enable,
616 .disable = std_clk_disable,
617};
618
619static struct clk_ops cpu_ops = {
620 .enable = std_clk_enable,
621 .disable = std_clk_disable,
622 .get_rate = cpu_get_rate,
623 .set_rate = cpu_set_rate,
624 .round_rate = cpu_round_rate,
625 .set_parent = clkseq_set_parent,
626};
627
628static struct clk_ops io_ops = {
629 .enable = std_clk_enable,
630 .disable = std_clk_disable,
631 .get_rate = io_get_rate,
632 .set_rate = io_set_rate,
633};
634
635static struct clk_ops hbus_ops = {
636 .get_rate = hbus_get_rate,
637 .set_rate = hbus_set_rate,
638};
639
640static struct clk_ops xbus_ops = {
641 .get_rate = xbus_get_rate,
642 .set_rate = xbus_set_rate,
643};
644
645static struct clk_ops lcdif_ops = {
646 .enable = std_clk_enable,
647 .disable = std_clk_disable,
648 .get_rate = lcdif_get_rate,
649 .set_rate = lcdif_set_rate,
650 .set_parent = clkseq_set_parent,
651};
652
653static struct clk_ops emi_ops = {
654 .get_rate = emi_get_rate,
655};
656
657/* List of on-chip clocks */
658
659static struct clk osc_24M = {
660 .flags = FIXED_RATE | ENABLED,
661 .rate = 24000,
662};
663
664static struct clk pll_clk = {
665 .parent = &osc_24M,
666 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
667 .enable_shift = 16,
668 .enable_wait = 10,
669 .flags = FIXED_RATE | ENABLED,
670 .rate = 480000,
671 .ops = &min_ops,
672};
673
674static struct clk cpu_clk = {
675 .parent = &pll_clk,
676 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
677 .scale_shift = 0,
678 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
679 .bypass_shift = 7,
680 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CPU,
681 .busy_bit = 28,
682 .flags = RATE_PROPAGATES | ENABLED,
683 .ops = &cpu_ops,
684};
685
686static struct clk io_clk = {
687 .parent = &pll_clk,
688 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
689 .enable_shift = 31,
690 .enable_negate = 1,
691 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
692 .scale_shift = 24,
693 .flags = RATE_PROPAGATES | ENABLED,
694 .ops = &io_ops,
695};
696
697static struct clk hclk = {
698 .parent = &cpu_clk,
699 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
700 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
701 .bypass_shift = 7,
702 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS,
703 .busy_bit = 29,
704 .flags = RATE_PROPAGATES | ENABLED,
705 .ops = &hbus_ops,
706};
707
708static struct clk xclk = {
709 .parent = &osc_24M,
710 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
711 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XBUS,
712 .busy_bit = 31,
713 .flags = RATE_PROPAGATES | ENABLED,
714 .ops = &xbus_ops,
715};
716
717static struct clk uart_clk = {
718 .parent = &xclk,
719 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
720 .enable_shift = 31,
721 .enable_negate = 1,
722 .flags = ENABLED,
723 .ops = &min_ops,
724};
725
726static struct clk audio_clk = {
727 .parent = &xclk,
728 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
729 .enable_shift = 30,
730 .enable_negate = 1,
731 .ops = &min_ops,
732};
733
734static struct clk pwm_clk = {
735 .parent = &xclk,
736 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
737 .enable_shift = 29,
738 .enable_negate = 1,
739 .ops = &min_ops,
740};
741
742static struct clk dri_clk = {
743 .parent = &xclk,
744 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
745 .enable_shift = 28,
746 .enable_negate = 1,
747 .ops = &min_ops,
748};
749
750static struct clk digctl_clk = {
751 .parent = &xclk,
752 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
753 .enable_shift = 27,
754 .enable_negate = 1,
755 .ops = &min_ops,
756};
757
758static struct clk timer_clk = {
759 .parent = &xclk,
760 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_XTAL,
761 .enable_shift = 26,
762 .enable_negate = 1,
763 .flags = ENABLED,
764 .ops = &min_ops,
765};
766
767static struct clk lcdif_clk = {
768 .parent = &pll_clk,
769 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
770 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
771 .busy_bit = 29,
772 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PIX,
773 .enable_shift = 31,
774 .enable_negate = 1,
775 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
776 .bypass_shift = 1,
777 .flags = NEEDS_SET_PARENT,
778 .ops = &lcdif_ops,
779};
780
781static struct clk ssp_clk = {
782 .parent = &io_clk,
783 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
784 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
785 .busy_bit = 29,
786 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SSP,
787 .enable_shift = 31,
788 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
789 .bypass_shift = 5,
790 .enable_negate = 1,
791 .flags = NEEDS_SET_PARENT,
792 .ops = &std_ops,
793};
794
795static struct clk gpmi_clk = {
796 .parent = &io_clk,
797 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
798 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
799 .busy_bit = 29,
800 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_GPMI,
801 .enable_shift = 31,
802 .enable_negate = 1,
803 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
804 .bypass_shift = 4,
805 .flags = NEEDS_SET_PARENT,
806 .ops = &std_ops,
807};
808
809static struct clk spdif_clk = {
810 .parent = &pll_clk,
811 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SPDIF,
812 .enable_shift = 31,
813 .enable_negate = 1,
814 .ops = &min_ops,
815};
816
817static struct clk emi_clk = {
818 .parent = &pll_clk,
819 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
820 .enable_shift = 31,
821 .enable_negate = 1,
822 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_FRAC,
823 .scale_shift = 8,
824 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_EMI,
825 .busy_bit = 28,
826 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
827 .bypass_shift = 6,
828 .flags = ENABLED,
829 .ops = &emi_ops,
830};
831
832static struct clk ir_clk = {
833 .parent = &io_clk,
834 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_IR,
835 .enable_shift = 31,
836 .enable_negate = 1,
837 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
838 .bypass_shift = 3,
839 .ops = &min_ops,
840};
841
842static struct clk saif_clk = {
843 .parent = &pll_clk,
844 .scale_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
845 .busy_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
846 .busy_bit = 29,
847 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_SAIF,
848 .enable_shift = 31,
849 .enable_negate = 1,
850 .bypass_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_CLKSEQ,
851 .bypass_shift = 0,
852 .ops = &std_ops,
853};
854
855static struct clk usb_clk = {
856 .parent = &pll_clk,
857 .enable_reg = REGS_CLKCTRL_BASE + HW_CLKCTRL_PLLCTRL0,
858 .enable_shift = 18,
859 .enable_negate = 1,
860 .ops = &min_ops,
861};
862
863/* list of all the clocks */
864static struct clk_lookup onchip_clks[] = {
865 {
866 .con_id = "osc_24M",
867 .clk = &osc_24M,
868 }, {
869 .con_id = "pll",
870 .clk = &pll_clk,
871 }, {
872 .con_id = "cpu",
873 .clk = &cpu_clk,
874 }, {
875 .con_id = "hclk",
876 .clk = &hclk,
877 }, {
878 .con_id = "xclk",
879 .clk = &xclk,
880 }, {
881 .con_id = "io",
882 .clk = &io_clk,
883 }, {
884 .con_id = "uart",
885 .clk = &uart_clk,
886 }, {
887 .con_id = "audio",
888 .clk = &audio_clk,
889 }, {
890 .con_id = "pwm",
891 .clk = &pwm_clk,
892 }, {
893 .con_id = "dri",
894 .clk = &dri_clk,
895 }, {
896 .con_id = "digctl",
897 .clk = &digctl_clk,
898 }, {
899 .con_id = "timer",
900 .clk = &timer_clk,
901 }, {
902 .con_id = "lcdif",
903 .clk = &lcdif_clk,
904 }, {
905 .con_id = "ssp",
906 .clk = &ssp_clk,
907 }, {
908 .con_id = "gpmi",
909 .clk = &gpmi_clk,
910 }, {
911 .con_id = "spdif",
912 .clk = &spdif_clk,
913 }, {
914 .con_id = "emi",
915 .clk = &emi_clk,
916 }, {
917 .con_id = "ir",
918 .clk = &ir_clk,
919 }, {
920 .con_id = "saif",
921 .clk = &saif_clk,
922 }, {
923 .con_id = "usb",
924 .clk = &usb_clk,
925 },
926};
927
928static int __init propagate_rate(struct clk *clk)
929{
930 struct clk_lookup *cl;
931
932 for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
933 cl++) {
934 if (unlikely(!clk_good(cl->clk)))
935 continue;
936 if (cl->clk->parent == clk && cl->clk->ops->get_rate) {
937 cl->clk->ops->get_rate(cl->clk);
938 if (cl->clk->flags & RATE_PROPAGATES)
939 propagate_rate(cl->clk);
940 }
941 }
942
943 return 0;
944}
945
946/* Exported API */
947unsigned long clk_get_rate(struct clk *clk)
948{
949 if (unlikely(!clk_good(clk)))
950 return 0;
951
952 if (clk->rate != 0)
953 return clk->rate;
954
955 if (clk->ops->get_rate != NULL)
956 return clk->ops->get_rate(clk);
957
958 return clk_get_rate(clk->parent);
959}
960EXPORT_SYMBOL(clk_get_rate);
961
962long clk_round_rate(struct clk *clk, unsigned long rate)
963{
964 if (unlikely(!clk_good(clk)))
965 return 0;
966
967 if (clk->ops->round_rate)
968 return clk->ops->round_rate(clk, rate);
969
970 return 0;
971}
972EXPORT_SYMBOL(clk_round_rate);
973
974static inline int close_enough(long rate1, long rate2)
975{
976 return rate1 && !((rate2 - rate1) * 1000 / rate1);
977}
978
979int clk_set_rate(struct clk *clk, unsigned long rate)
980{
981 int ret = -EINVAL;
982
983 if (unlikely(!clk_good(clk)))
984 goto out;
985
986 if (clk->flags & FIXED_RATE || !clk->ops->set_rate)
987 goto out;
988
989 else if (!close_enough(clk->rate, rate)) {
990 ret = clk->ops->set_rate(clk, rate);
991 if (ret < 0)
992 goto out;
993 clk->rate = rate;
994 if (clk->flags & RATE_PROPAGATES)
995 propagate_rate(clk);
996 } else
997 ret = 0;
998
999out:
1000 return ret;
1001}
1002EXPORT_SYMBOL(clk_set_rate);
1003
1004int clk_enable(struct clk *clk)
1005{
1006 unsigned long clocks_flags;
1007
1008 if (unlikely(!clk_good(clk)))
1009 return -EINVAL;
1010
1011 if (clk->parent)
1012 clk_enable(clk->parent);
1013
1014 spin_lock_irqsave(&clocks_lock, clocks_flags);
1015
1016 clk->usage++;
1017 if (clk->ops && clk->ops->enable)
1018 clk->ops->enable(clk);
1019
1020 spin_unlock_irqrestore(&clocks_lock, clocks_flags);
1021 return 0;
1022}
1023EXPORT_SYMBOL(clk_enable);
1024
1025static void local_clk_disable(struct clk *clk)
1026{
1027 if (unlikely(!clk_good(clk)))
1028 return;
1029
1030 if (clk->usage == 0 && clk->ops->disable)
1031 clk->ops->disable(clk);
1032
1033 if (clk->parent)
1034 local_clk_disable(clk->parent);
1035}
1036
1037void clk_disable(struct clk *clk)
1038{
1039 unsigned long clocks_flags;
1040
1041 if (unlikely(!clk_good(clk)))
1042 return;
1043
1044 spin_lock_irqsave(&clocks_lock, clocks_flags);
1045
1046 if ((--clk->usage) == 0 && clk->ops->disable)
1047 clk->ops->disable(clk);
1048
1049 spin_unlock_irqrestore(&clocks_lock, clocks_flags);
1050 if (clk->parent)
1051 clk_disable(clk->parent);
1052}
1053EXPORT_SYMBOL(clk_disable);
1054
1055/* Some additional API */
1056int clk_set_parent(struct clk *clk, struct clk *parent)
1057{
1058 int ret = -ENODEV;
1059 unsigned long clocks_flags;
1060
1061 if (unlikely(!clk_good(clk)))
1062 goto out;
1063
1064 if (!clk->ops->set_parent)
1065 goto out;
1066
1067 spin_lock_irqsave(&clocks_lock, clocks_flags);
1068
1069 ret = clk->ops->set_parent(clk, parent);
1070 if (!ret) {
1071 /* disable if usage count is 0 */
1072 local_clk_disable(parent);
1073
1074 parent->usage += clk->usage;
1075 clk->parent->usage -= clk->usage;
1076
1077 /* disable if new usage count is 0 */
1078 local_clk_disable(clk->parent);
1079
1080 clk->parent = parent;
1081 }
1082 spin_unlock_irqrestore(&clocks_lock, clocks_flags);
1083
1084out:
1085 return ret;
1086}
1087EXPORT_SYMBOL(clk_set_parent);
1088
1089struct clk *clk_get_parent(struct clk *clk)
1090{
1091 if (unlikely(!clk_good(clk)))
1092 return NULL;
1093 return clk->parent;
1094}
1095EXPORT_SYMBOL(clk_get_parent);
1096
1097static int __init clk_init(void)
1098{
1099 struct clk_lookup *cl;
1100 struct clk_ops *ops;
1101
1102 spin_lock_init(&clocks_lock);
1103
1104 for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
1105 cl++) {
1106 if (cl->clk->flags & ENABLED)
1107 clk_enable(cl->clk);
1108 else
1109 local_clk_disable(cl->clk);
1110
1111 ops = cl->clk->ops;
1112
1113 if ((cl->clk->flags & NEEDS_INITIALIZATION) &&
1114 ops && ops->set_rate)
1115 ops->set_rate(cl->clk, cl->clk->rate);
1116
1117 if (cl->clk->flags & FIXED_RATE) {
1118 if (cl->clk->flags & RATE_PROPAGATES)
1119 propagate_rate(cl->clk);
1120 } else {
1121 if (ops && ops->get_rate)
1122 ops->get_rate(cl->clk);
1123 }
1124
1125 if (cl->clk->flags & NEEDS_SET_PARENT) {
1126 if (ops && ops->set_parent)
1127 ops->set_parent(cl->clk, cl->clk->parent);
1128 }
1129
1130 clkdev_add(cl);
1131 }
1132 return 0;
1133}
1134
1135arch_initcall(clk_init);
diff --git a/arch/arm/plat-stmp3xxx/clock.h b/arch/arm/plat-stmp3xxx/clock.h
new file mode 100644
index 000000000000..a6611e1a3510
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/clock.h
@@ -0,0 +1,61 @@
1/*
2 * Clock control driver for Freescale STMP37XX/STMP378X - internal header file
3 *
4 * Author: Vitaly Wool <vital@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __ARCH_ARM_STMX3XXX_CLOCK_H__
19#define __ARCH_ARM_STMX3XXX_CLOCK_H__
20
21#ifndef __ASSEMBLER__
22
23struct clk_ops {
24 int (*enable) (struct clk *);
25 int (*disable) (struct clk *);
26 long (*get_rate) (struct clk *);
27 long (*round_rate) (struct clk *, u32);
28 int (*set_rate) (struct clk *, u32);
29 int (*set_parent) (struct clk *, struct clk *);
30};
31
32struct clk {
33 struct clk *parent;
34 u32 rate;
35 u32 flags;
36 u8 scale_shift;
37 u8 enable_shift;
38 u8 bypass_shift;
39 u8 busy_bit;
40 s8 usage;
41 int enable_wait;
42 int enable_negate;
43 u32 saved_div;
44 void __iomem *enable_reg;
45 void __iomem *scale_reg;
46 void __iomem *bypass_reg;
47 void __iomem *busy_reg;
48 struct clk_ops *ops;
49};
50
51#endif /* __ASSEMBLER__ */
52
53/* Flags */
54#define RATE_PROPAGATES (1<<0)
55#define NEEDS_INITIALIZATION (1<<1)
56#define PARENT_SET_RATE (1<<2)
57#define FIXED_RATE (1<<3)
58#define ENABLED (1<<4)
59#define NEEDS_SET_PARENT (1<<5)
60
61#endif
diff --git a/arch/arm/plat-stmp3xxx/core.c b/arch/arm/plat-stmp3xxx/core.c
new file mode 100644
index 000000000000..37b8a09148a4
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/core.c
@@ -0,0 +1,128 @@
1/*
2 * Freescale STMP37XX/STMP378X core routines
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/io.h>
21
22#include <mach/stmp3xxx.h>
23#include <mach/platform.h>
24#include <mach/dma.h>
25#include <mach/regs-clkctrl.h>
26
27static int __stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
28{
29 u32 c;
30 int timeout;
31
32 /* the process of software reset of IP block is done
33 in several steps:
34
35 - clear SFTRST and wait for block is enabled;
36 - clear clock gating (CLKGATE bit);
37 - set the SFTRST again and wait for block is in reset;
38 - clear SFTRST and wait for reset completion.
39 */
40 c = __raw_readl(hwreg);
41 c &= ~(1<<31); /* clear SFTRST */
42 __raw_writel(c, hwreg);
43 for (timeout = 1000000; timeout > 0; timeout--)
44 /* still in SFTRST state ? */
45 if ((__raw_readl(hwreg) & (1<<31)) == 0)
46 break;
47 if (timeout <= 0) {
48 printk(KERN_ERR"%s(%p): timeout when enabling\n",
49 __func__, hwreg);
50 return -ETIME;
51 }
52
53 c = __raw_readl(hwreg);
54 c &= ~(1<<30); /* clear CLKGATE */
55 __raw_writel(c, hwreg);
56
57 if (!just_enable) {
58 c = __raw_readl(hwreg);
59 c |= (1<<31); /* now again set SFTRST */
60 __raw_writel(c, hwreg);
61 for (timeout = 1000000; timeout > 0; timeout--)
62 /* poll until CLKGATE set */
63 if (__raw_readl(hwreg) & (1<<30))
64 break;
65 if (timeout <= 0) {
66 printk(KERN_ERR"%s(%p): timeout when resetting\n",
67 __func__, hwreg);
68 return -ETIME;
69 }
70
71 c = __raw_readl(hwreg);
72 c &= ~(1<<31); /* clear SFTRST */
73 __raw_writel(c, hwreg);
74 for (timeout = 1000000; timeout > 0; timeout--)
75 /* still in SFTRST state ? */
76 if ((__raw_readl(hwreg) & (1<<31)) == 0)
77 break;
78 if (timeout <= 0) {
79 printk(KERN_ERR"%s(%p): timeout when enabling "
80 "after reset\n", __func__, hwreg);
81 return -ETIME;
82 }
83
84 c = __raw_readl(hwreg);
85 c &= ~(1<<30); /* clear CLKGATE */
86 __raw_writel(c, hwreg);
87 }
88 for (timeout = 1000000; timeout > 0; timeout--)
89 /* still in SFTRST state ? */
90 if ((__raw_readl(hwreg) & (1<<30)) == 0)
91 break;
92
93 if (timeout <= 0) {
94 printk(KERN_ERR"%s(%p): timeout when unclockgating\n",
95 __func__, hwreg);
96 return -ETIME;
97 }
98
99 return 0;
100}
101
102int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
103{
104 int try = 10;
105 int r;
106
107 while (try--) {
108 r = __stmp3xxx_reset_block(hwreg, just_enable);
109 if (!r)
110 break;
111 pr_debug("%s: try %d failed\n", __func__, 10 - try);
112 }
113 return r;
114}
115EXPORT_SYMBOL(stmp3xxx_reset_block);
116
117struct platform_device stmp3xxx_dbguart = {
118 .name = "stmp3xxx-dbguart",
119 .id = -1,
120};
121
122void __init stmp3xxx_init(void)
123{
124 /* Turn off auto-slow and other tricks */
125 stmp3xxx_clearl(0x7f00000, REGS_CLKCTRL_BASE + HW_CLKCTRL_HBUS);
126
127 stmp3xxx_dma_init();
128}
diff --git a/arch/arm/plat-stmp3xxx/devices.c b/arch/arm/plat-stmp3xxx/devices.c
new file mode 100644
index 000000000000..68fed4b8746a
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/devices.c
@@ -0,0 +1,389 @@
1/*
2* Freescale STMP37XX/STMP378X platform devices
3*
4* Embedded Alley Solutions, Inc <source@embeddedalley.com>
5*
6* Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7* Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8*/
9
10/*
11* The code contained herein is licensed under the GNU General Public
12* License. You may obtain a copy of the GNU General Public License
13* Version 2 or later at the following locations:
14*
15* http://www.opensource.org/licenses/gpl-license.html
16* http://www.gnu.org/copyleft/gpl.html
17*/
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/device.h>
21#include <linux/platform_device.h>
22#include <linux/dma-mapping.h>
23
24#include <mach/dma.h>
25#include <mach/platform.h>
26#include <mach/stmp3xxx.h>
27#include <mach/regs-lcdif.h>
28#include <mach/regs-uartapp.h>
29#include <mach/regs-gpmi.h>
30#include <mach/regs-usbctrl.h>
31#include <mach/regs-ssp.h>
32#include <mach/regs-rtc.h>
33
34static u64 common_dmamask = DMA_BIT_MASK(32);
35
36static struct resource appuart_resources[] = {
37 {
38 .start = IRQ_UARTAPP_INTERNAL,
39 .end = IRQ_UARTAPP_INTERNAL,
40 .flags = IORESOURCE_IRQ,
41 }, {
42 .start = IRQ_UARTAPP_RX_DMA,
43 .end = IRQ_UARTAPP_RX_DMA,
44 .flags = IORESOURCE_IRQ,
45 }, {
46 .start = IRQ_UARTAPP_TX_DMA,
47 .end = IRQ_UARTAPP_TX_DMA,
48 .flags = IORESOURCE_IRQ,
49 }, {
50 .start = REGS_UARTAPP1_PHYS,
51 .end = REGS_UARTAPP1_PHYS + REGS_UARTAPP_SIZE,
52 .flags = IORESOURCE_MEM,
53 }, {
54 /* Rx DMA channel */
55 .start = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
56 .end = STMP3XXX_DMA(6, STMP3XXX_BUS_APBX),
57 .flags = IORESOURCE_DMA,
58 }, {
59 /* Tx DMA channel */
60 .start = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
61 .end = STMP3XXX_DMA(7, STMP3XXX_BUS_APBX),
62 .flags = IORESOURCE_DMA,
63 },
64};
65
66struct platform_device stmp3xxx_appuart = {
67 .name = "stmp3xxx-appuart",
68 .id = 0,
69 .resource = appuart_resources,
70 .num_resources = ARRAY_SIZE(appuart_resources),
71 .dev = {
72 .dma_mask = &common_dmamask,
73 .coherent_dma_mask = DMA_BIT_MASK(32),
74 },
75};
76
77struct platform_device stmp3xxx_watchdog = {
78 .name = "stmp3xxx_wdt",
79 .id = -1,
80};
81
82static struct resource ts_resource[] = {
83 {
84 .flags = IORESOURCE_IRQ,
85 .start = IRQ_TOUCH_DETECT,
86 .end = IRQ_TOUCH_DETECT,
87 }, {
88 .flags = IORESOURCE_IRQ,
89 .start = IRQ_LRADC_CH5,
90 .end = IRQ_LRADC_CH5,
91 },
92};
93
94struct platform_device stmp3xxx_touchscreen = {
95 .name = "stmp3xxx_ts",
96 .id = -1,
97 .resource = ts_resource,
98 .num_resources = ARRAY_SIZE(ts_resource),
99};
100
101/*
102* Keypad device
103*/
104struct platform_device stmp3xxx_keyboard = {
105 .name = "stmp3xxx-keyboard",
106 .id = -1,
107};
108
109static struct resource gpmi_resources[] = {
110 {
111 .flags = IORESOURCE_MEM,
112 .start = REGS_GPMI_PHYS,
113 .end = REGS_GPMI_PHYS + REGS_GPMI_SIZE,
114 }, {
115 .flags = IORESOURCE_IRQ,
116 .start = IRQ_GPMI_DMA,
117 .end = IRQ_GPMI_DMA,
118 }, {
119 .flags = IORESOURCE_DMA,
120 .start = STMP3XXX_DMA(4, STMP3XXX_BUS_APBH),
121 .end = STMP3XXX_DMA(8, STMP3XXX_BUS_APBH),
122 },
123};
124
125struct platform_device stmp3xxx_gpmi = {
126 .name = "gpmi",
127 .id = -1,
128 .dev = {
129 .dma_mask = &common_dmamask,
130 .coherent_dma_mask = DMA_BIT_MASK(32),
131 },
132 .resource = gpmi_resources,
133 .num_resources = ARRAY_SIZE(gpmi_resources),
134};
135
136static struct resource mmc1_resource[] = {
137 {
138 .flags = IORESOURCE_MEM,
139 .start = REGS_SSP1_PHYS,
140 .end = REGS_SSP1_PHYS + REGS_SSP_SIZE,
141 }, {
142 .flags = IORESOURCE_DMA,
143 .start = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
144 .end = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
145 }, {
146 .flags = IORESOURCE_IRQ,
147 .start = IRQ_SSP1_DMA,
148 .end = IRQ_SSP1_DMA,
149 }, {
150 .flags = IORESOURCE_IRQ,
151 .start = IRQ_SSP_ERROR,
152 .end = IRQ_SSP_ERROR,
153 },
154};
155
156struct platform_device stmp3xxx_mmc = {
157 .name = "stmp3xxx-mmc",
158 .id = 1,
159 .dev = {
160 .dma_mask = &common_dmamask,
161 .coherent_dma_mask = DMA_BIT_MASK(32),
162 },
163 .resource = mmc1_resource,
164 .num_resources = ARRAY_SIZE(mmc1_resource),
165};
166
167static struct resource usb_resources[] = {
168 {
169 .start = REGS_USBCTRL_PHYS,
170 .end = REGS_USBCTRL_PHYS + SZ_4K,
171 .flags = IORESOURCE_MEM,
172 }, {
173 .start = IRQ_USB_CTRL,
174 .end = IRQ_USB_CTRL,
175 .flags = IORESOURCE_IRQ,
176 },
177};
178
179struct platform_device stmp3xxx_udc = {
180 .name = "fsl-usb2-udc",
181 .id = -1,
182 .dev = {
183 .dma_mask = &common_dmamask,
184 .coherent_dma_mask = DMA_BIT_MASK(32),
185 },
186 .resource = usb_resources,
187 .num_resources = ARRAY_SIZE(usb_resources),
188};
189
190struct platform_device stmp3xxx_ehci = {
191 .name = "fsl-ehci",
192 .id = -1,
193 .dev = {
194 .dma_mask = &common_dmamask,
195 .coherent_dma_mask = DMA_BIT_MASK(32),
196 },
197 .resource = usb_resources,
198 .num_resources = ARRAY_SIZE(usb_resources),
199};
200
201static struct resource rtc_resources[] = {
202 {
203 .start = REGS_RTC_PHYS,
204 .end = REGS_RTC_PHYS + REGS_RTC_SIZE,
205 .flags = IORESOURCE_MEM,
206 }, {
207 .start = IRQ_RTC_ALARM,
208 .end = IRQ_RTC_ALARM,
209 .flags = IORESOURCE_IRQ,
210 }, {
211 .start = IRQ_RTC_1MSEC,
212 .end = IRQ_RTC_1MSEC,
213 .flags = IORESOURCE_IRQ,
214 },
215};
216
217struct platform_device stmp3xxx_rtc = {
218 .name = "stmp3xxx-rtc",
219 .id = -1,
220 .resource = rtc_resources,
221 .num_resources = ARRAY_SIZE(rtc_resources),
222};
223
224static struct resource ssp1_resources[] = {
225 {
226 .start = REGS_SSP1_PHYS,
227 .end = REGS_SSP1_PHYS + REGS_SSP_SIZE,
228 .flags = IORESOURCE_MEM,
229 }, {
230 .start = IRQ_SSP1_DMA,
231 .end = IRQ_SSP1_DMA,
232 .flags = IORESOURCE_IRQ,
233 }, {
234 .start = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
235 .end = STMP3XXX_DMA(1, STMP3XXX_BUS_APBH),
236 .flags = IORESOURCE_DMA,
237 },
238};
239
240static struct resource ssp2_resources[] = {
241 {
242 .start = REGS_SSP2_PHYS,
243 .end = REGS_SSP2_PHYS + REGS_SSP_SIZE,
244 .flags = IORESOURCE_MEM,
245 }, {
246 .start = IRQ_SSP2_DMA,
247 .end = IRQ_SSP2_DMA,
248 .flags = IORESOURCE_IRQ,
249 }, {
250 .start = STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
251 .end = STMP3XXX_DMA(2, STMP3XXX_BUS_APBH),
252 .flags = IORESOURCE_DMA,
253 },
254};
255
256struct platform_device stmp3xxx_spi1 = {
257 .name = "stmp3xxx_ssp",
258 .id = 1,
259 .dev = {
260 .dma_mask = &common_dmamask,
261 .coherent_dma_mask = DMA_BIT_MASK(32),
262 },
263 .resource = ssp1_resources,
264 .num_resources = ARRAY_SIZE(ssp1_resources),
265};
266
267struct platform_device stmp3xxx_spi2 = {
268 .name = "stmp3xxx_ssp",
269 .id = 2,
270 .dev = {
271 .dma_mask = &common_dmamask,
272 .coherent_dma_mask = DMA_BIT_MASK(32),
273 },
274 .resource = ssp2_resources,
275 .num_resources = ARRAY_SIZE(ssp2_resources),
276};
277
278static struct resource fb_resource[] = {
279 {
280 .flags = IORESOURCE_IRQ,
281 .start = IRQ_LCDIF_DMA,
282 .end = IRQ_LCDIF_DMA,
283 }, {
284 .flags = IORESOURCE_IRQ,
285 .start = IRQ_LCDIF_ERROR,
286 .end = IRQ_LCDIF_ERROR,
287 }, {
288 .flags = IORESOURCE_MEM,
289 .start = REGS_LCDIF_PHYS,
290 .end = REGS_LCDIF_PHYS + REGS_LCDIF_SIZE,
291 },
292};
293
294struct platform_device stmp3xxx_framebuffer = {
295 .name = "stmp3xxx-fb",
296 .id = -1,
297 .dev = {
298 .dma_mask = &common_dmamask,
299 .coherent_dma_mask = DMA_BIT_MASK(32),
300 },
301 .num_resources = ARRAY_SIZE(fb_resource),
302 .resource = fb_resource,
303};
304
305#define CMDLINE_DEVICE_CHOOSE(name, dev1, dev2) \
306 static char *cmdline_device_##name; \
307 static int cmdline_device_##name##_setup(char *dev) \
308 { \
309 cmdline_device_##name = dev + 1; \
310 return 0; \
311 } \
312 __setup(#name, cmdline_device_##name##_setup); \
313 int stmp3xxx_##name##_device_register(void) \
314 { \
315 struct platform_device *d = NULL; \
316 if (!cmdline_device_##name || \
317 !strcmp(cmdline_device_##name, #dev1)) \
318 d = &stmp3xxx_##dev1; \
319 else if (!strcmp(cmdline_device_##name, #dev2)) \
320 d = &stmp3xxx_##dev2; \
321 else \
322 printk(KERN_ERR"Unknown %s assignment '%s'.\n", \
323 #name, cmdline_device_##name); \
324 return d ? platform_device_register(d) : -ENOENT; \
325 }
326
327CMDLINE_DEVICE_CHOOSE(ssp1, mmc, spi1)
328CMDLINE_DEVICE_CHOOSE(ssp2, gpmi, spi2)
329
330struct platform_device stmp3xxx_backlight = {
331 .name = "stmp3xxx-bl",
332 .id = -1,
333};
334
335struct platform_device stmp3xxx_rotdec = {
336 .name = "stmp3xxx-rotdec",
337 .id = -1,
338};
339
340struct platform_device stmp3xxx_persistent = {
341 .name = "stmp3xxx-persistent",
342 .id = -1,
343};
344
345struct platform_device stmp3xxx_dcp_bootstream = {
346 .name = "stmp3xxx-dcpboot",
347 .id = -1,
348 .dev = {
349 .dma_mask = &common_dmamask,
350 .coherent_dma_mask = DMA_BIT_MASK(32),
351 },
352};
353
354static struct resource dcp_resources[] = {
355 {
356 .start = IRQ_DCP_VMI,
357 .end = IRQ_DCP_VMI,
358 .flags = IORESOURCE_IRQ,
359 }, {
360 .start = IRQ_DCP,
361 .end = IRQ_DCP,
362 .flags = IORESOURCE_IRQ,
363 },
364};
365
366struct platform_device stmp3xxx_dcp = {
367 .name = "stmp3xxx-dcp",
368 .id = -1,
369 .resource = dcp_resources,
370 .num_resources = ARRAY_SIZE(dcp_resources),
371 .dev = {
372 .dma_mask = &common_dmamask,
373 .coherent_dma_mask = DMA_BIT_MASK(32),
374 },
375};
376
377static struct resource battery_resource[] = {
378 {
379 .flags = IORESOURCE_IRQ,
380 .start = IRQ_VDD5V,
381 .end = IRQ_VDD5V,
382 },
383};
384
385struct platform_device stmp3xxx_battery = {
386 .name = "stmp3xxx-battery",
387 .resource = battery_resource,
388 .num_resources = ARRAY_SIZE(battery_resource),
389};
diff --git a/arch/arm/plat-stmp3xxx/dma.c b/arch/arm/plat-stmp3xxx/dma.c
new file mode 100644
index 000000000000..d2f497764dce
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/dma.c
@@ -0,0 +1,463 @@
1/*
2 * DMA helper routines for Freescale STMP37XX/STMP378X
3 *
4 * Author: dmitry pervushin <dpervushin@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/kernel.h>
19#include <linux/device.h>
20#include <linux/dmapool.h>
21#include <linux/sysdev.h>
22#include <linux/cpufreq.h>
23
24#include <asm/page.h>
25
26#include <mach/platform.h>
27#include <mach/dma.h>
28#include <mach/regs-apbx.h>
29#include <mach/regs-apbh.h>
30
31static const size_t pool_item_size = sizeof(struct stmp3xxx_dma_command);
32static const size_t pool_alignment = 8;
33static struct stmp3xxx_dma_user {
34 void *pool;
35 int inuse;
36 const char *name;
37} channels[MAX_DMA_CHANNELS];
38
39#define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
40#define IS_USED(ch) (channels[ch].inuse)
41
42int stmp3xxx_dma_request(int ch, struct device *dev, const char *name)
43{
44 struct stmp3xxx_dma_user *user;
45 int err = 0;
46
47 user = channels + ch;
48 if (!IS_VALID_CHANNEL(ch)) {
49 err = -ENODEV;
50 goto out;
51 }
52 if (IS_USED(ch)) {
53 err = -EBUSY;
54 goto out;
55 }
56 /* Create a pool to allocate dma commands from */
57 user->pool = dma_pool_create(name, dev, pool_item_size,
58 pool_alignment, PAGE_SIZE);
59 if (user->pool == NULL) {
60 err = -ENOMEM;
61 goto out;
62 }
63 user->name = name;
64 user->inuse++;
65out:
66 return err;
67}
68EXPORT_SYMBOL(stmp3xxx_dma_request);
69
70int stmp3xxx_dma_release(int ch)
71{
72 struct stmp3xxx_dma_user *user = channels + ch;
73 int err = 0;
74
75 if (!IS_VALID_CHANNEL(ch)) {
76 err = -ENODEV;
77 goto out;
78 }
79 if (!IS_USED(ch)) {
80 err = -EBUSY;
81 goto out;
82 }
83 BUG_ON(user->pool == NULL);
84 dma_pool_destroy(user->pool);
85 user->inuse--;
86out:
87 return err;
88}
89EXPORT_SYMBOL(stmp3xxx_dma_release);
90
91int stmp3xxx_dma_read_semaphore(int channel)
92{
93 int sem = -1;
94
95 switch (STMP3XXX_DMA_BUS(channel)) {
96 case STMP3XXX_BUS_APBH:
97 sem = __raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
98 STMP3XXX_DMA_CHANNEL(channel) * 0x70);
99 sem &= BM_APBH_CHn_SEMA_PHORE;
100 sem >>= BP_APBH_CHn_SEMA_PHORE;
101 break;
102
103 case STMP3XXX_BUS_APBX:
104 sem = __raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
105 STMP3XXX_DMA_CHANNEL(channel) * 0x70);
106 sem &= BM_APBX_CHn_SEMA_PHORE;
107 sem >>= BP_APBX_CHn_SEMA_PHORE;
108 break;
109 default:
110 BUG();
111 }
112 return sem;
113}
114EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore);
115
116int stmp3xxx_dma_allocate_command(int channel,
117 struct stmp3xxx_dma_descriptor *descriptor)
118{
119 struct stmp3xxx_dma_user *user = channels + channel;
120 int err = 0;
121
122 if (!IS_VALID_CHANNEL(channel)) {
123 err = -ENODEV;
124 goto out;
125 }
126 if (!IS_USED(channel)) {
127 err = -EBUSY;
128 goto out;
129 }
130 if (descriptor == NULL) {
131 err = -EINVAL;
132 goto out;
133 }
134
135 /* Allocate memory for a command from the buffer */
136 descriptor->command =
137 dma_pool_alloc(user->pool, GFP_KERNEL, &descriptor->handle);
138
139 /* Check it worked */
140 if (!descriptor->command) {
141 err = -ENOMEM;
142 goto out;
143 }
144
145 memset(descriptor->command, 0, pool_item_size);
146out:
147 WARN_ON(err);
148 return err;
149}
150EXPORT_SYMBOL(stmp3xxx_dma_allocate_command);
151
152int stmp3xxx_dma_free_command(int channel,
153 struct stmp3xxx_dma_descriptor *descriptor)
154{
155 int err = 0;
156
157 if (!IS_VALID_CHANNEL(channel)) {
158 err = -ENODEV;
159 goto out;
160 }
161 if (!IS_USED(channel)) {
162 err = -EBUSY;
163 goto out;
164 }
165
166 /* Return the command memory to the pool */
167 dma_pool_free(channels[channel].pool, descriptor->command,
168 descriptor->handle);
169
170 /* Initialise descriptor so we're not tempted to use it */
171 descriptor->command = NULL;
172 descriptor->handle = 0;
173 descriptor->virtual_buf_ptr = NULL;
174 descriptor->next_descr = NULL;
175
176 WARN_ON(err);
177out:
178 return err;
179}
180EXPORT_SYMBOL(stmp3xxx_dma_free_command);
181
182void stmp3xxx_dma_go(int channel,
183 struct stmp3xxx_dma_descriptor *head, u32 semaphore)
184{
185 int ch = STMP3XXX_DMA_CHANNEL(channel);
186 void __iomem *c, *s;
187
188 switch (STMP3XXX_DMA_BUS(channel)) {
189 case STMP3XXX_BUS_APBH:
190 c = REGS_APBH_BASE + HW_APBH_CHn_NXTCMDAR + 0x70 * ch;
191 s = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * ch;
192 break;
193
194 case STMP3XXX_BUS_APBX:
195 c = REGS_APBX_BASE + HW_APBX_CHn_NXTCMDAR + 0x70 * ch;
196 s = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * ch;
197 break;
198
199 default:
200 return;
201 }
202
203 /* Set next command */
204 __raw_writel(head->handle, c);
205 /* Set counting semaphore (kicks off transfer). Assumes
206 peripheral has been set up correctly */
207 __raw_writel(semaphore, s);
208}
209EXPORT_SYMBOL(stmp3xxx_dma_go);
210
211int stmp3xxx_dma_running(int channel)
212{
213 switch (STMP3XXX_DMA_BUS(channel)) {
214 case STMP3XXX_BUS_APBH:
215 return (__raw_readl(REGS_APBH_BASE + HW_APBH_CHn_SEMA +
216 0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
217 BM_APBH_CHn_SEMA_PHORE;
218
219 case STMP3XXX_BUS_APBX:
220 return (__raw_readl(REGS_APBX_BASE + HW_APBX_CHn_SEMA +
221 0x70 * STMP3XXX_DMA_CHANNEL(channel))) &
222 BM_APBX_CHn_SEMA_PHORE;
223 default:
224 BUG();
225 return 0;
226 }
227}
228EXPORT_SYMBOL(stmp3xxx_dma_running);
229
230/*
231 * Circular dma chain management
232 */
233void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain)
234{
235 int i;
236
237 for (i = 0; i < chain->total_count; i++)
238 stmp3xxx_dma_free_command(
239 STMP3XXX_DMA(chain->channel, chain->bus),
240 &chain->chain[i]);
241}
242EXPORT_SYMBOL(stmp3xxx_dma_free_chain);
243
244int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
245 struct stmp3xxx_dma_descriptor descriptors[],
246 unsigned items)
247{
248 int i;
249 int err = 0;
250
251 if (items == 0)
252 return err;
253
254 for (i = 0; i < items; i++) {
255 err = stmp3xxx_dma_allocate_command(ch, &descriptors[i]);
256 if (err) {
257 WARN_ON(err);
258 /*
259 * Couldn't allocate the whole chain.
260 * deallocate what has been allocated
261 */
262 if (i) {
263 do {
264 stmp3xxx_dma_free_command(ch,
265 &descriptors
266 [i]);
267 } while (i-- >= 0);
268 }
269 return err;
270 }
271
272 /* link them! */
273 if (i > 0) {
274 descriptors[i - 1].next_descr = &descriptors[i];
275 descriptors[i - 1].command->next =
276 descriptors[i].handle;
277 }
278 }
279
280 /* make list circular */
281 descriptors[items - 1].next_descr = &descriptors[0];
282 descriptors[items - 1].command->next = descriptors[0].handle;
283
284 chain->total_count = items;
285 chain->chain = descriptors;
286 chain->free_index = 0;
287 chain->active_index = 0;
288 chain->cooked_index = 0;
289 chain->free_count = items;
290 chain->active_count = 0;
291 chain->cooked_count = 0;
292 chain->bus = STMP3XXX_DMA_BUS(ch);
293 chain->channel = STMP3XXX_DMA_CHANNEL(ch);
294 return err;
295}
296EXPORT_SYMBOL(stmp3xxx_dma_make_chain);
297
298void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain)
299{
300 BUG_ON(stmp3xxx_dma_running(STMP3XXX_DMA(chain->channel, chain->bus)));
301 chain->free_index = 0;
302 chain->active_index = 0;
303 chain->cooked_index = 0;
304 chain->free_count = chain->total_count;
305 chain->active_count = 0;
306 chain->cooked_count = 0;
307}
308EXPORT_SYMBOL(stmp37xx_circ_clear_chain);
309
310void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
311 unsigned count)
312{
313 BUG_ON(chain->cooked_count < count);
314
315 chain->cooked_count -= count;
316 chain->cooked_index += count;
317 chain->cooked_index %= chain->total_count;
318 chain->free_count += count;
319}
320EXPORT_SYMBOL(stmp37xx_circ_advance_free);
321
322void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
323 unsigned count)
324{
325 void __iomem *c;
326 u32 mask_clr, mask;
327 BUG_ON(chain->free_count < count);
328
329 chain->free_count -= count;
330 chain->free_index += count;
331 chain->free_index %= chain->total_count;
332 chain->active_count += count;
333
334 switch (chain->bus) {
335 case STMP3XXX_BUS_APBH:
336 c = REGS_APBH_BASE + HW_APBH_CHn_SEMA + 0x70 * chain->channel;
337 mask_clr = BM_APBH_CHn_SEMA_INCREMENT_SEMA;
338 mask = BF(count, APBH_CHn_SEMA_INCREMENT_SEMA);
339 break;
340 case STMP3XXX_BUS_APBX:
341 c = REGS_APBX_BASE + HW_APBX_CHn_SEMA + 0x70 * chain->channel;
342 mask_clr = BM_APBX_CHn_SEMA_INCREMENT_SEMA;
343 mask = BF(count, APBX_CHn_SEMA_INCREMENT_SEMA);
344 break;
345 default:
346 BUG();
347 return;
348 }
349
350 /* Set counting semaphore (kicks off transfer). Assumes
351 peripheral has been set up correctly */
352 stmp3xxx_clearl(mask_clr, c);
353 stmp3xxx_setl(mask, c);
354}
355EXPORT_SYMBOL(stmp37xx_circ_advance_active);
356
357unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain)
358{
359 unsigned cooked;
360
361 cooked = chain->active_count -
362 stmp3xxx_dma_read_semaphore(STMP3XXX_DMA(chain->channel, chain->bus));
363
364 chain->active_count -= cooked;
365 chain->active_index += cooked;
366 chain->active_index %= chain->total_count;
367
368 chain->cooked_count += cooked;
369
370 return cooked;
371}
372EXPORT_SYMBOL(stmp37xx_circ_advance_cooked);
373
374void stmp3xxx_dma_set_alt_target(int channel, int function)
375{
376#if defined(CONFIG_ARCH_STMP37XX)
377 unsigned bits = 4;
378#elif defined(CONFIG_ARCH_STMP378X)
379 unsigned bits = 2;
380#else
381#error wrong arch
382#endif
383 int shift = STMP3XXX_DMA_CHANNEL(channel) * bits;
384 unsigned mask = (1<<bits) - 1;
385 void __iomem *c;
386
387 BUG_ON(function < 0 || function >= (1<<bits));
388 pr_debug("%s: channel = %d, using mask %x, "
389 "shift = %d\n", __func__, channel, mask, shift);
390
391 switch (STMP3XXX_DMA_BUS(channel)) {
392 case STMP3XXX_BUS_APBH:
393 c = REGS_APBH_BASE + HW_APBH_DEVSEL;
394 break;
395 case STMP3XXX_BUS_APBX:
396 c = REGS_APBX_BASE + HW_APBX_DEVSEL;
397 break;
398 default:
399 BUG();
400 }
401 stmp3xxx_clearl(mask << shift, c);
402 stmp3xxx_setl(mask << shift, c);
403}
404EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target);
405
406void stmp3xxx_dma_suspend(void)
407{
408 stmp3xxx_setl(BM_APBH_CTRL0_CLKGATE, REGS_APBH_BASE + HW_APBH_CTRL0);
409 stmp3xxx_setl(BM_APBX_CTRL0_CLKGATE, REGS_APBX_BASE + HW_APBX_CTRL0);
410}
411
412void stmp3xxx_dma_resume(void)
413{
414 stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
415 REGS_APBH_BASE + HW_APBH_CTRL0);
416 stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
417 REGS_APBX_BASE + HW_APBX_CTRL0);
418}
419
420#ifdef CONFIG_CPU_FREQ
421
422struct dma_notifier_block {
423 struct notifier_block nb;
424 void *data;
425};
426
427static int dma_cpufreq_notifier(struct notifier_block *self,
428 unsigned long phase, void *p)
429{
430 switch (phase) {
431 case CPUFREQ_POSTCHANGE:
432 stmp3xxx_dma_resume();
433 break;
434
435 case CPUFREQ_PRECHANGE:
436 stmp3xxx_dma_suspend();
437 break;
438
439 default:
440 break;
441 }
442
443 return NOTIFY_DONE;
444}
445
446static struct dma_notifier_block dma_cpufreq_nb = {
447 .nb = {
448 .notifier_call = dma_cpufreq_notifier,
449 },
450};
451#endif /* CONFIG_CPU_FREQ */
452
453void __init stmp3xxx_dma_init(void)
454{
455 stmp3xxx_clearl(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST,
456 REGS_APBH_BASE + HW_APBH_CTRL0);
457 stmp3xxx_clearl(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST,
458 REGS_APBX_BASE + HW_APBX_CTRL0);
459#ifdef CONFIG_CPU_FREQ
460 cpufreq_register_notifier(&dma_cpufreq_nb.nb,
461 CPUFREQ_TRANSITION_NOTIFIER);
462#endif /* CONFIG_CPU_FREQ */
463}
diff --git a/arch/arm/plat-stmp3xxx/include/mach/clkdev.h b/arch/arm/plat-stmp3xxx/include/mach/clkdev.h
new file mode 100644
index 000000000000..f9c39772d7c5
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/clkdev.h
@@ -0,0 +1,18 @@
1/*
2 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12#ifndef __ASM_MACH_CLKDEV_H
13#define __ASM_MACH_CLKDEV_H
14
15#define __clk_get(clk) ({ 1; })
16#define __clk_put(clk) do { } while (0)
17
18#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/cputype.h b/arch/arm/plat-stmp3xxx/include/mach/cputype.h
new file mode 100644
index 000000000000..b4e205b95f2c
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/cputype.h
@@ -0,0 +1,33 @@
1/*
2 * Freescale STMP37XX/STMP378X CPU type detection
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __ASM_PLAT_CPU_H
19#define __ASM_PLAT_CPU_H
20
21#ifdef CONFIG_ARCH_STMP37XX
22#define cpu_is_stmp37xx() (1)
23#else
24#define cpu_is_stmp37xx() (0)
25#endif
26
27#ifdef CONFIG_ARCH_STMP378X
28#define cpu_is_stmp378x() (1)
29#else
30#define cpu_is_stmp378x() (0)
31#endif
32
33#endif /* __ASM_PLAT_CPU_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
new file mode 100644
index 000000000000..fb3b969bf0a2
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/debug-macro.S
@@ -0,0 +1,42 @@
1/*
2 * Debugging macro include header
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18
19 .macro addruart,rx
20 mrc p15, 0, \rx, c1, c0
21 tst \rx, #1 @ MMU enabled?
22 moveq \rx, #0x80000000 @ physical base address
23 addeq \rx, \rx, #0x00070000
24 movne \rx, #0xf0000000 @ virtual base
25 addne \rx, \rx, #0x00070000
26 .endm
27
28 .macro senduart,rd,rx
29 strb \rd, [\rx, #0] @ data register at 0
30 .endm
31
32 .macro waituart,rd,rx
331001: ldr \rd, [\rx, #0x18] @ UARTFLG
34 tst \rd, #1 << 5 @ UARTFLGUTXFF - 1 when full
35 bne 1001b
36 .endm
37
38 .macro busyuart,rd,rx
391001: ldr \rd, [\rx, #0x18] @ UARTFLG
40 tst \rd, #1 << 3 @ UARTFLGUBUSY - 1 when busy
41 bne 1001b
42 .endm
diff --git a/arch/arm/plat-stmp3xxx/include/mach/dma.h b/arch/arm/plat-stmp3xxx/include/mach/dma.h
new file mode 100644
index 000000000000..7c58557c6766
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/dma.h
@@ -0,0 +1,153 @@
1/*
2 * Freescale STMP37XX/STMP378X DMA helper interface
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __ASM_PLAT_STMP3XXX_DMA_H
19#define __ASM_PLAT_STMP3XXX_DMA_H
20
21#include <linux/platform_device.h>
22#include <linux/dmapool.h>
23
24#if !defined(MAX_PIO_WORDS)
25#define MAX_PIO_WORDS (15)
26#endif
27
28#define STMP3XXX_BUS_APBH 0
29#define STMP3XXX_BUS_APBX 1
30#define STMP3XXX_DMA_MAX_CHANNEL 16
31#define STMP3XXX_DMA_BUS(dma) ((dma) / 16)
32#define STMP3XXX_DMA_CHANNEL(dma) ((dma) % 16)
33#define STMP3XXX_DMA(channel, bus) ((bus) * 16 + (channel))
34#define MAX_DMA_ADDRESS 0xffffffff
35#define MAX_DMA_CHANNELS 32
36
37struct stmp3xxx_dma_command {
38 u32 next;
39 u32 cmd;
40 union {
41 u32 buf_ptr;
42 u32 alternate;
43 };
44 u32 pio_words[MAX_PIO_WORDS];
45};
46
47struct stmp3xxx_dma_descriptor {
48 struct stmp3xxx_dma_command *command;
49 dma_addr_t handle;
50
51 /* The virtual address of the buffer pointer */
52 void *virtual_buf_ptr;
53 /* The next descriptor in a the DMA chain (optional) */
54 struct stmp3xxx_dma_descriptor *next_descr;
55};
56
57struct stmp37xx_circ_dma_chain {
58 unsigned total_count;
59 struct stmp3xxx_dma_descriptor *chain;
60
61 unsigned free_index;
62 unsigned free_count;
63 unsigned active_index;
64 unsigned active_count;
65 unsigned cooked_index;
66 unsigned cooked_count;
67
68 int bus;
69 unsigned channel;
70};
71
72static inline struct stmp3xxx_dma_descriptor
73 *stmp3xxx_dma_circ_get_free_head(struct stmp37xx_circ_dma_chain *chain)
74{
75 return &(chain->chain[chain->free_index]);
76}
77
78static inline struct stmp3xxx_dma_descriptor
79 *stmp3xxx_dma_circ_get_cooked_head(struct stmp37xx_circ_dma_chain *chain)
80{
81 return &(chain->chain[chain->cooked_index]);
82}
83
84int stmp3xxx_dma_request(int ch, struct device *dev, const char *name);
85int stmp3xxx_dma_release(int ch);
86int stmp3xxx_dma_allocate_command(int ch,
87 struct stmp3xxx_dma_descriptor *descriptor);
88int stmp3xxx_dma_free_command(int ch,
89 struct stmp3xxx_dma_descriptor *descriptor);
90void stmp3xxx_dma_continue(int channel, u32 semaphore);
91void stmp3xxx_dma_go(int ch, struct stmp3xxx_dma_descriptor *head,
92 u32 semaphore);
93int stmp3xxx_dma_running(int ch);
94int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
95 struct stmp3xxx_dma_descriptor descriptors[],
96 unsigned items);
97void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain);
98void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain);
99void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
100 unsigned count);
101void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
102 unsigned count);
103unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain);
104int stmp3xxx_dma_read_semaphore(int ch);
105void stmp3xxx_dma_init(void);
106void stmp3xxx_dma_set_alt_target(int ch, int target);
107void stmp3xxx_dma_suspend(void);
108void stmp3xxx_dma_resume(void);
109
110/*
111 * STMP37xx and STMP378x have different DMA control
112 * registers layout
113 */
114
115void stmp3xxx_arch_dma_freeze(int ch);
116void stmp3xxx_arch_dma_unfreeze(int ch);
117void stmp3xxx_arch_dma_reset_channel(int ch);
118void stmp3xxx_arch_dma_enable_interrupt(int ch);
119void stmp3xxx_arch_dma_clear_interrupt(int ch);
120int stmp3xxx_arch_dma_is_interrupt(int ch);
121
122static inline void stmp3xxx_dma_reset_channel(int ch)
123{
124 stmp3xxx_arch_dma_reset_channel(ch);
125}
126
127
128static inline void stmp3xxx_dma_freeze(int ch)
129{
130 stmp3xxx_arch_dma_freeze(ch);
131}
132
133static inline void stmp3xxx_dma_unfreeze(int ch)
134{
135 stmp3xxx_arch_dma_unfreeze(ch);
136}
137
138static inline void stmp3xxx_dma_enable_interrupt(int ch)
139{
140 stmp3xxx_arch_dma_enable_interrupt(ch);
141}
142
143static inline void stmp3xxx_dma_clear_interrupt(int ch)
144{
145 stmp3xxx_arch_dma_clear_interrupt(ch);
146}
147
148static inline int stmp3xxx_dma_is_interrupt(int ch)
149{
150 return stmp3xxx_arch_dma_is_interrupt(ch);
151}
152
153#endif /* __ASM_PLAT_STMP3XXX_DMA_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpio.h b/arch/arm/plat-stmp3xxx/include/mach/gpio.h
new file mode 100644
index 000000000000..a8b579256170
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/gpio.h
@@ -0,0 +1,28 @@
1/*
2 * Freescale STMP37XX/STMP378X GPIO interface
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __ASM_PLAT_GPIO_H
19#define __ASM_PLAT_GPIO_H
20
21#define ARCH_NR_GPIOS (32 * 3)
22#define gpio_to_irq(gpio) __gpio_to_irq(gpio)
23#define gpio_get_value(gpio) __gpio_get_value(gpio)
24#define gpio_set_value(gpio, value) __gpio_set_value(gpio, value)
25
26#include <asm-generic/gpio.h>
27
28#endif /* __ASM_PLAT_GPIO_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/gpmi.h b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
new file mode 100644
index 000000000000..e166432910ad
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/gpmi.h
@@ -0,0 +1,12 @@
1#ifndef __MACH_GPMI_H
2
3#include <linux/mtd/partitions.h>
4#include <mach/regs-gpmi.h>
5
6struct gpmi_platform_data {
7 void *pins;
8 int nr_parts;
9 struct mtd_partition *parts;
10 const char *part_types[];
11};
12#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/hardware.h b/arch/arm/plat-stmp3xxx/include/mach/hardware.h
new file mode 100644
index 000000000000..47b8978405bc
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/hardware.h
@@ -0,0 +1,32 @@
1/*
2 * This file contains the hardware definitions of the Freescale STMP3XXX
3 *
4 * Copyright (C) 2005 Sigmatel Inc
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __ASM_ARCH_HARDWARE_H
19#define __ASM_ARCH_HARDWARE_H
20
21/*
22 * Where in virtual memory the IO devices (timers, system controllers
23 * and so on)
24 */
25#define IO_BASE 0xF0000000 /* VA of IO */
26#define IO_SIZE 0x00100000 /* How much? */
27#define IO_START 0x80000000 /* PA of IO */
28
29/* macro to get at IO space when running virtually */
30#define IO_ADDRESS(x) (((x) & 0x000fffff) | IO_BASE)
31
32#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/io.h b/arch/arm/plat-stmp3xxx/include/mach/io.h
new file mode 100644
index 000000000000..d08b1b7f3d1c
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/io.h
@@ -0,0 +1,25 @@
1/*
2 * Copyright (C) 2005 Sigmatel Inc
3 *
4 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
5 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
6 */
7
8/*
9 * The code contained herein is licensed under the GNU General Public
10 * License. You may obtain a copy of the GNU General Public License
11 * Version 2 or later at the following locations:
12 *
13 * http://www.opensource.org/licenses/gpl-license.html
14 * http://www.gnu.org/copyleft/gpl.html
15 */
16#ifndef __ASM_ARM_ARCH_IO_H
17#define __ASM_ARM_ARCH_IO_H
18
19#define IO_SPACE_LIMIT 0xffffffff
20
21#define __io(a) __typesafe_io(a)
22#define __mem_pci(a) (a)
23#define __mem_isa(a) (a)
24
25#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/memory.h b/arch/arm/plat-stmp3xxx/include/mach/memory.h
new file mode 100644
index 000000000000..7b875a07a1a7
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/memory.h
@@ -0,0 +1,22 @@
1/*
2 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
4 */
5
6/*
7 * The code contained herein is licensed under the GNU General Public
8 * License. You may obtain a copy of the GNU General Public License
9 * Version 2 or later at the following locations:
10 *
11 * http://www.opensource.org/licenses/gpl-license.html
12 * http://www.gnu.org/copyleft/gpl.html
13 */
14#ifndef __ASM_ARCH_MEMORY_H
15#define __ASM_ARCH_MEMORY_H
16
17/*
18 * Physical DRAM offset.
19 */
20#define PHYS_OFFSET UL(0x40000000)
21
22#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/mmc.h b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
new file mode 100644
index 000000000000..ba81e1543761
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/mmc.h
@@ -0,0 +1,14 @@
1#ifndef _MACH_MMC_H
2#define _MACH_MMC_H
3
4#include <mach/regs-ssp.h>
5
6struct stmp3xxxmmc_platform_data {
7 int (*get_wp)(void);
8 unsigned long (*setclock)(void __iomem *base, unsigned long);
9 void (*cmd_pullup)(int);
10 int (*hw_init)(void);
11 void (*hw_release)(void);
12};
13
14#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pinmux.h b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
new file mode 100644
index 000000000000..cc5af82279ad
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/pinmux.h
@@ -0,0 +1,157 @@
1/*
2 * Freescale STMP37XX/STMP378X Pin Multiplexing
3 *
4 * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __PINMUX_H
19#define __PINMUX_H
20
21#include <linux/spinlock.h>
22#include <linux/types.h>
23#include <linux/gpio.h>
24#include <asm-generic/gpio.h>
25
26/* Pin definitions */
27#include "pins.h"
28#include <mach/pins.h>
29
30/*
31 * Each pin may be routed up to four different HW interfaces
32 * including GPIO
33 */
34enum pin_fun {
35 PIN_FUN1 = 0,
36 PIN_FUN2,
37 PIN_FUN3,
38 PIN_GPIO,
39};
40
41/*
42 * Each pin may have different output drive strength in range from
43 * 4mA to 20mA. The most common case is 4, 8 and 12 mA strengths.
44 */
45enum pin_strength {
46 PIN_4MA = 0,
47 PIN_8MA,
48 PIN_12MA,
49 PIN_16MA,
50 PIN_20MA,
51};
52
53/*
54 * Each pin can be programmed for 1.8V or 3.3V
55 */
56enum pin_voltage {
57 PIN_1_8V = 0,
58 PIN_3_3V,
59};
60
61/*
62 * Structure to define a group of pins and their parameters
63 */
64struct pin_desc {
65 unsigned id;
66 enum pin_fun fun;
67 enum pin_strength strength;
68 enum pin_voltage voltage;
69 unsigned pullup:1;
70};
71
72struct pin_group {
73 struct pin_desc *pins;
74 int nr_pins;
75};
76
77/* Set pin drive strength */
78void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
79 const char *label);
80
81/* Set pin voltage */
82void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
83 const char *label);
84
85/* Enable pull-up resistor for a pin */
86void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label);
87
88/*
89 * Request a pin ownership, only one module (identified by @label)
90 * may own a pin.
91 */
92int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label);
93
94/* Release pin */
95void stmp3xxx_release_pin(unsigned id, const char *label);
96
97void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun);
98
99/*
100 * Each bank is associated with a number of registers to control
101 * pin function, drive strength, voltage and pull-up reigster. The
102 * number of registers of a given type depends on the number of bits
103 * describin particular pin.
104 */
105#define HW_MUXSEL_NUM 2 /* registers per bank */
106#define HW_MUXSEL_PIN_LEN 2 /* bits per pin */
107#define HW_MUXSEL_PIN_NUM 16 /* pins per register */
108#define HW_MUXSEL_PINFUN_MASK 0x3 /* pin function mask */
109#define HW_MUXSEL_PINFUN_NUM 4 /* four options for a pin */
110
111#define HW_DRIVE_NUM 4 /* registers per bank */
112#define HW_DRIVE_PIN_LEN 4 /* bits per pin */
113#define HW_DRIVE_PIN_NUM 8 /* pins per register */
114#define HW_DRIVE_PINDRV_MASK 0x3 /* pin strength mask - 2 bits */
115#define HW_DRIVE_PINDRV_NUM 5 /* five possible strength values */
116#define HW_DRIVE_PINV_MASK 0x4 /* pin voltage mask - 1 bit */
117
118
119struct stmp3xxx_pinmux_bank {
120 struct gpio_chip chip;
121
122 /* Pins allocation map */
123 unsigned long pin_map;
124
125 /* Pin owner names */
126 const char *pin_labels[32];
127
128 /* Bank registers */
129 void __iomem *hw_muxsel[HW_MUXSEL_NUM];
130 void __iomem *hw_drive[HW_DRIVE_NUM];
131 void __iomem *hw_pull;
132
133 void __iomem *pin2irq,
134 *irqlevel,
135 *irqpolarity,
136 *irqen,
137 *irqstat;
138
139 /* HW MUXSEL register function bit values */
140 u8 functions[HW_MUXSEL_PINFUN_NUM];
141
142 /*
143 * HW DRIVE register strength bit values:
144 * 0xff - requested strength is not supported for this bank
145 */
146 u8 strengths[HW_DRIVE_PINDRV_NUM];
147
148 /* GPIO things */
149 void __iomem *hw_gpio_in,
150 *hw_gpio_out,
151 *hw_gpio_doe;
152 int irq, virq;
153};
154
155int __init stmp3xxx_pinmux_init(int virtual_irq_start);
156
157#endif /* __PINMUX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/pins.h b/arch/arm/plat-stmp3xxx/include/mach/pins.h
new file mode 100644
index 000000000000..c573318e1caa
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/pins.h
@@ -0,0 +1,30 @@
1/*
2 * Freescale STMP37XX/STMP378X Pin multiplexing interface definitions
3 *
4 * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __ASM_PLAT_PINS_H
19#define __ASM_PLAT_PINS_H
20
21#define STMP3XXX_PINID(bank, pin) (bank * 32 + pin)
22#define STMP3XXX_PINID_TO_BANK(pinid) (pinid / 32)
23#define STMP3XXX_PINID_TO_PINNUM(pinid) (pinid % 32)
24
25/*
26 * Special invalid pin identificator to show a pin doesn't exist
27 */
28#define PINID_NO_PIN STMP3XXX_PINID(0xFF, 0xFF)
29
30#endif /* __ASM_PLAT_PINS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/platform.h b/arch/arm/plat-stmp3xxx/include/mach/platform.h
new file mode 100644
index 000000000000..7007ddaa91eb
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/platform.h
@@ -0,0 +1,68 @@
1/*
2 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
4 */
5
6/*
7 * The code contained herein is licensed under the GNU General Public
8 * License. You may obtain a copy of the GNU General Public License
9 * Version 2 or later at the following locations:
10 *
11 * http://www.opensource.org/licenses/gpl-license.html
12 * http://www.gnu.org/copyleft/gpl.html
13 */
14#ifndef __ASM_PLAT_PLATFORM_H
15#define __ASM_PLAT_PLATFORM_H
16
17#ifndef __ASSEMBLER__
18#include <linux/io.h>
19#endif
20#include <asm/sizes.h>
21
22/* Virtual address where registers are mapped */
23#define STMP3XXX_REGS_PHBASE 0x80000000
24#ifdef __ASSEMBLER__
25#define STMP3XXX_REGS_BASE 0xF0000000
26#else
27#define STMP3XXX_REGS_BASE (void __iomem *)0xF0000000
28#endif
29#define STMP3XXX_REGS_SIZE SZ_1M
30
31/* Virtual address where OCRAM is mapped */
32#define STMP3XXX_OCRAM_PHBASE 0x00000000
33#ifdef __ASSEMBLER__
34#define STMP3XXX_OCRAM_BASE 0xf1000000
35#else
36#define STMP3XXX_OCRAM_BASE (void __iomem *)0xf1000000
37#endif
38#define STMP3XXX_OCRAM_SIZE (32 * SZ_1K)
39
40#ifdef CONFIG_ARCH_STMP37XX
41#define IRQ_PRIORITY_REG_RD HW_ICOLL_PRIORITYn_RD
42#define IRQ_PRIORITY_REG_WR HW_ICOLL_PRIORITYn_WR
43#endif
44
45#ifdef CONFIG_ARCH_STMP378X
46#define IRQ_PRIORITY_REG_RD HW_ICOLL_INTERRUPTn_RD
47#define IRQ_PRIORITY_REG_WR HW_ICOLL_INTERRUPTn_WR
48#endif
49
50#define HW_STMP3XXX_SET 0x04
51#define HW_STMP3XXX_CLR 0x08
52#define HW_STMP3XXX_TOG 0x0c
53
54#ifndef __ASSEMBLER__
55static inline void stmp3xxx_clearl(u32 v, void __iomem *r)
56{
57 __raw_writel(v, r + HW_STMP3XXX_CLR);
58}
59
60static inline void stmp3xxx_setl(u32 v, void __iomem *r)
61{
62 __raw_writel(v, r + HW_STMP3XXX_SET);
63}
64#endif
65
66#define BF(value, field) (((value) << BP_##field) & BM_##field)
67
68#endif /* __ASM_ARCH_PLATFORM_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
new file mode 100644
index 000000000000..2e300feaa4cf
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/stmp3xxx.h
@@ -0,0 +1,54 @@
1/*
2 * Freescale STMP37XX/STMP378X core structure and function declarations
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#ifndef __ASM_PLAT_STMP3XXX_H
19#define __ASM_PLAT_STMP3XXX_H
20
21#include <linux/irq.h>
22
23extern struct sys_timer stmp3xxx_timer;
24
25void stmp3xxx_init_irq(struct irq_chip *chip);
26void stmp3xxx_init(void);
27int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable);
28extern struct platform_device stmp3xxx_dbguart,
29 stmp3xxx_appuart,
30 stmp3xxx_watchdog,
31 stmp3xxx_touchscreen,
32 stmp3xxx_keyboard,
33 stmp3xxx_gpmi,
34 stmp3xxx_mmc,
35 stmp3xxx_udc,
36 stmp3xxx_ehci,
37 stmp3xxx_rtc,
38 stmp3xxx_spi1,
39 stmp3xxx_spi2,
40 stmp3xxx_backlight,
41 stmp3xxx_rotdec,
42 stmp3xxx_dcp,
43 stmp3xxx_dcp_bootstream,
44 stmp3xxx_persistent,
45 stmp3xxx_framebuffer,
46 stmp3xxx_battery;
47int stmp3xxx_ssp1_device_register(void);
48int stmp3xxx_ssp2_device_register(void);
49
50struct pin_group;
51void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label);
52int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label);
53
54#endif /* __ASM_PLAT_STMP3XXX_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/system.h b/arch/arm/plat-stmp3xxx/include/mach/system.h
new file mode 100644
index 000000000000..28a988889319
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/system.h
@@ -0,0 +1,49 @@
1/*
2 * Copyright (C) 2005 Sigmatel Inc
3 *
4 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
5 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
6 */
7
8/*
9 * The code contained herein is licensed under the GNU General Public
10 * License. You may obtain a copy of the GNU General Public License
11 * Version 2 or later at the following locations:
12 *
13 * http://www.opensource.org/licenses/gpl-license.html
14 * http://www.gnu.org/copyleft/gpl.html
15 */
16#ifndef __ASM_ARCH_SYSTEM_H
17#define __ASM_ARCH_SYSTEM_H
18
19#include <asm/proc-fns.h>
20#include <mach/platform.h>
21#include <mach/regs-clkctrl.h>
22#include <mach/regs-power.h>
23
24static inline void arch_idle(void)
25{
26 /*
27 * This should do all the clock switching
28 * and wait for interrupt tricks
29 */
30
31 cpu_do_idle();
32}
33
34static inline void arch_reset(char mode, const char *cmd)
35{
36 /* Set BATTCHRG to default value */
37 __raw_writel(0x00010000, REGS_POWER_BASE + HW_POWER_CHARGE);
38
39 /* Set MINPWR to default value */
40 __raw_writel(0, REGS_POWER_BASE + HW_POWER_MINPWR);
41
42 /* Reset digital side of chip (but not power or RTC) */
43 __raw_writel(BM_CLKCTRL_RESET_DIG,
44 REGS_CLKCTRL_BASE + HW_CLKCTRL_RESET);
45
46 /* Should not return */
47}
48
49#endif
diff --git a/arch/arm/plat-stmp3xxx/include/mach/timex.h b/arch/arm/plat-stmp3xxx/include/mach/timex.h
new file mode 100644
index 000000000000..3373985d7a8e
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/timex.h
@@ -0,0 +1,20 @@
1/*
2 * Copyright (C) 1999 ARM Limited
3 *
4 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
5 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
6 */
7
8/*
9 * The code contained herein is licensed under the GNU General Public
10 * License. You may obtain a copy of the GNU General Public License
11 * Version 2 or later at the following locations:
12 *
13 * http://www.opensource.org/licenses/gpl-license.html
14 * http://www.gnu.org/copyleft/gpl.html
15 */
16
17/*
18 * System time clock is sourced from the 32k clock
19 */
20#define CLOCK_TICK_RATE (32768)
diff --git a/arch/arm/plat-stmp3xxx/include/mach/uncompress.h b/arch/arm/plat-stmp3xxx/include/mach/uncompress.h
new file mode 100644
index 000000000000..f79f5ee56cd4
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/uncompress.h
@@ -0,0 +1,53 @@
1/*
2 *
3 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
4 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
5 */
6
7/*
8 * The code contained herein is licensed under the GNU General Public
9 * License. You may obtain a copy of the GNU General Public License
10 * Version 2 or later at the following locations:
11 *
12 * http://www.opensource.org/licenses/gpl-license.html
13 * http://www.gnu.org/copyleft/gpl.html
14 */
15#ifndef __ASM_PLAT_UNCOMPRESS_H
16#define __ASM_PLAT_UNCOMPRESS_H
17
18/*
19 * Register includes are for when the MMU enabled; we need to define our
20 * own stuff here for pre-MMU use
21 */
22#define UARTDBG_BASE 0x80070000
23#define UART(c) (((volatile unsigned *)UARTDBG_BASE)[c])
24
25/*
26 * This does not append a newline
27 */
28static void putc(char c)
29{
30 /* Wait for TX fifo empty */
31 while ((UART(6) & (1<<7)) == 0)
32 continue;
33
34 /* Write byte */
35 UART(0) = c;
36
37 /* Wait for last bit to exit the UART */
38 while (UART(6) & (1<<3))
39 continue;
40}
41
42static void flush(void)
43{
44}
45
46/*
47 * nothing to do
48 */
49#define arch_decomp_setup()
50
51#define arch_decomp_wdog()
52
53#endif /* __ASM_PLAT_UNCOMPRESS_H */
diff --git a/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
new file mode 100644
index 000000000000..541b880c1863
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/include/mach/vmalloc.h
@@ -0,0 +1,12 @@
1/*
2 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
3 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
4 *
5 * The code contained herein is licensed under the GNU General Public
6 * License. You may obtain a copy of the GNU General Public License
7 * Version 2 or later at the following locations:
8 *
9 * http://www.opensource.org/licenses/gpl-license.html
10 * http://www.gnu.org/copyleft/gpl.html
11 */
12#define VMALLOC_END (0xF0000000)
diff --git a/arch/arm/plat-stmp3xxx/irq.c b/arch/arm/plat-stmp3xxx/irq.c
new file mode 100644
index 000000000000..20de4e0401ef
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/irq.c
@@ -0,0 +1,51 @@
1/*
2 * Freescale STMP37XX/STMP378X common interrupt handling code
3 *
4 * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/init.h>
19#include <linux/interrupt.h>
20#include <linux/delay.h>
21#include <linux/irq.h>
22#include <linux/sysdev.h>
23
24#include <mach/stmp3xxx.h>
25#include <mach/platform.h>
26#include <mach/regs-icoll.h>
27
28void __init stmp3xxx_init_irq(struct irq_chip *chip)
29{
30 unsigned int i, lv;
31
32 /* Reset the interrupt controller */
33 stmp3xxx_reset_block(REGS_ICOLL_BASE + HW_ICOLL_CTRL, true);
34
35 /* Disable all interrupts initially */
36 for (i = 0; i < NR_REAL_IRQS; i++) {
37 chip->mask(i);
38 set_irq_chip(i, chip);
39 set_irq_handler(i, handle_level_irq);
40 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
41 }
42
43 /* Ensure vector is cleared */
44 for (lv = 0; lv < 4; lv++)
45 __raw_writel(1 << lv, REGS_ICOLL_BASE + HW_ICOLL_LEVELACK);
46 __raw_writel(0, REGS_ICOLL_BASE + HW_ICOLL_VECTOR);
47
48 /* Barrier */
49 (void)__raw_readl(REGS_ICOLL_BASE + HW_ICOLL_STAT);
50}
51
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
new file mode 100644
index 000000000000..d41200382208
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/pinmux.c
@@ -0,0 +1,552 @@
1/*
2 * Freescale STMP378X/STMP378X Pin Multiplexing
3 *
4 * Author: Vladislav Buzov <vbuzov@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#define DEBUG
19#include <linux/module.h>
20#include <linux/kernel.h>
21#include <linux/errno.h>
22#include <linux/sysdev.h>
23#include <linux/string.h>
24#include <linux/bitops.h>
25#include <linux/sysdev.h>
26#include <linux/irq.h>
27
28#include <mach/hardware.h>
29#include <mach/platform.h>
30#include <mach/regs-pinctrl.h>
31#include <mach/pins.h>
32#include <mach/pinmux.h>
33
34#define NR_BANKS ARRAY_SIZE(pinmux_banks)
35static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
36 [0] = {
37 .hw_muxsel = {
38 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL0,
39 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL1,
40 },
41 .hw_drive = {
42 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE0,
43 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE1,
44 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE2,
45 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE3,
46 },
47 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL0,
48 .functions = { 0x0, 0x1, 0x2, 0x3 },
49 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
50
51 .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN0,
52 .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT0,
53 .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE0,
54 .irq = IRQ_GPIO0,
55
56 .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ0,
57 .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT0,
58 .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL0,
59 .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL0,
60 .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN0,
61 },
62 [1] = {
63 .hw_muxsel = {
64 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL2,
65 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL3,
66 },
67 .hw_drive = {
68 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE4,
69 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE5,
70 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE6,
71 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE7,
72 },
73 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL1,
74 .functions = { 0x0, 0x1, 0x2, 0x3 },
75 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
76
77 .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN1,
78 .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT1,
79 .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE1,
80 .irq = IRQ_GPIO1,
81
82 .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ1,
83 .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT1,
84 .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL1,
85 .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL1,
86 .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN1,
87 },
88 [2] = {
89 .hw_muxsel = {
90 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL4,
91 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL5,
92 },
93 .hw_drive = {
94 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE8,
95 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE9,
96 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE10,
97 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE11,
98 },
99 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL2,
100 .functions = { 0x0, 0x1, 0x2, 0x3 },
101 .strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
102
103 .hw_gpio_in = REGS_PINCTRL_BASE + HW_PINCTRL_DIN2,
104 .hw_gpio_out = REGS_PINCTRL_BASE + HW_PINCTRL_DOUT2,
105 .hw_gpio_doe = REGS_PINCTRL_BASE + HW_PINCTRL_DOE2,
106 .irq = IRQ_GPIO2,
107
108 .pin2irq = REGS_PINCTRL_BASE + HW_PINCTRL_PIN2IRQ2,
109 .irqstat = REGS_PINCTRL_BASE + HW_PINCTRL_IRQSTAT2,
110 .irqlevel = REGS_PINCTRL_BASE + HW_PINCTRL_IRQLEVEL2,
111 .irqpolarity = REGS_PINCTRL_BASE + HW_PINCTRL_IRQPOL2,
112 .irqen = REGS_PINCTRL_BASE + HW_PINCTRL_IRQEN2,
113 },
114 [3] = {
115 .hw_muxsel = {
116 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL6,
117 REGS_PINCTRL_BASE + HW_PINCTRL_MUXSEL7,
118 },
119 .hw_drive = {
120 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE12,
121 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE13,
122 REGS_PINCTRL_BASE + HW_PINCTRL_DRIVE14,
123 NULL,
124 },
125 .hw_pull = REGS_PINCTRL_BASE + HW_PINCTRL_PULL3,
126 .functions = {0x0, 0x1, 0x2, 0x3},
127 .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
128 },
129};
130
131static inline struct stmp3xxx_pinmux_bank *
132stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
133{
134 unsigned b, p;
135
136 b = STMP3XXX_PINID_TO_BANK(id);
137 p = STMP3XXX_PINID_TO_PINNUM(id);
138 BUG_ON(b >= NR_BANKS);
139 if (bank)
140 *bank = b;
141 if (pin)
142 *pin = p;
143 return &pinmux_banks[b];
144}
145
146/* Check if requested pin is owned by caller */
147static int stmp3xxx_check_pin(unsigned id, const char *label)
148{
149 unsigned pin;
150 struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
151
152 if (!test_bit(pin, &pm->pin_map)) {
153 printk(KERN_WARNING
154 "%s: Accessing free pin %x, caller %s\n",
155 __func__, id, label);
156
157 return -EINVAL;
158 }
159
160 if (label && pm->pin_labels[pin] &&
161 strcmp(label, pm->pin_labels[pin])) {
162 printk(KERN_WARNING
163 "%s: Wrong pin owner %x, caller %s owner %s\n",
164 __func__, id, label, pm->pin_labels[pin]);
165
166 return -EINVAL;
167 }
168 return 0;
169}
170
171void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
172 const char *label)
173{
174 struct stmp3xxx_pinmux_bank *pbank;
175 void __iomem *hwdrive;
176 u32 shift, val;
177 u32 bank, pin;
178
179 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
180 pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
181 bank, pin, strength);
182
183 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
184 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
185 val = pbank->strengths[strength];
186 if (val == 0xff) {
187 printk(KERN_WARNING
188 "%s: strength is not supported for bank %d, caller %s",
189 __func__, bank, label);
190 return;
191 }
192
193 if (stmp3xxx_check_pin(id, label))
194 return;
195
196 pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
197 val << shift, hwdrive);
198 stmp3xxx_clearl(HW_DRIVE_PINDRV_MASK << shift, hwdrive);
199 stmp3xxx_setl(val << shift, hwdrive);
200}
201
202void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
203 const char *label)
204{
205 struct stmp3xxx_pinmux_bank *pbank;
206 void __iomem *hwdrive;
207 u32 shift;
208 u32 bank, pin;
209
210 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
211 pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
212 bank, pin, voltage);
213
214 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
215 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
216
217 if (stmp3xxx_check_pin(id, label))
218 return;
219
220 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
221 __func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
222 if (voltage == PIN_1_8V)
223 stmp3xxx_clearl(HW_DRIVE_PINV_MASK << shift, hwdrive);
224 else
225 stmp3xxx_setl(HW_DRIVE_PINV_MASK << shift, hwdrive);
226}
227
228void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
229{
230 struct stmp3xxx_pinmux_bank *pbank;
231 void __iomem *hwpull;
232 u32 bank, pin;
233
234 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
235 pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
236 bank, pin, enable);
237
238 hwpull = pbank->hw_pull;
239
240 if (stmp3xxx_check_pin(id, label))
241 return;
242
243 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
244 __func__, 1 << pin, hwpull);
245 if (enable)
246 stmp3xxx_setl(1 << pin, hwpull);
247 else
248 stmp3xxx_clearl(1 << pin, hwpull);
249}
250
251int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
252{
253 struct stmp3xxx_pinmux_bank *pbank;
254 u32 bank, pin;
255 int ret = 0;
256
257 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
258 pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
259 bank, pin, fun);
260
261 if (test_bit(pin, &pbank->pin_map)) {
262 printk(KERN_WARNING
263 "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
264 __func__, bank, pin, label, pbank->pin_labels[pin]);
265 return -EBUSY;
266 }
267
268 set_bit(pin, &pbank->pin_map);
269 pbank->pin_labels[pin] = label;
270
271 stmp3xxx_set_pin_type(id, fun);
272
273 return ret;
274}
275
276void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
277{
278 struct stmp3xxx_pinmux_bank *pbank;
279 void __iomem *hwmux;
280 u32 shift, val;
281 u32 bank, pin;
282
283 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
284
285 hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
286 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
287
288 val = pbank->functions[fun];
289 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
290 pr_debug("%s: writing 0x%x to 0x%p register\n",
291 __func__, val << shift, hwmux);
292 stmp3xxx_clearl(HW_MUXSEL_PINFUN_MASK << shift, hwmux);
293 stmp3xxx_setl(val << shift, hwmux);
294}
295
296void stmp3xxx_release_pin(unsigned id, const char *label)
297{
298 struct stmp3xxx_pinmux_bank *pbank;
299 u32 bank, pin;
300
301 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
302 pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
303
304 if (stmp3xxx_check_pin(id, label))
305 return;
306
307 clear_bit(pin, &pbank->pin_map);
308 pbank->pin_labels[pin] = NULL;
309}
310
311int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
312{
313 struct pin_desc *pin;
314 int p;
315 int err = 0;
316
317 /* Allocate and configure pins */
318 for (p = 0; p < pin_group->nr_pins; p++) {
319 pr_debug("%s: #%d\n", __func__, p);
320 pin = &pin_group->pins[p];
321
322 err = stmp3xxx_request_pin(pin->id, pin->fun, label);
323 if (err)
324 goto out_err;
325
326 stmp3xxx_pin_strength(pin->id, pin->strength, label);
327 stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
328 stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
329 }
330
331 return 0;
332
333out_err:
334 /* Release allocated pins in case of error */
335 while (--p >= 0) {
336 pr_debug("%s: releasing #%d\n", __func__, p);
337 stmp3xxx_release_pin(pin_group->pins[p].id, label);
338 }
339 return err;
340}
341EXPORT_SYMBOL(stmp3xxx_request_pin_group);
342
343void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
344{
345 struct pin_desc *pin;
346 int p;
347
348 for (p = 0; p < pin_group->nr_pins; p++) {
349 pin = &pin_group->pins[p];
350 stmp3xxx_release_pin(pin->id, label);
351 }
352}
353EXPORT_SYMBOL(stmp3xxx_release_pin_group);
354
355static int stmp3xxx_irq_to_gpio(int irq,
356 struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
357{
358 struct stmp3xxx_pinmux_bank *pm;
359
360 for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
361 if (pm->virq <= irq && irq < pm->virq + 32) {
362 *bank = pm;
363 *gpio = irq - pm->virq;
364 return 0;
365 }
366 return -ENOENT;
367}
368
369static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
370{
371 struct stmp3xxx_pinmux_bank *pm;
372 unsigned gpio;
373 int l, p;
374
375 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
376 switch (type) {
377 case IRQ_TYPE_EDGE_RISING:
378 l = 0; p = 1; break;
379 case IRQ_TYPE_EDGE_FALLING:
380 l = 0; p = 0; break;
381 case IRQ_TYPE_LEVEL_HIGH:
382 l = 1; p = 1; break;
383 case IRQ_TYPE_LEVEL_LOW:
384 l = 1; p = 0; break;
385 default:
386 pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
387 __func__, type);
388 return -ENXIO;
389 }
390
391 if (l)
392 stmp3xxx_setl(1 << gpio, pm->irqlevel);
393 else
394 stmp3xxx_clearl(1 << gpio, pm->irqlevel);
395 if (p)
396 stmp3xxx_setl(1 << gpio, pm->irqpolarity);
397 else
398 stmp3xxx_clearl(1 << gpio, pm->irqpolarity);
399 return 0;
400}
401
402static void stmp3xxx_pin_ack_irq(unsigned irq)
403{
404 u32 stat;
405 struct stmp3xxx_pinmux_bank *pm;
406 unsigned gpio;
407
408 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
409 stat = __raw_readl(pm->irqstat) & (1 << gpio);
410 stmp3xxx_clearl(stat, pm->irqstat);
411}
412
413static void stmp3xxx_pin_mask_irq(unsigned irq)
414{
415 struct stmp3xxx_pinmux_bank *pm;
416 unsigned gpio;
417
418 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
419 stmp3xxx_clearl(1 << gpio, pm->irqen);
420 stmp3xxx_clearl(1 << gpio, pm->pin2irq);
421}
422
423static void stmp3xxx_pin_unmask_irq(unsigned irq)
424{
425 struct stmp3xxx_pinmux_bank *pm;
426 unsigned gpio;
427
428 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
429 stmp3xxx_setl(1 << gpio, pm->irqen);
430 stmp3xxx_setl(1 << gpio, pm->pin2irq);
431}
432
433static inline
434struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
435{
436 return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
437}
438
439static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
440{
441 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
442 return pm->virq + offset;
443}
444
445static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
446{
447 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
448 unsigned v;
449
450 v = __raw_readl(pm->hw_gpio_in) & (1 << offset);
451 return v ? 1 : 0;
452}
453
454static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
455{
456 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
457
458 if (v)
459 stmp3xxx_setl(1 << offset, pm->hw_gpio_out);
460 else
461 stmp3xxx_clearl(1 << offset, pm->hw_gpio_out);
462}
463
464static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
465{
466 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
467
468 stmp3xxx_setl(1 << offset, pm->hw_gpio_doe);
469 stmp3xxx_gpio_set(chip, offset, v);
470 return 0;
471}
472
473static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
474{
475 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
476
477 stmp3xxx_clearl(1 << offset, pm->hw_gpio_doe);
478 return 0;
479}
480
481static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
482{
483 return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
484}
485
486static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
487{
488 stmp3xxx_release_pin(chip->base + offset, "gpio");
489}
490
491static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
492{
493 struct stmp3xxx_pinmux_bank *pm = get_irq_data(irq);
494 int gpio_irq = pm->virq;
495 u32 stat = __raw_readl(pm->irqstat);
496
497 while (stat) {
498 if (stat & 1)
499 irq_desc[gpio_irq].handle_irq(gpio_irq,
500 &irq_desc[gpio_irq]);
501 gpio_irq++;
502 stat >>= 1;
503 }
504}
505
506static struct irq_chip gpio_irq_chip = {
507 .ack = stmp3xxx_pin_ack_irq,
508 .mask = stmp3xxx_pin_mask_irq,
509 .unmask = stmp3xxx_pin_unmask_irq,
510 .set_type = stmp3xxx_set_irqtype,
511};
512
513int __init stmp3xxx_pinmux_init(int virtual_irq_start)
514{
515 int b, r = 0;
516 struct stmp3xxx_pinmux_bank *pm;
517 int virq;
518
519 for (b = 0; b < 3; b++) {
520 /* only banks 0,1,2 are allowed to GPIO */
521 pm = pinmux_banks + b;
522 pm->chip.base = 32 * b;
523 pm->chip.ngpio = 32;
524 pm->chip.owner = THIS_MODULE;
525 pm->chip.can_sleep = 1;
526 pm->chip.exported = 1;
527 pm->chip.to_irq = stmp3xxx_gpio_to_irq;
528 pm->chip.direction_input = stmp3xxx_gpio_input;
529 pm->chip.direction_output = stmp3xxx_gpio_output;
530 pm->chip.get = stmp3xxx_gpio_get;
531 pm->chip.set = stmp3xxx_gpio_set;
532 pm->chip.request = stmp3xxx_gpio_request;
533 pm->chip.free = stmp3xxx_gpio_free;
534 pm->virq = virtual_irq_start + b * 32;
535
536 for (virq = pm->virq; virq < pm->virq; virq++) {
537 gpio_irq_chip.mask(virq);
538 set_irq_chip(virq, &gpio_irq_chip);
539 set_irq_handler(virq, handle_level_irq);
540 set_irq_flags(virq, IRQF_VALID);
541 }
542 r = gpiochip_add(&pm->chip);
543 if (r < 0)
544 break;
545 set_irq_chained_handler(pm->irq, stmp3xxx_gpio_irq);
546 set_irq_data(pm->irq, pm);
547 }
548 return r;
549}
550
551MODULE_AUTHOR("Vladislav Buzov");
552MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-stmp3xxx/timer.c b/arch/arm/plat-stmp3xxx/timer.c
new file mode 100644
index 000000000000..063c7bc0e740
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/timer.c
@@ -0,0 +1,189 @@
1/*
2 * System timer for Freescale STMP37XX/STMP378X
3 *
4 * Embedded Alley Solutions, Inc <source@embeddedalley.com>
5 *
6 * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
7 * Copyright 2008 Embedded Alley Solutions, Inc All Rights Reserved.
8 */
9
10/*
11 * The code contained herein is licensed under the GNU General Public
12 * License. You may obtain a copy of the GNU General Public License
13 * Version 2 or later at the following locations:
14 *
15 * http://www.opensource.org/licenses/gpl-license.html
16 * http://www.gnu.org/copyleft/gpl.html
17 */
18#include <linux/kernel.h>
19#include <linux/init.h>
20#include <linux/spinlock.h>
21#include <linux/clocksource.h>
22#include <linux/clockchips.h>
23#include <linux/io.h>
24#include <linux/irq.h>
25#include <linux/interrupt.h>
26
27#include <asm/mach/time.h>
28#include <mach/stmp3xxx.h>
29#include <mach/platform.h>
30#include <mach/regs-timrot.h>
31
32static irqreturn_t
33stmp3xxx_timer_interrupt(int irq, void *dev_id)
34{
35 struct clock_event_device *c = dev_id;
36
37 /* timer 0 */
38 if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0) &
39 BM_TIMROT_TIMCTRLn_IRQ) {
40 stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
41 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
42 c->event_handler(c);
43 }
44
45 /* timer 1 */
46 else if (__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1)
47 & BM_TIMROT_TIMCTRLn_IRQ) {
48 stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ,
49 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
50 stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN,
51 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
52 __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
53 }
54
55 return IRQ_HANDLED;
56}
57
58static cycle_t stmp3xxx_clock_read(struct clocksource *cs)
59{
60 return ~((__raw_readl(REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1)
61 & 0xFFFF0000) >> 16);
62}
63
64static int
65stmp3xxx_timrot_set_next_event(unsigned long delta,
66 struct clock_event_device *dev)
67{
68 /* reload the timer */
69 __raw_writel(delta, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
70 return 0;
71}
72
73static void
74stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
75 struct clock_event_device *dev)
76{
77}
78
79static struct clock_event_device ckevt_timrot = {
80 .name = "timrot",
81 .features = CLOCK_EVT_FEAT_ONESHOT,
82 .shift = 32,
83 .set_next_event = stmp3xxx_timrot_set_next_event,
84 .set_mode = stmp3xxx_timrot_set_mode,
85};
86
87static struct clocksource cksrc_stmp3xxx = {
88 .name = "cksrc_stmp3xxx",
89 .rating = 250,
90 .read = stmp3xxx_clock_read,
91 .mask = CLOCKSOURCE_MASK(16),
92 .shift = 10,
93 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
94};
95
96static struct irqaction stmp3xxx_timer_irq = {
97 .name = "stmp3xxx_timer",
98 .flags = IRQF_DISABLED | IRQF_TIMER,
99 .handler = stmp3xxx_timer_interrupt,
100 .dev_id = &ckevt_timrot,
101};
102
103
104/*
105 * Set up timer interrupt, and return the current time in seconds.
106 */
107static void __init stmp3xxx_init_timer(void)
108{
109 cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
110 cksrc_stmp3xxx.shift);
111 ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
112 ckevt_timrot.shift);
113 ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
114 ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
115 ckevt_timrot.cpumask = cpumask_of(0);
116
117 stmp3xxx_reset_block(REGS_TIMROT_BASE, false);
118
119 /* clear two timers */
120 __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
121 __raw_writel(0, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
122
123 /* configure them */
124 __raw_writel(
125 (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */
126 BM_TIMROT_TIMCTRLn_RELOAD |
127 BM_TIMROT_TIMCTRLn_UPDATE |
128 BM_TIMROT_TIMCTRLn_IRQ_EN,
129 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
130 __raw_writel(
131 (8 << BP_TIMROT_TIMCTRLn_SELECT) | /* 32 kHz */
132 BM_TIMROT_TIMCTRLn_RELOAD |
133 BM_TIMROT_TIMCTRLn_UPDATE |
134 BM_TIMROT_TIMCTRLn_IRQ_EN,
135 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
136
137 __raw_writel(CLOCK_TICK_RATE / HZ - 1,
138 REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
139 __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
140
141 setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
142
143 clocksource_register(&cksrc_stmp3xxx);
144 clockevents_register_device(&ckevt_timrot);
145}
146
147#ifdef CONFIG_PM
148
149void stmp3xxx_suspend_timer(void)
150{
151 stmp3xxx_clearl(BM_TIMROT_TIMCTRLn_IRQ_EN | BM_TIMROT_TIMCTRLn_IRQ,
152 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
153 stmp3xxx_setl(BM_TIMROT_ROTCTRL_CLKGATE,
154 REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
155}
156
157void stmp3xxx_resume_timer(void)
158{
159 stmp3xxx_clearl(BM_TIMROT_ROTCTRL_SFTRST | BM_TIMROT_ROTCTRL_CLKGATE,
160 REGS_TIMROT_BASE + HW_TIMROT_ROTCTRL);
161 __raw_writel(
162 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */
163 BM_TIMROT_TIMCTRLn_RELOAD |
164 BM_TIMROT_TIMCTRLn_UPDATE |
165 BM_TIMROT_TIMCTRLn_IRQ_EN,
166 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL0);
167 __raw_writel(
168 8 << BP_TIMROT_TIMCTRLn_SELECT | /* 32 kHz */
169 BM_TIMROT_TIMCTRLn_RELOAD |
170 BM_TIMROT_TIMCTRLn_UPDATE |
171 BM_TIMROT_TIMCTRLn_IRQ_EN,
172 REGS_TIMROT_BASE + HW_TIMROT_TIMCTRL1);
173 __raw_writel(CLOCK_TICK_RATE / HZ - 1,
174 REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT0);
175 __raw_writel(0xFFFF, REGS_TIMROT_BASE + HW_TIMROT_TIMCOUNT1);
176}
177
178#else
179
180#define stmp3xxx_suspend_timer NULL
181#define stmp3xxx_resume_timer NULL
182
183#endif /* CONFIG_PM */
184
185struct sys_timer stmp3xxx_timer = {
186 .init = stmp3xxx_init_timer,
187 .suspend = stmp3xxx_suspend_timer,
188 .resume = stmp3xxx_resume_timer,
189};