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