diff options
Diffstat (limited to 'arch/arm/mach-s3c2443')
-rw-r--r-- | arch/arm/mach-s3c2443/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-s3c2443/clock.c | 513 |
2 files changed, 127 insertions, 387 deletions
diff --git a/arch/arm/mach-s3c2443/Kconfig b/arch/arm/mach-s3c2443/Kconfig index 4314c4424909..698140af247c 100644 --- a/arch/arm/mach-s3c2443/Kconfig +++ b/arch/arm/mach-s3c2443/Kconfig | |||
@@ -7,6 +7,7 @@ config CPU_S3C2443 | |||
7 | depends on ARCH_S3C2410 | 7 | depends on ARCH_S3C2410 |
8 | select S3C2443_DMA if S3C2410_DMA | 8 | select S3C2443_DMA if S3C2410_DMA |
9 | select CPU_LLSERIAL_S3C2440 | 9 | select CPU_LLSERIAL_S3C2440 |
10 | select SAMSUNG_CLKSRC | ||
10 | help | 11 | help |
11 | Support for the S3C2443 SoC from the S3C24XX line | 12 | Support for the S3C2443 SoC from the S3C24XX line |
12 | 13 | ||
diff --git a/arch/arm/mach-s3c2443/clock.c b/arch/arm/mach-s3c2443/clock.c index 5d061ea0c513..f89e71f50345 100644 --- a/arch/arm/mach-s3c2443/clock.c +++ b/arch/arm/mach-s3c2443/clock.c | |||
@@ -1,6 +1,6 @@ | |||
1 | /* linux/arch/arm/mach-s3c2443/clock.c | 1 | /* linux/arch/arm/mach-s3c2443/clock.c |
2 | * | 2 | * |
3 | * Copyright (c) 2007 Simtec Electronics | 3 | * Copyright (c) 2007,2010 Simtec Electronics |
4 | * Ben Dooks <ben@simtec.co.uk> | 4 | * Ben Dooks <ben@simtec.co.uk> |
5 | * | 5 | * |
6 | * S3C2443 Clock control support | 6 | * S3C2443 Clock control support |
@@ -42,6 +42,7 @@ | |||
42 | 42 | ||
43 | #include <plat/s3c2443.h> | 43 | #include <plat/s3c2443.h> |
44 | #include <plat/clock.h> | 44 | #include <plat/clock.h> |
45 | #include <plat/clock-clksrc.h> | ||
45 | #include <plat/cpu.h> | 46 | #include <plat/cpu.h> |
46 | 47 | ||
47 | /* We currently have to assume that the system is running | 48 | /* We currently have to assume that the system is running |
@@ -82,45 +83,7 @@ static int s3c2443_clkcon_enable_s(struct clk *clk, int enable) | |||
82 | return s3c2443_gate(S3C2443_SCLKCON, clk, enable); | 83 | return s3c2443_gate(S3C2443_SCLKCON, clk, enable); |
83 | } | 84 | } |
84 | 85 | ||
85 | static unsigned long s3c2443_roundrate_clksrc(struct clk *clk, | 86 | /* s3c2443_roundate_clksrc is close enough to s3c_roundate_clksrc */ |
86 | unsigned long rate, | ||
87 | unsigned int max) | ||
88 | { | ||
89 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
90 | int div; | ||
91 | |||
92 | if (rate > parent_rate) | ||
93 | return parent_rate; | ||
94 | |||
95 | /* note, we remove the +/- 1 calculations as they cancel out */ | ||
96 | |||
97 | div = (rate / parent_rate); | ||
98 | |||
99 | if (div < 1) | ||
100 | div = 1; | ||
101 | else if (div > max) | ||
102 | div = max; | ||
103 | |||
104 | return parent_rate / div; | ||
105 | } | ||
106 | |||
107 | static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk, | ||
108 | unsigned long rate) | ||
109 | { | ||
110 | return s3c2443_roundrate_clksrc(clk, rate, 4); | ||
111 | } | ||
112 | |||
113 | static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk, | ||
114 | unsigned long rate) | ||
115 | { | ||
116 | return s3c2443_roundrate_clksrc(clk, rate, 16); | ||
117 | } | ||
118 | |||
119 | static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk, | ||
120 | unsigned long rate) | ||
121 | { | ||
122 | return s3c2443_roundrate_clksrc(clk, rate, 256); | ||
123 | } | ||
124 | 87 | ||
125 | /* clock selections */ | 88 | /* clock selections */ |
126 | 89 | ||
@@ -143,31 +106,23 @@ static struct clk clk_i2s_ext = { | |||
143 | .id = -1, | 106 | .id = -1, |
144 | }; | 107 | }; |
145 | 108 | ||
146 | static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent) | 109 | static struct clk *clk_epllref_sources[] = { |
147 | { | 110 | [0] = &clk_mpllref, |
148 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 111 | [1] = &clk_mpllref, |
149 | 112 | [2] = &clk_xtal, | |
150 | clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK; | 113 | [3] = &clk_ext, |
151 | 114 | }; | |
152 | if (parent == &clk_xtal) | ||
153 | clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL; | ||
154 | else if (parent == &clk_ext) | ||
155 | clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK; | ||
156 | else if (parent != &clk_mpllref) | ||
157 | return -EINVAL; | ||
158 | |||
159 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
160 | clk->parent = parent; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | 115 | ||
165 | static struct clk clk_epllref = { | 116 | static struct clksrc_clk clk_epllref = { |
166 | .name = "epllref", | 117 | .clk = { |
167 | .id = -1, | 118 | .name = "epllref", |
168 | .ops = &(struct clk_ops) { | 119 | .id = -1, |
169 | .set_parent = s3c2443_setparent_epllref, | 120 | }, |
121 | .sources = &(struct clksrc_sources) { | ||
122 | .sources = clk_epllref_sources, | ||
123 | .nr_sources = ARRAY_SIZE(clk_epllref_sources), | ||
170 | }, | 124 | }, |
125 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 7 }, | ||
171 | }; | 126 | }; |
172 | 127 | ||
173 | static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) | 128 | static unsigned long s3c2443_getrate_mdivclk(struct clk *clk) |
@@ -273,7 +228,7 @@ static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent) | |||
273 | 228 | ||
274 | if (parent == &clk_epll) | 229 | if (parent == &clk_epll) |
275 | clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; | 230 | clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL; |
276 | else if (parent == &clk_epllref) | 231 | else if (parent == &clk_epllref.clk) |
277 | clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; | 232 | clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL; |
278 | else | 233 | else |
279 | return -EINVAL; | 234 | return -EINVAL; |
@@ -298,87 +253,30 @@ static struct clk clk_esysclk = { | |||
298 | * UART baud-rate clock sourced from esysclk via a divisor | 253 | * UART baud-rate clock sourced from esysclk via a divisor |
299 | */ | 254 | */ |
300 | 255 | ||
301 | static unsigned long s3c2443_getrate_uart(struct clk *clk) | 256 | static struct clksrc_clk clk_uart = { |
302 | { | 257 | .clk = { |
303 | unsigned long parent_rate = clk_get_rate(clk->parent); | 258 | .name = "uartclk", |
304 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 259 | .id = -1, |
305 | 260 | .parent = &clk_esysclk, | |
306 | div &= S3C2443_CLKDIV1_UARTDIV_MASK; | ||
307 | div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
308 | |||
309 | return parent_rate / (div + 1); | ||
310 | } | ||
311 | |||
312 | |||
313 | static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate) | ||
314 | { | ||
315 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
316 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
317 | |||
318 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
319 | rate = parent_rate / rate; | ||
320 | |||
321 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | ||
322 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
323 | |||
324 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static struct clk clk_uart = { | ||
329 | .name = "uartclk", | ||
330 | .id = -1, | ||
331 | .parent = &clk_esysclk, | ||
332 | .ops = &(struct clk_ops) { | ||
333 | .get_rate = s3c2443_getrate_uart, | ||
334 | .set_rate = s3c2443_setrate_uart, | ||
335 | .round_rate = s3c2443_roundrate_clksrc16, | ||
336 | }, | 261 | }, |
262 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 8 }, | ||
337 | }; | 263 | }; |
338 | 264 | ||
265 | |||
339 | /* hsspi | 266 | /* hsspi |
340 | * | 267 | * |
341 | * high-speed spi clock, sourced from esysclk | 268 | * high-speed spi clock, sourced from esysclk |
342 | */ | 269 | */ |
343 | 270 | ||
344 | static unsigned long s3c2443_getrate_hsspi(struct clk *clk) | 271 | static struct clksrc_clk clk_hsspi = { |
345 | { | 272 | .clk = { |
346 | unsigned long parent_rate = clk_get_rate(clk->parent); | 273 | .name = "hsspi", |
347 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 274 | .id = -1, |
348 | 275 | .parent = &clk_esysclk, | |
349 | div &= S3C2443_CLKDIV1_HSSPIDIV_MASK; | 276 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, |
350 | div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | 277 | .enable = s3c2443_clkcon_enable_s, |
351 | |||
352 | return parent_rate / (div + 1); | ||
353 | } | ||
354 | |||
355 | |||
356 | static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate) | ||
357 | { | ||
358 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
359 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
360 | |||
361 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
362 | rate = parent_rate / rate; | ||
363 | |||
364 | clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK; | ||
365 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT; | ||
366 | |||
367 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
368 | return 0; | ||
369 | } | ||
370 | |||
371 | static struct clk clk_hsspi = { | ||
372 | .name = "hsspi", | ||
373 | .id = -1, | ||
374 | .parent = &clk_esysclk, | ||
375 | .ctrlbit = S3C2443_SCLKCON_HSSPICLK, | ||
376 | .enable = s3c2443_clkcon_enable_s, | ||
377 | .ops = &(struct clk_ops) { | ||
378 | .get_rate = s3c2443_getrate_hsspi, | ||
379 | .set_rate = s3c2443_setrate_hsspi, | ||
380 | .round_rate = s3c2443_roundrate_clksrc4, | ||
381 | }, | 278 | }, |
279 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, | ||
382 | }; | 280 | }; |
383 | 281 | ||
384 | /* usbhost | 282 | /* usbhost |
@@ -386,43 +284,15 @@ static struct clk clk_hsspi = { | |||
386 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing | 284 | * usb host bus-clock, usually 48MHz to provide USB bus clock timing |
387 | */ | 285 | */ |
388 | 286 | ||
389 | static unsigned long s3c2443_getrate_usbhost(struct clk *clk) | 287 | static struct clksrc_clk clk_usb_bus_host = { |
390 | { | 288 | .clk = { |
391 | unsigned long parent_rate = clk_get_rate(clk->parent); | 289 | .name = "usb-bus-host-parent", |
392 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 290 | .id = -1, |
393 | 291 | .parent = &clk_esysclk, | |
394 | div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK; | 292 | .ctrlbit = S3C2443_SCLKCON_USBHOST, |
395 | div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | 293 | .enable = s3c2443_clkcon_enable_s, |
396 | |||
397 | return parent_rate / (div + 1); | ||
398 | } | ||
399 | |||
400 | static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate) | ||
401 | { | ||
402 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
403 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
404 | |||
405 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
406 | rate = parent_rate / rate; | ||
407 | |||
408 | clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK; | ||
409 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT; | ||
410 | |||
411 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static struct clk clk_usb_bus_host = { | ||
416 | .name = "usb-bus-host-parent", | ||
417 | .id = -1, | ||
418 | .parent = &clk_esysclk, | ||
419 | .ctrlbit = S3C2443_SCLKCON_USBHOST, | ||
420 | .enable = s3c2443_clkcon_enable_s, | ||
421 | .ops = &(struct clk_ops) { | ||
422 | .get_rate = s3c2443_getrate_usbhost, | ||
423 | .set_rate = s3c2443_setrate_usbhost, | ||
424 | .round_rate = s3c2443_roundrate_clksrc4, | ||
425 | }, | 294 | }, |
295 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 4 }, | ||
426 | }; | 296 | }; |
427 | 297 | ||
428 | /* clk_hsmcc_div | 298 | /* clk_hsmcc_div |
@@ -432,41 +302,13 @@ static struct clk clk_usb_bus_host = { | |||
432 | * be fed to the hsmmc block | 302 | * be fed to the hsmmc block |
433 | */ | 303 | */ |
434 | 304 | ||
435 | static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk) | 305 | static struct clksrc_clk clk_hsmmc_div = { |
436 | { | 306 | .clk = { |
437 | unsigned long parent_rate = clk_get_rate(clk->parent); | 307 | .name = "hsmmc-div", |
438 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 308 | .id = -1, |
439 | 309 | .parent = &clk_esysclk, | |
440 | div &= S3C2443_CLKDIV1_HSMMCDIV_MASK; | ||
441 | div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | ||
442 | |||
443 | return parent_rate / (div + 1); | ||
444 | } | ||
445 | |||
446 | static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate) | ||
447 | { | ||
448 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
449 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
450 | |||
451 | rate = s3c2443_roundrate_clksrc4(clk, rate); | ||
452 | rate = parent_rate / rate; | ||
453 | |||
454 | clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK; | ||
455 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT; | ||
456 | |||
457 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static struct clk clk_hsmmc_div = { | ||
462 | .name = "hsmmc-div", | ||
463 | .id = -1, | ||
464 | .parent = &clk_esysclk, | ||
465 | .ops = &(struct clk_ops) { | ||
466 | .get_rate = s3c2443_getrate_hsmmc_div, | ||
467 | .set_rate = s3c2443_setrate_hsmmc_div, | ||
468 | .round_rate = s3c2443_roundrate_clksrc4, | ||
469 | }, | 310 | }, |
311 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 2, .shift = 6 }, | ||
470 | }; | 312 | }; |
471 | 313 | ||
472 | static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) | 314 | static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent) |
@@ -499,7 +341,7 @@ static int s3c2443_enable_hsmmc(struct clk *clk, int enable) | |||
499 | static struct clk clk_hsmmc = { | 341 | static struct clk clk_hsmmc = { |
500 | .name = "hsmmc-if", | 342 | .name = "hsmmc-if", |
501 | .id = -1, | 343 | .id = -1, |
502 | .parent = &clk_hsmmc_div, | 344 | .parent = &clk_hsmmc_div.clk, |
503 | .enable = s3c2443_enable_hsmmc, | 345 | .enable = s3c2443_enable_hsmmc, |
504 | .ops = &(struct clk_ops) { | 346 | .ops = &(struct clk_ops) { |
505 | .set_parent = s3c2443_setparent_hsmmc, | 347 | .set_parent = s3c2443_setparent_hsmmc, |
@@ -508,79 +350,46 @@ static struct clk clk_hsmmc = { | |||
508 | 350 | ||
509 | /* i2s_eplldiv | 351 | /* i2s_eplldiv |
510 | * | 352 | * |
511 | * this clock is the output from the i2s divisor of esysclk | 353 | * This clock is the output from the I2S divisor of ESYSCLK, and is seperate |
354 | * from the mux that comes after it (cannot merge into one single clock) | ||
512 | */ | 355 | */ |
513 | 356 | ||
514 | static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk) | 357 | static struct clksrc_clk clk_i2s_eplldiv = { |
515 | { | 358 | .clk = { |
516 | unsigned long parent_rate = clk_get_rate(clk->parent); | 359 | .name = "i2s-eplldiv", |
517 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 360 | .id = -1, |
518 | 361 | .parent = &clk_esysclk, | |
519 | div &= S3C2443_CLKDIV1_I2SDIV_MASK; | ||
520 | div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT; | ||
521 | |||
522 | return parent_rate / (div + 1); | ||
523 | } | ||
524 | |||
525 | static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate) | ||
526 | { | ||
527 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
528 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
529 | |||
530 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
531 | rate = parent_rate / rate; | ||
532 | |||
533 | clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK; | ||
534 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT; | ||
535 | |||
536 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static struct clk clk_i2s_eplldiv = { | ||
541 | .name = "i2s-eplldiv", | ||
542 | .id = -1, | ||
543 | .parent = &clk_esysclk, | ||
544 | .ops = &(struct clk_ops) { | ||
545 | .get_rate = s3c2443_getrate_i2s_eplldiv, | ||
546 | .set_rate = s3c2443_setrate_i2s_eplldiv, | ||
547 | .round_rate = s3c2443_roundrate_clksrc16, | ||
548 | }, | 362 | }, |
363 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 12, }, | ||
549 | }; | 364 | }; |
550 | 365 | ||
551 | /* i2s-ref | 366 | /* i2s-ref |
552 | * | 367 | * |
553 | * i2s bus reference clock, selectable from external, esysclk or epllref | 368 | * i2s bus reference clock, selectable from external, esysclk or epllref |
369 | * | ||
370 | * Note, this used to be two clocks, but was compressed into one. | ||
554 | */ | 371 | */ |
555 | 372 | ||
556 | static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent) | 373 | struct clk *clk_i2s_srclist[] = { |
557 | { | 374 | [0] = &clk_i2s_eplldiv.clk, |
558 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 375 | [1] = &clk_i2s_ext, |
559 | 376 | [2] = &clk_epllref.clk, | |
560 | clksrc &= ~S3C2443_CLKSRC_I2S_MASK; | 377 | [3] = &clk_epllref.clk, |
561 | 378 | }; | |
562 | if (parent == &clk_epllref) | ||
563 | clksrc |= S3C2443_CLKSRC_I2S_EPLLREF; | ||
564 | else if (parent == &clk_i2s_ext) | ||
565 | clksrc |= S3C2443_CLKSRC_I2S_EXT; | ||
566 | else if (parent != &clk_i2s_eplldiv) | ||
567 | return -EINVAL; | ||
568 | |||
569 | clk->parent = parent; | ||
570 | __raw_writel(clksrc, S3C2443_CLKSRC); | ||
571 | 379 | ||
572 | return 0; | 380 | static struct clksrc_clk clk_i2s = { |
573 | } | 381 | .clk = { |
382 | .name = "i2s-if", | ||
383 | .id = -1, | ||
384 | .ctrlbit = S3C2443_SCLKCON_I2SCLK, | ||
385 | .enable = s3c2443_clkcon_enable_s, | ||
574 | 386 | ||
575 | static struct clk clk_i2s = { | ||
576 | .name = "i2s-if", | ||
577 | .id = -1, | ||
578 | .parent = &clk_i2s_eplldiv, | ||
579 | .ctrlbit = S3C2443_SCLKCON_I2SCLK, | ||
580 | .enable = s3c2443_clkcon_enable_s, | ||
581 | .ops = &(struct clk_ops) { | ||
582 | .set_parent = s3c2443_setparent_i2s, | ||
583 | }, | 387 | }, |
388 | .sources = &(struct clksrc_sources) { | ||
389 | .sources = clk_i2s_srclist, | ||
390 | .nr_sources = ARRAY_SIZE(clk_i2s_srclist), | ||
391 | }, | ||
392 | .reg_src = { .reg = S3C2443_CLKSRC, .size = 2, .shift = 14 }, | ||
584 | }; | 393 | }; |
585 | 394 | ||
586 | /* cam-if | 395 | /* cam-if |
@@ -588,43 +397,15 @@ static struct clk clk_i2s = { | |||
588 | * camera interface bus-clock, divided down from esysclk | 397 | * camera interface bus-clock, divided down from esysclk |
589 | */ | 398 | */ |
590 | 399 | ||
591 | static unsigned long s3c2443_getrate_cam(struct clk *clk) | 400 | static struct clksrc_clk clk_cam = { |
592 | { | 401 | .clk = { |
593 | unsigned long parent_rate = clk_get_rate(clk->parent); | 402 | .name = "camif-upll", /* same as 2440 name */ |
594 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 403 | .id = -1, |
595 | 404 | .parent = &clk_esysclk, | |
596 | div &= S3C2443_CLKDIV1_CAMDIV_MASK; | 405 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, |
597 | div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT; | 406 | .enable = s3c2443_clkcon_enable_s, |
598 | |||
599 | return parent_rate / (div + 1); | ||
600 | } | ||
601 | |||
602 | static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate) | ||
603 | { | ||
604 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
605 | unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1); | ||
606 | |||
607 | rate = s3c2443_roundrate_clksrc16(clk, rate); | ||
608 | rate = parent_rate / rate; | ||
609 | |||
610 | clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK; | ||
611 | clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT; | ||
612 | |||
613 | __raw_writel(clkdiv1, S3C2443_CLKDIV1); | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static struct clk clk_cam = { | ||
618 | .name = "camif-upll", /* same as 2440 name */ | ||
619 | .id = -1, | ||
620 | .parent = &clk_esysclk, | ||
621 | .ctrlbit = S3C2443_SCLKCON_CAMCLK, | ||
622 | .enable = s3c2443_clkcon_enable_s, | ||
623 | .ops = &(struct clk_ops) { | ||
624 | .get_rate = s3c2443_getrate_cam, | ||
625 | .set_rate = s3c2443_setrate_cam, | ||
626 | .round_rate = s3c2443_roundrate_clksrc16, | ||
627 | }, | 407 | }, |
408 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 4, .shift = 26 }, | ||
628 | }; | 409 | }; |
629 | 410 | ||
630 | /* display-if | 411 | /* display-if |
@@ -632,43 +413,15 @@ static struct clk clk_cam = { | |||
632 | * display interface clock, divided from esysclk | 413 | * display interface clock, divided from esysclk |
633 | */ | 414 | */ |
634 | 415 | ||
635 | static unsigned long s3c2443_getrate_display(struct clk *clk) | 416 | static struct clksrc_clk clk_display = { |
636 | { | 417 | .clk = { |
637 | unsigned long parent_rate = clk_get_rate(clk->parent); | 418 | .name = "display-if", |
638 | unsigned long div = __raw_readl(S3C2443_CLKDIV1); | 419 | .id = -1, |
639 | 420 | .parent = &clk_esysclk, | |
640 | div &= S3C2443_CLKDIV1_DISPDIV_MASK; | 421 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, |
641 | div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT; | 422 | .enable = s3c2443_clkcon_enable_s, |
642 | |||
643 | return parent_rate / (div + 1); | ||
644 | } | ||
645 | |||
646 | static int s3c2443_setrate_display(struct clk *clk, unsigned long rate) | ||
647 | { | ||
648 | unsigned long parent_rate = clk_get_rate(clk->parent); | ||
649 | unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1); | ||
650 | |||
651 | rate = s3c2443_roundrate_clksrc256(clk, rate); | ||
652 | rate = parent_rate / rate; | ||
653 | |||
654 | clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK; | ||
655 | clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT; | ||
656 | |||
657 | __raw_writel(clkdivn, S3C2443_CLKDIV1); | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static struct clk clk_display = { | ||
662 | .name = "display-if", | ||
663 | .id = -1, | ||
664 | .parent = &clk_esysclk, | ||
665 | .ctrlbit = S3C2443_SCLKCON_DISPCLK, | ||
666 | .enable = s3c2443_clkcon_enable_s, | ||
667 | .ops = &(struct clk_ops) { | ||
668 | .get_rate = s3c2443_getrate_display, | ||
669 | .set_rate = s3c2443_setrate_display, | ||
670 | .round_rate = s3c2443_roundrate_clksrc256, | ||
671 | }, | 423 | }, |
424 | .reg_div = { .reg = S3C2443_CLKDIV1, .size = 8, .shift = 16 }, | ||
672 | }; | 425 | }; |
673 | 426 | ||
674 | /* prediv | 427 | /* prediv |
@@ -865,7 +618,7 @@ static struct clk init_clocks[] = { | |||
865 | }, { | 618 | }, { |
866 | .name = "usb-bus-host", | 619 | .name = "usb-bus-host", |
867 | .id = -1, | 620 | .id = -1, |
868 | .parent = &clk_usb_bus_host, | 621 | .parent = &clk_usb_bus_host.clk, |
869 | }, { | 622 | }, { |
870 | .name = "ac97", | 623 | .name = "ac97", |
871 | .id = -1, | 624 | .id = -1, |
@@ -887,50 +640,27 @@ static int __init clk_init_set_parent(struct clk *clk, struct clk *parent) | |||
887 | return clk_set_parent(clk, parent); | 640 | return clk_set_parent(clk, parent); |
888 | } | 641 | } |
889 | 642 | ||
643 | static struct clksrc_clk __initdata *init_list[] = { | ||
644 | &clk_epllref, /* should be first */ | ||
645 | &clk_i2s_eplldiv, | ||
646 | &clk_i2s, | ||
647 | &clk_cam, | ||
648 | &clk_uart, | ||
649 | &clk_display, | ||
650 | &clk_hsmmc_div, | ||
651 | &clk_usb_bus_host, | ||
652 | }; | ||
653 | |||
890 | static void __init s3c2443_clk_initparents(void) | 654 | static void __init s3c2443_clk_initparents(void) |
891 | { | 655 | { |
892 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); | 656 | unsigned long clksrc = __raw_readl(S3C2443_CLKSRC); |
893 | struct clk *parent; | 657 | struct clk *parent; |
894 | 658 | int ptr; | |
895 | switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) { | ||
896 | case S3C2443_CLKSRC_EPLLREF_EXTCLK: | ||
897 | parent = &clk_ext; | ||
898 | break; | ||
899 | |||
900 | case S3C2443_CLKSRC_EPLLREF_XTAL: | ||
901 | default: | ||
902 | parent = &clk_xtal; | ||
903 | break; | ||
904 | |||
905 | case S3C2443_CLKSRC_EPLLREF_MPLLREF: | ||
906 | case S3C2443_CLKSRC_EPLLREF_MPLLREF2: | ||
907 | parent = &clk_mpllref; | ||
908 | break; | ||
909 | } | ||
910 | |||
911 | clk_init_set_parent(&clk_epllref, parent); | ||
912 | |||
913 | switch (clksrc & S3C2443_CLKSRC_I2S_MASK) { | ||
914 | case S3C2443_CLKSRC_I2S_EXT: | ||
915 | parent = &clk_i2s_ext; | ||
916 | break; | ||
917 | |||
918 | case S3C2443_CLKSRC_I2S_EPLLDIV: | ||
919 | default: | ||
920 | parent = &clk_i2s_eplldiv; | ||
921 | break; | ||
922 | |||
923 | case S3C2443_CLKSRC_I2S_EPLLREF: | ||
924 | case S3C2443_CLKSRC_I2S_EPLLREF3: | ||
925 | parent = &clk_epllref; | ||
926 | } | ||
927 | |||
928 | clk_init_set_parent(&clk_i2s, &clk_epllref); | ||
929 | 659 | ||
930 | /* esysclk source */ | 660 | /* esysclk source */ |
931 | 661 | ||
932 | parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ? | 662 | parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ? |
933 | &clk_epll : &clk_epllref; | 663 | &clk_epll : &clk_epllref.clk; |
934 | 664 | ||
935 | clk_init_set_parent(&clk_esysclk, parent); | 665 | clk_init_set_parent(&clk_esysclk, parent); |
936 | 666 | ||
@@ -953,6 +683,9 @@ static void __init s3c2443_clk_initparents(void) | |||
953 | parent = &clk_armdiv; | 683 | parent = &clk_armdiv; |
954 | 684 | ||
955 | clk_init_set_parent(&clk_arm, parent); | 685 | clk_init_set_parent(&clk_arm, parent); |
686 | |||
687 | for (ptr = 0; ptr < ARRAY_SIZE(init_list); ptr++) | ||
688 | s3c_set_clksrc(init_list[ptr], false); | ||
956 | } | 689 | } |
957 | 690 | ||
958 | /* armdiv divisor table */ | 691 | /* armdiv divisor table */ |
@@ -984,15 +717,9 @@ static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0) | |||
984 | 717 | ||
985 | /* clocks to add straight away */ | 718 | /* clocks to add straight away */ |
986 | 719 | ||
987 | static struct clk *clks[] __initdata = { | 720 | static struct clksrc_clk *clksrcs[] __initdata = { |
988 | &clk_ext, | ||
989 | &clk_epll, | ||
990 | &clk_usb_bus_host, | 721 | &clk_usb_bus_host, |
991 | &clk_usb_bus, | ||
992 | &clk_esysclk, | ||
993 | &clk_epllref, | 722 | &clk_epllref, |
994 | &clk_mpllref, | ||
995 | &clk_msysclk, | ||
996 | &clk_uart, | 723 | &clk_uart, |
997 | &clk_display, | 724 | &clk_display, |
998 | &clk_cam, | 725 | &clk_cam, |
@@ -1000,6 +727,15 @@ static struct clk *clks[] __initdata = { | |||
1000 | &clk_i2s, | 727 | &clk_i2s, |
1001 | &clk_hsspi, | 728 | &clk_hsspi, |
1002 | &clk_hsmmc_div, | 729 | &clk_hsmmc_div, |
730 | }; | ||
731 | |||
732 | static struct clk *clks[] __initdata = { | ||
733 | &clk_ext, | ||
734 | &clk_epll, | ||
735 | &clk_usb_bus, | ||
736 | &clk_esysclk, | ||
737 | &clk_mpllref, | ||
738 | &clk_msysclk, | ||
1003 | &clk_hsmmc, | 739 | &clk_hsmmc, |
1004 | &clk_armdiv, | 740 | &clk_armdiv, |
1005 | &clk_arm, | 741 | &clk_arm, |
@@ -1064,15 +800,18 @@ void __init s3c2443_init_clocks(int xtal) | |||
1064 | } | 800 | } |
1065 | } | 801 | } |
1066 | 802 | ||
803 | for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) | ||
804 | s3c_register_clksrc(clksrcs[ptr], 1); | ||
805 | |||
1067 | clk_epll.rate = s3c2443_get_epll(epllcon, xtal); | 806 | clk_epll.rate = s3c2443_get_epll(epllcon, xtal); |
1068 | clk_epll.parent = &clk_epllref; | 807 | clk_epll.parent = &clk_epllref.clk; |
1069 | clk_usb_bus.parent = &clk_usb_bus_host; | 808 | clk_usb_bus.parent = &clk_usb_bus_host.clk; |
1070 | 809 | ||
1071 | /* ensure usb bus clock is within correct rate of 48MHz */ | 810 | /* ensure usb bus clock is within correct rate of 48MHz */ |
1072 | 811 | ||
1073 | if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) { | 812 | if (clk_get_rate(&clk_usb_bus_host.clk) != (48 * 1000 * 1000)) { |
1074 | printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); | 813 | printk(KERN_INFO "Warning: USB host bus not at 48MHz\n"); |
1075 | clk_set_rate(&clk_usb_bus_host, 48*1000*1000); | 814 | clk_set_rate(&clk_usb_bus_host.clk, 48*1000*1000); |
1076 | } | 815 | } |
1077 | 816 | ||
1078 | printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", | 817 | printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n", |