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