linux/arch/arm/mach-s3c2443/clock.c
<<
>>
Prefs
   1/* linux/arch/arm/mach-s3c2443/clock.c
   2 *
   3 * Copyright (c) 2007 Simtec Electronics
   4 *      Ben Dooks <ben@simtec.co.uk>
   5 *
   6 * S3C2443 Clock control 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 as published by
  10 * the Free Software Foundation; either version 2 of the License, or
  11 * (at your option) any later version.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 *
  18 * You should have received a copy of the GNU General Public License
  19 * along with this program; if not, write to the Free Software
  20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  21*/
  22
  23#include <linux/init.h>
  24#include <linux/module.h>
  25#include <linux/kernel.h>
  26#include <linux/list.h>
  27#include <linux/errno.h>
  28#include <linux/err.h>
  29#include <linux/sysdev.h>
  30#include <linux/clk.h>
  31#include <linux/mutex.h>
  32#include <linux/serial_core.h>
  33#include <linux/io.h>
  34
  35#include <asm/mach/map.h>
  36
  37#include <mach/hardware.h>
  38
  39#include <mach/regs-s3c2443-clock.h>
  40
  41#include <plat/cpu-freq.h>
  42
  43#include <plat/s3c2443.h>
  44#include <plat/clock.h>
  45#include <plat/cpu.h>
  46
  47/* We currently have to assume that the system is running
  48 * from the XTPll input, and that all ***REFCLKs are being
  49 * fed from it, as we cannot read the state of OM[4] from
  50 * software.
  51 *
  52 * It would be possible for each board initialisation to
  53 * set the correct muxing at initialisation
  54*/
  55
  56static int s3c2443_clkcon_enable_h(struct clk *clk, int enable)
  57{
  58        unsigned int clocks = clk->ctrlbit;
  59        unsigned long clkcon;
  60
  61        clkcon = __raw_readl(S3C2443_HCLKCON);
  62
  63        if (enable)
  64                clkcon |= clocks;
  65        else
  66                clkcon &= ~clocks;
  67
  68        __raw_writel(clkcon, S3C2443_HCLKCON);
  69
  70        return 0;
  71}
  72
  73static int s3c2443_clkcon_enable_p(struct clk *clk, int enable)
  74{
  75        unsigned int clocks = clk->ctrlbit;
  76        unsigned long clkcon;
  77
  78        clkcon = __raw_readl(S3C2443_PCLKCON);
  79
  80        if (enable)
  81                clkcon |= clocks;
  82        else
  83                clkcon &= ~clocks;
  84
  85        __raw_writel(clkcon, S3C2443_PCLKCON);
  86
  87        return 0;
  88}
  89
  90static int s3c2443_clkcon_enable_s(struct clk *clk, int enable)
  91{
  92        unsigned int clocks = clk->ctrlbit;
  93        unsigned long clkcon;
  94
  95        clkcon = __raw_readl(S3C2443_SCLKCON);
  96
  97        if (enable)
  98                clkcon |= clocks;
  99        else
 100                clkcon &= ~clocks;
 101
 102        __raw_writel(clkcon, S3C2443_SCLKCON);
 103
 104        return 0;
 105}
 106
 107static unsigned long s3c2443_roundrate_clksrc(struct clk *clk,
 108                                              unsigned long rate,
 109                                              unsigned int max)
 110{
 111        unsigned long parent_rate = clk_get_rate(clk->parent);
 112        int div;
 113
 114        if (rate > parent_rate)
 115                return parent_rate;
 116
 117        /* note, we remove the +/- 1 calculations as they cancel out */
 118
 119        div = (rate / parent_rate);
 120
 121        if (div < 1)
 122                div = 1;
 123        else if (div > max)
 124                div = max;
 125
 126        return parent_rate / div;
 127}
 128
 129static unsigned long s3c2443_roundrate_clksrc4(struct clk *clk,
 130                                               unsigned long rate)
 131{
 132        return s3c2443_roundrate_clksrc(clk, rate, 4);
 133}
 134
 135static unsigned long s3c2443_roundrate_clksrc16(struct clk *clk,
 136                                                unsigned long rate)
 137{
 138        return s3c2443_roundrate_clksrc(clk, rate, 16);
 139}
 140
 141static unsigned long s3c2443_roundrate_clksrc256(struct clk *clk,
 142                                                 unsigned long rate)
 143{
 144        return s3c2443_roundrate_clksrc(clk, rate, 256);
 145}
 146
 147/* clock selections */
 148
 149static struct clk clk_mpllref = {
 150        .name           = "mpllref",
 151        .parent         = &clk_xtal,
 152        .id             = -1,
 153};
 154
 155#if 0
 156static struct clk clk_mpll = {
 157        .name           = "mpll",
 158        .parent         = &clk_mpllref,
 159        .id             = -1,
 160};
 161#endif
 162
 163static struct clk clk_i2s_ext = {
 164        .name           = "i2s-ext",
 165        .id             = -1,
 166};
 167
 168static int s3c2443_setparent_epllref(struct clk *clk, struct clk *parent)
 169{
 170        unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
 171
 172        clksrc &= ~S3C2443_CLKSRC_EPLLREF_MASK;
 173
 174        if (parent == &clk_xtal)
 175                clksrc |= S3C2443_CLKSRC_EPLLREF_XTAL;
 176        else if (parent == &clk_ext)
 177                clksrc |= S3C2443_CLKSRC_EPLLREF_EXTCLK;
 178        else if (parent != &clk_mpllref)
 179                return -EINVAL;
 180
 181        __raw_writel(clksrc, S3C2443_CLKSRC);
 182        clk->parent = parent;
 183
 184        return 0;
 185}
 186
 187static struct clk clk_epllref = {
 188        .name           = "epllref",
 189        .id             = -1,
 190        .set_parent     = s3c2443_setparent_epllref,
 191};
 192
 193static unsigned long s3c2443_getrate_mdivclk(struct clk *clk)
 194{
 195        unsigned long parent_rate = clk_get_rate(clk->parent);
 196        unsigned long div = __raw_readl(S3C2443_CLKDIV0);
 197
 198        div  &= S3C2443_CLKDIV0_EXTDIV_MASK;
 199        div >>= (S3C2443_CLKDIV0_EXTDIV_SHIFT-1);       /* x2 */
 200
 201        return parent_rate / (div + 1);
 202}
 203
 204static struct clk clk_mdivclk = {
 205        .name           = "mdivclk",
 206        .parent         = &clk_mpllref,
 207        .id             = -1,
 208        .get_rate       = s3c2443_getrate_mdivclk,
 209};
 210
 211static int s3c2443_setparent_msysclk(struct clk *clk, struct clk *parent)
 212{
 213        unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
 214
 215        clksrc &= ~(S3C2443_CLKSRC_MSYSCLK_MPLL |
 216                    S3C2443_CLKSRC_EXTCLK_DIV);
 217
 218        if (parent == &clk_mpll)
 219                clksrc |= S3C2443_CLKSRC_MSYSCLK_MPLL;
 220        else if (parent == &clk_mdivclk)
 221                clksrc |= S3C2443_CLKSRC_EXTCLK_DIV;
 222        else if (parent != &clk_mpllref)
 223                return -EINVAL;
 224
 225        __raw_writel(clksrc, S3C2443_CLKSRC);
 226        clk->parent = parent;
 227
 228        return 0;
 229}
 230
 231static struct clk clk_msysclk = {
 232        .name           = "msysclk",
 233        .parent         = &clk_xtal,
 234        .id             = -1,
 235        .set_parent     = s3c2443_setparent_msysclk,
 236};
 237
 238/* armdiv
 239 *
 240 * this clock is sourced from msysclk and can have a number of
 241 * divider values applied to it to then be fed into armclk.
 242*/
 243
 244static struct clk clk_armdiv = {
 245        .name           = "armdiv",
 246        .id             = -1,
 247        .parent         = &clk_msysclk,
 248};
 249
 250/* armclk
 251 *
 252 * this is the clock fed into the ARM core itself, either from
 253 * armdiv or from hclk.
 254 */
 255
 256static int s3c2443_setparent_armclk(struct clk *clk, struct clk *parent)
 257{
 258        unsigned long clkdiv0;
 259
 260        clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
 261
 262        if (parent == &clk_armdiv)
 263                clkdiv0 &= ~S3C2443_CLKDIV0_DVS;
 264        else if (parent == &clk_h)
 265                clkdiv0 |= S3C2443_CLKDIV0_DVS;
 266        else
 267                return -EINVAL;
 268
 269        __raw_writel(clkdiv0, S3C2443_CLKDIV0);
 270        return 0;
 271}
 272
 273static struct clk clk_arm = {
 274        .name           = "armclk",
 275        .id             = -1,
 276        .set_parent     = s3c2443_setparent_armclk,
 277};
 278
 279/* esysclk
 280 *
 281 * this is sourced from either the EPLL or the EPLLref clock
 282*/
 283
 284static int s3c2443_setparent_esysclk(struct clk *clk, struct clk *parent)
 285{
 286        unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
 287
 288        if (parent == &clk_epll)
 289                clksrc |= S3C2443_CLKSRC_ESYSCLK_EPLL;
 290        else if (parent == &clk_epllref)
 291                clksrc &= ~S3C2443_CLKSRC_ESYSCLK_EPLL;
 292        else
 293                return -EINVAL;
 294
 295        __raw_writel(clksrc, S3C2443_CLKSRC);
 296        clk->parent = parent;
 297
 298        return 0;
 299}
 300
 301static struct clk clk_esysclk = {
 302        .name           = "esysclk",
 303        .parent         = &clk_epll,
 304        .id             = -1,
 305        .set_parent     = s3c2443_setparent_esysclk,
 306};
 307
 308/* uartclk
 309 *
 310 * UART baud-rate clock sourced from esysclk via a divisor
 311*/
 312
 313static unsigned long s3c2443_getrate_uart(struct clk *clk)
 314{
 315        unsigned long parent_rate = clk_get_rate(clk->parent);
 316        unsigned long div = __raw_readl(S3C2443_CLKDIV1);
 317
 318        div &= S3C2443_CLKDIV1_UARTDIV_MASK;
 319        div >>= S3C2443_CLKDIV1_UARTDIV_SHIFT;
 320
 321        return parent_rate / (div + 1);
 322}
 323
 324
 325static int s3c2443_setrate_uart(struct clk *clk, unsigned long rate)
 326{
 327        unsigned long parent_rate = clk_get_rate(clk->parent);
 328        unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
 329
 330        rate = s3c2443_roundrate_clksrc16(clk, rate);
 331        rate = parent_rate / rate;
 332
 333        clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
 334        clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
 335
 336        __raw_writel(clkdivn, S3C2443_CLKDIV1);
 337        return 0;
 338}
 339
 340static struct clk clk_uart = {
 341        .name           = "uartclk",
 342        .id             = -1,
 343        .parent         = &clk_esysclk,
 344        .get_rate       = s3c2443_getrate_uart,
 345        .set_rate       = s3c2443_setrate_uart,
 346        .round_rate     = s3c2443_roundrate_clksrc16,
 347};
 348
 349/* hsspi
 350 *
 351 * high-speed spi clock, sourced from esysclk
 352*/
 353
 354static unsigned long s3c2443_getrate_hsspi(struct clk *clk)
 355{
 356        unsigned long parent_rate = clk_get_rate(clk->parent);
 357        unsigned long div = __raw_readl(S3C2443_CLKDIV1);
 358
 359        div &= S3C2443_CLKDIV1_HSSPIDIV_MASK;
 360        div >>= S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
 361
 362        return parent_rate / (div + 1);
 363}
 364
 365
 366static int s3c2443_setrate_hsspi(struct clk *clk, unsigned long rate)
 367{
 368        unsigned long parent_rate = clk_get_rate(clk->parent);
 369        unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
 370
 371        rate = s3c2443_roundrate_clksrc4(clk, rate);
 372        rate = parent_rate / rate;
 373
 374        clkdivn &= ~S3C2443_CLKDIV1_HSSPIDIV_MASK;
 375        clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSSPIDIV_SHIFT;
 376
 377        __raw_writel(clkdivn, S3C2443_CLKDIV1);
 378        return 0;
 379}
 380
 381static struct clk clk_hsspi = {
 382        .name           = "hsspi",
 383        .id             = -1,
 384        .parent         = &clk_esysclk,
 385        .ctrlbit        = S3C2443_SCLKCON_HSSPICLK,
 386        .enable         = s3c2443_clkcon_enable_s,
 387        .get_rate       = s3c2443_getrate_hsspi,
 388        .set_rate       = s3c2443_setrate_hsspi,
 389        .round_rate     = s3c2443_roundrate_clksrc4,
 390};
 391
 392/* usbhost
 393 *
 394 * usb host bus-clock, usually 48MHz to provide USB bus clock timing
 395*/
 396
 397static unsigned long s3c2443_getrate_usbhost(struct clk *clk)
 398{
 399        unsigned long parent_rate = clk_get_rate(clk->parent);
 400        unsigned long div = __raw_readl(S3C2443_CLKDIV1);
 401
 402        div &= S3C2443_CLKDIV1_USBHOSTDIV_MASK;
 403        div >>= S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
 404
 405        return parent_rate / (div + 1);
 406}
 407
 408static int s3c2443_setrate_usbhost(struct clk *clk, unsigned long rate)
 409{
 410        unsigned long parent_rate = clk_get_rate(clk->parent);
 411        unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
 412
 413        rate = s3c2443_roundrate_clksrc4(clk, rate);
 414        rate = parent_rate / rate;
 415
 416        clkdivn &= ~S3C2443_CLKDIV1_USBHOSTDIV_MASK;
 417        clkdivn |= (rate - 1) << S3C2443_CLKDIV1_USBHOSTDIV_SHIFT;
 418
 419        __raw_writel(clkdivn, S3C2443_CLKDIV1);
 420        return 0;
 421}
 422
 423static struct clk clk_usb_bus_host = {
 424        .name           = "usb-bus-host-parent",
 425        .id             = -1,
 426        .parent         = &clk_esysclk,
 427        .ctrlbit        = S3C2443_SCLKCON_USBHOST,
 428        .enable         = s3c2443_clkcon_enable_s,
 429        .get_rate       = s3c2443_getrate_usbhost,
 430        .set_rate       = s3c2443_setrate_usbhost,
 431        .round_rate     = s3c2443_roundrate_clksrc4,
 432};
 433
 434/* clk_hsmcc_div
 435 *
 436 * this clock is sourced from epll, and is fed through a divider,
 437 * to a mux controlled by sclkcon where either it or a extclk can
 438 * be fed to the hsmmc block
 439*/
 440
 441static unsigned long s3c2443_getrate_hsmmc_div(struct clk *clk)
 442{
 443        unsigned long parent_rate = clk_get_rate(clk->parent);
 444        unsigned long div = __raw_readl(S3C2443_CLKDIV1);
 445
 446        div &= S3C2443_CLKDIV1_HSMMCDIV_MASK;
 447        div >>= S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
 448
 449        return parent_rate / (div + 1);
 450}
 451
 452static int s3c2443_setrate_hsmmc_div(struct clk *clk, unsigned long rate)
 453{
 454        unsigned long parent_rate = clk_get_rate(clk->parent);
 455        unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
 456
 457        rate = s3c2443_roundrate_clksrc4(clk, rate);
 458        rate = parent_rate / rate;
 459
 460        clkdivn &= ~S3C2443_CLKDIV1_HSMMCDIV_MASK;
 461        clkdivn |= (rate - 1) << S3C2443_CLKDIV1_HSMMCDIV_SHIFT;
 462
 463        __raw_writel(clkdivn, S3C2443_CLKDIV1);
 464        return 0;
 465}
 466
 467static struct clk clk_hsmmc_div = {
 468        .name           = "hsmmc-div",
 469        .id             = -1,
 470        .parent         = &clk_esysclk,
 471        .get_rate       = s3c2443_getrate_hsmmc_div,
 472        .set_rate       = s3c2443_setrate_hsmmc_div,
 473        .round_rate     = s3c2443_roundrate_clksrc4,
 474};
 475
 476static int s3c2443_setparent_hsmmc(struct clk *clk, struct clk *parent)
 477{
 478        unsigned long clksrc = __raw_readl(S3C2443_SCLKCON);
 479
 480        clksrc &= ~(S3C2443_SCLKCON_HSMMCCLK_EXT |
 481                    S3C2443_SCLKCON_HSMMCCLK_EPLL);
 482
 483        if (parent == &clk_epll)
 484                clksrc |= S3C2443_SCLKCON_HSMMCCLK_EPLL;
 485        else if (parent == &clk_ext)
 486                clksrc |= S3C2443_SCLKCON_HSMMCCLK_EXT;
 487        else
 488                return -EINVAL;
 489
 490        if (clk->usage > 0) {
 491                __raw_writel(clksrc, S3C2443_SCLKCON);
 492        }
 493
 494        clk->parent = parent;
 495        return 0;
 496}
 497
 498static int s3c2443_enable_hsmmc(struct clk *clk, int enable)
 499{
 500        return s3c2443_setparent_hsmmc(clk, clk->parent);
 501}
 502
 503static struct clk clk_hsmmc = {
 504        .name           = "hsmmc-if",
 505        .id             = -1,
 506        .parent         = &clk_hsmmc_div,
 507        .enable         = s3c2443_enable_hsmmc,
 508        .set_parent     = s3c2443_setparent_hsmmc,
 509};
 510
 511/* i2s_eplldiv
 512 *
 513 * this clock is the output from the i2s divisor of esysclk
 514*/
 515
 516static unsigned long s3c2443_getrate_i2s_eplldiv(struct clk *clk)
 517{
 518        unsigned long parent_rate = clk_get_rate(clk->parent);
 519        unsigned long div = __raw_readl(S3C2443_CLKDIV1);
 520
 521        div &= S3C2443_CLKDIV1_I2SDIV_MASK;
 522        div >>= S3C2443_CLKDIV1_I2SDIV_SHIFT;
 523
 524        return parent_rate / (div + 1);
 525}
 526
 527static int s3c2443_setrate_i2s_eplldiv(struct clk *clk, unsigned long rate)
 528{
 529        unsigned long parent_rate = clk_get_rate(clk->parent);
 530        unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
 531
 532        rate = s3c2443_roundrate_clksrc16(clk, rate);
 533        rate = parent_rate / rate;
 534
 535        clkdivn &= ~S3C2443_CLKDIV1_I2SDIV_MASK;
 536        clkdivn |= (rate - 1) << S3C2443_CLKDIV1_I2SDIV_SHIFT;
 537
 538        __raw_writel(clkdivn, S3C2443_CLKDIV1);
 539        return 0;
 540}
 541
 542static struct clk clk_i2s_eplldiv = {
 543        .name           = "i2s-eplldiv",
 544        .id             = -1,
 545        .parent         = &clk_esysclk,
 546        .get_rate       = s3c2443_getrate_i2s_eplldiv,
 547        .set_rate       = s3c2443_setrate_i2s_eplldiv,
 548        .round_rate     = s3c2443_roundrate_clksrc16,
 549};
 550
 551/* i2s-ref
 552 *
 553 * i2s bus reference clock, selectable from external, esysclk or epllref
 554*/
 555
 556static int s3c2443_setparent_i2s(struct clk *clk, struct clk *parent)
 557{
 558        unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
 559
 560        clksrc &= ~S3C2443_CLKSRC_I2S_MASK;
 561
 562        if (parent == &clk_epllref)
 563                clksrc |= S3C2443_CLKSRC_I2S_EPLLREF;
 564        else if (parent == &clk_i2s_ext)
 565                clksrc |= S3C2443_CLKSRC_I2S_EXT;
 566        else if (parent != &clk_i2s_eplldiv)
 567                return -EINVAL;
 568
 569        clk->parent = parent;
 570        __raw_writel(clksrc, S3C2443_CLKSRC);
 571
 572        return 0;
 573}
 574
 575static struct clk clk_i2s = {
 576        .name           = "i2s-if",
 577        .id             = -1,
 578        .parent         = &clk_i2s_eplldiv,
 579        .ctrlbit        = S3C2443_SCLKCON_I2SCLK,
 580        .enable         = s3c2443_clkcon_enable_s,
 581        .set_parent     = s3c2443_setparent_i2s,
 582};
 583
 584/* cam-if
 585 *
 586 * camera interface bus-clock, divided down from esysclk
 587*/
 588
 589static unsigned long s3c2443_getrate_cam(struct clk *clk)
 590{
 591        unsigned long parent_rate = clk_get_rate(clk->parent);
 592        unsigned long div = __raw_readl(S3C2443_CLKDIV1);
 593
 594        div  &= S3C2443_CLKDIV1_CAMDIV_MASK;
 595        div >>= S3C2443_CLKDIV1_CAMDIV_SHIFT;
 596
 597        return parent_rate / (div + 1);
 598}
 599
 600static int s3c2443_setrate_cam(struct clk *clk, unsigned long rate)
 601{
 602        unsigned long parent_rate = clk_get_rate(clk->parent);
 603        unsigned long clkdiv1 = __raw_readl(S3C2443_CLKDIV1);
 604
 605        rate = s3c2443_roundrate_clksrc16(clk, rate);
 606        rate = parent_rate / rate;
 607
 608        clkdiv1 &= ~S3C2443_CLKDIV1_CAMDIV_MASK;
 609        clkdiv1 |= (rate - 1) << S3C2443_CLKDIV1_CAMDIV_SHIFT;
 610
 611        __raw_writel(clkdiv1, S3C2443_CLKDIV1);
 612        return 0;
 613}
 614
 615static struct clk clk_cam = {
 616        .name           = "camif-upll",         /* same as 2440 name */
 617        .id             = -1,
 618        .parent         = &clk_esysclk,
 619        .ctrlbit        = S3C2443_SCLKCON_CAMCLK,
 620        .enable         = s3c2443_clkcon_enable_s,
 621        .get_rate       = s3c2443_getrate_cam,
 622        .set_rate       = s3c2443_setrate_cam,
 623        .round_rate     = s3c2443_roundrate_clksrc16,
 624};
 625
 626/* display-if
 627 *
 628 * display interface clock, divided from esysclk
 629*/
 630
 631static unsigned long s3c2443_getrate_display(struct clk *clk)
 632{
 633        unsigned long parent_rate = clk_get_rate(clk->parent);
 634        unsigned long div = __raw_readl(S3C2443_CLKDIV1);
 635
 636        div &= S3C2443_CLKDIV1_DISPDIV_MASK;
 637        div >>= S3C2443_CLKDIV1_DISPDIV_SHIFT;
 638
 639        return parent_rate / (div + 1);
 640}
 641
 642static int s3c2443_setrate_display(struct clk *clk, unsigned long rate)
 643{
 644        unsigned long parent_rate = clk_get_rate(clk->parent);
 645        unsigned long clkdivn = __raw_readl(S3C2443_CLKDIV1);
 646
 647        rate = s3c2443_roundrate_clksrc256(clk, rate);
 648        rate = parent_rate / rate;
 649
 650        clkdivn &= ~S3C2443_CLKDIV1_UARTDIV_MASK;
 651        clkdivn |= (rate - 1) << S3C2443_CLKDIV1_UARTDIV_SHIFT;
 652
 653        __raw_writel(clkdivn, S3C2443_CLKDIV1);
 654        return 0;
 655}
 656
 657static struct clk clk_display = {
 658        .name           = "display-if",
 659        .id             = -1,
 660        .parent         = &clk_esysclk,
 661        .ctrlbit        = S3C2443_SCLKCON_DISPCLK,
 662        .enable         = s3c2443_clkcon_enable_s,
 663        .get_rate       = s3c2443_getrate_display,
 664        .set_rate       = s3c2443_setrate_display,
 665        .round_rate     = s3c2443_roundrate_clksrc256,
 666};
 667
 668/* prediv
 669 *
 670 * this divides the msysclk down to pass to h/p/etc.
 671 */
 672
 673static unsigned long s3c2443_prediv_getrate(struct clk *clk)
 674{
 675        unsigned long rate = clk_get_rate(clk->parent);
 676        unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
 677
 678        clkdiv0 &= S3C2443_CLKDIV0_PREDIV_MASK;
 679        clkdiv0 >>= S3C2443_CLKDIV0_PREDIV_SHIFT;
 680
 681        return rate / (clkdiv0 + 1);
 682}
 683
 684static struct clk clk_prediv = {
 685        .name           = "prediv",
 686        .id             = -1,
 687        .parent         = &clk_msysclk,
 688        .get_rate       = s3c2443_prediv_getrate,
 689};
 690
 691/* standard clock definitions */
 692
 693static struct clk init_clocks_disable[] = {
 694        {
 695                .name           = "nand",
 696                .id             = -1,
 697                .parent         = &clk_h,
 698        }, {
 699                .name           = "sdi",
 700                .id             = -1,
 701                .parent         = &clk_p,
 702                .enable         = s3c2443_clkcon_enable_p,
 703                .ctrlbit        = S3C2443_PCLKCON_SDI,
 704        }, {
 705                .name           = "adc",
 706                .id             = -1,
 707                .parent         = &clk_p,
 708                .enable         = s3c2443_clkcon_enable_p,
 709                .ctrlbit        = S3C2443_PCLKCON_ADC,
 710        }, {
 711                .name           = "i2c",
 712                .id             = -1,
 713                .parent         = &clk_p,
 714                .enable         = s3c2443_clkcon_enable_p,
 715                .ctrlbit        = S3C2443_PCLKCON_IIC,
 716        }, {
 717                .name           = "iis",
 718                .id             = -1,
 719                .parent         = &clk_p,
 720                .enable         = s3c2443_clkcon_enable_p,
 721                .ctrlbit        = S3C2443_PCLKCON_IIS,
 722        }, {
 723                .name           = "spi",
 724                .id             = 0,
 725                .parent         = &clk_p,
 726                .enable         = s3c2443_clkcon_enable_p,
 727                .ctrlbit        = S3C2443_PCLKCON_SPI0,
 728        }, {
 729                .name           = "spi",
 730                .id             = 1,
 731                .parent         = &clk_p,
 732                .enable         = s3c2443_clkcon_enable_p,
 733                .ctrlbit        = S3C2443_PCLKCON_SPI1,
 734        }
 735};
 736
 737static struct clk init_clocks[] = {
 738        {
 739                .name           = "dma",
 740                .id             = 0,
 741                .parent         = &clk_h,
 742                .enable         = s3c2443_clkcon_enable_h,
 743                .ctrlbit        = S3C2443_HCLKCON_DMA0,
 744        }, {
 745                .name           = "dma",
 746                .id             = 1,
 747                .parent         = &clk_h,
 748                .enable         = s3c2443_clkcon_enable_h,
 749                .ctrlbit        = S3C2443_HCLKCON_DMA1,
 750        }, {
 751                .name           = "dma",
 752                .id             = 2,
 753                .parent         = &clk_h,
 754                .enable         = s3c2443_clkcon_enable_h,
 755                .ctrlbit        = S3C2443_HCLKCON_DMA2,
 756        }, {
 757                .name           = "dma",
 758                .id             = 3,
 759                .parent         = &clk_h,
 760                .enable         = s3c2443_clkcon_enable_h,
 761                .ctrlbit        = S3C2443_HCLKCON_DMA3,
 762        }, {
 763                .name           = "dma",
 764                .id             = 4,
 765                .parent         = &clk_h,
 766                .enable         = s3c2443_clkcon_enable_h,
 767                .ctrlbit        = S3C2443_HCLKCON_DMA4,
 768        }, {
 769                .name           = "dma",
 770                .id             = 5,
 771                .parent         = &clk_h,
 772                .enable         = s3c2443_clkcon_enable_h,
 773                .ctrlbit        = S3C2443_HCLKCON_DMA5,
 774        }, {
 775                .name           = "lcd",
 776                .id             = -1,
 777                .parent         = &clk_h,
 778                .enable         = s3c2443_clkcon_enable_h,
 779                .ctrlbit        = S3C2443_HCLKCON_LCDC,
 780        }, {
 781                .name           = "gpio",
 782                .id             = -1,
 783                .parent         = &clk_p,
 784                .enable         = s3c2443_clkcon_enable_p,
 785                .ctrlbit        = S3C2443_PCLKCON_GPIO,
 786        }, {
 787                .name           = "usb-host",
 788                .id             = -1,
 789                .parent         = &clk_h,
 790                .enable         = s3c2443_clkcon_enable_h,
 791                .ctrlbit        = S3C2443_HCLKCON_USBH,
 792        }, {
 793                .name           = "usb-device",
 794                .id             = -1,
 795                .parent         = &clk_h,
 796                .enable         = s3c2443_clkcon_enable_h,
 797                .ctrlbit        = S3C2443_HCLKCON_USBD,
 798        }, {
 799                .name           = "hsmmc",
 800                .id             = -1,
 801                .parent         = &clk_h,
 802                .enable         = s3c2443_clkcon_enable_h,
 803                .ctrlbit        = S3C2443_HCLKCON_HSMMC,
 804        }, {
 805                .name           = "cfc",
 806                .id             = -1,
 807                .parent         = &clk_h,
 808                .enable         = s3c2443_clkcon_enable_h,
 809                .ctrlbit        = S3C2443_HCLKCON_CFC,
 810        }, {
 811                .name           = "ssmc",
 812                .id             = -1,
 813                .parent         = &clk_h,
 814                .enable         = s3c2443_clkcon_enable_h,
 815                .ctrlbit        = S3C2443_HCLKCON_SSMC,
 816        }, {
 817                .name           = "timers",
 818                .id             = -1,
 819                .parent         = &clk_p,
 820                .enable         = s3c2443_clkcon_enable_p,
 821                .ctrlbit        = S3C2443_PCLKCON_PWMT,
 822        }, {
 823                .name           = "uart",
 824                .id             = 0,
 825                .parent         = &clk_p,
 826                .enable         = s3c2443_clkcon_enable_p,
 827                .ctrlbit        = S3C2443_PCLKCON_UART0,
 828        }, {
 829                .name           = "uart",
 830                .id             = 1,
 831                .parent         = &clk_p,
 832                .enable         = s3c2443_clkcon_enable_p,
 833                .ctrlbit        = S3C2443_PCLKCON_UART1,
 834        }, {
 835                .name           = "uart",
 836                .id             = 2,
 837                .parent         = &clk_p,
 838                .enable         = s3c2443_clkcon_enable_p,
 839                .ctrlbit        = S3C2443_PCLKCON_UART2,
 840        }, {
 841                .name           = "uart",
 842                .id             = 3,
 843                .parent         = &clk_p,
 844                .enable         = s3c2443_clkcon_enable_p,
 845                .ctrlbit        = S3C2443_PCLKCON_UART3,
 846        }, {
 847                .name           = "rtc",
 848                .id             = -1,
 849                .parent         = &clk_p,
 850                .enable         = s3c2443_clkcon_enable_p,
 851                .ctrlbit        = S3C2443_PCLKCON_RTC,
 852        }, {
 853                .name           = "watchdog",
 854                .id             = -1,
 855                .parent         = &clk_p,
 856                .ctrlbit        = S3C2443_PCLKCON_WDT,
 857        }, {
 858                .name           = "usb-bus-host",
 859                .id             = -1,
 860                .parent         = &clk_usb_bus_host,
 861        }, {
 862                .name           = "ac97",
 863                .id             = -1,
 864                .parent         = &clk_p,
 865                .ctrlbit        = S3C2443_PCLKCON_AC97,
 866        }
 867};
 868
 869/* clocks to add where we need to check their parentage */
 870
 871/* s3c2443_clk_initparents
 872 *
 873 * Initialise the parents for the clocks that we get at start-time
 874*/
 875
 876static int __init clk_init_set_parent(struct clk *clk, struct clk *parent)
 877{
 878        printk(KERN_DEBUG "clock %s: parent %s\n", clk->name, parent->name);
 879        return clk_set_parent(clk, parent);
 880}
 881
 882static void __init s3c2443_clk_initparents(void)
 883{
 884        unsigned long clksrc = __raw_readl(S3C2443_CLKSRC);
 885        struct clk *parent;
 886
 887        switch (clksrc & S3C2443_CLKSRC_EPLLREF_MASK) {
 888        case S3C2443_CLKSRC_EPLLREF_EXTCLK:
 889                parent = &clk_ext;
 890                break;
 891
 892        case S3C2443_CLKSRC_EPLLREF_XTAL:
 893        default:
 894                parent = &clk_xtal;
 895                break;
 896
 897        case S3C2443_CLKSRC_EPLLREF_MPLLREF:
 898        case S3C2443_CLKSRC_EPLLREF_MPLLREF2:
 899                parent = &clk_mpllref;
 900                break;
 901        }
 902
 903        clk_init_set_parent(&clk_epllref, parent);
 904
 905        switch (clksrc & S3C2443_CLKSRC_I2S_MASK) {
 906        case S3C2443_CLKSRC_I2S_EXT:
 907                parent = &clk_i2s_ext;
 908                break;
 909
 910        case S3C2443_CLKSRC_I2S_EPLLDIV:
 911        default:
 912                parent = &clk_i2s_eplldiv;
 913                break;
 914
 915        case S3C2443_CLKSRC_I2S_EPLLREF:
 916        case S3C2443_CLKSRC_I2S_EPLLREF3:
 917                parent = &clk_epllref;
 918        }
 919
 920        clk_init_set_parent(&clk_i2s, &clk_epllref);
 921
 922        /* esysclk source */
 923
 924        parent = (clksrc & S3C2443_CLKSRC_ESYSCLK_EPLL) ?
 925                &clk_epll : &clk_epllref;
 926
 927        clk_init_set_parent(&clk_esysclk, parent);
 928
 929        /* msysclk source */
 930
 931        if (clksrc & S3C2443_CLKSRC_MSYSCLK_MPLL) {
 932                parent = &clk_mpll;
 933        } else {
 934                parent = (clksrc & S3C2443_CLKSRC_EXTCLK_DIV) ?
 935                        &clk_mdivclk : &clk_mpllref;
 936        }
 937
 938        clk_init_set_parent(&clk_msysclk, parent);
 939
 940        /* arm */
 941
 942        if (__raw_readl(S3C2443_CLKDIV0) & S3C2443_CLKDIV0_DVS)
 943                parent = &clk_h;
 944        else
 945                parent = &clk_armdiv;
 946
 947        clk_init_set_parent(&clk_arm, parent);
 948}
 949
 950/* armdiv divisor table */
 951
 952static unsigned int armdiv[16] = {
 953        [S3C2443_CLKDIV0_ARMDIV_1 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 1,
 954        [S3C2443_CLKDIV0_ARMDIV_2 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 2,
 955        [S3C2443_CLKDIV0_ARMDIV_3 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 3,
 956        [S3C2443_CLKDIV0_ARMDIV_4 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 4,
 957        [S3C2443_CLKDIV0_ARMDIV_6 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 6,
 958        [S3C2443_CLKDIV0_ARMDIV_8 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]      = 8,
 959        [S3C2443_CLKDIV0_ARMDIV_12 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 12,
 960        [S3C2443_CLKDIV0_ARMDIV_16 >> S3C2443_CLKDIV0_ARMDIV_SHIFT]     = 16,
 961};
 962
 963static inline unsigned int s3c2443_fclk_div(unsigned long clkcon0)
 964{
 965        clkcon0 &= S3C2443_CLKDIV0_ARMDIV_MASK;
 966
 967        return armdiv[clkcon0 >> S3C2443_CLKDIV0_ARMDIV_SHIFT];
 968}
 969
 970static inline unsigned long s3c2443_get_hdiv(unsigned long clkcon0)
 971{
 972        clkcon0 &= S3C2443_CLKDIV0_HCLKDIV_MASK;
 973
 974        return clkcon0 + 1;
 975}
 976
 977/* clocks to add straight away */
 978
 979static struct clk *clks[] __initdata = {
 980        &clk_ext,
 981        &clk_epll,
 982        &clk_usb_bus_host,
 983        &clk_usb_bus,
 984        &clk_esysclk,
 985        &clk_epllref,
 986        &clk_mpllref,
 987        &clk_msysclk,
 988        &clk_uart,
 989        &clk_display,
 990        &clk_cam,
 991        &clk_i2s_eplldiv,
 992        &clk_i2s,
 993        &clk_hsspi,
 994        &clk_hsmmc_div,
 995        &clk_hsmmc,
 996        &clk_armdiv,
 997        &clk_arm,
 998        &clk_prediv,
 999};
1000
1001void __init_or_cpufreq s3c2443_setup_clocks(void)
1002{
1003        unsigned long mpllcon = __raw_readl(S3C2443_MPLLCON);
1004        unsigned long clkdiv0 = __raw_readl(S3C2443_CLKDIV0);
1005        struct clk *xtal_clk;
1006        unsigned long xtal;
1007        unsigned long pll;
1008        unsigned long fclk;
1009        unsigned long hclk;
1010        unsigned long pclk;
1011
1012        xtal_clk = clk_get(NULL, "xtal");
1013        xtal = clk_get_rate(xtal_clk);
1014        clk_put(xtal_clk);
1015
1016        pll = s3c2443_get_mpll(mpllcon, xtal);
1017        clk_msysclk.rate = pll;
1018
1019        fclk = pll / s3c2443_fclk_div(clkdiv0);
1020        hclk = s3c2443_prediv_getrate(&clk_prediv);
1021        hclk /= s3c2443_get_hdiv(clkdiv0);
1022        pclk = hclk / ((clkdiv0 & S3C2443_CLKDIV0_HALF_PCLK) ? 2 : 1);
1023
1024        s3c24xx_setup_clocks(fclk, hclk, pclk);
1025
1026        printk("S3C2443: mpll %s %ld.%03ld MHz, cpu %ld.%03ld MHz, mem %ld.%03ld MHz, pclk %ld.%03ld MHz\n",
1027               (mpllcon & S3C2443_PLLCON_OFF) ? "off":"on",
1028               print_mhz(pll), print_mhz(fclk),
1029               print_mhz(hclk), print_mhz(pclk));
1030
1031        s3c24xx_setup_clocks(fclk, hclk, pclk);
1032}
1033
1034void __init s3c2443_init_clocks(int xtal)
1035{
1036        struct clk *clkp;
1037        unsigned long epllcon = __raw_readl(S3C2443_EPLLCON);
1038        int ret;
1039        int ptr;
1040
1041        /* s3c2443 parents h and p clocks from prediv */
1042        clk_h.parent = &clk_prediv;
1043        clk_p.parent = &clk_prediv;
1044
1045        s3c24xx_register_baseclocks(xtal);
1046        s3c2443_setup_clocks();
1047        s3c2443_clk_initparents();
1048
1049        for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
1050                clkp = clks[ptr];
1051
1052                ret = s3c24xx_register_clock(clkp);
1053                if (ret < 0) {
1054                        printk(KERN_ERR "Failed to register clock %s (%d)\n",
1055                               clkp->name, ret);
1056                }
1057        }
1058
1059        clk_epll.rate = s3c2443_get_epll(epllcon, xtal);
1060        clk_epll.parent = &clk_epllref;
1061        clk_usb_bus.parent = &clk_usb_bus_host;
1062
1063        /* ensure usb bus clock is within correct rate of 48MHz */
1064
1065        if (clk_get_rate(&clk_usb_bus_host) != (48 * 1000 * 1000)) {
1066                printk(KERN_INFO "Warning: USB host bus not at 48MHz\n");
1067                clk_set_rate(&clk_usb_bus_host, 48*1000*1000);
1068        }
1069
1070        printk("S3C2443: epll %s %ld.%03ld MHz, usb-bus %ld.%03ld MHz\n",
1071               (epllcon & S3C2443_PLLCON_OFF) ? "off":"on",
1072               print_mhz(clk_get_rate(&clk_epll)),
1073               print_mhz(clk_get_rate(&clk_usb_bus)));
1074
1075        /* register clocks from clock array */
1076
1077        clkp = init_clocks;
1078        for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {
1079                ret = s3c24xx_register_clock(clkp);
1080                if (ret < 0) {
1081                        printk(KERN_ERR "Failed to register clock %s (%d)\n",
1082                               clkp->name, ret);
1083                }
1084        }
1085
1086        /* We must be careful disabling the clocks we are not intending to
1087         * be using at boot time, as subsystems such as the LCD which do
1088         * their own DMA requests to the bus can cause the system to lockup
1089         * if they where in the middle of requesting bus access.
1090         *
1091         * Disabling the LCD clock if the LCD is active is very dangerous,
1092         * and therefore the bootloader should be careful to not enable
1093         * the LCD clock if it is not needed.
1094        */
1095
1096        /* install (and disable) the clocks we do not need immediately */
1097
1098        clkp = init_clocks_disable;
1099        for (ptr = 0; ptr < ARRAY_SIZE(init_clocks_disable); ptr++, clkp++) {
1100
1101                ret = s3c24xx_register_clock(clkp);
1102                if (ret < 0) {
1103                        printk(KERN_ERR "Failed to register clock %s (%d)\n",
1104                               clkp->name, ret);
1105                }
1106
1107                (clkp->enable)(clkp, 0);
1108        }
1109
1110        s3c_pwmclk_init();
1111}
1112