diff options
Diffstat (limited to 'arch/arm/mach-mx25/clock.c')
-rw-r--r-- | arch/arm/mach-mx25/clock.c | 1739 |
1 files changed, 1739 insertions, 0 deletions
diff --git a/arch/arm/mach-mx25/clock.c b/arch/arm/mach-mx25/clock.c new file mode 100644 index 000000000000..7d6ce2b09434 --- /dev/null +++ b/arch/arm/mach-mx25/clock.c @@ -0,0 +1,1739 @@ +/* + * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved. + */ + +/* + * The code contained herein is licensed under the GNU General Public + * License. You may obtain a copy of the GNU General Public License + * Version 2 or later at the following locations: + * + * http://www.opensource.org/licenses/gpl-license.html + * http://www.gnu.org/copyleft/gpl.html + */ + +/* based on mach-mx27/clock.c */ + +#include <linux/module.h> +#include <linux/spinlock.h> +#include <linux/clk.h> +#include <linux/io.h> +#include <mach/clock.h> +#include <mach/common.h> +#include "crm_regs.h" + +#define OSC24M_CLK_FREQ 24000000 /* 24M reference clk */ +#define OSC32K_CLK_FREQ 32768 /* 32.768k oscillator in */ + +#if defined CONFIG_CPU_FREQ_IMX +#define AHB_CLK_DEFAULT 133000000 +#define ARM_SRC_DEFAULT 532000000 +#endif + +static struct clk mpll_clk; +static struct clk upll_clk; +static struct clk ahb_clk; +static struct clk upll_24610k_clk; +int cpu_wp_nr; + +static int _clk_enable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(clk->enable_reg); + reg |= 1 << clk->enable_shift; + __raw_writel(reg, clk->enable_reg); + + return 0; +} + +static void _clk_disable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(clk->enable_reg); + reg &= ~(1 << clk->enable_shift); + __raw_writel(reg, clk->enable_reg); +} + +static int _clk_upll_enable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CCTL); + reg &= ~MXC_CCM_CCTL_UPLL_DISABLE; + __raw_writel(reg, MXC_CCM_CCTL); + + while ((__raw_readl(MXC_CCM_UPCTL) & MXC_CCM_UPCTL_LF) == 0) ; + + return 0; +} + +static void _clk_upll_disable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CCTL); + reg |= MXC_CCM_CCTL_UPLL_DISABLE; + __raw_writel(reg, MXC_CCM_CCTL); +} + +static int _perclk_enable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CGCR0); + reg |= 1 << clk->id; + __raw_writel(reg, MXC_CCM_CGCR0); + + return 0; +} + +static void _perclk_disable(struct clk *clk) +{ + unsigned long reg; + + reg = __raw_readl(MXC_CCM_CGCR0); + reg &= ~(1 << clk->id); + __raw_writel(reg, MXC_CCM_CGCR0); +} + +static void _clk_pll_recalc(struct clk *clk) +{ + unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0; + unsigned long ref_clk; + unsigned long reg; + unsigned long long temp; + + ref_clk = clk->parent->rate; + + if (clk == &mpll_clk) { + reg = __raw_readl(MXC_CCM_MPCTL); + pdf = (reg & MXC_CCM_MPCTL_PD_MASK) >> MXC_CCM_MPCTL_PD_OFFSET; + mfd = + (reg & MXC_CCM_MPCTL_MFD_MASK) >> MXC_CCM_MPCTL_MFD_OFFSET; + mfi = + (reg & MXC_CCM_MPCTL_MFI_MASK) >> MXC_CCM_MPCTL_MFI_OFFSET; + mfn = + (reg & MXC_CCM_MPCTL_MFN_MASK) >> MXC_CCM_MPCTL_MFN_OFFSET; + } else if (clk == &upll_clk) { + reg = __raw_readl(MXC_CCM_UPCTL); + pdf = (reg & MXC_CCM_UPCTL_PD_MASK) >> MXC_CCM_UPCTL_PD_OFFSET; + mfd = + (reg & MXC_CCM_UPCTL_MFD_MASK) >> MXC_CCM_UPCTL_MFD_OFFSET; + mfi = + (reg & MXC_CCM_UPCTL_MFI_MASK) >> MXC_CCM_UPCTL_MFI_OFFSET; + mfn = + (reg & MXC_CCM_UPCTL_MFN_MASK) >> MXC_CCM_UPCTL_MFN_OFFSET; + } else { + BUG(); /* oops */ + } + + mfi = (mfi <= 5) ? 5 : mfi; + temp = 2LL * ref_clk * mfn; + do_div(temp, mfd + 1); + temp = 2LL * ref_clk * mfi + temp; + do_div(temp, pdf + 1); + + clk->rate = temp; +} + +static unsigned long _clk_cpu_round_rate(struct clk *clk, unsigned long rate) +{ + int div = clk->parent->rate / rate; + + if (clk->parent->rate % rate) + div++; + + if (div > 4) + div = 4; + + return clk->parent->rate / div; +} + +static int _clk_cpu_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long div = 0x0, reg = 0x0; + unsigned long cctl = __raw_readl(MXC_CCM_CCTL); + +#if defined CONFIG_CPU_FREQ_IMX + struct cpu_wp *cpu_wp; + unsigned long ahb_clk_div = 0; + unsigned long arm_src = 0; + int i; + + cpu_wp = get_cpu_wp(&cpu_wp_nr); + for (i = 0; i < cpu_wp_nr; i++) { + if (cpu_wp[i].cpu_rate == rate) { + div = cpu_wp[i].cpu_podf; + ahb_clk_div = cpu_wp[i].cpu_rate / AHB_CLK_DEFAULT - 1; + arm_src = + (cpu_wp[i].pll_rate == ARM_SRC_DEFAULT) ? 0 : 1; + break; + } + } + if (i == cpu_wp_nr) + return -EINVAL; + reg = (cctl & ~MXC_CCM_CCTL_ARM_MASK) | + (div << MXC_CCM_CCTL_ARM_OFFSET); + reg = (reg & ~MXC_CCM_CCTL_AHB_MASK) | + (ahb_clk_div << MXC_CCM_CCTL_AHB_OFFSET); + reg = (reg & ~MXC_CCM_CCTL_ARM_SRC) | + (arm_src << MXC_CCM_CCTL_ARM_SRC_OFFSET); + __raw_writel(reg, MXC_CCM_CCTL); + clk->rate = rate; +#else + div = clk->parent->rate / rate; + + if (div > 4 || div < 1 || ((clk->parent->rate / div) != rate)) + return -EINVAL; + div--; + + reg = + (cctl & ~MXC_CCM_CCTL_ARM_MASK) | (div << MXC_CCM_CCTL_ARM_OFFSET); + __raw_writel(reg, MXC_CCM_CCTL); + clk->rate = rate; +#endif + + return 0; +} + +static void _clk_cpu_recalc(struct clk *clk) +{ + unsigned long div; + unsigned long cctl = __raw_readl(MXC_CCM_CCTL); + + div = (cctl & MXC_CCM_CCTL_ARM_MASK) >> MXC_CCM_CCTL_ARM_OFFSET; + + clk->rate = clk->parent->rate / (div + 1); + + if (cctl & MXC_CCM_CCTL_ARM_SRC) { + clk->rate *= 3; + clk->rate /= 4; + } +} + +static void _clk_ahb_recalc(struct clk *clk) +{ + unsigned long div; + unsigned long cctl = __raw_readl(MXC_CCM_CCTL); + + div = (cctl & MXC_CCM_CCTL_AHB_MASK) >> MXC_CCM_CCTL_AHB_OFFSET; + + clk->rate = clk->parent->rate / (div + 1); +} + +static void *pcdr_a[4] = { + MXC_CCM_PCDR0, MXC_CCM_PCDR1, MXC_CCM_PCDR2, MXC_CCM_PCDR3 +}; +static void _clk_perclkx_recalc(struct clk *clk) +{ + unsigned long perclk_pdf; + unsigned long pcdr; + + if (clk->id < 0 || clk->id > 15) + return; + + pcdr = __raw_readl(pcdr_a[clk->id >> 2]); + + perclk_pdf = + (pcdr >> ((clk->id & 3) << 3)) & MXC_CCM_PCDR1_PERDIV1_MASK; + + clk->rate = clk->parent->rate / (perclk_pdf + 1); +} + +static unsigned long _clk_perclkx_round_rate(struct clk *clk, + unsigned long rate) +{ + unsigned long div; + + div = clk->parent->rate / rate; + if (clk->parent->rate % rate) + div++; + + if (div > 64) + div = 64; + + return clk->parent->rate / div; +} + +static int _clk_perclkx_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long reg; + unsigned long div; + + if (clk->id < 0 || clk->id > 15) + return -EINVAL; + + div = clk->parent->rate / rate; + if (div > 64 || div < 1 || ((clk->parent->rate / div) != rate)) + return -EINVAL; + div--; + + reg = + __raw_readl(pcdr_a[clk->id >> 2]) & ~(MXC_CCM_PCDR1_PERDIV1_MASK << + ((clk->id & 3) << 3)); + reg |= div << ((clk->id & 3) << 3); + __raw_writel(reg, pcdr_a[clk->id >> 2]); + + clk->rate = rate; + + return 0; +} + +static int _clk_perclkx_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long mcr; + + if (parent != &upll_clk && parent != &ahb_clk) + return -EINVAL; + + clk->parent = parent; + mcr = __raw_readl(MXC_CCM_MCR); + if (parent == &upll_clk) + mcr |= (1 << clk->id); + else + mcr &= ~(1 << clk->id); + + __raw_writel(mcr, MXC_CCM_MCR); + + return 0; +} + +static int _clk_perclkx_set_parent3(struct clk *clk, struct clk *parent) +{ + unsigned long mcr = __raw_readl(MXC_CCM_MCR); + int bit; + + if (parent != &upll_clk && parent != &ahb_clk && + parent != &upll_24610k_clk) + return -EINVAL; + + switch (clk->id) { + case 2: + bit = MXC_CCM_MCR_ESAI_CLK_MUX_OFFSET; + break; + case 13: + bit = MXC_CCM_MCR_SSI1_CLK_MUX_OFFSET; + break; + case 14: + bit = MXC_CCM_MCR_SSI2_CLK_MUX_OFFSET; + break; + default: + return -EINVAL; + } + + if (parent == &upll_24610k_clk) { + mcr |= 1 << bit; + __raw_writel(mcr, MXC_CCM_MCR); + clk->parent = parent; + } else { + mcr &= ~(1 << bit); + __raw_writel(mcr, MXC_CCM_MCR); + return _clk_perclkx_set_parent(clk, parent); + } + + return 0; +} + +static void _clk_ipg_recalc(struct clk *clk) +{ + clk->rate = clk->parent->rate / 2; /* Always AHB / 2 */ +} + +static unsigned long _clk_parent_round_rate(struct clk *clk, unsigned long rate) +{ + return clk->parent->round_rate(clk->parent, rate); +} + +static int _clk_parent_set_rate(struct clk *clk, unsigned long rate) +{ + int ret; + + ret = clk->parent->set_rate(clk->parent, rate); + if (ret == 0) + clk->rate = rate; + return ret; +} + +/* Top-level clocks */ + +static struct clk osc24m_clk = { + .name = "osc24m", + .rate = OSC24M_CLK_FREQ, + .flags = RATE_PROPAGATES, +}; + +static struct clk osc32k_clk = { + .name = "osc32k", + .rate = OSC32K_CLK_FREQ, + .flags = RATE_PROPAGATES, +}; + +static struct clk mpll_clk = { + .name = "mpll", + .parent = &osc24m_clk, + .recalc = _clk_pll_recalc, + .flags = RATE_PROPAGATES, +}; + +static struct clk upll_clk = { + .name = "upll", + .parent = &osc24m_clk, + .recalc = _clk_pll_recalc, + .enable = _clk_upll_enable, + .disable = _clk_upll_disable, + .flags = RATE_PROPAGATES, +}; + +static void _clk_24610k_recalc(struct clk *clk) +{ + long long temp = clk->parent->rate * 2461LL; + + do_div(temp, 24000); + + clk->rate = temp; /* Always (UPLL * 24.61 / 240) */ +} + +static struct clk upll_24610k_clk = { + .name = "upll_24610k", + .parent = &upll_clk, + .recalc = _clk_24610k_recalc, + .flags = RATE_PROPAGATES, +}; + +/* Mid-level clocks */ + +static struct clk cpu_clk = { /* ARM clock */ + .name = "cpu_clk", + .parent = &mpll_clk, + .set_rate = _clk_cpu_set_rate, + .recalc = _clk_cpu_recalc, + .round_rate = _clk_cpu_round_rate, + .flags = RATE_PROPAGATES, +}; + +static struct clk ahb_clk = { /* a.k.a. HCLK */ + .name = "ahb_clk", + .parent = &cpu_clk, + .recalc = _clk_ahb_recalc, + .flags = RATE_PROPAGATES, +}; + +static struct clk ipg_clk = { + .name = "ipg_clk", + .parent = &ahb_clk, + .recalc = _clk_ipg_recalc, + .flags = RATE_PROPAGATES, +}; + +/* Bottom-level clocks */ + +struct clk usb_ahb_clk = { + .name = "usb_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_USBOTG_OFFSET, + .disable = _clk_disable, +}; + +struct clk rtic_clk = { + .name = "rtic_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_RTIC_OFFSET, + .disable = _clk_disable, +}; + +struct clk emi_clk = { + .name = "emi_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_EMI_OFFSET, + .disable = _clk_disable, +}; + +struct clk brom_clk = { + .name = "brom_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_BROM_OFFSET, + .disable = _clk_disable, +}; + +static struct clk per_clk[] = { + { + .name = "per_csi_clk", + .id = 0, + .parent = &upll_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_epit_clk", + .id = 1, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_esai_clk", + .id = 2, + .parent = &ahb_clk, /* can be AHB or UPLL or 24.61MHz */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent3, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_esdhc1_clk", + .id = 3, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_esdhc2_clk", + .id = 4, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_gpt_clk", + .id = 5, + .parent = &ahb_clk, /* Must be AHB */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_i2c_clk", + .id = 6, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_lcdc_clk", + .id = 7, + .parent = &upll_clk, /* Must be UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_nfc_clk", + .id = 8, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_owire_clk", + .id = 9, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_pwm_clk", + .id = 10, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_sim1_clk", + .id = 11, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_sim2_clk", + .id = 12, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_ssi1_clk", + .id = 13, + .parent = &ahb_clk, /* can be AHB or UPLL or 24.61MHz */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent3, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_ssi2_clk", + .id = 14, + .parent = &ahb_clk, /* can be AHB or UPLL or 24.61MHz */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent3, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, + { + .name = "per_uart_clk", + .id = 15, + .parent = &ahb_clk, /* can be AHB or UPLL */ + .round_rate = _clk_perclkx_round_rate, + .set_rate = _clk_perclkx_set_rate, + .set_parent = _clk_perclkx_set_parent, + .recalc = _clk_perclkx_recalc, + .enable = _perclk_enable, + .disable = _perclk_disable, + .flags = RATE_PROPAGATES,}, +}; + +struct clk nfc_clk = { + .name = "nfc_clk", + .id = 0, + .parent = &per_clk[8], +}; + +struct clk audmux_clk = { + .name = "audmux_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_AUDMUX_OFFSET, + .disable = _clk_disable, +}; + +struct clk ata_clk[] = { + { + .name = "ata_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ATA_OFFSET, + .disable = _clk_disable, + .secondary = &ata_clk[1],}, + { + .name = "ata_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ATA_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk can_clk[] = { + { + .name = "can_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CAN1_OFFSET, + .disable = _clk_disable,}, + { + .name = "can_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CAN2_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk csi_clk[] = { + { + .name = "csi_clk", + .id = 0, + .parent = &per_clk[0], + .secondary = &csi_clk[1],}, + { + .name = "csi_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSI_OFFSET, + .disable = _clk_disable, + .secondary = &csi_clk[2],}, + { + .name = "csi_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_CSI_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk cspi_clk[] = { + { + .name = "cspi_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSPI1_OFFSET, + .disable = _clk_disable,}, + { + .name = "cspi_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSPI2_OFFSET, + .disable = _clk_disable,}, + { + .name = "cspi_clk", + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_CSPI3_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk dryice_clk = { + .name = "dryice_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_DRYICE_OFFSET, + .disable = _clk_disable, +}; + +struct clk ect_clk = { + .name = "ect_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ECT_OFFSET, + .disable = _clk_disable, +}; + +struct clk epit1_clk[] = { + { + .name = "epit_clk", + .id = 0, + .parent = &per_clk[1], + .secondary = &epit1_clk[1],}, + { + .name = "epit_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_EPIT1_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk epit2_clk[] = { + { + .name = "epit_clk", + .id = 1, + .parent = &per_clk[1], + .secondary = &epit2_clk[1],}, + { + .name = "epit_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_EPIT2_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk esai_clk[] = { + { + .name = "esai_clk", + .id = 0, + .parent = &per_clk[2], + .secondary = &esai_clk[1],}, + { + .name = "esai_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ESAI_OFFSET, + .disable = _clk_disable, + .secondary = &esai_clk[2],}, + { + .name = "esai_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ESAI_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk esdhc1_clk[] = { + { + .name = "esdhc_clk", + .id = 0, + .parent = &per_clk[3], + .secondary = &esdhc1_clk[1],}, + { + .name = "esdhc_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ESDHC1_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc1_clk[2],}, + { + .name = "esdhc_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ESDHC1_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk esdhc2_clk[] = { + { + .name = "esdhc_clk", + .id = 1, + .parent = &per_clk[4], + .secondary = &esdhc2_clk[1],}, + { + .name = "esdhc_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_ESDHC2_OFFSET, + .disable = _clk_disable, + .secondary = &esdhc2_clk[2],}, + { + .name = "esdhc_ahb_clk", + .id = 1, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_ESDHC2_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk fec_clk[] = { + { + .name = "fec_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_FEC_OFFSET, + .disable = _clk_disable, + .secondary = &fec_clk[1],}, + { + .name = "fec_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_FEC_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk gpio_clk[] = { + { + .name = "gpio_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPIO1_OFFSET, + .disable = _clk_disable,}, + { + .name = "gpio_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPIO2_OFFSET, + .disable = _clk_disable,}, + { + .name = "gpio_clk", + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPIO3_OFFSET, + .disable = _clk_disable,}, +}; + +static struct clk gpt1_clk[] = { + { + .name = "gpt_clk", + .id = 0, + .parent = &per_clk[5], + .secondary = &gpt1_clk[1],}, + { + .name = "gpt_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT1_OFFSET, + .disable = _clk_disable,}, +}; + +static struct clk gpt2_clk[] = { + { + .name = "gpt_clk", + .id = 1, + .parent = &per_clk[5], + .secondary = &gpt1_clk[1],}, + { + .name = "gpt_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT2_OFFSET, + .disable = _clk_disable,}, +}; + +static struct clk gpt3_clk[] = { + { + .name = "gpt_clk", + .id = 2, + .parent = &per_clk[5], + .secondary = &gpt1_clk[1],}, + { + .name = "gpt_ipg_clk", + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT3_OFFSET, + .disable = _clk_disable,}, +}; + +static struct clk gpt4_clk[] = { + { + .name = "gpt_clk", + .id = 3, + .parent = &per_clk[5], + .secondary = &gpt1_clk[1],}, + { + .name = "gpt_ipg_clk", + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_GPT4_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk i2c_clk[] = { + { + .name = "i2c_clk", + .id = 0, + .parent = &per_clk[6],}, + { + .name = "i2c_clk", + .id = 1, + .parent = &per_clk[6],}, + { + .name = "i2c_clk", + .id = 2, + .parent = &per_clk[6],}, +}; + +struct clk iim_clk = { + .name = "iim_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_IIM_OFFSET, + .disable = _clk_disable, +}; + +struct clk iomuxc_clk = { + .name = "iomuxc_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_IOMUXC_OFFSET, + .disable = _clk_disable, +}; + +struct clk kpp_clk = { + .name = "kpp_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_KPP_OFFSET, + .disable = _clk_disable, +}; + +struct clk lcdc_clk[] = { + { + .name = "lcdc_clk", + .id = 0, + .parent = &per_clk[7], + .secondary = &lcdc_clk[1], + .round_rate = _clk_parent_round_rate, + .set_rate = _clk_parent_set_rate,}, + { + .name = "lcdc_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_LCDC_OFFSET, + .disable = _clk_disable, + .secondary = &lcdc_clk[2],}, + { + .name = "lcdc_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_LCDC_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk owire_clk[] = { + { + .name = "owire_clk", + .id = 0, + .parent = &per_clk[9], + .secondary = &owire_clk[1],}, + { + .name = "owire_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_OWIRE_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk pwm1_clk[] = { + { + .name = "pwm_clk", + .id = 0, + .parent = &per_clk[10], + .secondary = &pwm1_clk[1],}, + { + .name = "pwm_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR1, + .enable_shift = MXC_CCM_CGCR1_PWM1_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk pwm2_clk[] = { + { + .name = "pwm_clk", + .id = 1, + .parent = &per_clk[10], + .secondary = &pwm2_clk[1],}, + { + .name = "pwm_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_PWM2_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk pwm3_clk[] = { + { + .name = "pwm_clk", + .id = 2, + .parent = &per_clk[10], + .secondary = &pwm3_clk[1],}, + { + .name = "pwm_ipg_clk", + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_PWM3_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk pwm4_clk[] = { + { + .name = "pwm_clk", + .id = 3, + .parent = &per_clk[10], + .secondary = &pwm4_clk[1],}, + { + .name = "pwm_ipg_clk", + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_PWM3_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk rng_clk = { + .name = "rng_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_RNGB_OFFSET, + .disable = _clk_disable, +}; + +struct clk scc_clk = { + .name = "scc_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SCC_OFFSET, + .disable = _clk_disable, +}; + +struct clk sdma_clk[] = { + { + .name = "sdma_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SDMA_OFFSET, + .disable = _clk_disable, + .secondary = &sdma_clk[1],}, + { + .name = "sdma_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_SDMA_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk sim1_clk[] = { + { + .name = "sim1_clk", + .id = 0, + .parent = &per_clk[11], + .secondary = &sim1_clk[1],}, + { + .name = "sim_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SIM1_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk sim2_clk[] = { + { + .name = "sim2_clk", + .id = 1, + .parent = &per_clk[12], + .secondary = &sim2_clk[1],}, + { + .name = "sim_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SIM2_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk slcdc_clk[] = { + { + .name = "slcdc_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SLCDC_OFFSET, + .disable = _clk_disable, + .secondary = &slcdc_clk[1],}, + { + .name = "slcdc_ahb_clk", + .id = 0, + .parent = &ahb_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR0, + .enable_shift = MXC_CCM_CGCR0_HCLK_SLCDC_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk spba_clk = { + .name = "spba_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SPBA_OFFSET, + .disable = _clk_disable, +}; + +struct clk ssi1_clk[] = { + { + .name = "ssi_clk", + .id = 0, + .parent = &per_clk[13], + .secondary = &ssi1_clk[1],}, + { + .name = "ssi_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SSI1_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk ssi2_clk[] = { + { + .name = "ssi_clk", + .id = 1, + .parent = &per_clk[14], + .secondary = &ssi2_clk[1],}, + { + .name = "ssi_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_SSI2_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk tchscrn_clk = { + .name = "tchscrn_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_TCHSCRN_OFFSET, + .disable = _clk_disable, +}; + +struct clk uart1_clk[] = { + { + .name = "uart_clk", + .id = 0, + .parent = &per_clk[15], + .secondary = &uart1_clk[1],}, + { + .name = "uart_ipg_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART1_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk uart2_clk[] = { + { + .name = "uart_clk", + .id = 1, + .parent = &per_clk[15], + .secondary = &uart2_clk[1],}, + { + .name = "uart_ipg_clk", + .id = 1, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART2_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk uart3_clk[] = { + { + .name = "uart_clk", + .id = 2, + .parent = &per_clk[15], + .secondary = &uart3_clk[1],}, + { + .name = "uart_ipg_clk", + .id = 2, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART3_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk uart4_clk[] = { + { + .name = "uart_clk", + .id = 3, + .parent = &per_clk[15], + .secondary = &uart4_clk[1],}, + { + .name = "uart_ipg_clk", + .id = 3, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART4_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk uart5_clk[] = { + { + .name = "uart_clk", + .id = 4, + .parent = &per_clk[15], + .secondary = &uart5_clk[1],}, + { + .name = "uart_ipg_clk", + .id = 4, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_UART5_OFFSET, + .disable = _clk_disable,}, +}; + +struct clk wdog_clk = { + .name = "wdog_clk", + .id = 0, + .parent = &ipg_clk, + .enable = _clk_enable, + .enable_reg = MXC_CCM_CGCR2, + .enable_shift = MXC_CCM_CGCR2_WDOG_OFFSET, + .disable = _clk_disable, +}; + +static unsigned long _clk_usb_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long div; + + div = clk->parent->rate / rate; + if (clk->parent->rate % rate) + div++; + + if (div > 64) + return -EINVAL; + + return clk->parent->rate / div; +} + +static int _clk_usb_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long reg; + unsigned long div; + + div = clk->parent->rate / rate; + + if (clk->parent->rate / div != rate) + return -EINVAL; + if (div > 64) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_CCTL) & ~MXC_CCM_CCTL_USB_DIV_MASK; + reg |= (div - 1) << MXC_CCM_CCTL_USB_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_CCTL); + + return 0; +} + +static void _clk_usb_recalc(struct clk *clk) +{ + unsigned long div = + __raw_readl(MXC_CCM_CCTL) & MXC_CCM_CCTL_USB_DIV_MASK; + + div >>= MXC_CCM_CCTL_USB_DIV_OFFSET; + + clk->rate = clk->parent->rate / (div + 1); +} + +static int _clk_usb_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long mcr; + + if (parent != &upll_clk && parent != &ahb_clk) + return -EINVAL; + + clk->parent = parent; + mcr = __raw_readl(MXC_CCM_MCR); + if (parent == &ahb_clk) + mcr |= (1 << MXC_CCM_MCR_USB_CLK_MUX_OFFSET); + else + mcr &= ~(1 << MXC_CCM_MCR_USB_CLK_MUX_OFFSET); + + __raw_writel(mcr, MXC_CCM_MCR); + + return 0; +} + +static struct clk usb_clk = { + .name = "usb_clk", + .parent = &upll_clk, + .recalc = _clk_usb_recalc, + .set_rate = _clk_usb_set_rate, + .round_rate = _clk_usb_round_rate, + .set_parent = _clk_usb_set_parent, +}; + +/* CLKO */ + +static unsigned long _clk_clko_round_rate(struct clk *clk, unsigned long rate) +{ + unsigned long div; + + div = clk->parent->rate / rate; + if (clk->parent->rate % rate) + div++; + + if (div > 64) + return -EINVAL; + + return clk->parent->rate / div; +} + +static int _clk_clko_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long reg; + unsigned long div; + + div = clk->parent->rate / rate; + + if ((clk->parent->rate / div) != rate) + return -EINVAL; + if (div > 64) + return -EINVAL; + + reg = __raw_readl(MXC_CCM_MCR) & ~MXC_CCM_MCR_CLKO_DIV_MASK; + reg |= (div - 1) << MXC_CCM_MCR_CLKO_DIV_OFFSET; + __raw_writel(reg, MXC_CCM_MCR); + + return 0; +} + +static void _clk_clko_recalc(struct clk *clk) +{ + unsigned long div = + __raw_readl(MXC_CCM_MCR) & MXC_CCM_MCR_CLKO_DIV_MASK; + + div >>= MXC_CCM_MCR_CLKO_DIV_OFFSET; + + clk->rate = clk->parent->rate / (div + 1); +} + +static struct clk *clko_sources[] = { + &osc32k_clk, /* 0x0 */ + &osc24m_clk, /* 0x1 */ + &cpu_clk, /* 0x2 */ + &ahb_clk, /* 0x3 */ + &ipg_clk, /* 0x4 */ + NULL, /* 0x5 */ + NULL, /* 0x6 */ + NULL, /* 0x7 */ + NULL, /* 0x8 */ + NULL, /* 0x9 */ + &per_clk[0], /* 0xA */ + &per_clk[2], /* 0xB */ + &per_clk[13], /* 0xC */ + &per_clk[14], /* 0xD */ + &usb_clk, /* 0xE */ + NULL, /* 0xF */ +}; + +#define NR_CLKO_SOURCES (sizeof(clko_sources) / sizeof(struct clk *)) + +static int _clk_clko_set_parent(struct clk *clk, struct clk *parent) +{ + unsigned long reg = + __raw_readl(MXC_CCM_MCR) & ~MXC_CCM_MCR_CLKO_SEL_MASK; + struct clk **src; + int i; + + for (i = 0, src = clko_sources; i < NR_CLKO_SOURCES; i++, src++) + if (*src == parent) + break; + + if (i == NR_CLKO_SOURCES) + return -EINVAL; + + clk->parent = parent; + + reg |= i << MXC_CCM_MCR_CLKO_SEL_OFFSET; + + __raw_writel(reg, MXC_CCM_MCR); + + return 0; +} + +static struct clk clko_clk = { + .name = "clko_clk", + .recalc = _clk_clko_recalc, + .set_rate = _clk_clko_set_rate, + .round_rate = _clk_clko_round_rate, + .set_parent = _clk_clko_set_parent, + .enable = _clk_enable, + .enable_reg = MXC_CCM_MCR, + .enable_shift = MXC_CCM_MCR_CLKO_EN_OFFSET, + .disable = _clk_disable, +}; + +static struct clk *mxc_clks[] = { + &osc24m_clk, + &osc32k_clk, + &mpll_clk, + &upll_clk, + &cpu_clk, + &ahb_clk, + &ipg_clk, + &usb_ahb_clk, + &per_clk[0], + &per_clk[1], + &per_clk[2], + &per_clk[3], + &per_clk[4], + &per_clk[5], + &per_clk[6], + &per_clk[7], + &per_clk[8], + &per_clk[9], + &per_clk[10], + &per_clk[11], + &per_clk[12], + &per_clk[13], + &per_clk[14], + &per_clk[15], + &nfc_clk, + &audmux_clk, + &ata_clk[0], + &ata_clk[1], + &can_clk[0], + &can_clk[1], + &csi_clk[0], + &csi_clk[1], + &csi_clk[2], + &cspi_clk[0], + &cspi_clk[1], + &cspi_clk[2], + &dryice_clk, + &ect_clk, + &epit1_clk[0], + &epit1_clk[1], + &epit2_clk[0], + &epit2_clk[1], + &esai_clk[0], + &esai_clk[1], + &esai_clk[2], + &esdhc1_clk[0], + &esdhc1_clk[1], + &esdhc1_clk[2], + &esdhc2_clk[0], + &esdhc2_clk[1], + &esdhc2_clk[2], + &fec_clk[0], + &fec_clk[1], + &gpio_clk[0], + &gpio_clk[1], + &gpio_clk[2], + &gpt1_clk[0], + &gpt1_clk[1], + &gpt2_clk[0], + &gpt2_clk[1], + &gpt3_clk[0], + &gpt3_clk[1], + &gpt4_clk[0], + &gpt4_clk[1], + &i2c_clk[0], + &i2c_clk[1], + &i2c_clk[2], + &iim_clk, + &iomuxc_clk, + &kpp_clk, + &lcdc_clk[0], + &lcdc_clk[1], + &lcdc_clk[2], + &owire_clk[0], + &owire_clk[1], + &pwm1_clk[0], + &pwm1_clk[1], + &pwm2_clk[0], + &pwm2_clk[1], + &pwm3_clk[0], + &pwm3_clk[1], + &pwm4_clk[0], + &pwm4_clk[1], + &rng_clk, + &scc_clk, + &sdma_clk[0], + &sdma_clk[1], + &sim1_clk[0], + &sim1_clk[1], + &sim2_clk[0], + &sim2_clk[1], + &slcdc_clk[0], + &slcdc_clk[1], + &spba_clk, + &ssi1_clk[0], + &ssi1_clk[1], + &ssi2_clk[0], + &ssi2_clk[1], + &tchscrn_clk, + &uart1_clk[0], + &uart1_clk[1], + &uart2_clk[0], + &uart2_clk[1], + &uart3_clk[0], + &uart3_clk[1], + &uart4_clk[0], + &uart4_clk[1], + &uart5_clk[0], + &uart5_clk[1], + &wdog_clk, + &usb_clk, + &clko_clk, +}; + +/*! + * Function to get timer clock rate early in boot process before clock tree is + * initialized. + * + * @return Clock rate for timer + */ +unsigned long __init clk_early_get_timer_rate(void) +{ + upll_clk.recalc(&upll_clk); + per_clk[5].recalc(&per_clk[5]); + per_clk[5].enable(&per_clk[5]); + + return per_clk[5].rate; +} + +extern void propagate_rate(struct clk *tclk); + +int __init mx25_clocks_init(unsigned long fref) +{ + int i; + struct clk **clkp; + + for (clkp = mxc_clks; clkp < mxc_clks + ARRAY_SIZE(mxc_clks); clkp++) + clk_register(*clkp); + + /* Turn off all possible clocks */ + __raw_writel((1 << MXC_CCM_CGCR0_HCLK_EMI_OFFSET), MXC_CCM_CGCR0); + + __raw_writel((1 << MXC_CCM_CGCR1_GPT1_OFFSET) | + (1 << MXC_CCM_CGCR1_IIM_OFFSET), MXC_CCM_CGCR1); + __raw_writel(1 << MXC_CCM_CGCR2_SCC_OFFSET, MXC_CCM_CGCR2); + + /* Init all perclk sources to ahb clock*/ + for (i = 0; i < (sizeof(per_clk) / sizeof(struct clk)); i++) + per_clk[i].set_parent(&per_clk[i], &ahb_clk); + + /* This will propagate to all children and init all the clock rates */ + propagate_rate(&osc24m_clk); + propagate_rate(&osc32k_clk); + + /* GPT clock must be derived from AHB clock */ + clk_set_rate(&per_clk[5], ahb_clk.rate / 10); + + /* LCDC clock must be derived from UPLL clock */ + clk_set_parent(&per_clk[7], &upll_clk); + clk_set_rate(&per_clk[7], upll_clk.rate); + + /* the NFC clock must be derived from AHB clock */ + clk_set_parent(&per_clk[8], &ahb_clk); + clk_set_rate(&per_clk[8], ahb_clk.rate / 6); + + /* sim clock */ + clk_set_rate(&per_clk[11], ahb_clk.rate / 2); + + /* the csi clock must be derived from UPLL clock */ + clk_set_parent(&per_clk[0], &upll_clk); + clk_set_rate(&per_clk[0], upll_clk.rate / 5); + + pr_info("Clock input source is %ld\n", osc24m_clk.rate); + + clk_enable(&emi_clk); + clk_enable(&gpio_clk[0]); + clk_enable(&gpio_clk[1]); + clk_enable(&gpio_clk[2]); + clk_enable(&iim_clk); + clk_enable(&gpt1_clk[0]); + clk_enable(&iomuxc_clk); + clk_enable(&scc_clk); + + mxc_timer_init(&gpt1_clk[0], IO_ADDRESS(GPT1_BASE_ADDR), MXC_INT_GPT1); + return 0; +} |