1/* linux/arch/arm/plat-s3c64xx/clock.c 2 * 3 * Copyright 2008 Openmoko, Inc. 4 * Copyright 2008 Simtec Electronics 5 * Ben Dooks <ben@simtec.co.uk> 6 * http://armlinux.simtec.co.uk/ 7 * 8 * S3C64XX Base clock support 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/interrupt.h> 18#include <linux/ioport.h> 19#include <linux/clk.h> 20#include <linux/err.h> 21#include <linux/io.h> 22 23#include <mach/hardware.h> 24#include <mach/map.h> 25 26#include <mach/regs-sys.h> 27#include <mach/regs-clock.h> 28#include <mach/pll.h> 29 30#include <plat/cpu.h> 31#include <plat/devs.h> 32#include <plat/cpu-freq.h> 33#include <plat/clock.h> 34#include <plat/clock-clksrc.h> 35 36/* fin_apll, fin_mpll and fin_epll are all the same clock, which we call 37 * ext_xtal_mux for want of an actual name from the manual. 38*/ 39 40static struct clk clk_ext_xtal_mux = { 41 .name = "ext_xtal", 42 .id = -1, 43}; 44 45#define clk_fin_apll clk_ext_xtal_mux 46#define clk_fin_mpll clk_ext_xtal_mux 47#define clk_fin_epll clk_ext_xtal_mux 48 49#define clk_fout_mpll clk_mpll 50#define clk_fout_epll clk_epll 51 52struct clk clk_h2 = { 53 .name = "hclk2", 54 .id = -1, 55 .rate = 0, 56}; 57 58struct clk clk_27m = { 59 .name = "clk_27m", 60 .id = -1, 61 .rate = 27000000, 62}; 63 64static int clk_48m_ctrl(struct clk *clk, int enable) 65{ 66 unsigned long flags; 67 u32 val; 68 69 /* can't rely on clock lock, this register has other usages */ 70 local_irq_save(flags); 71 72 val = __raw_readl(S3C64XX_OTHERS); 73 if (enable) 74 val |= S3C64XX_OTHERS_USBMASK; 75 else 76 val &= ~S3C64XX_OTHERS_USBMASK; 77 78 __raw_writel(val, S3C64XX_OTHERS); 79 local_irq_restore(flags); 80 81 return 0; 82} 83 84struct clk clk_48m = { 85 .name = "clk_48m", 86 .id = -1, 87 .rate = 48000000, 88 .enable = clk_48m_ctrl, 89}; 90 91struct clk clk_xusbxti = { 92 .name = "xusbxti", 93 .id = -1, 94 .rate = 48000000, 95}; 96 97static int inline s3c64xx_gate(void __iomem *reg, 98 struct clk *clk, 99 int enable) 100{ 101 unsigned int ctrlbit = clk->ctrlbit; 102 u32 con; 103 104 con = __raw_readl(reg); 105 106 if (enable) 107 con |= ctrlbit; 108 else 109 con &= ~ctrlbit; 110 111 __raw_writel(con, reg); 112 return 0; 113} 114 115static int s3c64xx_pclk_ctrl(struct clk *clk, int enable) 116{ 117 return s3c64xx_gate(S3C_PCLK_GATE, clk, enable); 118} 119 120static int s3c64xx_hclk_ctrl(struct clk *clk, int enable) 121{ 122 return s3c64xx_gate(S3C_HCLK_GATE, clk, enable); 123} 124 125int s3c64xx_sclk_ctrl(struct clk *clk, int enable) 126{ 127 return s3c64xx_gate(S3C_SCLK_GATE, clk, enable); 128} 129 130static struct clk init_clocks_disable[] = { 131 { 132 .name = "nand", 133 .id = -1, 134 .parent = &clk_h, 135 }, { 136 .name = "rtc", 137 .id = -1, 138 .parent = &clk_p, 139 .enable = s3c64xx_pclk_ctrl, 140 .ctrlbit = S3C_CLKCON_PCLK_RTC, 141 }, { 142 .name = "adc", 143 .id = -1, 144 .parent = &clk_p, 145 .enable = s3c64xx_pclk_ctrl, 146 .ctrlbit = S3C_CLKCON_PCLK_TSADC, 147 }, { 148 .name = "i2c", 149 .id = -1, 150 .parent = &clk_p, 151 .enable = s3c64xx_pclk_ctrl, 152 .ctrlbit = S3C_CLKCON_PCLK_IIC, 153 }, { 154 .name = "iis", 155 .id = 0, 156 .parent = &clk_p, 157 .enable = s3c64xx_pclk_ctrl, 158 .ctrlbit = S3C_CLKCON_PCLK_IIS0, 159 }, { 160 .name = "iis", 161 .id = 1, 162 .parent = &clk_p, 163 .enable = s3c64xx_pclk_ctrl, 164 .ctrlbit = S3C_CLKCON_PCLK_IIS1, 165 }, { 166#ifdef CONFIG_CPU_S3C6410 167 .name = "iis", 168 .id = -1, /* There's only one IISv4 port */ 169 .parent = &clk_p, 170 .enable = s3c64xx_pclk_ctrl, 171 .ctrlbit = S3C6410_CLKCON_PCLK_IIS2, 172 }, { 173#endif 174 .name = "keypad", 175 .id = -1, 176 .parent = &clk_p, 177 .enable = s3c64xx_pclk_ctrl, 178 .ctrlbit = S3C_CLKCON_PCLK_KEYPAD, 179 }, { 180 .name = "spi", 181 .id = 0, 182 .parent = &clk_p, 183 .enable = s3c64xx_pclk_ctrl, 184 .ctrlbit = S3C_CLKCON_PCLK_SPI0, 185 }, { 186 .name = "spi", 187 .id = 1, 188 .parent = &clk_p, 189 .enable = s3c64xx_pclk_ctrl, 190 .ctrlbit = S3C_CLKCON_PCLK_SPI1, 191 }, { 192 .name = "spi_48m", 193 .id = 0, 194 .parent = &clk_48m, 195 .enable = s3c64xx_sclk_ctrl, 196 .ctrlbit = S3C_CLKCON_SCLK_SPI0_48, 197 }, { 198 .name = "spi_48m", 199 .id = 1, 200 .parent = &clk_48m, 201 .enable = s3c64xx_sclk_ctrl, 202 .ctrlbit = S3C_CLKCON_SCLK_SPI1_48, 203 }, { 204 .name = "48m", 205 .id = 0, 206 .parent = &clk_48m, 207 .enable = s3c64xx_sclk_ctrl, 208 .ctrlbit = S3C_CLKCON_SCLK_MMC0_48, 209 }, { 210 .name = "48m", 211 .id = 1, 212 .parent = &clk_48m, 213 .enable = s3c64xx_sclk_ctrl, 214 .ctrlbit = S3C_CLKCON_SCLK_MMC1_48, 215 }, { 216 .name = "48m", 217 .id = 2, 218 .parent = &clk_48m, 219 .enable = s3c64xx_sclk_ctrl, 220 .ctrlbit = S3C_CLKCON_SCLK_MMC2_48, 221 }, { 222 .name = "dma0", 223 .id = -1, 224 .parent = &clk_h, 225 .enable = s3c64xx_hclk_ctrl, 226 .ctrlbit = S3C_CLKCON_HCLK_DMA0, 227 }, { 228 .name = "dma1", 229 .id = -1, 230 .parent = &clk_h, 231 .enable = s3c64xx_hclk_ctrl, 232 .ctrlbit = S3C_CLKCON_HCLK_DMA1, 233 }, 234}; 235 236static struct clk init_clocks[] = { 237 { 238 .name = "lcd", 239 .id = -1, 240 .parent = &clk_h, 241 .enable = s3c64xx_hclk_ctrl, 242 .ctrlbit = S3C_CLKCON_HCLK_LCD, 243 }, { 244 .name = "gpio", 245 .id = -1, 246 .parent = &clk_p, 247 .enable = s3c64xx_pclk_ctrl, 248 .ctrlbit = S3C_CLKCON_PCLK_GPIO, 249 }, { 250 .name = "usb-host", 251 .id = -1, 252 .parent = &clk_h, 253 .enable = s3c64xx_hclk_ctrl, 254 .ctrlbit = S3C_CLKCON_HCLK_UHOST, 255 }, { 256 .name = "hsmmc", 257 .id = 0, 258 .parent = &clk_h, 259 .enable = s3c64xx_hclk_ctrl, 260 .ctrlbit = S3C_CLKCON_HCLK_HSMMC0, 261 }, { 262 .name = "hsmmc", 263 .id = 1, 264 .parent = &clk_h, 265 .enable = s3c64xx_hclk_ctrl, 266 .ctrlbit = S3C_CLKCON_HCLK_HSMMC1, 267 }, { 268 .name = "hsmmc", 269 .id = 2, 270 .parent = &clk_h, 271 .enable = s3c64xx_hclk_ctrl, 272 .ctrlbit = S3C_CLKCON_HCLK_HSMMC2, 273 }, { 274 .name = "otg", 275 .id = -1, 276 .parent = &clk_h, 277 .enable = s3c64xx_hclk_ctrl, 278 .ctrlbit = S3C_CLKCON_HCLK_USB, 279 }, { 280 .name = "timers", 281 .id = -1, 282 .parent = &clk_p, 283 .enable = s3c64xx_pclk_ctrl, 284 .ctrlbit = S3C_CLKCON_PCLK_PWM, 285 }, { 286 .name = "uart", 287 .id = 0, 288 .parent = &clk_p, 289 .enable = s3c64xx_pclk_ctrl, 290 .ctrlbit = S3C_CLKCON_PCLK_UART0, 291 }, { 292 .name = "uart", 293 .id = 1, 294 .parent = &clk_p, 295 .enable = s3c64xx_pclk_ctrl, 296 .ctrlbit = S3C_CLKCON_PCLK_UART1, 297 }, { 298 .name = "uart", 299 .id = 2, 300 .parent = &clk_p, 301 .enable = s3c64xx_pclk_ctrl, 302 .ctrlbit = S3C_CLKCON_PCLK_UART2, 303 }, { 304 .name = "uart", 305 .id = 3, 306 .parent = &clk_p, 307 .enable = s3c64xx_pclk_ctrl, 308 .ctrlbit = S3C_CLKCON_PCLK_UART3, 309 }, { 310 .name = "watchdog", 311 .id = -1, 312 .parent = &clk_p, 313 .ctrlbit = S3C_CLKCON_PCLK_WDT, 314 }, { 315 .name = "ac97", 316 .id = -1, 317 .parent = &clk_p, 318 .ctrlbit = S3C_CLKCON_PCLK_AC97, 319 }, { 320 .name = "cfcon", 321 .id = -1, 322 .parent = &clk_h, 323 .enable = s3c64xx_hclk_ctrl, 324 .ctrlbit = S3C_CLKCON_HCLK_IHOST, 325 } 326}; 327 328 329static struct clk clk_fout_apll = { 330 .name = "fout_apll", 331 .id = -1, 332}; 333 334static struct clk *clk_src_apll_list[] = { 335 [0] = &clk_fin_apll, 336 [1] = &clk_fout_apll, 337}; 338 339static struct clksrc_sources clk_src_apll = { 340 .sources = clk_src_apll_list, 341 .nr_sources = ARRAY_SIZE(clk_src_apll_list), 342}; 343 344static struct clksrc_clk clk_mout_apll = { 345 .clk = { 346 .name = "mout_apll", 347 .id = -1, 348 }, 349 .reg_src = { .reg = S3C_CLK_SRC, .shift = 0, .size = 1 }, 350 .sources = &clk_src_apll, 351}; 352 353static struct clk *clk_src_epll_list[] = { 354 [0] = &clk_fin_epll, 355 [1] = &clk_fout_epll, 356}; 357 358static struct clksrc_sources clk_src_epll = { 359 .sources = clk_src_epll_list, 360 .nr_sources = ARRAY_SIZE(clk_src_epll_list), 361}; 362 363static struct clksrc_clk clk_mout_epll = { 364 .clk = { 365 .name = "mout_epll", 366 .id = -1, 367 }, 368 .reg_src = { .reg = S3C_CLK_SRC, .shift = 2, .size = 1 }, 369 .sources = &clk_src_epll, 370}; 371 372static struct clk *clk_src_mpll_list[] = { 373 [0] = &clk_fin_mpll, 374 [1] = &clk_fout_mpll, 375}; 376 377static struct clksrc_sources clk_src_mpll = { 378 .sources = clk_src_mpll_list, 379 .nr_sources = ARRAY_SIZE(clk_src_mpll_list), 380}; 381 382static struct clksrc_clk clk_mout_mpll = { 383 .clk = { 384 .name = "mout_mpll", 385 .id = -1, 386 }, 387 .reg_src = { .reg = S3C_CLK_SRC, .shift = 1, .size = 1 }, 388 .sources = &clk_src_mpll, 389}; 390 391static unsigned int armclk_mask; 392 393static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk) 394{ 395 unsigned long rate = clk_get_rate(clk->parent); 396 u32 clkdiv; 397 398 /* divisor mask starts at bit0, so no need to shift */ 399 clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask; 400 401 return rate / (clkdiv + 1); 402} 403 404static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk, 405 unsigned long rate) 406{ 407 unsigned long parent = clk_get_rate(clk->parent); 408 u32 div; 409 410 if (parent < rate) 411 return parent; 412 413 div = (parent / rate) - 1; 414 if (div > armclk_mask) 415 div = armclk_mask; 416 417 return parent / (div + 1); 418} 419 420static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate) 421{ 422 unsigned long parent = clk_get_rate(clk->parent); 423 u32 div; 424 u32 val; 425 426 if (rate < parent / (armclk_mask + 1)) 427 return -EINVAL; 428 429 rate = clk_round_rate(clk, rate); 430 div = clk_get_rate(clk->parent) / rate; 431 432 val = __raw_readl(S3C_CLK_DIV0); 433 val &= ~armclk_mask; 434 val |= (div - 1); 435 __raw_writel(val, S3C_CLK_DIV0); 436 437 return 0; 438 439} 440 441static struct clk clk_arm = { 442 .name = "armclk", 443 .id = -1, 444 .parent = &clk_mout_apll.clk, 445 .ops = &(struct clk_ops) { 446 .get_rate = s3c64xx_clk_arm_get_rate, 447 .set_rate = s3c64xx_clk_arm_set_rate, 448 .round_rate = s3c64xx_clk_arm_round_rate, 449 }, 450}; 451 452static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk) 453{ 454 unsigned long rate = clk_get_rate(clk->parent); 455 456 printk(KERN_DEBUG "%s: parent is %ld\n", __func__, rate); 457 458 if (__raw_readl(S3C_CLK_DIV0) & S3C6400_CLKDIV0_MPLL_MASK) 459 rate /= 2; 460 461 return rate; 462} 463 464static struct clk_ops clk_dout_ops = { 465 .get_rate = s3c64xx_clk_doutmpll_get_rate, 466}; 467 468static struct clk clk_dout_mpll = { 469 .name = "dout_mpll", 470 .id = -1, 471 .parent = &clk_mout_mpll.clk, 472 .ops = &clk_dout_ops, 473}; 474 475static struct clk *clkset_spi_mmc_list[] = { 476 &clk_mout_epll.clk, 477 &clk_dout_mpll, 478 &clk_fin_epll, 479 &clk_27m, 480}; 481 482static struct clksrc_sources clkset_spi_mmc = { 483 .sources = clkset_spi_mmc_list, 484 .nr_sources = ARRAY_SIZE(clkset_spi_mmc_list), 485}; 486 487static struct clk *clkset_irda_list[] = { 488 &clk_mout_epll.clk, 489 &clk_dout_mpll, 490 NULL, 491 &clk_27m, 492}; 493 494static struct clksrc_sources clkset_irda = { 495 .sources = clkset_irda_list, 496 .nr_sources = ARRAY_SIZE(clkset_irda_list), 497}; 498 499static struct clk *clkset_uart_list[] = { 500 &clk_mout_epll.clk, 501 &clk_dout_mpll, 502 NULL, 503 NULL 504}; 505 506static struct clksrc_sources clkset_uart = { 507 .sources = clkset_uart_list, 508 .nr_sources = ARRAY_SIZE(clkset_uart_list), 509}; 510 511static struct clk *clkset_uhost_list[] = { 512 &clk_48m, 513 &clk_mout_epll.clk, 514 &clk_dout_mpll, 515 &clk_fin_epll, 516}; 517 518static struct clksrc_sources clkset_uhost = { 519 .sources = clkset_uhost_list, 520 .nr_sources = ARRAY_SIZE(clkset_uhost_list), 521}; 522 523/* The peripheral clocks are all controlled via clocksource followed 524 * by an optional divider and gate stage. We currently roll this into 525 * one clock which hides the intermediate clock from the mux. 526 * 527 * Note, the JPEG clock can only be an even divider... 528 * 529 * The scaler and LCD clocks depend on the S3C64XX version, and also 530 * have a common parent divisor so are not included here. 531 */ 532 533/* clocks that feed other parts of the clock source tree */ 534 535static struct clk clk_iis_cd0 = { 536 .name = "iis_cdclk0", 537 .id = -1, 538}; 539 540static struct clk clk_iis_cd1 = { 541 .name = "iis_cdclk1", 542 .id = -1, 543}; 544 545static struct clk clk_iisv4_cd = { 546 .name = "iis_cdclk_v4", 547 .id = -1, 548}; 549 550static struct clk clk_pcm_cd = { 551 .name = "pcm_cdclk", 552 .id = -1, 553}; 554 555static struct clk *clkset_audio0_list[] = { 556 [0] = &clk_mout_epll.clk, 557 [1] = &clk_dout_mpll, 558 [2] = &clk_fin_epll, 559 [3] = &clk_iis_cd0, 560 [4] = &clk_pcm_cd, 561}; 562 563static struct clksrc_sources clkset_audio0 = { 564 .sources = clkset_audio0_list, 565 .nr_sources = ARRAY_SIZE(clkset_audio0_list), 566}; 567 568static struct clk *clkset_audio1_list[] = { 569 [0] = &clk_mout_epll.clk, 570 [1] = &clk_dout_mpll, 571 [2] = &clk_fin_epll, 572 [3] = &clk_iis_cd1, 573 [4] = &clk_pcm_cd, 574}; 575 576static struct clksrc_sources clkset_audio1 = { 577 .sources = clkset_audio1_list, 578 .nr_sources = ARRAY_SIZE(clkset_audio1_list), 579}; 580 581static struct clk *clkset_audio2_list[] = { 582 [0] = &clk_mout_epll.clk, 583 [1] = &clk_dout_mpll, 584 [2] = &clk_fin_epll, 585 [3] = &clk_iisv4_cd, 586 [4] = &clk_pcm_cd, 587}; 588 589static struct clksrc_sources clkset_audio2 = { 590 .sources = clkset_audio2_list, 591 .nr_sources = ARRAY_SIZE(clkset_audio2_list), 592}; 593 594static struct clk *clkset_camif_list[] = { 595 &clk_h2, 596}; 597 598static struct clksrc_sources clkset_camif = { 599 .sources = clkset_camif_list, 600 .nr_sources = ARRAY_SIZE(clkset_camif_list), 601}; 602 603static struct clksrc_clk clksrcs[] = { 604 { 605 .clk = { 606 .name = "mmc_bus", 607 .id = 0, 608 .ctrlbit = S3C_CLKCON_SCLK_MMC0, 609 .enable = s3c64xx_sclk_ctrl, 610 }, 611 .reg_src = { .reg = S3C_CLK_SRC, .shift = 18, .size = 2 }, 612 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 0, .size = 4 }, 613 .sources = &clkset_spi_mmc, 614 }, { 615 .clk = { 616 .name = "mmc_bus", 617 .id = 1, 618 .ctrlbit = S3C_CLKCON_SCLK_MMC1, 619 .enable = s3c64xx_sclk_ctrl, 620 }, 621 .reg_src = { .reg = S3C_CLK_SRC, .shift = 20, .size = 2 }, 622 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 4, .size = 4 }, 623 .sources = &clkset_spi_mmc, 624 }, { 625 .clk = { 626 .name = "mmc_bus", 627 .id = 2, 628 .ctrlbit = S3C_CLKCON_SCLK_MMC2, 629 .enable = s3c64xx_sclk_ctrl, 630 }, 631 .reg_src = { .reg = S3C_CLK_SRC, .shift = 22, .size = 2 }, 632 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 8, .size = 4 }, 633 .sources = &clkset_spi_mmc, 634 }, { 635 .clk = { 636 .name = "usb-bus-host", 637 .id = -1, 638 .ctrlbit = S3C_CLKCON_SCLK_UHOST, 639 .enable = s3c64xx_sclk_ctrl, 640 }, 641 .reg_src = { .reg = S3C_CLK_SRC, .shift = 5, .size = 2 }, 642 .reg_div = { .reg = S3C_CLK_DIV1, .shift = 20, .size = 4 }, 643 .sources = &clkset_uhost, 644 }, { 645 .clk = { 646 .name = "uclk1", 647 .id = -1, 648 .ctrlbit = S3C_CLKCON_SCLK_UART, 649 .enable = s3c64xx_sclk_ctrl, 650 }, 651 .reg_src = { .reg = S3C_CLK_SRC, .shift = 13, .size = 1 }, 652 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 16, .size = 4 }, 653 .sources = &clkset_uart, 654 }, { 655/* Where does UCLK0 come from? */ 656 .clk = { 657 .name = "spi-bus", 658 .id = 0, 659 .ctrlbit = S3C_CLKCON_SCLK_SPI0, 660 .enable = s3c64xx_sclk_ctrl, 661 }, 662 .reg_src = { .reg = S3C_CLK_SRC, .shift = 14, .size = 2 }, 663 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 0, .size = 4 }, 664 .sources = &clkset_spi_mmc, 665 }, { 666 .clk = { 667 .name = "spi-bus", 668 .id = 1, 669 .ctrlbit = S3C_CLKCON_SCLK_SPI1, 670 .enable = s3c64xx_sclk_ctrl, 671 }, 672 .reg_src = { .reg = S3C_CLK_SRC, .shift = 16, .size = 2 }, 673 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 4, .size = 4 }, 674 .sources = &clkset_spi_mmc, 675 }, { 676 .clk = { 677 .name = "audio-bus", 678 .id = 0, 679 .ctrlbit = S3C_CLKCON_SCLK_AUDIO0, 680 .enable = s3c64xx_sclk_ctrl, 681 }, 682 .reg_src = { .reg = S3C_CLK_SRC, .shift = 7, .size = 3 }, 683 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 8, .size = 4 }, 684 .sources = &clkset_audio0, 685 }, { 686 .clk = { 687 .name = "audio-bus", 688 .id = 1, 689 .ctrlbit = S3C_CLKCON_SCLK_AUDIO1, 690 .enable = s3c64xx_sclk_ctrl, 691 }, 692 .reg_src = { .reg = S3C_CLK_SRC, .shift = 10, .size = 3 }, 693 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 12, .size = 4 }, 694 .sources = &clkset_audio1, 695 }, { 696 .clk = { 697 .name = "audio-bus", 698 .id = -1, /* There's only one IISv4 port */ 699 .ctrlbit = S3C6410_CLKCON_SCLK_AUDIO2, 700 .enable = s3c64xx_sclk_ctrl, 701 }, 702 .reg_src = { .reg = S3C6410_CLK_SRC2, .shift = 0, .size = 3 }, 703 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 24, .size = 4 }, 704 .sources = &clkset_audio2, 705 }, { 706 .clk = { 707 .name = "irda-bus", 708 .id = 0, 709 .ctrlbit = S3C_CLKCON_SCLK_IRDA, 710 .enable = s3c64xx_sclk_ctrl, 711 }, 712 .reg_src = { .reg = S3C_CLK_SRC, .shift = 24, .size = 2 }, 713 .reg_div = { .reg = S3C_CLK_DIV2, .shift = 20, .size = 4 }, 714 .sources = &clkset_irda, 715 }, { 716 .clk = { 717 .name = "camera", 718 .id = -1, 719 .ctrlbit = S3C_CLKCON_SCLK_CAM, 720 .enable = s3c64xx_sclk_ctrl, 721 }, 722 .reg_div = { .reg = S3C_CLK_DIV0, .shift = 20, .size = 4 }, 723 .reg_src = { .reg = NULL, .shift = 0, .size = 0 }, 724 .sources = &clkset_camif, 725 }, 726}; 727 728/* Clock initialisation code */ 729 730static struct clksrc_clk *init_parents[] = { 731 &clk_mout_apll, 732 &clk_mout_epll, 733 &clk_mout_mpll, 734}; 735 736#define GET_DIV(clk, field) ((((clk) & field##_MASK) >> field##_SHIFT) + 1) 737 738void __init_or_cpufreq s3c6400_setup_clocks(void) 739{ 740 struct clk *xtal_clk; 741 unsigned long xtal; 742 unsigned long fclk; 743 unsigned long hclk; 744 unsigned long hclk2; 745 unsigned long pclk; 746 unsigned long epll; 747 unsigned long apll; 748 unsigned long mpll; 749 unsigned int ptr; 750 u32 clkdiv0; 751 752 printk(KERN_DEBUG "%s: registering clocks\n", __func__); 753 754 clkdiv0 = __raw_readl(S3C_CLK_DIV0); 755 printk(KERN_DEBUG "%s: clkdiv0 = %08x\n", __func__, clkdiv0); 756 757 xtal_clk = clk_get(NULL, "xtal"); 758 BUG_ON(IS_ERR(xtal_clk)); 759 760 xtal = clk_get_rate(xtal_clk); 761 clk_put(xtal_clk); 762 763 printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal); 764 765 /* For now assume the mux always selects the crystal */ 766 clk_ext_xtal_mux.parent = xtal_clk; 767 768 epll = s3c6400_get_epll(xtal); 769 mpll = s3c6400_get_pll(xtal, __raw_readl(S3C_MPLL_CON)); 770 apll = s3c6400_get_pll(xtal, __raw_readl(S3C_APLL_CON)); 771 772 fclk = mpll; 773 774 printk(KERN_INFO "S3C64XX: PLL settings, A=%ld, M=%ld, E=%ld\n", 775 apll, mpll, epll); 776 777 hclk2 = mpll / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK2); 778 hclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_HCLK); 779 pclk = hclk2 / GET_DIV(clkdiv0, S3C6400_CLKDIV0_PCLK); 780 781 printk(KERN_INFO "S3C64XX: HCLK2=%ld, HCLK=%ld, PCLK=%ld\n", 782 hclk2, hclk, pclk); 783 784 clk_fout_mpll.rate = mpll; 785 clk_fout_epll.rate = epll; 786 clk_fout_apll.rate = apll; 787 788 clk_h2.rate = hclk2; 789 clk_h.rate = hclk; 790 clk_p.rate = pclk; 791 clk_f.rate = fclk; 792 793 for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++) 794 s3c_set_clksrc(init_parents[ptr], true); 795 796 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) 797 s3c_set_clksrc(&clksrcs[ptr], true); 798} 799 800static struct clk *clks1[] __initdata = { 801 &clk_ext_xtal_mux, 802 &clk_iis_cd0, 803 &clk_iis_cd1, 804 &clk_iisv4_cd, 805 &clk_pcm_cd, 806 &clk_mout_epll.clk, 807 &clk_mout_mpll.clk, 808 &clk_dout_mpll, 809 &clk_arm, 810}; 811 812static struct clk *clks[] __initdata = { 813 &clk_ext, 814 &clk_epll, 815 &clk_27m, 816 &clk_48m, 817 &clk_h2, 818 &clk_xusbxti, 819}; 820 821/** 822 * s3c64xx_register_clocks - register clocks for s3c6400 and s3c6410 823 * @xtal: The rate for the clock crystal feeding the PLLs. 824 * @armclk_divlimit: Divisor mask for ARMCLK. 825 * 826 * Register the clocks for the S3C6400 and S3C6410 SoC range, such 827 * as ARMCLK as well as the necessary parent clocks. 828 * 829 * This call does not setup the clocks, which is left to the 830 * s3c6400_setup_clocks() call which may be needed by the cpufreq 831 * or resume code to re-set the clocks if the bootloader has changed 832 * them. 833 */ 834void __init s3c64xx_register_clocks(unsigned long xtal, 835 unsigned armclk_divlimit) 836{ 837 struct clk *clkp; 838 int ret; 839 int ptr; 840 841 armclk_mask = armclk_divlimit; 842 843 s3c24xx_register_baseclocks(xtal); 844 s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); 845 846 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); 847 848 clkp = init_clocks_disable; 849 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { 850 851 ret = s3c24xx_register_clock(clkp); 852 if (ret < 0) { 853 printk(KERN_ERR "Failed to register clock %s (%d)\n", 854 clkp->name, ret); 855 } 856 857 (clkp->enable)(clkp, 0); 858 } 859 860 s3c24xx_register_clocks(clks1, ARRAY_SIZE(clks1)); 861 s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); 862 s3c_pwmclk_init(); 863} 864