linux/arch/arm/mach-s5p6442/clock.c
<<
>>
Prefs
   1/* linux/arch/arm/mach-s5p6442/clock.c
   2 *
   3 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
   4 *              http://www.samsung.com/
   5 *
   6 * S5P6442 - 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/err.h>
  18#include <linux/clk.h>
  19#include <linux/io.h>
  20
  21#include <mach/map.h>
  22
  23#include <plat/cpu-freq.h>
  24#include <mach/regs-clock.h>
  25#include <plat/clock.h>
  26#include <plat/cpu.h>
  27#include <plat/pll.h>
  28#include <plat/s5p-clock.h>
  29#include <plat/clock-clksrc.h>
  30#include <plat/s5p6442.h>
  31
  32static struct clksrc_clk clk_mout_apll = {
  33        .clk    = {
  34                .name           = "mout_apll",
  35                .id             = -1,
  36        },
  37        .sources        = &clk_src_apll,
  38        .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
  39};
  40
  41static struct clksrc_clk clk_mout_mpll = {
  42        .clk = {
  43                .name           = "mout_mpll",
  44                .id             = -1,
  45        },
  46        .sources        = &clk_src_mpll,
  47        .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 4, .size = 1 },
  48};
  49
  50static struct clksrc_clk clk_mout_epll = {
  51        .clk    = {
  52                .name           = "mout_epll",
  53                .id             = -1,
  54        },
  55        .sources        = &clk_src_epll,
  56        .reg_src        = { .reg = S5P_CLK_SRC0, .shift = 8, .size = 1 },
  57};
  58
  59/* Possible clock sources for ARM Mux */
  60static struct clk *clk_src_arm_list[] = {
  61        [1] = &clk_mout_apll.clk,
  62        [2] = &clk_mout_mpll.clk,
  63};
  64
  65static struct clksrc_sources clk_src_arm = {
  66        .sources        = clk_src_arm_list,
  67        .nr_sources     = ARRAY_SIZE(clk_src_arm_list),
  68};
  69
  70static struct clksrc_clk clk_mout_arm = {
  71        .clk    = {
  72                .name           = "mout_arm",
  73                .id             = -1,
  74        },
  75        .sources        = &clk_src_arm,
  76        .reg_src        = { .reg = S5P_CLK_MUX_STAT0, .shift = 16, .size = 3 },
  77};
  78
  79static struct clk clk_dout_a2m = {
  80        .name           = "dout_a2m",
  81        .id             = -1,
  82        .parent         = &clk_mout_apll.clk,
  83};
  84
  85/* Possible clock sources for D0 Mux */
  86static struct clk *clk_src_d0_list[] = {
  87        [1] = &clk_mout_mpll.clk,
  88        [2] = &clk_dout_a2m,
  89};
  90
  91static struct clksrc_sources clk_src_d0 = {
  92        .sources        = clk_src_d0_list,
  93        .nr_sources     = ARRAY_SIZE(clk_src_d0_list),
  94};
  95
  96static struct clksrc_clk clk_mout_d0 = {
  97        .clk = {
  98                .name           = "mout_d0",
  99                .id             = -1,
 100        },
 101        .sources        = &clk_src_d0,
 102        .reg_src        = { .reg = S5P_CLK_MUX_STAT0, .shift = 20, .size = 3 },
 103};
 104
 105static struct clk clk_dout_apll = {
 106        .name           = "dout_apll",
 107        .id             = -1,
 108        .parent         = &clk_mout_arm.clk,
 109};
 110
 111/* Possible clock sources for D0SYNC Mux */
 112static struct clk *clk_src_d0sync_list[] = {
 113        [1] = &clk_mout_d0.clk,
 114        [2] = &clk_dout_apll,
 115};
 116
 117static struct clksrc_sources clk_src_d0sync = {
 118        .sources        = clk_src_d0sync_list,
 119        .nr_sources     = ARRAY_SIZE(clk_src_d0sync_list),
 120};
 121
 122static struct clksrc_clk clk_mout_d0sync = {
 123        .clk    = {
 124                .name           = "mout_d0sync",
 125                .id             = -1,
 126        },
 127        .sources        = &clk_src_d0sync,
 128        .reg_src        = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
 129};
 130
 131/* Possible clock sources for D1 Mux */
 132static struct clk *clk_src_d1_list[] = {
 133        [1] = &clk_mout_mpll.clk,
 134        [2] = &clk_dout_a2m,
 135};
 136
 137static struct clksrc_sources clk_src_d1 = {
 138        .sources        = clk_src_d1_list,
 139        .nr_sources     = ARRAY_SIZE(clk_src_d1_list),
 140};
 141
 142static struct clksrc_clk clk_mout_d1 = {
 143        .clk    = {
 144                .name           = "mout_d1",
 145                .id             = -1,
 146        },
 147        .sources        = &clk_src_d1,
 148        .reg_src        = { .reg = S5P_CLK_MUX_STAT0, .shift = 24, .size = 3 },
 149};
 150
 151/* Possible clock sources for D1SYNC Mux */
 152static struct clk *clk_src_d1sync_list[] = {
 153        [1] = &clk_mout_d1.clk,
 154        [2] = &clk_dout_apll,
 155};
 156
 157static struct clksrc_sources clk_src_d1sync = {
 158        .sources        = clk_src_d1sync_list,
 159        .nr_sources     = ARRAY_SIZE(clk_src_d1sync_list),
 160};
 161
 162static struct clksrc_clk clk_mout_d1sync = {
 163        .clk    = {
 164                .name           = "mout_d1sync",
 165                .id             = -1,
 166        },
 167        .sources        = &clk_src_d1sync,
 168        .reg_src        = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
 169};
 170
 171static struct clk clk_hclkd0 = {
 172        .name           = "hclkd0",
 173        .id             = -1,
 174        .parent         = &clk_mout_d0sync.clk,
 175};
 176
 177static struct clk clk_hclkd1 = {
 178        .name           = "hclkd1",
 179        .id             = -1,
 180        .parent         = &clk_mout_d1sync.clk,
 181};
 182
 183static struct clk clk_pclkd0 = {
 184        .name           = "pclkd0",
 185        .id             = -1,
 186        .parent         = &clk_hclkd0,
 187};
 188
 189static struct clk clk_pclkd1 = {
 190        .name           = "pclkd1",
 191        .id             = -1,
 192        .parent         = &clk_hclkd1,
 193};
 194
 195int s5p6442_clk_ip0_ctrl(struct clk *clk, int enable)
 196{
 197        return s5p_gatectrl(S5P_CLKGATE_IP0, clk, enable);
 198}
 199
 200int s5p6442_clk_ip3_ctrl(struct clk *clk, int enable)
 201{
 202        return s5p_gatectrl(S5P_CLKGATE_IP3, clk, enable);
 203}
 204
 205static struct clksrc_clk clksrcs[] = {
 206        {
 207                .clk    = {
 208                        .name           = "dout_a2m",
 209                        .id             = -1,
 210                        .parent         = &clk_mout_apll.clk,
 211                },
 212                .sources = &clk_src_apll,
 213                .reg_src = { .reg = S5P_CLK_SRC0, .shift = 0, .size = 1 },
 214                .reg_div = { .reg = S5P_CLK_DIV0, .shift = 4, .size = 3 },
 215        }, {
 216                .clk    = {
 217                        .name           = "dout_apll",
 218                        .id             = -1,
 219                        .parent         = &clk_mout_arm.clk,
 220                },
 221                .sources = &clk_src_arm,
 222                .reg_src = { .reg = S5P_CLK_MUX_STAT0, .shift = 16, .size = 3 },
 223                .reg_div = { .reg = S5P_CLK_DIV0, .shift = 0, .size = 3 },
 224        }, {
 225                .clk    = {
 226                        .name           = "hclkd1",
 227                        .id             = -1,
 228                        .parent         = &clk_mout_d1sync.clk,
 229                },
 230                .sources = &clk_src_d1sync,
 231                .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
 232                .reg_div = { .reg = S5P_CLK_DIV0, .shift = 24, .size = 4 },
 233        }, {
 234                .clk    = {
 235                        .name           = "hclkd0",
 236                        .id             = -1,
 237                        .parent         = &clk_mout_d0sync.clk,
 238                },
 239                .sources = &clk_src_d0sync,
 240                .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
 241                .reg_div = { .reg = S5P_CLK_DIV0, .shift = 16, .size = 4 },
 242        }, {
 243                .clk    = {
 244                        .name           = "pclkd0",
 245                        .id             = -1,
 246                        .parent         = &clk_hclkd0,
 247                },
 248                .sources = &clk_src_d0sync,
 249                .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 28, .size = 3 },
 250                .reg_div = { .reg = S5P_CLK_DIV0, .shift = 20, .size = 3 },
 251        }, {
 252                .clk    = {
 253                        .name           = "pclkd1",
 254                        .id             = -1,
 255                        .parent         = &clk_hclkd1,
 256                },
 257                .sources = &clk_src_d1sync,
 258                .reg_src = { .reg = S5P_CLK_MUX_STAT1, .shift = 24, .size = 3 },
 259                .reg_div = { .reg = S5P_CLK_DIV0, .shift = 28, .size = 3 },
 260        }
 261};
 262
 263/* Clock initialisation code */
 264static struct clksrc_clk *init_parents[] = {
 265        &clk_mout_apll,
 266        &clk_mout_mpll,
 267        &clk_mout_epll,
 268        &clk_mout_arm,
 269        &clk_mout_d0,
 270        &clk_mout_d0sync,
 271        &clk_mout_d1,
 272        &clk_mout_d1sync,
 273};
 274
 275void __init_or_cpufreq s5p6442_setup_clocks(void)
 276{
 277        struct clk *pclkd0_clk;
 278        struct clk *pclkd1_clk;
 279
 280        unsigned long xtal;
 281        unsigned long arm;
 282        unsigned long hclkd0 = 0;
 283        unsigned long hclkd1 = 0;
 284        unsigned long pclkd0 = 0;
 285        unsigned long pclkd1 = 0;
 286
 287        unsigned long apll;
 288        unsigned long mpll;
 289        unsigned long epll;
 290        unsigned int ptr;
 291
 292        printk(KERN_DEBUG "%s: registering clocks\n", __func__);
 293
 294        xtal = clk_get_rate(&clk_xtal);
 295
 296        printk(KERN_DEBUG "%s: xtal is %ld\n", __func__, xtal);
 297
 298        apll = s5p_get_pll45xx(xtal, __raw_readl(S5P_APLL_CON), pll_4508);
 299        mpll = s5p_get_pll45xx(xtal, __raw_readl(S5P_MPLL_CON), pll_4502);
 300        epll = s5p_get_pll45xx(xtal, __raw_readl(S5P_EPLL_CON), pll_4500);
 301
 302        printk(KERN_INFO "S5P6442: PLL settings, A=%ld, M=%ld, E=%ld",
 303                        apll, mpll, epll);
 304
 305        clk_fout_apll.rate = apll;
 306        clk_fout_mpll.rate = mpll;
 307        clk_fout_epll.rate = epll;
 308
 309        for (ptr = 0; ptr < ARRAY_SIZE(init_parents); ptr++)
 310                s3c_set_clksrc(init_parents[ptr], true);
 311
 312        for (ptr = 0; ptr < ARRAY_SIZE(clksrcs); ptr++)
 313                s3c_set_clksrc(&clksrcs[ptr], true);
 314
 315        arm = clk_get_rate(&clk_dout_apll);
 316        hclkd0 = clk_get_rate(&clk_hclkd0);
 317        hclkd1 = clk_get_rate(&clk_hclkd1);
 318
 319        pclkd0_clk = clk_get(NULL, "pclkd0");
 320        BUG_ON(IS_ERR(pclkd0_clk));
 321
 322        pclkd0 = clk_get_rate(pclkd0_clk);
 323        clk_put(pclkd0_clk);
 324
 325        pclkd1_clk = clk_get(NULL, "pclkd1");
 326        BUG_ON(IS_ERR(pclkd1_clk));
 327
 328        pclkd1 = clk_get_rate(pclkd1_clk);
 329        clk_put(pclkd1_clk);
 330
 331        printk(KERN_INFO "S5P6442: HCLKD0=%ld, HCLKD1=%ld, PCLKD0=%ld, PCLKD1=%ld\n",
 332                        hclkd0, hclkd1, pclkd0, pclkd1);
 333
 334        /* For backward compatibility */
 335        clk_f.rate = arm;
 336        clk_h.rate = hclkd1;
 337        clk_p.rate = pclkd1;
 338
 339        clk_pclkd0.rate = pclkd0;
 340        clk_pclkd1.rate = pclkd1;
 341}
 342
 343static struct clk init_clocks_off[] = {
 344        {
 345                .name           = "pdma",
 346                .id             = -1,
 347                .parent         = &clk_pclkd1,
 348                .enable         = s5p6442_clk_ip0_ctrl,
 349                .ctrlbit        = (1 << 3),
 350        },
 351};
 352
 353static struct clk init_clocks[] = {
 354        {
 355                .name           = "systimer",
 356                .id             = -1,
 357                .parent         = &clk_pclkd1,
 358                .enable         = s5p6442_clk_ip3_ctrl,
 359                .ctrlbit        = (1<<16),
 360        }, {
 361                .name           = "uart",
 362                .id             = 0,
 363                .parent         = &clk_pclkd1,
 364                .enable         = s5p6442_clk_ip3_ctrl,
 365                .ctrlbit        = (1<<17),
 366        }, {
 367                .name           = "uart",
 368                .id             = 1,
 369                .parent         = &clk_pclkd1,
 370                .enable         = s5p6442_clk_ip3_ctrl,
 371                .ctrlbit        = (1<<18),
 372        }, {
 373                .name           = "uart",
 374                .id             = 2,
 375                .parent         = &clk_pclkd1,
 376                .enable         = s5p6442_clk_ip3_ctrl,
 377                .ctrlbit        = (1<<19),
 378        }, {
 379                .name           = "watchdog",
 380                .id             = -1,
 381                .parent         = &clk_pclkd1,
 382                .enable         = s5p6442_clk_ip3_ctrl,
 383                .ctrlbit        = (1 << 22),
 384        }, {
 385                .name           = "timers",
 386                .id             = -1,
 387                .parent         = &clk_pclkd1,
 388                .enable         = s5p6442_clk_ip3_ctrl,
 389                .ctrlbit        = (1<<23),
 390        },
 391};
 392
 393static struct clk *clks[] __initdata = {
 394        &clk_ext,
 395        &clk_epll,
 396        &clk_mout_apll.clk,
 397        &clk_mout_mpll.clk,
 398        &clk_mout_epll.clk,
 399        &clk_mout_d0.clk,
 400        &clk_mout_d0sync.clk,
 401        &clk_mout_d1.clk,
 402        &clk_mout_d1sync.clk,
 403        &clk_hclkd0,
 404        &clk_pclkd0,
 405        &clk_hclkd1,
 406        &clk_pclkd1,
 407};
 408
 409void __init s5p6442_register_clocks(void)
 410{
 411        s3c24xx_register_clocks(clks, ARRAY_SIZE(clks));
 412
 413        s3c_register_clksrc(clksrcs, ARRAY_SIZE(clksrcs));
 414        s3c_register_clocks(init_clocks, ARRAY_SIZE(init_clocks));
 415
 416        s3c_register_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 417        s3c_disable_clocks(init_clocks_off, ARRAY_SIZE(init_clocks_off));
 418
 419        s3c_pwmclk_init();
 420}
 421