1/* linux/arch/arm/mach-s5p6440/clock.c 2 * 3 * Copyright (c) 2009 Samsung Electronics Co., Ltd. 4 * http://www.samsung.com/ 5 * 6 * S5P6440 - Clock support 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License version 2 as 10 * published by the Free Software Foundation. 11*/ 12 13#include <linux/init.h> 14#include <linux/module.h> 15#include <linux/kernel.h> 16#include <linux/list.h> 17#include <linux/errno.h> 18#include <linux/err.h> 19#include <linux/clk.h> 20#include <linux/sysdev.h> 21#include <linux/io.h> 22 23#include <mach/hardware.h> 24#include <mach/map.h> 25 26#include <plat/cpu-freq.h> 27#include <mach/regs-clock.h> 28#include <plat/clock.h> 29#include <plat/cpu.h> 30#include <plat/clock-clksrc.h> 31#include <plat/s5p-clock.h> 32#include <plat/pll.h> 33#include <plat/s5p6440.h> 34 35/* APLL Mux output clock */ 36static struct clksrc_clk clk_mout_apll = { 37 .clk = { 38 .name = "mout_apll", 39 .id = -1, 40 }, 41 .sources = &clk_src_apll, 42 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 }, 43}; 44 45static int s5p6440_epll_enable(struct clk *clk, int enable) 46{ 47 unsigned int ctrlbit = clk->ctrlbit; 48 unsigned int epll_con = __raw_readl(S5P_EPLL_CON) & ~ctrlbit; 49 50 if (enable) 51 __raw_writel(epll_con | ctrlbit, S5P_EPLL_CON); 52 else 53 __raw_writel(epll_con, S5P_EPLL_CON); 54 55 return 0; 56} 57 58static unsigned long s5p6440_epll_get_rate(struct clk *clk) 59{ 60 return clk->rate; 61} 62 63static u32 epll_div[][5] = { 64 { 36000000, 0, 48, 1, 4 }, 65 { 48000000, 0, 32, 1, 3 }, 66 { 60000000, 0, 40, 1, 3 }, 67 { 72000000, 0, 48, 1, 3 }, 68 { 84000000, 0, 28, 1, 2 }, 69 { 96000000, 0, 32, 1, 2 }, 70 { 32768000, 45264, 43, 1, 4 }, 71 { 45158000, 6903, 30, 1, 3 }, 72 { 49152000, 50332, 32, 1, 3 }, 73 { 67738000, 10398, 45, 1, 3 }, 74 { 73728000, 9961, 49, 1, 3 } 75}; 76 77static int s5p6440_epll_set_rate(struct clk *clk, unsigned long rate) 78{ 79 unsigned int epll_con, epll_con_k; 80 unsigned int i; 81 82 if (clk->rate == rate) /* Return if nothing changed */ 83 return 0; 84 85 epll_con = __raw_readl(S5P_EPLL_CON); 86 epll_con_k = __raw_readl(S5P_EPLL_CON_K); 87 88 epll_con_k &= ~(PLL90XX_KDIV_MASK); 89 epll_con &= ~(PLL90XX_MDIV_MASK | PLL90XX_PDIV_MASK | PLL90XX_SDIV_MASK); 90 91 for (i = 0; i < ARRAY_SIZE(epll_div); i++) { 92 if (epll_div[i][0] == rate) { 93 epll_con_k |= (epll_div[i][1] << PLL90XX_KDIV_SHIFT); 94 epll_con |= (epll_div[i][2] << PLL90XX_MDIV_SHIFT) | 95 (epll_div[i][3] << PLL90XX_PDIV_SHIFT) | 96 (epll_div[i][4] << PLL90XX_SDIV_SHIFT); 97 break; 98 } 99 } 100 101 if (i == ARRAY_SIZE(epll_div)) { 102 printk(KERN_ERR "%s: Invalid Clock EPLL Frequency\n", __func__); 103 return -EINVAL; 104 } 105 106 __raw_writel(epll_con, S5P_EPLL_CON); 107 __raw_writel(epll_con_k, S5P_EPLL_CON_K); 108 109 clk->rate = rate; 110 111 return 0; 112} 113 114static struct clk_ops s5p6440_epll_ops = { 115 .get_rate = s5p6440_epll_get_rate, 116 .set_rate = s5p6440_epll_set_rate, 117}; 118 119static struct clksrc_clk clk_mout_epll = { 120 .clk = { 121 .name = "mout_epll", 122 .id = -1, 123 }, 124 .sources = &clk_src_epll, 125 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 2, .size = 1 }, 126}; 127 128static struct clksrc_clk clk_mout_mpll = { 129 .clk = { 130 .name = "mout_mpll", 131 .id = -1, 132 }, 133 .sources = &clk_src_mpll, 134 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 1, .size = 1 }, 135}; 136 137enum perf_level { 138 L0 = 532*1000, 139 L1 = 266*1000, 140 L2 = 133*1000, 141}; 142 143static const u32 clock_table[][3] = { 144 /*{ARM_CLK, DIVarm, DIVhclk}*/ 145 {L0 * 1000, (0 << ARM_DIV_RATIO_SHIFT), (3 << S5P_CLKDIV0_HCLK_SHIFT)}, 146 {L1 * 1000, (1 << ARM_DIV_RATIO_SHIFT), (1 << S5P_CLKDIV0_HCLK_SHIFT)}, 147 {L2 * 1000, (3 << ARM_DIV_RATIO_SHIFT), (0 << S5P_CLKDIV0_HCLK_SHIFT)}, 148}; 149 150static unsigned long s5p6440_armclk_get_rate(struct clk *clk) 151{ 152 unsigned long rate = clk_get_rate(clk->parent); 153 u32 clkdiv; 154 155 /* divisor mask starts at bit0, so no need to shift */ 156 clkdiv = __raw_readl(ARM_CLK_DIV) & ARM_DIV_MASK; 157 158 return rate / (clkdiv + 1); 159} 160 161static unsigned long s5p6440_armclk_round_rate(struct clk *clk, 162 unsigned long rate) 163{ 164 u32 iter; 165 166 for (iter = 1 ; iter < ARRAY_SIZE(clock_table) ; iter++) { 167 if (rate > clock_table[iter][0]) 168 return clock_table[iter-1][0]; 169 } 170 171 return clock_table[ARRAY_SIZE(clock_table) - 1][0]; 172} 173 174static int s5p6440_armclk_set_rate(struct clk *clk, unsigned long rate) 175{ 176 u32 round_tmp; 177 u32 iter; 178 u32 clk_div0_tmp; 179 u32 cur_rate = clk->ops->get_rate(clk); 180 unsigned long flags; 181 182 round_tmp = clk->ops->round_rate(clk, rate); 183 if (round_tmp == cur_rate) 184 return 0; 185 186 187 for (iter = 0 ; iter < ARRAY_SIZE(clock_table) ; iter++) { 188 if (round_tmp == clock_table[iter][0]) 189 break; 190 } 191 192 if (iter >= ARRAY_SIZE(clock_table)) 193 iter = ARRAY_SIZE(clock_table) - 1; 194 195 local_irq_save(flags); 196 if (cur_rate > round_tmp) { 197 /* Frequency Down */ 198 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK); 199 clk_div0_tmp |= clock_table[iter][1]; 200 __raw_writel(clk_div0_tmp, ARM_CLK_DIV); 201 202 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & 203 ~(S5P_CLKDIV0_HCLK_MASK); 204 clk_div0_tmp |= clock_table[iter][2]; 205 __raw_writel(clk_div0_tmp, ARM_CLK_DIV); 206 207 208 } else { 209 /* Frequency Up */ 210 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & 211 ~(S5P_CLKDIV0_HCLK_MASK); 212 clk_div0_tmp |= clock_table[iter][2]; 213 __raw_writel(clk_div0_tmp, ARM_CLK_DIV); 214 215 clk_div0_tmp = __raw_readl(ARM_CLK_DIV) & ~(ARM_DIV_MASK); 216 clk_div0_tmp |= clock_table[iter][1]; 217 __raw_writel(clk_div0_tmp, ARM_CLK_DIV); 218 } 219 local_irq_restore(flags); 220 221 clk->rate = clock_table[iter][0]; 222 223 return 0; 224} 225 226static struct clk_ops s5p6440_clkarm_ops = { 227 .get_rate = s5p6440_armclk_get_rate, 228 .set_rate = s5p6440_armclk_set_rate, 229 .round_rate = s5p6440_armclk_round_rate, 230}; 231 232static struct clksrc_clk clk_armclk = { 233 .clk = { 234 .name = "armclk", 235 .id = 1, 236 .parent = &clk_mout_apll.clk, 237 .ops = &s5p6440_clkarm_ops, 238 }, 239 .reg_div = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 4 }, 240}; 241 242static struct clksrc_clk clk_dout_mpll = { 243 .clk = { 244 .name = "dout_mpll", 245 .id = -1, 246 .parent = &clk_mout_mpll.clk, 247 }, 248 .reg_div = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 1 }, 249}; 250 251static struct clksrc_clk clk_hclk = { 252 .clk = { 253 .name = "clk_hclk", 254 .id = -1, 255 .parent = &clk_armclk.clk, 256 }, 257 .reg_div = { .reg = S5P_CLK_DIV0, .shift = 8, .size = 4 }, 258}; 259 260static struct clksrc_clk clk_pclk = { 261 .clk = { 262 .name = "clk_pclk", 263 .id = -1, 264 .parent = &clk_hclk.clk, 265 }, 266 .reg_div = { .reg = S5P_CLK_DIV0, .shift = 12, .size = 4 }, 267}; 268 269static struct clk *clkset_hclklow_list[] = { 270 &clk_mout_apll.clk, 271 &clk_mout_mpll.clk, 272}; 273 274static struct clksrc_sources clkset_hclklow = { 275 .sources = clkset_hclklow_list, 276 .nr_sources = ARRAY_SIZE(clkset_hclklow_list), 277}; 278 279static struct clksrc_clk clk_hclk_low = { 280 .clk = { 281 .name = "hclk_low", 282 .id = -1, 283 }, 284 .sources = &clkset_hclklow, 285 .reg_src = { .reg = S5P_SYS_OTHERS, .shift = 6, .size = 1 }, 286 .reg_div = { .reg = S5P_CLK_DIV3, .shift = 8, .size = 4 }, 287}; 288 289static struct clksrc_clk clk_pclk_low = { 290 .clk = { 291 .name = "pclk_low", 292 .id = -1, 293 .parent = &clk_hclk_low.clk, 294 }, 295 .reg_div = { .reg = S5P_CLK_DIV3, .shift = 12, .size = 4 }, 296}; 297 298int s5p6440_clk48m_ctrl(struct clk *clk, int enable) 299{ 300 unsigned long flags; 301 u32 val; 302 303 /* can't rely on clock lock, this register has other usages */ 304 local_irq_save(flags); 305 306 val = __raw_readl(S5P_OTHERS); 307 if (enable) 308 val |= S5P_OTHERS_USB_SIG_MASK; 309 else 310 val &= ~S5P_OTHERS_USB_SIG_MASK; 311 312 __raw_writel(val, S5P_OTHERS); 313 314 local_irq_restore(flags); 315 316 return 0; 317} 318 319static int s5p6440_pclk_ctrl(struct clk *clk, int enable) 320{ 321 return s5p_gatectrl(S5P_CLK_GATE_PCLK, clk, enable); 322} 323 324static int s5p6440_hclk0_ctrl(struct clk *clk, int enable) 325{ 326 return s5p_gatectrl(S5P_CLK_GATE_HCLK0, clk, enable); 327} 328 329static int s5p6440_hclk1_ctrl(struct clk *clk, int enable) 330{ 331 return s5p_gatectrl(S5P_CLK_GATE_HCLK1, clk, enable); 332} 333 334static int s5p6440_sclk_ctrl(struct clk *clk, int enable) 335{ 336 return s5p_gatectrl(S5P_CLK_GATE_SCLK0, clk, enable); 337} 338 339static int s5p6440_sclk1_ctrl(struct clk *clk, int enable) 340{ 341 return s5p_gatectrl(S5P_CLK_GATE_SCLK1, clk, enable); 342} 343 344static int s5p6440_mem_ctrl(struct clk *clk, int enable) 345{ 346 return s5p_gatectrl(S5P_CLK_GATE_MEM0, clk, enable); 347} 348 349/* 350 * The following clocks will be disabled during clock initialization. It is 351 * recommended to keep the following clocks disabled until the driver requests 352 * for enabling the clock. 353 */ 354static struct clk init_clocks_disable[] = { 355 { 356 .name = "nand", 357 .id = -1, 358 .parent = &clk_hclk.clk, 359 .enable = s5p6440_mem_ctrl, 360 .ctrlbit = S5P_CLKCON_MEM0_HCLK_NFCON, 361 }, { 362 .name = "adc", 363 .id = -1, 364 .parent = &clk_pclk_low.clk, 365 .enable = s5p6440_pclk_ctrl, 366 .ctrlbit = S5P_CLKCON_PCLK_TSADC, 367 }, { 368 .name = "i2c", 369 .id = -1, 370 .parent = &clk_pclk_low.clk, 371 .enable = s5p6440_pclk_ctrl, 372 .ctrlbit = S5P_CLKCON_PCLK_IIC0, 373 }, { 374 .name = "i2s_v40", 375 .id = 0, 376 .parent = &clk_pclk_low.clk, 377 .enable = s5p6440_pclk_ctrl, 378 .ctrlbit = S5P_CLKCON_PCLK_IIS2, 379 }, { 380 .name = "spi", 381 .id = 0, 382 .parent = &clk_pclk_low.clk, 383 .enable = s5p6440_pclk_ctrl, 384 .ctrlbit = S5P_CLKCON_PCLK_SPI0, 385 }, { 386 .name = "spi", 387 .id = 1, 388 .parent = &clk_pclk_low.clk, 389 .enable = s5p6440_pclk_ctrl, 390 .ctrlbit = S5P_CLKCON_PCLK_SPI1, 391 }, { 392 .name = "sclk_spi_48", 393 .id = 0, 394 .parent = &clk_48m, 395 .enable = s5p6440_sclk_ctrl, 396 .ctrlbit = S5P_CLKCON_SCLK0_SPI0_48, 397 }, { 398 .name = "sclk_spi_48", 399 .id = 1, 400 .parent = &clk_48m, 401 .enable = s5p6440_sclk_ctrl, 402 .ctrlbit = S5P_CLKCON_SCLK0_SPI1_48, 403 }, { 404 .name = "mmc_48m", 405 .id = 0, 406 .parent = &clk_48m, 407 .enable = s5p6440_sclk_ctrl, 408 .ctrlbit = S5P_CLKCON_SCLK0_MMC0_48, 409 }, { 410 .name = "mmc_48m", 411 .id = 1, 412 .parent = &clk_48m, 413 .enable = s5p6440_sclk_ctrl, 414 .ctrlbit = S5P_CLKCON_SCLK0_MMC1_48, 415 }, { 416 .name = "mmc_48m", 417 .id = 2, 418 .parent = &clk_48m, 419 .enable = s5p6440_sclk_ctrl, 420 .ctrlbit = S5P_CLKCON_SCLK0_MMC2_48, 421 }, { 422 .name = "otg", 423 .id = -1, 424 .parent = &clk_hclk_low.clk, 425 .enable = s5p6440_hclk0_ctrl, 426 .ctrlbit = S5P_CLKCON_HCLK0_USB 427 }, { 428 .name = "post", 429 .id = -1, 430 .parent = &clk_hclk_low.clk, 431 .enable = s5p6440_hclk0_ctrl, 432 .ctrlbit = S5P_CLKCON_HCLK0_POST0 433 }, { 434 .name = "lcd", 435 .id = -1, 436 .parent = &clk_hclk_low.clk, 437 .enable = s5p6440_hclk1_ctrl, 438 .ctrlbit = S5P_CLKCON_HCLK1_DISPCON, 439 }, { 440 .name = "hsmmc", 441 .id = 0, 442 .parent = &clk_hclk_low.clk, 443 .enable = s5p6440_hclk0_ctrl, 444 .ctrlbit = S5P_CLKCON_HCLK0_HSMMC0, 445 }, { 446 .name = "hsmmc", 447 .id = 1, 448 .parent = &clk_hclk_low.clk, 449 .enable = s5p6440_hclk0_ctrl, 450 .ctrlbit = S5P_CLKCON_HCLK0_HSMMC1, 451 }, { 452 .name = "hsmmc", 453 .id = 2, 454 .parent = &clk_hclk_low.clk, 455 .enable = s5p6440_hclk0_ctrl, 456 .ctrlbit = S5P_CLKCON_HCLK0_HSMMC2, 457 }, { 458 .name = "rtc", 459 .id = -1, 460 .parent = &clk_pclk_low.clk, 461 .enable = s5p6440_pclk_ctrl, 462 .ctrlbit = S5P_CLKCON_PCLK_RTC, 463 }, { 464 .name = "watchdog", 465 .id = -1, 466 .parent = &clk_pclk_low.clk, 467 .enable = s5p6440_pclk_ctrl, 468 .ctrlbit = S5P_CLKCON_PCLK_WDT, 469 }, { 470 .name = "timers", 471 .id = -1, 472 .parent = &clk_pclk_low.clk, 473 .enable = s5p6440_pclk_ctrl, 474 .ctrlbit = S5P_CLKCON_PCLK_PWM, 475 }, { 476 .name = "hclk_fimgvg", 477 .id = -1, 478 .parent = &clk_hclk.clk, 479 .enable = s5p6440_hclk1_ctrl, 480 .ctrlbit = (1 << 2), 481 }, { 482 .name = "tsi", 483 .id = -1, 484 .parent = &clk_hclk_low.clk, 485 .enable = s5p6440_hclk1_ctrl, 486 .ctrlbit = (1 << 0), 487 }, { 488 .name = "pclk_fimgvg", 489 .id = -1, 490 .parent = &clk_pclk.clk, 491 .enable = s5p6440_pclk_ctrl, 492 .ctrlbit = (1 << 31), 493 }, { 494 .name = "dmc0", 495 .id = -1, 496 .parent = &clk_pclk.clk, 497 .enable = s5p6440_pclk_ctrl, 498 .ctrlbit = (1 << 30), 499 }, { 500 .name = "etm", 501 .id = -1, 502 .parent = &clk_pclk.clk, 503 .enable = s5p6440_pclk_ctrl, 504 .ctrlbit = (1 << 29), 505 }, { 506 .name = "dsim", 507 .id = -1, 508 .parent = &clk_pclk_low.clk, 509 .enable = s5p6440_pclk_ctrl, 510 .ctrlbit = (1 << 28), 511 }, { 512 .name = "gps", 513 .id = -1, 514 .parent = &clk_pclk_low.clk, 515 .enable = s5p6440_pclk_ctrl, 516 .ctrlbit = (1 << 25), 517 }, { 518 .name = "pcm", 519 .id = -1, 520 .parent = &clk_pclk_low.clk, 521 .enable = s5p6440_pclk_ctrl, 522 .ctrlbit = (1 << 8), 523 }, { 524 .name = "irom", 525 .id = -1, 526 .parent = &clk_hclk.clk, 527 .enable = s5p6440_hclk0_ctrl, 528 .ctrlbit = (1 << 25), 529 }, { 530 .name = "dma", 531 .id = -1, 532 .parent = &clk_hclk_low.clk, 533 .enable = s5p6440_hclk0_ctrl, 534 .ctrlbit = (1 << 12), 535 }, { 536 .name = "2d", 537 .id = -1, 538 .parent = &clk_hclk.clk, 539 .enable = s5p6440_hclk0_ctrl, 540 .ctrlbit = (1 << 8), 541 }, 542}; 543 544/* 545 * The following clocks will be enabled during clock initialization. 546 */ 547static struct clk init_clocks[] = { 548 { 549 .name = "gpio", 550 .id = -1, 551 .parent = &clk_pclk_low.clk, 552 .enable = s5p6440_pclk_ctrl, 553 .ctrlbit = S5P_CLKCON_PCLK_GPIO, 554 }, { 555 .name = "uart", 556 .id = 0, 557 .parent = &clk_pclk_low.clk, 558 .enable = s5p6440_pclk_ctrl, 559 .ctrlbit = S5P_CLKCON_PCLK_UART0, 560 }, { 561 .name = "uart", 562 .id = 1, 563 .parent = &clk_pclk_low.clk, 564 .enable = s5p6440_pclk_ctrl, 565 .ctrlbit = S5P_CLKCON_PCLK_UART1, 566 }, { 567 .name = "uart", 568 .id = 2, 569 .parent = &clk_pclk_low.clk, 570 .enable = s5p6440_pclk_ctrl, 571 .ctrlbit = S5P_CLKCON_PCLK_UART2, 572 }, { 573 .name = "uart", 574 .id = 3, 575 .parent = &clk_pclk_low.clk, 576 .enable = s5p6440_pclk_ctrl, 577 .ctrlbit = S5P_CLKCON_PCLK_UART3, 578 }, { 579 .name = "mem", 580 .id = -1, 581 .parent = &clk_hclk.clk, 582 .enable = s5p6440_hclk0_ctrl, 583 .ctrlbit = (1 << 21), 584 }, { 585 .name = "intc", 586 .id = -1, 587 .parent = &clk_hclk.clk, 588 .enable = s5p6440_hclk0_ctrl, 589 .ctrlbit = (1 << 1), 590 }, 591}; 592 593static struct clk clk_iis_cd_v40 = { 594 .name = "iis_cdclk_v40", 595 .id = -1, 596}; 597 598static struct clk clk_pcm_cd = { 599 .name = "pcm_cdclk", 600 .id = -1, 601}; 602 603static struct clk *clkset_group1_list[] = { 604 &clk_mout_epll.clk, 605 &clk_dout_mpll.clk, 606 &clk_fin_epll, 607}; 608 609static struct clksrc_sources clkset_group1 = { 610 .sources = clkset_group1_list, 611 .nr_sources = ARRAY_SIZE(clkset_group1_list), 612}; 613 614static struct clk *clkset_uart_list[] = { 615 &clk_mout_epll.clk, 616 &clk_dout_mpll.clk, 617}; 618 619static struct clksrc_sources clkset_uart = { 620 .sources = clkset_uart_list, 621 .nr_sources = ARRAY_SIZE(clkset_uart_list), 622}; 623 624static struct clk *clkset_audio_list[] = { 625 &clk_mout_epll.clk, 626 &clk_dout_mpll.clk, 627 &clk_fin_epll, 628 &clk_iis_cd_v40, 629 &clk_pcm_cd, 630}; 631 632static struct clksrc_sources clkset_audio = { 633 .sources = clkset_audio_list, 634 .nr_sources = ARRAY_SIZE(clkset_audio_list), 635}; 636 637static struct clksrc_clk clksrcs[] = { 638 { 639 .clk = { 640 .name = "mmc_bus", 641 .id = 0, 642 .ctrlbit = S5P_CLKCON_SCLK0_MMC0, 643 .enable = s5p6440_sclk_ctrl, 644 }, 645 .sources = &clkset_group1, 646 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 18, .size = 2 }, 647 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 0, .size = 4 }, 648 }, { 649 .clk = { 650 .name = "mmc_bus", 651 .id = 1, 652 .ctrlbit = S5P_CLKCON_SCLK0_MMC1, 653 .enable = s5p6440_sclk_ctrl, 654 }, 655 .sources = &clkset_group1, 656 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 20, .size = 2 }, 657 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 4, .size = 4 }, 658 }, { 659 .clk = { 660 .name = "mmc_bus", 661 .id = 2, 662 .ctrlbit = S5P_CLKCON_SCLK0_MMC2, 663 .enable = s5p6440_sclk_ctrl, 664 }, 665 .sources = &clkset_group1, 666 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 22, .size = 2 }, 667 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 8, .size = 4 }, 668 }, { 669 .clk = { 670 .name = "uclk1", 671 .id = -1, 672 .ctrlbit = S5P_CLKCON_SCLK0_UART, 673 .enable = s5p6440_sclk_ctrl, 674 }, 675 .sources = &clkset_uart, 676 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 13, .size = 1 }, 677 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 16, .size = 4 }, 678 }, { 679 .clk = { 680 .name = "spi_epll", 681 .id = 0, 682 .ctrlbit = S5P_CLKCON_SCLK0_SPI0, 683 .enable = s5p6440_sclk_ctrl, 684 }, 685 .sources = &clkset_group1, 686 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 14, .size = 2 }, 687 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 0, .size = 4 }, 688 }, { 689 .clk = { 690 .name = "spi_epll", 691 .id = 1, 692 .ctrlbit = S5P_CLKCON_SCLK0_SPI1, 693 .enable = s5p6440_sclk_ctrl, 694 }, 695 .sources = &clkset_group1, 696 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 16, .size = 2 }, 697 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 4, .size = 4 }, 698 }, { 699 .clk = { 700 .name = "sclk_post", 701 .id = -1, 702 .ctrlbit = (1 << 10), 703 .enable = s5p6440_sclk_ctrl, 704 }, 705 .sources = &clkset_group1, 706 .reg_src = { .reg = S5P_CLK_SRC0, .shift = 26, .size = 2 }, 707 .reg_div = { .reg = S5P_CLK_DIV1, .shift = 12, .size = 4 }, 708 }, { 709 .clk = { 710 .name = "sclk_dispcon", 711 .id = -1, 712 .ctrlbit = (1 << 1), 713 .enable = s5p6440_sclk1_ctrl, 714 }, 715 .sources = &clkset_group1, 716 .reg_src = { .reg = S5P_CLK_SRC1, .shift = 4, .size = 2 }, 717 .reg_div = { .reg = S5P_CLK_DIV3, .shift = 0, .size = 4 }, 718 }, { 719 .clk = { 720 .name = "sclk_fimgvg", 721 .id = -1, 722 .ctrlbit = (1 << 2), 723 .enable = s5p6440_sclk1_ctrl, 724 }, 725 .sources = &clkset_group1, 726 .reg_src = { .reg = S5P_CLK_SRC1, .shift = 8, .size = 2 }, 727 .reg_div = { .reg = S5P_CLK_DIV3, .shift = 4, .size = 4 }, 728 }, { 729 .clk = { 730 .name = "sclk_audio2", 731 .id = -1, 732 .ctrlbit = (1 << 11), 733 .enable = s5p6440_sclk_ctrl, 734 }, 735 .sources = &clkset_audio, 736 .reg_src = { .reg = S5P_CLK_SRC1, .shift = 0, .size = 3 }, 737 .reg_div = { .reg = S5P_CLK_DIV2, .shift = 24, .size = 4 }, 738 }, 739}; 740 741/* Clock initialisation code */ 742static struct clksrc_clk *sysclks[] = { 743 &clk_mout_apll, 744 &clk_mout_epll, 745 &clk_mout_mpll, 746 &clk_dout_mpll, 747 &clk_armclk, 748 &clk_hclk, 749 &clk_pclk, 750 &clk_hclk_low, 751 &clk_pclk_low, 752}; 753 754void __init_or_cpufreq s5p6440_setup_clocks(void) 755{ 756 struct clk *xtal_clk; 757 unsigned long xtal; 758 unsigned long fclk; 759 unsigned long hclk; 760 unsigned long hclk_low; 761 unsigned long pclk; 762 unsigned long pclk_low; 763 unsigned long epll; 764 unsigned long apll; 765 unsigned long mpll; 766 unsigned int ptr; 767 768 /* Set S5P6440 functions for clk_fout_epll */ 769 clk_fout_epll.enable = s5p6440_epll_enable; 770 clk_fout_epll.ops = &s5p6440_epll_ops; 771 772 clk_48m.enable = s5p6440_clk48m_ctrl; 773 774 xtal_clk = clk_get(NULL, "ext_xtal"); 775 BUG_ON(IS_ERR(xtal_clk)); 776 777 xtal = clk_get_rate(xtal_clk); 778 clk_put(xtal_clk); 779 780 epll = s5p_get_pll90xx(xtal, __raw_readl(S5P_EPLL_CON), 781 __raw_readl(S5P_EPLL_CON_K)); 782 mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502); 783 apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4502); 784 785 clk_fout_mpll.rate = mpll; 786 clk_fout_epll.rate = epll; 787 clk_fout_apll.rate = apll; 788 789 printk(KERN_INFO "S5P6440: PLL settings, A=%ld.%ldMHz, M=%ld.%ldMHz," \ 790 " E=%ld.%ldMHz\n", 791 print_mhz(apll), print_mhz(mpll), print_mhz(epll)); 792 793 fclk = clk_get_rate(&clk_armclk.clk); 794 hclk = clk_get_rate(&clk_hclk.clk); 795 pclk = clk_get_rate(&clk_pclk.clk); 796 hclk_low = clk_get_rate(&clk_hclk_low.clk); 797 pclk_low = clk_get_rate(&clk_pclk_low.clk); 798 799 printk(KERN_INFO "S5P6440: HCLK=%ld.%ldMHz, HCLK_LOW=%ld.%ldMHz," \ 800 " PCLK=%ld.%ldMHz, PCLK_LOW=%ld.%ldMHz\n", 801 print_mhz(hclk), print_mhz(hclk_low), 802 print_mhz(pclk), print_mhz(pclk_low)); 803 804 clk_f.rate = fclk; 805 clk_h.rate = hclk; 806 clk_p.rate = pclk; 807 808 for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++) 809 s3c_set_clksrc(&clksrcs[ptr], true); 810} 811 812static struct clk *clks[] __initdata = { 813 &clk_ext, 814 &clk_iis_cd_v40, 815 &clk_pcm_cd, 816}; 817 818void __init s5p6440_register_clocks(void) 819{ 820 struct clk *clkp; 821 int ret; 822 int ptr; 823 824 ret = s3c24xx_register_clocks(clks, ARRAY_SIZE(clks)); 825 if (ret > 0) 826 printk(KERN_ERR "Failed to register %u clocks\n", ret); 827 828 for (ptr = 0; ptr < ARRAY_SIZE(sysclks); ptr++) 829 s3c_register_clksrc(sysclks[ptr], 1); 830 831 s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs)); 832 s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks)); 833 834 clkp = init_clocks_disable; 835 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) { 836 837 ret = s3c24xx_register_clock(clkp); 838 if (ret < 0) { 839 printk(KERN_ERR "Failed to register clock %s (%d)\n", 840 clkp->name, ret); 841 } 842 (clkp->enable)(clkp, 0); 843 } 844 845 s3c_pwmclk_init(); 846} 847