acpiphp: Execute ACPI _REG method for hotadded devices
[linux/fpc-iii.git] / arch / arm / plat-s5pc1xx / s5pc100-clock.c
blobb436d44510c8ff1cfad5d34e892b72674480f46b
1 /* linux/arch/arm/plat-s5pc1xx/s5pc100-clock.c
3 * Copyright 2009 Samsung Electronics, Co.
4 * Byungho Min <bhmin@samsung.com>
6 * S5PC100 based common clock support
8 * Based on plat-s3c64xx/s3c6400-clock.c
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2 as
12 * published by the Free Software Foundation.
15 #include <linux/init.h>
16 #include <linux/module.h>
17 #include <linux/kernel.h>
18 #include <linux/list.h>
19 #include <linux/errno.h>
20 #include <linux/err.h>
21 #include <linux/clk.h>
22 #include <linux/sysdev.h>
23 #include <linux/io.h>
25 #include <mach/hardware.h>
26 #include <mach/map.h>
28 #include <plat/cpu-freq.h>
30 #include <plat/regs-clock.h>
31 #include <plat/clock.h>
32 #include <plat/cpu.h>
33 #include <plat/pll.h>
34 #include <plat/devs.h>
35 #include <plat/s5pc100.h>
37 /* fin_apll, fin_mpll and fin_epll are all the same clock, which we call
38 * ext_xtal_mux for want of an actual name from the manual.
41 static struct clk clk_ext_xtal_mux = {
42 .name = "ext_xtal",
43 .id = -1,
46 #define clk_fin_apll clk_ext_xtal_mux
47 #define clk_fin_mpll clk_ext_xtal_mux
48 #define clk_fin_epll clk_ext_xtal_mux
49 #define clk_fin_hpll clk_ext_xtal_mux
51 #define clk_fout_mpll clk_mpll
52 #define clk_vclk_54m clk_54m
54 struct clk_sources {
55 unsigned int nr_sources;
56 struct clk **sources;
59 struct clksrc_clk {
60 struct clk clk;
61 unsigned int mask;
62 unsigned int shift;
64 struct clk_sources *sources;
66 unsigned int divider_shift;
67 void __iomem *reg_divider;
68 void __iomem *reg_source;
71 /* APLL */
72 static struct clk clk_fout_apll = {
73 .name = "fout_apll",
74 .id = -1,
75 .rate = 27000000,
78 static struct clk *clk_src_apll_list[] = {
79 [0] = &clk_fin_apll,
80 [1] = &clk_fout_apll,
83 static struct clk_sources clk_src_apll = {
84 .sources = clk_src_apll_list,
85 .nr_sources = ARRAY_SIZE(clk_src_apll_list),
88 static struct clksrc_clk clk_mout_apll = {
89 .clk = {
90 .name = "mout_apll",
91 .id = -1,
93 .shift = S5PC100_CLKSRC0_APLL_SHIFT,
94 .mask = S5PC100_CLKSRC0_APLL_MASK,
95 .sources = &clk_src_apll,
96 .reg_source = S5PC100_CLKSRC0,
99 static unsigned long s5pc100_clk_dout_apll_get_rate(struct clk *clk)
101 unsigned long rate = clk_get_rate(clk->parent);
102 unsigned int ratio;
104 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_APLL_MASK;
105 ratio >>= S5PC100_CLKDIV0_APLL_SHIFT;
107 return rate / (ratio + 1);
110 static struct clk clk_dout_apll = {
111 .name = "dout_apll",
112 .id = -1,
113 .parent = &clk_mout_apll.clk,
114 .get_rate = s5pc100_clk_dout_apll_get_rate,
117 static unsigned long s5pc100_clk_arm_get_rate(struct clk *clk)
119 unsigned long rate = clk_get_rate(clk->parent);
120 unsigned int ratio;
122 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_ARM_MASK;
123 ratio >>= S5PC100_CLKDIV0_ARM_SHIFT;
125 return rate / (ratio + 1);
128 static unsigned long s5pc100_clk_arm_round_rate(struct clk *clk,
129 unsigned long rate)
131 unsigned long parent = clk_get_rate(clk->parent);
132 u32 div;
134 if (parent < rate)
135 return rate;
137 div = (parent / rate) - 1;
138 if (div > S5PC100_CLKDIV0_ARM_MASK)
139 div = S5PC100_CLKDIV0_ARM_MASK;
141 return parent / (div + 1);
144 static int s5pc100_clk_arm_set_rate(struct clk *clk, unsigned long rate)
146 unsigned long parent = clk_get_rate(clk->parent);
147 u32 div;
148 u32 val;
150 if (rate < parent / (S5PC100_CLKDIV0_ARM_MASK + 1))
151 return -EINVAL;
153 rate = clk_round_rate(clk, rate);
154 div = clk_get_rate(clk->parent) / rate;
156 val = __raw_readl(S5PC100_CLKDIV0);
157 val &= S5PC100_CLKDIV0_ARM_MASK;
158 val |= (div - 1);
159 __raw_writel(val, S5PC100_CLKDIV0);
161 return 0;
164 static struct clk clk_arm = {
165 .name = "armclk",
166 .id = -1,
167 .parent = &clk_dout_apll,
168 .get_rate = s5pc100_clk_arm_get_rate,
169 .set_rate = s5pc100_clk_arm_set_rate,
170 .round_rate = s5pc100_clk_arm_round_rate,
173 static unsigned long s5pc100_clk_dout_d0_bus_get_rate(struct clk *clk)
175 unsigned long rate = clk_get_rate(clk->parent);
176 unsigned int ratio;
178 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_D0_MASK;
179 ratio >>= S5PC100_CLKDIV0_D0_SHIFT;
181 return rate / (ratio + 1);
184 static struct clk clk_dout_d0_bus = {
185 .name = "dout_d0_bus",
186 .id = -1,
187 .parent = &clk_arm,
188 .get_rate = s5pc100_clk_dout_d0_bus_get_rate,
191 static unsigned long s5pc100_clk_dout_pclkd0_get_rate(struct clk *clk)
193 unsigned long rate = clk_get_rate(clk->parent);
194 unsigned int ratio;
196 ratio = __raw_readl(S5PC100_CLKDIV0) & S5PC100_CLKDIV0_PCLKD0_MASK;
197 ratio >>= S5PC100_CLKDIV0_PCLKD0_SHIFT;
199 return rate / (ratio + 1);
202 static struct clk clk_dout_pclkd0 = {
203 .name = "dout_pclkd0",
204 .id = -1,
205 .parent = &clk_dout_d0_bus,
206 .get_rate = s5pc100_clk_dout_pclkd0_get_rate,
209 static unsigned long s5pc100_clk_dout_apll2_get_rate(struct clk *clk)
211 unsigned long rate = clk_get_rate(clk->parent);
212 unsigned int ratio;
214 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_APLL2_MASK;
215 ratio >>= S5PC100_CLKDIV1_APLL2_SHIFT;
217 return rate / (ratio + 1);
220 static struct clk clk_dout_apll2 = {
221 .name = "dout_apll2",
222 .id = -1,
223 .parent = &clk_mout_apll.clk,
224 .get_rate = s5pc100_clk_dout_apll2_get_rate,
227 /* MPLL */
228 static struct clk *clk_src_mpll_list[] = {
229 [0] = &clk_fin_mpll,
230 [1] = &clk_fout_mpll,
233 static struct clk_sources clk_src_mpll = {
234 .sources = clk_src_mpll_list,
235 .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
238 static struct clksrc_clk clk_mout_mpll = {
239 .clk = {
240 .name = "mout_mpll",
241 .id = -1,
243 .shift = S5PC100_CLKSRC0_MPLL_SHIFT,
244 .mask = S5PC100_CLKSRC0_MPLL_MASK,
245 .sources = &clk_src_mpll,
246 .reg_source = S5PC100_CLKSRC0,
249 static struct clk *clkset_am_list[] = {
250 [0] = &clk_mout_mpll.clk,
251 [1] = &clk_dout_apll2,
254 static struct clk_sources clk_src_am = {
255 .sources = clkset_am_list,
256 .nr_sources = ARRAY_SIZE(clkset_am_list),
259 static struct clksrc_clk clk_mout_am = {
260 .clk = {
261 .name = "mout_am",
262 .id = -1,
264 .shift = S5PC100_CLKSRC0_AMMUX_SHIFT,
265 .mask = S5PC100_CLKSRC0_AMMUX_MASK,
266 .sources = &clk_src_am,
267 .reg_source = S5PC100_CLKSRC0,
270 static unsigned long s5pc100_clk_dout_d1_bus_get_rate(struct clk *clk)
272 unsigned long rate = clk_get_rate(clk->parent);
273 unsigned int ratio;
275 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
277 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_D1_MASK;
278 ratio >>= S5PC100_CLKDIV1_D1_SHIFT;
280 return rate / (ratio + 1);
283 static struct clk clk_dout_d1_bus = {
284 .name = "dout_d1_bus",
285 .id = -1,
286 .parent = &clk_mout_am.clk,
287 .get_rate = s5pc100_clk_dout_d1_bus_get_rate,
290 static struct clk *clkset_onenand_list[] = {
291 [0] = &clk_dout_d0_bus,
292 [1] = &clk_dout_d1_bus,
295 static struct clk_sources clk_src_onenand = {
296 .sources = clkset_onenand_list,
297 .nr_sources = ARRAY_SIZE(clkset_onenand_list),
300 static struct clksrc_clk clk_mout_onenand = {
301 .clk = {
302 .name = "mout_onenand",
303 .id = -1,
305 .shift = S5PC100_CLKSRC0_ONENAND_SHIFT,
306 .mask = S5PC100_CLKSRC0_ONENAND_MASK,
307 .sources = &clk_src_onenand,
308 .reg_source = S5PC100_CLKSRC0,
311 static unsigned long s5pc100_clk_dout_pclkd1_get_rate(struct clk *clk)
313 unsigned long rate = clk_get_rate(clk->parent);
314 unsigned int ratio;
316 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
318 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_PCLKD1_MASK;
319 ratio >>= S5PC100_CLKDIV1_PCLKD1_SHIFT;
321 return rate / (ratio + 1);
324 static struct clk clk_dout_pclkd1 = {
325 .name = "dout_pclkd1",
326 .id = -1,
327 .parent = &clk_dout_d1_bus,
328 .get_rate = s5pc100_clk_dout_pclkd1_get_rate,
331 static unsigned long s5pc100_clk_dout_mpll2_get_rate(struct clk *clk)
333 unsigned long rate = clk_get_rate(clk->parent);
334 unsigned int ratio;
336 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
338 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
339 ratio >>= S5PC100_CLKDIV1_MPLL2_SHIFT;
341 return rate / (ratio + 1);
344 static struct clk clk_dout_mpll2 = {
345 .name = "dout_mpll2",
346 .id = -1,
347 .parent = &clk_mout_am.clk,
348 .get_rate = s5pc100_clk_dout_mpll2_get_rate,
351 static unsigned long s5pc100_clk_dout_cam_get_rate(struct clk *clk)
353 unsigned long rate = clk_get_rate(clk->parent);
354 unsigned int ratio;
356 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
358 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_CAM_MASK;
359 ratio >>= S5PC100_CLKDIV1_CAM_SHIFT;
361 return rate / (ratio + 1);
364 static struct clk clk_dout_cam = {
365 .name = "dout_cam",
366 .id = -1,
367 .parent = &clk_dout_mpll2,
368 .get_rate = s5pc100_clk_dout_cam_get_rate,
371 static unsigned long s5pc100_clk_dout_mpll_get_rate(struct clk *clk)
373 unsigned long rate = clk_get_rate(clk->parent);
374 unsigned int ratio;
376 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
378 ratio = __raw_readl(S5PC100_CLKDIV1) & S5PC100_CLKDIV1_MPLL_MASK;
379 ratio >>= S5PC100_CLKDIV1_MPLL_SHIFT;
381 return rate / (ratio + 1);
384 static struct clk clk_dout_mpll = {
385 .name = "dout_mpll",
386 .id = -1,
387 .parent = &clk_mout_am.clk,
388 .get_rate = s5pc100_clk_dout_mpll_get_rate,
391 /* EPLL */
392 static struct clk clk_fout_epll = {
393 .name = "fout_epll",
394 .id = -1,
397 static struct clk *clk_src_epll_list[] = {
398 [0] = &clk_fin_epll,
399 [1] = &clk_fout_epll,
402 static struct clk_sources clk_src_epll = {
403 .sources = clk_src_epll_list,
404 .nr_sources = ARRAY_SIZE(clk_src_epll_list),
407 static struct clksrc_clk clk_mout_epll = {
408 .clk = {
409 .name = "mout_epll",
410 .id = -1,
412 .shift = S5PC100_CLKSRC0_EPLL_SHIFT,
413 .mask = S5PC100_CLKSRC0_EPLL_MASK,
414 .sources = &clk_src_epll,
415 .reg_source = S5PC100_CLKSRC0,
418 /* HPLL */
419 static struct clk clk_fout_hpll = {
420 .name = "fout_hpll",
421 .id = -1,
424 static struct clk *clk_src_hpll_list[] = {
425 [0] = &clk_27m,
426 [1] = &clk_fout_hpll,
429 static struct clk_sources clk_src_hpll = {
430 .sources = clk_src_hpll_list,
431 .nr_sources = ARRAY_SIZE(clk_src_hpll_list),
434 static struct clksrc_clk clk_mout_hpll = {
435 .clk = {
436 .name = "mout_hpll",
437 .id = -1,
439 .shift = S5PC100_CLKSRC0_HPLL_SHIFT,
440 .mask = S5PC100_CLKSRC0_HPLL_MASK,
441 .sources = &clk_src_hpll,
442 .reg_source = S5PC100_CLKSRC0,
445 /* Peripherals */
447 * The peripheral clocks are all controlled via clocksource followed
448 * by an optional divider and gate stage. We currently roll this into
449 * one clock which hides the intermediate clock from the mux.
451 * Note, the JPEG clock can only be an even divider...
453 * The scaler and LCD clocks depend on the S5PC100 version, and also
454 * have a common parent divisor so are not included here.
457 static inline struct clksrc_clk *to_clksrc(struct clk *clk)
459 return container_of(clk, struct clksrc_clk, clk);
462 static unsigned long s5pc100_getrate_clksrc(struct clk *clk)
464 struct clksrc_clk *sclk = to_clksrc(clk);
465 unsigned long rate = clk_get_rate(clk->parent);
466 u32 clkdiv = __raw_readl(sclk->reg_divider);
468 clkdiv >>= sclk->divider_shift;
469 clkdiv &= 0xf;
470 clkdiv++;
472 rate /= clkdiv;
473 return rate;
476 static int s5pc100_setrate_clksrc(struct clk *clk, unsigned long rate)
478 struct clksrc_clk *sclk = to_clksrc(clk);
479 void __iomem *reg = sclk->reg_divider;
480 unsigned int div;
481 u32 val;
483 rate = clk_round_rate(clk, rate);
484 div = clk_get_rate(clk->parent) / rate;
485 if (div > 16)
486 return -EINVAL;
488 val = __raw_readl(reg);
489 val &= ~(0xf << sclk->divider_shift);
490 val |= (div - 1) << sclk->divider_shift;
491 __raw_writel(val, reg);
493 return 0;
496 static int s5pc100_setparent_clksrc(struct clk *clk, struct clk *parent)
498 struct clksrc_clk *sclk = to_clksrc(clk);
499 struct clk_sources *srcs = sclk->sources;
500 u32 clksrc = __raw_readl(sclk->reg_source);
501 int src_nr = -1;
502 int ptr;
504 for (ptr = 0; ptr < srcs->nr_sources; ptr++)
505 if (srcs->sources[ptr] == parent) {
506 src_nr = ptr;
507 break;
510 if (src_nr >= 0) {
511 clksrc &= ~sclk->mask;
512 clksrc |= src_nr << sclk->shift;
514 __raw_writel(clksrc, sclk->reg_source);
515 return 0;
518 return -EINVAL;
521 static unsigned long s5pc100_roundrate_clksrc(struct clk *clk,
522 unsigned long rate)
524 unsigned long parent_rate = clk_get_rate(clk->parent);
525 int div;
527 if (rate > parent_rate)
528 rate = parent_rate;
529 else {
530 div = rate / parent_rate;
532 if (div == 0)
533 div = 1;
534 if (div > 16)
535 div = 16;
537 rate = parent_rate / div;
540 return rate;
543 static struct clk *clkset_spi_list[] = {
544 &clk_mout_epll.clk,
545 &clk_dout_mpll2,
546 &clk_fin_epll,
547 &clk_mout_hpll.clk,
550 static struct clk_sources clkset_spi = {
551 .sources = clkset_spi_list,
552 .nr_sources = ARRAY_SIZE(clkset_spi_list),
555 static struct clksrc_clk clk_spi0 = {
556 .clk = {
557 .name = "spi_bus",
558 .id = 0,
559 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0,
560 .enable = s5pc100_sclk0_ctrl,
561 .set_parent = s5pc100_setparent_clksrc,
562 .get_rate = s5pc100_getrate_clksrc,
563 .set_rate = s5pc100_setrate_clksrc,
564 .round_rate = s5pc100_roundrate_clksrc,
566 .shift = S5PC100_CLKSRC1_SPI0_SHIFT,
567 .mask = S5PC100_CLKSRC1_SPI0_MASK,
568 .sources = &clkset_spi,
569 .divider_shift = S5PC100_CLKDIV2_SPI0_SHIFT,
570 .reg_divider = S5PC100_CLKDIV2,
571 .reg_source = S5PC100_CLKSRC1,
574 static struct clksrc_clk clk_spi1 = {
575 .clk = {
576 .name = "spi_bus",
577 .id = 1,
578 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1,
579 .enable = s5pc100_sclk0_ctrl,
580 .set_parent = s5pc100_setparent_clksrc,
581 .get_rate = s5pc100_getrate_clksrc,
582 .set_rate = s5pc100_setrate_clksrc,
583 .round_rate = s5pc100_roundrate_clksrc,
585 .shift = S5PC100_CLKSRC1_SPI1_SHIFT,
586 .mask = S5PC100_CLKSRC1_SPI1_MASK,
587 .sources = &clkset_spi,
588 .divider_shift = S5PC100_CLKDIV2_SPI1_SHIFT,
589 .reg_divider = S5PC100_CLKDIV2,
590 .reg_source = S5PC100_CLKSRC1,
593 static struct clksrc_clk clk_spi2 = {
594 .clk = {
595 .name = "spi_bus",
596 .id = 2,
597 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2,
598 .enable = s5pc100_sclk0_ctrl,
599 .set_parent = s5pc100_setparent_clksrc,
600 .get_rate = s5pc100_getrate_clksrc,
601 .set_rate = s5pc100_setrate_clksrc,
602 .round_rate = s5pc100_roundrate_clksrc,
604 .shift = S5PC100_CLKSRC1_SPI2_SHIFT,
605 .mask = S5PC100_CLKSRC1_SPI2_MASK,
606 .sources = &clkset_spi,
607 .divider_shift = S5PC100_CLKDIV2_SPI2_SHIFT,
608 .reg_divider = S5PC100_CLKDIV2,
609 .reg_source = S5PC100_CLKSRC1,
612 static struct clk *clkset_uart_list[] = {
613 &clk_mout_epll.clk,
614 &clk_dout_mpll,
617 static struct clk_sources clkset_uart = {
618 .sources = clkset_uart_list,
619 .nr_sources = ARRAY_SIZE(clkset_uart_list),
622 static struct clksrc_clk clk_uart_uclk1 = {
623 .clk = {
624 .name = "uclk1",
625 .id = -1,
626 .ctrlbit = S5PC100_CLKGATE_SCLK0_UART,
627 .enable = s5pc100_sclk0_ctrl,
628 .set_parent = s5pc100_setparent_clksrc,
629 .get_rate = s5pc100_getrate_clksrc,
630 .set_rate = s5pc100_setrate_clksrc,
631 .round_rate = s5pc100_roundrate_clksrc,
633 .shift = S5PC100_CLKSRC1_UART_SHIFT,
634 .mask = S5PC100_CLKSRC1_UART_MASK,
635 .sources = &clkset_uart,
636 .divider_shift = S5PC100_CLKDIV2_UART_SHIFT,
637 .reg_divider = S5PC100_CLKDIV2,
638 .reg_source = S5PC100_CLKSRC1,
641 static struct clk clk_iis_cd0 = {
642 .name = "iis_cdclk0",
643 .id = -1,
646 static struct clk clk_iis_cd1 = {
647 .name = "iis_cdclk1",
648 .id = -1,
651 static struct clk clk_iis_cd2 = {
652 .name = "iis_cdclk2",
653 .id = -1,
656 static struct clk clk_pcm_cd0 = {
657 .name = "pcm_cdclk0",
658 .id = -1,
661 static struct clk clk_pcm_cd1 = {
662 .name = "pcm_cdclk1",
663 .id = -1,
666 static struct clk *clkset_audio0_list[] = {
667 &clk_mout_epll.clk,
668 &clk_dout_mpll,
669 &clk_fin_epll,
670 &clk_iis_cd0,
671 &clk_pcm_cd0,
672 &clk_mout_hpll.clk,
675 static struct clk_sources clkset_audio0 = {
676 .sources = clkset_audio0_list,
677 .nr_sources = ARRAY_SIZE(clkset_audio0_list),
680 static struct clksrc_clk clk_audio0 = {
681 .clk = {
682 .name = "audio-bus",
683 .id = 0,
684 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO0,
685 .enable = s5pc100_sclk1_ctrl,
686 .set_parent = s5pc100_setparent_clksrc,
687 .get_rate = s5pc100_getrate_clksrc,
688 .set_rate = s5pc100_setrate_clksrc,
689 .round_rate = s5pc100_roundrate_clksrc,
691 .shift = S5PC100_CLKSRC3_AUDIO0_SHIFT,
692 .mask = S5PC100_CLKSRC3_AUDIO0_MASK,
693 .sources = &clkset_audio0,
694 .divider_shift = S5PC100_CLKDIV4_AUDIO0_SHIFT,
695 .reg_divider = S5PC100_CLKDIV4,
696 .reg_source = S5PC100_CLKSRC3,
699 static struct clk *clkset_audio1_list[] = {
700 &clk_mout_epll.clk,
701 &clk_dout_mpll,
702 &clk_fin_epll,
703 &clk_iis_cd1,
704 &clk_pcm_cd1,
705 &clk_mout_hpll.clk,
708 static struct clk_sources clkset_audio1 = {
709 .sources = clkset_audio1_list,
710 .nr_sources = ARRAY_SIZE(clkset_audio1_list),
713 static struct clksrc_clk clk_audio1 = {
714 .clk = {
715 .name = "audio-bus",
716 .id = 1,
717 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO1,
718 .enable = s5pc100_sclk1_ctrl,
719 .set_parent = s5pc100_setparent_clksrc,
720 .get_rate = s5pc100_getrate_clksrc,
721 .set_rate = s5pc100_setrate_clksrc,
722 .round_rate = s5pc100_roundrate_clksrc,
724 .shift = S5PC100_CLKSRC3_AUDIO1_SHIFT,
725 .mask = S5PC100_CLKSRC3_AUDIO1_MASK,
726 .sources = &clkset_audio1,
727 .divider_shift = S5PC100_CLKDIV4_AUDIO1_SHIFT,
728 .reg_divider = S5PC100_CLKDIV4,
729 .reg_source = S5PC100_CLKSRC3,
732 static struct clk *clkset_audio2_list[] = {
733 &clk_mout_epll.clk,
734 &clk_dout_mpll,
735 &clk_fin_epll,
736 &clk_iis_cd2,
737 &clk_mout_hpll.clk,
740 static struct clk_sources clkset_audio2 = {
741 .sources = clkset_audio2_list,
742 .nr_sources = ARRAY_SIZE(clkset_audio2_list),
745 static struct clksrc_clk clk_audio2 = {
746 .clk = {
747 .name = "audio-bus",
748 .id = 2,
749 .ctrlbit = S5PC100_CLKGATE_SCLK1_AUDIO2,
750 .enable = s5pc100_sclk1_ctrl,
751 .set_parent = s5pc100_setparent_clksrc,
752 .get_rate = s5pc100_getrate_clksrc,
753 .set_rate = s5pc100_setrate_clksrc,
754 .round_rate = s5pc100_roundrate_clksrc,
756 .shift = S5PC100_CLKSRC3_AUDIO2_SHIFT,
757 .mask = S5PC100_CLKSRC3_AUDIO2_MASK,
758 .sources = &clkset_audio2,
759 .divider_shift = S5PC100_CLKDIV4_AUDIO2_SHIFT,
760 .reg_divider = S5PC100_CLKDIV4,
761 .reg_source = S5PC100_CLKSRC3,
764 static struct clk *clkset_spdif_list[] = {
765 &clk_audio0.clk,
766 &clk_audio1.clk,
767 &clk_audio2.clk,
770 static struct clk_sources clkset_spdif = {
771 .sources = clkset_spdif_list,
772 .nr_sources = ARRAY_SIZE(clkset_spdif_list),
775 static struct clksrc_clk clk_spdif = {
776 .clk = {
777 .name = "spdif",
778 .id = -1,
780 .shift = S5PC100_CLKSRC3_SPDIF_SHIFT,
781 .mask = S5PC100_CLKSRC3_SPDIF_MASK,
782 .sources = &clkset_spdif,
783 .reg_source = S5PC100_CLKSRC3,
786 static struct clk *clkset_lcd_fimc_list[] = {
787 &clk_mout_epll.clk,
788 &clk_dout_mpll,
789 &clk_mout_hpll.clk,
790 &clk_vclk_54m,
793 static struct clk_sources clkset_lcd_fimc = {
794 .sources = clkset_lcd_fimc_list,
795 .nr_sources = ARRAY_SIZE(clkset_lcd_fimc_list),
798 static struct clksrc_clk clk_lcd = {
799 .clk = {
800 .name = "lcd",
801 .id = -1,
802 .ctrlbit = S5PC100_CLKGATE_SCLK1_LCD,
803 .enable = s5pc100_sclk1_ctrl,
804 .set_parent = s5pc100_setparent_clksrc,
805 .get_rate = s5pc100_getrate_clksrc,
806 .set_rate = s5pc100_setrate_clksrc,
807 .round_rate = s5pc100_roundrate_clksrc,
809 .shift = S5PC100_CLKSRC2_LCD_SHIFT,
810 .mask = S5PC100_CLKSRC2_LCD_MASK,
811 .sources = &clkset_lcd_fimc,
812 .divider_shift = S5PC100_CLKDIV3_LCD_SHIFT,
813 .reg_divider = S5PC100_CLKDIV3,
814 .reg_source = S5PC100_CLKSRC2,
817 static struct clksrc_clk clk_fimc0 = {
818 .clk = {
819 .name = "fimc",
820 .id = 0,
821 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC0,
822 .enable = s5pc100_sclk1_ctrl,
823 .set_parent = s5pc100_setparent_clksrc,
824 .get_rate = s5pc100_getrate_clksrc,
825 .set_rate = s5pc100_setrate_clksrc,
826 .round_rate = s5pc100_roundrate_clksrc,
828 .shift = S5PC100_CLKSRC2_FIMC0_SHIFT,
829 .mask = S5PC100_CLKSRC2_FIMC0_MASK,
830 .sources = &clkset_lcd_fimc,
831 .divider_shift = S5PC100_CLKDIV3_FIMC0_SHIFT,
832 .reg_divider = S5PC100_CLKDIV3,
833 .reg_source = S5PC100_CLKSRC2,
836 static struct clksrc_clk clk_fimc1 = {
837 .clk = {
838 .name = "fimc",
839 .id = 1,
840 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC1,
841 .enable = s5pc100_sclk1_ctrl,
842 .set_parent = s5pc100_setparent_clksrc,
843 .get_rate = s5pc100_getrate_clksrc,
844 .set_rate = s5pc100_setrate_clksrc,
845 .round_rate = s5pc100_roundrate_clksrc,
847 .shift = S5PC100_CLKSRC2_FIMC1_SHIFT,
848 .mask = S5PC100_CLKSRC2_FIMC1_MASK,
849 .sources = &clkset_lcd_fimc,
850 .divider_shift = S5PC100_CLKDIV3_FIMC1_SHIFT,
851 .reg_divider = S5PC100_CLKDIV3,
852 .reg_source = S5PC100_CLKSRC2,
855 static struct clksrc_clk clk_fimc2 = {
856 .clk = {
857 .name = "fimc",
858 .id = 2,
859 .ctrlbit = S5PC100_CLKGATE_SCLK1_FIMC2,
860 .enable = s5pc100_sclk1_ctrl,
861 .set_parent = s5pc100_setparent_clksrc,
862 .get_rate = s5pc100_getrate_clksrc,
863 .set_rate = s5pc100_setrate_clksrc,
864 .round_rate = s5pc100_roundrate_clksrc,
866 .shift = S5PC100_CLKSRC2_FIMC2_SHIFT,
867 .mask = S5PC100_CLKSRC2_FIMC2_MASK,
868 .sources = &clkset_lcd_fimc,
869 .divider_shift = S5PC100_CLKDIV3_FIMC2_SHIFT,
870 .reg_divider = S5PC100_CLKDIV3,
871 .reg_source = S5PC100_CLKSRC2,
874 static struct clk *clkset_mmc_list[] = {
875 &clk_mout_epll.clk,
876 &clk_dout_mpll,
877 &clk_fin_epll,
878 &clk_mout_hpll.clk ,
881 static struct clk_sources clkset_mmc = {
882 .sources = clkset_mmc_list,
883 .nr_sources = ARRAY_SIZE(clkset_mmc_list),
886 static struct clksrc_clk clk_mmc0 = {
887 .clk = {
888 .name = "mmc_bus",
889 .id = 0,
890 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0,
891 .enable = s5pc100_sclk0_ctrl,
892 .set_parent = s5pc100_setparent_clksrc,
893 .get_rate = s5pc100_getrate_clksrc,
894 .set_rate = s5pc100_setrate_clksrc,
895 .round_rate = s5pc100_roundrate_clksrc,
897 .shift = S5PC100_CLKSRC2_MMC0_SHIFT,
898 .mask = S5PC100_CLKSRC2_MMC0_MASK,
899 .sources = &clkset_mmc,
900 .divider_shift = S5PC100_CLKDIV3_MMC0_SHIFT,
901 .reg_divider = S5PC100_CLKDIV3,
902 .reg_source = S5PC100_CLKSRC2,
905 static struct clksrc_clk clk_mmc1 = {
906 .clk = {
907 .name = "mmc_bus",
908 .id = 1,
909 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1,
910 .enable = s5pc100_sclk0_ctrl,
911 .set_parent = s5pc100_setparent_clksrc,
912 .get_rate = s5pc100_getrate_clksrc,
913 .set_rate = s5pc100_setrate_clksrc,
914 .round_rate = s5pc100_roundrate_clksrc,
916 .shift = S5PC100_CLKSRC2_MMC1_SHIFT,
917 .mask = S5PC100_CLKSRC2_MMC1_MASK,
918 .sources = &clkset_mmc,
919 .divider_shift = S5PC100_CLKDIV3_MMC1_SHIFT,
920 .reg_divider = S5PC100_CLKDIV3,
921 .reg_source = S5PC100_CLKSRC2,
924 static struct clksrc_clk clk_mmc2 = {
925 .clk = {
926 .name = "mmc_bus",
927 .id = 2,
928 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2,
929 .enable = s5pc100_sclk0_ctrl,
930 .set_parent = s5pc100_setparent_clksrc,
931 .get_rate = s5pc100_getrate_clksrc,
932 .set_rate = s5pc100_setrate_clksrc,
933 .round_rate = s5pc100_roundrate_clksrc,
935 .shift = S5PC100_CLKSRC2_MMC2_SHIFT,
936 .mask = S5PC100_CLKSRC2_MMC2_MASK,
937 .sources = &clkset_mmc,
938 .divider_shift = S5PC100_CLKDIV3_MMC2_SHIFT,
939 .reg_divider = S5PC100_CLKDIV3,
940 .reg_source = S5PC100_CLKSRC2,
944 static struct clk *clkset_usbhost_list[] = {
945 &clk_mout_epll.clk,
946 &clk_dout_mpll,
947 &clk_mout_hpll.clk,
948 &clk_48m,
951 static struct clk_sources clkset_usbhost = {
952 .sources = clkset_usbhost_list,
953 .nr_sources = ARRAY_SIZE(clkset_usbhost_list),
956 static struct clksrc_clk clk_usbhost = {
957 .clk = {
958 .name = "usbhost",
959 .id = -1,
960 .ctrlbit = S5PC100_CLKGATE_SCLK0_USBHOST,
961 .enable = s5pc100_sclk0_ctrl,
962 .set_parent = s5pc100_setparent_clksrc,
963 .get_rate = s5pc100_getrate_clksrc,
964 .set_rate = s5pc100_setrate_clksrc,
965 .round_rate = s5pc100_roundrate_clksrc,
967 .shift = S5PC100_CLKSRC1_UHOST_SHIFT,
968 .mask = S5PC100_CLKSRC1_UHOST_MASK,
969 .sources = &clkset_usbhost,
970 .divider_shift = S5PC100_CLKDIV2_UHOST_SHIFT,
971 .reg_divider = S5PC100_CLKDIV2,
972 .reg_source = S5PC100_CLKSRC1,
975 /* Clock initialisation code */
977 static struct clksrc_clk *init_parents[] = {
978 &clk_mout_apll,
979 &clk_mout_mpll,
980 &clk_mout_am,
981 &clk_mout_onenand,
982 &clk_mout_epll,
983 &clk_mout_hpll,
984 &clk_spi0,
985 &clk_spi1,
986 &clk_spi2,
987 &clk_uart_uclk1,
988 &clk_audio0,
989 &clk_audio1,
990 &clk_audio2,
991 &clk_spdif,
992 &clk_lcd,
993 &clk_fimc0,
994 &clk_fimc1,
995 &clk_fimc2,
996 &clk_mmc0,
997 &clk_mmc1,
998 &clk_mmc2,
999 &clk_usbhost,
1002 static void __init_or_cpufreq s5pc100_set_clksrc(struct clksrc_clk *clk)
1004 struct clk_sources *srcs = clk->sources;
1005 u32 clksrc = __raw_readl(clk->reg_source);
1007 clksrc &= clk->mask;
1008 clksrc >>= clk->shift;
1010 if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
1011 printk(KERN_ERR "%s: bad source %d\n",
1012 clk->clk.name, clksrc);
1013 return;
1016 clk->clk.parent = srcs->sources[clksrc];
1018 printk(KERN_INFO "%s: source is %s (%d), rate is %ld.%03ld MHz\n",
1019 clk->clk.name, clk->clk.parent->name, clksrc,
1020 print_mhz(clk_get_rate(&clk->clk)));
1023 #define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
1025 void __init_or_cpufreq s5pc100_setup_clocks(void)
1027 struct clk *xtal_clk;
1028 unsigned long xtal;
1029 unsigned long armclk;
1030 unsigned long hclkd0;
1031 unsigned long hclk;
1032 unsigned long pclkd0;
1033 unsigned long pclk;
1034 unsigned long apll, mpll, epll, hpll;
1035 unsigned int ptr;
1036 u32 clkdiv0, clkdiv1;
1038 printk(KERN_DEBUG "%s: registering clocks\n", __func__);
1040 clkdiv0 = __raw_readl(S5PC100_CLKDIV0);
1041 clkdiv1 = __raw_readl(S5PC100_CLKDIV1);
1043 printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n", __func__, clkdiv0, clkdiv1);
1045 xtal_clk = clk_get(NULL, "xtal");
1046 BUG_ON(IS_ERR(xtal_clk));
1048 xtal = clk_get_rate(xtal_clk);
1049 clk_put(xtal_clk);
1051 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
1053 apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_APLL_CON));
1054 mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_MPLL_CON));
1055 epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_EPLL_CON));
1056 hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
1058 printk(KERN_INFO "S5PC100: Apll=%ld.%03ld Mhz, Mpll=%ld.%03ld Mhz"
1059 ", Epll=%ld.%03ld Mhz, Hpll=%ld.%03ld Mhz\n",
1060 print_mhz(apll), print_mhz(mpll),
1061 print_mhz(epll), print_mhz(hpll));
1063 armclk = apll / GET_DIV(clkdiv0, S5PC100_CLKDIV0_APLL);
1064 armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
1065 hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
1066 pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
1067 hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
1068 pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
1070 printk(KERN_INFO "S5PC100: ARMCLK=%ld.%03ld MHz, HCLKD0=%ld.%03ld MHz,"
1071 " PCLKD0=%ld.%03ld MHz\n, HCLK=%ld.%03ld MHz,"
1072 " PCLK=%ld.%03ld MHz\n",
1073 print_mhz(armclk), print_mhz(hclkd0),
1074 print_mhz(pclkd0), print_mhz(hclk), print_mhz(pclk));
1076 clk_fout_apll.rate = apll;
1077 clk_fout_mpll.rate = mpll;
1078 clk_fout_epll.rate = epll;
1079 clk_fout_hpll.rate = hpll;
1081 clk_h.rate = hclk;
1082 clk_p.rate = pclk;
1083 clk_f.rate = armclk;
1085 for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
1086 s5pc100_set_clksrc(init_parents[ptr]);
1089 static struct clk *clks[] __initdata = {
1090 &clk_ext_xtal_mux,
1091 &clk_mout_apll.clk,
1092 &clk_dout_apll,
1093 &clk_dout_d0_bus,
1094 &clk_dout_pclkd0,
1095 &clk_dout_apll2,
1096 &clk_mout_mpll.clk,
1097 &clk_mout_am.clk,
1098 &clk_dout_d1_bus,
1099 &clk_mout_onenand.clk,
1100 &clk_dout_pclkd1,
1101 &clk_dout_mpll2,
1102 &clk_dout_cam,
1103 &clk_dout_mpll,
1104 &clk_mout_epll.clk,
1105 &clk_fout_epll,
1106 &clk_iis_cd0,
1107 &clk_iis_cd1,
1108 &clk_iis_cd2,
1109 &clk_pcm_cd0,
1110 &clk_pcm_cd1,
1111 &clk_spi0.clk,
1112 &clk_spi1.clk,
1113 &clk_spi2.clk,
1114 &clk_uart_uclk1.clk,
1115 &clk_audio0.clk,
1116 &clk_audio1.clk,
1117 &clk_audio2.clk,
1118 &clk_spdif.clk,
1119 &clk_lcd.clk,
1120 &clk_fimc0.clk,
1121 &clk_fimc1.clk,
1122 &clk_fimc2.clk,
1123 &clk_mmc0.clk,
1124 &clk_mmc1.clk,
1125 &clk_mmc2.clk,
1126 &clk_usbhost.clk,
1127 &clk_arm,
1130 void __init s5pc100_register_clocks(void)
1132 struct clk *clkp;
1133 int ret;
1134 int ptr;
1136 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
1137 clkp = clks[ptr];
1138 ret = s3c24xx_register_clock(clkp);
1139 if (ret < 0) {
1140 printk(KERN_ERR "Failed to register clock %s (%d)\n",
1141 clkp->name, ret);