blob: 6b24035172fae65962efe8df08b17a4c24360bfe [file] [log] [blame]
Byungho Minc1cc3db2009-06-23 21:39:56 +09001/* linux/arch/arm/plat-s5pc1xx/s5pc100-clock.c
2 *
3 * Copyright 2009 Samsung Electronics, Co.
4 * Byungho Min <bhmin@samsung.com>
5 *
6 * S5PC100 based common clock support
7 *
8 * Based on plat-s3c64xx/s3c6400-clock.c
9 *
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.
13*/
14
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>
24
25#include <mach/hardware.h>
26#include <mach/map.h>
27
28#include <plat/cpu-freq.h>
29
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>
36
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.
39*/
40
41static struct clk clk_ext_xtal_mux = {
42 .name = "ext_xtal",
43 .id = -1,
44};
45
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
50
51#define clk_fout_mpll clk_mpll
52
53struct clk_sources {
54 unsigned int nr_sources;
55 struct clk **sources;
56};
57
58struct clksrc_clk {
59 struct clk clk;
60 unsigned int mask;
61 unsigned int shift;
62
63 struct clk_sources *sources;
64
65 unsigned int divider_shift;
66 void __iomem *reg_divider;
67 void __iomem *reg_source;
68};
69
70static int clk_default_setrate(struct clk *clk, unsigned long rate)
71{
72 clk->rate = rate;
73 return 1;
74}
75
76struct clk clk_27m = {
77 .name = "clk_27m",
78 .id = -1,
79 .rate = 27000000,
80};
81
82static int clk_48m_ctrl(struct clk *clk, int enable)
83{
84 unsigned long flags;
85 u32 val;
86
87 /* can't rely on clock lock, this register has other usages */
88 local_irq_save(flags);
89
90 val = __raw_readl(S5PC1XX_CLK_SRC1);
91 if (enable)
92 val |= S5PC100_CLKSRC1_CLK48M_MASK;
93 else
94 val &= ~S5PC100_CLKSRC1_CLK48M_MASK;
95
96 __raw_writel(val, S5PC1XX_CLK_SRC1);
97 local_irq_restore(flags);
98
99 return 0;
100}
101
102struct clk clk_48m = {
103 .name = "clk_48m",
104 .id = -1,
105 .rate = 48000000,
106 .enable = clk_48m_ctrl,
107};
108
109struct clk clk_54m = {
110 .name = "clk_54m",
111 .id = -1,
112 .rate = 54000000,
113};
114
115struct clk clk_hpll = {
116 .name = "hpll",
117 .id = -1,
118};
119
120struct clk clk_hd0 = {
121 .name = "hclkd0",
122 .id = -1,
123 .rate = 0,
124 .parent = NULL,
125 .ctrlbit = 0,
126 .set_rate = clk_default_setrate,
127};
128
129struct clk clk_pd0 = {
130 .name = "pclkd0",
131 .id = -1,
132 .rate = 0,
133 .parent = NULL,
134 .ctrlbit = 0,
135 .set_rate = clk_default_setrate,
136};
137
138static int s5pc1xx_clk_gate(void __iomem *reg,
139 struct clk *clk,
140 int enable)
141{
142 unsigned int ctrlbit = clk->ctrlbit;
143 u32 con;
144
145 con = __raw_readl(reg);
146
147 if (enable)
148 con |= ctrlbit;
149 else
150 con &= ~ctrlbit;
151
152 __raw_writel(con, reg);
153 return 0;
154}
155
156static int s5pc1xx_clk_d00_ctrl(struct clk *clk, int enable)
157{
158 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D00, clk, enable);
159}
160
161static int s5pc1xx_clk_d01_ctrl(struct clk *clk, int enable)
162{
163 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D01, clk, enable);
164}
165
166static int s5pc1xx_clk_d02_ctrl(struct clk *clk, int enable)
167{
168 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D02, clk, enable);
169}
170
171static int s5pc1xx_clk_d10_ctrl(struct clk *clk, int enable)
172{
173 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D10, clk, enable);
174}
175
176static int s5pc1xx_clk_d11_ctrl(struct clk *clk, int enable)
177{
178 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D11, clk, enable);
179}
180
181static int s5pc1xx_clk_d12_ctrl(struct clk *clk, int enable)
182{
183 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D12, clk, enable);
184}
185
186static int s5pc1xx_clk_d13_ctrl(struct clk *clk, int enable)
187{
188 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D13, clk, enable);
189}
190
191static int s5pc1xx_clk_d14_ctrl(struct clk *clk, int enable)
192{
193 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D14, clk, enable);
194}
195
196static int s5pc1xx_clk_d15_ctrl(struct clk *clk, int enable)
197{
198 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D15, clk, enable);
199}
200
201static int s5pc1xx_clk_d20_ctrl(struct clk *clk, int enable)
202{
203 return s5pc1xx_clk_gate(S5PC100_CLKGATE_D20, clk, enable);
204}
205
206int s5pc1xx_sclk0_ctrl(struct clk *clk, int enable)
207{
208 return s5pc1xx_clk_gate(S5PC100_SCLKGATE0, clk, enable);
209}
210
211int s5pc1xx_sclk1_ctrl(struct clk *clk, int enable)
212{
213 return s5pc1xx_clk_gate(S5PC100_SCLKGATE1, clk, enable);
214}
215
216static struct clk init_clocks_disable[] = {
217 {
218 .name = "dsi",
219 .id = -1,
220 .parent = &clk_p,
221 .enable = s5pc1xx_clk_d11_ctrl,
222 .ctrlbit = S5PC100_CLKGATE_D11_DSI,
223 }, {
224 .name = "csi",
225 .id = -1,
226 .parent = &clk_h,
227 .enable = s5pc1xx_clk_d11_ctrl,
228 .ctrlbit = S5PC100_CLKGATE_D11_CSI,
229 }, {
230 .name = "ccan0",
231 .id = 0,
232 .parent = &clk_p,
233 .enable = s5pc1xx_clk_d14_ctrl,
234 .ctrlbit = S5PC100_CLKGATE_D14_CCAN0,
235 }, {
236 .name = "ccan1",
237 .id = 1,
238 .parent = &clk_p,
239 .enable = s5pc1xx_clk_d14_ctrl,
240 .ctrlbit = S5PC100_CLKGATE_D14_CCAN1,
241 }, {
242 .name = "keypad",
243 .id = -1,
244 .parent = &clk_p,
245 .enable = s5pc1xx_clk_d15_ctrl,
246 .ctrlbit = S5PC100_CLKGATE_D15_KEYIF,
247 }, {
248 .name = "hclkd2",
249 .id = -1,
250 .parent = NULL,
251 .enable = s5pc1xx_clk_d20_ctrl,
252 .ctrlbit = S5PC100_CLKGATE_D20_HCLKD2,
253 }, {
254 .name = "iis-d2",
255 .id = -1,
256 .parent = NULL,
257 .enable = s5pc1xx_clk_d20_ctrl,
258 .ctrlbit = S5PC100_CLKGATE_D20_I2SD2,
259 }, {
260 .name = "otg",
261 .id = -1,
262 .parent = &clk_h,
263 .enable = s5pc1xx_clk_d10_ctrl,
264 .ctrlbit = S5PC100_CLKGATE_D10_USBOTG,
265 },
266};
267
268static struct clk init_clocks[] = {
269 /* System1 (D0_0) devices */
270 {
271 .name = "intc",
272 .id = -1,
273 .parent = &clk_hd0,
274 .enable = s5pc1xx_clk_d00_ctrl,
275 .ctrlbit = S5PC100_CLKGATE_D00_INTC,
276 }, {
277 .name = "tzic",
278 .id = -1,
279 .parent = &clk_hd0,
280 .enable = s5pc1xx_clk_d00_ctrl,
281 .ctrlbit = S5PC100_CLKGATE_D00_TZIC,
282 }, {
283 .name = "cf-ata",
284 .id = -1,
285 .parent = &clk_hd0,
286 .enable = s5pc1xx_clk_d00_ctrl,
287 .ctrlbit = S5PC100_CLKGATE_D00_CFCON,
288 }, {
289 .name = "mdma",
290 .id = -1,
291 .parent = &clk_hd0,
292 .enable = s5pc1xx_clk_d00_ctrl,
293 .ctrlbit = S5PC100_CLKGATE_D00_MDMA,
294 }, {
295 .name = "g2d",
296 .id = -1,
297 .parent = &clk_hd0,
298 .enable = s5pc1xx_clk_d00_ctrl,
299 .ctrlbit = S5PC100_CLKGATE_D00_G2D,
300 }, {
301 .name = "secss",
302 .id = -1,
303 .parent = &clk_hd0,
304 .enable = s5pc1xx_clk_d00_ctrl,
305 .ctrlbit = S5PC100_CLKGATE_D00_SECSS,
306 }, {
307 .name = "cssys",
308 .id = -1,
309 .parent = &clk_hd0,
310 .enable = s5pc1xx_clk_d00_ctrl,
311 .ctrlbit = S5PC100_CLKGATE_D00_CSSYS,
312 },
313
314 /* Memory (D0_1) devices */
315 {
316 .name = "dmc",
317 .id = -1,
318 .parent = &clk_hd0,
319 .enable = s5pc1xx_clk_d01_ctrl,
320 .ctrlbit = S5PC100_CLKGATE_D01_DMC,
321 }, {
322 .name = "sromc",
323 .id = -1,
324 .parent = &clk_hd0,
325 .enable = s5pc1xx_clk_d01_ctrl,
326 .ctrlbit = S5PC100_CLKGATE_D01_SROMC,
327 }, {
328 .name = "onenand",
329 .id = -1,
330 .parent = &clk_hd0,
331 .enable = s5pc1xx_clk_d01_ctrl,
332 .ctrlbit = S5PC100_CLKGATE_D01_ONENAND,
333 }, {
334 .name = "nand",
335 .id = -1,
336 .parent = &clk_hd0,
337 .enable = s5pc1xx_clk_d01_ctrl,
338 .ctrlbit = S5PC100_CLKGATE_D01_NFCON,
339 }, {
340 .name = "intmem",
341 .id = -1,
342 .parent = &clk_hd0,
343 .enable = s5pc1xx_clk_d01_ctrl,
344 .ctrlbit = S5PC100_CLKGATE_D01_INTMEM,
345 }, {
346 .name = "ebi",
347 .id = -1,
348 .parent = &clk_hd0,
349 .enable = s5pc1xx_clk_d01_ctrl,
350 .ctrlbit = S5PC100_CLKGATE_D01_EBI,
351 },
352
353 /* System2 (D0_2) devices */
354 {
355 .name = "seckey",
356 .id = -1,
357 .parent = &clk_pd0,
358 .enable = s5pc1xx_clk_d02_ctrl,
359 .ctrlbit = S5PC100_CLKGATE_D02_SECKEY,
360 }, {
361 .name = "sdm",
362 .id = -1,
363 .parent = &clk_hd0,
364 .enable = s5pc1xx_clk_d02_ctrl,
365 .ctrlbit = S5PC100_CLKGATE_D02_SDM,
366 },
367
368 /* File (D1_0) devices */
369 {
370 .name = "pdma0",
371 .id = -1,
372 .parent = &clk_h,
373 .enable = s5pc1xx_clk_d10_ctrl,
374 .ctrlbit = S5PC100_CLKGATE_D10_PDMA0,
375 }, {
376 .name = "pdma1",
377 .id = -1,
378 .parent = &clk_h,
379 .enable = s5pc1xx_clk_d10_ctrl,
380 .ctrlbit = S5PC100_CLKGATE_D10_PDMA1,
381 }, {
382 .name = "usb-host",
383 .id = -1,
384 .parent = &clk_h,
385 .enable = s5pc1xx_clk_d10_ctrl,
386 .ctrlbit = S5PC100_CLKGATE_D10_USBHOST,
387 }, {
388 .name = "modem",
389 .id = -1,
390 .parent = &clk_h,
391 .enable = s5pc1xx_clk_d10_ctrl,
392 .ctrlbit = S5PC100_CLKGATE_D10_MODEMIF,
393 }, {
394 .name = "hsmmc",
395 .id = 0,
396 .parent = &clk_h,
397 .enable = s5pc1xx_clk_d10_ctrl,
398 .ctrlbit = S5PC100_CLKGATE_D10_HSMMC0,
399 }, {
400 .name = "hsmmc",
401 .id = 1,
402 .parent = &clk_h,
403 .enable = s5pc1xx_clk_d10_ctrl,
404 .ctrlbit = S5PC100_CLKGATE_D10_HSMMC1,
405 }, {
406 .name = "hsmmc",
407 .id = 2,
408 .parent = &clk_h,
409 .enable = s5pc1xx_clk_d10_ctrl,
410 .ctrlbit = S5PC100_CLKGATE_D10_HSMMC2,
411 },
412
413 /* Multimedia1 (D1_1) devices */
414 {
415 .name = "lcd",
416 .id = -1,
417 .parent = &clk_h,
418 .enable = s5pc1xx_clk_d11_ctrl,
419 .ctrlbit = S5PC100_CLKGATE_D11_LCD,
420 }, {
421 .name = "rotator",
422 .id = -1,
423 .parent = &clk_h,
424 .enable = s5pc1xx_clk_d11_ctrl,
425 .ctrlbit = S5PC100_CLKGATE_D11_ROTATOR,
426 }, {
427 .name = "fimc",
428 .id = 0,
429 .parent = &clk_h,
430 .enable = s5pc1xx_clk_d11_ctrl,
431 .ctrlbit = S5PC100_CLKGATE_D11_FIMC0,
432 }, {
433 .name = "fimc",
434 .id = 1,
435 .parent = &clk_h,
436 .enable = s5pc1xx_clk_d11_ctrl,
437 .ctrlbit = S5PC100_CLKGATE_D11_FIMC1,
438 }, {
439 .name = "fimc",
440 .id = 2,
441 .parent = &clk_h,
442 .enable = s5pc1xx_clk_d11_ctrl,
443 .ctrlbit = S5PC100_CLKGATE_D11_FIMC2,
444 }, {
445 .name = "jpeg",
446 .id = -1,
447 .parent = &clk_h,
448 .enable = s5pc1xx_clk_d11_ctrl,
449 .ctrlbit = S5PC100_CLKGATE_D11_JPEG,
450 }, {
451 .name = "g3d",
452 .id = -1,
453 .parent = &clk_h,
454 .enable = s5pc1xx_clk_d11_ctrl,
455 .ctrlbit = S5PC100_CLKGATE_D11_G3D,
456 },
457
458 /* Multimedia2 (D1_2) devices */
459 {
460 .name = "tv",
461 .id = -1,
462 .parent = &clk_h,
463 .enable = s5pc1xx_clk_d12_ctrl,
464 .ctrlbit = S5PC100_CLKGATE_D12_TV,
465 }, {
466 .name = "vp",
467 .id = -1,
468 .parent = &clk_h,
469 .enable = s5pc1xx_clk_d12_ctrl,
470 .ctrlbit = S5PC100_CLKGATE_D12_VP,
471 }, {
472 .name = "mixer",
473 .id = -1,
474 .parent = &clk_h,
475 .enable = s5pc1xx_clk_d12_ctrl,
476 .ctrlbit = S5PC100_CLKGATE_D12_MIXER,
477 }, {
478 .name = "hdmi",
479 .id = -1,
480 .parent = &clk_h,
481 .enable = s5pc1xx_clk_d12_ctrl,
482 .ctrlbit = S5PC100_CLKGATE_D12_HDMI,
483 }, {
484 .name = "mfc",
485 .id = -1,
486 .parent = &clk_h,
487 .enable = s5pc1xx_clk_d12_ctrl,
488 .ctrlbit = S5PC100_CLKGATE_D12_MFC,
489 },
490
491 /* System (D1_3) devices */
492 {
493 .name = "chipid",
494 .id = -1,
495 .parent = &clk_p,
496 .enable = s5pc1xx_clk_d13_ctrl,
497 .ctrlbit = S5PC100_CLKGATE_D13_CHIPID,
498 }, {
499 .name = "gpio",
500 .id = -1,
501 .parent = &clk_p,
502 .enable = s5pc1xx_clk_d13_ctrl,
503 .ctrlbit = S5PC100_CLKGATE_D13_GPIO,
504 }, {
505 .name = "apc",
506 .id = -1,
507 .parent = &clk_p,
508 .enable = s5pc1xx_clk_d13_ctrl,
509 .ctrlbit = S5PC100_CLKGATE_D13_APC,
510 }, {
511 .name = "iec",
512 .id = -1,
513 .parent = &clk_p,
514 .enable = s5pc1xx_clk_d13_ctrl,
515 .ctrlbit = S5PC100_CLKGATE_D13_IEC,
516 }, {
517 .name = "timers",
518 .id = -1,
519 .parent = &clk_p,
520 .enable = s5pc1xx_clk_d13_ctrl,
521 .ctrlbit = S5PC100_CLKGATE_D13_PWM,
522 }, {
523 .name = "systimer",
524 .id = -1,
525 .parent = &clk_p,
526 .enable = s5pc1xx_clk_d13_ctrl,
527 .ctrlbit = S5PC100_CLKGATE_D13_SYSTIMER,
528 }, {
529 .name = "watchdog",
530 .id = -1,
531 .parent = &clk_p,
532 .enable = s5pc1xx_clk_d13_ctrl,
533 .ctrlbit = S5PC100_CLKGATE_D13_WDT,
534 }, {
535 .name = "rtc",
536 .id = -1,
537 .parent = &clk_p,
538 .enable = s5pc1xx_clk_d13_ctrl,
539 .ctrlbit = S5PC100_CLKGATE_D13_RTC,
540 },
541
542 /* Connectivity (D1_4) devices */
543 {
544 .name = "uart",
545 .id = 0,
546 .parent = &clk_p,
547 .enable = s5pc1xx_clk_d14_ctrl,
548 .ctrlbit = S5PC100_CLKGATE_D14_UART0,
549 }, {
550 .name = "uart",
551 .id = 1,
552 .parent = &clk_p,
553 .enable = s5pc1xx_clk_d14_ctrl,
554 .ctrlbit = S5PC100_CLKGATE_D14_UART1,
555 }, {
556 .name = "uart",
557 .id = 2,
558 .parent = &clk_p,
559 .enable = s5pc1xx_clk_d14_ctrl,
560 .ctrlbit = S5PC100_CLKGATE_D14_UART2,
561 }, {
562 .name = "uart",
563 .id = 3,
564 .parent = &clk_p,
565 .enable = s5pc1xx_clk_d14_ctrl,
566 .ctrlbit = S5PC100_CLKGATE_D14_UART3,
567 }, {
568 .name = "i2c",
569 .id = -1,
570 .parent = &clk_p,
571 .enable = s5pc1xx_clk_d14_ctrl,
572 .ctrlbit = S5PC100_CLKGATE_D14_IIC,
573 }, {
574 .name = "hdmi-i2c",
575 .id = -1,
576 .parent = &clk_p,
577 .enable = s5pc1xx_clk_d14_ctrl,
578 .ctrlbit = S5PC100_CLKGATE_D14_HDMI_IIC,
579 }, {
580 .name = "spi",
581 .id = 0,
582 .parent = &clk_p,
583 .enable = s5pc1xx_clk_d14_ctrl,
584 .ctrlbit = S5PC100_CLKGATE_D14_SPI0,
585 }, {
586 .name = "spi",
587 .id = 1,
588 .parent = &clk_p,
589 .enable = s5pc1xx_clk_d14_ctrl,
590 .ctrlbit = S5PC100_CLKGATE_D14_SPI1,
591 }, {
592 .name = "spi",
593 .id = 2,
594 .parent = &clk_p,
595 .enable = s5pc1xx_clk_d14_ctrl,
596 .ctrlbit = S5PC100_CLKGATE_D14_SPI2,
597 }, {
598 .name = "irda",
599 .id = -1,
600 .parent = &clk_p,
601 .enable = s5pc1xx_clk_d14_ctrl,
602 .ctrlbit = S5PC100_CLKGATE_D14_IRDA,
603 }, {
604 .name = "hsitx",
605 .id = -1,
606 .parent = &clk_p,
607 .enable = s5pc1xx_clk_d14_ctrl,
608 .ctrlbit = S5PC100_CLKGATE_D14_HSITX,
609 }, {
610 .name = "hsirx",
611 .id = -1,
612 .parent = &clk_p,
613 .enable = s5pc1xx_clk_d14_ctrl,
614 .ctrlbit = S5PC100_CLKGATE_D14_HSIRX,
615 },
616
617 /* Audio (D1_5) devices */
618 {
619 .name = "iis",
620 .id = 0,
621 .parent = &clk_p,
622 .enable = s5pc1xx_clk_d15_ctrl,
623 .ctrlbit = S5PC100_CLKGATE_D15_IIS0,
624 }, {
625 .name = "iis",
626 .id = 1,
627 .parent = &clk_p,
628 .enable = s5pc1xx_clk_d15_ctrl,
629 .ctrlbit = S5PC100_CLKGATE_D15_IIS1,
630 }, {
631 .name = "iis",
632 .id = 2,
633 .parent = &clk_p,
634 .enable = s5pc1xx_clk_d15_ctrl,
635 .ctrlbit = S5PC100_CLKGATE_D15_IIS2,
636 }, {
637 .name = "ac97",
638 .id = -1,
639 .parent = &clk_p,
640 .enable = s5pc1xx_clk_d15_ctrl,
641 .ctrlbit = S5PC100_CLKGATE_D15_AC97,
642 }, {
643 .name = "pcm",
644 .id = 0,
645 .parent = &clk_p,
646 .enable = s5pc1xx_clk_d15_ctrl,
647 .ctrlbit = S5PC100_CLKGATE_D15_PCM0,
648 }, {
649 .name = "pcm",
650 .id = 1,
651 .parent = &clk_p,
652 .enable = s5pc1xx_clk_d15_ctrl,
653 .ctrlbit = S5PC100_CLKGATE_D15_PCM1,
654 }, {
655 .name = "spdif",
656 .id = -1,
657 .parent = &clk_p,
658 .enable = s5pc1xx_clk_d15_ctrl,
659 .ctrlbit = S5PC100_CLKGATE_D15_SPDIF,
660 }, {
661 .name = "adc",
662 .id = -1,
663 .parent = &clk_p,
664 .enable = s5pc1xx_clk_d15_ctrl,
665 .ctrlbit = S5PC100_CLKGATE_D15_TSADC,
666 }, {
667 .name = "keyif",
668 .id = -1,
669 .parent = &clk_p,
670 .enable = s5pc1xx_clk_d15_ctrl,
671 .ctrlbit = S5PC100_CLKGATE_D15_KEYIF,
672 }, {
673 .name = "cg",
674 .id = -1,
675 .parent = &clk_p,
676 .enable = s5pc1xx_clk_d15_ctrl,
677 .ctrlbit = S5PC100_CLKGATE_D15_CG,
678 },
679
680 /* Audio (D2_0) devices: all disabled */
681
682 /* Special Clocks 1 */
683 {
684 .name = "sclk_hpm",
685 .id = -1,
686 .parent = NULL,
687 .enable = s5pc1xx_sclk0_ctrl,
688 .ctrlbit = S5PC1XX_CLKGATE_SCLK0_HPM,
689 }, {
690 .name = "sclk_onenand",
691 .id = -1,
692 .parent = NULL,
693 .enable = s5pc1xx_sclk0_ctrl,
694 .ctrlbit = S5PC100_CLKGATE_SCLK0_ONENAND,
695 }, {
696 .name = "sclk_spi_48",
697 .id = 0,
698 .parent = &clk_48m,
699 .enable = s5pc1xx_sclk0_ctrl,
700 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI0_48,
701 }, {
702 .name = "sclk_spi_48",
703 .id = 1,
704 .parent = &clk_48m,
705 .enable = s5pc1xx_sclk0_ctrl,
706 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI1_48,
707 }, {
708 .name = "sclk_spi_48",
709 .id = 2,
710 .parent = &clk_48m,
711 .enable = s5pc1xx_sclk0_ctrl,
712 .ctrlbit = S5PC100_CLKGATE_SCLK0_SPI2_48,
713 }, {
714 .name = "sclk_mmc_48",
715 .id = 0,
716 .parent = &clk_48m,
717 .enable = s5pc1xx_sclk0_ctrl,
718 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC0_48,
719 }, {
720 .name = "sclk_mmc_48",
721 .id = 1,
722 .parent = &clk_48m,
723 .enable = s5pc1xx_sclk0_ctrl,
724 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC1_48,
725 }, {
726 .name = "sclk_mmc_48",
727 .id = 2,
728 .parent = &clk_48m,
729 .enable = s5pc1xx_sclk0_ctrl,
730 .ctrlbit = S5PC100_CLKGATE_SCLK0_MMC2_48,
731 },
732
733 /* Special Clocks 2 */
734 {
735 .name = "sclk_tv_54",
736 .id = -1,
737 .parent = &clk_54m,
738 .enable = s5pc1xx_sclk1_ctrl,
739 .ctrlbit = S5PC100_CLKGATE_SCLK1_TV54,
740 }, {
741 .name = "sclk_vdac_54",
742 .id = -1,
743 .parent = &clk_54m,
744 .enable = s5pc1xx_sclk1_ctrl,
745 .ctrlbit = S5PC100_CLKGATE_SCLK1_VDAC54,
746 }, {
747 .name = "sclk_spdif",
748 .id = -1,
749 .parent = NULL,
750 .enable = s5pc1xx_sclk1_ctrl,
751 .ctrlbit = S5PC100_CLKGATE_SCLK1_SPDIF,
752 },
753};
754
755void __init s5pc1xx_register_clocks(void)
756{
757 struct clk *clkp;
758 int ret;
759 int ptr;
760
761 clkp = init_clocks;
762 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
763 ret = s3c24xx_register_clock(clkp);
764 if (ret < 0) {
765 printk(KERN_ERR "Failed to register clock %s (%d)\n",
766 clkp->name, ret);
767 }
768 }
769
770 clkp = init_clocks_disable;
771 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
772
773 ret = s3c24xx_register_clock(clkp);
774 if (ret < 0) {
775 printk(KERN_ERR "Failed to register clock %s (%d)\n",
776 clkp->name, ret);
777 }
778
779 (clkp->enable)(clkp, 0);
780 }
781
782 s3c_pwmclk_init();
783}
784static struct clk clk_fout_apll = {
785 .name = "fout_apll",
786 .id = -1,
787};
788
789static struct clk *clk_src_apll_list[] = {
790 [0] = &clk_fin_apll,
791 [1] = &clk_fout_apll,
792};
793
794static struct clk_sources clk_src_apll = {
795 .sources = clk_src_apll_list,
796 .nr_sources = ARRAY_SIZE(clk_src_apll_list),
797};
798
799static struct clksrc_clk clk_mout_apll = {
800 .clk = {
801 .name = "mout_apll",
802 .id = -1,
803 },
804 .shift = S5PC1XX_CLKSRC0_APLL_SHIFT,
805 .mask = S5PC1XX_CLKSRC0_APLL_MASK,
806 .sources = &clk_src_apll,
807 .reg_source = S5PC1XX_CLK_SRC0,
808};
809
810static struct clk clk_fout_epll = {
811 .name = "fout_epll",
812 .id = -1,
813};
814
815static struct clk *clk_src_epll_list[] = {
816 [0] = &clk_fin_epll,
817 [1] = &clk_fout_epll,
818};
819
820static struct clk_sources clk_src_epll = {
821 .sources = clk_src_epll_list,
822 .nr_sources = ARRAY_SIZE(clk_src_epll_list),
823};
824
825static struct clksrc_clk clk_mout_epll = {
826 .clk = {
827 .name = "mout_epll",
828 .id = -1,
829 },
830 .shift = S5PC1XX_CLKSRC0_EPLL_SHIFT,
831 .mask = S5PC1XX_CLKSRC0_EPLL_MASK,
832 .sources = &clk_src_epll,
833 .reg_source = S5PC1XX_CLK_SRC0,
834};
835
836static struct clk *clk_src_mpll_list[] = {
837 [0] = &clk_fin_mpll,
838 [1] = &clk_fout_mpll,
839};
840
841static struct clk_sources clk_src_mpll = {
842 .sources = clk_src_mpll_list,
843 .nr_sources = ARRAY_SIZE(clk_src_mpll_list),
844};
845
846static struct clksrc_clk clk_mout_mpll = {
847 .clk = {
848 .name = "mout_mpll",
849 .id = -1,
850 },
851 .shift = S5PC1XX_CLKSRC0_MPLL_SHIFT,
852 .mask = S5PC1XX_CLKSRC0_MPLL_MASK,
853 .sources = &clk_src_mpll,
854 .reg_source = S5PC1XX_CLK_SRC0,
855};
856
857static unsigned long s5pc1xx_clk_doutmpll_get_rate(struct clk *clk)
858{
859 unsigned long rate = clk_get_rate(clk->parent);
860 unsigned long clkdiv;
861
862 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
863
864 clkdiv = __raw_readl(S5PC1XX_CLK_DIV1) & S5PC100_CLKDIV1_MPLL_MASK;
865 rate /= (clkdiv >> S5PC100_CLKDIV1_MPLL_SHIFT) + 1;
866
867 return rate;
868}
869
870static struct clk clk_dout_mpll = {
871 .name = "dout_mpll",
872 .id = -1,
873 .parent = &clk_mout_mpll.clk,
874 .get_rate = s5pc1xx_clk_doutmpll_get_rate,
875};
876
877static unsigned long s5pc1xx_clk_doutmpll2_get_rate(struct clk *clk)
878{
879 unsigned long rate = clk_get_rate(clk->parent);
880 unsigned long clkdiv;
881
882 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate);
883
884 clkdiv = __raw_readl(S5PC1XX_CLK_DIV1) & S5PC100_CLKDIV1_MPLL2_MASK;
885 rate /= (clkdiv >> S5PC100_CLKDIV1_MPLL2_SHIFT) + 1;
886
887 return rate;
888}
889
890struct clk clk_dout_mpll2 = {
891 .name = "dout_mpll2",
892 .id = -1,
893 .parent = &clk_mout_mpll.clk,
894 .get_rate = s5pc1xx_clk_doutmpll2_get_rate,
895};
896
897static struct clk *clkset_uart_list[] = {
898 &clk_mout_epll.clk,
899 &clk_dout_mpll,
900 NULL,
901 NULL
902};
903
904static struct clk_sources clkset_uart = {
905 .sources = clkset_uart_list,
906 .nr_sources = ARRAY_SIZE(clkset_uart_list),
907};
908
909static inline struct clksrc_clk *to_clksrc(struct clk *clk)
910{
911 return container_of(clk, struct clksrc_clk, clk);
912}
913
914static unsigned long s5pc1xx_getrate_clksrc(struct clk *clk)
915{
916 struct clksrc_clk *sclk = to_clksrc(clk);
917 unsigned long rate = clk_get_rate(clk->parent);
918 u32 clkdiv = __raw_readl(sclk->reg_divider);
919
920 clkdiv >>= sclk->divider_shift;
921 clkdiv &= 0xf;
922 clkdiv++;
923
924 rate /= clkdiv;
925 return rate;
926}
927
928static int s5pc1xx_setrate_clksrc(struct clk *clk, unsigned long rate)
929{
930 struct clksrc_clk *sclk = to_clksrc(clk);
931 void __iomem *reg = sclk->reg_divider;
932 unsigned int div;
933 u32 val;
934
935 rate = clk_round_rate(clk, rate);
936 div = clk_get_rate(clk->parent) / rate;
937 if (div > 16)
938 return -EINVAL;
939
940 val = __raw_readl(reg);
941 val &= ~(0xf << sclk->shift);
942 val |= (div - 1) << sclk->shift;
943 __raw_writel(val, reg);
944
945 return 0;
946}
947
948static int s5pc1xx_setparent_clksrc(struct clk *clk, struct clk *parent)
949{
950 struct clksrc_clk *sclk = to_clksrc(clk);
951 struct clk_sources *srcs = sclk->sources;
952 u32 clksrc = __raw_readl(sclk->reg_source);
953 int src_nr = -1;
954 int ptr;
955
956 for (ptr = 0; ptr < srcs->nr_sources; ptr++)
957 if (srcs->sources[ptr] == parent) {
958 src_nr = ptr;
959 break;
960 }
961
962 if (src_nr >= 0) {
963 clksrc &= ~sclk->mask;
964 clksrc |= src_nr << sclk->shift;
965
966 __raw_writel(clksrc, sclk->reg_source);
967 return 0;
968 }
969
970 return -EINVAL;
971}
972
973static unsigned long s5pc1xx_roundrate_clksrc(struct clk *clk,
974 unsigned long rate)
975{
976 unsigned long parent_rate = clk_get_rate(clk->parent);
977 int div;
978
979 if (rate > parent_rate)
980 rate = parent_rate;
981 else {
982 div = rate / parent_rate;
983
984 if (div == 0)
985 div = 1;
986 if (div > 16)
987 div = 16;
988
989 rate = parent_rate / div;
990 }
991
992 return rate;
993}
994
995static struct clksrc_clk clk_uart_uclk1 = {
996 .clk = {
997 .name = "uclk1",
998 .id = -1,
999 .ctrlbit = S5PC100_CLKGATE_SCLK0_UART,
1000 .enable = s5pc1xx_sclk0_ctrl,
1001 .set_parent = s5pc1xx_setparent_clksrc,
1002 .get_rate = s5pc1xx_getrate_clksrc,
1003 .set_rate = s5pc1xx_setrate_clksrc,
1004 .round_rate = s5pc1xx_roundrate_clksrc,
1005 },
1006 .shift = S5PC100_CLKSRC1_UART_SHIFT,
1007 .mask = S5PC100_CLKSRC1_UART_MASK,
1008 .sources = &clkset_uart,
1009 .divider_shift = S5PC100_CLKDIV2_UART_SHIFT,
1010 .reg_divider = S5PC1XX_CLK_DIV2,
1011 .reg_source = S5PC1XX_CLK_SRC1,
1012};
1013
1014/* Clock initialisation code */
1015
1016static struct clksrc_clk *init_parents[] = {
1017 &clk_mout_apll,
1018 &clk_mout_epll,
1019 &clk_mout_mpll,
1020 &clk_uart_uclk1,
1021};
1022
1023static void __init_or_cpufreq s5pc1xx_set_clksrc(struct clksrc_clk *clk)
1024{
1025 struct clk_sources *srcs = clk->sources;
1026 u32 clksrc = __raw_readl(clk->reg_source);
1027
1028 clksrc &= clk->mask;
1029 clksrc >>= clk->shift;
1030
1031 if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
1032 printk(KERN_ERR "%s: bad source %d\n",
1033 clk->clk.name, clksrc);
1034 return;
1035 }
1036
1037 clk->clk.parent = srcs->sources[clksrc];
1038
1039 printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
1040 clk->clk.name, clk->clk.parent->name, clksrc,
1041 clk_get_rate(&clk->clk));
1042}
1043
1044#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1)
1045
1046void __init_or_cpufreq s5pc100_setup_clocks(void)
1047{
1048 struct clk *xtal_clk;
1049 unsigned long xtal;
1050 unsigned long armclk;
1051 unsigned long hclkd0;
1052 unsigned long hclk;
1053 unsigned long pclkd0;
1054 unsigned long pclk;
1055 unsigned long apll;
1056 unsigned long mpll;
1057 unsigned long hpll;
1058 unsigned long epll;
1059 unsigned int ptr;
1060 u32 clkdiv0, clkdiv1;
1061
1062 printk(KERN_DEBUG "%s: registering clocks\n", __func__);
1063
1064 clkdiv0 = __raw_readl(S5PC1XX_CLK_DIV0);
1065 clkdiv1 = __raw_readl(S5PC1XX_CLK_DIV1);
1066
1067 printk(KERN_DEBUG "%s: clkdiv0 = %08x, clkdiv1 = %08x\n",
1068 __func__, clkdiv0, clkdiv1);
1069
1070 xtal_clk = clk_get(NULL, "xtal");
1071 BUG_ON(IS_ERR(xtal_clk));
1072
1073 xtal = clk_get_rate(xtal_clk);
1074 clk_put(xtal_clk);
1075
1076 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
1077
1078 apll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_APLL_CON));
1079 mpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_MPLL_CON));
1080 epll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC1XX_EPLL_CON));
1081 hpll = s5pc1xx_get_pll(xtal, __raw_readl(S5PC100_HPLL_CON));
1082
1083 printk(KERN_INFO "S5PC100: PLL settings, A=%ld, M=%ld, E=%ld, H=%ld\n",
1084 apll, mpll, epll, hpll);
1085
1086 armclk = apll / GET_DIV(clkdiv0, S5PC1XX_CLKDIV0_APLL);
1087 armclk = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_ARM);
1088 hclkd0 = armclk / GET_DIV(clkdiv0, S5PC100_CLKDIV0_D0);
1089 pclkd0 = hclkd0 / GET_DIV(clkdiv0, S5PC100_CLKDIV0_PCLKD0);
1090 hclk = mpll / GET_DIV(clkdiv1, S5PC100_CLKDIV1_D1);
1091 pclk = hclk / GET_DIV(clkdiv1, S5PC100_CLKDIV1_PCLKD1);
1092
1093 printk(KERN_INFO "S5PC100: ARMCLK=%ld, HCLKD0=%ld, PCLKD0=%ld, HCLK=%ld, PCLK=%ld\n",
1094 armclk, hclkd0, pclkd0, hclk, pclk);
1095
1096 clk_fout_apll.rate = apll;
1097 clk_fout_mpll.rate = mpll;
1098 clk_fout_epll.rate = epll;
1099 clk_fout_apll.rate = apll;
1100
1101 clk_h.rate = hclk;
1102 clk_p.rate = pclk;
1103
1104 for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
1105 s5pc1xx_set_clksrc(init_parents[ptr]);
1106}
1107
1108static struct clk *clks[] __initdata = {
1109 &clk_ext_xtal_mux,
1110 &clk_mout_epll.clk,
1111 &clk_fout_epll,
1112 &clk_mout_mpll.clk,
1113 &clk_dout_mpll,
1114 &clk_uart_uclk1.clk,
1115 &clk_ext,
1116 &clk_epll,
1117 &clk_27m,
1118 &clk_48m,
1119 &clk_54m,
1120};
1121
1122void __init s5pc100_register_clocks(void)
1123{
1124 struct clk *clkp;
1125 int ret;
1126 int ptr;
1127
1128 for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
1129 clkp = clks[ptr];
1130 ret = s3c24xx_register_clock(clkp);
1131 if (ret < 0) {
1132 printk(KERN_ERR "Failed to register clock %s (%d)\n",
1133 clkp->name, ret);
1134 }
1135 }
1136
1137 clk_mpll.parent = &clk_mout_mpll.clk;
1138 clk_epll.parent = &clk_mout_epll.clk;
1139}