linux/arch/arm/mach-mx3/clock.c
<<
>>
Prefs
   1/*
   2 * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
   3 * Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License
   7 * as published by the Free Software Foundation; either version 2
   8 * of the License, or (at your option) any later version.
   9 * This program is distributed in the hope that it will be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write to the Free Software
  16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  17 * MA 02110-1301, USA.
  18 */
  19
  20#include <linux/module.h>
  21#include <linux/spinlock.h>
  22#include <linux/delay.h>
  23#include <linux/clk.h>
  24#include <linux/err.h>
  25#include <linux/io.h>
  26#include <mach/clock.h>
  27#include <asm/div64.h>
  28
  29#include "crm_regs.h"
  30
  31#define PRE_DIV_MIN_FREQ    10000000 /* Minimum Frequency after Predivider */
  32
  33static void __calc_pre_post_dividers(u32 div, u32 *pre, u32 *post)
  34{
  35        u32 min_pre, temp_pre, old_err, err;
  36
  37        if (div >= 512) {
  38                *pre = 8;
  39                *post = 64;
  40        } else if (div >= 64) {
  41                min_pre = (div - 1) / 64 + 1;
  42                old_err = 8;
  43                for (temp_pre = 8; temp_pre >= min_pre; temp_pre--) {
  44                        err = div % temp_pre;
  45                        if (err == 0) {
  46                                *pre = temp_pre;
  47                                break;
  48                        }
  49                        err = temp_pre - err;
  50                        if (err < old_err) {
  51                                old_err = err;
  52                                *pre = temp_pre;
  53                        }
  54                }
  55                *post = (div + *pre - 1) / *pre;
  56        } else if (div <= 8) {
  57                *pre = div;
  58                *post = 1;
  59        } else {
  60                *pre = 1;
  61                *post = div;
  62        }
  63}
  64
  65static struct clk mcu_pll_clk;
  66static struct clk mcu_main_clk;
  67static struct clk usb_pll_clk;
  68static struct clk serial_pll_clk;
  69static struct clk ipg_clk;
  70static struct clk ckih_clk;
  71static struct clk ahb_clk;
  72
  73static int _clk_enable(struct clk *clk)
  74{
  75        u32 reg;
  76
  77        reg = __raw_readl(clk->enable_reg);
  78        reg |= 3 << clk->enable_shift;
  79        __raw_writel(reg, clk->enable_reg);
  80
  81        return 0;
  82}
  83
  84static void _clk_disable(struct clk *clk)
  85{
  86        u32 reg;
  87
  88        reg = __raw_readl(clk->enable_reg);
  89        reg &= ~(3 << clk->enable_shift);
  90        __raw_writel(reg, clk->enable_reg);
  91}
  92
  93static void _clk_emi_disable(struct clk *clk)
  94{
  95        u32 reg;
  96
  97        reg = __raw_readl(clk->enable_reg);
  98        reg &= ~(3 << clk->enable_shift);
  99        reg |= (1 << clk->enable_shift);
 100        __raw_writel(reg, clk->enable_reg);
 101}
 102
 103static int _clk_pll_set_rate(struct clk *clk, unsigned long rate)
 104{
 105        u32 reg;
 106        signed long pd = 1;     /* Pre-divider */
 107        signed long mfi;        /* Multiplication Factor (Integer part) */
 108        signed long mfn;        /* Multiplication Factor (Integer part) */
 109        signed long mfd;        /* Multiplication Factor (Denominator Part) */
 110        signed long tmp;
 111        u32 ref_freq = clk_get_rate(clk->parent);
 112
 113        while (((ref_freq / pd) * 10) > rate)
 114                pd++;
 115
 116        if ((ref_freq / pd) < PRE_DIV_MIN_FREQ)
 117                return -EINVAL;
 118
 119        /* the ref_freq/2 in the following is to round up */
 120        mfi = (((rate / 2) * pd) + (ref_freq / 2)) / ref_freq;
 121        if (mfi < 5 || mfi > 15)
 122                return -EINVAL;
 123
 124        /* pick a mfd value that will work
 125         * then solve for mfn */
 126        mfd = ref_freq / 50000;
 127
 128        /*
 129         *          pll_freq * pd * mfd
 130         *   mfn = --------------------  -  (mfi * mfd)
 131         *           2 * ref_freq
 132         */
 133        /* the tmp/2 is for rounding */
 134        tmp = ref_freq / 10000;
 135        mfn =
 136            ((((((rate / 2) + (tmp / 2)) / tmp) * pd) * mfd) / 10000) -
 137            (mfi * mfd);
 138
 139        mfn = mfn & 0x3ff;
 140        pd--;
 141        mfd--;
 142
 143        /* Change the Pll value */
 144        reg = (mfi << MXC_CCM_PCTL_MFI_OFFSET) |
 145            (mfn << MXC_CCM_PCTL_MFN_OFFSET) |
 146            (mfd << MXC_CCM_PCTL_MFD_OFFSET) | (pd << MXC_CCM_PCTL_PD_OFFSET);
 147
 148        if (clk == &mcu_pll_clk)
 149                __raw_writel(reg, MXC_CCM_MPCTL);
 150        else if (clk == &usb_pll_clk)
 151                __raw_writel(reg, MXC_CCM_UPCTL);
 152        else if (clk == &serial_pll_clk)
 153                __raw_writel(reg, MXC_CCM_SRPCTL);
 154
 155        return 0;
 156}
 157
 158static unsigned long _clk_pll_get_rate(struct clk *clk)
 159{
 160        long mfi, mfn, mfd, pdf, ref_clk, mfn_abs;
 161        unsigned long reg, ccmr;
 162        s64 temp;
 163        unsigned int prcs;
 164
 165        ccmr = __raw_readl(MXC_CCM_CCMR);
 166        prcs = (ccmr & MXC_CCM_CCMR_PRCS_MASK) >> MXC_CCM_CCMR_PRCS_OFFSET;
 167        if (prcs == 0x1)
 168                ref_clk = CKIL_CLK_FREQ * 1024;
 169        else
 170                ref_clk = clk_get_rate(&ckih_clk);
 171
 172        if (clk == &mcu_pll_clk) {
 173                if ((ccmr & MXC_CCM_CCMR_MPE) == 0)
 174                        return ref_clk;
 175                if ((ccmr & MXC_CCM_CCMR_MDS) != 0)
 176                        return ref_clk;
 177                reg = __raw_readl(MXC_CCM_MPCTL);
 178        } else if (clk == &usb_pll_clk)
 179                reg = __raw_readl(MXC_CCM_UPCTL);
 180        else if (clk == &serial_pll_clk)
 181                reg = __raw_readl(MXC_CCM_SRPCTL);
 182        else {
 183                BUG();
 184                return 0;
 185        }
 186
 187        pdf = (reg & MXC_CCM_PCTL_PD_MASK) >> MXC_CCM_PCTL_PD_OFFSET;
 188        mfd = (reg & MXC_CCM_PCTL_MFD_MASK) >> MXC_CCM_PCTL_MFD_OFFSET;
 189        mfi = (reg & MXC_CCM_PCTL_MFI_MASK) >> MXC_CCM_PCTL_MFI_OFFSET;
 190        mfi = (mfi <= 5) ? 5 : mfi;
 191        mfn = mfn_abs = reg & MXC_CCM_PCTL_MFN_MASK;
 192
 193        if (mfn >= 0x200) {
 194                mfn |= 0xFFFFFE00;
 195                mfn_abs = -mfn;
 196        }
 197
 198        ref_clk *= 2;
 199        ref_clk /= pdf + 1;
 200
 201        temp = (u64) ref_clk * mfn_abs;
 202        do_div(temp, mfd + 1);
 203        if (mfn < 0)
 204                temp = -temp;
 205        temp = (ref_clk * mfi) + temp;
 206
 207        return temp;
 208}
 209
 210static int _clk_usb_pll_enable(struct clk *clk)
 211{
 212        u32 reg;
 213
 214        reg = __raw_readl(MXC_CCM_CCMR);
 215        reg |= MXC_CCM_CCMR_UPE;
 216        __raw_writel(reg, MXC_CCM_CCMR);
 217
 218        /* No lock bit on MX31, so using max time from spec */
 219        udelay(80);
 220
 221        return 0;
 222}
 223
 224static void _clk_usb_pll_disable(struct clk *clk)
 225{
 226        u32 reg;
 227
 228        reg = __raw_readl(MXC_CCM_CCMR);
 229        reg &= ~MXC_CCM_CCMR_UPE;
 230        __raw_writel(reg, MXC_CCM_CCMR);
 231}
 232
 233static int _clk_serial_pll_enable(struct clk *clk)
 234{
 235        u32 reg;
 236
 237        reg = __raw_readl(MXC_CCM_CCMR);
 238        reg |= MXC_CCM_CCMR_SPE;
 239        __raw_writel(reg, MXC_CCM_CCMR);
 240
 241        /* No lock bit on MX31, so using max time from spec */
 242        udelay(80);
 243
 244        return 0;
 245}
 246
 247static void _clk_serial_pll_disable(struct clk *clk)
 248{
 249        u32 reg;
 250
 251        reg = __raw_readl(MXC_CCM_CCMR);
 252        reg &= ~MXC_CCM_CCMR_SPE;
 253        __raw_writel(reg, MXC_CCM_CCMR);
 254}
 255
 256#define PDR0(mask, off) ((__raw_readl(MXC_CCM_PDR0) & mask) >> off)
 257#define PDR1(mask, off) ((__raw_readl(MXC_CCM_PDR1) & mask) >> off)
 258#define PDR2(mask, off) ((__raw_readl(MXC_CCM_PDR2) & mask) >> off)
 259
 260static unsigned long _clk_mcu_main_get_rate(struct clk *clk)
 261{
 262        u32 pmcr0 = __raw_readl(MXC_CCM_PMCR0);
 263
 264        if ((pmcr0 & MXC_CCM_PMCR0_DFSUP1) == MXC_CCM_PMCR0_DFSUP1_SPLL)
 265                return clk_get_rate(&serial_pll_clk);
 266        else
 267                return clk_get_rate(&mcu_pll_clk);
 268}
 269
 270static unsigned long _clk_hclk_get_rate(struct clk *clk)
 271{
 272        unsigned long max_pdf;
 273
 274        max_pdf = PDR0(MXC_CCM_PDR0_MAX_PODF_MASK,
 275                       MXC_CCM_PDR0_MAX_PODF_OFFSET);
 276        return clk_get_rate(clk->parent) / (max_pdf + 1);
 277}
 278
 279static unsigned long _clk_ipg_get_rate(struct clk *clk)
 280{
 281        unsigned long ipg_pdf;
 282
 283        ipg_pdf = PDR0(MXC_CCM_PDR0_IPG_PODF_MASK,
 284                       MXC_CCM_PDR0_IPG_PODF_OFFSET);
 285        return clk_get_rate(clk->parent) / (ipg_pdf + 1);
 286}
 287
 288static unsigned long _clk_nfc_get_rate(struct clk *clk)
 289{
 290        unsigned long nfc_pdf;
 291
 292        nfc_pdf = PDR0(MXC_CCM_PDR0_NFC_PODF_MASK,
 293                       MXC_CCM_PDR0_NFC_PODF_OFFSET);
 294        return clk_get_rate(clk->parent) / (nfc_pdf + 1);
 295}
 296
 297static unsigned long _clk_hsp_get_rate(struct clk *clk)
 298{
 299        unsigned long hsp_pdf;
 300
 301        hsp_pdf = PDR0(MXC_CCM_PDR0_HSP_PODF_MASK,
 302                       MXC_CCM_PDR0_HSP_PODF_OFFSET);
 303        return clk_get_rate(clk->parent) / (hsp_pdf + 1);
 304}
 305
 306static unsigned long _clk_usb_get_rate(struct clk *clk)
 307{
 308        unsigned long usb_pdf, usb_prepdf;
 309
 310        usb_pdf = PDR1(MXC_CCM_PDR1_USB_PODF_MASK,
 311                       MXC_CCM_PDR1_USB_PODF_OFFSET);
 312        usb_prepdf = PDR1(MXC_CCM_PDR1_USB_PRDF_MASK,
 313                          MXC_CCM_PDR1_USB_PRDF_OFFSET);
 314        return clk_get_rate(clk->parent) / (usb_prepdf + 1) / (usb_pdf + 1);
 315}
 316
 317static unsigned long _clk_csi_get_rate(struct clk *clk)
 318{
 319        u32 reg, pre, post;
 320
 321        reg = __raw_readl(MXC_CCM_PDR0);
 322        pre = (reg & MXC_CCM_PDR0_CSI_PRDF_MASK) >>
 323            MXC_CCM_PDR0_CSI_PRDF_OFFSET;
 324        pre++;
 325        post = (reg & MXC_CCM_PDR0_CSI_PODF_MASK) >>
 326            MXC_CCM_PDR0_CSI_PODF_OFFSET;
 327        post++;
 328        return clk_get_rate(clk->parent) / (pre * post);
 329}
 330
 331static unsigned long _clk_csi_round_rate(struct clk *clk, unsigned long rate)
 332{
 333        u32 pre, post, parent = clk_get_rate(clk->parent);
 334        u32 div = parent / rate;
 335
 336        if (parent % rate)
 337                div++;
 338
 339        __calc_pre_post_dividers(div, &pre, &post);
 340
 341        return parent / (pre * post);
 342}
 343
 344static int _clk_csi_set_rate(struct clk *clk, unsigned long rate)
 345{
 346        u32 reg, div, pre, post, parent = clk_get_rate(clk->parent);
 347
 348        div = parent / rate;
 349
 350        if ((parent / div) != rate)
 351                return -EINVAL;
 352
 353        __calc_pre_post_dividers(div, &pre, &post);
 354
 355        /* Set CSI clock divider */
 356        reg = __raw_readl(MXC_CCM_PDR0) &
 357            ~(MXC_CCM_PDR0_CSI_PODF_MASK | MXC_CCM_PDR0_CSI_PRDF_MASK);
 358        reg |= (post - 1) << MXC_CCM_PDR0_CSI_PODF_OFFSET;
 359        reg |= (pre - 1) << MXC_CCM_PDR0_CSI_PRDF_OFFSET;
 360        __raw_writel(reg, MXC_CCM_PDR0);
 361
 362        return 0;
 363}
 364
 365static unsigned long _clk_per_get_rate(struct clk *clk)
 366{
 367        unsigned long per_pdf;
 368
 369        per_pdf = PDR0(MXC_CCM_PDR0_PER_PODF_MASK,
 370                       MXC_CCM_PDR0_PER_PODF_OFFSET);
 371        return clk_get_rate(clk->parent) / (per_pdf + 1);
 372}
 373
 374static unsigned long _clk_ssi1_get_rate(struct clk *clk)
 375{
 376        unsigned long ssi1_pdf, ssi1_prepdf;
 377
 378        ssi1_pdf = PDR1(MXC_CCM_PDR1_SSI1_PODF_MASK,
 379                        MXC_CCM_PDR1_SSI1_PODF_OFFSET);
 380        ssi1_prepdf = PDR1(MXC_CCM_PDR1_SSI1_PRE_PODF_MASK,
 381                           MXC_CCM_PDR1_SSI1_PRE_PODF_OFFSET);
 382        return clk_get_rate(clk->parent) / (ssi1_prepdf + 1) / (ssi1_pdf + 1);
 383}
 384
 385static unsigned long _clk_ssi2_get_rate(struct clk *clk)
 386{
 387        unsigned long ssi2_pdf, ssi2_prepdf;
 388
 389        ssi2_pdf = PDR1(MXC_CCM_PDR1_SSI2_PODF_MASK,
 390                        MXC_CCM_PDR1_SSI2_PODF_OFFSET);
 391        ssi2_prepdf = PDR1(MXC_CCM_PDR1_SSI2_PRE_PODF_MASK,
 392                           MXC_CCM_PDR1_SSI2_PRE_PODF_OFFSET);
 393        return clk_get_rate(clk->parent) / (ssi2_prepdf + 1) / (ssi2_pdf + 1);
 394}
 395
 396static unsigned long _clk_firi_get_rate(struct clk *clk)
 397{
 398        unsigned long firi_pdf, firi_prepdf;
 399
 400        firi_pdf = PDR1(MXC_CCM_PDR1_FIRI_PODF_MASK,
 401                        MXC_CCM_PDR1_FIRI_PODF_OFFSET);
 402        firi_prepdf = PDR1(MXC_CCM_PDR1_FIRI_PRE_PODF_MASK,
 403                           MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET);
 404        return clk_get_rate(clk->parent) / (firi_prepdf + 1) / (firi_pdf + 1);
 405}
 406
 407static unsigned long _clk_firi_round_rate(struct clk *clk, unsigned long rate)
 408{
 409        u32 pre, post;
 410        u32 parent = clk_get_rate(clk->parent);
 411        u32 div = parent / rate;
 412
 413        if (parent % rate)
 414                div++;
 415
 416        __calc_pre_post_dividers(div, &pre, &post);
 417
 418        return parent / (pre * post);
 419
 420}
 421
 422static int _clk_firi_set_rate(struct clk *clk, unsigned long rate)
 423{
 424        u32 reg, div, pre, post, parent = clk_get_rate(clk->parent);
 425
 426        div = parent / rate;
 427
 428        if ((parent / div) != rate)
 429                return -EINVAL;
 430
 431        __calc_pre_post_dividers(div, &pre, &post);
 432
 433        /* Set FIRI clock divider */
 434        reg = __raw_readl(MXC_CCM_PDR1) &
 435            ~(MXC_CCM_PDR1_FIRI_PODF_MASK | MXC_CCM_PDR1_FIRI_PRE_PODF_MASK);
 436        reg |= (pre - 1) << MXC_CCM_PDR1_FIRI_PRE_PODF_OFFSET;
 437        reg |= (post - 1) << MXC_CCM_PDR1_FIRI_PODF_OFFSET;
 438        __raw_writel(reg, MXC_CCM_PDR1);
 439
 440        return 0;
 441}
 442
 443static unsigned long _clk_mbx_get_rate(struct clk *clk)
 444{
 445        return clk_get_rate(clk->parent) / 2;
 446}
 447
 448static unsigned long _clk_mstick1_get_rate(struct clk *clk)
 449{
 450        unsigned long msti_pdf;
 451
 452        msti_pdf = PDR2(MXC_CCM_PDR2_MST1_PDF_MASK,
 453                        MXC_CCM_PDR2_MST1_PDF_OFFSET);
 454        return clk_get_rate(clk->parent) / (msti_pdf + 1);
 455}
 456
 457static unsigned long _clk_mstick2_get_rate(struct clk *clk)
 458{
 459        unsigned long msti_pdf;
 460
 461        msti_pdf = PDR2(MXC_CCM_PDR2_MST2_PDF_MASK,
 462                        MXC_CCM_PDR2_MST2_PDF_OFFSET);
 463        return clk_get_rate(clk->parent) / (msti_pdf + 1);
 464}
 465
 466static unsigned long ckih_rate;
 467
 468static unsigned long clk_ckih_get_rate(struct clk *clk)
 469{
 470        return ckih_rate;
 471}
 472
 473static struct clk ckih_clk = {
 474        .name = "ckih",
 475        .get_rate = clk_ckih_get_rate,
 476};
 477
 478static unsigned long clk_ckil_get_rate(struct clk *clk)
 479{
 480        return CKIL_CLK_FREQ;
 481}
 482
 483static struct clk ckil_clk = {
 484        .name = "ckil",
 485        .get_rate = clk_ckil_get_rate,
 486};
 487
 488static struct clk mcu_pll_clk = {
 489        .name = "mcu_pll",
 490        .parent = &ckih_clk,
 491        .set_rate = _clk_pll_set_rate,
 492        .get_rate = _clk_pll_get_rate,
 493};
 494
 495static struct clk mcu_main_clk = {
 496        .name = "mcu_main_clk",
 497        .parent = &mcu_pll_clk,
 498        .get_rate = _clk_mcu_main_get_rate,
 499};
 500
 501static struct clk serial_pll_clk = {
 502        .name = "serial_pll",
 503        .parent = &ckih_clk,
 504        .set_rate = _clk_pll_set_rate,
 505        .get_rate = _clk_pll_get_rate,
 506        .enable = _clk_serial_pll_enable,
 507        .disable = _clk_serial_pll_disable,
 508};
 509
 510static struct clk usb_pll_clk = {
 511        .name = "usb_pll",
 512        .parent = &ckih_clk,
 513        .set_rate = _clk_pll_set_rate,
 514        .get_rate = _clk_pll_get_rate,
 515        .enable = _clk_usb_pll_enable,
 516        .disable = _clk_usb_pll_disable,
 517};
 518
 519static struct clk ahb_clk = {
 520        .name = "ahb_clk",
 521        .parent = &mcu_main_clk,
 522        .get_rate = _clk_hclk_get_rate,
 523};
 524
 525static struct clk per_clk = {
 526        .name = "per_clk",
 527        .parent = &usb_pll_clk,
 528        .get_rate = _clk_per_get_rate,
 529};
 530
 531static struct clk perclk_clk = {
 532        .name = "perclk_clk",
 533        .parent = &ipg_clk,
 534};
 535
 536static struct clk cspi_clk[] = {
 537        {
 538         .name = "cspi_clk",
 539         .id = 0,
 540         .parent = &ipg_clk,
 541         .enable = _clk_enable,
 542         .enable_reg = MXC_CCM_CGR2,
 543         .enable_shift = MXC_CCM_CGR2_CSPI1_OFFSET,
 544         .disable = _clk_disable,},
 545        {
 546         .name = "cspi_clk",
 547         .id = 1,
 548         .parent = &ipg_clk,
 549         .enable = _clk_enable,
 550         .enable_reg = MXC_CCM_CGR2,
 551         .enable_shift = MXC_CCM_CGR2_CSPI2_OFFSET,
 552         .disable = _clk_disable,},
 553        {
 554         .name = "cspi_clk",
 555         .id = 2,
 556         .parent = &ipg_clk,
 557         .enable = _clk_enable,
 558         .enable_reg = MXC_CCM_CGR0,
 559         .enable_shift = MXC_CCM_CGR0_CSPI3_OFFSET,
 560         .disable = _clk_disable,},
 561};
 562
 563static struct clk ipg_clk = {
 564        .name = "ipg_clk",
 565        .parent = &ahb_clk,
 566        .get_rate = _clk_ipg_get_rate,
 567};
 568
 569static struct clk emi_clk = {
 570        .name = "emi_clk",
 571        .parent = &ahb_clk,
 572        .enable = _clk_enable,
 573        .enable_reg = MXC_CCM_CGR2,
 574        .enable_shift = MXC_CCM_CGR2_EMI_OFFSET,
 575        .disable = _clk_emi_disable,
 576};
 577
 578static struct clk gpt_clk = {
 579        .name = "gpt_clk",
 580        .parent = &perclk_clk,
 581        .enable = _clk_enable,
 582        .enable_reg = MXC_CCM_CGR0,
 583        .enable_shift = MXC_CCM_CGR0_GPT_OFFSET,
 584        .disable = _clk_disable,
 585};
 586
 587static struct clk pwm_clk = {
 588        .name = "pwm_clk",
 589        .parent = &perclk_clk,
 590        .enable = _clk_enable,
 591        .enable_reg = MXC_CCM_CGR0,
 592        .enable_shift = MXC_CCM_CGR1_PWM_OFFSET,
 593        .disable = _clk_disable,
 594};
 595
 596static struct clk epit_clk[] = {
 597        {
 598         .name = "epit_clk",
 599         .id = 0,
 600         .parent = &perclk_clk,
 601         .enable = _clk_enable,
 602         .enable_reg = MXC_CCM_CGR0,
 603         .enable_shift = MXC_CCM_CGR0_EPIT1_OFFSET,
 604         .disable = _clk_disable,},
 605        {
 606         .name = "epit_clk",
 607         .id = 1,
 608         .parent = &perclk_clk,
 609         .enable = _clk_enable,
 610         .enable_reg = MXC_CCM_CGR0,
 611         .enable_shift = MXC_CCM_CGR0_EPIT2_OFFSET,
 612         .disable = _clk_disable,},
 613};
 614
 615static struct clk nfc_clk = {
 616        .name = "nfc_clk",
 617        .parent = &ahb_clk,
 618        .get_rate = _clk_nfc_get_rate,
 619};
 620
 621static struct clk scc_clk = {
 622        .name = "scc_clk",
 623        .parent = &ipg_clk,
 624};
 625
 626static struct clk ipu_clk = {
 627        .name = "ipu_clk",
 628        .parent = &mcu_main_clk,
 629        .get_rate = _clk_hsp_get_rate,
 630        .enable = _clk_enable,
 631        .enable_reg = MXC_CCM_CGR1,
 632        .enable_shift = MXC_CCM_CGR1_IPU_OFFSET,
 633        .disable = _clk_disable,
 634};
 635
 636static struct clk kpp_clk = {
 637        .name = "kpp_clk",
 638        .parent = &ipg_clk,
 639        .enable = _clk_enable,
 640        .enable_reg = MXC_CCM_CGR1,
 641        .enable_shift = MXC_CCM_CGR1_KPP_OFFSET,
 642        .disable = _clk_disable,
 643};
 644
 645static struct clk wdog_clk = {
 646        .name = "wdog_clk",
 647        .parent = &ipg_clk,
 648        .enable = _clk_enable,
 649        .enable_reg = MXC_CCM_CGR1,
 650        .enable_shift = MXC_CCM_CGR1_WDOG_OFFSET,
 651        .disable = _clk_disable,
 652};
 653static struct clk rtc_clk = {
 654        .name = "rtc_clk",
 655        .parent = &ipg_clk,
 656        .enable = _clk_enable,
 657        .enable_reg = MXC_CCM_CGR1,
 658        .enable_shift = MXC_CCM_CGR1_RTC_OFFSET,
 659        .disable = _clk_disable,
 660};
 661
 662static struct clk usb_clk[] = {
 663        {
 664         .name = "usb_clk",
 665         .parent = &usb_pll_clk,
 666         .get_rate = _clk_usb_get_rate,},
 667        {
 668         .name = "usb_ahb_clk",
 669         .parent = &ahb_clk,
 670         .enable = _clk_enable,
 671         .enable_reg = MXC_CCM_CGR1,
 672         .enable_shift = MXC_CCM_CGR1_USBOTG_OFFSET,
 673         .disable = _clk_disable,},
 674};
 675
 676static struct clk csi_clk = {
 677        .name = "csi_clk",
 678        .parent = &serial_pll_clk,
 679        .get_rate = _clk_csi_get_rate,
 680        .round_rate = _clk_csi_round_rate,
 681        .set_rate = _clk_csi_set_rate,
 682        .enable = _clk_enable,
 683        .enable_reg = MXC_CCM_CGR1,
 684        .enable_shift = MXC_CCM_CGR1_CSI_OFFSET,
 685        .disable = _clk_disable,
 686};
 687
 688static struct clk uart_clk[] = {
 689        {
 690         .name = "uart_clk",
 691         .id = 0,
 692         .parent = &perclk_clk,
 693         .enable = _clk_enable,
 694         .enable_reg = MXC_CCM_CGR0,
 695         .enable_shift = MXC_CCM_CGR0_UART1_OFFSET,
 696         .disable = _clk_disable,},
 697        {
 698         .name = "uart_clk",
 699         .id = 1,
 700         .parent = &perclk_clk,
 701         .enable = _clk_enable,
 702         .enable_reg = MXC_CCM_CGR0,
 703         .enable_shift = MXC_CCM_CGR0_UART2_OFFSET,
 704         .disable = _clk_disable,},
 705        {
 706         .name = "uart_clk",
 707         .id = 2,
 708         .parent = &perclk_clk,
 709         .enable = _clk_enable,
 710         .enable_reg = MXC_CCM_CGR1,
 711         .enable_shift = MXC_CCM_CGR1_UART3_OFFSET,
 712         .disable = _clk_disable,},
 713        {
 714         .name = "uart_clk",
 715         .id = 3,
 716         .parent = &perclk_clk,
 717         .enable = _clk_enable,
 718         .enable_reg = MXC_CCM_CGR1,
 719         .enable_shift = MXC_CCM_CGR1_UART4_OFFSET,
 720         .disable = _clk_disable,},
 721        {
 722         .name = "uart_clk",
 723         .id = 4,
 724         .parent = &perclk_clk,
 725         .enable = _clk_enable,
 726         .enable_reg = MXC_CCM_CGR1,
 727         .enable_shift = MXC_CCM_CGR1_UART5_OFFSET,
 728         .disable = _clk_disable,},
 729};
 730
 731static struct clk i2c_clk[] = {
 732        {
 733         .name = "i2c_clk",
 734         .id = 0,
 735         .parent = &perclk_clk,
 736         .enable = _clk_enable,
 737         .enable_reg = MXC_CCM_CGR0,
 738         .enable_shift = MXC_CCM_CGR0_I2C1_OFFSET,
 739         .disable = _clk_disable,},
 740        {
 741         .name = "i2c_clk",
 742         .id = 1,
 743         .parent = &perclk_clk,
 744         .enable = _clk_enable,
 745         .enable_reg = MXC_CCM_CGR0,
 746         .enable_shift = MXC_CCM_CGR0_I2C2_OFFSET,
 747         .disable = _clk_disable,},
 748        {
 749         .name = "i2c_clk",
 750         .id = 2,
 751         .parent = &perclk_clk,
 752         .enable = _clk_enable,
 753         .enable_reg = MXC_CCM_CGR0,
 754         .enable_shift = MXC_CCM_CGR0_I2C3_OFFSET,
 755         .disable = _clk_disable,},
 756};
 757
 758static struct clk owire_clk = {
 759        .name = "owire_clk",
 760        .parent = &perclk_clk,
 761        .enable_reg = MXC_CCM_CGR1,
 762        .enable_shift = MXC_CCM_CGR1_OWIRE_OFFSET,
 763        .enable = _clk_enable,
 764        .disable = _clk_disable,
 765};
 766
 767static struct clk sdhc_clk[] = {
 768        {
 769         .name = "sdhc_clk",
 770         .id = 0,
 771         .parent = &perclk_clk,
 772         .enable = _clk_enable,
 773         .enable_reg = MXC_CCM_CGR0,
 774         .enable_shift = MXC_CCM_CGR0_SD_MMC1_OFFSET,
 775         .disable = _clk_disable,},
 776        {
 777         .name = "sdhc_clk",
 778         .id = 1,
 779         .parent = &perclk_clk,
 780         .enable = _clk_enable,
 781         .enable_reg = MXC_CCM_CGR0,
 782         .enable_shift = MXC_CCM_CGR0_SD_MMC2_OFFSET,
 783         .disable = _clk_disable,},
 784};
 785
 786static struct clk ssi_clk[] = {
 787        {
 788         .name = "ssi_clk",
 789         .parent = &serial_pll_clk,
 790         .get_rate = _clk_ssi1_get_rate,
 791         .enable = _clk_enable,
 792         .enable_reg = MXC_CCM_CGR0,
 793         .enable_shift = MXC_CCM_CGR0_SSI1_OFFSET,
 794         .disable = _clk_disable,},
 795        {
 796         .name = "ssi_clk",
 797         .id = 1,
 798         .parent = &serial_pll_clk,
 799         .get_rate = _clk_ssi2_get_rate,
 800         .enable = _clk_enable,
 801         .enable_reg = MXC_CCM_CGR2,
 802         .enable_shift = MXC_CCM_CGR2_SSI2_OFFSET,
 803         .disable = _clk_disable,},
 804};
 805
 806static struct clk firi_clk = {
 807        .name = "firi_clk",
 808        .parent = &usb_pll_clk,
 809        .round_rate = _clk_firi_round_rate,
 810        .set_rate = _clk_firi_set_rate,
 811        .get_rate = _clk_firi_get_rate,
 812        .enable = _clk_enable,
 813        .enable_reg = MXC_CCM_CGR2,
 814        .enable_shift = MXC_CCM_CGR2_FIRI_OFFSET,
 815        .disable = _clk_disable,
 816};
 817
 818static struct clk ata_clk = {
 819        .name = "ata_clk",
 820        .parent = &ipg_clk,
 821        .enable = _clk_enable,
 822        .enable_reg = MXC_CCM_CGR0,
 823        .enable_shift = MXC_CCM_CGR0_ATA_OFFSET,
 824        .disable = _clk_disable,
 825};
 826
 827static struct clk mbx_clk = {
 828        .name = "mbx_clk",
 829        .parent = &ahb_clk,
 830        .enable = _clk_enable,
 831        .enable_reg = MXC_CCM_CGR2,
 832        .enable_shift = MXC_CCM_CGR2_GACC_OFFSET,
 833        .get_rate = _clk_mbx_get_rate,
 834};
 835
 836static struct clk vpu_clk = {
 837        .name = "vpu_clk",
 838        .parent = &ahb_clk,
 839        .enable = _clk_enable,
 840        .enable_reg = MXC_CCM_CGR2,
 841        .enable_shift = MXC_CCM_CGR2_GACC_OFFSET,
 842        .get_rate = _clk_mbx_get_rate,
 843};
 844
 845static struct clk rtic_clk = {
 846        .name = "rtic_clk",
 847        .parent = &ahb_clk,
 848        .enable = _clk_enable,
 849        .enable_reg = MXC_CCM_CGR2,
 850        .enable_shift = MXC_CCM_CGR2_RTIC_OFFSET,
 851        .disable = _clk_disable,
 852};
 853
 854static struct clk rng_clk = {
 855        .name = "rng_clk",
 856        .parent = &ipg_clk,
 857        .enable = _clk_enable,
 858        .enable_reg = MXC_CCM_CGR0,
 859        .enable_shift = MXC_CCM_CGR0_RNG_OFFSET,
 860        .disable = _clk_disable,
 861};
 862
 863static struct clk sdma_clk[] = {
 864        {
 865         .name = "sdma_ahb_clk",
 866         .parent = &ahb_clk,
 867         .enable = _clk_enable,
 868         .enable_reg = MXC_CCM_CGR0,
 869         .enable_shift = MXC_CCM_CGR0_SDMA_OFFSET,
 870         .disable = _clk_disable,},
 871        {
 872         .name = "sdma_ipg_clk",
 873         .parent = &ipg_clk,}
 874};
 875
 876static struct clk mpeg4_clk = {
 877        .name = "mpeg4_clk",
 878        .parent = &ahb_clk,
 879        .enable = _clk_enable,
 880        .enable_reg = MXC_CCM_CGR1,
 881        .enable_shift = MXC_CCM_CGR1_HANTRO_OFFSET,
 882        .disable = _clk_disable,
 883};
 884
 885static struct clk vl2cc_clk = {
 886        .name = "vl2cc_clk",
 887        .parent = &ahb_clk,
 888        .enable = _clk_enable,
 889        .enable_reg = MXC_CCM_CGR1,
 890        .enable_shift = MXC_CCM_CGR1_HANTRO_OFFSET,
 891        .disable = _clk_disable,
 892};
 893
 894static struct clk mstick_clk[] = {
 895        {
 896         .name = "mstick_clk",
 897         .id = 0,
 898         .parent = &usb_pll_clk,
 899         .get_rate = _clk_mstick1_get_rate,
 900         .enable = _clk_enable,
 901         .enable_reg = MXC_CCM_CGR1,
 902         .enable_shift = MXC_CCM_CGR1_MEMSTICK1_OFFSET,
 903         .disable = _clk_disable,},
 904        {
 905         .name = "mstick_clk",
 906         .id = 1,
 907         .parent = &usb_pll_clk,
 908         .get_rate = _clk_mstick2_get_rate,
 909         .enable = _clk_enable,
 910         .enable_reg = MXC_CCM_CGR1,
 911         .enable_shift = MXC_CCM_CGR1_MEMSTICK2_OFFSET,
 912         .disable = _clk_disable,},
 913};
 914
 915static struct clk iim_clk = {
 916        .name = "iim_clk",
 917        .parent = &ipg_clk,
 918        .enable = _clk_enable,
 919        .enable_reg = MXC_CCM_CGR0,
 920        .enable_shift = MXC_CCM_CGR0_IIM_OFFSET,
 921        .disable = _clk_disable,
 922};
 923
 924static unsigned long _clk_cko1_round_rate(struct clk *clk, unsigned long rate)
 925{
 926        u32 div, parent = clk_get_rate(clk->parent);
 927
 928        div = parent / rate;
 929        if (parent % rate)
 930                div++;
 931
 932        if (div > 8)
 933                div = 16;
 934        else if (div > 4)
 935                div = 8;
 936        else if (div > 2)
 937                div = 4;
 938
 939        return parent / div;
 940}
 941
 942static int _clk_cko1_set_rate(struct clk *clk, unsigned long rate)
 943{
 944        u32 reg, div, parent = clk_get_rate(clk->parent);
 945
 946        div = parent / rate;
 947
 948        if (div == 16)
 949                div = 4;
 950        else if (div == 8)
 951                div = 3;
 952        else if (div == 4)
 953                div = 2;
 954        else if (div == 2)
 955                div = 1;
 956        else if (div == 1)
 957                div = 0;
 958        else
 959                return -EINVAL;
 960
 961        reg = __raw_readl(MXC_CCM_COSR) & ~MXC_CCM_COSR_CLKOUTDIV_MASK;
 962        reg |= div << MXC_CCM_COSR_CLKOUTDIV_OFFSET;
 963        __raw_writel(reg, MXC_CCM_COSR);
 964
 965        return 0;
 966}
 967
 968static unsigned long _clk_cko1_get_rate(struct clk *clk)
 969{
 970        u32 div;
 971
 972        div = __raw_readl(MXC_CCM_COSR) & MXC_CCM_COSR_CLKOUTDIV_MASK >>
 973            MXC_CCM_COSR_CLKOUTDIV_OFFSET;
 974
 975        return clk_get_rate(clk->parent) / (1 << div);
 976}
 977
 978static int _clk_cko1_set_parent(struct clk *clk, struct clk *parent)
 979{
 980        u32 reg;
 981
 982        reg = __raw_readl(MXC_CCM_COSR) & ~MXC_CCM_COSR_CLKOSEL_MASK;
 983
 984        if (parent == &mcu_main_clk)
 985                reg |= 0 << MXC_CCM_COSR_CLKOSEL_OFFSET;
 986        else if (parent == &ipg_clk)
 987                reg |= 1 << MXC_CCM_COSR_CLKOSEL_OFFSET;
 988        else if (parent == &usb_pll_clk)
 989                reg |= 2 << MXC_CCM_COSR_CLKOSEL_OFFSET;
 990        else if (parent == mcu_main_clk.parent)
 991                reg |= 3 << MXC_CCM_COSR_CLKOSEL_OFFSET;
 992        else if (parent == &ahb_clk)
 993                reg |= 5 << MXC_CCM_COSR_CLKOSEL_OFFSET;
 994        else if (parent == &serial_pll_clk)
 995                reg |= 7 << MXC_CCM_COSR_CLKOSEL_OFFSET;
 996        else if (parent == &ckih_clk)
 997                reg |= 8 << MXC_CCM_COSR_CLKOSEL_OFFSET;
 998        else if (parent == &emi_clk)
 999                reg |= 9 << MXC_CCM_COSR_CLKOSEL_OFFSET;
1000        else if (parent == &ipu_clk)
1001                reg |= 0xA << MXC_CCM_COSR_CLKOSEL_OFFSET;
1002        else if (parent == &nfc_clk)
1003                reg |= 0xB << MXC_CCM_COSR_CLKOSEL_OFFSET;
1004        else if (parent == &uart_clk[0])
1005                reg |= 0xC << MXC_CCM_COSR_CLKOSEL_OFFSET;
1006        else
1007                return -EINVAL;
1008
1009        __raw_writel(reg, MXC_CCM_COSR);
1010
1011        return 0;
1012}
1013
1014static int _clk_cko1_enable(struct clk *clk)
1015{
1016        u32 reg;
1017
1018        reg = __raw_readl(MXC_CCM_COSR) | MXC_CCM_COSR_CLKOEN;
1019        __raw_writel(reg, MXC_CCM_COSR);
1020
1021        return 0;
1022}
1023
1024static void _clk_cko1_disable(struct clk *clk)
1025{
1026        u32 reg;
1027
1028        reg = __raw_readl(MXC_CCM_COSR) & ~MXC_CCM_COSR_CLKOEN;
1029        __raw_writel(reg, MXC_CCM_COSR);
1030}
1031
1032static struct clk cko1_clk = {
1033        .name = "cko1_clk",
1034        .get_rate = _clk_cko1_get_rate,
1035        .set_rate = _clk_cko1_set_rate,
1036        .round_rate = _clk_cko1_round_rate,
1037        .set_parent = _clk_cko1_set_parent,
1038        .enable = _clk_cko1_enable,
1039        .disable = _clk_cko1_disable,
1040};
1041
1042static struct clk *mxc_clks[] = {
1043        &ckih_clk,
1044        &ckil_clk,
1045        &mcu_pll_clk,
1046        &usb_pll_clk,
1047        &serial_pll_clk,
1048        &mcu_main_clk,
1049        &ahb_clk,
1050        &per_clk,
1051        &perclk_clk,
1052        &cko1_clk,
1053        &emi_clk,
1054        &cspi_clk[0],
1055        &cspi_clk[1],
1056        &cspi_clk[2],
1057        &ipg_clk,
1058        &gpt_clk,
1059        &pwm_clk,
1060        &wdog_clk,
1061        &rtc_clk,
1062        &epit_clk[0],
1063        &epit_clk[1],
1064        &nfc_clk,
1065        &ipu_clk,
1066        &kpp_clk,
1067        &usb_clk[0],
1068        &usb_clk[1],
1069        &csi_clk,
1070        &uart_clk[0],
1071        &uart_clk[1],
1072        &uart_clk[2],
1073        &uart_clk[3],
1074        &uart_clk[4],
1075        &i2c_clk[0],
1076        &i2c_clk[1],
1077        &i2c_clk[2],
1078        &owire_clk,
1079        &sdhc_clk[0],
1080        &sdhc_clk[1],
1081        &ssi_clk[0],
1082        &ssi_clk[1],
1083        &firi_clk,
1084        &ata_clk,
1085        &rtic_clk,
1086        &rng_clk,
1087        &sdma_clk[0],
1088        &sdma_clk[1],
1089        &mstick_clk[0],
1090        &mstick_clk[1],
1091        &scc_clk,
1092        &iim_clk,
1093};
1094
1095int __init mxc_clocks_init(unsigned long fref)
1096{
1097        u32 reg;
1098        struct clk **clkp;
1099
1100        ckih_rate = fref;
1101
1102        for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++)
1103                clk_register(*clkp);
1104
1105        if (cpu_is_mx31()) {
1106                clk_register(&mpeg4_clk);
1107                clk_register(&mbx_clk);
1108        } else {
1109                clk_register(&vpu_clk);
1110                clk_register(&vl2cc_clk);
1111        }
1112
1113        /* Turn off all possible clocks */
1114        __raw_writel(MXC_CCM_CGR0_GPT_MASK, MXC_CCM_CGR0);
1115        __raw_writel(0, MXC_CCM_CGR1);
1116
1117        __raw_writel(MXC_CCM_CGR2_EMI_MASK |
1118                     MXC_CCM_CGR2_IPMUX1_MASK |
1119                     MXC_CCM_CGR2_IPMUX2_MASK |
1120                     MXC_CCM_CGR2_MXCCLKENSEL_MASK |    /* for MX32 */
1121                     MXC_CCM_CGR2_CHIKCAMPEN_MASK |     /* for MX32 */
1122                     MXC_CCM_CGR2_OVRVPUBUSY_MASK |     /* for MX32 */
1123                     1 << 27 | 1 << 28, /* Bit 27 and 28 are not defined for
1124                                           MX32, but still required to be set */
1125                     MXC_CCM_CGR2);
1126
1127        clk_disable(&cko1_clk);
1128        clk_disable(&usb_pll_clk);
1129
1130        pr_info("Clock input source is %ld\n", clk_get_rate(&ckih_clk));
1131
1132        clk_enable(&gpt_clk);
1133        clk_enable(&emi_clk);
1134        clk_enable(&iim_clk);
1135
1136        clk_enable(&serial_pll_clk);
1137
1138        if (mx31_revision() >= CHIP_REV_2_0) {
1139                reg = __raw_readl(MXC_CCM_PMCR1);
1140                /* No PLL restart on DVFS switch; enable auto EMI handshake */
1141                reg |= MXC_CCM_PMCR1_PLLRDIS | MXC_CCM_PMCR1_EMIRQ_EN;
1142                __raw_writel(reg, MXC_CCM_PMCR1);
1143        }
1144
1145        return 0;
1146}
1147
1148