add clock support
author黄涛 <huangtao@rock-chips.com>
Sat, 24 Apr 2010 03:48:44 +0000 (03:48 +0000)
committer黄涛 <huangtao@rock-chips.com>
Mon, 21 Jun 2010 05:34:47 +0000 (13:34 +0800)
arch/arm/mach-rk2818/Makefile
arch/arm/mach-rk2818/clock-rk2818.c [deleted file]
arch/arm/mach-rk2818/clock.c
arch/arm/mach-rk2818/clock.h [deleted file]

index f1000ca5146d55b30412b60e855b916a4a813db1..78ffd575c8065d52e7ab0666ee548ee87b30fa7e 100644 (file)
@@ -2,7 +2,7 @@ obj-y += io.o idle.o irq.o timer.o
 obj-y += devices.o
 obj-y += proc_comm.o
 obj-y += vreg.o
-obj-y += clock.o clock-rk2818.o
+obj-y += clock.o
 
 obj-$(CONFIG_MACH_RK2818MID) += board-midsdk.o
 
diff --git a/arch/arm/mach-rk2818/clock-rk2818.c b/arch/arm/mach-rk2818/clock-rk2818.c
deleted file mode 100644 (file)
index c4a6626..0000000
+++ /dev/null
@@ -1,111 +0,0 @@
-/* arch/arm/mach-rk2818/clock-rk2818.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.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/platform_device.h>
-
-#include "clock.h"
-#include "devices.h"
-
-/* clock IDs used by the modem processor */
-
-#define ACPU_CLK       0   /* Applications processor clock */
-#define ADM_CLK                1   /* Applications data mover clock */
-#define ADSP_CLK       2   /* ADSP clock */
-#define EBI1_CLK       3   /* External bus interface 1 clock */
-#define EBI2_CLK       4   /* External bus interface 2 clock */
-#define ECODEC_CLK     5   /* External CODEC clock */
-#define EMDH_CLK       6   /* External MDDI host clock */
-#define GP_CLK         7   /* General purpose clock */
-#define GRP_CLK                8   /* Graphics clock */
-#define I2C_CLK                9   /* I2C clock */
-#define ICODEC_RX_CLK  10  /* Internal CODEX RX clock */
-#define ICODEC_TX_CLK  11  /* Internal CODEX TX clock */
-#define IMEM_CLK       12  /* Internal graphics memory clock */
-#define MDC_CLK                13  /* MDDI client clock */
-#define MDP_CLK                14  /* Mobile display processor clock */
-#define PBUS_CLK       15  /* Peripheral bus clock */
-#define PCM_CLK                16  /* PCM clock */
-#define PMDH_CLK       17  /* Primary MDDI host clock */
-#define SDAC_CLK       18  /* Stereo DAC clock */
-#define SDC1_CLK       19  /* Secure Digital Card clocks */
-#define SDC1_PCLK      20
-#define SDC2_CLK       21
-#define SDC2_PCLK      22
-#define SDC3_CLK       23
-#define SDC3_PCLK      24
-#define SDC4_CLK       25
-#define SDC4_PCLK      26
-#define TSIF_CLK       27  /* Transport Stream Interface clocks */
-#define TSIF_REF_CLK   28
-#define TV_DAC_CLK     29  /* TV clocks */
-#define TV_ENC_CLK     30
-#define UART1_CLK      31  /* UART clocks */
-#define UART2_CLK      32
-#define UART3_CLK      33
-#define UART1DM_CLK    34
-#define UART2DM_CLK    35
-#define USB_HS_CLK     36  /* High speed USB core clock */
-#define USB_HS_PCLK    37  /* High speed USB pbus clock */
-#define USB_OTG_CLK    38  /* Full speed USB clock */
-#define VDC_CLK                39  /* Video controller clock */
-#define VFE_CLK                40  /* Camera / Video Front End clock */
-#define VFE_MDC_CLK    41  /* VFE MDDI client clock */
-
-#define NR_CLKS                42
-
-#define CLOCK(clk_name, clk_id, clk_dev, clk_flags) {  \
-       .name = clk_name, \
-       .id = clk_id, \
-       .flags = clk_flags, \
-       .dev = clk_dev, \
-       }
-
-#define OFF CLKFLAG_AUTO_OFF
-#define MINMAX CLKFLAG_USE_MIN_MAX_TO_SET
-
-struct clk rk2818_clocks[] = {
-       CLOCK("adm_clk",        ADM_CLK,        NULL, 0),
-       CLOCK("adsp_clk",       ADSP_CLK,       NULL, 0),
-       CLOCK("ebi1_clk",       EBI1_CLK,       NULL, 0),
-       CLOCK("ebi2_clk",       EBI2_CLK,       NULL, 0),
-       CLOCK("ecodec_clk",     ECODEC_CLK,     NULL, 0),
-       CLOCK("emdh_clk",       EMDH_CLK,       NULL, OFF),
-       CLOCK("gp_clk",         GP_CLK,         NULL, 0),
-       CLOCK("grp_clk",        GRP_CLK,        NULL, OFF),
-       CLOCK("icodec_rx_clk",  ICODEC_RX_CLK,  NULL, 0),
-       CLOCK("icodec_tx_clk",  ICODEC_TX_CLK,  NULL, 0),
-       CLOCK("imem_clk",       IMEM_CLK,       NULL, OFF),
-       CLOCK("mdc_clk",        MDC_CLK,        NULL, 0),
-       CLOCK("mdp_clk",        MDP_CLK,        NULL, OFF),
-       CLOCK("pbus_clk",       PBUS_CLK,       NULL, 0),
-       CLOCK("pcm_clk",        PCM_CLK,        NULL, 0),
-       CLOCK("pmdh_clk",       PMDH_CLK,       NULL, OFF | MINMAX),
-       CLOCK("sdac_clk",       SDAC_CLK,       NULL, OFF),
-       CLOCK("tsif_clk",       TSIF_CLK,       NULL, 0),
-       CLOCK("tsif_ref_clk",   TSIF_REF_CLK,   NULL, 0),
-       CLOCK("tv_dac_clk",     TV_DAC_CLK,     NULL, 0),
-       CLOCK("tv_enc_clk",     TV_ENC_CLK,     NULL, 0),
-       CLOCK("uart_clk",       UART1_CLK,      &rk2818_device_uart1.dev, OFF),
-       CLOCK("uart1dm_clk",    UART1DM_CLK,    NULL, OFF),
-       CLOCK("uart2dm_clk",    UART2DM_CLK,    NULL, 0),
-       CLOCK("usb_otg_clk",    USB_OTG_CLK,    NULL, 0),
-       CLOCK("vdc_clk",        VDC_CLK,        NULL, OFF | MINMAX),
-       CLOCK("vfe_clk",        VFE_CLK,        NULL, OFF),
-       CLOCK("vfe_mdc_clk",    VFE_MDC_CLK,    NULL, OFF),
-};
-
-unsigned rk2818_num_clocks = ARRAY_SIZE(rk2818_clocks);
index 01c1cedf945c9f1581af701ef4ed08421076e747..28085a389071dba71713d9e1a98381724de08730 100644 (file)
  *
  * 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
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  */
 
-#include <linux/version.h>
-#include <linux/kernel.h>
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/err.h>
 #include <linux/init.h>
-#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/spinlock.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <asm/clkdev.h>
+#include <mach/rk2818_iomap.h>
 
-#include "clock.h"
-#include "proc_comm.h"
+enum 
+{
+       /* SCU CLK GATE 0 CON */
+       SCU_IPID_ARM = 0,
+       SCU_IPID_DSP,
+       SCU_IPID_DMA,
+       SCU_IPID_SRAMARM,
+       SCU_IPID_SRAMDSP,
+       SCU_IPID_HIF,
+       SCU_IPID_OTGBUS,
+       SCU_IPID_OTGPHY,
+       SCU_IPID_NANDC,
+       SCU_IPID_INTC,
+       SCU_IPID_DEBLK,     /* 10 */
+       SCU_IPID_LCDC,
+       SCU_IPID_VIP,       /* as sensor */
+       SCU_IPID_I2S,
+       SCU_IPID_SDMMC0,    /* 14 */
+       SCU_IPID_EBROM,
+       SCU_IPID_GPIO0,
+       SCU_IPID_GPIO1,
+       SCU_IPID_UART0,
+       SCU_IPID_UART1,
+       SCU_IPID_I2C0,      /* 20 */
+       SCU_IPID_I2C1,
+       SCU_IPID_SPI0,
+       SCU_IPID_SPI1,
+       SCU_IPID_PWM,
+       SCU_IPID_TIMER,
+       SCU_IPID_WDT,
+       SCU_IPID_RTC,
+       SCU_IPID_LSADC,
+       SCU_IPID_UART2,
+       SCU_IPID_UART3,         /* 30 */
+       SCU_IPID_SDMMC1,
 
-static DEFINE_MUTEX(clocks_mutex);
-static DEFINE_SPINLOCK(clocks_lock);
-static LIST_HEAD(clocks);
+       /* SCU CLK GATE 1 CON */
+       SCU_IPID_HSADC = 32,
+       SCU_IPID_MOBILE_SDARM_COMMON = 47,
+       SCU_IPID_SDRAM_CONTROLLER,
+       SCU_IPID_MOBILE_SDRAM_CONTROLLER,
+       SCU_IPID_LCDC_SHARE_MEMORY,     /* 50 */
+       SCU_IPID_LCDC_HCLK,
+       SCU_IPID_DEBLK_H264,
+       SCU_IPID_GPU,
+       SCU_IPID_DDR_HCLK,
+       SCU_IPID_DDR,
+       SCU_IPID_CUSTOMIZED_SDRAM_CONTROLLER,
+       SCU_IPID_MCDMA,
+       SCU_IPID_SDRAM,
+       SCU_IPID_DDR_AXI,
+       SCU_IPID_DSP_TIMER,     /* 60 */
+       SCU_IPID_DSP_SLAVE,
+       SCU_IPID_DSP_MASTER,
+       SCU_IPID_USB_HOST,
 
-/*
- * glue for the proc_comm interface
- */
-static inline int pc_clk_enable(unsigned id)
+       /* SCU CLK GATE 2 CON */
+       SCU_IPID_ARMIBUS = 64,
+       SCU_IPID_ARMDBUS,
+       SCU_IPID_DSPBUS,
+       SCU_IPID_EXPBUS,
+       SCU_IPID_APBBUS,
+       SCU_IPID_EFUSE,
+       SCU_IPID_DTCM1,         /* 70 */
+       SCU_IPID_DTCM0,
+       SCU_IPID_ITCM,
+       SCU_IPID_VIDEOBUS,
+
+       SCU_IPID_GATE_MAX,
+};
+
+static struct rockchip_scu_reg_hw
 {
-       return rk2818_proc_comm(PCOM_CLKCTL_RPC_ENABLE, &id, NULL);
-}
+       u32 scu_pll_config[3];  /* 0:arm 1:dsp 2:codec */
+       u32 scu_mode_config;
+       u32 scu_pmu_config;
+       u32 scu_clksel0_config;
+       u32 scu_clksel1_config;
+       u32 scu_clkgate0_config;
+       u32 scu_clkgate1_config;
+       u32 scu_clkgate2_config;
+       u32 scu_softreset_config;
+       u32 scu_chipcfg_config;
+       u32 scu_cuppd;          /* arm power down */
+       u32 scu_clksel2_config;
+} *scu_register_base = (struct rockchip_scu_reg_hw *)(RK2818_SCU_BASE);
+
+#define CLKSEL0_REG    (u32 __iomem *)(RK2818_SCU_BASE + 0x14)
+#define CLKSEL1_REG    (u32 __iomem *)(RK2818_SCU_BASE + 0x18)
+#define CLKSEL2_REG    (u32 __iomem *)(RK2818_SCU_BASE + 0x34)
 
-static inline void pc_clk_disable(unsigned id)
+/* 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 */
+
+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 *);
+       int                     (*set_rate)(struct clk *, unsigned long);
+       long                    (*round_rate)(struct clk *, unsigned long);
+       void                    (*init)(struct clk *);  /* set clk's parent field from the hardware */
+       s16                     usecount;
+       u8                      gate_idx;
+       u8                      pll_idx;
+       u32 __iomem             *clksel_reg;
+       u32                     clksel_mask;
+       u8                      clksel_shift;
+       u8                      clksel_maxdiv;
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
+       struct dentry           *dent;  /* For visible tree hierarchy */
+#endif
+};
+
+static void __clk_disable(struct clk *clk);
+static void clk_reparent(struct clk *child, struct clk *parent);
+static void propagate_rate(struct clk *tclk);
+
+/* Used for clocks that always have same value as the parent clock */
+static unsigned long followparent_recalc(struct clk *clk)
 {
-       rk2818_proc_comm(PCOM_CLKCTL_RPC_DISABLE, &id, NULL);
+       return clk->parent->rate;
 }
 
-static inline int pc_clk_set_rate(unsigned id, unsigned rate)
+static unsigned long clksel_recalc(struct clk *clk)
 {
-       return rk2818_proc_comm(PCOM_CLKCTL_RPC_SET_RATE, &id, &rate);
+       u32 div = ((readl(clk->clksel_reg) & clk->clksel_mask) >> clk->clksel_shift) + 1;
+       unsigned long rate = clk->parent->rate / div;
+       pr_debug("clock: %s new clock rate is %ld (div %d) reg %p mask %x shift %d\n", clk->name, rate, div, clk->clksel_reg, clk->clksel_mask, clk->clksel_shift);
+       return rate;
 }
 
-static inline int pc_clk_set_min_rate(unsigned id, unsigned rate)
+static int clksel_set_rate(struct clk *clk, unsigned long rate)
 {
-       return rk2818_proc_comm(PCOM_CLKCTL_RPC_MIN_RATE, &id, &rate);
+       u32 div;
+
+       for (div = 1; div <= clk->clksel_maxdiv; div++) {
+               u32 new_rate = clk->parent->rate / div;
+               if (new_rate <= rate) {
+                       u32 *reg = clk->clksel_reg;
+                       u32 v = readl(reg);
+                       v &= ~clk->clksel_mask;
+                       v |= (div - 1) << clk->clksel_shift;
+                       writel(v, reg);
+                       clk->rate = new_rate;
+                       pr_debug("clock: clksel_set_rate for clock %s to rate %ld (div %d)\n", clk->name, rate, div);
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
 }
 
-static inline int pc_clk_set_max_rate(unsigned id, unsigned rate)
+static struct clk xin24m = {
+       .name           = "xin24m",
+       .rate           = 24000000,
+       .flags          = RATE_FIXED,
+};
+
+static struct clk clk12m = {
+       .name           = "clk12m",
+       .rate           = 12000000,
+       .parent         = &xin24m,
+       .flags          = RATE_FIXED,
+};
+
+static struct clk extclk = {
+       .name           = "extclk",
+       .rate           = 27000000,
+       .flags          = RATE_FIXED,
+};
+
+static unsigned long pll_clk_recalc(struct clk *clk)
 {
-       return rk2818_proc_comm(PCOM_CLKCTL_RPC_MAX_RATE, &id, &rate);
+       u32 v = readl(&scu_register_base->scu_pll_config[clk->pll_idx]);
+       u32 OD = ((v >> 1) & 0x7) + 1;
+       u32 NF = ((v >> 4) & 0xfff) + 1;
+       u32 NR = ((v >> 16) & 0x3f) + 1;
+       unsigned long rate = clk->parent->rate / NR * NF / OD;
+       pr_debug("clock: %s new clock rate is %ld NR %d NF %d OD %d\n", clk->name, rate, NR, NF, OD);
+       return rate;
+}
+
+#define PLL_CLK(NAME,IDX) \
+static struct clk NAME##_pll_clk = { \
+       .name           = #NAME"_pll", \
+       .parent         = &xin24m, \
+       .pll_idx        = IDX, \
+       .recalc         = pll_clk_recalc, \
 }
 
-static inline int pc_clk_set_flags(unsigned id, unsigned flags)
+PLL_CLK(arm, 0);
+PLL_CLK(dsp, 1);
+PLL_CLK(codec, 2);
+
+static struct clk arm_clk = {
+       .name           = "arm",
+       .parent         = &arm_pll_clk,
+       .recalc         = clksel_recalc,
+//     .set_rate       = arm_clk_set_rate,
+       .clksel_reg     = CLKSEL2_REG,
+       .clksel_mask    = 0xF,
+};
+
+static struct clk arm_hclk = {
+       .name           = "arm_hclk",
+       .parent         = &arm_clk,
+       .recalc         = clksel_recalc,
+       .clksel_reg     = CLKSEL0_REG,
+       .clksel_mask    = 0x3,
+};
+
+static struct clk clk48m = {
+       .name           = "clk48m",
+       .parent         = &arm_clk,
+       .recalc         = clksel_recalc,
+       .flags          = RATE_FIXED,
+       .clksel_reg     = CLKSEL2_REG,
+       .clksel_mask    = 0xF << 4,
+       .clksel_shift   = 4,
+};
+
+static unsigned long arm_pclk_recalc(struct clk *clk)
 {
-       return rk2818_proc_comm(PCOM_CLKCTL_RPC_SET_FLAGS, &id, &flags);
+       u32 shift = (readl(&scu_register_base->scu_clksel0_config) >> 2) & 0x3;
+       unsigned long rate = clk->parent->rate >> shift;
+       pr_debug("clock: %s new clock rate is %ld (shift %d)\n", clk->name, rate, shift);
+       return rate;
 }
 
-static inline unsigned pc_clk_get_rate(unsigned id)
+static struct clk arm_pclk = {
+       .name           = "arm_pclk",
+       .parent         = &arm_hclk,
+       .recalc         = arm_pclk_recalc,
+};
+
+static void demod_clk_init(struct clk *clk)
 {
-       if (rk2818_proc_comm(PCOM_CLKCTL_RPC_RATE, &id, NULL))
-               return 0;
-       else
-               return id;
+       struct clk *real_parent = clk->parent;
+       u32 r = readl(CLKSEL1_REG);
+       if (r & (1 << 26)) {
+               real_parent = &xin24m;
+       } else {
+               r >>= 24;
+               if (r == 0) {
+                       real_parent = &codec_pll_clk;
+               } else if (r == 1) {
+                       real_parent = &arm_pll_clk;
+               } else if (r == 2) {
+                       real_parent = &dsp_pll_clk;
+               }
+       }
+       if (real_parent != clk->parent) {
+               pr_debug("clock: inited %s parent to %s (was %s)\n", clk->name, real_parent->name, ((clk->parent) ? clk->parent->name : "NULL"));
+               clk_reparent(clk, real_parent);
+       }
 }
 
-static inline unsigned pc_clk_is_enabled(unsigned id)
+static struct clk demod_clk = {
+       .name           = "demod",
+       .parent         = &codec_pll_clk,
+       .recalc         = clksel_recalc,
+       .set_rate       = clksel_set_rate,
+       .init           = demod_clk_init,
+//     .set_parent     = demod_clk_set_parent,
+       .clksel_reg     = CLKSEL1_REG,
+       .clksel_mask    = 0xFF << 16,
+       .clksel_shift   = 16,
+       .clksel_maxdiv  = 128,
+};
+
+static struct clk codec_clk = {
+       .name           = "codec",
+       .parent         = &codec_pll_clk,
+       .recalc         = clksel_recalc,
+       .set_rate       = clksel_set_rate,
+       .clksel_reg     = CLKSEL1_REG,
+       .clksel_mask    = 0x1F << 3,
+       .clksel_shift   = 3,
+       .clksel_maxdiv  = 32,
+};
+
+static struct clk lcdc_divider_clk = {
+       .name           = "lcdc_divider",
+       .parent         = &arm_pll_clk,
+       .recalc         = clksel_recalc,
+       .set_rate       = clksel_set_rate,
+       .clksel_reg     = CLKSEL0_REG,
+       .clksel_mask    = 0xFF << 8,
+       .clksel_shift   = 8,
+       .clksel_maxdiv  = 128,
+};
+
+static void lcdc_clk_init(struct clk *clk)
 {
-       if (rk2818_proc_comm(PCOM_CLKCTL_RPC_ENABLED, &id, NULL))
-               return 0;
-       else
-               return id;
+       u32 r = readl(&scu_register_base->scu_clksel0_config) & (1 << 7);
+       struct clk *real_parent = r ? &extclk : &lcdc_divider_clk;
+       if (real_parent != clk->parent) {
+               pr_debug("clock: inited %s parent to %s (was %s)\n", clk->name, real_parent->name, ((clk->parent) ? clk->parent->name : "NULL"));
+               clk_reparent(clk, real_parent);
+       }
 }
 
-static inline int pc_pll_request(unsigned id, unsigned on)
+static int gate_mode(struct clk *clk, int on)
 {
-       on = !!on;
-       return rk2818_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on);
+       u32 *reg;
+       int idx = clk->gate_idx;
+       u32 v;
+
+       if (idx >= SCU_IPID_GATE_MAX)
+               return -EINVAL;
+
+       reg = &scu_register_base->scu_clkgate0_config;
+       reg += (idx >> 5);
+       idx &= 0x1F;
+
+       v = readl(reg);
+       if (on) {
+               v &= ~(1 << idx);       // clear bit 
+       } else {
+               v |= (1 << idx);        // set bit
+       }
+       writel(v, reg);
+
+       return 0;
 }
 
-/*
- * Standard clock functions defined in include/linux/clk.h
+/**
+ * uart_clk_init_ - set a uart clk's parent field from the hardware
+ * @clk: clock struct ptr to use
+ *
+ * Given a pointer to a source-selectable struct clk, read the hardware
+ * register and determine what its parent is currently set to.  Update the
+ * clk->parent field with the appropriate clk ptr.
  */
-struct clk *clk_get(struct device *dev, const char *id)
+static void uart_clk_init(struct clk *clk)
 {
-       struct clk *clk;
+       u32 r = readl(&scu_register_base->scu_clksel1_config) >> 31;
+       struct clk *real_parent = r ? &clk48m : &xin24m;
+       if (real_parent != clk->parent) {
+               pr_debug("clock: inited %s parent to %s (was %s)\n", clk->name, real_parent->name, ((clk->parent) ? clk->parent->name : "NULL"));
+               clk_reparent(clk, real_parent);
+       }
+}
 
-       mutex_lock(&clocks_mutex);
+#define UART_CLK(n) \
+static struct clk uart##n##_clk = { \
+       .name           = "uart"#n, \
+       .parent         = &xin24m, \
+       .gate_idx       = SCU_IPID_UART##n, \
+       .mode           = gate_mode, \
+       .recalc         = followparent_recalc, \
+       .init           = uart_clk_init, \
+}
 
-       list_for_each_entry(clk, &clocks, list)
-               if (!strcmp(id, clk->name) && clk->dev == dev)
-                       goto found_it;
+#define GATE_CLK(NAME,PARENT,ID) \
+static struct clk NAME##_clk = { \
+       .name           = #NAME, \
+       .parent         = &PARENT, \
+       .gate_idx       = SCU_IPID_##ID, \
+       .mode           = gate_mode, \
+       .recalc         = followparent_recalc, \
+}
 
-       list_for_each_entry(clk, &clocks, list)
-               if (!strcmp(id, clk->name) && clk->dev == NULL)
-                       goto found_it;
+GATE_CLK(arm_core, arm_clk, ARM);
+GATE_CLK(dsp, dsp_pll_clk, DSP);
+GATE_CLK(dma, arm_hclk, DMA);
+GATE_CLK(sramarm, arm_hclk, SRAMARM);
+GATE_CLK(sramdsp, arm_hclk, SRAMDSP);
+GATE_CLK(hif, arm_hclk, HIF);
+GATE_CLK(otgbus, arm_hclk, OTGBUS);
+//GATE_CLK(otgphy, arm_hclk, OTGPHY); //FIXME
+GATE_CLK(nandc, arm_hclk, NANDC);
+GATE_CLK(intc, arm_hclk, INTC);
+GATE_CLK(deblocking_rv, arm_hclk, DEBLK);
+static struct clk lcdc_clk = {
+       .name           = "lcdc",
+       .parent         = &lcdc_divider_clk,
+       .gate_idx       = SCU_IPID_LCDC,
+       .mode           = gate_mode,
+       .recalc         = followparent_recalc,
+       .init           = lcdc_clk_init,
+//     .set_parent     = lcdc_clk_set_parent,
+};
+GATE_CLK(vip, arm_hclk, VIP); //FIXME
+GATE_CLK(i2s, arm_pclk, I2S); //FIXME
+static struct clk sdmmc0_clk = {
+       .name           = "sdmmc0",
+       .parent         = &arm_hclk,
+       .gate_idx       = SCU_IPID_SDMMC0,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc,
+       .set_rate       = clksel_set_rate,
+       .clksel_reg     = CLKSEL0_REG,
+       .clksel_mask    = 7 << 4,
+       .clksel_shift   = 4,
+       .clksel_maxdiv  = 8,
+};
 
-       clk = ERR_PTR(-ENOENT);
-found_it:
-       mutex_unlock(&clocks_mutex);
-       return clk;
+GATE_CLK(ebrom, arm_hclk, EBROM);
+GATE_CLK(gpio0, arm_pclk, GPIO0);
+GATE_CLK(gpio1, arm_pclk, GPIO1);
+UART_CLK(0);
+UART_CLK(1);
+GATE_CLK(i2c0, arm_pclk, I2C0);
+GATE_CLK(i2c1, arm_pclk, I2C1);
+GATE_CLK(spi0, arm_pclk, SPI0);
+GATE_CLK(spi1, arm_pclk, SPI1);
+GATE_CLK(pwm, arm_pclk, PWM);
+GATE_CLK(timer, arm_pclk, TIMER);
+GATE_CLK(wdt, arm_pclk, WDT);
+GATE_CLK(rtc, arm_pclk, RTC);
+static struct clk lsadc_clk = {
+       .name           = "lsadc",
+       .parent         = &arm_pclk,
+       .gate_idx       = SCU_IPID_LSADC,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc,
+       .set_rate       = clksel_set_rate,
+       .clksel_reg     = CLKSEL1_REG,
+       .clksel_mask    = 0xFF << 8,
+       .clksel_shift   = 8,
+       .clksel_maxdiv  = 128,
+};
+UART_CLK(2);
+UART_CLK(3);
+static struct clk sdmmc1_clk = {
+       .name           = "sdmmc1",
+       .parent         = &arm_hclk,
+       .gate_idx       = SCU_IPID_SDMMC1,
+       .mode           = gate_mode,
+       .recalc         = clksel_recalc,
+       .set_rate       = clksel_set_rate,
+       .clksel_reg     = CLKSEL2_REG,
+       .clksel_mask    = 7 << 8,
+       .clksel_shift   = 8,
+       .clksel_maxdiv  = 8,
+};
+
+static unsigned long hsadc_clk_recalc(struct clk *clk)
+{
+       return clk->parent->rate >> 1;
 }
-EXPORT_SYMBOL(clk_get);
 
-void clk_put(struct clk *clk)
+static struct clk hsadc_clk = {
+       .name           = "hsadc",
+       .parent         = &demod_clk,
+       .gate_idx       = SCU_IPID_HSADC,
+       .mode           = gate_mode,
+       .recalc         = hsadc_clk_recalc,
+};
+//GATE_CLK(mobile_sdram_common, arm_hclk, MOBILE_SDARM_COMMON);
+//GATE_CLK(sdram_controller, arm_hclk, SDRAM_CONTROLLER);
+//GATE_CLK(mobile_sdram_controller, arm_hclk, MOBILE_SDRAM_CONTROLLER);
+//GATE_CLK(lcdc_share_memory, arm_hclk, LCDC_SHARE_MEMORY); //FIXME
+//GATE_CLK(lcdc_hclk, arm_hclk, LCDC_HCLK); //FIXME
+//GATE_CLK(deblocking_h264, arm_hclk, DEBLK_H264);
+//GATE_CLK(gpu, arm_hclk, GPU);
+//GATE_CLK(ddr_hclk, arm_hclk, DDR_HCLK); //FIXME
+//GATE_CLK(ddr, arm_hclk, DDR); //FIXME
+//GATE_CLK(customized_sdram_controller, ); //FIXME
+//GATE_CLK(mcdma, arm_hclk, MCDMA); //FIXME
+//GATE_CLK(sdram, arm_hclk, SDRAM); //FIXME
+//GATE_CLK(ddr_axi, arm_hclk, DDR_AXI); //FIXME
+//GATE_CLK(dsp_timer, ); //FIXME
+//GATE_CLK(dsp_slave, ); //FIXME
+//GATE_CLK(dsp_master, ); //FIXME
+//GATE_CLK(usb_host, ); //FIXME
+
+GATE_CLK(armibus, arm_hclk, ARMIBUS);
+GATE_CLK(armdbus, arm_hclk, ARMDBUS);
+GATE_CLK(dspbus, arm_hclk, DSPBUS);
+GATE_CLK(expbus, arm_hclk, EXPBUS);
+GATE_CLK(apbbus, arm_hclk, APBBUS);
+GATE_CLK(efuse, arm_pclk, EFUSE);
+GATE_CLK(dtcm1, arm_clk, DTCM1);
+GATE_CLK(dtcm0, arm_clk, DTCM0);
+GATE_CLK(itcm, arm_clk, ITCM);
+GATE_CLK(videobus, arm_hclk, VIDEOBUS);
+
+#define CLK(dev, con, ck) \
+       { \
+               .dev_id = dev, \
+               .con_id = con, \
+               .clk = ck, \
+       }
+
+#define CLK1(name) \
+       { \
+               .dev_id = NULL, \
+               .con_id = #name, \
+               .clk = &name##_clk, \
+       }
+
+static struct clk_lookup clks[] = {
+       CLK(NULL, "xin24m", &xin24m),
+       CLK(NULL, "extclk", &extclk),
+
+       CLK(NULL, "clk12m", &clk12m),
+       CLK1(arm_pll),
+       CLK1(dsp_pll),
+       CLK1(codec_pll),
+       CLK1(arm),
+       CLK(NULL, "arm_hclk", &arm_hclk),
+       CLK(NULL, "clk48m", &clk48m),
+       CLK(NULL, "arm_pclk", &arm_pclk),
+       CLK1(demod),
+       CLK1(codec),
+       CLK1(lcdc_divider),
+
+       CLK1(arm_core),
+       CLK1(dsp),
+       CLK1(dma),
+       CLK1(sramarm),
+       CLK1(sramdsp),
+       CLK1(hif),
+       CLK1(otgbus),
+       //CLK1(otgphy), //FIXME
+       CLK1(nandc),
+       CLK1(intc),
+       CLK1(deblocking_rv),
+       CLK1(lcdc),
+       CLK1(vip), //FIXME
+       CLK1(i2s), //FIXME
+       CLK1(sdmmc0),
+       CLK1(ebrom),
+       CLK1(gpio0),
+       CLK1(gpio1),
+       CLK("rk2818_serial.0", "uart", &uart0_clk),
+       CLK("rk2818_serial.1", "uart", &uart1_clk),
+       CLK1(i2c0),
+       CLK1(i2c1),
+       CLK1(spi0),
+       CLK1(spi1),
+       CLK1(pwm),
+       CLK1(timer),
+       CLK1(wdt),
+       CLK1(rtc),
+       CLK1(lsadc),
+       CLK("rk2818_serial.2", "uart", &uart2_clk),
+       CLK("rk2818_serial.3", "uart", &uart3_clk),
+       CLK1(sdmmc1),
+
+       CLK1(hsadc),
+       //CLK1(mobile_sdram_common),
+       //CLK1(sdram_controller),
+       //CLK1(mobile_sdram_controller),
+       //CLK1(lcdc_share_memory), //FIXME
+       //CLK1(lcdc_hclk), //FIXME
+       //CLK1(deblocking_h264),
+       //CLK1(gpu),
+       //CLK1(ddr_hclk), //FIXME
+       //CLK1(ddr), //FIXME
+       //CLK1(customized_sdram_controller), //FIXME
+       //CLK1(mcdma), //FIXME
+       //CLK1(sdram), //FIXME
+       //CLK1(ddr_axi), //FIXME
+       //CLK1(dsp_timer), //FIXME
+       //CLK1(dsp_slave), //FIXME
+       //CLK1(dsp_master), //FIXME
+       //CLK1(usb_host), //FIXME
+
+       CLK1(armibus),
+       CLK1(armdbus),
+       CLK1(dspbus),
+       CLK1(expbus),
+       CLK1(apbbus),
+       CLK1(efuse),
+       CLK1(dtcm1),
+       CLK1(dtcm0),
+       CLK1(itcm),
+       CLK1(videobus),
+};
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
+
+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("clock: %s enabled\n", clk->name);
+       }
+       clk->usecount++;
+
+       return ret;
 }
-EXPORT_SYMBOL(clk_put);
 
 int clk_enable(struct clk *clk)
 {
+       int ret = 0;
        unsigned long flags;
-       spin_lock_irqsave(&clocks_lock, flags);
-       clk->count++;
-       if (clk->count == 1)
-               pc_clk_enable(clk->id);
-       spin_unlock_irqrestore(&clocks_lock, flags);
-       return 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       ret = __clk_enable(clk);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       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("clock: %s disabled\n", clk->name);
+       }
+       if (clk->parent)
+               __clk_disable(clk->parent);
+}
+
 void clk_disable(struct clk *clk)
 {
        unsigned long flags;
-       spin_lock_irqsave(&clocks_lock, flags);
-       BUG_ON(clk->count == 0);
-       clk->count--;
-       if (clk->count == 0)
-               pc_clk_disable(clk->id);
-       spin_unlock_irqrestore(&clocks_lock, flags);
+
+       if (clk == NULL || IS_ERR(clk))
+               return;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       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:
+       spin_unlock_irqrestore(&clockfw_lock, flags);
 }
 EXPORT_SYMBOL(clk_disable);
 
 unsigned long clk_get_rate(struct clk *clk)
 {
-       return pc_clk_get_rate(clk->id);
+       unsigned long flags;
+       unsigned long ret;
+
+       if (clk == NULL || IS_ERR(clk))
+               return 0;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       ret = clk->rate;
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       return ret;
 }
 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)
+{
+       unsigned long flags;
+       long ret = 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return ret;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       ret = __clk_round_rate(clk, rate);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       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("clock: 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;
+}
+
 int clk_set_rate(struct clk *clk, unsigned long rate)
 {
-       int ret;
-       if (clk->flags & CLKFLAG_USE_MIN_MAX_TO_SET) {
-               ret = pc_clk_set_max_rate(clk->id, rate);
-               if (ret)
-                       return ret;
-               return pc_clk_set_min_rate(clk->id, rate);
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (clk == NULL || IS_ERR(clk))
+               return ret;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       ret = __clk_set_rate(clk, rate);
+       if (ret == 0) {
+               if (clk->recalc)
+                       clk->rate = clk->recalc(clk);
+               propagate_rate(clk);
        }
-       return pc_clk_set_rate(clk->id, rate);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       return ret;
 }
 EXPORT_SYMBOL(clk_set_rate);
 
+static int __clk_set_parent(struct clk *clk, struct clk *new_parent)
+{
+       return -EINVAL; // FIXME
+}
+
 int clk_set_parent(struct clk *clk, struct clk *parent)
 {
-       return -ENOSYS;
+       unsigned long flags;
+       int ret = -EINVAL;
+
+       if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
+               return ret;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       if (clk->usecount == 0) {
+               ret = __clk_set_parent(clk, parent);
+               if (ret == 0) {
+                       if (clk->recalc)
+                               clk->rate = clk->recalc(clk);
+                       propagate_rate(clk);
+               }
+       } else
+               ret = -EBUSY;
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+
+       return ret;
 }
 EXPORT_SYMBOL(clk_set_parent);
 
 struct clk *clk_get_parent(struct clk *clk)
 {
-       return ERR_PTR(-ENOSYS);
+       return clk->parent;
 }
 EXPORT_SYMBOL(clk_get_parent);
 
-int clk_set_flags(struct clk *clk, unsigned long flags)
+static void clk_reparent(struct clk *child, struct clk *parent)
+{
+       list_del_init(&child->sibling);
+       if (parent)
+               list_add(&child->sibling, &parent->children);
+       child->parent = parent;
+
+       /* now do the debugfs renaming to reattach the child
+          to the proper parent */
+}
+
+/* Propagate rate to children */
+static void propagate_rate(struct clk *tclk)
+{
+       struct clk *clkp;
+
+       list_for_each_entry(clkp, &tclk->children, sibling) {
+               if (clkp->recalc)
+                       clkp->rate = clkp->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) {
+               if (clkp->recalc)
+                       clkp->rate = clkp->recalc(clkp);
+               propagate_rate(clkp);
+       }
+}
+
+/**
+ * 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;
-       return pc_clk_set_flags(clk->id, flags);
+
+       /*
+        * trap out already registered clocks
+        */
+       if (clk->node.next || clk->node.prev)
+               return 0;
+
+       mutex_lock(&clocks_mutex);
+       if (clk->parent)
+               list_add(&clk->sibling, &clk->parent->children);
+       else
+               list_add(&clk->sibling, &root_clks);
+
+       list_add(&clk->node, &clocks);
+       if (clk->init)
+               clk->init(clk);
+       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);
+       }
 }
-EXPORT_SYMBOL(clk_set_flags);
 
+#ifdef CONFIG_CPU_FREQ
+void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&clockfw_lock, flags);
+       __clk_init_cpufreq_table(table);
+       spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_init_cpufreq_table);
+#endif
+
+static unsigned int __initdata armclk;
+
+/*
+ * By default we use the rate set by the bootloader.
+ * You can override this with armclk= cmdline option.
+ */
+static int __init clk_setup(char *str)
+{
+       get_option(&str, &armclk);
+
+       if (!armclk)
+               return 1;
+
+       if (armclk < 1000)
+               armclk *= 1000000;
+
+       return 1;
+}
+__setup("armclk=", clk_setup);
+
+/*
+ * Switch the arm_clk rate if specified on cmdline.
+ * We cannot do this early until cmdline is parsed.
+ */
+static int __init rk28_clk_arch_init(void)
+{
+       if (!armclk)
+               return -EINVAL;
+
+       if (clk_set_rate(&arm_clk, armclk))
+               printk(KERN_ERR "*** Unable to set arm_clk rate\n");
+
+       recalculate_root_clocks();
+
+       printk(KERN_INFO "Switched to new clocking rate (pll/arm/hclk/pclk): "
+              "%ld/%ld/%ld/%ld MHz\n",
+              arm_pll_clk.rate / 1000000, arm_clk.rate / 1000000,
+              arm_hclk.rate / 1000000, arm_pclk.rate / 1000000);
+
+       calibrate_delay();
+
+       return 0;
+}
+arch_initcall(rk28_clk_arch_init);
 
 void __init rk2818_clock_init(void)
 {
-       unsigned n;
+       struct clk_lookup *lk;
 
-       spin_lock_init(&clocks_lock);
-       mutex_lock(&clocks_mutex);
-       for (n = 0; n < rk2818_num_clocks; n++)
-               list_add_tail(&rk2818_clocks[n].list, &clocks);
-       mutex_unlock(&clocks_mutex);
+       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 (pll/arm/hclk/pclk): "
+              "%ld/%ld/%ld/%ld MHz\n",
+              arm_pll_clk.rate / 1000000, arm_clk.rate / 1000000,
+              arm_hclk.rate / 1000000, arm_pclk.rate / 1000000);
+
+       /*
+        * Only enable those clocks we will need, let the drivers
+        * enable other clocks as necessary
+        */
+       clk_enable_init_clocks();
 }
 
-/* The bootloader and/or AMSS may have left various clocks enabled.
- * Disable any clocks that belong to us (CLKFLAG_AUTO_OFF) but have
- * not been explicitly enabled by a clk_enable() call.
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
+/*
+ *     debugfs support to trace clock tree hierarchy and attributes
  */
-static int __init clock_late_init(void)
+static struct dentry *clk_debugfs_root;
+
+static int clk_debugfs_register_one(struct clk *c)
 {
-       unsigned long flags;
-       struct clk *clk;
-       unsigned count = 0;
+       int err;
+       struct dentry *d, *child;
+       struct clk *pa = c->parent;
+       char s[255];
+       char *p = s;
 
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(clk, &clocks, list) {
-               if (clk->flags & CLKFLAG_AUTO_OFF) {
-                       spin_lock_irqsave(&clocks_lock, flags);
-                       if (!clk->count) {
-                               count++;
-                               pc_clk_disable(clk->id);
-                       }
-                       spin_unlock_irqrestore(&clocks_lock, flags);
-               }
+       p += sprintf(p, "%s", c->name);
+       d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
+       if (!d)
+               return -ENOMEM;
+       c->dent = d;
+
+       d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+       d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
+       if (!d) {
+               err = -ENOMEM;
+               goto err_out;
        }
-       mutex_unlock(&clocks_mutex);
-       pr_info("clock_late_init() disabled %d unused clocks\n", count);
        return 0;
+
+err_out:
+       d = c->dent;
+       list_for_each_entry(child, &d->d_subdirs, d_u.d_child)
+               debugfs_remove(child);
+       debugfs_remove(c->dent);
+       return err;
 }
 
-late_initcall(clock_late_init);
+static int clk_debugfs_register(struct clk *c)
+{
+       int err;
+       struct clk *pa = c->parent;
+
+       if (pa && !pa->dent) {
+               err = clk_debugfs_register(pa);
+               if (err)
+                       return err;
+       }
+
+       if (!c->dent) {
+               err = clk_debugfs_register_one(c);
+               if (err)
+                       return err;
+       }
+       return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+       struct clk *c;
+       struct dentry *d;
+       int err;
+
+       d = debugfs_create_dir("clock", NULL);
+       if (!d)
+               return -ENOMEM;
+       clk_debugfs_root = d;
+
+       list_for_each_entry(c, &clocks, node) {
+               err = clk_debugfs_register(c);
+               if (err)
+                       goto err_out;
+       }
+       return 0;
+err_out:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+       debugfs_remove_recursive(clk_debugfs_root);
+#endif
+       return err;
+}
+late_initcall(clk_debugfs_init);
+
+#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */
+
diff --git a/arch/arm/mach-rk2818/clock.h b/arch/arm/mach-rk2818/clock.h
deleted file mode 100644 (file)
index 4059b10..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/* arch/arm/mach-rk2818/clock.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 __ARCH_ARM_MACH_RK2818_CLOCK_H
-#define __ARCH_ARM_MACH_RK2818_CLOCK_H
-
-#include <linux/list.h>
-
-#define CLKFLAG_INVERT                 0x00000001
-#define CLKFLAG_NOINVERT               0x00000002
-#define CLKFLAG_NONEST                 0x00000004
-#define CLKFLAG_NORESET                        0x00000008
-
-#define CLK_FIRST_AVAILABLE_FLAG       0x00000100
-#define CLKFLAG_USE_MIN_MAX_TO_SET     0x00000200
-#define CLKFLAG_AUTO_OFF               0x00000400
-
-struct clk {
-       uint32_t id;
-       uint32_t count;
-       uint32_t flags;
-       const char *name;
-       struct list_head list;
-       struct device *dev;
-};
-
-//#define A11S_CLK_CNTL_ADDR           (MSM_CSR_BASE + 0x100)
-//#define A11S_CLK_SEL_ADDR            (MSM_CSR_BASE + 0x104)
-//#define A11S_VDD_SVS_PLEVEL_ADDR     (MSM_CSR_BASE + 0x124)
-
-extern struct clk rk2818_clocks[];
-extern unsigned rk2818_num_clocks;
-
-#endif
-