rk29: add clock
author黄涛 <huangtao@rock-chips.com>
Sat, 23 Oct 2010 07:45:50 +0000 (15:45 +0800)
committer黄涛 <huangtao@rock-chips.com>
Sat, 23 Oct 2010 07:45:50 +0000 (15:45 +0800)
arch/arm/Kconfig
arch/arm/mach-rk29/Makefile
arch/arm/mach-rk29/board-rk29sdk.c
arch/arm/mach-rk29/clock.c [new file with mode: 0644]
arch/arm/mach-rk29/include/mach/board.h
arch/arm/mach-rk29/include/mach/cru.h [new file with mode: 0644]
arch/arm/mach-rk29/include/mach/rk29_iomap.h
arch/arm/mach-rk29/io.c
arch/arm/mach-rk29/timer.c

index e1007715a7debc1e41c0aa4213a8f67a9885b586..b35fec253dec861d6079b2d4b475fd6fe8949ce5 100644 (file)
@@ -720,6 +720,8 @@ config ARCH_RK29
        bool "Rockchip Soc Rk29"
        select HAVE_CLK
        select CPU_V7
+       select HAVE_CLK
+       select COMMON_CLKDEV
        select GENERIC_TIME
        select GENERIC_CLOCKEVENTS
         select ARM_GIC
index e9fb9849bdf7ce531dc1424c87cd491b71f982e8..027b83305c67cdac1d7d4c14949ba73043e126fc 100644 (file)
@@ -1,2 +1,2 @@
-obj-y += timer.o io.o devices.o iomux.o 
+obj-y += timer.o io.o devices.o iomux.o clock.o
 obj-$(CONFIG_MACH_RK29SDK) += board-rk29sdk.o
index 234f7415f23e74f982b8c5c08006200d28309cb3..9191fc992dc3b09e9a5827156f486730b61a746e 100644 (file)
@@ -69,7 +69,7 @@ static void __init machine_rk29_board_init(void)
 static void __init machine_rk29_mapio(void)\r
 {\r
        rk29_map_common_io();\r
-       //rk29_clock_init();\r
+       rk29_clock_init();\r
        //rk29_iomux_init();    \r
 }\r
 \r
diff --git a/arch/arm/mach-rk29/clock.c b/arch/arm/mach-rk29/clock.c
new file mode 100644 (file)
index 0000000..2452d0f
--- /dev/null
@@ -0,0 +1,1681 @@
+/* arch/arm/mach-rk29/clock.c
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#define DEBUG
+#define pr_fmt(fmt) "clock: %s: " fmt, __func__
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/clkdev.h>
+#include <mach/rk29_iomap.h>
+#include <mach/cru.h>
+
+/* CRU PLL CON */
+#define PLL_BAND       (0x01 << 16)
+#define PLL_PD         (0x01 << 15)
+
+#define PLL_CLKR(i)    ((((i) - 1) << & 0x1f) << 10)
+#define PLL_NR(v)      ((((v) >> 10) & 0x1f) + 1)
+
+#define PLL_CLKF(i)    ((((i) - 1) & 0x7f) << 3)
+#define PLL_NF(v)      ((((v) >> 3) & 0x7f) + 1)
+#define PLL_NF2(v)     (((((v) >> 3) & 0x7f) + 1) << 1)
+
+#define PLL_CLKOD(i)   (((i) & 0x03) << 1)
+#define PLL_NO_1       PLL_CLKOD(0)
+#define PLL_NO_2       PLL_CLKOD(1)
+#define PLL_NO_4       PLL_CLKOD(2)
+#define PLL_NO_8       PLL_CLKOD(3)
+#define PLL_NO_SHIFT(v)        (((v) >> 1) & 0x03)
+
+#define PLL_BYPASS     (0x01)
+
+/* CRU MODE CON */
+#define CRU_CPU_MODE_MASK      (0x03u << 0)
+#define CRU_CPU_MODE_SLOW      (0x00u << 0)
+#define CRU_CPU_MODE_NORMAL    (0x01u << 0)
+#define CRU_CPU_MODE_DSLOW     (0x02u << 0)
+
+#define CRU_PERIPH_MODE_MASK   (0x03u << 2)
+#define CRU_PERIPH_MODE_SLOW   (0x00u << 2)
+#define CRU_PERIPH_MODE_NORMAL (0x01u << 2)
+#define CRU_PERIPH_MODE_DSLOW  (0x02u << 2)
+
+#define CRU_CODEC_MODE_MASK    (0x03u << 4)
+#define CRU_CODEC_MODE_SLOW    (0x00u << 4)
+#define CRU_CODEC_MODE_NORMAL  (0x01u << 4)
+#define CRU_CODEC_MODE_DSLOW   (0x02u << 4)
+
+#define CRU_DDR_MODE_MASK      (0x03u << 6)
+#define CRU_DDR_MODE_SLOW      (0x00u << 6)
+#define CRU_DDR_MODE_NORMAL    (0x01u << 6)
+#define CRU_DDR_MODE_DSLOW     (0x02u << 6)
+
+/* Clock flags */
+/* bit 0 is free */
+#define RATE_FIXED             (1 << 1)        /* Fixed clock rate */
+#define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
+#define ENABLE_ON_INIT         (1 << 11)       /* Enable upon framework init */
+
+#define cru_readl(offset)      readl(RK29_CRU_BASE + offset)
+#define cru_writel(v, offset)  writel(v, RK29_CRU_BASE + offset)
+#define cru_writel_force(v, offset)    do { u32 _v = v; u32 _count = 5; do { cru_writel(_v, offset); } while (cru_readl(offset) != _v && _count--); } while (0)        /* huangtao: when write CRU_xPLL_CON, first time may failed, so try again. unknown why. */
+
+struct clk {
+       struct list_head        node;
+       const char              *name;
+       struct clk              *parent;
+       struct list_head        children;
+       struct list_head        sibling;        /* node for children */
+       unsigned long           rate;
+       u32                     flags;
+       int                     (*mode)(struct clk *clk, int on);
+       unsigned long           (*recalc)(struct clk *);        /* if null, follow parent */
+       int                     (*set_rate)(struct clk *, unsigned long);
+       long                    (*round_rate)(struct clk *, unsigned long);
+       struct clk*             (*get_parent)(struct clk *);    /* get clk's parent from the hardware. default is clksel_get_parent if parents present */
+       int                     (*set_parent)(struct clk *, struct clk *);      /* default is clksel_set_parent if parents present */
+       s32                     usecount;
+       u8                      gate_idx;
+       u8                      pll_idx;
+       u8                      clksel_con;
+       u8                      clksel_mask;
+       u8                      clksel_shift;
+       u8                      clksel_maxdiv;
+       u8                      clksel_parent_mask;
+       u8                      clksel_parent_shift;
+       struct clk              **parents;
+};
+
+int ddr_disabled = 0;
+
+static void __clk_disable(struct clk *clk);
+static void __clk_reparent(struct clk *child, struct clk *parent);
+static void __propagate_rate(struct clk *tclk);
+
+static unsigned long clksel_recalc_div(struct clk *clk)
+{
+       u32 div = ((cru_readl(clk->clksel_con) >> clk->clksel_shift) & clk->clksel_mask) + 1;
+       unsigned long rate = clk->parent->rate / div;
+       pr_debug("%s new clock rate is %lu (div %u)\n", clk->name, rate, div);
+       return rate;
+}
+
+static unsigned long clksel_recalc_shift(struct clk *clk)
+{
+       u32 shift = (cru_readl(clk->clksel_con) >> clk->clksel_shift) & clk->clksel_mask;
+       unsigned long rate = clk->parent->rate >> shift;
+       pr_debug("%s new clock rate is %lu (shift %u)\n", clk->name, rate, shift);
+       return rate;
+}
+
+static unsigned long clksel_recalc_frac(struct clk *clk)
+{
+       unsigned long rate;
+       u64 rate64;
+       u32 r = cru_readl(clk->clksel_con), numerator, denominator;
+       if (r == 0) // FPGA ?
+               return clk->parent->rate;
+       numerator = r >> 16;
+       denominator = r & 0xFFFF;
+       rate64 = (u64)clk->parent->rate * numerator;
+       do_div(rate64, denominator);
+       rate = rate64;
+       pr_debug("%s new clock rate is %lu (frac %u/%u)\n", clk->name, rate, numerator, denominator);
+       return rate;
+}
+
+static int clksel_set_rate_div(struct clk *clk, unsigned long rate)
+{
+       u32 div;
+
+       for (div = 0; div <= clk->clksel_mask; div++) {
+               u32 new_rate = clk->parent->rate / (div + 1);
+               if (new_rate <= rate) {
+                       u32 v = cru_readl(clk->clksel_con);
+                       v &= ~((u32) clk->clksel_mask << clk->clksel_shift);
+                       v |= div << clk->clksel_shift;
+                       cru_writel(v, clk->clksel_con);
+                       clk->rate = new_rate;
+                       pr_debug("clksel_set_rate_div for clock %s to rate %ld (div %d)\n", clk->name, rate, div + 1);
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
+static int clksel_set_rate_shift(struct clk *clk, unsigned long rate)
+{
+       u32 shift;
+
+       for (shift = 0; (1 << shift) <= clk->clksel_maxdiv; shift++) {
+               u32 new_rate = clk->parent->rate >> shift;
+               if (new_rate <= rate) {
+                       u32 v = cru_readl(clk->clksel_con);
+                       v &= ~((u32) clk->clksel_mask << clk->clksel_shift);
+                       v |= shift << clk->clksel_shift;
+                       cru_writel(v, clk->clksel_con);
+                       clk->rate = new_rate;
+                       pr_debug("clksel_set_rate_shift for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift);
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+
+static struct clk* clksel_get_parent(struct clk *clk)
+{
+       return clk->parents[(cru_readl(clk->clksel_con) >> clk->clksel_parent_shift) & clk->clksel_parent_mask];
+}
+
+static int clksel_set_parent(struct clk *clk, struct clk *parent)
+{
+       struct clk **p = clk->parents;
+       u32 i;
+
+       if (unlikely(!p))
+               return -EINVAL;
+       for (i = 0; (i <= clk->clksel_parent_mask) && *p; i++, p++) {
+               u32 v;
+               if (*p != parent)
+                       continue;
+               v = cru_readl(clk->clksel_con);
+               v &= ~((u32) clk->clksel_parent_mask << clk->clksel_parent_shift);
+               v |= (i << clk->clksel_parent_shift);
+               cru_writel(v, clk->clksel_con);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int gate_mode(struct clk *clk, int on)
+{
+       u32 reg;
+       int idx = clk->gate_idx;
+       u32 v;
+
+       if (idx >= CLK_GATE_MAX)
+               return -EINVAL;
+
+       reg = CRU_CLKGATE0_CON;
+       reg += (idx >> 5) << 2;
+       idx &= 0x1F;
+
+       v = cru_readl(reg);
+       if (on) {
+               v &= ~(1 << idx);       // clear bit 
+       } else {
+               v |= (1 << idx);        // set bit
+       }
+       cru_writel(v, reg);
+
+       return 0;
+}
+
+static struct clk xin24m = {
+       .name           = "xin24m",
+       .rate           = 24000000,
+       .flags          = RATE_FIXED,
+};
+
+static struct clk clk_12m = {
+       .name           = "clk_12m",
+       .rate           = 12000000,
+       .parent         = &xin24m,
+       .flags          = RATE_FIXED,
+};
+
+static struct clk extclk = {
+       .name           = "extclk",
+       .rate           = 27000000,
+       .flags          = RATE_FIXED,
+};
+
+static struct clk otgphy0_clkin = {
+       .name           = "otgphy0_clkin",
+       .rate           = 480000000,
+       .flags          = RATE_FIXED,
+};
+
+static struct clk otgphy1_clkin = {
+       .name           = "otgphy1_clkin",
+       .rate           = 480000000,
+       .flags          = RATE_FIXED,
+};
+
+
+static unsigned long arm_pll_clk_recalc(struct clk *clk)
+{
+       unsigned long rate;
+
+       if ((cru_readl(CRU_MODE_CON) & CRU_CPU_MODE_MASK) == CRU_CPU_MODE_NORMAL) {
+               u32 v = cru_readl(CRU_APLL_CON);
+               u64 rate64 = (u64) clk->parent->rate * PLL_NF2(v);
+               do_div(rate64, PLL_NR(v));
+               rate = rate64 >> PLL_NO_SHIFT(v);
+               pr_debug("%s new clock rate is %ld (NF %d NR %d NO %d)\n", clk->name, rate, PLL_NF2(v), PLL_NR(v), 1 << PLL_NO_SHIFT(v));
+       } else {
+               rate = clk->parent->rate;
+               pr_debug("%s new clock rate is %ld (slow mode)\n", clk->name, rate);
+       }
+
+       return rate;
+}
+
+static struct clk arm_pll_clk = {
+       .name           = "arm_pll",
+       .parent         = &xin24m,
+       .recalc         = arm_pll_clk_recalc,
+};
+
+static unsigned long ddr_pll_clk_recalc(struct clk *clk)
+{
+       unsigned long rate;
+
+       if ((cru_readl(CRU_MODE_CON) & CRU_DDR_MODE_MASK) == CRU_DDR_MODE_NORMAL) {
+               u32 v = cru_readl(CRU_DPLL_CON);
+               u64 rate64 = (u64) clk->parent->rate * PLL_NF(v);
+               do_div(rate64, PLL_NR(v));
+               rate = rate64 >> PLL_NO_SHIFT(v);
+               pr_debug("%s new clock rate is %ld (NF %d NR %d NO %d)\n", clk->name, rate, PLL_NF(v), PLL_NR(v), 1 << PLL_NO_SHIFT(v));
+       } else {
+               rate = clk->parent->rate;
+               pr_debug("%s new clock rate is %ld (slow mode)\n", clk->name, rate);
+       }
+
+       return rate;
+}
+
+static struct clk ddr_pll_clk = {
+       .name           = "ddr_pll",
+       .parent         = &xin24m,
+       .recalc         = ddr_pll_clk_recalc,
+};
+
+
+static unsigned long codec_pll_clk_recalc(struct clk *clk)
+{
+       unsigned long rate;
+
+       if ((cru_readl(CRU_MODE_CON) & CRU_CODEC_MODE_MASK) == CRU_CODEC_MODE_NORMAL) {
+               u32 v = cru_readl(CRU_CPLL_CON);
+               u64 rate64 = (u64) clk->parent->rate * PLL_NF(v);
+               do_div(rate64, PLL_NR(v));
+               rate = rate64 >> PLL_NO_SHIFT(v);
+               pr_debug("%s new clock rate is %ld (NF %d NR %d NO %d)\n", clk->name, rate, PLL_NF(v), PLL_NR(v), 1 << PLL_NO_SHIFT(v));
+       } else {
+               rate = clk->parent->rate;
+               pr_debug("%s new clock rate is %ld (slow mode)\n", clk->name, rate);
+       }
+
+       return rate;
+}
+
+static struct clk codec_pll_clk = {
+       .name           = "codec_pll",
+       .parent         = &xin24m,
+       .recalc         = codec_pll_clk_recalc,
+};
+
+
+static unsigned long periph_pll_clk_recalc(struct clk *clk)
+{
+       unsigned long rate;
+
+       if ((cru_readl(CRU_MODE_CON) & CRU_CODEC_MODE_MASK) == CRU_CODEC_MODE_NORMAL) {
+               u32 v = cru_readl(CRU_CPLL_CON);
+               u64 rate64 = (u64) clk->parent->rate * PLL_NF(v);
+               do_div(rate64, PLL_NR(v));
+               rate = rate64 >> PLL_NO_SHIFT(v);
+               pr_debug("%s new clock rate is %ld (NF %d NR %d NO %d)\n", clk->name, rate, PLL_NF(v), PLL_NR(v), 1 << PLL_NO_SHIFT(v));
+       } else {
+               rate = clk->parent->rate;
+               pr_debug("%s new clock rate is %ld (slow mode)\n", clk->name, rate);
+       }
+
+       return rate;
+}
+
+static struct clk periph_pll_clk = {
+       .name           = "periph_pll",
+       .parent         = &xin24m,
+       .recalc         = periph_pll_clk_recalc,
+};
+
+
+static struct clk clk_core = {
+       .name           = "core",
+       .parent         = &arm_pll_clk,
+       .recalc         = clksel_recalc_div,
+       .clksel_con     = CRU_CLKSEL0_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 0,
+};
+
+static unsigned long aclk_cpu_recalc(struct clk *clk)
+{
+       unsigned long rate;
+       u32 div = ((cru_readl(CRU_CLKSEL0_CON) >> 5) & 0x7) + 1;
+
+       BUG_ON(div > 5);
+       if (div >= 5)
+               div = 8;
+       rate = clk->parent->rate / div;
+       pr_debug("%s new clock rate is %ld (div %d)\n", clk->name, rate, div);
+
+       return rate;
+}
+
+static struct clk aclk_cpu = {
+       .name           = "aclk_cpu",
+       .parent         = &clk_core,
+       .recalc         = aclk_cpu_recalc,
+};
+
+static struct clk hclk_cpu = {
+       .name           = "hclk_cpu",
+       .parent         = &aclk_cpu,
+       .recalc         = clksel_recalc_shift,
+       .clksel_con     = CRU_CLKSEL0_CON,
+       .clksel_mask    = 3,
+       .clksel_shift   = 8,
+       .clksel_maxdiv  = 4,
+};
+
+static struct clk pclk_cpu = {
+       .name           = "pclk_cpu",
+       .parent         = &aclk_cpu,
+       .recalc         = clksel_recalc_shift,
+       .clksel_con     = CRU_CLKSEL0_CON,
+       .clksel_mask    = 3,
+       .clksel_shift   = 10,
+       .clksel_maxdiv  = 8,
+};
+
+static struct clk aclk_periph = {
+       .name           = "aclk_periph",
+       .parent         = &periph_pll_clk,
+       .recalc         = clksel_recalc_div,
+       .clksel_con     = CRU_CLKSEL0_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 14,
+};
+
+static struct clk pclk_periph = {
+       .name           = "pclk_periph",
+       .parent         = &aclk_periph,
+       .recalc         = clksel_recalc_shift,
+       .clksel_con     = CRU_CLKSEL0_CON,
+       .clksel_mask    = 3,
+       .clksel_shift   = 19,
+       .clksel_maxdiv  = 8,
+};
+
+static struct clk hclk_periph = {
+       .name           = "hclk_periph",
+       .parent         = &aclk_periph,
+       .recalc         = clksel_recalc_shift,
+       .clksel_con     = CRU_CLKSEL0_CON,
+       .clksel_mask    = 3,
+       .clksel_shift   = 21,
+       .clksel_maxdiv  = 4,
+};
+
+
+static struct clk *clk_uhost_parents[8] = { &periph_pll_clk, &ddr_pll_clk, &codec_pll_clk, &arm_pll_clk, &otgphy0_clkin, &otgphy1_clkin };
+
+static struct clk clk_uhost = {
+       .name           = "uhost",
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_UHOST,
+       .clksel_con     = CRU_CLKSEL1_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 16,
+       .clksel_parent_mask     = 7,
+       .clksel_parent_shift    = 13,
+       .parents        = clk_uhost_parents,
+};
+
+static struct clk *clk_otgphy_parents[4] = { &xin24m, &clk_12m, &clk_uhost };
+
+static struct clk clk_otgphy0 = {
+       .name           = "otgphy0",
+       .clksel_con     = CRU_CLKSEL1_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 9,
+       .parents        = clk_otgphy_parents,
+};
+
+static struct clk clk_otgphy1 = {
+       .name           = "otgphy1",
+       .clksel_con     = CRU_CLKSEL1_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 11,
+       .parents        = clk_otgphy_parents,
+};
+
+
+static struct clk rmii_clkin = {
+       .name           = "rmii_clkin",
+};
+
+static struct clk *clk_mac_ref_div_parents[4] = { &arm_pll_clk, &periph_pll_clk, &codec_pll_clk, &ddr_pll_clk };
+
+static struct clk clk_mac_ref_div = {
+       .name           = "mac_ref_div",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL1_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 23,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 21,
+       .parents        = clk_mac_ref_div_parents,
+};
+
+static struct clk *clk_mac_ref_parents[2] = { &clk_mac_ref_div, &rmii_clkin };
+
+static struct clk clk_mac_ref = {
+       .name           = "mac_ref",
+       .clksel_con     = CRU_CLKSEL1_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 28,
+       .parents        = clk_mac_ref_parents,
+};
+
+
+static struct clk *clk_i2s_div_parents[8] = { &codec_pll_clk, &periph_pll_clk, &arm_pll_clk, &ddr_pll_clk, &otgphy0_clkin, &otgphy1_clkin };
+
+static struct clk clk_i2s0_div = {
+       .name           = "i2s0_div",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL2_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 3,
+       .clksel_parent_mask     = 7,
+       .clksel_parent_shift    = 0,
+       .parents        = clk_i2s_div_parents,
+};
+
+static struct clk clk_i2s1_div = {
+       .name           = "i2s1_div",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL2_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 13,
+       .clksel_parent_mask     = 7,
+       .clksel_parent_shift    = 10,
+       .parents        = clk_i2s_div_parents,
+};
+
+static struct clk clk_spdif_div = {
+       .name           = "spdif_div",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL2_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 23,
+       .clksel_parent_mask     = 7,
+       .clksel_parent_shift    = 20,
+       .parents        = clk_i2s_div_parents,
+};
+
+static struct clk clk_i2s0_frac_div = {
+       .name           = "i2s0_frac_div",
+       .parent         = &clk_i2s0_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL3_CON,
+};
+
+static struct clk clk_i2s1_frac_div = {
+       .name           = "i2s1_frac_div",
+       .parent         = &clk_i2s1_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL4_CON,
+};
+
+static struct clk clk_spdif_frac_div = {
+       .name           = "spdif_frac_div",
+       .parent         = &clk_spdif_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL5_CON,
+};
+
+static struct clk *clk_i2s0_parents[4] = { &clk_i2s0_div, &clk_i2s0_frac_div, &clk_12m, &xin24m };
+
+static struct clk clk_i2s0 = {
+       .name           = "i2s0",
+       .clksel_con     = CRU_CLKSEL2_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 8,
+       .parents        = clk_i2s0_parents,
+};
+
+static struct clk *clk_i2s1_parents[4] = { &clk_i2s1_div, &clk_i2s1_frac_div, &clk_12m, &xin24m };
+
+static struct clk clk_i2s1 = {
+       .name           = "i2s1",
+       .clksel_con     = CRU_CLKSEL2_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 18,
+       .parents        = clk_i2s1_parents,
+};
+
+static struct clk *clk_spdif_parents[4] = { &clk_spdif_div, &clk_spdif_frac_div, &clk_12m, &xin24m };
+
+static struct clk clk_spdif = {
+       .name           = "spdif",
+       .clksel_con     = CRU_CLKSEL2_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 28,
+       .parents        = clk_spdif_parents,
+};
+
+
+static struct clk *clk_spi_src_parents[4] = { &periph_pll_clk, &ddr_pll_clk, &codec_pll_clk, &arm_pll_clk };
+
+static struct clk clk_spi_src = {
+       .name           = "spi_src",
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 0,
+       .parents        = clk_spi_src_parents,
+};
+
+static struct clk clk_spi0 = {
+       .name           = "spi0",
+       .parent         = &clk_spi_src,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_SPI0,
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_mask    = 0x7F,
+       .clksel_shift   = 2,
+};
+
+static struct clk clk_spi1 = {
+       .name           = "spi1",
+       .parent         = &clk_spi_src,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_SPI1,
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_mask    = 0x7F,
+       .clksel_shift   = 11,
+};
+
+
+static struct clk clk_saradc = {
+       .name           = "saradc",
+       .parent         = &pclk_periph,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_SARADC,
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_mask    = 0xFF,
+       .clksel_shift   = 18,
+};
+
+
+static struct clk *clk_cpu_timer_parents[2] = { &pclk_cpu, &xin24m };
+
+static struct clk clk_timer0 = {
+       .name           = "timer0",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_TIMER0,
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 26,
+       .parents        = clk_cpu_timer_parents,
+};
+
+static struct clk clk_timer1 = {
+       .name           = "timer1",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_TIMER1,
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 27,
+       .parents        = clk_cpu_timer_parents,
+};
+
+static struct clk *clk_periph_timer_parents[2] = { &pclk_periph, &xin24m };
+
+static struct clk clk_timer2 = {
+       .name           = "timer2",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_TIMER2,
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 28,
+       .parents        = clk_periph_timer_parents,
+};
+
+static struct clk clk_timer3 = {
+       .name           = "timer3",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_TIMER3,
+       .clksel_con     = CRU_CLKSEL6_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 29,
+       .parents        = clk_periph_timer_parents,
+};
+
+
+static struct clk *clk_sdmmc_src_parents[4] = { &arm_pll_clk, &periph_pll_clk, &codec_pll_clk, &ddr_pll_clk };
+
+static struct clk clk_sdmmc_src = {
+       .name           = "sdmmc_src",
+       .clksel_con     = CRU_CLKSEL7_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 0,
+       .parents        = clk_sdmmc_src_parents,
+};
+
+static struct clk clk_sdmmc0 = {
+       .name           = "sdmmc0",
+       .parent         = &clk_sdmmc_src,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_SDMMC0,
+       .clksel_con     = CRU_CLKSEL7_CON,
+       .clksel_mask    = 0x3F,
+       .clksel_shift   = 2,
+};
+
+static struct clk clk_sdmmc1 = {
+       .name           = "sdmmc1",
+       .parent         = &clk_sdmmc_src,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_SDMMC1,
+       .clksel_con     = CRU_CLKSEL7_CON,
+       .clksel_mask    = 0x3F,
+       .clksel_shift   = 10,
+};
+
+static struct clk clk_emmc = {
+       .name           = "emmc",
+       .parent         = &clk_sdmmc_src,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_EMMC,
+       .clksel_con     = CRU_CLKSEL7_CON,
+       .clksel_mask    = 0x3F,
+       .clksel_shift   = 18,
+};
+
+
+static struct clk *clk_ddr_parents[8] = { &ddr_pll_clk, &periph_pll_clk, &codec_pll_clk, &arm_pll_clk };
+
+static struct clk clk_ddr = {
+       .name           = "ddr",
+       .recalc         = clksel_recalc_shift,
+       .clksel_con     = CRU_CLKSEL7_CON,
+       .clksel_mask    = 7,
+       .clksel_shift   = 26,
+       .clksel_maxdiv  = 32,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 24,
+       .parents        = clk_ddr_parents,
+};
+
+
+static struct clk *clk_uart_src_parents[8] = { &periph_pll_clk, &ddr_pll_clk, &codec_pll_clk, &arm_pll_clk, &otgphy0_clkin, &otgphy1_clkin };
+
+static struct clk clk_uart01_src = {
+       .name           = "uart01_src",
+       .clksel_con     = CRU_CLKSEL8_CON,
+       .clksel_parent_mask     = 7,
+       .clksel_parent_shift    = 0,
+       .parents        = clk_uart_src_parents,
+};
+
+static struct clk clk_uart0_div = {
+       .name           = "uart0_div",
+       .parent         = &clk_uart01_src,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL8_CON,
+       .clksel_mask    = 0x3F,
+       .clksel_shift   = 3,
+};
+
+static struct clk clk_uart0_frac_div = {
+       .name           = "uart0_frac_div",
+       .parent         = &clk_uart0_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL10_CON,
+};
+
+static struct clk *clk_uart0_parents[4] = { &clk_uart0_div, &clk_uart0_frac_div, &xin24m };
+
+static struct clk clk_uart0 = {
+       .name           = "uart0",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART0,
+       .clksel_con     = CRU_CLKSEL8_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 9,
+       .parents        = clk_uart0_parents,
+};
+
+static struct clk clk_uart1_div = {
+       .name           = "uart1_div",
+       .parent         = &clk_uart01_src,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL8_CON,
+       .clksel_mask    = 0x3F,
+       .clksel_shift   = 14,
+};
+
+static struct clk clk_uart1_frac_div = {
+       .name           = "uart1_frac_div",
+       .parent         = &clk_uart1_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL11_CON,
+};
+
+static struct clk *clk_uart1_parents[4] = { &clk_uart1_div, &clk_uart1_frac_div, &xin24m };
+
+static struct clk clk_uart1 = {
+       .name           = "uart1",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART1,
+       .clksel_con     = CRU_CLKSEL8_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 20,
+       .parents        = clk_uart1_parents,
+};
+
+static struct clk clk_uart23_src = {
+       .name           = "uart23_src",
+       .clksel_con     = CRU_CLKSEL9_CON,
+       .clksel_parent_mask     = 7,
+       .clksel_parent_shift    = 0,
+       .parents        = clk_uart_src_parents,
+};
+
+static struct clk clk_uart2_div = {
+       .name           = "uart2_div",
+       .parent         = &clk_uart23_src,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL9_CON,
+       .clksel_mask    = 0x3F,
+       .clksel_shift   = 3,
+};
+
+static struct clk clk_uart2_frac_div = {
+       .name           = "uart2_frac_div",
+       .parent         = &clk_uart2_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL12_CON,
+};
+
+static struct clk *clk_uart2_parents[4] = { &clk_uart2_div, &clk_uart2_frac_div, &xin24m };
+
+static struct clk clk_uart2 = {
+       .name           = "uart2",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART2,
+       .clksel_con     = CRU_CLKSEL9_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 9,
+       .parents        = clk_uart2_parents,
+};
+
+static struct clk clk_uart3_div = {
+       .name           = "uart3_div",
+       .parent         = &clk_uart23_src,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL9_CON,
+       .clksel_mask    = 0x3F,
+       .clksel_shift   = 14,
+};
+
+static struct clk clk_uart3_frac_div = {
+       .name           = "uart3_frac_div",
+       .parent         = &clk_uart3_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL13_CON,
+};
+
+static struct clk *clk_uart3_parents[4] = { &clk_uart3_div, &clk_uart3_frac_div, &xin24m };
+
+static struct clk clk_uart3 = {
+       .name           = "uart3",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART3,
+       .clksel_con     = CRU_CLKSEL9_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 20,
+       .parents        = clk_uart3_parents,
+};
+
+
+static struct clk *clk_hsadc_div_parents[8] = { &codec_pll_clk, &ddr_pll_clk, &periph_pll_clk, &arm_pll_clk, &otgphy0_clkin, &otgphy1_clkin };
+
+static struct clk clk_hsadc_div = {
+       .name           = "hsadc_div",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL14_CON,
+       .clksel_mask    = 0xFF,
+       .clksel_shift   = 10,
+       .clksel_parent_mask     = 7,
+       .clksel_parent_shift    = 7,
+       .parents        = clk_hsadc_div_parents,
+};
+
+static struct clk clk_hsadc_frac_div = {
+       .name           = "hsadc_frac_div",
+       .parent         = &clk_hsadc_div,
+       .recalc         = clksel_recalc_frac,
+       .clksel_con     = CRU_CLKSEL15_CON,
+};
+
+static struct clk *clk_demod_parents[4] = { &clk_hsadc_div, &clk_hsadc_frac_div, &extclk };
+
+static struct clk clk_demod = {
+       .name           = "demod",
+       .clksel_con     = CRU_CLKSEL14_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 18,
+       .parents        = clk_demod_parents,
+};
+
+static struct clk gpsclk = {
+       .name           = "gpsclk",
+};
+
+static struct clk *clk_hsadc_parents[2] = { &clk_demod, &gpsclk };
+
+static struct clk clk_hsadc = {
+       .name           = "hsadc",
+       .clksel_con     = CRU_CLKSEL14_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 21,
+       .parents        = clk_hsadc_parents,
+};
+
+static unsigned long div2_recalc(struct clk *clk)
+{
+       return clk->parent->rate >> 1;
+}
+
+static struct clk clk_hsadc_div2 = {
+       .name           = "hsadc_div2",
+       .parent         = &clk_demod,
+       .recalc         = div2_recalc,
+};
+
+static struct clk clk_hsadc_div2_inv = {
+       .name           = "hsadc_div2_inv",
+       .parent         = &clk_demod,
+       .recalc         = div2_recalc,
+};
+
+static struct clk *clk_hsadc_out_parents[2] = { &clk_hsadc_div2, &clk_hsadc_div2_inv };
+
+static struct clk clk_hsadc_out = {
+       .name           = "hsadc_out",
+       .clksel_con     = CRU_CLKSEL14_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 20,
+       .parents        = clk_hsadc_out_parents,
+};
+
+
+static struct clk *dclk_lcdc_div_parents[4] = { &codec_pll_clk, &ddr_pll_clk, &periph_pll_clk, &arm_pll_clk };
+
+static struct clk dclk_lcdc_div = {
+       .name           = "dclk_lcdc_div",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL16_CON,
+       .clksel_mask    = 0xFF,
+       .clksel_shift   = 2,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 0,
+       .parents        = dclk_lcdc_div_parents,
+};
+
+static struct clk *dclk_lcdc_parents[2] = { &dclk_lcdc_div, &extclk };
+
+static struct clk dclk_lcdc = {
+       .name           = "dclk_lcdc",
+       .clksel_con     = CRU_CLKSEL16_CON,
+       .clksel_parent_mask     = 1,
+       .clksel_parent_shift    = 10,
+       .parents        = dclk_lcdc_parents,
+};
+
+static struct clk dclk_ebook = {
+       .name           = "dclk_ebook",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL16_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 13,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 11,
+       .parents        = dclk_lcdc_div_parents,
+};
+
+static struct clk *aclk_lcdc_parents[4] = { &ddr_pll_clk, &codec_pll_clk, &periph_pll_clk, &arm_pll_clk };
+
+static struct clk aclk_lcdc = {
+       .name           = "aclk_lcdc",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL16_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 20,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 18,
+       .parents        = aclk_lcdc_parents,
+};
+
+static struct clk hclk_lcdc = {
+       .name           = "hclk_lcdc",
+       .parent         = &aclk_lcdc,
+       .clksel_con     = CRU_CLKSEL16_CON,
+       .recalc         = clksel_recalc_shift,
+       .set_rate       = clksel_set_rate_shift,
+       .clksel_mask    = 3,
+       .clksel_shift   = 25,
+       .clksel_maxdiv  = 4,
+};
+
+static struct clk *xpu_parents[4] = { &periph_pll_clk, &ddr_pll_clk, &codec_pll_clk, &arm_pll_clk };
+
+static struct clk aclk_vepu = {
+       .name           = "aclk_vepu",
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GAET_VEPU_AXI,
+       .clksel_con     = CRU_CLKSEL17_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 2,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 0,
+       .parents        = xpu_parents,
+};
+
+static struct clk hclk_vepu = {
+       .name           = "hclk_vepu",
+       .parent         = &aclk_vepu,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_shift,
+       .set_rate       = clksel_set_rate_shift,
+       .gate_idx       = CLK_GATE_VEPU_AHB,
+       .clksel_con     = CRU_CLKSEL17_CON,
+       .clksel_mask    = 3,
+       .clksel_shift   = 28,
+       .clksel_maxdiv  = 4,
+};
+
+static struct clk aclk_vdpu = {
+       .name           = "aclk_vdpu",
+       .parent         = &periph_pll_clk,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .gate_idx       = CLK_GATE_VDPU_AXI,
+       .clksel_con     = CRU_CLKSEL17_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 9,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 7,
+       .parents        = xpu_parents,
+};
+
+static struct clk hclk_vdpu = {
+       .name           = "hclk_vdpu",
+       .parent         = &aclk_vdpu,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc_shift,
+       .set_rate       = clksel_set_rate_shift,
+       .gate_idx       = CLK_GATE_VDPU_AHB,
+       .clksel_con     = CRU_CLKSEL17_CON,
+       .clksel_mask    = 3,
+       .clksel_shift   = 30,
+       .clksel_maxdiv  = 4,
+};
+
+static struct clk clk_gpu = {
+       .name           = "gpu",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL17_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 16,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 14,
+       .parents        = xpu_parents,
+};
+
+static struct clk aclk_gpu = {
+       .name           = "aclk_gpu",
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_div,
+       .clksel_con     = CRU_CLKSEL17_CON,
+       .clksel_mask    = 0x1F,
+       .clksel_shift   = 23,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 21,
+       .parents        = xpu_parents,
+};
+
+
+static struct clk *clk_vip_parents[4] = { &xin24m, &extclk, &dclk_ebook };
+
+static struct clk clk_vip = {
+       .name           = "vip",
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_VIP,
+       .clksel_con     = CRU_CLKSEL1_CON,
+       .clksel_parent_mask     = 3,
+       .clksel_parent_shift    = 7,
+       .parents        = clk_vip_parents,
+};
+
+
+#define GATE_CLK(NAME,PARENT,ID) \
+static struct clk clk_##NAME = { \
+       .name           = #NAME, \
+       .parent         = &PARENT, \
+       .mode           = gate_mode, \
+       .gate_idx       = CLK_GATE_##ID, \
+}
+
+#define CLK(dev, con, ck) \
+       { \
+               .dev_id = dev, \
+               .con_id = con, \
+               .clk = ck, \
+       }
+
+#define CLK1(name) \
+       { \
+               .dev_id = NULL, \
+               .con_id = #name, \
+               .clk = &clk_##name, \
+       }
+
+static struct clk_lookup clks[] = {
+       CLK(NULL, "xin24m", &xin24m),
+       CLK(NULL, "extclk", &extclk),
+       CLK(NULL, "otgphy0_clkin", &otgphy0_clkin),
+       CLK(NULL, "otgphy1_clkin", &otgphy1_clkin),
+       CLK(NULL, "gpsclk", &gpsclk),
+
+       CLK1(12m),
+       CLK(NULL, "arm_pll", &arm_pll_clk),
+       CLK(NULL, "ddr_pll", &ddr_pll_clk),
+       CLK(NULL, "codec_pll", &codec_pll_clk),
+       CLK(NULL, "periph_pll", &periph_pll_clk),
+
+       CLK1(core),
+       CLK(NULL, "aclk_cpu", &aclk_cpu),
+       CLK(NULL, "hclk_cpu", &hclk_cpu),
+       CLK(NULL, "pclk_cpu", &pclk_cpu),
+
+       CLK(NULL, "aclk_periph", &aclk_periph),
+       CLK(NULL, "hclk_periph", &hclk_periph),
+       CLK(NULL, "pclk_periph", &pclk_periph),
+
+       CLK1(vip),
+       CLK("rk29_otgphy.0", "otgphy", &clk_otgphy0),
+       CLK("rk29_otgphy.1", "otgphy", &clk_otgphy1),
+       CLK(NULL, "uhost", &clk_uhost),
+       CLK(NULL, "mac_ref_div", &clk_mac_ref_div),
+       CLK(NULL, "mac_ref", &clk_mac_ref),
+
+       CLK("rk29_i2s.0", "i2s_div", &clk_i2s0_div),
+       CLK("rk29_i2s.0", "i2s_frac_div", &clk_i2s0_frac_div),
+       CLK("rk29_i2s.0", "i2s", &clk_i2s0),
+       CLK("rk29_i2s.1", "i2s_div", &clk_i2s1_div),
+       CLK("rk29_i2s.1", "i2s_frac_div", &clk_i2s1_frac_div),
+       CLK("rk29_i2s.1", "i2s", &clk_i2s1),
+       CLK(NULL, "spdif_div", &clk_spdif_div),
+       CLK(NULL, "spdif_frac_div", &clk_spdif_frac_div),
+       CLK(NULL, "spdif", &clk_spdif),
+
+       CLK1(spi_src),
+       CLK("rk29_spi.0", "spi", &clk_spi0),
+       CLK("rk29_spi.1", "spi", &clk_spi1),
+
+       CLK1(saradc),
+       CLK1(timer0),
+       CLK1(timer1),
+       CLK1(timer2),
+       CLK1(timer3),
+
+       CLK1(sdmmc_src),
+       CLK("rk29_sdmmc.0", "sdmmc", &clk_sdmmc0),
+       CLK("rk29_sdmmc.1", "sdmmc", &clk_sdmmc1),
+       CLK1(emmc),
+       CLK1(ddr),
+
+       CLK1(uart01_src),
+       CLK("rk29_serial.0", "uart", &clk_uart0),
+       CLK("rk29_serial.0", "uart_div", &clk_uart0_div),
+       CLK("rk29_serial.0", "uart_frac_div", &clk_uart0_frac_div),
+       CLK("rk29_serial.1", "uart", &clk_uart1),
+       CLK("rk29_serial.1", "uart_div", &clk_uart1_div),
+       CLK("rk29_serial.1", "uart_frac_div", &clk_uart1_frac_div),
+
+       CLK1(uart23_src),
+       CLK("rk29_serial.2", "uart", &clk_uart2),
+       CLK("rk29_serial.2", "uart_div", &clk_uart2_div),
+       CLK("rk29_serial.2", "uart_frac_div", &clk_uart2_frac_div),
+       CLK("rk29_serial.3", "uart", &clk_uart3),
+       CLK("rk29_serial.3", "uart_div", &clk_uart3_div),
+       CLK("rk29_serial.3", "uart_frac_div", &clk_uart3_frac_div),
+
+       CLK1(hsadc_div),
+       CLK1(hsadc_frac_div),
+       CLK1(demod),
+       CLK1(hsadc),
+       CLK1(hsadc_div2),
+       CLK1(hsadc_div2_inv),
+       CLK1(hsadc_out),
+
+       CLK(NULL, "dclk_lcdc_div", &dclk_lcdc_div),
+       CLK(NULL, "dclk_lcdc", &dclk_lcdc),
+       CLK(NULL, "dclk_ebook", &dclk_ebook),
+       CLK(NULL, "aclk_lcdc", &aclk_lcdc),
+       CLK(NULL, "hclk_lcdc", &hclk_lcdc),
+
+       CLK(NULL, "aclk_vepu", &aclk_vepu),
+       CLK(NULL, "hclk_vepu", &hclk_vepu),
+       CLK(NULL, "aclk_vdpu", &aclk_vdpu),
+       CLK(NULL, "hclk_vdpu", &hclk_vdpu),
+       CLK1(gpu),
+       CLK(NULL, "aclk_gpu", &aclk_gpu),
+};
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
+#define LOCK() do { WARN_ON(in_irq()); if (!irqs_disabled()) spin_lock_bh(&clockfw_lock); } while (0)
+#define UNLOCK() do { if (!irqs_disabled()) spin_unlock_bh(&clockfw_lock); } while (0)
+
+static int __clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (clk->usecount == 0) {
+               if (clk->parent) {
+                       ret = __clk_enable(clk->parent);
+                       if (ret)
+                               return ret;
+               }
+
+               if (clk->mode) {
+                       ret = clk->mode(clk, 1);
+                       if (ret) {
+                               if (clk->parent)
+                                       __clk_disable(clk->parent);
+                               return ret;
+                       }
+               }
+               pr_debug("%s enabled\n", clk->name);
+       }
+       clk->usecount++;
+
+       return ret;
+}
+
+int clk_enable(struct clk *clk)
+{
+       int ret = 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       LOCK();
+       ret = __clk_enable(clk);
+       UNLOCK();
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+static void __clk_disable(struct clk *clk)
+{
+       if (--clk->usecount == 0) {
+               if (clk->mode)
+                       clk->mode(clk, 0);
+               pr_debug("%s disabled\n", clk->name);
+               if (clk->parent)
+                       __clk_disable(clk->parent);
+       }
+}
+
+void clk_disable(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return;
+
+       LOCK();
+       if (clk->usecount == 0) {
+               printk(KERN_ERR "Trying disable clock %s with 0 usecount\n", clk->name);
+               WARN_ON(1);
+               goto out;
+       }
+
+       __clk_disable(clk);
+
+out:
+       UNLOCK();
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return 0;
+
+       return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/*-------------------------------------------------------------------------
+ * Optional clock functions defined in include/linux/clk.h
+ *-------------------------------------------------------------------------*/
+
+/* Given a clock and a rate apply a clock specific rounding function */
+static long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       if (clk->round_rate)
+               return clk->round_rate(clk, rate);
+
+       if (clk->flags & RATE_FIXED)
+               printk(KERN_ERR "clock: clk_round_rate called on fixed-rate clock %s\n", clk->name);
+
+       return clk->rate;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       long ret = 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return ret;
+
+       LOCK();
+       ret = __clk_round_rate(clk, rate);
+       UNLOCK();
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+/* Set the clock rate for a clock source */
+static int __clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = -EINVAL;
+
+       pr_debug("set_rate for clock %s to rate %ld\n", clk->name, rate);
+
+       if (clk->flags & CONFIG_PARTICIPANT)
+               return -EINVAL;
+
+       if (clk->set_rate)
+               ret = clk->set_rate(clk, rate);
+
+       return ret;
+}
+
+static void __clk_recalc(struct clk *clk)
+{
+       if (unlikely(clk->flags & RATE_FIXED))
+               return;
+       if (clk->recalc)
+               clk->rate = clk->recalc(clk);
+       else if (clk->parent)
+               clk->rate = clk->parent->rate;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = -EINVAL;
+
+       if (clk == NULL || IS_ERR(clk))
+               return ret;
+
+       LOCK();
+       if (rate == clk->rate) {
+               ret = 0;
+               goto out;
+       }
+       ret = __clk_set_rate(clk, rate);
+       if (ret == 0) {
+               __clk_recalc(clk);
+               __propagate_rate(clk);
+       }
+out:
+       UNLOCK();
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+       int ret = -EINVAL;
+
+       if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
+               return ret;
+
+       if (clk->set_parent == NULL && clk->parents == NULL)
+               return ret;
+
+       LOCK();
+       if (clk->usecount == 0) {
+               if (clk->set_parent)
+                       ret = clk->set_parent(clk, parent);
+               else
+                       ret = clksel_set_parent(clk, parent);
+               if (ret == 0) {
+                       __clk_reparent(clk, parent);
+                       __clk_recalc(clk);
+                       __propagate_rate(clk);
+               }
+       } else
+               ret = -EBUSY;
+       UNLOCK();
+
+       return ret;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+       return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+static void __clk_reparent(struct clk *child, struct clk *parent)
+{
+       if (child->parent == parent)
+               return;
+       pr_debug("%s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL"));
+
+       list_del_init(&child->sibling);
+       if (parent)
+               list_add(&child->sibling, &parent->children);
+       child->parent = parent;
+}
+
+/* Propagate rate to children */
+static void __propagate_rate(struct clk *tclk)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &tclk->children, sibling) {
+               __clk_recalc(clkp);
+               __propagate_rate(clkp);
+       }
+}
+
+static LIST_HEAD(root_clks);
+
+/**
+ * recalculate_root_clocks - recalculate and propagate all root clocks
+ *
+ * Recalculates all root clocks (clocks with no parent), which if the
+ * clock's .recalc is set correctly, should also propagate their rates.
+ * Called at init.
+ */
+static void recalculate_root_clocks(void)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &root_clks, sibling) {
+               __clk_recalc(clkp);
+               __propagate_rate(clkp);
+       }
+}
+
+void clk_recalculate_root_clocks(void)
+{
+       LOCK();
+       recalculate_root_clocks();
+       UNLOCK();
+}
+
+
+/**
+ * clk_preinit - initialize any fields in the struct clk before clk init
+ * @clk: struct clk * to initialize
+ *
+ * Initialize any struct clk fields needed before normal clk initialization
+ * can run.  No return value.
+ */
+static void clk_preinit(struct clk *clk)
+{
+       INIT_LIST_HEAD(&clk->children);
+}
+
+static int clk_register(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       /*
+        * trap out already registered clocks
+        */
+       if (clk->node.next || clk->node.prev)
+               return 0;
+
+       mutex_lock(&clocks_mutex);
+
+       if (clk->get_parent)
+               clk->parent = clk->get_parent(clk);
+       else if (clk->parents)
+               clk->parent = clksel_get_parent(clk);
+
+       if (clk->parent)
+               list_add(&clk->sibling, &clk->parent->children);
+       else
+               list_add(&clk->sibling, &root_clks);
+
+       list_add(&clk->node, &clocks);
+
+       mutex_unlock(&clocks_mutex);
+
+       return 0;
+}
+
+static void clk_enable_init_clocks(void)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &clocks, node) {
+               if (clkp->flags & ENABLE_ON_INIT)
+                       clk_enable(clkp);
+       }
+}
+
+void __init rk29_clock_init(void)
+{
+       struct clk_lookup *lk;
+
+       for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++)
+               clk_preinit(lk->clk);
+
+       for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++) {
+               clkdev_add(lk);
+               clk_register(lk->clk);
+       }
+
+       recalculate_root_clocks();
+
+       printk(KERN_INFO "Clocking rate (apll/dpll/cpll/ppll/core/aclk/hclk/pclk): %ld/%ld/%ld/%ld/%ld/%ld/%ld/%ld MHz\n",
+              arm_pll_clk.rate / 1000000, ddr_pll_clk.rate / 1000000, codec_pll_clk.rate / 1000000, periph_pll_clk.rate / 1000000,
+              clk_core.rate / 1000000, aclk_cpu.rate / 1000000, hclk_cpu.rate / 1000000, pclk_cpu.rate / 1000000);
+
+       /*
+        * Only enable those clocks we will need, let the drivers
+        * enable other clocks as necessary
+        */
+       clk_enable_init_clocks();
+}
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static void dump_clock(struct seq_file *s, struct clk *clk, int deep)
+{
+       struct clk* ck;
+       int i;
+       unsigned long rate = clk->rate;
+
+       for (i = 0; i < deep; i++)
+               seq_printf(s, "    ");
+
+       seq_printf(s, "%-9s ", clk->name);
+
+       if (clk->mode && (clk->gate_idx < CLK_GATE_MAX)) {
+               u32 reg;
+               int idx = clk->gate_idx;
+               u32 v;
+
+               reg = CRU_CLKGATE0_CON;
+               reg += (idx >> 5) << 2;
+               idx &= 0x1F;
+
+               v = cru_readl(reg) & (1 << idx);
+               
+               seq_printf(s, "%s ", v ? "off" : "on ");
+       }
+
+       if (rate >= 1000000) {
+               if (rate % 1000000)
+                       seq_printf(s, "%ld.%06ld MHz", rate / 1000000, rate % 1000000);
+               else
+                       seq_printf(s, "%ld MHz", rate / 1000000);
+       } else if (rate >= 1000) {
+               if (rate % 1000)
+                       seq_printf(s, "%ld.%03ld KHz", rate / 1000, rate % 1000);
+               else
+                       seq_printf(s, "%ld KHz", rate / 1000);
+       } else {
+               seq_printf(s, "%ld Hz", rate);
+       }
+
+       seq_printf(s, " usecount = %d", clk->usecount);
+
+       seq_printf(s, " parent = %s\n", clk->parent ? clk->parent->name : "NULL");
+
+       list_for_each_entry(ck, &clocks, node) {
+               if (ck->parent == clk)
+                       dump_clock(s, ck, deep + 1);
+       }
+}
+
+static int proc_clk_show(struct seq_file *s, void *v)
+{
+       struct clk* clk;
+
+       mutex_lock(&clocks_mutex);
+       list_for_each_entry(clk, &clocks, node) {
+               if (!clk->parent)
+                       dump_clock(s, clk, 0);
+       }
+       mutex_unlock(&clocks_mutex);
+
+       seq_printf(s, "\nRegisters:\n");
+       seq_printf(s, "APLL     : 0x%08x\n", cru_readl(CRU_APLL_CON));
+       seq_printf(s, "DPLL     : 0x%08x\n", cru_readl(CRU_DPLL_CON));
+       seq_printf(s, "CPLL     : 0x%08x\n", cru_readl(CRU_CPLL_CON));
+       seq_printf(s, "PPLL     : 0x%08x\n", cru_readl(CRU_PPLL_CON));
+       seq_printf(s, "MODE     : 0x%08x\n", cru_readl(CRU_MODE_CON));
+       seq_printf(s, "CLKSEL0  : 0x%08x\n", cru_readl(CRU_CLKSEL0_CON));
+       seq_printf(s, "CLKSEL1  : 0x%08x\n", cru_readl(CRU_CLKSEL1_CON));
+       seq_printf(s, "CLKSEL2  : 0x%08x\n", cru_readl(CRU_CLKSEL2_CON));
+       seq_printf(s, "CLKSEL3  : 0x%08x\n", cru_readl(CRU_CLKSEL3_CON));
+       seq_printf(s, "CLKSEL4  : 0x%08x\n", cru_readl(CRU_CLKSEL4_CON));
+       seq_printf(s, "CLKSEL5  : 0x%08x\n", cru_readl(CRU_CLKSEL5_CON));
+       seq_printf(s, "CLKSEL6  : 0x%08x\n", cru_readl(CRU_CLKSEL6_CON));
+       seq_printf(s, "CLKSEL7  : 0x%08x\n", cru_readl(CRU_CLKSEL7_CON));
+       seq_printf(s, "CLKSEL8  : 0x%08x\n", cru_readl(CRU_CLKSEL8_CON));
+       seq_printf(s, "CLKSEL9  : 0x%08x\n", cru_readl(CRU_CLKSEL9_CON));
+       seq_printf(s, "CLKSEL10 : 0x%08x\n", cru_readl(CRU_CLKSEL10_CON));
+       seq_printf(s, "CLKSEL11 : 0x%08x\n", cru_readl(CRU_CLKSEL11_CON));
+       seq_printf(s, "CLKSEL12 : 0x%08x\n", cru_readl(CRU_CLKSEL12_CON));
+       seq_printf(s, "CLKSEL13 : 0x%08x\n", cru_readl(CRU_CLKSEL13_CON));
+       seq_printf(s, "CLKSEL14 : 0x%08x\n", cru_readl(CRU_CLKSEL14_CON));
+       seq_printf(s, "CLKSEL15 : 0x%08x\n", cru_readl(CRU_CLKSEL15_CON));
+       seq_printf(s, "CLKSEL16 : 0x%08x\n", cru_readl(CRU_CLKSEL16_CON));
+       seq_printf(s, "CLKSEL17 : 0x%08x\n", cru_readl(CRU_CLKSEL17_CON));
+       seq_printf(s, "CLKGATE0 : 0x%08x\n", cru_readl(CRU_CLKGATE0_CON));
+       seq_printf(s, "CLKGATE1 : 0x%08x\n", cru_readl(CRU_CLKGATE1_CON));
+       seq_printf(s, "CLKGATE2 : 0x%08x\n", cru_readl(CRU_CLKGATE2_CON));
+       seq_printf(s, "CLKGATE3 : 0x%08x\n", cru_readl(CRU_CLKGATE3_CON));
+
+       return 0;
+}
+
+static int proc_clk_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, proc_clk_show, NULL);
+}
+
+static const struct file_operations proc_clk_fops = {
+       .open           = proc_clk_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init clk_proc_init(void)
+{
+       proc_create("clocks", 0, NULL, &proc_clk_fops);
+       return 0;
+
+}
+late_initcall(clk_proc_init);
+#endif /* CONFIG_PROC_FS */
+
index 0126051ef85ef6c7e84c957b44a606a779c28320..476a4d49099049039f566c890ffbde54e8361b34 100644 (file)
@@ -18,5 +18,6 @@
 #include <linux/types.h>
 
 void __init rk29_map_common_io(void);
+void __init rk29_clock_init(void);
 
-#endif
\ No newline at end of file
+#endif
diff --git a/arch/arm/mach-rk29/include/mach/cru.h b/arch/arm/mach-rk29/include/mach/cru.h
new file mode 100644 (file)
index 0000000..ee1215b
--- /dev/null
@@ -0,0 +1,173 @@
+/* arch/arm/mach-rk29/include/mach/cru.h
+ *
+ * Copyright (C) 2010 ROCKCHIP, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __ASM_ARCH_RK29_CRU_H
+
+enum cru_clk_gate
+{
+       /* SCU CLK GATE 0 CON */
+       CLK_GATE_CORE = 0,
+       CLK_GATE_CORE_APB,
+       CLK_GATE_CORE_ATB,
+       CLK_GATE_CPU_AXI,
+       CLK_GATE_CPU_AXI2,
+       CLK_GATE_CPU_AHB,
+       CLK_GATE_CPU_MATRIX1_AHB,
+       CLK_GATE_CPU_APB,
+       CLK_GATE_CPU_ATB,
+       CLK_GATE_DMA0,
+       CLK_GATE_DMA1,
+       CLK_GATE_GIC,
+       CLK_GATE_IMEM,
+       CLK_GATE_EBROM = 14,
+       CLK_GATE_I2S0,
+       CLK_GATE_I2S1,
+       CLK_GATE_SPDIF,
+       CLK_GATE_DDR_PHY,
+       CLK_GATE_DDR_REG,
+       CLK_GATE_DDR_CPU,
+       CLK_GATE_EFUSE,
+       CLK_GATE_TZPC,
+       CLK_GATE_TIMER0,
+       CLK_GATE_GPIO0,
+       CLK_GATE_UART0,
+       CLK_GATE_I2C0,
+       CLK_GATE_DEBUG,
+       CLK_GATE_TPIU,
+       CLK_GATE_RTC,
+       CLK_GATE_PMU,
+       CLK_GATE_GRF,
+
+       /* SCU CLK GATE 1 CON */
+       CLK_GATE_PEIRPH_AXI = 32,
+       CLK_GATE_PEIRPH_AHB,
+       CLK_GATE_PEIRPH_APB,
+       CLK_GATE_EMEM,
+       CLK_GATE_USB,
+       CLK_GATE_DMA2,
+       CLK_GATE_DDR_PERIPH,
+       CLK_GATE_PERIPH,        /* FIXME */
+       CLK_GATE_SMC_AXI,
+       CLK_GATE_SMC,
+       CLK_GATE_MAC_AHB = 43,
+       CLK_GATE_MAC_PHY,
+       CLK_GATE_MAC_TX,
+       CLK_GATE_MAC_RX,
+       CLK_GATE_HIF,
+       CLK_GATE_NANDC,
+       CLK_GATE_HSADC_AHB,
+       CLK_GATE_HSADC,
+       CLK_GATE_SDMMC0_AHB,
+       CLK_GATE_SDMMC0,
+       CLK_GATE_SDMMC1_AHB,
+       CLK_GATE_SDMMC1,
+       CLK_GATE_EMMC_AHB,
+       CLK_GATE_EMMC,
+       CLK_GATE_USBOTG0,
+       CLK_GATE_USBPHY0,
+       CLK_GATE_USBOTG1,
+       CLK_GATE_USBPHY1,
+       CLK_GATE_UHOST_AHB,
+       CLK_GATE_UHOST,
+       CLK_GATE_PID_FILTER,
+
+       /* SCU CLK GATE 2 CON */
+       CLK_GATE_UART1 = 64,
+       CLK_GATE_UART2,
+       CLK_GATE_UART3,
+       CLK_GATE_TIMER1,
+       CLK_GATE_TIMER2,
+       CLK_GATE_TIMER3,
+       CLK_GATE_GPIO1,
+       CLK_GATE_GPIO2,
+       CLK_GATE_GPIO3,
+       CLK_GATE_GPIO4,
+       CLK_GATE_GPIO5,
+       CLK_GATE_GPIO6,
+       CLK_GATE_I2C1,
+       CLK_GATE_I2C2,
+       CLK_GATE_I2C3,
+       CLK_GATE_SPI0,
+       CLK_GATE_SPI1,
+       CLK_GATE_VIP_SLAVE = 82,
+       CLK_GATE_WDT,
+       CLK_GATE_SARADC,
+       CLK_GATE_PWM,
+       CLK_GATE_VIP_BUS,
+       CLK_GATE_VIP_MATRIX,
+       CLK_GATE_VIP,
+       CLK_GATE_VIP_INPUT,
+       CLK_GATE_JTAG,
+
+       /* CRU CLK GATE 3 CON */
+       CLK_GATE_LCDC_AXI = 96,
+       CLK_GATE_DDR_LCDC_AXI,
+       CLK_GATE_LCDC_AHB,
+       CLK_GATE_LCDC,
+       CLK_GATE_IPP_AXI,
+       CLK_GATE_IPP_AHB,
+       CLK_GATE_EBOOK_AHB,
+       CLK_GATE_EBOOK,
+       CLK_GATE_DISPLAY_MATRIX_AXI,
+       CLK_GATE_DISPLAY_MATRIX_AHB,
+       CLK_GAET_VEPU_AXI,
+       CLK_GATE_DDR_VEDU_AXI,
+       CLK_GATE_VDPU_AXI,
+       CLK_GATE_DDR_VDPU_AXI,
+       CLK_GATE_GPU,
+       CLK_GATE_GPU_AXI,
+       CLK_GATE_DDR_GPU_AXI,
+       CLK_GATE_GPU_AHB,
+       CLK_GATE_VEPU_AHB,
+       CLK_GATE_VDPU_AHB,
+       CLK_GATE_CPU_VCODEC_AHB,
+       CLK_GATE_CPU_DISPLAY_AHB,
+
+       CLK_GATE_MAX,
+};
+
+/* Register definitions */
+#define CRU_APLL_CON           0x00
+#define CRU_DPLL_CON           0x04
+#define CRU_CPLL_CON           0x08
+#define CRU_PPLL_CON           0x0c
+#define CRU_MODE_CON           0x10
+#define CRU_CLKSEL0_CON                0x14
+#define CRU_CLKSEL1_CON                0x18
+#define CRU_CLKSEL2_CON                0x1c
+#define CRU_CLKSEL3_CON                0x20
+#define CRU_CLKSEL4_CON                0x24
+#define CRU_CLKSEL5_CON                0x28
+#define CRU_CLKSEL6_CON                0x2c
+#define CRU_CLKSEL7_CON                0x30
+#define CRU_CLKSEL8_CON                0x34
+#define CRU_CLKSEL9_CON                0x38
+#define CRU_CLKSEL10_CON       0x3c
+#define CRU_CLKSEL11_CON       0x40
+#define CRU_CLKSEL12_CON       0x44
+#define CRU_CLKSEL13_CON       0x48
+#define CRU_CLKSEL14_CON       0x4c
+#define CRU_CLKSEL15_CON       0x50
+#define CRU_CLKSEL16_CON       0x54
+#define CRU_CLKSEL17_CON       0x58
+#define CRU_CLKGATE0_CON       0x5c
+#define CRU_CLKGATE1_CON       0x60
+#define CRU_CLKGATE2_CON       0x64
+#define CRU_CLKGATE3_CON       0x68
+#define CRU_SOFTRST0_CON       0x6c
+#define CRU_SOFTRST1_CON       0x70
+#define CRU_SOFTRST2_CON       0x74
+
+#endif
index 49c90cc634503098da7a5b5d7f1a419805e58dcc..fa1fadcc2c50f2fcae018c560bf89cd683786b35 100644 (file)
 
 //CPU AXI 1 APB
 #define RK29_CRU_PHYS                          0x20000000
-#define RK29_CRU_SIZE                          SZ_16K
+#define RK29_CRU_BASE                          RK29_ADDR_BASE1
+#define RK29_CRU_SIZE                          SZ_4K
 #define RK29_PMU_PHYS                          0x20004000
 #define RK29_PMU_SIZE                          SZ_16K
 #define RK29_GRF_BASE                          (RK29_ADDR_BASE1+0x8000)
index d8db9973e8c454619dc5c3b6125233870d2e02ac..99117d0e028566c6e4baa37a8d551941e2372942 100644 (file)
@@ -37,9 +37,10 @@ static struct map_desc rk29_io_desc[] __initdata = {
        RK29_DEVICE(DDRC),
        RK29_DEVICE(UART1),
        RK29_DEVICE(GRF),
+       RK29_DEVICE(CRU),
 };
 
 void __init rk29_map_common_io(void)
 {
        iotable_init(rk29_io_desc, ARRAY_SIZE(rk29_io_desc));
-}
\ No newline at end of file
+}
index 5f3d4364184e1c86e5c8b058ddf7fb12f2d7e144..4493362fe90db22cde5e31b7a50bd78cd60cd6af 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/clk.h>
 #include <linux/clockchips.h>
 #include <linux/io.h>
-#include <linux/cpufreq.h>
 
 #include <asm/mach/time.h>
 #include <mach/rk29_iomap.h>
@@ -35,8 +34,6 @@
 #define TIMER_ENABLE                   3
 #define TIMER_ENABLE_FREE_RUNNING      1
 
-#define CHECK_VBUS_MS                  1000    /* ms */
-
 #define RK_TIMER_ENABLE(n)             writel(TIMER_ENABLE, RK29_TIMER0_BASE + 0x2000 * n + TIMER_CONTROL_REG)
 #define RK_TIMER_ENABLE_FREE_RUNNING(n)        writel(TIMER_ENABLE_FREE_RUNNING, RK29_TIMER0_BASE + 0x2000 * n + TIMER_CONTROL_REG)
 #define RK_TIMER_DISABLE(n)            writel(TIMER_DISABLE, RK29_TIMER0_BASE + 0x2000 * n + TIMER_CONTROL_REG)
@@ -47,6 +44,8 @@
 #define RK_TIMER_READVALUE(n)          readl(RK29_TIMER0_BASE + 0x2000 * n + TIMER_CUR_VALUE)
 #define RK_TIMER_INT_CLEAR(n)          readl(RK29_TIMER0_BASE + 0x2000 * n + TIMER_EOI)
 
+#define RK_TIMER_INT_STATUS(n)         readl(RK29_TIMER0_BASE + 0x2000 * n + TIMER_INT_STATUS)
+
 #define TIMER_CLKEVT                   0       /* timer0 */
 #define IRQ_NR_TIMER_CLKEVT            IRQ_TIMER0
 #define TIMER_CLKEVT_NAME              "timer0"
 #define IRQ_NR_TIMER_CLKSRC            IRQ_TIMER1
 #define TIMER_CLKSRC_NAME              "timer1"
 
-//static struct clk *timer_clk;
-
-
 static int rk29_timer_set_next_event(unsigned long cycles, struct clock_event_device *evt)
 {
        RK_TIMER_DISABLE(TIMER_CLKEVT);
-       RK_TIMER_SETCOUNT(TIMER_CLKEVT, cycles );
+       RK_TIMER_SETCOUNT(TIMER_CLKEVT, cycles);
        RK_TIMER_ENABLE(TIMER_CLKEVT);
 
        return 0;
@@ -113,14 +109,18 @@ static struct irqaction rk29_timer_clockevent_irq = {
 static __init int rk29_timer_init_clockevent(void)
 {
        struct clock_event_device *ce = &rk29_timer_clockevent;
+       struct clk *clk = clk_get(NULL, TIMER_CLKEVT_NAME);
+       struct clk *xin24m = clk_get(NULL, "xin24m");
+
+       clk_set_parent(clk, xin24m);
+       clk_enable(clk);
 
-       //timer_clk = clk_get(NULL, "timer");
        RK_TIMER_DISABLE(TIMER_CLKEVT);
 
        setup_irq(rk29_timer_clockevent_irq.irq, &rk29_timer_clockevent_irq);
 
        ce->mult = div_sc(24000000, NSEC_PER_SEC, ce->shift);
-       ce->max_delta_ns = clockevent_delta2ns(0xFFFFFFFFUL, ce); // max pclk < 256MHz
+       ce->max_delta_ns = clockevent_delta2ns(0xFFFFFFFFUL, ce);
        ce->min_delta_ns = clockevent_delta2ns(1, ce) + 1;
 
        ce->cpumask = cpumask_of(0);
@@ -148,6 +148,11 @@ static void __init rk29_timer_init_clocksource(void)
 {
        static char err[] __initdata = KERN_ERR "%s: can't register clocksource!\n";
        struct clocksource *cs = &rk29_timer_clocksource;
+       struct clk *clk = clk_get(NULL, TIMER_CLKSRC_NAME);
+       struct clk *xin24m = clk_get(NULL, "xin24m");
+
+       clk_set_parent(clk, xin24m);
+       clk_enable(clk);
 
        RK_TIMER_DISABLE(TIMER_CLKSRC);
        RK_TIMER_SETCOUNT(TIMER_CLKSRC, 0xFFFFFFFF);
@@ -156,7 +161,6 @@ static void __init rk29_timer_init_clocksource(void)
        cs->mult = clocksource_hz2mult(24000000, cs->shift);
        if (clocksource_register(cs))
                printk(err, cs->name);
-
 }
 
 static void __init rk29_timer_init(void)
@@ -169,8 +173,3 @@ struct sys_timer rk29_timer = {
        .init = rk29_timer_init
 };
 
-
-
-
-
-