aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authordmitry pervushin <dpervushin@embeddedalley.com>2009-04-23 07:24:13 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-04-27 05:28:08 -0400
commit5cccd37ea15970846a93b4b01fafd6e043bafe8e (patch)
tree4ab99b59f91964028fbba128d8ae086f60bd8c82 /arch/arm
parente317872ac532fd845c597e55ceb5a9bceee878c1 (diff)
[ARM] 5477/1: Freescale STMP platform support [6/10]
Sources: common STMP3xxx platform support Signed-off-by: dmitry pervushin <dpervushin@embeddedalley.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/plat-stmp3xxx/Kconfig37
-rw-r--r--arch/arm/plat-stmp3xxx/Makefile5
-rw-r--r--arch/arm/plat-stmp3xxx/clock.c1112
-rw-r--r--arch/arm/plat-stmp3xxx/clock.h61
-rw-r--r--arch/arm/plat-stmp3xxx/core.c127
-rw-r--r--arch/arm/plat-stmp3xxx/dma.c462
-rw-r--r--arch/arm/plat-stmp3xxx/irq.c59
-rw-r--r--arch/arm/plat-stmp3xxx/pinmux.c545
-rw-r--r--arch/arm/plat-stmp3xxx/timer.c172
9 files changed, 2580 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..b63480066d6b
--- /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
diff --git a/arch/arm/plat-stmp3xxx/clock.c b/arch/arm/plat-stmp3xxx/clock.c
new file mode 100644
index 000000000000..9a1d46b470cd
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/clock.c
@@ -0,0 +1,1112 @@
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#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/clk.h>
22#include <linux/spinlock.h>
23#include <linux/errno.h>
24#include <linux/err.h>
25#include <linux/delay.h>
26#include <linux/io.h>
27
28#include <asm/mach-types.h>
29#include <asm/clkdev.h>
30#include <mach/regs-clkctrl.h>
31
32#include "clock.h"
33
34static DEFINE_SPINLOCK(clocks_lock);
35
36static struct clk osc_24M;
37static struct clk pll_clk;
38static struct clk cpu_clk;
39static struct clk hclk;
40
41static int propagate_rate(struct clk *);
42
43static inline int clk_is_busy(struct clk *clk)
44{
45 return __raw_readl(clk->busy_reg) & (1 << clk->busy_bit);
46}
47
48static inline int clk_good(struct clk *clk)
49{
50 return clk && !IS_ERR(clk) && clk->ops;
51}
52
53static int std_clk_enable(struct clk *clk)
54{
55 if (clk->enable_reg) {
56 u32 clk_reg = __raw_readl(clk->enable_reg);
57 if (clk->enable_negate)
58 clk_reg &= ~(1 << clk->enable_shift);
59 else
60 clk_reg |= (1 << clk->enable_shift);
61 __raw_writel(clk_reg, clk->enable_reg);
62 if (clk->enable_wait)
63 udelay(clk->enable_wait);
64 return 0;
65 } else
66 return -EINVAL;
67}
68
69static int std_clk_disable(struct clk *clk)
70{
71 if (clk->enable_reg) {
72 u32 clk_reg = __raw_readl(clk->enable_reg);
73 if (clk->enable_negate)
74 clk_reg |= (1 << clk->enable_shift);
75 else
76 clk_reg &= ~(1 << clk->enable_shift);
77 __raw_writel(clk_reg, clk->enable_reg);
78 return 0;
79 } else
80 return -EINVAL;
81}
82
83static int io_set_rate(struct clk *clk, u32 rate)
84{
85 u32 reg_frac, clkctrl_frac;
86 int i, ret = 0, mask = 0x1f;
87
88 clkctrl_frac = (clk->parent->rate * 18 + rate - 1) / rate;
89
90 if (clkctrl_frac < 18 || clkctrl_frac > 35) {
91 ret = -EINVAL;
92 goto out;
93 }
94
95 reg_frac = __raw_readl(clk->scale_reg);
96 reg_frac &= ~(mask << clk->scale_shift);
97 __raw_writel(reg_frac | (clkctrl_frac << clk->scale_shift),
98 clk->scale_reg);
99 if (clk->busy_reg) {
100 for (i = 10000; i; i--)
101 if (!clk_is_busy(clk))
102 break;
103 if (!i)
104 ret = -ETIMEDOUT;
105 else
106 ret = 0;
107 }
108out:
109 return ret;
110}
111
112static long io_get_rate(struct clk *clk)
113{
114 long rate = clk->parent->rate * 18;
115 int mask = 0x1f;
116
117 rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
118 clk->rate = rate;
119
120 return rate;
121}
122
123static long per_get_rate(struct clk *clk)
124{
125 long rate = clk->parent->rate;
126 long div;
127 const int mask = 0xff;
128
129 if (clk->enable_reg &&
130 !(__raw_readl(clk->enable_reg) & clk->enable_shift))
131 clk->rate = 0;
132 else {
133 div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
134 if (div)
135 rate /= div;
136 clk->rate = rate;
137 }
138
139 return clk->rate;
140}
141
142static int per_set_rate(struct clk *clk, u32 rate)
143{
144 int ret = -EINVAL;
145 int div = (clk->parent->rate + rate - 1) / rate;
146 u32 reg_frac;
147 const int mask = 0xff;
148 int try = 10;
149 int i = -1;
150
151 if (div == 0 || div > mask)
152 goto out;
153
154 reg_frac = __raw_readl(clk->scale_reg);
155 reg_frac &= ~(mask << clk->scale_shift);
156
157 while (try--) {
158 __raw_writel(reg_frac | (div << clk->scale_shift),
159 clk->scale_reg);
160
161 if (clk->busy_reg) {
162 for (i = 10000; i; i--)
163 if (!clk_is_busy(clk))
164 break;
165 }
166 if (i)
167 break;
168 }
169
170 if (!i)
171 ret = -ETIMEDOUT;
172 else
173 ret = 0;
174
175out:
176 if (ret != 0)
177 printk(KERN_ERR "%s: error %d\n", __func__, ret);
178 return ret;
179}
180
181static long lcdif_get_rate(struct clk *clk)
182{
183 long rate = clk->parent->rate;
184 long div;
185 const int mask = 0xff;
186
187 div = (__raw_readl(clk->scale_reg) >> clk->scale_shift) & mask;
188 if (div) {
189 rate /= div;
190 div = (HW_CLKCTRL_FRAC_RD() & BM_CLKCTRL_FRAC_PIXFRAC) >>
191 BP_CLKCTRL_FRAC_PIXFRAC;
192 rate /= div;
193 }
194 clk->rate = rate;
195
196 return rate;
197}
198
199static int lcdif_set_rate(struct clk *clk, u32 rate)
200{
201 int ret = 0;
202 /*
203 * On 3700, we can get most timings exact by modifying ref_pix
204 * and the divider, but keeping the phase timings at 1 (2
205 * phases per cycle).
206 *
207 * ref_pix can be between 480e6*18/35=246.9MHz and 480e6*18/18=480MHz,
208 * which is between 18/(18*480e6)=2.084ns and 35/(18*480e6)=4.050ns.
209 *
210 * ns_cycle >= 2*18e3/(18*480) = 25/6
211 * ns_cycle <= 2*35e3/(18*480) = 875/108
212 *
213 * Multiply the ns_cycle by 'div' to lengthen it until it fits the
214 * bounds. This is the divider we'll use after ref_pix.
215 *
216 * 6 * ns_cycle >= 25 * div
217 * 108 * ns_cycle <= 875 * div
218 */
219 u32 ns_cycle = 1000000 / rate;
220 u32 div, reg_val;
221 u32 lowest_result = (u32) -1;
222 u32 lowest_div = 0, lowest_fracdiv = 0;
223
224 for (div = 1; div < 256; ++div) {
225 u32 fracdiv;
226 u32 ps_result;
227 int lower_bound = 6 * ns_cycle >= 25 * div;
228 int upper_bound = 108 * ns_cycle <= 875 * div;
229 if (!lower_bound)
230 break;
231 if (!upper_bound)
232 continue;
233 /*
234 * Found a matching div. Calculate fractional divider needed,
235 * rounded up.
236 */
237 fracdiv = ((clk->parent->rate / 1000 * 18 / 2) *
238 ns_cycle + 1000 * div - 1) /
239 (1000 * div);
240 if (fracdiv < 18 || fracdiv > 35) {
241 ret = -EINVAL;
242 goto out;
243 }
244 /* Calculate the actual cycle time this results in */
245 ps_result = 6250 * div * fracdiv / 27;
246
247 /* Use the fastest result that doesn't break ns_cycle */
248 if (ps_result <= lowest_result) {
249 lowest_result = ps_result;
250 lowest_div = div;
251 lowest_fracdiv = fracdiv;
252 }
253 }
254
255 if (div >= 256 || lowest_result == (u32) -1) {
256 ret = -EINVAL;
257 goto out;
258 }
259 pr_debug("Programming PFD=%u,DIV=%u ref_pix=%uMHz "
260 "PIXCLK=%uMHz cycle=%u.%03uns\n",
261 lowest_fracdiv, lowest_div,
262 480*18/lowest_fracdiv, 480*18/lowest_fracdiv/lowest_div,
263 lowest_result / 1000, lowest_result % 1000);
264
265 /* Program ref_pix phase fractional divider */
266 HW_CLKCTRL_FRAC_WR((HW_CLKCTRL_FRAC_RD() & ~BM_CLKCTRL_FRAC_PIXFRAC) |
267 BF_CLKCTRL_FRAC_PIXFRAC(lowest_fracdiv));
268 /* Ungate PFD */
269 HW_CLKCTRL_FRAC_CLR(BM_CLKCTRL_FRAC_CLKGATEPIX);
270
271 /* Program pix divider */
272 reg_val = __raw_readl(clk->scale_reg);
273 reg_val &= ~(BM_CLKCTRL_PIX_DIV | BM_CLKCTRL_PIX_CLKGATE);
274 reg_val |= BF_CLKCTRL_PIX_DIV(lowest_div);
275 __raw_writel(reg_val, clk->scale_reg);
276
277 /* Wait for divider update */
278 if (clk->busy_reg) {
279 int i;
280 for (i = 10000; i; i--)
281 if (!clk_is_busy(clk))
282 break;
283 if (!i) {
284 ret = -ETIMEDOUT;
285 goto out;
286 }
287 }
288
289 /* Switch to ref_pix source */
290 HW_CLKCTRL_CLKSEQ_CLR(BM_CLKCTRL_CLKSEQ_BYPASS_PIX);
291
292out:
293 return ret;
294}
295
296
297static int cpu_set_rate(struct clk *clk, u32 rate)
298{
299 if (rate < 24000)
300 return -EINVAL;
301 else if (rate == 24000) {
302 /* switch to the 24M source */
303 clk_set_parent(clk, &osc_24M);
304 } else {
305 int i;
306 u32 clkctrl_cpu = 1;
307 u32 c = clkctrl_cpu;
308 u32 clkctrl_frac = 1;
309 u32 val;
310 for ( ; c < 0x40; c++) {
311 u32 f = (pll_clk.rate*18/c + rate/2) / rate;
312 int s1, s2;
313
314 if (f < 18 || f > 35)
315 continue;
316 s1 = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu - rate;
317 s2 = pll_clk.rate*18/c/f - rate;
318 pr_debug("%s: s1 %d, s2 %d\n", __func__, s1, s2);
319 if (abs(s1) > abs(s2)) {
320 clkctrl_cpu = c;
321 clkctrl_frac = f;
322 }
323 if (s2 == 0)
324 break;
325 };
326 pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
327 clkctrl_cpu, clkctrl_frac);
328 if (c == 0x40) {
329 int d = pll_clk.rate*18/clkctrl_frac/clkctrl_cpu -
330 rate;
331 if (abs(d) > 100 ||
332 clkctrl_frac < 18 || clkctrl_frac > 35)
333 return -EINVAL;
334 }
335
336 /* 4.6.2 */
337 val = __raw_readl(clk->scale_reg);
338 val &= ~(0x3f << clk->scale_shift);
339 val |= clkctrl_frac;
340 clk_set_parent(clk, &osc_24M);
341 udelay(10);
342 __raw_writel(val, clk->scale_reg);
343 /* ungate */
344 __raw_writel(1<<7, clk->scale_reg + 8);
345 /* write clkctrl_cpu */
346 clk->saved_div = clkctrl_cpu;
347 HW_CLKCTRL_CPU_WR((HW_CLKCTRL_CPU_RD() & ~0x3f) | clkctrl_cpu);
348 for (i = 10000; i; i--)
349 if (!clk_is_busy(clk))
350 break;
351 if (!i) {
352 printk(KERN_ERR "couldn't set up CPU divisor\n");
353 return -ETIMEDOUT;
354 }
355 clk_set_parent(clk, &pll_clk);
356 clk->saved_div = 0;
357 udelay(10);
358 }
359 return 0;
360}
361
362static long cpu_get_rate(struct clk *clk)
363{
364 long rate = clk->parent->rate * 18;
365
366 rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
367 rate /= HW_CLKCTRL_CPU_RD() & 0x3f;
368 rate = ((rate + 9) / 10) * 10;
369 clk->rate = rate;
370
371 return rate;
372}
373
374static long cpu_round_rate(struct clk *clk, u32 rate)
375{
376 unsigned long r = 0;
377
378 if (rate <= 24000)
379 r = 24000;
380 else {
381 u32 clkctrl_cpu = 1;
382 u32 clkctrl_frac;
383 do {
384 clkctrl_frac =
385 (pll_clk.rate*18 / clkctrl_cpu + rate/2) / rate;
386 if (clkctrl_frac > 35)
387 continue;
388 if (pll_clk.rate*18 / clkctrl_frac / clkctrl_cpu/10 ==
389 rate / 10)
390 break;
391 } while (pll_clk.rate / 2 >= clkctrl_cpu++ * rate);
392 if (pll_clk.rate / 2 < (clkctrl_cpu - 1) * rate)
393 clkctrl_cpu--;
394 pr_debug("%s: clkctrl_cpu %d, clkctrl_frac %d\n", __func__,
395 clkctrl_cpu, clkctrl_frac);
396 if (clkctrl_frac < 18)
397 clkctrl_frac = 18;
398 if (clkctrl_frac > 35)
399 clkctrl_frac = 35;
400
401 r = pll_clk.rate * 18;
402 r /= clkctrl_frac;
403 r /= clkctrl_cpu;
404 r = 10 * ((r + 9) / 10);
405 }
406 return r;
407}
408
409static long emi_get_rate(struct clk *clk)
410{
411 long rate = clk->parent->rate * 18;
412
413 rate /= (__raw_readl(clk->scale_reg) >> clk->scale_shift) & 0x3f;
414 rate /= HW_CLKCTRL_EMI_RD() & 0x3f;
415 clk->rate = rate;
416
417 return rate;
418}
419
420static int clkseq_set_parent(struct clk *clk, struct clk *parent)
421{
422 int ret = -EINVAL;
423 int shift = 8;
424
425 /* bypass? */
426 if (parent == &osc_24M)
427 shift = 4;
428
429 if (clk->bypass_reg) {
430 u32 hbus_mask = BM_CLKCTRL_HBUS_DIV_FRAC_EN |
431 BM_CLKCTRL_HBUS_DIV;
432
433 if (clk == &cpu_clk && shift == 4) {
434 u32 hbus_val = HW_CLKCTRL_HBUS_RD();
435 u32 cpu_val = HW_CLKCTRL_CPU_RD();
436 hbus_val &= ~hbus_mask;
437 hbus_val |= 1;
438 clk->saved_div = cpu_val & BM_CLKCTRL_CPU_DIV_CPU;
439 cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
440 cpu_val |= 1;
441 __raw_writel(1 << clk->bypass_shift,
442 clk->bypass_reg + shift);
443 if (machine_is_stmp378x()) {
444 HW_CLKCTRL_HBUS_WR(hbus_val);
445 HW_CLKCTRL_CPU_WR(cpu_val);
446 hclk.rate = 0;
447 }
448 } else if (clk == &cpu_clk && shift == 8) {
449 u32 hbus_val = HW_CLKCTRL_HBUS_RD();
450 u32 cpu_val = HW_CLKCTRL_CPU_RD();
451 hbus_val &= ~hbus_mask;
452 hbus_val |= 2;
453 cpu_val &= ~BM_CLKCTRL_CPU_DIV_CPU;
454 if (clk->saved_div)
455 cpu_val |= clk->saved_div;
456 else
457 cpu_val |= 2;
458 if (machine_is_stmp378x()) {
459 HW_CLKCTRL_HBUS_WR(hbus_val);
460 HW_CLKCTRL_CPU_WR(cpu_val);
461 hclk.rate = 0;
462 }
463 __raw_writel(1 << clk->bypass_shift,
464 clk->bypass_reg + shift);
465 } else
466 __raw_writel(1 << clk->bypass_shift,
467 clk->bypass_reg + shift);
468
469 ret = 0;
470 }
471
472 return ret;
473}
474
475static int hbus_set_rate(struct clk *clk, u32 rate)
476{
477 u8 div = 0;
478 int is_frac = 0;
479 u32 clkctrl_hbus;
480 struct clk *parent = clk->parent;
481
482 pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
483 parent->rate);
484
485 if (rate > parent->rate)
486 return -EINVAL;
487
488 if (((parent->rate + rate/2) / rate) * rate != parent->rate &&
489 parent->rate / rate < 32) {
490 pr_debug("%s: switching to fractional mode\n", __func__);
491 is_frac = 1;
492 }
493
494 if (is_frac)
495 div = (32 * rate + parent->rate / 2) / parent->rate;
496 else
497 div = (parent->rate + rate - 1) / rate;
498 pr_debug("%s: div calculated is %d\n", __func__, div);
499 if (!div || div > 0x1f)
500 return -EINVAL;
501
502 clk_set_parent(&cpu_clk, &osc_24M);
503 udelay(10);
504 clkctrl_hbus = __raw_readl(clk->scale_reg);
505 clkctrl_hbus &= ~0x3f;
506 clkctrl_hbus |= div;
507 clkctrl_hbus |= (is_frac << 5);
508
509 __raw_writel(clkctrl_hbus, clk->scale_reg);
510 if (clk->busy_reg) {
511 int i;
512 for (i = 10000; i; i--)
513 if (!clk_is_busy(clk))
514 break;
515 if (!i) {
516 printk(KERN_ERR "couldn't set up CPU divisor\n");
517 return -ETIMEDOUT;
518 }
519 }
520 clk_set_parent(&cpu_clk, &pll_clk);
521 __raw_writel(clkctrl_hbus, clk->scale_reg);
522 udelay(10);
523 return 0;
524}
525
526static long hbus_get_rate(struct clk *clk)
527{
528 long rate = clk->parent->rate;
529
530 if (__raw_readl(clk->scale_reg) & 0x20) {
531 rate *= __raw_readl(clk->scale_reg) & 0x1f;
532 rate /= 32;
533 } else
534 rate /= __raw_readl(clk->scale_reg) & 0x1f;
535 clk->rate = rate;
536
537 return rate;
538}
539
540static int xbus_set_rate(struct clk *clk, u32 rate)
541{
542 u16 div = 0;
543 u32 clkctrl_xbus;
544
545 pr_debug("%s: rate %d, parent rate %d\n", __func__, rate,
546 clk->parent->rate);
547
548 div = (clk->parent->rate + rate - 1) / rate;
549 pr_debug("%s: div calculated is %d\n", __func__, div);
550 if (!div || div > 0x3ff)
551 return -EINVAL;
552
553 clkctrl_xbus = __raw_readl(clk->scale_reg);
554 clkctrl_xbus &= ~0x3ff;
555 clkctrl_xbus |= div;
556 __raw_writel(clkctrl_xbus, clk->scale_reg);
557 if (clk->busy_reg) {
558 int i;
559 for (i = 10000; i; i--)
560 if (!clk_is_busy(clk))
561 break;
562 if (!i) {
563 printk(KERN_ERR "couldn't set up xbus divisor\n");
564 return -ETIMEDOUT;
565 }
566 }
567 return 0;
568}
569
570static long xbus_get_rate(struct clk *clk)
571{
572 long rate = clk->parent->rate;
573
574 rate /= __raw_readl(clk->scale_reg) & 0x3ff;
575 clk->rate = rate;
576
577 return rate;
578}
579
580
581/* Clock ops */
582
583static struct clk_ops std_ops = {
584 .enable = std_clk_enable,
585 .disable = std_clk_disable,
586 .get_rate = per_get_rate,
587 .set_rate = per_set_rate,
588 .set_parent = clkseq_set_parent,
589};
590
591static struct clk_ops min_ops = {
592 .enable = std_clk_enable,
593 .disable = std_clk_disable,
594};
595
596static struct clk_ops cpu_ops = {
597 .enable = std_clk_enable,
598 .disable = std_clk_disable,
599 .get_rate = cpu_get_rate,
600 .set_rate = cpu_set_rate,
601 .round_rate = cpu_round_rate,
602 .set_parent = clkseq_set_parent,
603};
604
605static struct clk_ops io_ops = {
606 .enable = std_clk_enable,
607 .disable = std_clk_disable,
608 .get_rate = io_get_rate,
609 .set_rate = io_set_rate,
610};
611
612static struct clk_ops hbus_ops = {
613 .get_rate = hbus_get_rate,
614 .set_rate = hbus_set_rate,
615};
616
617static struct clk_ops xbus_ops = {
618 .get_rate = xbus_get_rate,
619 .set_rate = xbus_set_rate,
620};
621
622static struct clk_ops lcdif_ops = {
623 .enable = std_clk_enable,
624 .disable = std_clk_disable,
625 .get_rate = lcdif_get_rate,
626 .set_rate = lcdif_set_rate,
627 .set_parent = clkseq_set_parent,
628};
629
630static struct clk_ops emi_ops = {
631 .get_rate = emi_get_rate,
632};
633
634/* List of on-chip clocks */
635
636static struct clk osc_24M = {
637 .flags = FIXED_RATE | ENABLED,
638 .rate = 24000,
639};
640
641static struct clk pll_clk = {
642 .parent = &osc_24M,
643 .enable_reg = HW_CLKCTRL_PLLCTRL0_ADDR,
644 .enable_shift = 16,
645 .enable_wait = 10,
646 .flags = FIXED_RATE | ENABLED,
647 .rate = 480000,
648 .ops = &min_ops,
649};
650
651static struct clk cpu_clk = {
652 .parent = &pll_clk,
653 .scale_reg = HW_CLKCTRL_FRAC_ADDR,
654 .scale_shift = 0,
655 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
656 .bypass_shift = 7,
657 .busy_reg = HW_CLKCTRL_CPU_ADDR,
658 .busy_bit = 28,
659 .flags = RATE_PROPAGATES | ENABLED,
660 .ops = &cpu_ops,
661};
662
663static struct clk io_clk = {
664 .parent = &pll_clk,
665 .enable_reg = HW_CLKCTRL_FRAC_ADDR,
666 .enable_shift = 31,
667 .enable_negate = 1,
668 .scale_reg = HW_CLKCTRL_FRAC_ADDR,
669 .scale_shift = 24,
670 .flags = RATE_PROPAGATES | ENABLED,
671 .ops = &io_ops,
672};
673
674static struct clk hclk = {
675 .parent = &cpu_clk,
676 .scale_reg = HW_CLKCTRL_HBUS_ADDR,
677 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
678 .bypass_shift = 7,
679 .busy_reg = HW_CLKCTRL_HBUS_ADDR,
680 .busy_bit = 29,
681 .flags = RATE_PROPAGATES | ENABLED,
682 .ops = &hbus_ops,
683};
684
685static struct clk xclk = {
686 .parent = &osc_24M,
687 .scale_reg = HW_CLKCTRL_XBUS_ADDR,
688 .busy_reg = HW_CLKCTRL_XBUS_ADDR,
689 .busy_bit = 31,
690 .flags = RATE_PROPAGATES | ENABLED,
691 .ops = &xbus_ops,
692};
693
694static struct clk uart_clk = {
695 .parent = &xclk,
696 .enable_reg = HW_CLKCTRL_XTAL_ADDR,
697 .enable_shift = 31,
698 .enable_negate = 1,
699 .flags = ENABLED,
700 .ops = &min_ops,
701};
702
703static struct clk audio_clk = {
704 .parent = &xclk,
705 .enable_reg = HW_CLKCTRL_XTAL_ADDR,
706 .enable_shift = 30,
707 .enable_negate = 1,
708 .ops = &min_ops,
709};
710
711static struct clk pwm_clk = {
712 .parent = &xclk,
713 .enable_reg = HW_CLKCTRL_XTAL_ADDR,
714 .enable_shift = 29,
715 .enable_negate = 1,
716 .ops = &min_ops,
717};
718
719static struct clk dri_clk = {
720 .parent = &xclk,
721 .enable_reg = HW_CLKCTRL_XTAL_ADDR,
722 .enable_shift = 28,
723 .enable_negate = 1,
724 .ops = &min_ops,
725};
726
727static struct clk digctl_clk = {
728 .parent = &xclk,
729 .enable_reg = HW_CLKCTRL_XTAL_ADDR,
730 .enable_shift = 27,
731 .enable_negate = 1,
732 .ops = &min_ops,
733};
734
735static struct clk timer_clk = {
736 .parent = &xclk,
737 .enable_reg = HW_CLKCTRL_XTAL_ADDR,
738 .enable_shift = 26,
739 .enable_negate = 1,
740 .flags = ENABLED,
741 .ops = &min_ops,
742};
743
744static struct clk lcdif_clk = {
745 .parent = &pll_clk,
746 .scale_reg = HW_CLKCTRL_PIX_ADDR,
747 .busy_reg = HW_CLKCTRL_PIX_ADDR,
748 .busy_bit = 29,
749 .enable_reg = HW_CLKCTRL_PIX_ADDR,
750 .enable_shift = 31,
751 .enable_negate = 1,
752 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
753 .bypass_shift = 1,
754 .flags = NEEDS_SET_PARENT,
755 .ops = &lcdif_ops,
756};
757
758static struct clk ssp_clk = {
759 .parent = &io_clk,
760 .scale_reg = HW_CLKCTRL_SSP_ADDR,
761 .busy_reg = HW_CLKCTRL_SSP_ADDR,
762 .busy_bit = 29,
763 .enable_reg = HW_CLKCTRL_SSP_ADDR,
764 .enable_shift = 31,
765 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
766 .bypass_shift = 5,
767 .enable_negate = 1,
768 .flags = NEEDS_SET_PARENT,
769 .ops = &std_ops,
770};
771
772static struct clk gpmi_clk = {
773 .parent = &io_clk,
774 .scale_reg = HW_CLKCTRL_GPMI_ADDR,
775 .busy_reg = HW_CLKCTRL_GPMI_ADDR,
776 .busy_bit = 29,
777 .enable_reg = HW_CLKCTRL_GPMI_ADDR,
778 .enable_shift = 31,
779 .enable_negate = 1,
780 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
781 .bypass_shift = 4,
782 .flags = NEEDS_SET_PARENT,
783 .ops = &std_ops,
784};
785
786static struct clk spdif_clk = {
787 .parent = &pll_clk,
788 .enable_reg = HW_CLKCTRL_SPDIF_ADDR,
789 .enable_shift = 31,
790 .enable_negate = 1,
791 .ops = &min_ops,
792};
793
794static struct clk emi_clk = {
795 .parent = &pll_clk,
796 .enable_reg = HW_CLKCTRL_EMI_ADDR,
797 .enable_shift = 31,
798 .enable_negate = 1,
799 .scale_reg = HW_CLKCTRL_FRAC_ADDR,
800 .scale_shift = 8,
801 .busy_reg = HW_CLKCTRL_EMI_ADDR,
802 .busy_bit = 28,
803 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
804 .bypass_shift = 6,
805 .flags = ENABLED,
806 .ops = &emi_ops,
807};
808
809static struct clk ir_clk = {
810 .parent = &io_clk,
811 .enable_reg = HW_CLKCTRL_IR_ADDR,
812 .enable_shift = 31,
813 .enable_negate = 1,
814 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
815 .bypass_shift = 3,
816 .ops = &min_ops,
817};
818
819static struct clk saif_clk = {
820 .parent = &pll_clk,
821 .scale_reg = HW_CLKCTRL_SAIF_ADDR,
822 .busy_reg = HW_CLKCTRL_SAIF_ADDR,
823 .busy_bit = 29,
824 .enable_reg = HW_CLKCTRL_SAIF_ADDR,
825 .enable_shift = 31,
826 .enable_negate = 1,
827 .bypass_reg = HW_CLKCTRL_CLKSEQ_ADDR,
828 .bypass_shift = 0,
829 .ops = &std_ops,
830};
831
832static struct clk usb_clk = {
833 .parent = &pll_clk,
834 .enable_reg = HW_CLKCTRL_PLLCTRL0_ADDR,
835 .enable_shift = 18,
836 .enable_negate = 1,
837 .ops = &min_ops,
838};
839
840/* list of all the clocks */
841static __initdata struct clk_lookup onchip_clks[] = {
842 {
843 .con_id = "osc_24M",
844 .clk = &osc_24M,
845 }, {
846 .con_id = "pll",
847 .clk = &pll_clk,
848 }, {
849 .con_id = "cpu",
850 .clk = &cpu_clk,
851 }, {
852 .con_id = "hclk",
853 .clk = &hclk,
854 }, {
855 .con_id = "xclk",
856 .clk = &xclk,
857 }, {
858 .con_id = "io",
859 .clk = &io_clk,
860 }, {
861 .con_id = "uart",
862 .clk = &uart_clk,
863 }, {
864 .con_id = "audio",
865 .clk = &audio_clk,
866 }, {
867 .con_id = "pwm",
868 .clk = &pwm_clk,
869 }, {
870 .con_id = "dri",
871 .clk = &dri_clk,
872 }, {
873 .con_id = "digctl",
874 .clk = &digctl_clk,
875 }, {
876 .con_id = "timer",
877 .clk = &timer_clk,
878 }, {
879 .con_id = "lcdif",
880 .clk = &lcdif_clk,
881 }, {
882 .con_id = "ssp",
883 .clk = &ssp_clk,
884 }, {
885 .con_id = "gpmi",
886 .clk = &gpmi_clk,
887 }, {
888 .con_id = "spdif",
889 .clk = &spdif_clk,
890 }, {
891 .con_id = "emi",
892 .clk = &emi_clk,
893 }, {
894 .con_id = "ir",
895 .clk = &ir_clk,
896 }, {
897 .con_id = "saif",
898 .clk = &saif_clk,
899 }, {
900 .con_id = "usb",
901 .clk = &usb_clk,
902 },
903};
904
905static int __init propagate_rate(struct clk *clk)
906{
907 struct clk_lookup *cl;
908
909 for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
910 cl++) {
911 if (unlikely(!clk_good(cl->clk)))
912 continue;
913 if (cl->clk->parent == clk && cl->clk->ops->get_rate) {
914 cl->clk->ops->get_rate(cl->clk);
915 if (cl->clk->flags & RATE_PROPAGATES)
916 propagate_rate(cl->clk);
917 }
918 }
919
920 return 0;
921}
922
923/* Exported API */
924unsigned long clk_get_rate(struct clk *clk)
925{
926 if (unlikely(!clk_good(clk)))
927 return 0;
928
929 if (clk->rate != 0)
930 return clk->rate;
931
932 if (clk->ops->get_rate != NULL)
933 return clk->ops->get_rate(clk);
934
935 return clk_get_rate(clk->parent);
936}
937EXPORT_SYMBOL(clk_get_rate);
938
939long clk_round_rate(struct clk *clk, unsigned long rate)
940{
941 if (unlikely(!clk_good(clk)))
942 return 0;
943
944 if (clk->ops->round_rate)
945 return clk->ops->round_rate(clk, rate);
946
947 return 0;
948}
949EXPORT_SYMBOL(clk_round_rate);
950
951static inline int close_enough(long rate1, long rate2)
952{
953 return rate1 && !((rate2 - rate1) * 1000 / rate1);
954}
955
956int clk_set_rate(struct clk *clk, unsigned long rate)
957{
958 int ret = -EINVAL;
959
960 if (unlikely(!clk_good(clk)))
961 goto out;
962
963 if (clk->flags & FIXED_RATE || !clk->ops->set_rate)
964 goto out;
965
966 else if (!close_enough(clk->rate, rate)) {
967 ret = clk->ops->set_rate(clk, rate);
968 if (ret < 0)
969 goto out;
970 clk->rate = rate;
971 if (clk->flags & RATE_PROPAGATES)
972 propagate_rate(clk);
973 } else
974 ret = 0;
975
976out:
977 return ret;
978}
979EXPORT_SYMBOL(clk_set_rate);
980
981int clk_enable(struct clk *clk)
982{
983 unsigned long clocks_flags;
984
985 if (unlikely(!clk_good(clk)))
986 return -EINVAL;
987
988 if (clk->parent)
989 clk_enable(clk->parent);
990
991 spin_lock_irqsave(&clocks_lock, clocks_flags);
992
993 clk->usage++;
994 if (clk->ops && clk->ops->enable)
995 clk->ops->enable(clk);
996
997 spin_unlock_irqrestore(&clocks_lock, clocks_flags);
998 return 0;
999}
1000EXPORT_SYMBOL(clk_enable);
1001
1002static void local_clk_disable(struct clk *clk)
1003{
1004 if (unlikely(!clk_good(clk)))
1005 return;
1006
1007 if (clk->usage == 0 && clk->ops->disable)
1008 clk->ops->disable(clk);
1009
1010 if (clk->parent)
1011 local_clk_disable(clk->parent);
1012}
1013
1014void clk_disable(struct clk *clk)
1015{
1016 unsigned long clocks_flags;
1017
1018 if (unlikely(!clk_good(clk)))
1019 return;
1020
1021 spin_lock_irqsave(&clocks_lock, clocks_flags);
1022
1023 if ((--clk->usage) == 0 && clk->ops->disable)
1024 clk->ops->disable(clk);
1025
1026 spin_unlock_irqrestore(&clocks_lock, clocks_flags);
1027 if (clk->parent)
1028 clk_disable(clk->parent);
1029}
1030EXPORT_SYMBOL(clk_disable);
1031
1032/* Some additional API */
1033int clk_set_parent(struct clk *clk, struct clk *parent)
1034{
1035 int ret = -ENODEV;
1036 unsigned long clocks_flags;
1037
1038 if (unlikely(!clk_good(clk)))
1039 goto out;
1040
1041 if (!clk->ops->set_parent)
1042 goto out;
1043
1044 spin_lock_irqsave(&clocks_lock, clocks_flags);
1045
1046 ret = clk->ops->set_parent(clk, parent);
1047 if (!ret) {
1048 /* disable if usage count is 0 */
1049 local_clk_disable(parent);
1050
1051 parent->usage += clk->usage;
1052 clk->parent->usage -= clk->usage;
1053
1054 /* disable if new usage count is 0 */
1055 local_clk_disable(clk->parent);
1056
1057 clk->parent = parent;
1058 }
1059 spin_unlock_irqrestore(&clocks_lock, clocks_flags);
1060
1061out:
1062 return ret;
1063}
1064EXPORT_SYMBOL(clk_set_parent);
1065
1066struct clk *clk_get_parent(struct clk *clk)
1067{
1068 if (unlikely(!clk_good(clk)))
1069 return NULL;
1070 return clk->parent;
1071}
1072EXPORT_SYMBOL(clk_get_parent);
1073
1074static int __init clk_init(void)
1075{
1076 struct clk_lookup *cl;
1077 struct clk_ops *ops;
1078
1079 spin_lock_init(&clocks_lock);
1080
1081 for (cl = onchip_clks; cl < onchip_clks + ARRAY_SIZE(onchip_clks);
1082 cl++) {
1083 if (cl->clk->flags & ENABLED)
1084 clk_enable(cl->clk);
1085 else
1086 local_clk_disable(cl->clk);
1087
1088 ops = cl->clk->ops;
1089
1090 if ((cl->clk->flags & NEEDS_INITIALIZATION) &&
1091 ops && ops->set_rate)
1092 ops->set_rate(cl->clk, cl->clk->rate);
1093
1094 if (cl->clk->flags & FIXED_RATE) {
1095 if (cl->clk->flags & RATE_PROPAGATES)
1096 propagate_rate(cl->clk);
1097 } else {
1098 if (ops && ops->get_rate)
1099 ops->get_rate(cl->clk);
1100 }
1101
1102 if (cl->clk->flags & NEEDS_SET_PARENT) {
1103 if (ops && ops->set_parent)
1104 ops->set_parent(cl->clk, cl->clk->parent);
1105 }
1106
1107 clkdev_add(cl);
1108 }
1109 return 0;
1110}
1111
1112arch_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..6e2fef1639b0
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/core.c
@@ -0,0 +1,127 @@
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/dma.h>
24#include <mach/regs-clkctrl.h>
25
26static int __stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
27{
28 u32 c;
29 int timeout;
30
31 /* the process of software reset of IP block is done
32 in several steps:
33
34 - clear SFTRST and wait for block is enabled;
35 - clear clock gating (CLKGATE bit);
36 - set the SFTRST again and wait for block is in reset;
37 - clear SFTRST and wait for reset completion.
38 */
39 c = __raw_readl(hwreg);
40 c &= ~(1<<31); /* clear SFTRST */
41 __raw_writel(c, hwreg);
42 for (timeout = 1000000; timeout > 0; timeout--)
43 /* still in SFTRST state ? */
44 if ((__raw_readl(hwreg) & (1<<31)) == 0)
45 break;
46 if (timeout <= 0) {
47 printk(KERN_ERR"%s(%p): timeout when enabling\n",
48 __func__, hwreg);
49 return -ETIME;
50 }
51
52 c = __raw_readl(hwreg);
53 c &= ~(1<<30); /* clear CLKGATE */
54 __raw_writel(c, hwreg);
55
56 if (!just_enable) {
57 c = __raw_readl(hwreg);
58 c |= (1<<31); /* now again set SFTRST */
59 __raw_writel(c, hwreg);
60 for (timeout = 1000000; timeout > 0; timeout--)
61 /* poll until CLKGATE set */
62 if (__raw_readl(hwreg) & (1<<30))
63 break;
64 if (timeout <= 0) {
65 printk(KERN_ERR"%s(%p): timeout when resetting\n",
66 __func__, hwreg);
67 return -ETIME;
68 }
69
70 c = __raw_readl(hwreg);
71 c &= ~(1<<31); /* clear SFTRST */
72 __raw_writel(c, hwreg);
73 for (timeout = 1000000; timeout > 0; timeout--)
74 /* still in SFTRST state ? */
75 if ((__raw_readl(hwreg) & (1<<31)) == 0)
76 break;
77 if (timeout <= 0) {
78 printk(KERN_ERR"%s(%p): timeout when enabling "
79 "after reset\n", __func__, hwreg);
80 return -ETIME;
81 }
82
83 c = __raw_readl(hwreg);
84 c &= ~(1<<30); /* clear CLKGATE */
85 __raw_writel(c, hwreg);
86 }
87 for (timeout = 1000000; timeout > 0; timeout--)
88 /* still in SFTRST state ? */
89 if ((__raw_readl(hwreg) & (1<<30)) == 0)
90 break;
91
92 if (timeout <= 0) {
93 printk(KERN_ERR"%s(%p): timeout when unclockgating\n",
94 __func__, hwreg);
95 return -ETIME;
96 }
97
98 return 0;
99}
100
101int stmp3xxx_reset_block(void __iomem *hwreg, int just_enable)
102{
103 int try = 10;
104 int r;
105
106 while (try--) {
107 r = __stmp3xxx_reset_block(hwreg, just_enable);
108 if (!r)
109 break;
110 pr_debug("%s: try %d failed\n", __func__, 10 - try);
111 }
112 return r;
113}
114EXPORT_SYMBOL(stmp3xxx_reset_block);
115
116struct platform_device stmp3xxx_dbguart = {
117 .name = "stmp3xxx-dbguart",
118 .id = -1,
119};
120
121void __init stmp3xxx_init(void)
122{
123 /* Turn off auto-slow and other tricks */
124 HW_CLKCTRL_HBUS_CLR(0x07f00000U);
125
126 stmp3xxx_dma_init();
127}
diff --git a/arch/arm/plat-stmp3xxx/dma.c b/arch/arm/plat-stmp3xxx/dma.c
new file mode 100644
index 000000000000..cf42de05e568
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/dma.c
@@ -0,0 +1,462 @@
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/dma.h>
27#include <mach/regs-apbx.h>
28#include <mach/regs-apbh.h>
29
30static const size_t pool_item_size = sizeof(struct stmp3xxx_dma_command);
31static const size_t pool_alignment = 8;
32static struct stmp3xxx_dma_user {
33 void *pool;
34 int inuse;
35 const char *name;
36} channels[MAX_DMA_CHANNELS];
37
38static inline int dmach(int ch)
39{
40 return ch % 16;
41}
42
43static inline int dmabus(int ch)
44{
45 return ch / 16;
46}
47
48#define IS_VALID_CHANNEL(ch) ((ch) >= 0 && (ch) < MAX_DMA_CHANNELS)
49#define IS_USED(ch) (channels[ch].inuse)
50
51int stmp3xxx_dma_request(int ch, struct device *dev, const char *name)
52{
53 struct stmp3xxx_dma_user *user;
54 int err = 0;
55
56 user = channels + ch;
57 if (!IS_VALID_CHANNEL(ch)) {
58 err = -ENODEV;
59 goto out;
60 }
61 if (IS_USED(ch)) {
62 err = -EBUSY;
63 goto out;
64 }
65 /* Create a pool to allocate dma commands from */
66 user->pool = dma_pool_create(name, dev, pool_item_size,
67 pool_alignment, PAGE_SIZE);
68 if (user->pool == NULL) {
69 err = -ENOMEM;
70 goto out;
71 }
72 user->name = name;
73 user->inuse++;
74out:
75 return err;
76}
77EXPORT_SYMBOL(stmp3xxx_dma_request);
78
79int stmp3xxx_dma_release(int ch)
80{
81 struct stmp3xxx_dma_user *user = channels + ch;
82 int err = 0;
83
84 if (!IS_VALID_CHANNEL(ch)) {
85 err = -ENODEV;
86 goto out;
87 }
88 if (!IS_USED(ch)) {
89 err = -EBUSY;
90 goto out;
91 }
92 BUG_ON(user->pool == NULL);
93 dma_pool_destroy(user->pool);
94 user->inuse--;
95out:
96 return err;
97}
98EXPORT_SYMBOL(stmp3xxx_dma_release);
99
100int stmp3xxx_dma_read_semaphore(int channel)
101{
102 int sem = -1;
103
104 switch (dmabus(channel)) {
105 case STMP3XXX_BUS_APBH:
106 sem =
107 (HW_APBH_CHn_SEMA_RD(dmach(channel)) &
108 BM_APBH_CHn_SEMA_PHORE) >> BP_APBH_CHn_SEMA_PHORE;
109 break;
110
111 case STMP3XXX_BUS_APBX:
112 sem =
113 (HW_APBX_CHn_SEMA_RD(dmach(channel)) &
114 BM_APBX_CHn_SEMA_PHORE) >> BP_APBX_CHn_SEMA_PHORE;
115 break;
116 default:
117 BUG();
118 }
119 return sem;
120}
121EXPORT_SYMBOL(stmp3xxx_dma_read_semaphore);
122
123int stmp3xxx_dma_allocate_command(int channel,
124 struct stmp3xxx_dma_descriptor *descriptor)
125{
126 struct stmp3xxx_dma_user *user = channels + channel;
127 int err = 0;
128
129 if (!IS_VALID_CHANNEL(channel)) {
130 err = -ENODEV;
131 goto out;
132 }
133 if (!IS_USED(channel)) {
134 err = -EBUSY;
135 goto out;
136 }
137 if (descriptor == NULL) {
138 err = -EINVAL;
139 goto out;
140 }
141
142 /* Allocate memory for a command from the buffer */
143 descriptor->command =
144 dma_pool_alloc(user->pool, GFP_KERNEL, &descriptor->handle);
145
146 /* Check it worked */
147 if (!descriptor->command) {
148 err = -ENOMEM;
149 goto out;
150 }
151
152 memset(descriptor->command, 0, pool_item_size);
153out:
154 WARN_ON(err);
155 return err;
156}
157EXPORT_SYMBOL(stmp3xxx_dma_allocate_command);
158
159int stmp3xxx_dma_free_command(int channel,
160 struct stmp3xxx_dma_descriptor *descriptor)
161{
162 int err = 0;
163
164 if (!IS_VALID_CHANNEL(channel)) {
165 err = -ENODEV;
166 goto out;
167 }
168 if (!IS_USED(channel)) {
169 err = -EBUSY;
170 goto out;
171 }
172
173 /* Return the command memory to the pool */
174 dma_pool_free(channels[channel].pool, descriptor->command,
175 descriptor->handle);
176
177 /* Initialise descriptor so we're not tempted to use it */
178 descriptor->command = NULL;
179 descriptor->handle = 0;
180 descriptor->virtual_buf_ptr = NULL;
181 descriptor->next_descr = NULL;
182
183 WARN_ON(err);
184out:
185 return err;
186}
187EXPORT_SYMBOL(stmp3xxx_dma_free_command);
188
189void stmp3xxx_dma_go(int channel,
190 struct stmp3xxx_dma_descriptor *head, u32 semaphore)
191{
192 int ch = dmach(channel);
193
194 switch (dmabus(channel)) {
195 case STMP3XXX_BUS_APBH:
196 /* Set next command */
197 HW_APBH_CHn_NXTCMDAR_WR(ch, head->handle);
198 /* Set counting semaphore (kicks off transfer). Assumes
199 peripheral has been set up correctly */
200 HW_APBH_CHn_SEMA_WR(ch, semaphore);
201 break;
202
203 case STMP3XXX_BUS_APBX:
204 /* Set next command */
205 HW_APBX_CHn_NXTCMDAR_WR(ch, head->handle);
206 /* Set counting semaphore (kicks off transfer). Assumes
207 peripheral has been set up correctly */
208 HW_APBX_CHn_SEMA_WR(ch, semaphore);
209 break;
210 }
211}
212EXPORT_SYMBOL(stmp3xxx_dma_go);
213
214int stmp3xxx_dma_running(int channel)
215{
216 switch (dmabus(channel)) {
217 case STMP3XXX_BUS_APBH:
218 return HW_APBH_CHn_SEMA_RD(dmach(channel)) &
219 BM_APBH_CHn_SEMA_PHORE;
220
221 case STMP3XXX_BUS_APBX:
222 return HW_APBX_CHn_SEMA_RD(dmach(channel)) &
223 BM_APBX_CHn_SEMA_PHORE;
224
225 default:
226 BUG();
227 return 0;
228 }
229}
230EXPORT_SYMBOL(stmp3xxx_dma_running);
231
232/*
233 * Circular dma chain management
234 */
235void stmp3xxx_dma_free_chain(struct stmp37xx_circ_dma_chain *chain)
236{
237 int i;
238
239 for (i = 0; i < chain->total_count; i++)
240 stmp3xxx_dma_free_command(
241 STMP3xxx_DMA(chain->channel, chain->bus),
242 &chain->chain[i]);
243}
244EXPORT_SYMBOL(stmp3xxx_dma_free_chain);
245
246int stmp3xxx_dma_make_chain(int ch, struct stmp37xx_circ_dma_chain *chain,
247 struct stmp3xxx_dma_descriptor descriptors[],
248 unsigned items)
249{
250 int i;
251 int err = 0;
252
253 if (items == 0)
254 return err;
255
256 for (i = 0; i < items; i++) {
257 err = stmp3xxx_dma_allocate_command(ch, &descriptors[i]);
258 if (err) {
259 WARN_ON(err);
260 /*
261 * Couldn't allocate the whole chain.
262 * deallocate what has been allocated
263 */
264 if (i) {
265 do {
266 stmp3xxx_dma_free_command(ch,
267 &descriptors
268 [i]);
269 } while (i-- >= 0);
270 }
271 return err;
272 }
273
274 /* link them! */
275 if (i > 0) {
276 descriptors[i - 1].next_descr = &descriptors[i];
277 descriptors[i - 1].command->next =
278 descriptors[i].handle;
279 }
280 }
281
282 /* make list circular */
283 descriptors[items - 1].next_descr = &descriptors[0];
284 descriptors[items - 1].command->next = descriptors[0].handle;
285
286 chain->total_count = items;
287 chain->chain = descriptors;
288 chain->free_index = 0;
289 chain->active_index = 0;
290 chain->cooked_index = 0;
291 chain->free_count = items;
292 chain->active_count = 0;
293 chain->cooked_count = 0;
294 chain->bus = dmabus(ch);
295 chain->channel = dmach(ch);
296 return err;
297}
298EXPORT_SYMBOL(stmp3xxx_dma_make_chain);
299
300void stmp37xx_circ_clear_chain(struct stmp37xx_circ_dma_chain *chain)
301{
302 BUG_ON(stmp3xxx_dma_running(STMP3xxx_DMA(chain->channel, chain->bus)) >
303 0);
304 chain->free_index = 0;
305 chain->active_index = 0;
306 chain->cooked_index = 0;
307 chain->free_count = chain->total_count;
308 chain->active_count = 0;
309 chain->cooked_count = 0;
310}
311EXPORT_SYMBOL(stmp37xx_circ_clear_chain);
312
313void stmp37xx_circ_advance_free(struct stmp37xx_circ_dma_chain *chain,
314 unsigned count)
315{
316 BUG_ON(chain->cooked_count < count);
317
318 chain->cooked_count -= count;
319 chain->cooked_index += count;
320 chain->cooked_index %= chain->total_count;
321 chain->free_count += count;
322}
323EXPORT_SYMBOL(stmp37xx_circ_advance_free);
324
325void stmp37xx_circ_advance_active(struct stmp37xx_circ_dma_chain *chain,
326 unsigned count)
327{
328 BUG_ON(chain->free_count < count);
329
330 chain->free_count -= count;
331 chain->free_index += count;
332 chain->free_index %= chain->total_count;
333 chain->active_count += count;
334
335 switch (chain->bus) {
336 case STMP3XXX_BUS_APBH:
337 /* Set counting semaphore (kicks off transfer). Assumes
338 peripheral has been set up correctly */
339 HW_APBH_CHn_SEMA_CLR(chain->channel,
340 BM_APBH_CHn_SEMA_INCREMENT_SEMA);
341 HW_APBH_CHn_SEMA_SET(chain->channel,
342 BF_APBH_CHn_SEMA_INCREMENT_SEMA(count));
343 break;
344
345 case STMP3XXX_BUS_APBX:
346 /* Set counting semaphore (kicks off transfer). Assumes
347 peripheral has been set up correctly */
348 HW_APBX_CHn_SEMA_CLR(chain->channel,
349 BM_APBX_CHn_SEMA_INCREMENT_SEMA);
350 HW_APBX_CHn_SEMA_SET(chain->channel,
351 BF_APBX_CHn_SEMA_INCREMENT_SEMA(count));
352 break;
353
354 default:
355 BUG();
356 }
357}
358EXPORT_SYMBOL(stmp37xx_circ_advance_active);
359
360unsigned stmp37xx_circ_advance_cooked(struct stmp37xx_circ_dma_chain *chain)
361{
362 unsigned cooked;
363
364 cooked = chain->active_count -
365 stmp3xxx_dma_read_semaphore(STMP3xxx_DMA(chain->channel, chain->bus));
366
367 chain->active_count -= cooked;
368 chain->active_index += cooked;
369 chain->active_index %= chain->total_count;
370
371 chain->cooked_count += cooked;
372
373 return cooked;
374}
375EXPORT_SYMBOL(stmp37xx_circ_advance_cooked);
376
377void stmp3xxx_dma_set_alt_target(int channel, int function)
378{
379#if defined(CONFIG_ARCH_STMP37XX)
380 unsigned bits = 4;
381#elif defined(CONFIG_ARCH_STMP378X)
382 unsigned bits = 2;
383#else
384#error wrong arch
385#endif
386 int shift = dmach(channel) * bits;
387 unsigned mask = (1<<bits) - 1;
388
389 BUG_ON(function < 0 || function >= (1<<bits));
390 pr_debug("%s: channel = %d, using mask %x, "
391 "shift = %d\n", __func__, channel, mask, shift);
392
393 switch (dmabus(channel)) {
394 case STMP3XXX_BUS_APBH:
395 HW_APBH_DEVSEL_CLR(mask<<shift);
396 HW_APBH_DEVSEL_SET(function<<shift);
397 break;
398 case STMP3XXX_BUS_APBX:
399 HW_APBX_DEVSEL_CLR(mask<<shift);
400 HW_APBX_DEVSEL_SET(function<<shift);
401 break;
402 default:
403 BUG();
404 }
405}
406EXPORT_SYMBOL(stmp3xxx_dma_set_alt_target);
407
408void stmp3xxx_dma_suspend(void)
409{
410 HW_APBH_CTRL0_SET(BM_APBH_CTRL0_CLKGATE);
411 HW_APBX_CTRL0_SET(BM_APBX_CTRL0_CLKGATE);
412}
413
414void stmp3xxx_dma_resume(void)
415{
416 HW_APBH_CTRL0_CLR(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST);
417 HW_APBX_CTRL0_CLR(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST);
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 HW_APBH_CTRL0_CLR(BM_APBH_CTRL0_CLKGATE | BM_APBH_CTRL0_SFTRST);
456 HW_APBX_CTRL0_CLR(BM_APBX_CTRL0_CLKGATE | BM_APBX_CTRL0_SFTRST);
457#ifdef CONFIG_CPU_FREQ
458 cpufreq_register_notifier(&dma_cpufreq_nb.nb,
459 CPUFREQ_TRANSITION_NOTIFIER);
460#endif /* CONFIG_CPU_FREQ */
461
462}
diff --git a/arch/arm/plat-stmp3xxx/irq.c b/arch/arm/plat-stmp3xxx/irq.c
new file mode 100644
index 000000000000..cb3659096681
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/irq.c
@@ -0,0 +1,59 @@
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/regs-icoll.h>
26
27void __init stmp3xxx_init_irq(struct irq_chip *chip)
28{
29 unsigned int i;
30
31 /* Reset the interrupt controller */
32 HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_CLKGATE);
33 udelay(10);
34 HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_SFTRST);
35 udelay(10);
36 HW_ICOLL_CTRL_SET(BM_ICOLL_CTRL_SFTRST);
37 while (!(HW_ICOLL_CTRL_RD() & BM_ICOLL_CTRL_CLKGATE))
38 continue;
39 HW_ICOLL_CTRL_CLR(BM_ICOLL_CTRL_SFTRST | BM_ICOLL_CTRL_CLKGATE);
40
41 /* Disable all interrupts initially */
42 for (i = 0; i < NR_REAL_IRQS; i++) {
43 chip->mask(i);
44 set_irq_chip(i, chip);
45 set_irq_handler(i, handle_level_irq);
46 set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
47 }
48
49 /* Ensure vector is cleared */
50 HW_ICOLL_LEVELACK_WR(1);
51 HW_ICOLL_LEVELACK_WR(2);
52 HW_ICOLL_LEVELACK_WR(4);
53 HW_ICOLL_LEVELACK_WR(8);
54
55 HW_ICOLL_VECTOR_WR(0);
56 /* Barrier */
57 (void) HW_ICOLL_STAT_RD();
58}
59
diff --git a/arch/arm/plat-stmp3xxx/pinmux.c b/arch/arm/plat-stmp3xxx/pinmux.c
new file mode 100644
index 000000000000..9b28cc83f31c
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/pinmux.c
@@ -0,0 +1,545 @@
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#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/errno.h>
21#include <linux/sysdev.h>
22#include <linux/string.h>
23#include <linux/bitops.h>
24#include <linux/sysdev.h>
25#include <linux/irq.h>
26
27#include <mach/hardware.h>
28#include <mach/regs-pinctrl.h>
29#include <mach/pins.h>
30#include <mach/pinmux.h>
31
32#define NR_BANKS ARRAY_SIZE(pinmux_banks)
33static struct stmp3xxx_pinmux_bank pinmux_banks[] = {
34 [0] = {
35 .hw_muxsel = {
36 HW_PINCTRL_MUXSEL0_ADDR,
37 HW_PINCTRL_MUXSEL1_ADDR
38 },
39 .hw_drive = {
40 HW_PINCTRL_DRIVE0_ADDR,
41 HW_PINCTRL_DRIVE1_ADDR,
42 HW_PINCTRL_DRIVE2_ADDR,
43 HW_PINCTRL_DRIVE3_ADDR
44 },
45 .hw_pull = HW_PINCTRL_PULL0_ADDR,
46 .functions = { 0x0, 0x1, 0x2, 0x3 },
47 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
48
49 .hw_gpio_read = HW_PINCTRL_DIN0_ADDR,
50 .hw_gpio_set = HW_PINCTRL_DOUT0_ADDR + HW_STMP3xxx_SET,
51 .hw_gpio_clr = HW_PINCTRL_DOUT0_ADDR + HW_STMP3xxx_CLR,
52 .hw_gpio_doe = HW_PINCTRL_DOE0_ADDR,
53 .irq = IRQ_GPIO0,
54
55 .pin2irq = HW_PINCTRL_PIN2IRQ0_ADDR,
56 .irqstat = HW_PINCTRL_IRQSTAT0_ADDR,
57 .irqlevel = HW_PINCTRL_IRQLEVEL0_ADDR,
58 .irqpolarity = HW_PINCTRL_IRQPOL0_ADDR,
59 .irqen = HW_PINCTRL_IRQEN0_ADDR,
60 },
61 [1] = {
62 .hw_muxsel = {
63 HW_PINCTRL_MUXSEL2_ADDR,
64 HW_PINCTRL_MUXSEL3_ADDR
65 },
66 .hw_drive = {
67 HW_PINCTRL_DRIVE4_ADDR,
68 HW_PINCTRL_DRIVE5_ADDR,
69 HW_PINCTRL_DRIVE6_ADDR,
70 HW_PINCTRL_DRIVE7_ADDR
71 },
72 .hw_pull = HW_PINCTRL_PULL1_ADDR,
73 .functions = { 0x0, 0x1, 0x2, 0x3 },
74 .strengths = { 0x0, 0x1, 0x2, 0x3, 0xff },
75
76 .hw_gpio_read = HW_PINCTRL_DIN1_ADDR,
77 .hw_gpio_set = HW_PINCTRL_DOUT1_ADDR + HW_STMP3xxx_SET,
78 .hw_gpio_clr = HW_PINCTRL_DOUT1_ADDR + HW_STMP3xxx_CLR,
79 .hw_gpio_doe = HW_PINCTRL_DOE1_ADDR,
80 .irq = IRQ_GPIO1,
81
82 .pin2irq = HW_PINCTRL_PIN2IRQ1_ADDR,
83 .irqstat = HW_PINCTRL_IRQSTAT1_ADDR,
84 .irqlevel = HW_PINCTRL_IRQLEVEL1_ADDR,
85 .irqpolarity = HW_PINCTRL_IRQPOL1_ADDR,
86 .irqen = HW_PINCTRL_IRQEN1_ADDR,
87 },
88 [2] = {
89 .hw_muxsel = {
90 HW_PINCTRL_MUXSEL4_ADDR,
91 HW_PINCTRL_MUXSEL5_ADDR,
92 },
93 .hw_drive = {
94 HW_PINCTRL_DRIVE8_ADDR,
95 HW_PINCTRL_DRIVE9_ADDR,
96 HW_PINCTRL_DRIVE10_ADDR,
97 HW_PINCTRL_DRIVE11_ADDR,
98 },
99 .hw_pull = HW_PINCTRL_PULL2_ADDR,
100 .functions = { 0x0, 0x1, 0x2, 0x3 },
101 .strengths = { 0x0, 0x1, 0x2, 0x1, 0x2 },
102
103 .hw_gpio_read = HW_PINCTRL_DIN2_ADDR,
104 .hw_gpio_set = HW_PINCTRL_DOUT2_ADDR + HW_STMP3xxx_SET,
105 .hw_gpio_clr = HW_PINCTRL_DOUT2_ADDR + HW_STMP3xxx_CLR,
106 .hw_gpio_doe = HW_PINCTRL_DOE2_ADDR,
107 .irq = IRQ_GPIO2,
108
109 .pin2irq = HW_PINCTRL_PIN2IRQ2_ADDR,
110 .irqstat = HW_PINCTRL_IRQSTAT2_ADDR,
111 .irqlevel = HW_PINCTRL_IRQLEVEL2_ADDR,
112 .irqpolarity = HW_PINCTRL_IRQPOL2_ADDR,
113 .irqen = HW_PINCTRL_IRQEN2_ADDR,
114 },
115 [3] = {
116 .hw_muxsel = {
117 HW_PINCTRL_MUXSEL6_ADDR,
118 HW_PINCTRL_MUXSEL7_ADDR,
119 },
120 .hw_drive = {
121 HW_PINCTRL_DRIVE12_ADDR,
122 HW_PINCTRL_DRIVE13_ADDR,
123 HW_PINCTRL_DRIVE14_ADDR,
124 NULL,
125 },
126 .hw_pull = HW_PINCTRL_PULL3_ADDR,
127 .functions = {0x0, 0x1, 0x2, 0x3},
128 .strengths = {0x0, 0x1, 0x2, 0x3, 0xff},
129 },
130};
131
132static inline struct stmp3xxx_pinmux_bank *
133stmp3xxx_pinmux_bank(unsigned id, unsigned *bank, unsigned *pin)
134{
135 unsigned b, p;
136
137 b = STMP3XXX_PINID_TO_BANK(id);
138 p = STMP3XXX_PINID_TO_PINNUM(id);
139 BUG_ON(b >= NR_BANKS);
140 if (bank)
141 *bank = b;
142 if (pin)
143 *pin = p;
144 return &pinmux_banks[b];
145}
146
147/* Check if requested pin is owned by caller */
148static int stmp3xxx_check_pin(unsigned id, const char *label)
149{
150 unsigned pin;
151 struct stmp3xxx_pinmux_bank *pm = stmp3xxx_pinmux_bank(id, NULL, &pin);
152
153 if (!test_bit(pin, &pm->pin_map)) {
154 printk(KERN_WARNING
155 "%s: Accessing free pin %x, caller %s\n",
156 __func__, id, label);
157
158 return -EINVAL;
159 }
160
161 if (label && pm->pin_labels[pin] &&
162 strcmp(label, pm->pin_labels[pin])) {
163 printk(KERN_WARNING
164 "%s: Wrong pin owner %x, caller %s owner %s\n",
165 __func__, id, label, pm->pin_labels[pin]);
166
167 return -EINVAL;
168 }
169 return 0;
170}
171
172void stmp3xxx_pin_strength(unsigned id, enum pin_strength strength,
173 const char *label)
174{
175 struct stmp3xxx_pinmux_bank *pbank;
176 void __iomem *hwdrive;
177 u32 shift, val;
178 u32 bank, pin;
179
180 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
181 pr_debug("%s: label %s bank %d pin %d strength %d\n", __func__, label,
182 bank, pin, strength);
183
184 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
185 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
186 val = pbank->strengths[strength];
187 if (val == 0xff) {
188 printk(KERN_WARNING
189 "%s: strength is not supported for bank %d, caller %s",
190 __func__, bank, label);
191 return;
192 }
193
194 if (stmp3xxx_check_pin(id, label))
195 return;
196
197 pr_debug("%s: writing 0x%x to 0x%p register\n", __func__,
198 val << shift, hwdrive);
199 __raw_writel(HW_DRIVE_PINDRV_MASK << shift, hwdrive + HW_STMP3xxx_CLR);
200 __raw_writel(val << shift, hwdrive + HW_STMP3xxx_SET);
201}
202
203void stmp3xxx_pin_voltage(unsigned id, enum pin_voltage voltage,
204 const char *label)
205{
206 struct stmp3xxx_pinmux_bank *pbank;
207 void __iomem *hwdrive;
208 u32 shift;
209 u32 bank, pin;
210
211 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
212 pr_debug("%s: label %s bank %d pin %d voltage %d\n", __func__, label,
213 bank, pin, voltage);
214
215 hwdrive = pbank->hw_drive[pin / HW_DRIVE_PIN_NUM];
216 shift = (pin % HW_DRIVE_PIN_NUM) * HW_DRIVE_PIN_LEN;
217
218 if (stmp3xxx_check_pin(id, label))
219 return;
220
221 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
222 __func__, HW_DRIVE_PINV_MASK << shift, hwdrive);
223 if (voltage == PIN_1_8V)
224 __raw_writel(HW_DRIVE_PINV_MASK << shift,
225 hwdrive + HW_STMP3xxx_CLR);
226 else
227 __raw_writel(HW_DRIVE_PINV_MASK << shift,
228 hwdrive + HW_STMP3xxx_SET);
229}
230
231void stmp3xxx_pin_pullup(unsigned id, int enable, const char *label)
232{
233 struct stmp3xxx_pinmux_bank *pbank;
234 void __iomem *hwpull;
235 u32 bank, pin;
236
237 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
238 pr_debug("%s: label %s bank %d pin %d enable %d\n", __func__, label,
239 bank, pin, enable);
240
241 hwpull = pbank->hw_pull;
242
243 if (stmp3xxx_check_pin(id, label))
244 return;
245
246 pr_debug("%s: changing 0x%x bit in 0x%p register\n",
247 __func__, 1 << pin, hwpull);
248 __raw_writel(1 << pin,
249 hwpull + (enable ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR));
250}
251
252int stmp3xxx_request_pin(unsigned id, enum pin_fun fun, const char *label)
253{
254 struct stmp3xxx_pinmux_bank *pbank;
255 u32 bank, pin;
256 int ret = 0;
257
258 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
259 pr_debug("%s: label %s bank %d pin %d fun %d\n", __func__, label,
260 bank, pin, fun);
261
262 if (test_bit(pin, &pbank->pin_map)) {
263 printk(KERN_WARNING
264 "%s: CONFLICT DETECTED pin %d:%d caller %s owner %s\n",
265 __func__, bank, pin, label, pbank->pin_labels[pin]);
266 return -EBUSY;
267 }
268
269 set_bit(pin, &pbank->pin_map);
270 pbank->pin_labels[pin] = label;
271
272 stmp3xxx_set_pin_type(id, fun);
273
274 return ret;
275}
276
277void stmp3xxx_set_pin_type(unsigned id, enum pin_fun fun)
278{
279 struct stmp3xxx_pinmux_bank *pbank;
280 void __iomem *hwmux;
281 u32 shift, val;
282 u32 bank, pin;
283
284 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
285
286 hwmux = pbank->hw_muxsel[pin / HW_MUXSEL_PIN_NUM];
287 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
288
289 val = pbank->functions[fun];
290 shift = (pin % HW_MUXSEL_PIN_NUM) * HW_MUXSEL_PIN_LEN;
291 pr_debug("%s: writing 0x%x to 0x%p register\n",
292 __func__, val << shift, hwmux);
293 __raw_writel(HW_MUXSEL_PINFUN_MASK << shift, hwmux + HW_STMP3xxx_CLR);
294 __raw_writel(val << shift, hwmux + HW_STMP3xxx_SET);
295}
296
297void stmp3xxx_release_pin(unsigned id, const char *label)
298{
299 struct stmp3xxx_pinmux_bank *pbank;
300 u32 bank, pin;
301
302 pbank = stmp3xxx_pinmux_bank(id, &bank, &pin);
303 pr_debug("%s: label %s bank %d pin %d\n", __func__, label, bank, pin);
304
305 if (stmp3xxx_check_pin(id, label))
306 return;
307
308 clear_bit(pin, &pbank->pin_map);
309 pbank->pin_labels[pin] = NULL;
310}
311
312int stmp3xxx_request_pin_group(struct pin_group *pin_group, const char *label)
313{
314 struct pin_desc *pin;
315 int p;
316 int err = 0;
317
318 /* Allocate and configure pins */
319 for (p = 0; p < pin_group->nr_pins; p++) {
320 pr_debug("%s: #%d\n", __func__, p);
321 pin = &pin_group->pins[p];
322
323 err = stmp3xxx_request_pin(pin->id, pin->fun, label);
324 if (err)
325 goto out_err;
326
327 stmp3xxx_pin_strength(pin->id, pin->strength, label);
328 stmp3xxx_pin_voltage(pin->id, pin->voltage, label);
329 stmp3xxx_pin_pullup(pin->id, pin->pullup, label);
330 }
331
332 return 0;
333
334out_err:
335 /* Release allocated pins in case of error */
336 while (--p >= 0) {
337 pr_debug("%s: releasing #%d\n", __func__, p);
338 stmp3xxx_release_pin(pin_group->pins[p].id, label);
339 }
340 return err;
341}
342EXPORT_SYMBOL(stmp3xxx_request_pin_group);
343
344void stmp3xxx_release_pin_group(struct pin_group *pin_group, const char *label)
345{
346 struct pin_desc *pin;
347 int p;
348
349 for (p = 0; p < pin_group->nr_pins; p++) {
350 pin = &pin_group->pins[p];
351 stmp3xxx_release_pin(pin->id, label);
352 }
353}
354EXPORT_SYMBOL(stmp3xxx_release_pin_group);
355
356static int stmp3xxx_irq_to_gpio(int irq,
357 struct stmp3xxx_pinmux_bank **bank, unsigned *gpio)
358{
359 struct stmp3xxx_pinmux_bank *pm;
360
361 for (pm = pinmux_banks; pm < pinmux_banks + NR_BANKS; pm++)
362 if (pm->virq <= irq && irq < pm->virq + 32) {
363 *bank = pm;
364 *gpio = irq - pm->virq;
365 return 0;
366 }
367 return -ENOENT;
368}
369
370static int stmp3xxx_set_irqtype(unsigned irq, unsigned type)
371{
372 struct stmp3xxx_pinmux_bank *pm;
373 unsigned gpio;
374 int l, p;
375
376 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
377 switch (type) {
378 case IRQ_TYPE_EDGE_RISING:
379 l = 0; p = 1; break;
380 case IRQ_TYPE_EDGE_FALLING:
381 l = 0; p = 0; break;
382 case IRQ_TYPE_LEVEL_HIGH:
383 l = 1; p = 1; break;
384 case IRQ_TYPE_LEVEL_LOW:
385 l = 1; p = 0; break;
386 default:
387 pr_debug("%s: Incorrect GPIO interrupt type 0x%x\n",
388 __func__, type);
389 return -ENXIO;
390 }
391 __raw_writel(1 << gpio,
392 pm->irqlevel + (l ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR));
393 __raw_writel(1 << gpio,
394 pm->irqpolarity + (p ? HW_STMP3xxx_SET : HW_STMP3xxx_CLR));
395 return 0;
396}
397
398static void stmp3xxx_pin_ack_irq(unsigned irq)
399{
400 u32 stat;
401 struct stmp3xxx_pinmux_bank *pm;
402 unsigned gpio;
403
404 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
405 stat = __raw_readl(pm->irqstat) & (1<<gpio);
406 __raw_writel(stat, pm->irqstat + HW_STMP3xxx_CLR);
407}
408
409static void stmp3xxx_pin_mask_irq(unsigned irq)
410{
411 struct stmp3xxx_pinmux_bank *pm;
412 unsigned gpio;
413
414 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
415 __raw_writel(1 << gpio, pm->irqen + HW_STMP3xxx_CLR);
416 __raw_writel(1 << gpio, pm->pin2irq + HW_STMP3xxx_CLR);
417}
418
419static void stmp3xxx_pin_unmask_irq(unsigned irq)
420{
421 struct stmp3xxx_pinmux_bank *pm;
422 unsigned gpio;
423
424 stmp3xxx_irq_to_gpio(irq, &pm, &gpio);
425 __raw_writel(1 << gpio, pm->irqen + HW_STMP3xxx_SET);
426 __raw_writel(1 << gpio, pm->pin2irq + HW_STMP3xxx_SET);
427}
428
429static inline
430struct stmp3xxx_pinmux_bank *to_pinmux_bank(struct gpio_chip *chip)
431{
432 return container_of(chip, struct stmp3xxx_pinmux_bank, chip);
433}
434
435static int stmp3xxx_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
436{
437 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
438 return pm->virq + offset;
439}
440
441static int stmp3xxx_gpio_get(struct gpio_chip *chip, unsigned offset)
442{
443 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
444 unsigned v;
445
446 v = __raw_readl(pm->hw_gpio_read) & (1 << offset);
447 return v ? 1 : 0;
448}
449
450static void stmp3xxx_gpio_set(struct gpio_chip *chip, unsigned offset, int v)
451{
452 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
453
454 __raw_writel(1 << offset, v ? pm->hw_gpio_set : pm->hw_gpio_clr);
455}
456
457static int stmp3xxx_gpio_output(struct gpio_chip *chip, unsigned offset, int v)
458{
459 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
460
461 __raw_writel(1 << offset, pm->hw_gpio_doe + HW_STMP3xxx_SET);
462 stmp3xxx_gpio_set(chip, offset, v);
463 return 0;
464}
465
466static int stmp3xxx_gpio_input(struct gpio_chip *chip, unsigned offset)
467{
468 struct stmp3xxx_pinmux_bank *pm = to_pinmux_bank(chip);
469
470 __raw_writel(1 << offset, pm->hw_gpio_doe + HW_STMP3xxx_CLR);
471 return 0;
472}
473
474static int stmp3xxx_gpio_request(struct gpio_chip *chip, unsigned offset)
475{
476 return stmp3xxx_request_pin(chip->base + offset, PIN_GPIO, "gpio");
477}
478
479static void stmp3xxx_gpio_free(struct gpio_chip *chip, unsigned offset)
480{
481 stmp3xxx_release_pin(chip->base + offset, "gpio");
482}
483
484static void stmp3xxx_gpio_irq(u32 irq, struct irq_desc *desc)
485{
486 struct stmp3xxx_pinmux_bank *pm = get_irq_data(irq);
487 int gpio_irq = pm->virq;
488 u32 stat = __raw_readl(pm->irqstat);
489
490 while (stat) {
491 if (stat & 1)
492 irq_desc[gpio_irq].handle_irq(gpio_irq,
493 &irq_desc[gpio_irq]);
494 gpio_irq++;
495 stat >>= 1;
496 }
497}
498
499static struct irq_chip gpio_irq_chip = {
500 .ack = stmp3xxx_pin_ack_irq,
501 .mask = stmp3xxx_pin_mask_irq,
502 .unmask = stmp3xxx_pin_unmask_irq,
503 .set_type = stmp3xxx_set_irqtype,
504};
505
506int __init stmp3xxx_pinmux_init(int virtual_irq_start)
507{
508 int b, r = 0;
509 struct stmp3xxx_pinmux_bank *pm;
510 int virq;
511
512 for (b = 0; b < 3; b++) {
513 /* only banks 0,1,2 are allowed to GPIO */
514 pm = pinmux_banks + b;
515 pm->chip.base = 32 * b;
516 pm->chip.ngpio = 32;
517 pm->chip.owner = THIS_MODULE;
518 pm->chip.can_sleep = 1;
519 pm->chip.exported = 1;
520 pm->chip.to_irq = stmp3xxx_gpio_to_irq;
521 pm->chip.direction_input = stmp3xxx_gpio_input;
522 pm->chip.direction_output = stmp3xxx_gpio_output;
523 pm->chip.get = stmp3xxx_gpio_get;
524 pm->chip.set = stmp3xxx_gpio_set;
525 pm->chip.request = stmp3xxx_gpio_request;
526 pm->chip.free = stmp3xxx_gpio_free;
527 pm->virq = virtual_irq_start + b * 32;
528
529 for (virq = pm->virq; virq < pm->virq; virq++) {
530 gpio_irq_chip.mask(virq);
531 set_irq_chip(virq, &gpio_irq_chip);
532 set_irq_handler(virq, handle_level_irq);
533 set_irq_flags(virq, IRQF_VALID);
534 }
535 r = gpiochip_add(&pm->chip);
536 if (r < 0)
537 break;
538 set_irq_chained_handler(pm->irq, stmp3xxx_gpio_irq);
539 set_irq_data(pm->irq, pm);
540 }
541 return r;
542}
543
544MODULE_AUTHOR("Vladislav Buzov");
545MODULE_LICENSE("GPL");
diff --git a/arch/arm/plat-stmp3xxx/timer.c b/arch/arm/plat-stmp3xxx/timer.c
new file mode 100644
index 000000000000..c916068f0cab
--- /dev/null
+++ b/arch/arm/plat-stmp3xxx/timer.c
@@ -0,0 +1,172 @@
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/regs-timrot.h>
30
31static irqreturn_t
32stmp3xxx_timer_interrupt(int irq, void *dev_id)
33{
34 struct clock_event_device *c = dev_id;
35
36 if (HW_TIMROT_TIMCTRLn_RD(0) & (1<<15)) {
37 HW_TIMROT_TIMCTRLn_CLR(0, (1<<15));
38 c->event_handler(c);
39 } else if (HW_TIMROT_TIMCTRLn_RD(1) & (1<<15)) {
40 HW_TIMROT_TIMCTRLn_CLR(1, (1<<15));
41 HW_TIMROT_TIMCTRLn_CLR(1, BM_TIMROT_TIMCTRLn_IRQ_EN);
42 HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF);
43 }
44
45 return IRQ_HANDLED;
46}
47
48static cycle_t stmp3xxx_clock_read(void)
49{
50 return ~((HW_TIMROT_TIMCOUNTn_RD(1) & 0xFFFF0000) >> 16);
51}
52
53static int
54stmp3xxx_timrot_set_next_event(unsigned long delta,
55 struct clock_event_device *dev)
56{
57 HW_TIMROT_TIMCOUNTn_WR(0, delta); /* reload */
58 return 0;
59}
60
61static void
62stmp3xxx_timrot_set_mode(enum clock_event_mode mode,
63 struct clock_event_device *dev)
64{
65}
66
67static struct clock_event_device ckevt_timrot = {
68 .name = "timrot",
69 .features = CLOCK_EVT_FEAT_ONESHOT,
70 .shift = 32,
71 .set_next_event = stmp3xxx_timrot_set_next_event,
72 .set_mode = stmp3xxx_timrot_set_mode,
73};
74
75static struct clocksource cksrc_stmp3xxx = {
76 .name = "cksrc_stmp3xxx",
77 .rating = 250,
78 .read = stmp3xxx_clock_read,
79 .mask = CLOCKSOURCE_MASK(16),
80 .shift = 10,
81 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
82};
83
84static struct irqaction stmp3xxx_timer_irq = {
85 .name = "stmp3xxx_timer",
86 .flags = IRQF_DISABLED | IRQF_TIMER,
87 .handler = stmp3xxx_timer_interrupt,
88 .dev_id = &ckevt_timrot,
89};
90
91
92/*
93 * Set up timer interrupt, and return the current time in seconds.
94 */
95static void __init stmp3xxx_init_timer(void)
96{
97 cksrc_stmp3xxx.mult = clocksource_hz2mult(CLOCK_TICK_RATE,
98 cksrc_stmp3xxx.shift);
99 ckevt_timrot.mult = div_sc(CLOCK_TICK_RATE, NSEC_PER_SEC,
100 ckevt_timrot.shift);
101 ckevt_timrot.min_delta_ns = clockevent_delta2ns(2, &ckevt_timrot);
102 ckevt_timrot.max_delta_ns = clockevent_delta2ns(0xFFF, &ckevt_timrot);
103 ckevt_timrot.cpumask = cpumask_of(0);
104
105 HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST |
106 BM_TIMROT_ROTCTRL_CLKGATE);
107 HW_TIMROT_TIMCOUNTn_WR(0, 0);
108 HW_TIMROT_TIMCOUNTn_WR(1, 0);
109
110 HW_TIMROT_TIMCTRLn_WR(0,
111 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
112 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
113 BM_TIMROT_TIMCTRLn_RELOAD |
114 BM_TIMROT_TIMCTRLn_UPDATE |
115 BM_TIMROT_TIMCTRLn_IRQ_EN));
116 HW_TIMROT_TIMCTRLn_WR(1,
117 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
118 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
119 BM_TIMROT_TIMCTRLn_RELOAD |
120 BM_TIMROT_TIMCTRLn_UPDATE));
121
122 HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1);
123 HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */
124
125 setup_irq(IRQ_TIMER0, &stmp3xxx_timer_irq);
126
127 clocksource_register(&cksrc_stmp3xxx);
128 clockevents_register_device(&ckevt_timrot);
129}
130
131#ifdef CONFIG_PM
132
133void stmp3xxx_suspend_timer(void)
134{
135 HW_TIMROT_TIMCTRLn_CLR(0, BM_TIMROT_TIMCTRLn_IRQ_EN);
136 HW_TIMROT_TIMCTRLn_CLR(0, (1<<15));
137 HW_TIMROT_ROTCTRL_SET(BM_TIMROT_ROTCTRL_CLKGATE);
138}
139
140void stmp3xxx_resume_timer(void)
141{
142 HW_TIMROT_ROTCTRL_CLR(BM_TIMROT_ROTCTRL_SFTRST |
143 BM_TIMROT_ROTCTRL_CLKGATE);
144
145
146 HW_TIMROT_TIMCTRLn_WR(0,
147 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
148 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
149 BM_TIMROT_TIMCTRLn_UPDATE |
150 BM_TIMROT_TIMCTRLn_IRQ_EN));
151 HW_TIMROT_TIMCTRLn_WR(1,
152 (BF_TIMROT_TIMCTRLn_SELECT(8) | /* 32 kHz */
153 BF_TIMROT_TIMCTRLn_PRESCALE(0) |
154 BM_TIMROT_TIMCTRLn_RELOAD |
155 BM_TIMROT_TIMCTRLn_UPDATE));
156
157 HW_TIMROT_TIMCOUNTn_WR(0, CLOCK_TICK_RATE / HZ - 1);
158 HW_TIMROT_TIMCOUNTn_WR(1, 0xFFFF); /* reload */
159}
160
161#else
162
163#define stmp3xxx_suspend_timer NULL
164#define stmp3xxx_resume_timer NULL
165
166#endif /* CONFIG_PM */
167
168struct sys_timer stmp3xxx_timer = {
169 .init = stmp3xxx_init_timer,
170 .suspend = stmp3xxx_suspend_timer,
171 .resume = stmp3xxx_resume_timer,
172};