aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2443/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2443/clock.c')
-rw-r--r--arch/arm/mach-s3c2443/clock.c1007
1 files changed, 1007 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c
new file mode 100644
index 000000000000..dd2272fb1131
--- /dev/null
+++ b/arch/arm/mach-s3c2443/clock.c
@@ -0,0 +1,1007 @@
1/* linux/arch/arm/mach-s3c2443/clock.c
2 *
3 * Copyright (c) 2007 Simtec Electronics
4 * Ben Dooks <ben@simtec.co.uk>
5 *
6 * S3C2443 Clock control support
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21*/
22
23#include <linux/init.h>
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/list.h>
27#include <linux/errno.h>
28#include <linux/err.h>
29#include <linux/sysdev.h>
30#include <linux/clk.h>
31#include <linux/mutex.h>
32#include <linux/delay.h>
33#include <linux/serial_core.h>
34
35#include <asm/mach/map.h>
36
37#include <asm/hardware.h>
38#include <asm/io.h>
39
40#include <asm/arch/regs-s3c2443-clock.h>
41
42#include <asm/plat-s3c24xx/s3c2443.h>
43#include <asm/plat-s3c24xx/clock.h>
44#include <asm/plat-s3c24xx/cpu.h>
45
46/* We currently have to assume that the system is running
47 * from the XTPll input, and that all ***REFCLKs are being
48 * fed from it, as we cannot read the state of OM[4] from
49 * software.
50 *
51 * It would be possible for each board initialisation to
52 * set the correct muxing at initialisation
53*/
54
55static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
56{
57 unsigned int clocks = clk->ctrlbit;
58 unsigned long clkcon;
59
60 clkcon = __raw_readl(S3C2443_HCLKCON);
61
62 if (enable)
63 clkcon |= clocks;
64 else
65 clkcon &= ~clocks;
66
67 __raw_writel(clkcon, S3C2443_HCLKCON);
68
69 return 0;
70}
71
72static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
73{
74 unsigned int clocks = clk->ctrlbit;
75 unsigned long clkcon;
76
77 clkcon = __raw_readl(S3C2443_PCLKCON);
78
79 if (enable)
80 clkcon |= clocks;
81 else
82 clkcon &= ~clocks;
83
84 __raw_writel(clkcon, S3C2443_HCLKCON);
85
86 return 0;
87}
88
89static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
90{
91 unsigned int clocks = clk->ctrlbit;
92 unsigned long clkcon;
93
94 clkcon = __raw_readl(S3C2443_SCLKCON);
95
96 if (enable)
97 clkcon |= clocks;
98 else
99 clkcon &= ~clocks;
100
101 __raw_writel(clkcon, S3C2443_SCLKCON);
102
103 return 0;
104}
105
106static unsigned long s3c2443_roundrate_clksrc(struct clk *clk,
107 unsigned long rate,
108 unsigned int max)
109{
110 unsigned long parent_rate = clk_get_rate(clk->parent);
111 int div;
112
113 if (rate > parent_rate)
114 return parent_rate;
115
116 /* note, we remove the +/- 1 calculations as they cancel out */
117
118 div = (rate / parent_rate);
119
120 if (div < 1)
121 div = 1;
122 else if (div > max)
123 div = max;
124
125 return parent_rate / div;
126}
127
128static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk,
129 unsigned long rate)
130{
131 return s3c2443_roundrate_clksrc(clk, rate, 4);
132}
133
134static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk,
135 unsigned long rate)
136{
137 return s3c2443_roundrate_clksrc(clk, rate, 16);
138}
139
140static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk,
141 unsigned long rate)
142{
143 return s3c2443_roundrate_clksrc(clk, rate, 256);
144}
145
146/* clock selections */
147
148/* CPU EXTCLK input */
149static struct clk clk_ext = {
150 .name = "ext",
151 .id = -1,
152};
153
154static struct clk clk_mpllref = {
155 .name = "mpllref",
156 .parent = &clk_xtal,
157 .id = -1,
158};
159
160#if 0
161static struct clk clk_mpll = {
162 .name = "mpll",
163 .parent = &clk_mpllref,
164 .id = -1,
165};
166#endif
167
168static struct clk clk_epllref;
169
170static struct clk clk_epll = {
171 .name = "epll",
172 .parent = &clk_epllref,
173 .id = -1,
174};
175
176static struct clk clk_i2s_ext = {
177 .name = "i2s-ext",
178 .id = -1,
179};
180
181static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent)
182{
183 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
184
185 clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK;
186
187 if (parent == &clk_xtal)
188 clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL;
189 else if (parent == &clk_ext)
190 clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK;
191 else if (parent != &clk_mpllref)
192 return -EINVAL;
193
194 __raw_writel(clksrc, S3C2443_CLKSRC);
195 clk->parent = parent;
196
197 return 0;
198}
199
200static struct clk clk_epllref = {
201 .name = "epllref",
202 .id = -1,
203 .set_parent = s3c2443_setparent_epllref,
204};
205
206static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
207{
208 unsigned long parent_rate = clk_get_rate(clk->parent);
209 unsigned long div = __raw_readl(S3C2443_CLKDIV0);
210
211 div &= S3C2443_CLKDIV0_EXTDIV_MASK;
212 div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1); /* x2 */
213
214 return parent_rate / (div + 1);
215}
216
217static struct clk clk_mdivclk = {
218 .name = "mdivclk",
219 .parent = &clk_mpllref,
220 .id = -1,
221 .get_rate = s3c2443_getrate_mdivclk,
222};
223
224
225static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent)
226{
227 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
228
229 clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL |
230 S3C2443_CLKSRC_EXTCLK_DIV);
231
232 if (parent == &clk_mpll)
233 clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL;
234 else if (parent == &clk_mdivclk)
235 clksrc |= S3C2443_CLKSRC_EXTCLK_DIV;
236 else if (parent != &clk_mpllref)
237 return -EINVAL;
238
239 __raw_writel(clksrc, S3C2443_CLKSRC);
240 clk->parent = parent;
241
242 return 0;
243}
244
245static struct clk clk_msysclk = {
246 .name = "msysclk",
247 .parent = &clk_xtal,
248 .id = -1,
249 .set_parent = s3c2443_setparent_msysclk,
250};
251
252
253/* esysclk
254 *
255 * this is sourced from either the EPLL or the EPLLref clock
256*/
257
258static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent)
259{
260 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
261
262 if (parent == &clk_epll)
263 clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL;
264 else if (parent == &clk_epllref)
265 clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL;
266 else
267 return -EINVAL;
268
269 __raw_writel(clksrc, S3C2443_CLKSRC);
270 clk->parent = parent;
271
272 return 0;
273}
274
275static struct clk clk_esysclk = {
276 .name = "esysclk",
277 .parent = &clk_epll,
278 .id = -1,
279 .set_parent = s3c2443_setparent_esysclk,
280};
281
282/* uartclk
283 *
284 * UART baud-rate clock sourced from esysclk via a divisor
285*/
286
287static unsigned long s3c2443_getrate_uart(struct clk *clk)
288{
289 unsigned long parent_rate = clk_get_rate(clk->parent);
290 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
291
292 div &= S3C2443_CLKDIV1_UARTDIV_MASK;
293 div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT;
294
295 return parent_rate / (div + 1);
296}
297
298
299static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate)
300{
301 unsigned long parent_rate = clk_get_rate(clk->parent);
302 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
303
304 rate = s3c2443_roundrate_clksrc16(clk, rate);
305 rate = parent_rate / rate;
306
307 clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
308 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
309
310 __raw_writel(clkdivn, S3C2443_CLKDIV1);
311 return 0;
312}
313
314static struct clk clk_uart = {
315 .name = "uartclk",
316 .id = -1,
317 .parent = &clk_esysclk,
318 .get_rate = s3c2443_getrate_uart,
319 .set_rate = s3c2443_setrate_uart,
320 .round_rate = s3c2443_roundrate_clksrc16,
321};
322
323/* hsspi
324 *
325 * high-speed spi clock, sourced from esysclk
326*/
327
328static unsigned long s3c2443_getrate_hsspi(struct clk *clk)
329{
330 unsigned long parent_rate = clk_get_rate(clk->parent);
331 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
332
333 div &= S3C2443_CLKDIV1_HSSPIDIV_MASK;
334 div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
335
336 return parent_rate / (div + 1);
337}
338
339
340static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate)
341{
342 unsigned long parent_rate = clk_get_rate(clk->parent);
343 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
344
345 rate = s3c2443_roundrate_clksrc4(clk, rate);
346 rate = parent_rate / rate;
347
348 clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK;
349 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
350
351 __raw_writel(clkdivn, S3C2443_CLKDIV1);
352 return 0;
353}
354
355static struct clk clk_hsspi = {
356 .name = "hsspi",
357 .id = -1,
358 .parent = &clk_esysclk,
359 .ctrlbit = S3C2443_SCLKCON_HSSPICLK,
360 .enable = s3c2443_clkcon_enable_s,
361 .get_rate = s3c2443_getrate_hsspi,
362 .set_rate = s3c2443_setrate_hsspi,
363 .round_rate = s3c2443_roundrate_clksrc4,
364};
365
366/* usbhost
367 *
368 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
369*/
370
371static unsigned long s3c2443_getrate_usbhost(struct clk *clk)
372{
373 unsigned long parent_rate = clk_get_rate(clk->parent);
374 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
375
376 div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK;
377 div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
378
379 return parent_rate / (div + 1);
380}
381
382static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate)
383{
384 unsigned long parent_rate = clk_get_rate(clk->parent);
385 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
386
387 rate = s3c2443_roundrate_clksrc4(clk, rate);
388 rate = parent_rate / rate;
389
390 clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK;
391 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
392
393 __raw_writel(clkdivn, S3C2443_CLKDIV1);
394 return 0;
395}
396
397struct clk clk_usb_bus_host = {
398 .name = "usb-bus-host-parent",
399 .id = -1,
400 .parent = &clk_esysclk,
401 .ctrlbit = S3C2443_SCLKCON_USBHOST,
402 .enable = s3c2443_clkcon_enable_s,
403 .get_rate = s3c2443_getrate_usbhost,
404 .set_rate = s3c2443_setrate_usbhost,
405 .round_rate = s3c2443_roundrate_clksrc4,
406};
407
408/* clk_hsmcc_div
409 *
410 * this clock is sourced from epll, and is fed through a divider,
411 * to a mux controlled by sclkcon where either it or a extclk can
412 * be fed to the hsmmc block
413*/
414
415static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk)
416{
417 unsigned long parent_rate = clk_get_rate(clk->parent);
418 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
419
420 div &= S3C2443_CLKDIV1_HSMMCDIV_MASK;
421 div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
422
423 return parent_rate / (div + 1);
424}
425
426static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate)
427{
428 unsigned long parent_rate = clk_get_rate(clk->parent);
429 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
430
431 rate = s3c2443_roundrate_clksrc4(clk, rate);
432 rate = parent_rate / rate;
433
434 clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK;
435 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
436
437 __raw_writel(clkdivn, S3C2443_CLKDIV1);
438 return 0;
439}
440
441static struct clk clk_hsmmc_div = {
442 .name = "hsmmc-div",
443 .id = -1,
444 .parent = &clk_esysclk,
445 .get_rate = s3c2443_getrate_hsmmc_div,
446 .set_rate = s3c2443_setrate_hsmmc_div,
447 .round_rate = s3c2443_roundrate_clksrc4,
448};
449
450static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
451{
452 unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
453
454 clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
455 S3C2443_SCLKCON_HSMMCCLK_EPLL);
456
457 if (parent == &clk_epll)
458 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
459 else if (parent == &clk_ext)
460 clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
461 else
462 return -EINVAL;
463
464 if (clk->usage > 0) {
465 __raw_writel(clksrc, S3C2443_SCLKCON);
466 }
467
468 clk->parent = parent;
469 return 0;
470}
471
472static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
473{
474 return s3c2443_setparent_hsmmc(clk, clk->parent);
475}
476
477static struct clk clk_hsmmc = {
478 .name = "hsmmc-if",
479 .id = -1,
480 .parent = &clk_hsmmc_div,
481 .enable = s3c2443_enable_hsmmc,
482 .set_parent = s3c2443_setparent_hsmmc,
483};
484
485/* i2s_eplldiv
486 *
487 * this clock is the output from the i2s divisor of esysclk
488*/
489
490static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk)
491{
492 unsigned long parent_rate = clk_get_rate(clk->parent);
493 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
494
495 div &= S3C2443_CLKDIV1_I2SDIV_MASK;
496 div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT;
497
498 return parent_rate / (div + 1);
499}
500
501static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate)
502{
503 unsigned long parent_rate = clk_get_rate(clk->parent);
504 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
505
506 rate = s3c2443_roundrate_clksrc16(clk, rate);
507 rate = parent_rate / rate;
508
509 clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK;
510 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT;
511
512 __raw_writel(clkdivn, S3C2443_CLKDIV1);
513 return 0;
514}
515
516static struct clk clk_i2s_eplldiv = {
517 .name = "i2s-eplldiv",
518 .id = -1,
519 .parent = &clk_esysclk,
520 .get_rate = s3c2443_getrate_i2s_eplldiv,
521 .set_rate = s3c2443_setrate_i2s_eplldiv,
522 .round_rate = s3c2443_roundrate_clksrc16,
523};
524
525/* i2s-ref
526 *
527 * i2s bus reference clock, selectable from external, esysclk or epllref
528*/
529
530static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent)
531{
532 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
533
534 clksrc &= ~S3C2443_CLKSRC_I2S_MASK;
535
536 if (parent == &clk_epllref)
537 clksrc |= S3C2443_CLKSRC_I2S_EPLLREF;
538 else if (parent == &clk_i2s_ext)
539 clksrc |= S3C2443_CLKSRC_I2S_EXT;
540 else if (parent != &clk_i2s_eplldiv)
541 return -EINVAL;
542
543 clk->parent = parent;
544 __raw_writel(clksrc, S3C2443_CLKSRC);
545
546 return 0;
547}
548
549static struct clk clk_i2s = {
550 .name = "i2s-if",
551 .id = -1,
552 .parent = &clk_i2s_eplldiv,
553 .ctrlbit = S3C2443_SCLKCON_I2SCLK,
554 .enable = s3c2443_clkcon_enable_s,
555 .set_parent = s3c2443_setparent_i2s,
556};
557
558/* cam-if
559 *
560 * camera interface bus-clock, divided down from esysclk
561*/
562
563static unsigned long s3c2443_getrate_cam(struct clk *clk)
564{
565 unsigned long parent_rate = clk_get_rate(clk->parent);
566 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
567
568 div &= S3C2443_CLKDIV1_CAMDIV_MASK;
569 div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT;
570
571 return parent_rate / (div + 1);
572}
573
574static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate)
575{
576 unsigned long parent_rate = clk_get_rate(clk->parent);
577 unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1);
578
579 rate = s3c2443_roundrate_clksrc16(clk, rate);
580 rate = parent_rate / rate;
581
582 clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK;
583 clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT;
584
585 __raw_writel(clkdiv1, S3C2443_CLKDIV1);
586 return 0;
587}
588
589static struct clk clk_cam = {
590 .name = "camif-upll", /* same as 2440 name */
591 .id = -1,
592 .parent = &clk_esysclk,
593 .ctrlbit = S3C2443_SCLKCON_CAMCLK,
594 .enable = s3c2443_clkcon_enable_s,
595 .get_rate = s3c2443_getrate_cam,
596 .set_rate = s3c2443_setrate_cam,
597 .round_rate = s3c2443_roundrate_clksrc16,
598};
599
600/* display-if
601 *
602 * display interface clock, divided from esysclk
603*/
604
605static unsigned long s3c2443_getrate_display(struct clk *clk)
606{
607 unsigned long parent_rate = clk_get_rate(clk->parent);
608 unsigned long div = __raw_readl(S3C2443_CLKDIV1);
609
610 div &= S3C2443_CLKDIV1_DISPDIV_MASK;
611 div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT;
612
613 return parent_rate / (div + 1);
614}
615
616static int s3c2443_setrate_display(struct clk *clk, unsigned long rate)
617{
618 unsigned long parent_rate = clk_get_rate(clk->parent);
619 unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
620
621 rate = s3c2443_roundrate_clksrc256(clk, rate);
622 rate = parent_rate / rate;
623
624 clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
625 clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
626
627 __raw_writel(clkdivn, S3C2443_CLKDIV1);
628 return 0;
629}
630
631static struct clk clk_display = {
632 .name = "display-if",
633 .id = -1,
634 .parent = &clk_esysclk,
635 .ctrlbit = S3C2443_SCLKCON_DISPCLK,
636 .enable = s3c2443_clkcon_enable_s,
637 .get_rate = s3c2443_getrate_display,
638 .set_rate = s3c2443_setrate_display,
639 .round_rate = s3c2443_roundrate_clksrc256,
640};
641
642/* standard clock definitions */
643
644static struct clk init_clocks_disable[] = {
645 {
646 .name = "nand",
647 .id = -1,
648 .parent = &clk_h,
649 }, {
650 .name = "sdi",
651 .id = -1,
652 .parent = &clk_p,
653 .enable = s3c2443_clkcon_enable_p,
654 .ctrlbit = S3C2443_PCLKCON_SDI,
655 }, {
656 .name = "adc",
657 .id = -1,
658 .parent = &clk_p,
659 .enable = s3c2443_clkcon_enable_p,
660 .ctrlbit = S3C2443_PCLKCON_ADC,
661 }, {
662 .name = "i2c",
663 .id = -1,
664 .parent = &clk_p,
665 .enable = s3c2443_clkcon_enable_p,
666 .ctrlbit = S3C2443_PCLKCON_IIC,
667 }, {
668 .name = "iis",
669 .id = -1,
670 .parent = &clk_p,
671 .enable = s3c2443_clkcon_enable_p,
672 .ctrlbit = S3C2443_PCLKCON_IIS,
673 }, {
674 .name = "spi",
675 .id = 0,
676 .parent = &clk_p,
677 .enable = s3c2443_clkcon_enable_p,
678 .ctrlbit = S3C2443_PCLKCON_SPI0,
679 }, {
680 .name = "spi",
681 .id = 1,
682 .parent = &clk_p,
683 .enable = s3c2443_clkcon_enable_p,
684 .ctrlbit = S3C2443_PCLKCON_SPI1,
685 }
686};
687
688static struct clk init_clocks[] = {
689 {
690 .name = "dma",
691 .id = 0,
692 .parent = &clk_h,
693 .enable = s3c2443_clkcon_enable_h,
694 .ctrlbit = S3C2443_HCLKCON_DMA0,
695 }, {
696 .name = "dma",
697 .id = 1,
698 .parent = &clk_h,
699 .enable = s3c2443_clkcon_enable_h,
700 .ctrlbit = S3C2443_HCLKCON_DMA1,
701 }, {
702 .name = "dma",
703 .id = 2,
704 .parent = &clk_h,
705 .enable = s3c2443_clkcon_enable_h,
706 .ctrlbit = S3C2443_HCLKCON_DMA2,
707 }, {
708 .name = "dma",
709 .id = 3,
710 .parent = &clk_h,
711 .enable = s3c2443_clkcon_enable_h,
712 .ctrlbit = S3C2443_HCLKCON_DMA3,
713 }, {
714 .name = "dma",
715 .id = 4,
716 .parent = &clk_h,
717 .enable = s3c2443_clkcon_enable_h,
718 .ctrlbit = S3C2443_HCLKCON_DMA4,
719 }, {
720 .name = "dma",
721 .id = 5,
722 .parent = &clk_h,
723 .enable = s3c2443_clkcon_enable_h,
724 .ctrlbit = S3C2443_HCLKCON_DMA5,
725 }, {
726 .name = "lcd",
727 .id = -1,
728 .parent = &clk_h,
729 .enable = s3c2443_clkcon_enable_h,
730 .ctrlbit = S3C2443_HCLKCON_LCDC,
731 }, {
732 .name = "gpio",
733 .id = -1,
734 .parent = &clk_p,
735 .enable = s3c2443_clkcon_enable_p,
736 .ctrlbit = S3C2443_PCLKCON_GPIO,
737 }, {
738 .name = "usb-host",
739 .id = -1,
740 .parent = &clk_h,
741 .enable = s3c2443_clkcon_enable_h,
742 .ctrlbit = S3C2443_HCLKCON_USBH,
743 }, {
744 .name = "usb-device",
745 .id = -1,
746 .parent = &clk_h,
747 .enable = s3c2443_clkcon_enable_h,
748 .ctrlbit = S3C2443_HCLKCON_USBD,
749 }, {
750 .name = "timers",
751 .id = -1,
752 .parent = &clk_p,
753 .enable = s3c2443_clkcon_enable_p,
754 .ctrlbit = S3C2443_PCLKCON_PWMT,
755 }, {
756 .name = "uart",
757 .id = 0,
758 .parent = &clk_p,
759 .enable = s3c2443_clkcon_enable_p,
760 .ctrlbit = S3C2443_PCLKCON_UART0,
761 }, {
762 .name = "uart",
763 .id = 1,
764 .parent = &clk_p,
765 .enable = s3c2443_clkcon_enable_p,
766 .ctrlbit = S3C2443_PCLKCON_UART1,
767 }, {
768 .name = "uart",
769 .id = 2,
770 .parent = &clk_p,
771 .enable = s3c2443_clkcon_enable_p,
772 .ctrlbit = S3C2443_PCLKCON_UART2,
773 }, {
774 .name = "uart",
775 .id = 3,
776 .parent = &clk_p,
777 .enable = s3c2443_clkcon_enable_p,
778 .ctrlbit = S3C2443_PCLKCON_UART3,
779 }, {
780 .name = "rtc",
781 .id = -1,
782 .parent = &clk_p,
783 .enable = s3c2443_clkcon_enable_p,
784 .ctrlbit = S3C2443_PCLKCON_RTC,
785 }, {
786 .name = "watchdog",
787 .id = -1,
788 .parent = &clk_p,
789 .ctrlbit = S3C2443_PCLKCON_WDT,
790 }, {
791 .name = "usb-bus-host",
792 .id = -1,
793 .parent = &clk_usb_bus_host,
794 }
795};
796
797/* clocks to add where we need to check their parentage */
798
799/* s3c2443_clk_initparents
800 *
801 * Initialise the parents for the clocks that we get at start-time
802*/
803
804static int __init clk_init_set_parent(struct clk *clk, struct clk *parent)
805{
806 printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name);
807 return clk_set_parent(clk, parent);
808}
809
810static void __init s3c2443_clk_initparents(void)
811{
812 unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
813 struct clk *parent;
814
815 switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) {
816 case S3C2443_CLKSRC_EPLLREF_EXTCLK:
817 parent = &clk_ext;
818 break;
819
820 case S3C2443_CLKSRC_EPLLREF_XTAL:
821 default:
822 parent = &clk_xtal;
823 break;
824
825 case S3C2443_CLKSRC_EPLLREF_MPLLREF:
826 case S3C2443_CLKSRC_EPLLREF_MPLLREF2:
827 parent = &clk_mpllref;
828 break;
829 }
830
831 clk_init_set_parent(&clk_epllref, parent);
832
833 switch (clksrc & S3C2443_CLKSRC_I2S_MASK) {
834 case S3C2443_CLKSRC_I2S_EXT:
835 parent = &clk_i2s_ext;
836 break;
837
838 case S3C2443_CLKSRC_I2S_EPLLDIV:
839 default:
840 parent = &clk_i2s_eplldiv;
841 break;
842
843 case S3C2443_CLKSRC_I2S_EPLLREF:
844 case S3C2443_CLKSRC_I2S_EPLLREF3:
845 parent = &clk_epllref;
846 }
847
848 clk_init_set_parent(&clk_i2s, &clk_epllref);
849
850 /* esysclk source */
851
852 parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ?
853 &clk_epll : &clk_epllref;
854
855 clk_init_set_parent(&clk_esysclk, parent);
856
857 /* msysclk source */
858
859 if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) {
860 parent = &clk_mpll;
861 } else {
862 parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ?
863 &clk_mdivclk : &clk_mpllref;
864 }
865
866 clk_init_set_parent(&clk_msysclk, parent);
867}
868
869/* armdiv divisor table */
870
871static unsigned int armdiv[16] = {
872 [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 1,
873 [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 2,
874 [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 3,
875 [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 4,
876 [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 6,
877 [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 8,
878 [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 12,
879 [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT] = 16,
880};
881
882static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
883{
884 clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
885
886 return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
887}
888
889static inline unsigned long s3c2443_get_prediv(unsigned long clkcon0)
890{
891 clkcon0 &= S3C2443_CLKDIV0_PREDIV_MASK;
892 clkcon0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
893
894 return clkcon0 + 1;
895}
896
897/* clocks to add straight away */
898
899static struct clk *clks[] __initdata = {
900 &clk_ext,
901 &clk_epll,
902 &clk_usb_bus_host,
903 &clk_usb_bus,
904 &clk_esysclk,
905 &clk_epllref,
906 &clk_mpllref,
907 &clk_msysclk,
908 &clk_uart,
909 &clk_display,
910 &clk_cam,
911 &clk_i2s_eplldiv,
912 &clk_i2s,
913 &clk_hsspi,
914 &clk_hsmmc_div,
915 &clk_hsmmc,
916};
917
918void __init s3c2443_init_clocks(int xtal)
919{
920 unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
921 unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
922 unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
923 unsigned long pll;
924 unsigned long fclk;
925 unsigned long hclk;
926 unsigned long pclk;
927 struct clk *clkp;
928 int ret;
929 int ptr;
930
931 pll = s3c2443_get_mpll(mpllcon, xtal);
932
933 fclk = pll / s3c2443_fclk_div(clkdiv0);
934 hclk = fclk / s3c2443_get_prediv(clkdiv0);
935 hclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_HCLK) ? 2 : 1);
936 pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
937
938 s3c24xx_setup_clocks(xtal, fclk, hclk, pclk);
939
940 printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
941 (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
942 print_mhz(pll), print_mhz(fclk),
943 print_mhz(hclk), print_mhz(pclk));
944
945 s3c2443_clk_initparents();
946
947 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
948 clkp = clks[ptr];
949
950 ret = s3c24xx_register_clock(clkp);
951 if (ret < 0) {
952 printk(KERN_ERR "Failed to register clock %s (%d)\n",
953 clkp->name, ret);
954 }
955 }
956
957 clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
958
959 clk_usb_bus.parent = &clk_usb_bus_host;
960
961 /* ensure usb bus clock is within correct rate of 48MHz */
962
963 if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) {
964 printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
965 clk_set_rate(&clk_usb_bus_host, 48*1000*1000);
966 }
967
968 printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
969 (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
970 print_mhz(clk_get_rate(&clk_epll)),
971 print_mhz(clk_get_rate(&clk_usb_bus)));
972
973 /* register clocks from clock array */
974
975 clkp = init_clocks;
976 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
977 ret = s3c24xx_register_clock(clkp);
978 if (ret < 0) {
979 printk(KERN_ERR "Failed to register clock %s (%d)\n",
980 clkp->name, ret);
981 }
982 }
983
984 /* We must be careful disabling the clocks we are not intending to
985 * be using at boot time, as subsytems such as the LCD which do
986 * their own DMA requests to the bus can cause the system to lockup
987 * if they where in the middle of requesting bus access.
988 *
989 * Disabling the LCD clock if the LCD is active is very dangerous,
990 * and therefore the bootloader should be careful to not enable
991 * the LCD clock if it is not needed.
992 */
993
994 /* install (and disable) the clocks we do not need immediately */
995
996 clkp = init_clocks_disable;
997 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
998
999 ret = s3c24xx_register_clock(clkp);
1000 if (ret < 0) {
1001 printk(KERN_ERR "Failed to register clock %s (%d)\n",
1002 clkp->name, ret);
1003 }
1004
1005 (clkp->enable)(clkp, 0);
1006 }
1007}