rk2928:sdk: add clock support
authorchenxing <chenxing@ubuntu.(none)>
Mon, 6 Aug 2012 06:51:32 +0000 (14:51 +0800)
committerchenxing <chenxing@ubuntu.(none)>
Mon, 6 Aug 2012 06:51:32 +0000 (14:51 +0800)
arch/arm/mach-rk2928/Makefile
arch/arm/mach-rk2928/board-rk2928-sdk.c
arch/arm/mach-rk2928/clock.c [new file with mode: 0755]
arch/arm/mach-rk2928/clock.h [new file with mode: 0644]
arch/arm/mach-rk2928/clock_data.c [new file with mode: 0644]
arch/arm/mach-rk2928/include/mach/board.h
arch/arm/mach-rk2928/include/mach/clock.h [new file with mode: 0755]
arch/arm/mach-rk2928/include/mach/cru.h [new file with mode: 0755]

index a9df193cfc0a123df588db1b0f7ca64d130d3614..68053947e8301d9bdde29f0329068690ddea5f68 100644 (file)
@@ -4,6 +4,8 @@ obj-y += reset.o
 obj-y += timer.o
 obj-y += devices.o
 obj-y += iomux.o
+obj-y += clock.o
+obj-y += clock_data.o
 obj-$(CONFIG_PM) += pm.o
 
 obj-$(CONFIG_MACH_RK2928_FPGA) += board-rk2928-fpga.o board-rk2928-fpga-key.o
index b01d4d92868b73b07ded21868842c496cd2d4d19..2a433f41c3e8e766cb5447dc1e8bdc08e432db80 100755 (executable)
@@ -1189,81 +1189,10 @@ static void __init rk2928_reserve(void)
        board_mem_reserved();
 }
 
-#if 1
-#include <linux/clkdev.h>
-
-struct clk {
-       const char              *name;
-       unsigned long           rate;
-};
-
-static struct clk xin24m = {
-       .name           = "xin24m",
-       .rate           = 24000000,
-};
-
-#define CLK(dev, con, ck) \
-       { \
-               .dev_id = dev, \
-               .con_id = con, \
-               .clk = ck, \
-       }
-
-static struct clk_lookup clks[] = {
-       CLK("rk30_i2c.0", "i2c", &xin24m),
-       CLK("rk30_i2c.1", "i2c", &xin24m),
-       CLK("rk30_i2c.2", "i2c", &xin24m),
-       CLK("rk30_i2c.3", "i2c", &xin24m),
-       CLK("rk29xx_spim.0", "spi", &xin24m),
-       CLK("rk29xx_spim.1", "spi", &xin24m),
-
-        CLK("rk_serial.0", "uart_div", &xin24m),
-       CLK("rk_serial.0", "uart_frac_div", &xin24m),
-       CLK("rk_serial.0", "uart", &xin24m),
-       CLK("rk_serial.0", "pclk_uart", &xin24m),
-       CLK("rk_serial.1", "uart_div", &xin24m),
-       CLK("rk_serial.1", "uart_frac_div", &xin24m),
-       CLK("rk_serial.1", "uart", &xin24m),
-       CLK("rk_serial.1", "pclk_uart", &xin24m),
-       CLK("rk_serial.2", "uart_div", &xin24m),
-       CLK("rk_serial.2", "uart_frac_div", &xin24m),
-       CLK("rk_serial.2", "uart", &xin24m),
-       CLK("rk_serial.2", "pclk_uart", &xin24m),
-
-        CLK("rk29_i2s.0", "i2s_div", &xin24m),
-       CLK("rk29_i2s.0", "i2s_frac_div", &xin24m),
-       CLK("rk29_i2s.0", "i2s", &xin24m),
-       CLK("rk29_i2s.0", "hclk_i2s", &xin24m),
-        CLK(NULL, "pd_lcdc0", &xin24m),
-        CLK(NULL, "hclk_lcdc0", &xin24m),
-        CLK(NULL, "aclk_lcdc0", &xin24m),
-        CLK(NULL, "dclk_lcdc0", &xin24m),
-
-        CLK(NULL, "pd_cif0", &xin24m),
-        CLK(NULL, "aclk_cif0", &xin24m),
-        CLK(NULL, "hclk_cif0", &xin24m),
-        CLK(NULL, "cif0_in", &xin24m),
-        CLK(NULL, "cif0_out", &xin24m),
-};
-
-void __init rk30_clock_init(void)
-{
-       struct clk_lookup *lk;
-
-       for (lk = clks; lk < clks + ARRAY_SIZE(clks); lk++) {
-               clkdev_add(lk);
-       }
-}
-
 void __init board_clock_init(void)
 {
-        rk30_clock_init();
+       rk2928_clock_data_init(periph_pll_default, codec_pll_default, RK30_CLOCKS_DEFAULT_FLAGS);
 }
-#else
-void __init board_clock_init(void)
-{
-}
-#endif
 
 
 MACHINE_START(RK2928, "RK2928board")
diff --git a/arch/arm/mach-rk2928/clock.c b/arch/arm/mach-rk2928/clock.c
new file mode 100755 (executable)
index 0000000..02530f2
--- /dev/null
@@ -0,0 +1,754 @@
+/* linux/arch/arm/mach-rk30/clock.c
+ *
+ * Copyright (C) 2012 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/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/hardirq.h>
+#include <linux/delay.h>
+#include <mach/clock.h>
+#include "clock.h"
+//#include <mach/dvfs.h>
+#include <linux/delay.h>
+
+#define CLOCK_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args);
+#define CLOCK_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args);
+#define CLOCK_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args);
+
+/* Clock flags */
+/* bit 0 is free */
+#define RATE_FIXED             (1 << 1)        /* Fixed clock rate */
+#define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
+
+#define MHZ                    (1000*1000)
+#define KHZ                    (1000)
+
+static void __clk_recalc(struct clk *clk);
+static void __propagate_rate(struct clk *tclk);
+static void __clk_reparent(struct clk *child, struct clk *parent);
+
+static LIST_HEAD(clocks);
+static DEFINE_MUTEX(clocks_mutex);
+static DEFINE_SPINLOCK(clockfw_lock);
+static LIST_HEAD(root_clks);
+static void clk_notify(struct clk *clk, unsigned long msg,
+                      unsigned long old_rate, unsigned long new_rate);
+
+#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)
+/**********************************************for clock data****************************************************/
+static struct clk *def_ops_clk=NULL;
+
+void clk_register_default_ops_clk(struct clk *clk)
+{
+       def_ops_clk=clk;
+}
+
+static struct clk *clk_default_get_parent(struct clk *clk)
+{
+       if(def_ops_clk&&def_ops_clk->get_parent)
+               return def_ops_clk->get_parent(clk);
+       else return NULL;
+
+
+
+}
+static int clk_default_set_parent(struct clk *clk, struct clk *parent)
+{
+       if(def_ops_clk&&def_ops_clk->set_parent)
+               return def_ops_clk->set_parent(clk,parent);
+       else
+               return -EINVAL;
+}
+
+int __init clk_disable_unused(void)
+{
+       struct clk *ck;
+       list_for_each_entry(ck, &clocks, node) {
+       if (ck->usecount > 0 || ck->mode == NULL || (ck->flags & IS_PD))
+               continue;
+               LOCK();
+               clk_enable_nolock(ck);
+               clk_disable_nolock(ck);
+               UNLOCK();
+       }
+       return 0;
+}
+/**
+ * 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.
+ */
+void clk_recalculate_root_clocks_nolock(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();
+       clk_recalculate_root_clocks_nolock();
+       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.
+ */
+int clk_register(struct clk *clk)
+{
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+       //INIT_LIST_HEAD(&clk->sibling);
+       INIT_LIST_HEAD(&clk->children);
+       /*
+        * 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 =clk_default_get_parent(clk);
+       
+       if (clk->parent){
+               printk("clk has parent\n");
+               list_add(&clk->sibling, &clk->parent->children);
+       }
+       else{
+               printk("clk has no parent\n");
+               list_add(&clk->sibling, &root_clks);
+       }
+       list_add(&clk->node, &clocks);
+       mutex_unlock(&clocks_mutex);    
+       return 0;
+}
+
+/************************************************************/
+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;
+}
+static void __clk_reparent(struct clk *child, struct clk *parent)
+{
+       if (child->parent == parent)
+               return;
+       //CLOCK_PRINTK_DBG("%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;
+       
+       //CLOCK_PRINTK_DBG("propagate_rate clk %s\n",clkp->name);
+       
+       list_for_each_entry(clkp, &tclk->children, sibling) {
+               __clk_recalc(clkp);
+               __propagate_rate(clkp);
+       }
+       //CLOCK_PRINTK_DBG("propagate_rate clk %s end\n",clkp->name);
+}
+
+int clk_enable_nolock(struct clk *clk)
+{
+       int ret = 0;
+
+       if (clk->usecount == 0) {
+               if (clk->parent) {
+                       ret = clk_enable_nolock(clk->parent);
+                       if (ret)
+                               return ret;
+               }
+
+               if (clk->notifier_count)
+                       clk_notify(clk, CLK_PRE_ENABLE, clk->rate, clk->rate);
+               if (clk->mode)
+                       ret = clk->mode(clk, 1);
+               if (clk->notifier_count)
+                       clk_notify(clk, ret ? CLK_ABORT_ENABLE : CLK_POST_ENABLE, clk->rate, clk->rate);
+               if (ret) {
+                       if (clk->parent)
+                               clk_disable_nolock(clk->parent);
+                       return ret;
+               }
+               //pr_debug("%s enabled\n", clk->name);
+               printk("%s enabled\n", clk->name);
+       }
+       clk->usecount++;
+
+       return ret;
+}
+void clk_disable_nolock(struct clk *clk)
+{
+       if (clk->usecount == 0) {
+               CLOCK_PRINTK_ERR(KERN_ERR "Trying disable clock %s with 0 usecount\n", clk->name);
+               WARN_ON(1);
+               return;
+       }
+       if (--clk->usecount == 0) {
+               int ret = 0;
+               if (clk->notifier_count)
+                       clk_notify(clk, CLK_PRE_DISABLE, clk->rate, clk->rate);
+               if (clk->mode)
+                       ret = clk->mode(clk, 0);
+               if (clk->notifier_count)
+                       clk_notify(clk, ret ? CLK_ABORT_DISABLE : CLK_POST_DISABLE, clk->rate, clk->rate);
+               pr_debug("%s disabled\n", clk->name);
+               if (ret == 0 && clk->parent)
+                       clk_disable_nolock(clk->parent);
+       }
+}
+/* Given a clock and a rate apply a clock specific rounding function */
+long clk_round_rate_nolock(struct clk *clk, unsigned long rate)
+{
+       if (clk->round_rate)
+               return clk->round_rate(clk, rate);
+
+       if (clk->flags & RATE_FIXED)
+               CLOCK_PRINTK_ERR("clock: clk_round_rate called on fixed-rate clock %s\n", clk->name);
+
+       return clk->rate;
+}
+int is_suport_round_rate(struct clk *clk)
+{
+       return (clk->round_rate) ? 0:(-1);
+}
+
+int clk_set_rate_nolock(struct clk *clk, unsigned long rate)
+{
+       int ret;
+       unsigned long old_rate;
+
+       if (rate == clk->rate)
+               return 0;
+       if (clk->flags & CONFIG_PARTICIPANT)
+               return -EINVAL;
+
+       if (!clk->set_rate)
+               return -EINVAL;
+       
+       printk("**will set %s rate %lu\n", clk->name, rate);
+
+       old_rate = clk->rate;
+       if (clk->notifier_count)
+               clk_notify(clk, CLK_PRE_RATE_CHANGE, old_rate, rate);
+
+       ret = clk->set_rate(clk, rate);
+
+       if (ret == 0) {
+               __clk_recalc(clk);
+               printk("**set %s rate recalc=%lu\n",clk->name,clk->rate);
+               __propagate_rate(clk);
+       }
+
+       if (clk->notifier_count)
+               clk_notify(clk, ret ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE, old_rate, clk->rate);
+
+       return ret;
+}
+int clk_set_parent_nolock(struct clk *clk, struct clk *parent)
+{
+       int ret;
+       int enabled = clk->usecount > 0;
+       struct clk *old_parent = clk->parent;
+
+       if (clk->parent == parent)
+               return 0;
+
+       /* if clk is already enabled, enable new parent first and disable old parent later. */
+       if (enabled)
+               clk_enable_nolock(parent);
+
+       if (clk->set_parent)
+               ret = clk->set_parent(clk, parent);
+       else
+               ret = clk_default_set_parent(clk,parent);
+
+       if (ret == 0) {
+               /* OK */
+               
+               //CLOCK_PRINTK_DBG("set_parent %s reparent\n",clk->name,parent->name);
+               __clk_reparent(clk, parent);
+               __clk_recalc(clk);
+               __propagate_rate(clk);
+               if (enabled)
+                       clk_disable_nolock(old_parent);
+       } else {
+               //CLOCK_PRINTK_DBG("set_parent err\n",clk->name,parent->name);
+               if (enabled)
+                       clk_disable_nolock(parent);
+       }
+
+       return ret;
+}
+/**********************************dvfs****************************************************/
+#if 0
+struct clk_node *clk_get_dvfs_info(struct clk *clk)
+{
+    return clk->dvfs_info;
+}
+
+int clk_set_rate_locked(struct clk * clk,unsigned long rate)
+{
+       int ret;
+       //CLOCK_PRINTK_DBG("%s dvfs clk_set_locked\n",clk->name);
+       LOCK();
+    ret=clk_set_rate_nolock(clk, rate);;
+    UNLOCK();
+       return ret;
+       
+}
+void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk)
+{
+    clk->dvfs_info = dvfs_clk;
+}
+#endif
+
+/*-------------------------------------------------------------------------
+ * Optional clock functions defined in include/linux/clk.h
+ *-------------------------------------------------------------------------*/
+#ifdef RK30_CLK_OFFBOARD_TEST
+long rk30_clk_round_rate(struct clk *clk, unsigned long rate)
+#else
+long clk_round_rate(struct clk *clk, unsigned long rate)
+#endif
+{
+       long ret = 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return ret;
+
+       LOCK();
+       ret = clk_round_rate_nolock(clk, rate);
+       UNLOCK();
+
+       return ret;
+}
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_round_rate);
+#else
+EXPORT_SYMBOL(clk_round_rate);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+unsigned long rk30_clk_get_rate(struct clk *clk)
+#else
+unsigned long clk_get_rate(struct clk *clk)
+#endif
+{
+       if (clk == NULL || IS_ERR(clk))
+               return 0;
+
+       return clk->rate;
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_get_rate);
+#else
+EXPORT_SYMBOL(clk_get_rate);
+#endif
+
+
+/* Set the clock rate for a clock source */
+#ifdef RK30_CLK_OFFBOARD_TEST
+int rk30_clk_set_rate(struct clk *clk, unsigned long rate)
+#else
+int clk_set_rate(struct clk *clk, unsigned long rate)
+#endif
+{
+       int ret = -EINVAL;
+       if (clk == NULL || IS_ERR(clk)){
+               return ret;
+       }
+       if (rate == clk->rate)
+               return 0;
+#if 0
+       if (clk->dvfs_info!=NULL&&is_support_dvfs(clk->dvfs_info))
+               return dvfs_set_rate(clk, rate);
+#endif
+       LOCK();
+       ret = clk_set_rate_nolock(clk, rate);
+       UNLOCK();
+
+       return ret;
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_set_rate);
+#else
+EXPORT_SYMBOL(clk_set_rate);
+#endif
+
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+int rk30_clk_set_parent(struct clk *clk, struct clk *parent)
+#else
+int clk_set_parent(struct clk *clk, struct clk *parent)
+#endif
+{
+       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)
+               ret = clk_set_parent_nolock(clk, parent);
+       else
+               ret = -EBUSY;
+       UNLOCK();
+
+       return ret;
+}
+int clk_set_parent_force(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();
+               ret = clk_set_parent_nolock(clk, parent);       
+       UNLOCK();
+       return ret;
+}
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_set_parent);
+#else
+EXPORT_SYMBOL(clk_set_parent);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+struct clk *rk30_clk_get_parent(struct clk *clk)
+#else
+struct clk *clk_get_parent(struct clk *clk)
+#endif
+{
+       if (clk == NULL || IS_ERR(clk)) {
+               return ERR_PTR(-EINVAL);
+       }
+       return clk->parent;
+}
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_get_parent);
+#else
+EXPORT_SYMBOL(clk_get_parent);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+void rk30_clk_disable(struct clk *clk)
+#else
+void clk_disable(struct clk *clk)
+#endif
+{
+       if (clk == NULL || IS_ERR(clk))
+               return;
+
+       LOCK();
+       clk_disable_nolock(clk);
+       UNLOCK();
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_disable);
+#else
+EXPORT_SYMBOL(clk_disable);
+#endif
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+int rk30_clk_enable(struct clk *clk)
+#else
+int  clk_enable(struct clk *clk)
+#endif
+{
+       int ret = 0;
+
+       if (clk == NULL || IS_ERR(clk))
+               return -EINVAL;
+
+       LOCK();
+       ret = clk_enable_nolock(clk);
+       UNLOCK();
+
+       return ret;
+}
+#ifdef RK30_CLK_OFFBOARD_TEST
+EXPORT_SYMBOL(rk30_clk_enable);
+#else
+EXPORT_SYMBOL(clk_enable);
+#endif
+
+/* Clk notifier implementation */
+
+/**
+ * struct clk_notifier - associate a clk with a notifier
+ * @clk: struct clk * to associate the notifier with
+ * @notifier_head: a raw_notifier_head for this clk
+ * @node: linked list pointers
+ *
+ * A list of struct clk_notifier is maintained by the notifier code.
+ * An entry is created whenever code registers the first notifier on a
+ * particular @clk.  Future notifiers on that @clk are added to the
+ * @notifier_head.
+ */
+struct clk_notifier {
+       struct clk                      *clk;
+       struct raw_notifier_head        notifier_head;
+       struct list_head                node;
+};
+static LIST_HEAD(clk_notifier_list);
+/**
+ * _clk_free_notifier_chain - safely remove struct clk_notifier
+ * @cn: struct clk_notifier *
+ *
+ * Removes the struct clk_notifier @cn from the clk_notifier_list and
+ * frees it.
+ */
+static void _clk_free_notifier_chain(struct clk_notifier *cn)
+{
+       list_del(&cn->node);
+       kfree(cn);
+}
+
+/**
+ * clk_notify - call clk notifier chain
+ * @clk: struct clk * that is changing rate
+ * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h)
+ * @old_rate: old rate
+ * @new_rate: new rate
+ *
+ * Triggers a notifier call chain on the post-clk-rate-change notifier
+ * for clock 'clk'.  Passes a pointer to the struct clk and the
+ * previous and current rates to the notifier callback.  Intended to be
+ * called by internal clock code only.  No return value.
+ */
+static void clk_notify(struct clk *clk, unsigned long msg,
+                      unsigned long old_rate, unsigned long new_rate)
+{
+       struct clk_notifier *cn;
+       struct clk_notifier_data cnd;
+
+       cnd.clk = clk;
+       cnd.old_rate = old_rate;
+       cnd.new_rate = new_rate;
+
+       UNLOCK();
+       list_for_each_entry(cn, &clk_notifier_list, node) {
+               if (cn->clk == clk) {
+                       pr_debug("%s msg %lu rate %lu -> %lu\n", clk->name, msg, old_rate, new_rate);
+                       raw_notifier_call_chain(&cn->notifier_head, msg, &cnd);
+                       break;
+               }
+       }
+       LOCK();
+}
+
+/**
+ * clk_notifier_register - add a clock parameter change notifier
+ * @clk: struct clk * to watch
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request notification for changes to the clock 'clk'.  This uses a
+ * blocking notifier.  Callback code must not call into the clock
+ * framework, as clocks_mutex is held.  Pre-notifier callbacks will be
+ * passed the previous and new rate of the clock.
+ *
+ * clk_notifier_register() must be called from process
+ * context.  Returns -EINVAL if called with null arguments, -ENOMEM
+ * upon allocation failure; otherwise, passes along the return value
+ * of blocking_notifier_chain_register().
+ */
+int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb)
+{
+       struct clk_notifier *cn = NULL, *cn_new = NULL;
+       int r;
+       struct clk *clkp;
+
+       if (!clk || IS_ERR(clk) || !nb)
+               return -EINVAL;
+
+       mutex_lock(&clocks_mutex);
+
+       list_for_each_entry(cn, &clk_notifier_list, node)
+               if (cn->clk == clk)
+                       break;
+
+       if (cn->clk != clk) {
+               cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
+               if (!cn_new) {
+                       r = -ENOMEM;
+                       goto cnr_out;
+               };
+
+               cn_new->clk = clk;
+               RAW_INIT_NOTIFIER_HEAD(&cn_new->notifier_head);
+
+               list_add(&cn_new->node, &clk_notifier_list);
+               cn = cn_new;
+       }
+
+       r = raw_notifier_chain_register(&cn->notifier_head, nb);
+       if (!IS_ERR_VALUE(r)) {
+               clkp = clk;
+               do {
+                       clkp->notifier_count++;
+               } while ((clkp = clkp->parent));
+       } else {
+               if (cn_new)
+                       _clk_free_notifier_chain(cn);
+       }
+
+cnr_out:
+       mutex_unlock(&clocks_mutex);
+
+       return r;
+}
+EXPORT_SYMBOL(rk30_clk_notifier_register);
+
+/**
+ * clk_notifier_unregister - remove a clock change notifier
+ * @clk: struct clk *
+ * @nb: struct notifier_block * with callback info
+ *
+ * Request no further notification for changes to clock 'clk'.
+ * Returns -EINVAL if called with null arguments; otherwise, passes
+ * along the return value of blocking_notifier_chain_unregister().
+ */
+int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
+{
+       struct clk_notifier *cn = NULL;
+       struct clk *clkp;
+       int r = -EINVAL;
+
+       if (!clk || IS_ERR(clk) || !nb)
+               return -EINVAL;
+
+       mutex_lock(&clocks_mutex);
+
+       list_for_each_entry(cn, &clk_notifier_list, node)
+               if (cn->clk == clk)
+                       break;
+
+       if (cn->clk != clk) {
+               r = -ENOENT;
+               goto cnu_out;
+       };
+
+       r = raw_notifier_chain_unregister(&cn->notifier_head, nb);
+       if (!IS_ERR_VALUE(r)) {
+               clkp = clk;
+               do {
+                       clkp->notifier_count--;
+               } while ((clkp = clkp->parent));
+       }
+
+       /*
+        * XXX ugh, layering violation.  There should be some
+        * support in the notifier code for this.
+        */
+       if (!cn->notifier_head.head)
+               _clk_free_notifier_chain(cn);
+
+cnu_out:
+       mutex_unlock(&clocks_mutex);
+
+       return r;
+}
+EXPORT_SYMBOL(rk30_clk_notifier_unregister);
+
+static struct clk_dump_ops *dump_def_ops;
+
+void clk_register_dump_ops(struct clk_dump_ops *ops)
+{
+       dump_def_ops=ops;
+}
+       
+static int proc_clk_show(struct seq_file *s, void *v)
+{
+       struct clk* clk;
+       
+       if(!dump_def_ops)
+               return 0;
+
+       if(dump_def_ops->dump_clk)
+       {
+               mutex_lock(&clocks_mutex);
+               list_for_each_entry(clk, &clocks, node) {
+                       if (!clk->parent)
+                       {
+                               dump_def_ops->dump_clk(s, clk, 0,&clocks);
+                       }
+               }
+               mutex_unlock(&clocks_mutex);
+       }
+       if(dump_def_ops->dump_regs)
+               dump_def_ops->dump_regs(s);
+       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);
+
diff --git a/arch/arm/mach-rk2928/clock.h b/arch/arm/mach-rk2928/clock.h
new file mode 100644 (file)
index 0000000..5e956f0
--- /dev/null
@@ -0,0 +1,99 @@
+#ifndef __MACH_CLOCK_H__
+#define __MACH_CLOCK_H__
+
+#ifndef CONFIG_ARCH_RK2928
+#define RK30_CLK_OFFBOARD_TEST
+#endif
+
+
+/* Clock flags */
+/* bit 0 is free */
+#define RATE_FIXED             (1 << 1)        /* Fixed clock rate */
+#define CONFIG_PARTICIPANT     (1 << 10)       /* Fundamental clock */
+#define IS_PD                  (1 << 2)        /* Power Domain */
+
+enum _clk_i2s_rate_support {
+       i2s_8192khz = 8192000,
+       i2s_11289_6khz = 11289600,
+       i2s_12288khz = 12288000,
+       i2s_22579_2khz = 22579200,
+       i2s_24576khz = 24576000,//HDMI
+       i2s_49152khz = 24576000,//HDMI
+};
+
+struct _pll_data{
+       u8 id;
+       void *table;
+};
+//struct clk_node;
+struct clk {
+       struct list_head        node;
+       const char              *name;
+       struct clk              *parent;
+       struct list_head        children;
+       struct list_head        sibling;        /* node for children */
+       
+       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 */
+
+       unsigned long           rate;
+       u32                     flags;
+       s16                     usecount;
+       u16                     notifier_count;
+       u8                      gate_idx;
+       struct _pll_data *pll;
+       u32                     clksel_con;
+       u32                     div_mask;
+       u32                     div_shift;
+       u32                     div_max;
+       u32                     src_mask;
+       u32                     src_shift;
+       
+       struct clk      **parents;
+       u8      parents_num;
+       struct clk_node *dvfs_info;
+       
+};
+
+int __init clk_disable_unused(void);
+void clk_recalculate_root_clocks_nolock(void);
+void clk_recalculate_root_clocks(void);
+int clk_register(struct clk *clk);
+void clk_register_default_ops_clk(struct clk *clk);
+
+int clk_enable_nolock(struct clk *clk);
+void clk_disable_nolock(struct clk *clk);
+long clk_round_rate_nolock(struct clk *clk, unsigned long rate);
+int clk_set_rate_nolock(struct clk *clk, unsigned long rate);
+int clk_set_parent_nolock(struct clk *clk, struct clk *parent);
+int clk_set_rate_locked(struct clk * clk,unsigned long rate);
+void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk);
+struct clk_node *clk_get_dvfs_info(struct clk *clk);
+int is_suport_round_rate(struct clk *clk);
+
+#ifdef RK30_CLK_OFFBOARD_TEST
+#include <linux/device.h>
+struct clk *rk30_clk_get(struct device *dev, const char *con_id);
+#endif
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+struct clk_dump_ops {
+       void (*dump_clk)(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks);
+       void (*dump_regs)(struct seq_file *s);
+};
+
+void clk_register_dump_ops(struct clk_dump_ops *ops);
+#else
+static void clk_register_dump_ops(struct clk_dump_ops *ops){
+}
+
+#endif
+
+#endif
diff --git a/arch/arm/mach-rk2928/clock_data.c b/arch/arm/mach-rk2928/clock_data.c
new file mode 100644 (file)
index 0000000..8225d9d
--- /dev/null
@@ -0,0 +1,2444 @@
+/* arch/arm/mach-rk2928/clock_data.c
+ *
+ * Copyright (C) 2012 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/clk.h>
+#include <linux/clkdev.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/hardirq.h>
+#include <mach/cru.h>
+#include <mach/iomux.h>
+#include <mach/clock.h>
+#include "clock.h"
+//#include <mach/pmu.h>
+
+#define MHZ    (1000 * 1000)
+#define KHZ    (1000)
+#define CLK_LOOPS_JIFFY_REF 11996091ULL
+#define CLK_LOOPS_RATE_REF (1200) //Mhz
+#define CLK_LOOPS_RECALC(new_rate)  div_u64(CLK_LOOPS_JIFFY_REF*(new_rate),CLK_LOOPS_RATE_REF*MHZ)
+
+
+struct apll_clk_set {
+       unsigned long rate;
+       u32     pllcon0;
+       u32     pllcon1; 
+       u32     pllcon2; //nb=bwadj+1;0:11;nb=nf/2
+       u32     clksel0;
+       u32     clksel1;
+       u32     rst_dly;//us
+       unsigned long lpj;      //loop per jeffise
+};
+
+struct pll_clk_set {
+       unsigned long rate;
+       u32     pllcon0;
+       u32     pllcon1; 
+       u32     pllcon2; //nb=bwadj+1;0:11;nb=nf/2
+       u32     rst_dly;//us
+};
+#if 1
+#define CLKDATA_DBG(fmt, args...) printk("CLOCK_DATA:\t"fmt, ## args)
+#define CLKDATA_LOG(fmt, args...) printk("CLOCK_DATA:\t"fmt, ## args)
+#else
+#define CLKDATA_DBG(fmt, args...) do {} while(0)
+#define CLKDATA_LOG(fmt, args...) do {} while(0)
+#endif
+#define CLKDATA_ERR(fmt, args...) pr_err(fmt, ## args)
+
+//#define RK2928_TEST_MODE
+#ifndef RK2928_TEST_MODE
+#define cru_readl(offset)      readl_relaxed(RK2928_CRU_BASE + offset)
+#define cru_writel(v, offset)  do { writel_relaxed(v, RK2928_CRU_BASE + offset); dsb(); } while (0)
+#else
+u32 TEST_CRU_REGS[500] = {0};
+#define cru_readl(offset)      (TEST_CRU_REGS[offset / 4])
+#define cru_writel(v, offset)  do { TEST_CRU_REGS[offset / 4] = v; } while (0)
+#endif
+
+#define rk_clock_udelay(a) udelay(a);
+
+#define PLLS_IN_NORM(pll_id) \
+       (((cru_readl(CRU_MODE_CON) & PLL_MODE_MSK(pll_id)) == (PLL_MODE_NORM(pll_id) & PLL_MODE_MSK(pll_id)))\
+        && !(cru_readl(PLL_CONS(pll_id, 0)) & PLL_BYPASS))
+
+#define get_cru_bits(con, mask, shift)\
+       ((cru_readl((con)) >> (shift)) & (mask))
+
+#define CRU_DIV_SET(mask, shift, max) \
+       .div_mask = (mask),\
+.div_shift = (shift),\
+.div_max = (max)
+
+#define CRU_SRC_SET(mask, shift ) \
+       .src_mask = (mask),\
+.src_shift = (shift)
+
+#define CRU_PARENTS_SET(parents_array) \
+       .parents = (parents_array),\
+.parents_num = ARRAY_SIZE((parents_array))
+
+#define get_cru_bits(con,mask,shift)\
+       ((cru_readl((con)) >> (shift)) & (mask))
+
+#define set_cru_bits_w_msk(val,mask,shift,con)\
+       cru_writel(((mask)<<(shift+16))|((val)<<(shift)),(con))
+#define regfile_readl(offset)  readl_relaxed(RK2928_GRF_BASE + offset)
+#define regfile_writel(v, offset) do { writel_relaxed(v, RK2928_GRF_BASE + offset); dsb(); } while (0)
+#define cru_writel_frac(v,offset) cru_writel((v),(offset))
+/*******************PLL CON0 BITS***************************/
+#define SET_PLL_DATA(_pll_id,_table) \
+{\
+       .id=(_pll_id),\
+       .table=(_table),\
+}
+
+#define GATE_CLK(NAME,PARENT,ID) \
+       static struct clk clk_##NAME = { \
+               .name           = #NAME, \
+               .parent         = &PARENT, \
+               .mode           = gate_mode, \
+               .gate_idx       = CLK_GATE_##ID, \
+       }
+
+//FIXME
+//lpj
+#define _APLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac, \
+               _periph_div, _aclk_core_div, _axi_div, _apb_div, _ahb_div) \
+{ \
+       .rate   = (_mhz) * MHZ, \
+       .pllcon0 = PLL_SET_POSTDIV1(_postdiv1) | PLL_SET_FBDIV(_fbdiv), \
+       .pllcon1 = PLL_SET_DSMPD(_dsmpd) | PLL_SET_POSTDIV2(_postdiv2) | PLL_SET_REFDIV(_refdiv),       \
+       .pllcon2 = PLL_SET_FRAC(_frac), \
+       .clksel0 = ACLK_CPU_DIV(RATIO_##_axi_div) | CLK_CORE_DIV(RATIO_##_aclk_core_div),\
+       .clksel1 = PCLK_CPU_DIV(RATIO_##_apb_div) | HCLK_CPU_DIV(RATIO_##_ahb_div) \
+       | ACLK_CORE_DIV(RATIO_##_aclk_core_div) | CLK_CORE_PERI_DIV(RATIO_##_periph_div),       \
+       .lpj    = 1500, \
+}
+static const struct apll_clk_set apll_clks[] = {
+       _APLL_SET_CLKS(650, 6, 325, 2, 1, 1, 0,         41, 21, 81, 21, 21),
+};
+
+#define _PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \
+{ \
+       .rate   = (_mhz) * KHZ, \
+       .pllcon0 = PLL_SET_POSTDIV1(_postdiv1) | PLL_SET_FBDIV(_fbdiv), \
+       .pllcon1 = PLL_SET_DSMPD(_dsmpd) | PLL_SET_POSTDIV2(_postdiv2) | PLL_SET_REFDIV(_refdiv),       \
+       .pllcon2 = PLL_SET_FRAC(_frac), \
+}
+static const struct pll_clk_set cpll_clks[] = {
+       _PLL_SET_CLKS(798000, 4, 133, 1, 1, 0, 0),
+       _PLL_SET_CLKS(1064000, 3, 133, 1, 1, 0, 0),
+};
+
+static const struct pll_clk_set gpll_clks[] = {
+       _PLL_SET_CLKS(297000, 2, 99, 4, 1, 0, 0),
+};
+
+static u32 clk_gcd(u32 numerator, u32 denominator)
+{
+       u32 a, b;
+
+       if (!numerator || !denominator)
+               return 0;
+
+       if (numerator > denominator) {
+               a = numerator;
+               b = denominator;
+       } else {
+               a = denominator;
+               b = numerator;
+       }
+
+       while (b != 0) {
+               int r = b;
+               b = a % b;
+               a = r;
+       }
+
+       return a;
+}
+
+static int frac_div_get_seting(unsigned long rate_out,unsigned long rate,
+               u32 *numerator,u32 *denominator)
+{
+       u32 gcd_vl;
+       gcd_vl = clk_gcd(rate, rate_out);
+       CLKDATA_DBG("frac_get_seting rate=%lu,parent=%lu,gcd=%d\n",rate_out,rate, gcd_vl);
+
+       if (!gcd_vl) {
+               CLKDATA_ERR("gcd=0, i2s frac div is not be supported\n");
+               return -ENOENT;
+       }
+
+       *numerator = rate_out / gcd_vl;
+       *denominator = rate/ gcd_vl;
+
+       CLKDATA_DBG("frac_get_seting numerator=%d,denominator=%d,times=%d\n",
+                       *numerator, *denominator, *denominator / *numerator);
+
+       if (*numerator > 0xffff || *denominator > 0xffff||
+                       (*denominator/(*numerator))<20) {
+               CLKDATA_ERR("can't get a available nume and deno\n");
+               return -ENOENT;
+       }       
+
+       return 0;
+
+}
+/************************option functions*****************/
+/************************clk recalc div rate**************/
+
+//for free div
+static unsigned long clksel_recalc_div(struct clk *clk)
+{
+       u32 div = get_cru_bits(clk->clksel_con, clk->div_mask, clk->div_shift) + 1;
+       unsigned long rate = clk->parent->rate / div;
+
+       CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name);
+       CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, div);
+       return rate;
+}
+
+//for div 2^n
+static unsigned long clksel_recalc_shift(struct clk *clk)
+{
+       u32 shift = get_cru_bits(clk->clksel_con, clk->div_mask, clk->div_shift);
+       unsigned long rate = clk->parent->rate >> shift;
+       CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name);
+       CLKDATA_DBG("%s new clock rate is %lu (shift %u)\n", clk->name, rate, shift);
+       return rate;
+}
+
+//for rate equal to parent
+static unsigned long clksel_recalc_equal_parent(struct clk *clk)
+{
+       unsigned long rate = clk->parent->rate;
+       CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name);
+       CLKDATA_DBG("%s new clock rate is %lu (equal to parent)\n", clk->name, rate);
+
+       return clk->parent->rate;
+}
+
+//for Fixed divide ratio
+static unsigned long clksel_recalc_fixed_div2(struct clk *clk)
+{
+       unsigned long rate = clk->parent->rate >> 1;
+       CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name);
+       CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, 2);
+
+       return rate;
+}
+
+static unsigned long clksel_recalc_fixed_div4(struct clk *clk)
+{      
+       unsigned long rate = clk->parent->rate >> 2;
+       CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name);
+       CLKDATA_DBG("%s new clock rate is %lu (div %u)\n", clk->name, rate, 4);
+
+       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;
+       CLKDATA_DBG("ENTER %s clk=%s\n", __func__, clk->name);
+       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;
+       CLKDATA_DBG("%s new clock rate is %lu (frac %u/%u)\n", clk->name, rate, numerator, denominator);
+       return rate;
+}
+
+#define FRAC_MODE      0
+static unsigned long pll_clk_recalc(u8 pll_id, unsigned long parent_rate)
+{
+       unsigned long rate;
+       unsigned int dsmp = 0;
+       u64 rate64 = 0, frac_rate64 = 0;
+       dsmp = PLL_GET_DSMPD(cru_readl(PLL_CONS(pll_id, 1)));
+
+       if (PLLS_IN_NORM(pll_id)) {
+               u32 pll_con0 = cru_readl(PLL_CONS(pll_id, 0));
+               u32 pll_con1 = cru_readl(PLL_CONS(pll_id, 1));
+               //integer mode
+               rate64 = (u64)parent_rate * PLL_GET_FBDIV(pll_con1);
+               do_div(rate64, PLL_GET_REFDIV(pll_con1));
+
+               if (FRAC_MODE == dsmp) {
+                       //fractional mode
+                       frac_rate64 = (u64)parent_rate * PLL_GET_FRAC(pll_con1);
+                       do_div(frac_rate64, PLL_GET_REFDIV(pll_con1));
+                       rate64 += frac_rate64 >> 24;
+                       CLKDATA_DBG("%s id=%d frac_rate=%llu(0x%08x/2^24) by pass mode\n", 
+                                       __func__, pll_id, frac_rate64, PLL_GET_FRAC(pll_con1)); 
+               }               
+               do_div(rate64, PLL_GET_POSTDIV1(pll_con0));
+               do_div(rate64, PLL_GET_POSTDIV2(pll_con0));
+
+               rate = rate64;
+       } else {
+               rate = parent_rate;     
+               CLKDATA_DBG("pll_clk_recalc id=%d rate=%lu by pass mode\n", pll_id, rate);      
+       }
+       return rate;
+}
+
+static unsigned long plls_clk_recalc(struct clk *clk)
+{
+       return pll_clk_recalc(clk->pll->id, clk->parent->rate);
+}
+
+/************************clk set rate*********************************/
+static int clksel_set_rate_freediv(struct clk *clk, unsigned long rate)
+{
+       u32 div;
+       for (div = 0; div < clk->div_max; div++) {
+               u32 new_rate = clk->parent->rate / (div + 1);
+               if (new_rate <= rate) {
+                       set_cru_bits_w_msk(div,clk->div_mask,clk->div_shift,clk->clksel_con);
+                       //clk->rate = new_rate;
+                       CLKDATA_DBG("clksel_set_rate_freediv for clock %s to rate %ld (div %d)\n", clk->name, rate, div + 1);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+//for div 1 2 4 2^n
+static int clksel_set_rate_shift(struct clk *clk, unsigned long rate)
+{
+       u32 shift;
+       for (shift = 0; (1 << shift) < clk->div_max; shift++) {
+               u32 new_rate = clk->parent->rate >> shift;
+               if (new_rate <= rate) {
+                       set_cru_bits_w_msk(shift,clk->div_mask,clk->div_shift,clk->clksel_con);
+                       clk->rate = new_rate;
+                       CLKDATA_DBG("clksel_set_rate_shift for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+#if 0
+//for div 2 4 2^n
+static int clksel_set_rate_shift_2(struct clk *clk, unsigned long rate)
+{
+       u32 shift;
+
+       for (shift = 1; (1 << shift) < clk->div_max; shift++) {
+               u32 new_rate = clk->parent->rate >> shift;
+               if (new_rate <= rate) {
+                       set_cru_bits_w_msk(shift-1,clk->div_mask,clk->div_shift,clk->clksel_con);
+                       clk->rate = new_rate;
+                       CLKDATA_DBG("clksel_set_rate_shift for clock %s to rate %ld (shift %d)\n", clk->name, rate, shift);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+#endif
+static u32 clk_get_freediv(unsigned long rate_out, unsigned long rate ,u32 div_max)
+{
+       u32 div;
+       unsigned long new_rate;
+       for (div = 0; div <div_max; div++) {
+               new_rate = rate / (div + 1);
+               if (new_rate <= rate_out) {
+                       return div+1;
+               }
+       }       
+       return div_max?div_max:1;
+}
+struct clk *get_freediv_parents_div(struct clk *clk,unsigned long rate,u32 *div_out)
+{
+       u32 div[2]={0,0};
+       unsigned long new_rate[2]={0,0};
+       u32 i;
+
+       if(clk->rate==rate)
+               return clk->parent;
+       for(i=0;i<2;i++)
+       {
+               div[i]=clk_get_freediv(rate,clk->parents[i]->rate,clk->div_max);
+               new_rate[i] = clk->parents[i]->rate/div[i];
+               if(new_rate[i]==rate)
+               {
+                       *div_out=div[i];
+                       return clk->parents[i];
+               }       
+       }
+       if(new_rate[0]<new_rate[1])
+               i=1;
+       else
+               i=0;
+       *div_out=div[i];
+       return clk->parents[i];
+}
+
+static int clkset_rate_freediv_autosel_parents(struct clk *clk, unsigned long rate)
+{
+       struct clk *p_clk;
+       u32 div,old_div;
+       int ret=0;
+       if(clk->rate==rate)
+               return 0;
+       p_clk=get_freediv_parents_div(clk,rate,&div);
+
+       if(!p_clk)
+               return -ENOENT;
+
+       CLKDATA_DBG("%s %lu,form %s\n",clk->name,rate,p_clk->name);
+       if (clk->parent != p_clk)
+       {
+               old_div=CRU_GET_REG_BITS_VAL(cru_readl(clk->clksel_con),clk->div_shift,clk->div_mask)+1;
+
+               if(div>old_div)
+               {
+                       set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con);
+               }
+               ret=clk_set_parent_nolock(clk,p_clk);
+               if(ret)
+               {
+                       CLKDATA_ERR("%s can't set %lu,reparent err\n",clk->name,rate);
+                       return -ENOENT;
+               }
+       }
+       //set div
+       set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con);
+       return 0;       
+}
+#if 0
+//rate==div rate //hdmi
+static int clk_freediv_autosel_parents_set_fixed_rate(struct clk *clk, unsigned long rate)
+{
+       struct clk *p_clk;
+       u32 div,old_div;
+       int ret;
+       p_clk=get_freediv_parents_div(clk,rate,&div);
+
+       if(!p_clk)
+               return -ENOENT;
+
+       if((p_clk->rate/div)!=rate||(p_clk->rate%div))
+               return -ENOENT;
+
+       if (clk->parent != p_clk)
+       {
+               old_div=CRU_GET_REG_BITS_VAL(cru_readl(clk->clksel_con),
+                               clk->div_shift,clk->div_mask)+1;
+               if(div>old_div)
+               {
+                       set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con);
+               }
+               ret=clk_set_parent_nolock(clk,p_clk);
+               if (ret)
+               {
+                       CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate);
+                       return ret;
+               }
+       }
+       //set div
+       set_cru_bits_w_msk(div-1,clk->div_mask,clk->div_shift,clk->clksel_con);
+       return 0;       
+}
+#endif
+/************************round functions*****************/
+static long clksel_freediv_round_rate(struct clk *clk, unsigned long rate)
+{
+       return clk->parent->rate/clk_get_freediv(rate,clk->parent->rate,clk->div_max);
+}
+
+static long clk_freediv_round_autosel_parents_rate(struct clk *clk, unsigned long rate)
+{
+       u32 div;
+       struct clk *p_clk;
+       if(clk->rate == rate)
+               return clk->rate;
+       p_clk=get_freediv_parents_div(clk,rate,&div);
+       if(!p_clk)
+               return 0;
+       return p_clk->rate/div;
+}
+
+static const struct apll_clk_set* apll_clk_get_best_pll_set(unsigned long rate,
+               struct apll_clk_set *tables)
+{
+       const struct apll_clk_set *ps, *pt;
+
+       /* find the arm_pll we want. */
+       ps = pt = tables;
+       while (pt->rate) {
+               if (pt->rate == rate) {
+                       ps = pt;
+                       break;
+               }
+               // we are sorted, and ps->rate > pt->rate.
+               if ((pt->rate > rate || (rate - pt->rate < ps->rate - rate)))
+                       ps = pt;
+               if (pt->rate < rate)
+                       break;
+               pt++;
+       }
+       //CLKDATA_DBG("arm pll best rate=%lu\n",ps->rate);
+       return ps;
+}
+static long apll_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       return apll_clk_get_best_pll_set(rate, clk->pll->table)->rate;
+}
+
+/************************others functions*****************/
+static void pll_wait_lock(int pll_idx)
+{
+       u32 pll_state[4]={1,0,2,3};
+       u32 bit = 0x10u << pll_state[pll_idx];
+       int delay = 24000000;
+       while (delay > 0) {
+               if (!(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT))) {
+                       //printk("%s %08x\n", __func__, cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT));
+                       //printk("%s ! %08x\n", __func__, !(cru_readl(PLL_CONS(pll_idx, 1)) & (0x1 << PLL_LOCK_SHIFT)));
+                       break;
+               }
+               delay--;
+       }
+       if (delay == 0) {
+               CLKDATA_ERR("wait pll bit 0x%x time out!\n", bit);
+               while(1);
+       }
+}
+static int pll_clk_mode(struct clk *clk, int on)
+{
+       u8 pll_id = clk->pll->id;
+       // FIXME here 500 must be changed
+       u32 dly = 1500;
+
+       CLKDATA_DBG("pll_mode %s(%d)", clk->name, on);
+       //FIXME
+       if (on) {
+               cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_ON, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 0));
+               rk_clock_udelay(dly);
+               pll_wait_lock(pll_id);
+               cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON);
+       } else {
+               cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON);
+               cru_writel(CRU_W_MSK_SETBIT(PLL_PWR_DN, PLL_LOCK_SHIFT), PLL_CONS(pll_id, 0));
+       }
+       return 0;
+}
+static struct clk* clksel_get_parent(struct clk *clk)
+{
+       return clk->parents[(cru_readl(clk->clksel_con) >> clk->src_shift) & clk->src_mask];
+}
+static int clksel_set_parent(struct clk *clk, struct clk *parent)
+{
+       u32 i;
+       if (unlikely(!clk->parents))
+               return -EINVAL;
+       for (i = 0; (i <clk->parents_num); i++) {
+               if (clk->parents[i]!= parent)
+                       continue;
+               set_cru_bits_w_msk(i,clk->src_mask,clk->src_shift,clk->clksel_con);
+               return 0;
+       }
+       return -EINVAL;
+}
+
+static int gate_mode(struct clk *clk, int on)
+{
+       int idx = clk->gate_idx;
+       CLKDATA_DBG("ENTER %s clk=%s, on=%d\n", __func__, clk->name, on);
+       if (idx >= CLK_GATE_MAX)
+               return -EINVAL;
+       if(on) {
+               cru_writel(CLK_GATE_W_MSK(idx) | CLK_UN_GATE(idx), CLK_GATE_CLKID_CONS(idx));
+       } else {
+               cru_writel(CLK_GATE_W_MSK(idx) | CLK_GATE(idx), CLK_GATE_CLKID_CONS(idx));
+       }
+       return 0;
+}
+#define PLL_INT_MODE   1
+#define PLL_FRAC_MODE  0
+
+#define rk2928_clock_udelay(a) udelay(a);
+static int pll_clk_set_rate(struct pll_clk_set *clk_set, u8 pll_id)
+{
+       //enter slowmode
+       cru_writel(PLL_MODE_SLOW(pll_id), CRU_MODE_CON);
+       
+       cru_writel(clk_set->pllcon0, PLL_CONS(pll_id,0));
+       cru_writel(clk_set->pllcon1, PLL_CONS(pll_id,1));
+       cru_writel(clk_set->pllcon2, PLL_CONS(pll_id,2));
+
+       //printk("id=%d,pllcon0%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,0)));
+       //printk("id=%d,pllcon1%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,1)));
+       //printk("id=%d,pllcon2%08x\n", pll_id, cru_readl(PLL_CONS(pll_id,2)));
+       //rk2928_clock_udelay(5);
+
+       //wating lock state
+       rk2928_clock_udelay(clk_set->rst_dly);
+       pll_wait_lock(pll_id);
+
+       //return form slow
+       cru_writel(PLL_MODE_NORM(pll_id), CRU_MODE_CON);
+
+       return 0;
+}
+#define PLL_FREF_MIN (183*KHZ)
+#define PLL_FREF_MAX (1500*MHZ)
+
+#define PLL_FVCO_MIN (300*MHZ)
+#define PLL_FVCO_MAX (1500*MHZ)
+
+#define PLL_FOUT_MIN (18750*KHZ)
+#define PLL_FOUT_MAX (1500*MHZ)
+
+#define PLL_NF_MAX (4096)
+#define PLL_NR_MAX (64)
+#define PLL_NO_MAX (16)
+
+static int pll_clk_check_legality(unsigned long fin_hz,unsigned long fout_hz,
+               u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2)
+{
+       fin_hz /= MHZ;
+       if (fin_hz < 1 || fin_hz > 800) {
+               CLKDATA_ERR("%s fbdiv out of [1, 800]MHz\n", __func__);
+               return -1;
+       }
+
+       if (fbdiv < 16 || fbdiv > 1600) {
+               CLKDATA_ERR("%s fbdiv out of [16, 1600]MHz\n", __func__);
+               return -1;
+       }
+
+       if (fin_hz / refdiv < 1 || fin_hz / refdiv > 40) {
+               CLKDATA_ERR("%s fin / refdiv out of [1, 40]MHz\n", __func__);
+               return -1;
+       }
+
+       if (fin_hz * fbdiv / refdiv < 400 || fin_hz * fbdiv / refdiv > 1600) {
+               CLKDATA_ERR("%s fin_hz * fbdiv / refdiv out of [400, 1600]MHz\n", __func__);
+               return -1;
+       }
+
+       if (fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 < 8 
+                       || fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 > 1600) {
+               CLKDATA_ERR("%s fin_hz * fbdiv / refdiv / postdiv1 / postdiv2  out of [8, 1600]MHz\n", __func__);
+               return -1;
+       }
+
+}
+
+static int pll_clk_check_legality_frac(unsigned long fin_hz,unsigned long fout_hz,
+               u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac)
+{
+       fin_hz /= MHZ;
+       if (fin_hz < 10 || fin_hz > 800) {
+               CLKDATA_ERR("%s fin_hz out of [10, 800]MHz\n", __func__);
+               return -1;
+       }
+       if (fbdiv < 19 || fbdiv > 160) {
+               CLKDATA_ERR("%s fbdiv out of [19, 160]MHz\n", __func__);
+               return -1;
+       }
+
+       if (fin_hz / refdiv < 1 || fin_hz / refdiv > 40) {
+               CLKDATA_ERR("%s fin / refdiv out of [1, 40]MHz\n", __func__);
+               return -1;
+       }
+
+       if (fin_hz * fbdiv / refdiv < 400 || fin_hz * fbdiv / refdiv > 1600) {
+               CLKDATA_ERR("%s fin_hz * fbdiv / refdiv out of [400, 1600]MHz\n", __func__);
+               return -1;
+       }
+
+       if (fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 < 8 
+                       || fin_hz * fbdiv / refdiv / postdiv1 / postdiv2 > 1600) {
+               CLKDATA_ERR("%s fin_hz * fbdiv / refdiv / postdiv1 / postdiv2  out of [8, 1600]MHz\n", __func__);
+               return -1;
+       }
+
+}
+static int pll_clk_get_set(unsigned long fin_hz,unsigned long fout_hz,
+               u32 *refdiv, u32 *fbdiv, u32 *postdiv1, u32 *postdiv2, u32 *frac)
+{
+       // FIXME set postdiv1/2 always 1        
+       u32 gcd;
+       
+       if(!fin_hz || !fout_hz || fout_hz == fin_hz)
+               return -1;
+
+       fin_hz /= MHZ;
+       fout_hz /= MHZ;
+       gcd = clk_gcd(fin_hz, fout_hz);
+       refdiv = gcd;
+       fbdiv = fout_hz / gcd;
+       postdiv1 = 1;
+       postdiv2 = 1;
+
+       frac = 0;
+
+       CLKDATA_DBG("fin=%lu,fout=%lu,gcd=%lu,refdiv=%lu,fbdiv=%lu,postdiv1=%lu,postdiv2=%lu,frac=%lu\n",
+                       fin_hz, fout_hz, gcd, refdiv, fbdiv, postdiv1, postdiv2, frac);
+
+       return 0;
+}
+static int pll_set_con(u8 id, u32 refdiv, u32 fbdiv, u32 postdiv1, u32 postdiv2, u32 frac)
+{
+       struct pll_clk_set temp_clk_set;
+       temp_clk_set.pllcon0 = PLL_SET_FBDIV(fbdiv) | PLL_SET_POSTDIV1(postdiv1) ;
+       temp_clk_set.pllcon1 = PLL_SET_REFDIV(refdiv) | PLL_SET_POSTDIV2(postdiv2);
+       temp_clk_set.pllcon2 = PLL_SET_FRAC(frac);
+       temp_clk_set.rst_dly = 1500;
+       printk("setting....\n");
+       return pll_clk_set_rate(&temp_clk_set, id);
+}
+static int apll_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       // FIXME 
+       u32 refdiv, fbdiv, postdiv1, postdiv2, frac;
+       printk("%s %s %d\n", __func__, clk->name, rate);
+       pll_clk_get_set(clk->parent->rate, rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac); 
+       pll_set_con(clk->pll->id, refdiv, fbdiv, postdiv1, postdiv2, frac);
+
+       printk("setting OK\n");
+       return 0;
+}
+
+static int dpll_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       // FIXME do nothing here
+       printk("setting OK\n");
+       return 0;
+}
+
+static int cpll_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       // FIXME        
+       struct _pll_data *pll_data=clk->pll;
+       struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table;
+       struct pll_clk_set temp_clk_set;
+
+       u32 fin_hz, fout_hz;
+       u32 refdiv, fbdiv, postdiv1, postdiv2, frac;
+       fin_hz = clk->parent->rate;
+       fout_hz = rate;
+
+       while(clk_set->rate) {
+               if (clk_set->rate == rate) {
+                       break;
+               }
+               clk_set++;
+       }
+
+       if(clk_set->rate==rate) {
+               CLKDATA_DBG("cpll get a rate\n");
+               pll_clk_set_rate(clk_set, pll_data->id);
+       
+       } else {
+               CLKDATA_DBG("cpll get auto calc a rate\n");
+               if(pll_clk_get_set(clk->parent->rate, &rate, &refdiv, &fbdiv, &postdiv1, &postdiv2, &frac) != 0) {
+                       pr_err("cpll auto set rate error\n");
+                       return -ENOENT;
+               }
+               CLKDATA_DBG("%s get fin=%d, fout=%d, refdiv=%lu, fbdiv=%lu, postdiv1=%lu, postdiv2=%d",
+                               __func__, fin_hz, fout_hz, rate, refdiv, fbdiv, postdiv1, postdiv2);
+               pll_set_con(pll_data->id, refdiv, fbdiv, postdiv1, postdiv2, frac);
+       }
+
+       printk("setting OK\n");
+       return 0;       
+}
+
+static int gpll_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+       // FIXME                
+       struct _pll_data *pll_data=clk->pll;
+       struct pll_clk_set *clk_set=(struct pll_clk_set*)pll_data->table;
+       
+       printk("******%s\n", __func__);
+       while(clk_set->rate)
+       {
+               printk("******%s clk_set->rate=%d\n", __func__, clk_set->rate);
+               if (clk_set->rate == rate) {
+                       break;
+               }
+               clk_set++;
+       }
+       if(clk_set->rate== rate)
+       {
+               pll_clk_set_rate(clk_set,pll_data->id);
+               //lpj_gpll = CLK_LOOPS_RECALC(rate);
+       }
+       else
+       {
+               CLKDATA_ERR("gpll is no corresponding rate=%lu\n", rate);
+               return -1;
+       }
+       printk("******%s end\n", __func__);
+
+       return 0;
+}
+
+/**********************pll datas*************************/
+static u32 rk2928_clock_flags = 0;
+static struct _pll_data apll_data = SET_PLL_DATA(APLL_ID, (void *)apll_clks);
+static struct _pll_data dpll_data = SET_PLL_DATA(DPLL_ID, NULL);
+static struct _pll_data cpll_data = SET_PLL_DATA(CPLL_ID, (void *)cpll_clks);
+static struct _pll_data gpll_data = SET_PLL_DATA(GPLL_ID, (void *)gpll_clks);
+/*********************************************************/
+/************************clocks***************************/
+/*********************************************************/
+
+static struct clk xin24m = {
+       .name           = "xin24m",
+       .rate           = 24 * MHZ,
+       .flags          = RATE_FIXED,
+};
+
+static struct clk clk_12m = {
+       .name           = "clk_12m",
+       .parent         = &xin24m,
+       .rate           = 12 * MHZ,
+       .flags          = RATE_FIXED,
+};
+/************************plls***********************/
+static struct clk arm_pll_clk = {
+       .name           = "arm_pll",
+       .parent         = &xin24m,
+       .mode           = pll_clk_mode,
+       .recalc         = plls_clk_recalc,
+       .set_rate       = apll_clk_set_rate,
+       .round_rate     = apll_clk_round_rate,
+       .pll            = &apll_data,
+};
+
+static struct clk ddr_pll_clk = {
+       .name           = "ddr_pll",
+       .parent         = &xin24m,
+       .mode           = pll_clk_mode,
+       .recalc         = plls_clk_recalc,
+       .set_rate       = dpll_clk_set_rate,
+       .pll            = &dpll_data,
+};
+
+static struct clk codec_pll_clk = {
+       .name           = "codec_pll",
+       .parent         = &xin24m,
+       .mode           = pll_clk_mode,
+       .recalc         = plls_clk_recalc,
+       .set_rate       = cpll_clk_set_rate,
+       .pll            = &cpll_data,
+};
+
+static struct clk general_pll_clk = {
+       .name           = "general_pll",
+       .parent         = &xin24m,
+       .mode           = pll_clk_mode,
+       .gate_idx       = CLK_GATE_CPU_GPLL,
+       .recalc         = plls_clk_recalc,
+       .set_rate       = gpll_clk_set_rate,
+       .pll            = &gpll_data,
+};
+#define SELECT_FROM_2PLLS {&general_pll_clk, &codec_pll_clk}
+/*********ddr******/
+static int ddr_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       // need to do nothing
+       return 0;
+}
+
+static struct clk clk_ddrphy2x = {
+       .name           = "ddrphy2x",
+       .parent         = &ddr_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_DDRPHY_SRC,
+       .recalc         = clksel_recalc_shift,
+       .set_rate       = ddr_clk_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(26),
+};
+
+static struct clk clk_ddrc = {
+       .name           = "ddrc",
+       .parent         = &clk_ddrphy2x,
+       .recalc         = clksel_recalc_fixed_div2,
+};
+
+static struct clk clk_ddrphy = {
+       .name           = "ddrphy",
+       .parent         = &clk_ddrphy2x,
+       .recalc         = clksel_recalc_fixed_div2,
+};
+
+/****************core*******************/
+#if 0
+static unsigned long core_clk_get_rate(struct clk *c)
+{
+       u32 div=(get_cru_bits(c->clksel_con,c->div_mask,c->div_shift)+1);
+       //c->parent->rate=c->parent->recalc(c->parent);
+       return c->parent->rate/div;
+}
+#endif
+static long core_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+       u32 div=(get_cru_bits(clk->clksel_con,clk->div_mask,clk->div_shift)+1);
+       return clk_round_rate_nolock(clk->parent,rate)/div;
+}
+
+static int core_clksel_set_parent(struct clk *clk, struct clk *new_prt)
+{
+       // FIXME
+       u32 temp_div;
+       struct clk *old_prt;
+
+       if(clk->parent==new_prt)
+               return 0;
+       if (unlikely(!clk->parents))
+               return -EINVAL;
+       CLKDATA_DBG("%s,reparent %s\n",clk->name,new_prt->name);
+       //arm
+       old_prt=clk->parent;
+
+       if(clk->parents[0]==new_prt)
+       {
+               new_prt->set_rate(new_prt,300*MHZ);
+               set_cru_bits_w_msk(0,clk->div_mask,clk->div_shift,clk->clksel_con);             
+       }
+       else if(clk->parents[1]==new_prt)
+       {
+
+               if(new_prt->rate>old_prt->rate) 
+               {
+                       temp_div=clk_get_freediv(old_prt->rate,new_prt->rate,clk->div_max);
+                       set_cru_bits_w_msk(temp_div-1,clk->div_mask,clk->div_shift,clk->clksel_con);    
+               }
+               set_cru_bits_w_msk(1,clk->src_mask,clk->src_shift,clk->clksel_con);
+               new_prt->set_rate(new_prt,300*MHZ);
+       }
+       else
+               return -1;
+
+       return 0;
+}
+
+static struct clk *clk_core_pre_parents[2]             = {&arm_pll_clk, &general_pll_clk};
+// this clk is cpu?
+static int arm_core_clk_set_rate(struct clk *c, unsigned long rate)
+{
+       int ret;
+       //set arm pll div 1
+       //set_cru_bits_w_msk(0,c->div_mask,c->div_shift,c->clksel_con);
+       
+       CLKDATA_DBG("Failed to change clk pll %s to %lu\n",c->name,rate);
+       ret = clk_set_rate_nolock(c->parent, rate);
+       if (ret) {
+               CLKDATA_ERR("Failed to change clk pll %s to %lu\n",c->name,rate);
+               return ret;
+       }
+       CLKDATA_DBG("change clk pll %s to %lu OK\n",c->name,rate);
+       return 0;
+}
+static struct clk clk_core_pre = {
+       .name           = "core_pre",
+       .parent         = &arm_pll_clk,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = arm_core_clk_set_rate,
+       .round_rate     = core_clk_round_rate,
+       .set_parent     = core_clksel_set_parent,
+
+       .clksel_con     = CRU_CLKSELS_CON(0),
+       CRU_DIV_SET(A9_CORE_DIV_MASK, A9_CORE_DIV_SHIFT, 32),
+       CRU_SRC_SET(0x1, CORE_CLK_PLL_SEL_SHIFT),
+       CRU_PARENTS_SET(clk_core_pre_parents),
+};
+
+static struct clk clk_core_periph = {
+       .name           = "core_periph",
+       .parent         = &clk_core_pre,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_CORE_PERIPH,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(1),
+       CRU_DIV_SET(CORE_PERIPH_DIV_MASK, CORE_PERIPH_DIV_SHIFT, 16),
+};
+
+static struct clk clken_core_periph = {
+       .name           = "core_periph_en",
+       .parent         = &clk_core_periph,
+       .recalc         = clksel_recalc_equal_parent,
+};
+
+static struct clk clk_l2c = {
+       .name           = "l2c",
+       .parent         = &clk_core_pre,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_CLK_L2C,
+};
+
+static struct clk aclk_core_pre = {
+       .name           = "aclk_core_pre",
+       .parent         = &clk_core_pre,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_ACLK_CORE,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(1),
+       CRU_DIV_SET(ACLK_CORE_DIV_MASK, ACLK_CORE_DIV_SHIFT, 2),
+};
+
+/****************cpu*******************/
+
+static struct clk *clk_cpu_div_parents[]               = {&arm_pll_clk, &general_pll_clk};
+/*seperate because of gating*/
+static struct clk clk_cpu_div = {
+       .name           = "cpu_div",
+       .parent         = &general_pll_clk,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(0),
+       CRU_DIV_SET(ACLK_CPU_DIV_MASK, ACLK_CPU_DIV_SHIFT, 32),
+       CRU_SRC_SET(0x1, CPU_CLK_PLL_SEL_SHIFT),
+       CRU_PARENTS_SET(clk_cpu_div_parents),
+};
+static struct clk aclk_cpu_pre = {
+       .name           = "aclk_cpu_pre",
+       .parent         = &clk_cpu_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_ACLK_CPU,
+       .recalc         = clksel_recalc_equal_parent,
+};
+static struct clk hclk_cpu_pre = {
+       .name           = "hclk_cpu_pre",
+       .parent         = &clk_cpu_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_HCLK_CPU,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(1),
+       CRU_DIV_SET(HCLK_CPU_DIV_MASK, HCLK_CPU_DIV_SHIFT, 4),
+};
+static struct clk pclk_cpu_pre = {
+       .name           = "pclk_cpu_pre",
+       .parent         = &clk_cpu_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_PCLK_CPU,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(1),
+       CRU_DIV_SET(PCLK_CPU_DIV_MASK, PCLK_CPU_DIV_SHIFT, 8),
+};
+/****************vcodec*******************/
+static struct clk *clk_aclk_vepu_parents[]             = SELECT_FROM_2PLLS;
+static struct clk *clk_aclk_vdpu_parents[]             = SELECT_FROM_2PLLS;
+static struct clk aclk_vepu = {
+       .name           = "aclk_vepu",
+       .parent         = &codec_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_ACLK_VEPU_SRC,
+       .recalc         = clksel_recalc_div,
+       .clksel_con     = CRU_CLKSELS_CON(32),
+       .set_rate       = clkset_rate_freediv_autosel_parents,
+       CRU_DIV_SET(0x1f, 0, 32),
+       CRU_SRC_SET(0x1, 7),
+       CRU_PARENTS_SET(clk_aclk_vepu_parents),
+};
+static struct clk aclk_vdpu = {
+       .name           = "aclk_vdpu",
+       .parent         = &clk_cpu_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_ACLK_VDPU_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clkset_rate_freediv_autosel_parents,  
+       .clksel_con     = CRU_CLKSELS_CON(32),
+       CRU_DIV_SET(0x1f, 8, 32),
+       CRU_SRC_SET(0x1, 15),   
+       CRU_PARENTS_SET(clk_aclk_vdpu_parents),
+};
+static struct clk hclk_vepu = {
+       .name           = "hclk_vepu",
+       .parent         = &aclk_vepu,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_HCLK_VEPU,
+       .recalc         = clksel_recalc_fixed_div4,
+};
+static struct clk hclk_vdpu = {
+       .name           = "hclk_vdpu",
+       .parent         = &aclk_vdpu,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_HCLK_VDPU,
+       .recalc         = clksel_recalc_fixed_div4,
+};
+
+/****************vio*******************/
+// name: lcdc0_aclk
+static struct clk *clk_aclk_vio_pre_parents[]          = SELECT_FROM_2PLLS;
+static struct clk aclk_vio_pre = {
+       .name           = "aclk_vio_pre",
+       .parent         = &clk_cpu_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_ACLK_VIO_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(31),
+       CRU_DIV_SET(0x1f, 0, 32),
+       CRU_PARENTS_SET(clk_aclk_vio_pre_parents),
+};
+static struct clk hclk_vio_pre = {
+       .name           = "hclk_vio_pre",
+       .parent         = &aclk_vio_pre,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_HCLK_VIO_PRE,
+       .recalc         = clksel_recalc_fixed_div4,
+};
+
+/****************periph*******************/
+static struct clk *peri_aclk_parents[]         = SELECT_FROM_2PLLS;
+static struct clk peri_aclk = {
+       .name           = "peri_aclk",
+       .parent         = &general_pll_clk,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_PERIPH_SRC,
+       .clksel_con     = CRU_CLKSELS_CON(10),
+       CRU_DIV_SET(PERI_ACLK_DIV_MASK, PERI_ACLK_DIV_SHIFT, 32),
+       CRU_SRC_SET(0x1, PERI_PLL_SEL_SHIFT),   
+       CRU_PARENTS_SET(peri_aclk_parents),
+};
+
+static struct clk peri_hclk = {
+       .name           = "peri_hclk",
+       .parent         = &peri_aclk,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_shift,
+       .clksel_con     = CRU_CLKSELS_CON(10),
+       CRU_DIV_SET(PERI_HCLK_DIV_MASK, PERI_HCLK_DIV_SHIFT, 8),
+};
+
+static struct clk peri_pclk = {
+       .name           = "peri_pclk",
+       .parent         = &peri_aclk,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_shift,
+       .clksel_con     = CRU_CLKSELS_CON(10),
+       CRU_DIV_SET(PERI_PCLK_DIV_MASK, PERI_PCLK_DIV_SHIFT, 4),
+};
+
+static struct clk aclk_periph_pre = {
+       .name           = "aclk_periph_pre",
+       .parent         = &peri_aclk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_ACLK_PERIPH,
+       .recalc         = clksel_recalc_equal_parent,
+};
+
+static struct clk hclk_periph_pre = {
+       .name           = "hclk_periph_pre",
+       .parent         = &peri_hclk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_HCLK_PERIPH,
+       .recalc         = clksel_recalc_equal_parent,
+};
+
+static struct clk pclk_periph_pre = {
+       .name           = "pclk_periph_pre",
+       .parent         = &peri_pclk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_PCLK_PERIPH,
+       .recalc         = clksel_recalc_equal_parent,
+};
+/****************timer*******************/
+static struct clk *clk_timer0_parents[]                = {&xin24m, &peri_pclk};
+static struct clk *clk_timer1_parents[]                = {&xin24m, &peri_pclk};
+static struct clk clk_timer0 = {
+       .name           = "timer0",
+       .parent         = &xin24m,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_TIMER0,
+       .recalc         = clksel_recalc_equal_parent,
+       .clksel_con     = CRU_CLKSELS_CON(10),
+       CRU_SRC_SET(0x1, 4),    
+       CRU_PARENTS_SET(clk_timer0_parents),
+};
+static struct clk clk_timer1 = {
+       .name           = "timer1",
+       .parent         = &xin24m,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_TIMER1,
+       .recalc         = clksel_recalc_equal_parent,
+       .clksel_con     = CRU_CLKSELS_CON(10),
+       CRU_SRC_SET(0x1, 5),    
+       CRU_PARENTS_SET(clk_timer1_parents),
+};
+/****************spi*******************/
+static struct clk clk_spi = {
+       .name           = "spi",
+       .parent         = &peri_pclk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_SPI0_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(25),
+       CRU_DIV_SET(0x7f, 0, 128),
+};
+/****************sdmmc*******************/
+static struct clk *clk_sdmmc0_parents[]                = SELECT_FROM_2PLLS;
+static struct clk clk_sdmmc0 = {
+       .name           = "sdmmc0",
+       .parent         = &general_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_MMC0_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(11),
+       CRU_SRC_SET(0x1, 6),    
+       CRU_DIV_SET(0x3f,0,64),
+       CRU_PARENTS_SET(clk_sdmmc0_parents),
+};
+#if 0
+static struct clk clk_sdmmc0_sample = {
+       .name           = "sdmmc0_sample",
+       .parent         = &general_pll_clk,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+static struct clk clk_sdmmc0_drv = {
+       .name           = "sdmmc0_drv",
+       .parent         = &clk_sdmmc0,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+#endif
+/****************sdio*******************/
+static struct clk *clk_sdio_parents[]          = SELECT_FROM_2PLLS;
+static struct clk clk_sdio = {
+       .name           = "sdio",
+       .parent         = &general_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_SDIO_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con     = CRU_CLKSELS_CON(12),
+       CRU_DIV_SET(0x3f,0,64),
+       CRU_PARENTS_SET(clk_sdio_parents),
+};
+#if 0
+static struct clk clk_sdio_sample = {
+       .name           = "sdio_sample",
+       .parent         = &general_pll_clk,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+static struct clk clk_sdio_drv = {
+       .name           = "sdio_drv",
+       .parent         = &clk_sdio,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+#endif 
+/****************emmc*******************/
+static struct clk *clk_emmc_parents[]          = SELECT_FROM_2PLLS;
+static struct clk clk_emmc = {
+       .name           = "emmc",
+       .parent         = &general_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_EMMC_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .clksel_con =CRU_CLKSELS_CON(12),
+       CRU_DIV_SET(0x3f,8,64),
+       CRU_PARENTS_SET(clk_emmc_parents),
+};
+#if 0
+static struct clk clk_emmc_sample = {
+       .name           = "emmc_sample",
+       .parent         = &general_pll_clk,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+static struct clk clk_emmc_drv = {
+       .name           = "emmc_drv",
+       .parent         = &clk_emmc,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+#endif
+/****************lcdc*******************/
+static struct clk *dclk_lcdc_parents[]         = {&arm_pll_clk, &general_pll_clk, &codec_pll_clk};
+static struct clk dclk_lcdc = {
+       .name           = "dclk_lcdc",
+       .parent         = &general_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_DCLK_LCDC0_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clkset_rate_freediv_autosel_parents,
+       .clksel_con     = CRU_CLKSELS_CON(27),
+       CRU_DIV_SET(0xff, 8, 256),
+       CRU_SRC_SET(0x3, 0),
+       CRU_PARENTS_SET(dclk_lcdc_parents),
+};
+static struct clk *sclk_lcdc_parents[]         = SELECT_FROM_2PLLS;
+static struct clk sclk_lcdc = {
+       .name           = "sclk_lcdc",
+       .parent         = &general_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_SCLK_LCDC_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clkset_rate_freediv_autosel_parents,
+       .clksel_con     = CRU_CLKSELS_CON(28),
+       CRU_DIV_SET(0xff, 8, 256),
+       CRU_SRC_SET(0x1, 0),
+       CRU_PARENTS_SET(sclk_lcdc_parents),
+};
+/****************gps*******************/
+#if 0
+static struct clk hclk_gps_parents             = SELECT_FROM_2PLLS;
+static struct clk hclk_gps = {
+       .name           = "hclk_gps",
+       .parent         = &general_pll_clk,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+#endif
+/****************camera*******************/
+static struct clk *clk_cif_out_div_parents[]           = SELECT_FROM_2PLLS;
+static struct clk clk_cif_out_div = {
+       .name           = "cif_out_div",
+       .parent         = &general_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_CIF_OUT_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clkset_rate_freediv_autosel_parents,
+       .clksel_con     = CRU_CLKSELS_CON(29),
+       CRU_SRC_SET(0x1, 0),
+       CRU_DIV_SET(0x1f, 1, 32),
+       CRU_PARENTS_SET(clk_cif_out_div_parents),
+};
+static struct clk *clk_cif_out_parents[]               = {&xin24m, &clk_cif_out_div};
+static struct clk clk_cif_out = {
+       .name           = "cif0_out",
+       .parent         = &clk_cif_out_div,
+       .clksel_con     = CRU_CLKSELS_CON(29),
+       CRU_SRC_SET(0x1, 7),
+       CRU_PARENTS_SET(clk_cif_out_parents),
+};
+
+/*External clock*/
+static struct clk pclkin_cif0 = {
+       .name           = "pclkin_cif0",
+       .mode           = gate_mode,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_PCLKIN_CIF,  
+};
+
+static struct clk inv_cif0 = {
+       .name           = "inv_cif0",
+       .parent         = &pclkin_cif0,
+};
+
+static struct clk *cif0_in_parents[]                   = {&pclkin_cif0, &inv_cif0};
+static struct clk cif0_in = {
+       .name           = "cif0_in",
+       .parent         = &pclkin_cif0,
+       .clksel_con     = CRU_CLKSELS_CON(30),
+       CRU_SRC_SET(0x1, 8),
+       CRU_PARENTS_SET(cif0_in_parents),
+};
+
+/****************i2s*******************/
+#define I2S_SRC_12M  (0x0)
+#define I2S_SRC_DIV  (0x1)
+#define I2S_SRC_FRAC  (0x2)
+
+static int i2s_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = -EINVAL;
+       struct clk *parent;
+
+       if (rate == clk->parents[I2S_SRC_12M]->rate){
+               parent = clk->parents[I2S_SRC_12M];
+       }else if((long)clk_round_rate_nolock(clk->parents[I2S_SRC_DIV],rate)==rate)
+       {
+               parent = clk->parents[I2S_SRC_DIV]; 
+       }
+       else 
+       {
+               parent =clk->parents[I2S_SRC_FRAC];
+       }
+
+       CLKDATA_DBG(" %s set rate=%lu parent %s(old %s)\n",
+               clk->name,rate,parent->name,clk->parent->name);
+
+       if(parent!=clk->parents[I2S_SRC_12M])
+       {
+               ret = clk_set_rate_nolock(parent,rate);//div 1:1
+               if (ret)
+               {
+                       CLKDATA_DBG("%s set rate%lu err\n",clk->name,rate);
+                       return ret;
+               }
+       }
+
+       if (clk->parent != parent)
+       {
+               ret = clk_set_parent_nolock(clk, parent);
+               if (ret)
+               {
+                       CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate);
+                       return ret;
+               }
+       }
+
+       return ret;
+};
+static struct clk *clk_i2s_div_parents[]               = SELECT_FROM_2PLLS;
+static struct clk clk_i2s_pll = {
+       .name           = "i2s_pll",
+       .parent         = &general_pll_clk,
+       .clksel_con     = CRU_CLKSELS_CON(2),
+       CRU_SRC_SET(0x1,15),
+       CRU_PARENTS_SET(clk_i2s_div_parents),
+};
+
+static struct clk clk_i2s_div = {
+       .name           = "i2s_div",
+       .parent         = &clk_i2s_pll,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_I2S_SRC,     
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .round_rate     = clksel_freediv_round_rate,
+       .clksel_con     = CRU_CLKSELS_CON(3),
+       CRU_DIV_SET(0x7f, 0, 64),
+};
+static struct clk clk_i2s_frac_div = {
+       .name           = "i2s_frac_div",
+       .parent         = &clk_i2s_div,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .round_rate     = clksel_freediv_round_rate,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_I2S_FRAC_SRC,
+       .clksel_con     = CRU_CLKSELS_CON(7),
+};
+
+static struct clk *clk_i2s_parents[]           = {&clk_12m, &clk_i2s_div, &clk_i2s_frac_div};
+static struct clk clk_i2s = {
+       .name           = "i2s",
+       .parent         = &clk_i2s_div,
+       .set_rate       = i2s_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(3),
+       CRU_SRC_SET(0x3, 8),
+       CRU_PARENTS_SET(clk_i2s_parents),
+};
+
+/****************otgphy*******************/
+#if 0
+static struct clk clk_otgphy0 = {
+       .name           = "otgphy0",
+       .parent         = &clk_12m,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+static struct clk clk_otgphy1 = {
+       .name           = "otgphy1",
+       .parent         = &clk_12m,
+       .recalc         = ,
+       //.set_rate     = ,
+       .clksel_con     = ,
+       CRU_DIV_SET(,,),
+};
+#endif
+GATE_CLK(otgphy0, clk_12m, OTGPHY0);
+GATE_CLK(otgphy1, clk_12m, OTGPHY1);
+/****************saradc*******************/
+static struct clk clk_saradc = {
+       .name           = "saradc",
+       .parent         = &xin24m,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_SARADC_SRC,
+       .clksel_con     = CRU_CLKSELS_CON(24),
+       CRU_DIV_SET(0xff,8,256),
+};
+/****************gpu_pre*******************/
+// name: gpu_aclk
+static struct clk *clk_gpu_pre_parents[]               = SELECT_FROM_2PLLS;
+static struct clk clk_gpu_pre = {
+       .name           = "gpu_pre",
+       .parent         = &general_pll_clk,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_GPU_PRE,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clkset_rate_freediv_autosel_parents,
+       .round_rate     = clk_freediv_round_autosel_parents_rate,
+       .clksel_con     = CRU_CLKSELS_CON(34),
+       CRU_DIV_SET(0x1f, 0, 32),
+       CRU_PARENTS_SET(clk_gpu_pre_parents),
+};
+/****************uart*******************/
+static int clk_uart_fracdiv_set_rate(struct clk *clk, unsigned long rate)
+{
+       u32 numerator, denominator;
+       //clk_uart0_div->clk_uart_pll->gpll/cpll
+       //clk->parent->parent
+       if(frac_div_get_seting(rate,clk->parent->parent->rate,
+                               &numerator,&denominator)==0)
+       {
+               clk_set_rate_nolock(clk->parent,clk->parent->parent->rate);//PLL:DIV 1:
+
+               cru_writel_frac(numerator << 16 | denominator, clk->clksel_con);
+
+               CLKDATA_DBG("%s set rate=%lu,is ok\n",clk->name,rate);
+       }
+       else
+       {
+               CLKDATA_ERR("clk_frac_div can't get rate=%lu,%s\n",rate,clk->name);
+               return -ENOENT;
+       } 
+       return 0;
+}
+#define UART_SRC_DIV 0
+#define UART_SRC_FRAC 1
+#define UART_SRC_24M 2
+static int clk_uart_set_rate(struct clk *clk, unsigned long rate)
+{
+       int ret = 0;
+       struct clk *parent;
+
+       if(rate==clk->parents[UART_SRC_24M]->rate)//24m
+       {       
+               parent = clk->parents[UART_SRC_24M];
+       }
+       else if((long)clk_round_rate_nolock(clk->parents[UART_SRC_DIV], rate)==rate)
+       {
+               parent = clk->parents[UART_SRC_DIV];
+       }
+       else
+       {
+               parent = clk->parents[UART_SRC_FRAC];
+       }
+
+
+
+       CLKDATA_DBG(" %s set rate=%lu parent %s(old %s)\n",
+                       clk->name,rate,parent->name,clk->parent->name);
+
+
+       if(parent!=clk->parents[UART_SRC_24M])
+       {
+               ret = clk_set_rate_nolock(parent,rate); 
+               if (ret)
+               {
+                       CLKDATA_DBG("%s set rate%lu err\n",clk->name,rate);
+                       return ret;
+               }
+       }
+
+       if (clk->parent != parent)
+       {
+               ret = clk_set_parent_nolock(clk, parent);
+               if (ret)
+               {
+                       CLKDATA_DBG("%s can't get rate%lu,reparent err\n",clk->name,rate);
+                       return ret;
+               }
+       }
+
+
+       return ret;
+}
+
+
+static struct clk *clk_uart_pll_src_parents[]  = SELECT_FROM_2PLLS;
+static struct clk clk_uart_pll = {
+       .name           = "uart_pll",
+       .parent         = &general_pll_clk,
+       .clksel_con     = CRU_CLKSELS_CON(12),
+       CRU_SRC_SET(0x1, 15),
+       CRU_PARENTS_SET(clk_uart_pll_src_parents),
+};
+//static struct clk clk_uart0_div_parents              = SELECT_FROM_2PLLS;
+//static struct clk clk_uart1_div_parents              = SELECT_FROM_2PLLS;
+//static struct clk clk_uart2_div_parents              = SELECT_FROM_2PLLS;
+static struct clk clk_uart0_div = {
+       .name           = "uart0_div",
+       .parent         = &clk_uart_pll,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART0_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .round_rate     = clksel_freediv_round_rate,
+       .clksel_con     = CRU_CLKSELS_CON(13),
+       CRU_DIV_SET(0x7f, 0, 64),       
+};
+static struct clk clk_uart1_div = {
+       .name           = "uart1_div",
+       .parent         = &clk_uart_pll,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART1_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .round_rate     = clksel_freediv_round_rate,
+       .clksel_con     = CRU_CLKSELS_CON(15),
+       CRU_DIV_SET(0x7f, 0, 64),       
+};
+static struct clk clk_uart2_div = {
+       .name           = "uart2_div",
+       .parent         = &clk_uart_pll,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART2_SRC,
+       .recalc         = clksel_recalc_div,
+       .set_rate       = clksel_set_rate_freediv,
+       .round_rate     = clksel_freediv_round_rate,
+       .clksel_con     = CRU_CLKSELS_CON(15),
+       CRU_DIV_SET(0x7f, 0, 64),       
+};
+static struct clk clk_uart0_frac_div = {
+       .name           = "uart0_frac_div",
+       .parent         = &clk_uart0_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART0_FRAC_SRC,
+       .recalc         = clksel_recalc_frac,
+       .set_rate       = clk_uart_fracdiv_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(17),
+};
+static struct clk clk_uart1_frac_div = {
+       .name           = "uart1_frac_div",
+       .parent         = &clk_uart1_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART1_FRAC_SRC,
+       .recalc         = clksel_recalc_frac,
+       .set_rate       = clk_uart_fracdiv_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(18),
+};
+static struct clk clk_uart2_frac_div = {
+       .name           = "uart2_frac_div",
+       .parent         = &clk_uart2_div,
+       .mode           = gate_mode,
+       .gate_idx       = CLK_GATE_UART2_FRAC_SRC,
+       .recalc         = clksel_recalc_frac,
+       .set_rate       = clk_uart_fracdiv_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(19),
+};
+
+static struct clk *clk_uart0_parents[]         = {&clk_uart0_div, &clk_uart0_frac_div, &xin24m};
+static struct clk *clk_uart1_parents[]         = {&clk_uart1_div, &clk_uart1_frac_div, &xin24m};
+static struct clk *clk_uart2_parents[]         = {&clk_uart2_div, &clk_uart2_frac_div, &xin24m};
+static struct clk clk_uart0= {
+       .name           = "uart0",
+       .parent         = &xin24m,
+       .set_rate       = clk_uart_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(13),
+       CRU_SRC_SET(0x3, 8),            
+       CRU_PARENTS_SET(clk_uart0_parents),
+};
+static struct clk clk_uart1= {
+       .name           = "uart1",
+       .parent         = &xin24m,
+       .set_rate       = clk_uart_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(14),
+       CRU_SRC_SET(0x3, 8),                    
+       CRU_PARENTS_SET(clk_uart1_parents),
+};
+static struct clk clk_uart2= {
+       .name           = "uart2",
+       .parent         = &xin24m,
+       .set_rate       = clk_uart_set_rate,
+       .clksel_con     = CRU_CLKSELS_CON(15),
+       CRU_SRC_SET(0x3, 8),            
+       CRU_PARENTS_SET(clk_uart2_parents),
+};
+/****************sub clock---pre*******************/
+/*************************aclk_cpu***********************/
+GATE_CLK(aclk_intmem,  aclk_cpu_pre,   ACLK_INTMEM);
+GATE_CLK(aclk_strc_sys,        aclk_cpu_pre,   ACLK_STRC_SYS);
+
+/*************************hclk_cpu***********************/
+//FIXME
+//GATE_CLK(hclk_cpubus,        hclk_cpu_pre,   HCLK_CPUBUS);
+GATE_CLK(hclk_rom,     hclk_cpu_pre,   HCLK_ROM);
+
+/*************************pclk_cpu***********************/
+//FIXME
+//GATE_CLK(pclk_hdmi,  pclk_cpu_pre, PCLK_HDMI);
+GATE_CLK(pclk_ddrupctl,        pclk_cpu_pre, PCLK_DDRUPCTL);
+GATE_CLK(pclk_grf,     pclk_cpu_pre, PCLK_GRF);
+GATE_CLK(pclk_acodec,  pclk_cpu_pre, PCLK_ACODEC);
+
+/*************************aclk_periph********************/
+GATE_CLK(aclk_dma2,    aclk_periph_pre, ACLK_DMAC2);
+GATE_CLK(aclk_peri_niu,        aclk_periph_pre, ACLK_PERI_NIU);
+GATE_CLK(aclk_cpu_peri,        aclk_periph_pre, ACLK_CPU_PERI);
+GATE_CLK(aclk_peri_axi_matrix, aclk_periph_pre, ACLK_PERI_AXI_MATRIX);
+//FIXME
+//GATE_CLK(aclk_gps,   aclk_periph_pre, ACLK_GPS);
+
+/*************************hclk_periph***********************/
+GATE_CLK(hclk_peri_axi_matrix, hclk_periph_pre, HCLK_PERI_AXI_MATRIX);
+GATE_CLK(hclk_peri_ahb_arbi,   hclk_periph_pre, HCLK_PERI_ARBI);
+GATE_CLK(hclk_nandc, hclk_periph_pre, HCLK_NANDC);
+GATE_CLK(hclk_usb_peri, hclk_periph_pre, HCLK_USB_PERI);
+GATE_CLK(hclk_otg0, hclk_periph_pre, HCLK_OTG0);
+GATE_CLK(hclk_otg1, hclk_periph_pre, HCLK_OTG1);
+GATE_CLK(hclk_i2s, hclk_periph_pre, HCLK_I2S);
+GATE_CLK(hclk_sdmmc0, hclk_periph_pre, HCLK_SDMMC0);
+GATE_CLK(hclk_sdio, hclk_periph_pre, HCLK_SDIO);
+GATE_CLK(hclk_emmc, hclk_periph_pre, HCLK_EMMC);
+
+/*************************pclk_periph***********************/
+GATE_CLK(pclk_peri_axi_matrix, pclk_periph_pre, PCLK_PERI_AXI_MATRIX);
+GATE_CLK(pclk_pwm01, pclk_periph_pre, PCLK_PWM01);
+GATE_CLK(pclk_wdt, pclk_periph_pre, PCLK_WDT);
+GATE_CLK(pclk_spi0, pclk_periph_pre, PCLK_SPI0);
+GATE_CLK(pclk_uart0, pclk_periph_pre, PCLK_UART0);
+GATE_CLK(pclk_uart1, pclk_periph_pre, PCLK_UART1);
+GATE_CLK(pclk_uart2, pclk_periph_pre, PCLK_UART2);
+GATE_CLK(pclk_i2c0, pclk_periph_pre, PCLK_I2C0);
+GATE_CLK(pclk_i2c1, pclk_periph_pre, PCLK_I2C1);
+GATE_CLK(pclk_i2c2, pclk_periph_pre, PCLK_I2C2);
+GATE_CLK(pclk_i2c3, pclk_periph_pre, PCLK_I2C3);
+GATE_CLK(pclk_timer0, pclk_periph_pre, PCLK_TIMER0);
+GATE_CLK(pclk_timer1, pclk_periph_pre, PCLK_TIMER1);
+GATE_CLK(pclk_gpio0, pclk_periph_pre, PCLK_GPIO0);
+GATE_CLK(pclk_gpio1, pclk_periph_pre, PCLK_GPIO1);
+GATE_CLK(pclk_gpio2, pclk_periph_pre, PCLK_GPIO2);
+GATE_CLK(pclk_gpio3, pclk_periph_pre, PCLK_GPIO3);
+GATE_CLK(pclk_saradc, pclk_periph_pre, PCLK_SARADC);
+GATE_CLK(pclk_efuse, pclk_periph_pre, PCLK_EFUSE);
+
+/*************************aclk_vio***********************/
+GATE_CLK(aclk_vio0, aclk_vio_pre, ACLK_VIO0);
+GATE_CLK(aclk_lcdc0, aclk_vio_pre, ACLK_LCDC0);
+GATE_CLK(aclk_cif0, aclk_vio_pre, ACLK_CIF);
+GATE_CLK(aclk_rga,  aclk_vio_pre, ACLK_RGA);
+
+/*************************hclk_vio***********************/
+GATE_CLK(hclk_lcdc0, hclk_vio_pre, HCLK_LCDC0);
+GATE_CLK(hclk_cif0, hclk_vio_pre, HCLK_CIF);
+GATE_CLK(hclk_rga,  hclk_vio_pre, HCLK_RGA);
+GATE_CLK(hclk_vio_bus, hclk_vio_pre, HCLK_VIO_BUS);
+
+/* Power domain, not exist in fact*/
+enum pmu_power_domain {
+       PD_A9_0 = 0,
+       PD_A9_1,
+       PD_ALIVE,
+       PD_RTC,
+       PD_SCU,
+       PD_CPU,
+       PD_PERI = 6,
+       PD_VIO,
+       PD_VIDEO,
+       PD_VCODEC = PD_VIDEO,
+       PD_GPU,
+       PD_DBG,
+};
+
+static int pm_off_mode(struct clk *clk, int on)
+{
+       return 0;
+}
+static struct clk pd_peri = {
+       .name           = "pd_peri",
+       .flags          = IS_PD,
+       .mode           = pm_off_mode,
+       .gate_idx       = PD_PERI,
+};
+
+static int pd_display_mode(struct clk *clk, int on)
+{
+       return 0;
+}
+
+static struct clk pd_display = {
+       .name           = "pd_display",
+       .flags          = IS_PD,
+       .mode           = pd_display_mode,
+       .gate_idx       = PD_VIO,
+};
+
+static struct clk pd_lcdc0 = {
+       .parent         = &pd_display,
+       .name           = "pd_lcdc0",
+};
+static struct clk pd_lcdc1 = {
+       .parent         = &pd_display,
+       .name           = "pd_lcdc1",
+};
+static struct clk pd_cif0 = {
+       .parent         = &pd_display,
+       .name           = "pd_cif0",
+};
+static struct clk pd_cif1 = {
+       .parent         = &pd_display,
+       .name           = "pd_cif1",
+};
+static struct clk pd_rga = {
+       .parent         = &pd_display,
+       .name           = "pd_rga",
+};
+static struct clk pd_ipp = {
+       .parent         = &pd_display,
+       .name           = "pd_ipp",
+};
+static int pd_video_mode(struct clk *clk, int on)
+{
+       return 0;
+}
+
+static struct clk pd_video = {
+       .name           = "pd_video",
+       .flags          = IS_PD,
+       .mode           = pd_video_mode,
+       .gate_idx       = PD_VIDEO,
+};
+
+static int pd_gpu_mode(struct clk *clk, int on)
+{
+       return 0;
+}
+
+static struct clk pd_gpu = {
+       .name           = "pd_gpu",
+       .flags          = IS_PD,
+       .mode           = pd_gpu_mode,
+       .gate_idx       = PD_GPU,
+};
+static struct clk pd_dbg = {
+       .name           = "pd_dbg",
+       .flags          = IS_PD,
+       .mode           = pm_off_mode,
+       .gate_idx       = PD_DBG,
+};
+
+#define PD_CLK(name) \
+{\
+       .dev_id = NULL,\
+       .con_id = #name,\
+       .clk = &name,\
+}
+/* Power domain END, not exist in fact*/
+
+#define CLK(dev, con, ck) \
+{\
+       .dev_id = dev,\
+       .con_id = con,\
+       .clk = ck,\
+}
+
+#define CLK_GATE_NODEV(name) \
+{\
+       .dev_id = NULL,\
+       .con_id = #name,\
+       .clk = &clk_##name,\
+}
+
+static struct clk_lookup clks[] = {
+       CLK(NULL, "xin24m", &xin24m),
+       CLK(NULL, "xin12m", &clk_12m),
+
+       CLK(NULL, "arm_pll", &arm_pll_clk),
+       CLK(NULL, "ddr_pll", &ddr_pll_clk),
+       CLK(NULL, "codec_pll", &codec_pll_clk),
+       CLK(NULL, "general_pll", &general_pll_clk),
+
+       CLK(NULL, "ddrphy2x", &clk_ddrphy2x),
+       CLK(NULL, "ddrphy", &clk_ddrphy),
+       CLK(NULL, "ddrc", &clk_ddrc),
+
+       CLK(NULL, "core_pre", &clk_core_pre),
+       CLK(NULL, "core_periph", &clk_core_periph),
+       CLK(NULL, "core_periph_en", &clken_core_periph),
+       CLK(NULL, "l2c", &clk_l2c),
+       CLK(NULL, "aclk_core_pre", &aclk_core_pre),
+
+       CLK(NULL, "cpu_div", &clk_cpu_div),
+       CLK(NULL, "aclk_cpu_pre", &aclk_cpu_pre),
+       CLK(NULL, "pclk_cpu_pre", &pclk_cpu_pre),
+       CLK(NULL, "hclk_cpu_pre", &hclk_cpu_pre),
+
+       CLK(NULL, "aclk_vepu", &aclk_vepu),
+       CLK(NULL, "aclk_vdpu", &aclk_vdpu),
+       CLK(NULL, "hclk_vepu", &hclk_vepu),
+       CLK(NULL, "hclk_vdpu", &hclk_vdpu),
+
+       CLK(NULL, "aclk_vio_pre", &aclk_vio_pre),
+       CLK(NULL, "hclk_vio_pre", &hclk_vio_pre),
+
+       CLK(NULL, "peri_aclk", &peri_aclk),
+       CLK(NULL, "peri_pclk", &peri_pclk),
+       CLK(NULL, "peri_hclk", &peri_hclk),
+
+       CLK(NULL, "timer0", &clk_timer0),
+       CLK(NULL, "timer1", &clk_timer1),
+
+       CLK("rk29xx_spim.0", "spi", &clk_spi),
+
+       CLK("rk29_sdmmc.0", "mmc", &clk_sdmmc0),
+       //CLK("rk29_sdmmc.0", "mmc_sample", &clk_sdmmc0_sample),
+       //CLK("rk29_sdmmc.0", "mmc_drv", &clk_sdmmc0_drv),
+
+       CLK("rk29_sdmmc.1", "mmc", &clk_sdio),
+       //CLK("rk29_sdmmc.1", "mmc_sample", &clk_sdio_sample),
+       //CLK("rk29_sdmmc.1", "mmc_drv", &clk_sdio_drv),
+
+       CLK(NULL, "emmc", &clk_emmc),
+       //CLK(NULL, "emmc_sample", &clk_emmc_sample),
+       //CLK(NULL, "emmc_drv", &clk_emmc_drv),
+
+       CLK(NULL, "dclk_lcdc0", &dclk_lcdc),
+       CLK(NULL, "sclk_lcdc0", &sclk_lcdc),
+       //FIXME
+       //CLK(NULL, "hclk_gps", &hclk_gps),
+
+       CLK(NULL, "cif_out_div", &clk_cif_out_div),
+       CLK(NULL, "cif0_out", &clk_cif_out),
+       CLK(NULL, "pclkin_cif0", &pclkin_cif0),
+       CLK(NULL, "inv_cif0", &inv_cif0),
+       CLK(NULL, "cif0_in", &cif0_in),
+
+       CLK(NULL, "i2s_pll", &clk_i2s_pll),
+       CLK("rk29_i2s.0", "i2s_div", &clk_i2s_div),
+       CLK("rk29_i2s.0", "i2s_frac_div", &clk_i2s_frac_div),
+       CLK("rk29_i2s.0", "i2s", &clk_i2s),
+
+       CLK(NULL, "otgphy0", &clk_otgphy0),
+       CLK(NULL, "otgphy1", &clk_otgphy1),
+       CLK(NULL, "saradc", &clk_saradc),
+       CLK(NULL, "gpu_pre", &clk_gpu_pre),
+
+       CLK(NULL, "uart_pll", &clk_uart_pll),
+       CLK("rk_serial.0", "uart_div", &clk_uart0_div),
+       CLK("rk_serial.1", "uart_div", &clk_uart1_div),
+       CLK("rk_serial.2", "uart_div", &clk_uart2_div),
+       CLK("rk_serial.0", "uart_frac_div", &clk_uart0_frac_div),
+       CLK("rk_serial.1", "uart_frac_div", &clk_uart1_frac_div),
+       CLK("rk_serial.2", "uart_frac_div", &clk_uart2_frac_div),
+       CLK("rk_serial.0", "uart", &clk_uart0),
+       CLK("rk_serial.1", "uart", &clk_uart1),
+       CLK("rk_serial.2", "uart", &clk_uart2),
+
+       CLK(NULL, "aclk_periph_pre", &aclk_periph_pre),
+       CLK(NULL, "hclk_periph_pre", &hclk_periph_pre),
+       CLK(NULL, "pclk_periph_pre", &pclk_periph_pre),
+
+       /*********fixed clock ******/
+       CLK_GATE_NODEV(aclk_intmem),
+       CLK_GATE_NODEV(aclk_strc_sys),
+
+       //FIXME
+       //CLK_GATE_NODEV(hclk_cpubus),
+       CLK_GATE_NODEV(hclk_rom),
+
+       //FIXME
+       //CLK_GATE_NODEV(pclk_hdmi),
+       CLK_GATE_NODEV(pclk_ddrupctl),
+       CLK_GATE_NODEV(pclk_grf),
+       CLK_GATE_NODEV(pclk_acodec),
+
+       CLK_GATE_NODEV(aclk_dma2),
+       CLK_GATE_NODEV(aclk_peri_niu),
+       CLK_GATE_NODEV(aclk_cpu_peri),
+       CLK_GATE_NODEV(aclk_peri_axi_matrix),
+       //FIXME
+       //CLK_GATE_NODEV(aclk_gps),
+
+       CLK_GATE_NODEV(hclk_peri_axi_matrix),
+       CLK_GATE_NODEV(hclk_peri_ahb_arbi),
+       CLK_GATE_NODEV(hclk_nandc),
+       CLK_GATE_NODEV(hclk_usb_peri),
+       CLK_GATE_NODEV(hclk_otg0),
+       CLK_GATE_NODEV(hclk_otg1),
+       CLK_GATE_NODEV(hclk_i2s),
+       CLK("rk29_sdmmc.0", "hclk_mmc", &clk_hclk_sdmmc0),
+       CLK("rk29_sdmmc.1", "hclk_mmc", &clk_hclk_sdio),
+       CLK("rk29_sdmmc.2", "hclk_mmc", &clk_hclk_emmc),
+
+       CLK_GATE_NODEV(pclk_peri_axi_matrix),
+       CLK(NULL, "pwm01", &clk_pclk_pwm01),
+       CLK_GATE_NODEV(pclk_wdt),
+       CLK_GATE_NODEV(pclk_spi0),
+       CLK("rk_serial.0", "pclk_uart", &clk_pclk_uart0),
+       CLK("rk_serial.1", "pclk_uart", &clk_pclk_uart1),
+       CLK("rk_serial.2", "pclk_uart", &clk_pclk_uart2),
+       CLK("rk30_i2c.0", "i2c", &clk_pclk_i2c0),
+       CLK("rk30_i2c.1", "i2c", &clk_pclk_i2c1),
+       CLK("rk30_i2c.2", "i2c", &clk_pclk_i2c2),
+       CLK("rk30_i2c.3", "i2c", &clk_pclk_i2c3),
+       CLK_GATE_NODEV(pclk_timer0),
+       CLK_GATE_NODEV(pclk_timer1),
+       CLK_GATE_NODEV(pclk_gpio0),
+       CLK_GATE_NODEV(pclk_gpio1),
+       CLK_GATE_NODEV(pclk_gpio2),
+       CLK_GATE_NODEV(pclk_gpio3),
+       CLK_GATE_NODEV(pclk_saradc),
+       CLK_GATE_NODEV(pclk_efuse),
+
+       CLK_GATE_NODEV(aclk_vio0),
+       CLK_GATE_NODEV(aclk_lcdc0),
+       CLK_GATE_NODEV(aclk_cif0),
+       CLK_GATE_NODEV(aclk_rga),
+
+       CLK_GATE_NODEV(hclk_lcdc0),
+       CLK_GATE_NODEV(hclk_cif0),
+       CLK_GATE_NODEV(hclk_rga),
+       CLK_GATE_NODEV(hclk_vio_bus),
+
+       /* Power domain, not exist in fact*/
+       PD_CLK(pd_peri),
+       PD_CLK(pd_display),
+       PD_CLK(pd_video),
+       PD_CLK(pd_lcdc0),
+       PD_CLK(pd_lcdc1),
+       PD_CLK(pd_cif0),
+       PD_CLK(pd_cif1),
+       PD_CLK(pd_rga),
+       PD_CLK(pd_ipp),
+       PD_CLK(pd_video),
+       PD_CLK(pd_gpu),
+       PD_CLK(pd_dbg),
+
+};
+
+static void __init rk30_init_enable_clocks(void)
+{
+       CLKDATA_DBG("ENTER %s\n", __func__);
+       clk_enable_nolock(&clk_core_pre);       //cpu
+       clk_enable_nolock(&clk_core_periph);
+       clk_enable_nolock(&aclk_cpu_pre);
+       clk_enable_nolock(&hclk_cpu_pre);
+       clk_enable_nolock(&pclk_cpu_pre);
+
+       clk_enable_nolock(&aclk_periph_pre);
+       clk_enable_nolock(&pclk_periph_pre);
+       clk_enable_nolock(&hclk_periph_pre);
+
+#if CONFIG_RK_DEBUG_UART == 0
+       clk_enable_nolock(&clk_uart0);
+       clk_enable_nolock(&clk_pclk_uart0);
+
+#elif CONFIG_RK_DEBUG_UART == 1
+       clk_enable_nolock(&clk_uart1);
+       clk_enable_nolock(&clk_pclk_uart1);
+
+#elif CONFIG_RK_DEBUG_UART == 2
+       clk_enable_nolock(&clk_uart2);
+       clk_enable_nolock(&clk_pclk_uart2);
+#endif
+
+       /*************************aclk_cpu***********************/
+       clk_enable_nolock(&clk_aclk_intmem);
+       clk_enable_nolock(&clk_aclk_strc_sys);
+
+       /*************************hclk_cpu***********************/
+       clk_enable_nolock(&clk_hclk_rom);
+
+       /*************************pclk_cpu***********************/
+       clk_enable_nolock(&clk_pclk_ddrupctl);
+       clk_enable_nolock(&clk_pclk_grf);
+
+       /*************************aclk_periph***********************/
+       clk_enable_nolock(&clk_aclk_dma2);
+       clk_enable_nolock(&clk_aclk_peri_niu);
+       clk_enable_nolock(&clk_aclk_cpu_peri);
+       clk_enable_nolock(&clk_aclk_peri_axi_matrix);
+
+       /*************************hclk_periph***********************/
+       clk_enable_nolock(&clk_hclk_peri_axi_matrix);
+       clk_enable_nolock(&clk_hclk_peri_ahb_arbi);
+       clk_enable_nolock(&clk_hclk_nandc);
+
+       /*************************pclk_periph***********************/
+       clk_enable_nolock(&clk_pclk_peri_axi_matrix);
+       /*************************hclk_vio***********************/
+       clk_enable_nolock(&clk_hclk_vio_bus);
+}
+
+#ifdef CONFIG_PROC_FS
+
+static void dump_clock(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks)
+{
+       struct clk* ck;
+       int i;
+       unsigned long rate = clk->rate;
+       //CLKDATA_DBG("dump_clock %s\n",clk->name);
+       for (i = 0; i < deep; i++)
+               seq_printf(s, "    ");
+
+       seq_printf(s, "%-11s ", clk->name);
+
+       if ((clk->mode == gate_mode) && (clk->gate_idx < CLK_GATE_MAX)) {
+               int idx = clk->gate_idx;
+               u32 v;
+               v = cru_readl(CLK_GATE_CLKID_CONS(idx))&((0x1)<<(idx%16));
+               seq_printf(s, "%s ", v ? "off" : "on ");
+       }
+
+       if (clk->pll)
+       {
+               u32 pll_mode;
+               u32 pll_id=clk->pll->id;
+               pll_mode=cru_readl(CRU_MODE_CON)&PLL_MODE_MSK(pll_id);
+               if(pll_mode==PLL_MODE_SLOW(pll_id))
+                       seq_printf(s, "slow   ");
+               else if(pll_mode==PLL_MODE_NORM(pll_id))
+                       seq_printf(s, "normal ");
+               if(cru_readl(PLL_CONS(pll_id,3)) & PLL_BYPASS) 
+                       seq_printf(s, "bypass ");
+       }
+       else if(clk == &ddr_pll_clk) {
+               rate = clk->recalc(clk);
+       }
+
+       if (rate >= MHZ) {
+               if (rate % MHZ)
+                       seq_printf(s, "%ld.%06ld MHz", rate / MHZ, rate % MHZ);
+               else
+                       seq_printf(s, "%ld MHz", rate / MHZ);
+       } else if (rate >= KHZ) {
+               if (rate % KHZ)
+                       seq_printf(s, "%ld.%03ld KHz", rate / KHZ, rate % KHZ);
+               else
+                       seq_printf(s, "%ld KHz", rate / KHZ);
+       } else {
+               seq_printf(s, "%ld Hz", rate);
+       }
+
+       seq_printf(s, " usecount = %d", clk->usecount);
+
+       if (clk->parent)
+               seq_printf(s, " parent = %s", clk->parent->name);
+
+       seq_printf(s, "\n");
+
+       list_for_each_entry(ck, root_clocks, node) {
+               if (ck->parent == clk)
+                       dump_clock(s, ck, deep + 1,root_clocks);
+       }
+}
+
+static void dump_regs(struct seq_file *s)
+{
+       int i=0;
+       seq_printf(s, "\nPLL(id=0 apll,id=1,dpll,id=2,cpll,id=3 cpll)\n");
+       seq_printf(s, "\nPLLRegisters:\n");
+       for(i=0;i<END_PLL_ID;i++)
+       {
+               seq_printf(s,"pll%d        :cons:%x,%x,%x,%x\n",i,
+                               cru_readl(PLL_CONS(i,0)),
+                               cru_readl(PLL_CONS(i,1)),
+                               cru_readl(PLL_CONS(i,2)),
+                               cru_readl(PLL_CONS(i,3))
+                         );
+       }
+       seq_printf(s, "MODE        :%x\n", cru_readl(CRU_MODE_CON));
+
+       for(i=0;i<CRU_CLKSELS_CON_CNT;i++)
+       {
+               seq_printf(s,"CLKSEL%d     :%x\n",i,cru_readl(CRU_CLKSELS_CON(i)));
+       }
+       for(i=0;i<CRU_CLKGATES_CON_CNT;i++)
+       {
+               seq_printf(s,"CLKGATE%d           :%x\n",i,cru_readl(CRU_CLKGATES_CON(i)));
+       }
+       seq_printf(s,"GLB_SRST_FST:%x\n",cru_readl(CRU_GLB_SRST_FST));
+       seq_printf(s,"GLB_SRST_SND:%x\n",cru_readl(CRU_GLB_SRST_SND));
+
+       for(i=0;i<CRU_SOFTRSTS_CON_CNT;i++)
+       {
+               seq_printf(s,"CLKGATE%d           :%x\n",i,cru_readl(CRU_SOFTRSTS_CON(i)));
+       }
+       seq_printf(s,"CRU MISC    :%x\n",cru_readl(CRU_MISC_CON));
+       seq_printf(s,"GLB_CNT_TH  :%x\n",cru_readl(CRU_GLB_CNT_TH));
+
+}
+
+void rk30_clk_dump_regs(void)
+{
+       int i=0;
+       printk("\nPLL(id=0 apll,id=1,dpll,id=2,cpll,id=3 cpll)\n");
+       printk("\nPLLRegisters:\n");
+       for(i=0;i<END_PLL_ID;i++)
+       {
+               printk("pll%d        :cons:%x,%x,%x,%x\n",i,
+                               cru_readl(PLL_CONS(i,0)),
+                               cru_readl(PLL_CONS(i,1)),
+                               cru_readl(PLL_CONS(i,2)),
+                               cru_readl(PLL_CONS(i,3))
+                     );
+       }
+       printk("MODE        :%x\n", cru_readl(CRU_MODE_CON));
+
+       for(i=0;i<CRU_CLKSELS_CON_CNT;i++)
+       {
+               printk("CLKSEL%d           :%x\n",i,cru_readl(CRU_CLKSELS_CON(i)));
+       }
+       for(i=0;i<CRU_CLKGATES_CON_CNT;i++)
+       {
+               printk("CLKGATE%d         :%x\n",i,cru_readl(CRU_CLKGATES_CON(i)));
+       }
+       printk("GLB_SRST_FST:%x\n",cru_readl(CRU_GLB_SRST_FST));
+       printk("GLB_SRST_SND:%x\n",cru_readl(CRU_GLB_SRST_SND));
+
+       for(i=0;i<CRU_SOFTRSTS_CON_CNT;i++)
+       {
+               printk("SOFTRST%d         :%x\n",i,cru_readl(CRU_SOFTRSTS_CON(i)));
+       }
+       printk("CRU MISC    :%x\n",cru_readl(CRU_MISC_CON));
+       printk("GLB_CNT_TH  :%x\n",cru_readl(CRU_GLB_CNT_TH));
+
+}
+
+static struct clk def_ops_clk={
+       .get_parent=clksel_get_parent,
+       .set_parent=clksel_set_parent,
+};
+#ifdef CONFIG_PROC_FS
+static void dump_clock(struct seq_file *s, struct clk *clk, int deep,const struct list_head *root_clocks);
+struct clk_dump_ops dump_ops={
+       .dump_clk=dump_clock,
+       .dump_regs=dump_regs,
+};
+#endif
+#endif
+
+static void periph_clk_set_init(void)
+{
+       unsigned long aclk_p, hclk_p, pclk_p;
+       unsigned long ppll_rate=general_pll_clk.rate;
+       //aclk 148.5
+       
+       /* general pll */
+       switch (ppll_rate) {
+       case 148500* KHZ:
+               aclk_p = 148500*KHZ;
+               hclk_p = aclk_p>>1;
+               pclk_p = aclk_p>>2;
+               break;
+       case 1188*MHZ:
+               aclk_p = aclk_p>>3;// 0 
+               hclk_p = aclk_p>>1;
+               pclk_p = aclk_p>>2;
+
+       case 297 * MHZ:
+               aclk_p = ppll_rate>>1;
+               hclk_p = aclk_p>>0;
+               pclk_p = aclk_p>>1;
+               break;
+
+       case 300 * MHZ:
+               aclk_p = ppll_rate>>1;
+               hclk_p = aclk_p>>0;
+               pclk_p = aclk_p>>1;
+               break;  
+       default:
+               aclk_p = 150 * MHZ;
+               hclk_p = 150 * MHZ;
+               pclk_p = 75 * MHZ;
+               break;  
+       }
+       clk_set_parent_nolock(&aclk_periph_pre, &general_pll_clk);
+       clk_set_rate_nolock(&aclk_periph_pre, aclk_p);
+       clk_set_rate_nolock(&hclk_periph_pre, hclk_p);
+       clk_set_rate_nolock(&pclk_periph_pre, pclk_p);
+}
+
+
+#define CLK_FLG_MAX_I2S_12288KHZ       (1<<1)
+#define CLK_FLG_MAX_I2S_22579_2KHZ     (1<<2)
+#define CLK_FLG_MAX_I2S_24576KHZ       (1<<3)
+#define CLK_FLG_MAX_I2S_49152KHZ       (1<<4)
+
+void rk2928_clock_common_i2s_init(void)
+{
+       struct clk *max_clk,*min_clk;
+       unsigned long i2s_rate;
+       //20 times
+       if(rk2928_clock_flags&CLK_FLG_MAX_I2S_49152KHZ)
+       {
+               i2s_rate=49152000;      
+       }else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_24576KHZ)
+       {
+               i2s_rate=24576000;
+       }
+       else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_22579_2KHZ)
+       {
+               i2s_rate=22579000;
+       }
+       else if(rk2928_clock_flags&CLK_FLG_MAX_I2S_12288KHZ)
+       {
+               i2s_rate=12288000;
+       }
+       else
+       {
+               i2s_rate=49152000;      
+       }       
+
+       if(((i2s_rate*20)<=general_pll_clk.rate)||!(general_pll_clk.rate%i2s_rate))
+       {
+               clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk);
+       }
+       else if(((i2s_rate*20)<=codec_pll_clk.rate)||!(codec_pll_clk.rate%i2s_rate))
+       {
+               clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk);
+       }
+       else
+       {
+               if(general_pll_clk.rate>codec_pll_clk.rate)     
+                       clk_set_parent_nolock(&clk_i2s_pll, &general_pll_clk);
+               else
+                       clk_set_parent_nolock(&clk_i2s_pll, &codec_pll_clk);    
+       }
+               
+}
+static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned long cpll_rate)
+{
+       CLKDATA_DBG("ENTER %s\n", __func__);
+
+       clk_set_rate_nolock(&clk_core_pre, 650 * MHZ);//816
+       //general
+       clk_set_rate_nolock(&general_pll_clk, gpll_rate);
+       //code pll
+       clk_set_rate_nolock(&codec_pll_clk, cpll_rate);
+       //periph clk
+       periph_clk_set_init();
+
+       //i2s
+       rk2928_clock_common_i2s_init();
+
+       // spi
+       clk_set_rate_nolock(&clk_spi, clk_spi.parent->rate);
+
+       // uart
+#if 0 
+       clk_set_parent_nolock(&clk_uart_pll, &codec_pll_clk);
+#else
+       clk_set_parent_nolock(&clk_uart_pll, &general_pll_clk);
+#endif
+       //mac   
+       // FIXME
+#if 0
+       if(!(gpll_rate%(50*MHZ)))
+               clk_set_parent_nolock(&clk_mac_pll_div, &general_pll_clk);
+       else if(!(ddr_pll_clk.rate%(50*MHZ)))
+               clk_set_parent_nolock(&clk_mac_pll_div, &ddr_pll_clk);
+       else
+               CRU_PRINTK_ERR("mac can't get 50mhz\n");
+#endif
+       //hsadc
+       //auto pll sel
+       //clk_set_parent_nolock(&clk_hsadc_pll_div, &general_pll_clk);
+
+       //lcdc1  hdmi
+       //clk_set_parent_nolock(&dclk_lcdc1_div, &general_pll_clk);
+
+       //lcdc0 lcd auto sel pll
+       //clk_set_parent_nolock(&dclk_lcdc0_div, &general_pll_clk);
+
+       //cif
+       clk_set_parent_nolock(&clk_cif_out_div, &general_pll_clk);
+
+       //axi lcdc auto sel
+       //clk_set_parent_nolock(&aclk_lcdc0, &general_pll_clk);
+       //clk_set_parent_nolock(&aclk_lcdc1, &general_pll_clk);
+       // FIXME
+#if 0
+       clk_set_rate_nolock(&aclk_lcdc0_ipp_parent, 300*MHZ);
+       clk_set_rate_nolock(&aclk_lcdc1_rga_parent, 300*MHZ);
+#endif
+       //axi vepu auto sel
+       //clk_set_parent_nolock(&aclk_vepu, &general_pll_clk);
+       //clk_set_parent_nolock(&aclk_vdpu, &general_pll_clk);
+
+       clk_set_rate_nolock(&aclk_vepu, 300*MHZ);
+       clk_set_rate_nolock(&aclk_vdpu, 300*MHZ);
+       //gpu auto sel
+       //clk_set_parent_nolock(&clk_gpu, &general_pll_clk);
+       //
+}
+void __init _rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,int flags)
+{
+       struct clk_lookup *clk;
+       clk_register_dump_ops(&dump_ops);
+       clk_register_default_ops_clk(&def_ops_clk);
+
+       rk2928_clock_flags = flags;
+
+       CLKDATA_DBG("%s total %d clks\n", __func__, ARRAY_SIZE(clks));
+       for (clk = clks; clk < clks + ARRAY_SIZE(clks); clk++) {
+               CLKDATA_DBG("%s add dev_id=%s, con_id=%s\n", 
+                               __func__, clk->dev_id ? clk->dev_id : "NULL", clk->con_id ? clk->con_id : "NULL");
+               clkdev_add(clk);
+               clk_register(clk->clk);
+       }
+
+       CLKDATA_DBG("clk_recalculate_root_clocks_nolock\n");
+       clk_recalculate_root_clocks_nolock();
+
+       loops_per_jiffy = CLK_LOOPS_RECALC(arm_pll_clk.rate);
+
+       /*
+        * Only enable those clocks we will need, let the drivers
+        * enable other clocks as necessary
+        */
+       rk30_init_enable_clocks();
+
+       /*
+        * Disable any unused clocks left on by the bootloader
+        */
+       //clk_disable_unused();
+       CLKDATA_DBG("rk2928_clock_common_init, gpll=%lu, cpll=%lu\n", gpll, cpll);
+       rk2928_clock_common_init(gpll, cpll);
+       preset_lpj = loops_per_jiffy;
+
+       CLKDATA_DBG("%s clks init finish\n", __func__);
+}
+
+
+void __init rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,u32 flags)
+{
+       printk("version:        2012-8-6\n");
+       _rk2928_clock_data_init(gpll,cpll,flags);
+       //rk2928_dvfs_init();
+}
+
index 1e1059a7d3bad86f4e9283ffa7b938b74d1ebc4e..9292adca4591153a6bd3aae4a66bd2787745d356 100644 (file)
@@ -57,5 +57,35 @@ struct eeti_egalax_platform_data{
  
 };
 #endif
+enum _periph_pll {
+       periph_pll_1485mhz = 148500000,
+       periph_pll_297mhz = 297000000,
+       periph_pll_300mhz = 300000000,
+       periph_pll_1188mhz = 1188000000, /* for box*/
+};
+enum _codec_pll {
+       codec_pll_360mhz = 360000000, /* for HDMI */
+       codec_pll_408mhz = 408000000,
+       codec_pll_456mhz = 456000000,
+       codec_pll_504mhz = 504000000,
+       codec_pll_552mhz = 552000000, /* for HDMI */
+       codec_pll_600mhz = 600000000,
+       codec_pll_742_5khz = 742500000,
+       codec_pll_798mhz = 798000000,
+       codec_pll_1064mhz = 1064000000,
+       codec_pll_1188mhz = 1188000000,
+};
+
+//max i2s rate
+#define CLK_FLG_MAX_I2S_12288KHZ       (1<<1)
+#define CLK_FLG_MAX_I2S_22579_2KHZ     (1<<2)
+#define CLK_FLG_MAX_I2S_24576KHZ       (1<<3)
+#define CLK_FLG_MAX_I2S_49152KHZ       (1<<4)
+
+#define RK30_CLOCKS_DEFAULT_FLAGS (CLK_FLG_MAX_I2S_12288KHZ/*|CLK_FLG_EXT_27MHZ*/)
+#define periph_pll_default periph_pll_297mhz
+#define codec_pll_default codec_pll_798mhz
+//#define codec_pll_default codec_pll_1064mhz
+
 
 #endif
diff --git a/arch/arm/mach-rk2928/include/mach/clock.h b/arch/arm/mach-rk2928/include/mach/clock.h
new file mode 100755 (executable)
index 0000000..a94d6c8
--- /dev/null
@@ -0,0 +1,81 @@
+/* arch/arm/mach-rk29/include/mach/clock.h
+ *
+ * Copyright (C) 2011 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_RK30_CLOCK_H
+#define __ASM_ARCH_RK30_CLOCK_H
+
+/**
+ * struct clk_notifier_data - rate data to pass to the notifier callback
+ * @clk: struct clk * being changed
+ * @old_rate: previous rate of this clock
+ * @new_rate: new rate of this clock
+ *
+ * For a pre-notifier, old_rate is the clock's rate before this rate
+ * change, and new_rate is what the rate will be in the future.  For a
+ * post-notifier, old_rate and new_rate are both set to the clock's
+ * current rate (this was done to optimize the implementation).
+ */
+struct clk_notifier_data {
+       struct clk              *clk;
+       unsigned long           old_rate;
+       unsigned long           new_rate;
+};
+
+/*
+ * Clk notifier callback types
+ *
+ * Since the notifier is called with interrupts disabled, any actions
+ * taken by callbacks must be extremely fast and lightweight.
+ *
+ * CLK_PRE_RATE_CHANGE - called after all callbacks have approved the
+ *     rate change, immediately before the clock rate is changed, to
+ *     indicate that the rate change will proceed.  Drivers must
+ *     immediately terminate any operations that will be affected by
+ *     the rate change.  Callbacks must always return NOTIFY_DONE.
+ *
+ * CLK_ABORT_RATE_CHANGE: called if the rate change failed for some
+ *     reason after CLK_PRE_RATE_CHANGE.  In this case, all registered
+ *     notifiers on the clock will be called with
+ *     CLK_ABORT_RATE_CHANGE. Callbacks must always return
+ *     NOTIFY_DONE.
+ *
+ * CLK_POST_RATE_CHANGE - called after the clock rate change has
+ *     successfully completed.  Callbacks must always return
+ *     NOTIFY_DONE.
+ *
+ */
+#define CLK_PRE_RATE_CHANGE            1
+#define CLK_POST_RATE_CHANGE           2
+#define CLK_ABORT_RATE_CHANGE          3
+
+#define CLK_PRE_ENABLE                 4
+#define CLK_POST_ENABLE                        5
+#define CLK_ABORT_ENABLE               6
+
+#define CLK_PRE_DISABLE                        7
+#define CLK_POST_DISABLE               8
+#define CLK_ABORT_DISABLE              9
+
+struct notifier_block;
+
+extern int clk_notifier_register(struct clk *clk, struct notifier_block *nb);
+extern int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);
+
+#endif
+
+
+
+
+
diff --git a/arch/arm/mach-rk2928/include/mach/cru.h b/arch/arm/mach-rk2928/include/mach/cru.h
new file mode 100755 (executable)
index 0000000..b22b9a7
--- /dev/null
@@ -0,0 +1,563 @@
+#ifndef __MACH_CRU_H
+#define __MACH_CRU_H
+
+enum rk_plls_id {
+       APLL_ID = 0,
+       DPLL_ID,
+       CPLL_ID,
+       GPLL_ID,
+       END_PLL_ID,
+};
+
+/*****cru reg offset*****/
+
+#define CRU_MODE_CON           0x40
+#define CRU_CLKSEL_CON         0x44
+#define CRU_CLKGATE_CON                0xd0
+#define CRU_GLB_SRST_FST       0x100
+#define CRU_GLB_SRST_SND       0x104
+#define CRU_SOFTRST_CON                0x110
+
+#define PLL_CONS(id, i)                ((id) * 0x10 + ((i) * 4))
+
+#define CRU_CLKSELS_CON_CNT    (35)
+#define CRU_CLKSELS_CON(i)     (CRU_CLKSEL_CON + ((i) * 4))
+
+#define CRU_CLKGATES_CON_CNT   (10)
+#define CRU_CLKGATES_CON(i)    (CRU_CLKGATE_CON + ((i) * 4))
+
+#define CRU_SOFTRSTS_CON_CNT   (9)
+#define CRU_SOFTRSTS_CON(i)    (CRU_SOFTRST_CON + ((i) * 4))
+
+#define CRU_MISC_CON           (0x134)
+#define CRU_GLB_CNT_TH         (0x140)
+
+/*PLL_CON 0,1,2*/
+#define PLL_PWR_ON                     (1)
+#define PLL_PWR_DN                     (0)
+#define PLL_BYPASS                     (1 << 15)
+#define PLL_NO_BYPASS                  (0 << 15)
+//con0
+#define PLL_BYPASS_SHIFT               (15)
+
+#define PLL_POSTDIV1_MASK              (0x7)
+#define PLL_POSTDIV1_SHIFT             (12)
+#define PLL_FBDIV_MASK                 (0xfff)
+#define PLL_FBDIV_SHIFT                        (0)
+
+//con1
+#define PLL_RSTMODE_SHIFT              (15)
+#define PLL_RST_SHIFT                  (14)
+#define PLL_PWR_DN_SHIFT               (13)
+#define PLL_DSMPD_SHIFT                        (12)
+#define PLL_LOCK_SHIFT                 (10)
+
+#define PLL_POSTDIV2_MASK              (0x7)
+#define PLL_POSTDIV2_SHIFT             (6)
+#define PLL_REFDIV_MASK                        (0x3f)
+#define PLL_REFDIV_SHIFT               (0)
+
+//con2
+#define PLL_FOUT4PHASE_PWR_DN_SHIFT    (27)
+#define PLL_FOUTVCO_PWR_DN_SHIFT       (26)
+#define PLL_FOUTPOSTDIV_PWR_DN_SHIFT   (25)
+#define PLL_DAC_PWR_DN_SHIFT           (24)
+
+#define PLL_FRAC_MASK                  (0xffffff)
+#define PLL_FRAC_SHIFT                 (0)
+
+/********************************************************************/
+#define CRU_GET_REG_BIT_VAL(reg, bits_shift)           (((reg) >> (bits_shift)) & (0x1))
+#define CRU_GET_REG_BITS_VAL(reg, bits_shift, msk)     (((reg) >> (bits_shift)) & (msk))
+#define CRU_SET_BIT(val, bits_shift)                   (((val) & (0x1)) << (bits_shift))
+#define CRU_SET_BITS(val, bits_shift, msk)             (((val) & (msk)) << (bits_shift))
+#define CRU_W_MSK(bits_shift, msk)                     ((msk) << ((bits_shift) + 16))
+
+#define CRU_W_MSK_SETBITS(val, bits_shift, msk)        (CRU_W_MSK(bits_shift, msk)     \
+                                                       | CRU_SET_BITS(val, bits_shift, msk))
+#define CRU_W_MSK_SETBIT(val, bits_shift)              (CRU_W_MSK(bits_shift, 0x1)     \
+                                                       | CRU_SET_BIT(val, bits_shift))
+
+#define PLL_SET_REFDIV(val)                            CRU_W_MSK_SETBITS(val, PLL_REFDIV_SHIFT, PLL_REFDIV_MASK)
+#define PLL_SET_FBDIV(val)                             CRU_W_MSK_SETBITS(val, PLL_FBDIV_SHIFT, PLL_FBDIV_MASK)
+#define PLL_SET_POSTDIV1(val)                          CRU_W_MSK_SETBITS(val, PLL_POSTDIV1_SHIFT, PLL_POSTDIV1_MASK)
+#define PLL_SET_POSTDIV2(val)                          CRU_W_MSK_SETBITS(val, PLL_POSTDIV2_SHIFT, PLL_POSTDIV2_MASK)
+#define PLL_SET_FRAC(val)                              CRU_SET_BITS(val, PLL_FRAC_SHIFT, PLL_FRAC_MASK)
+
+#define PLL_GET_REFDIV(reg)                            CRU_GET_REG_BITS_VAL(reg, PLL_REFDIV_SHIFT, PLL_REFDIV_MASK)
+#define PLL_GET_FBDIV(reg)                             CRU_GET_REG_BITS_VAL(reg, PLL_FBDIV_SHIFT, PLL_FBDIV_MASK)
+#define PLL_GET_POSTDIV1(reg)                          CRU_GET_REG_BITS_VAL(reg, PLL_POSTDIV1_SHIFT, PLL_POSTDIV1_MASK)
+#define PLL_GET_POSTDIV2(reg)                          CRU_GET_REG_BITS_VAL(reg, PLL_POSTDIV2_SHIFT, PLL_POSTDIV2_MASK)
+#define PLL_GET_FRAC(reg)                              CRU_GET_REG_BITS_VAL(reg, PLL_FRAC_SHIFT, PLL_FRAC_MASK)
+
+//#define APLL_SET_BYPASS(val)                         CRU_SET_BIT(val, PLL_BYPASS_SHIFT)
+#define PLL_SET_DSMPD(val)                             CRU_SET_BIT(val, PLL_DSMPD_SHIFT)
+#define PLL_GET_DSMPD(reg)                             CRU_GET_REG_BIT_VAL(reg, PLL_DSMPD_SHIFT)
+/*******************MODE BITS***************************/
+#define PLL_MODE_MSK(id)               (0x1 << ((id) * 4))
+#define PLL_MODE_SHIFT(id)             ((id) * 4)
+#define PLL_MODE_SLOW(id)              (CRU_W_MSK_SETBIT(0x0, PLL_MODE_SHIFT(id)))
+#define PLL_MODE_NORM(id)              (CRU_W_MSK_SETBIT(0x1, PLL_MODE_SHIFT(id)))
+/*******************CLKSEL0 BITS***************************/
+#define CLK_SET_DIV_CON_SUB1(val, bits_shift, msk)     CRU_W_MSK_SETBITS((val - 1), bits_shift, msk)
+
+#define CPU_CLK_PLL_SEL_SHIFT          (13)
+#define CORE_CLK_PLL_SEL_SHIFT         (7)
+#define SEL_APLL                       (0)
+#define SEL_GPLL                       (1)
+#define CPU_SEL_PLL(plls)              CRU_W_MSK_SETBIT(plls, CPU_CLK_PLL_SEL_SHIFT)
+#define CORE_SEL_PLL(plls)             CRU_W_MSK_SETBIT(plls, CORE_CLK_PLL_SEL_SHIFT)
+
+#define ACLK_CPU_DIV_MASK              (0x1f)
+#define ACLK_CPU_DIV_SHIFT             (8)
+#define A9_CORE_DIV_MASK               (0x1f)
+#define A9_CORE_DIV_SHIFT              (0)
+
+#define ACLK_CPU_DIV(val)              CLK_SET_DIV_CON_SUB1(val, ACLK_CPU_DIV_SHIFT, ACLK_CPU_DIV_MASK)
+#define CLK_CORE_DIV(val)              CLK_SET_DIV_CON_SUB1(val, A9_CORE_DIV_SHIFT, A9_CORE_DIV_MASK)  
+/*******************CLKSEL1 BITS***************************/
+#define PCLK_CPU_DIV_MASK              (0x7)
+#define PCLK_CPU_DIV_SHIFT             (12)
+#define HCLK_CPU_DIV_MASK              (0x3)
+#define HCLK_CPU_DIV_SHIFT             (8)
+#define ACLK_CORE_DIV_MASK             (0x1)
+#define ACLK_CORE_DIV_SHIFT            (4)
+#define CORE_PERIPH_DIV_MASK           (0xf)
+#define CORE_PERIPH_DIV_SHIFT          (0)
+
+#define PCLK_CPU_DIV(val)              CLK_SET_DIV_CON_SUB1(val, PCLK_CPU_DIV_SHIFT, PCLK_CPU_DIV_MASK)
+#define HCLK_CPU_DIV(val)              CLK_SET_DIV_CON_SUB1(val, HCLK_CPU_DIV_SHIFT, HCLK_CPU_DIV_MASK)
+#define ACLK_CORE_DIV(val)             CLK_SET_DIV_CON_SUB1(val, ACLK_CORE_DIV_SHIFT, ACLK_CORE_DIV_MASK)
+#define CLK_CORE_PERI_DIV(val)         CLK_SET_DIV_CON_SUB1(val, CORE_PERIPH_DIV_SHIFT, CORE_PERIPH_DIV_MASK)  
+
+/*******************clksel10***************************/
+#define PERI_PLL_SEL_SHIFT     15
+#define PERI_PCLK_DIV_MASK     (0x3)
+#define PERI_PCLK_DIV_SHIFT    (12)
+#define PERI_HCLK_DIV_MASK     (0x3)
+#define PERI_HCLK_DIV_SHIFT    (8)
+#define PERI_ACLK_DIV_MASK     (0x1f)
+#define PERI_ACLK_DIV_SHIFT    (0)
+
+#define SEL_2PLL_GPLL          (0)
+#define SEL_2PLL_CPLL          (1)
+
+#define RATIO_11               (0)
+#define RATIO_21               (1)
+#define RATIO_41               (2)
+#define RATIO_81               (3)
+
+#define PERI_CLK_SEL_PLL(plls) CRU_W_MSK_SETBIT(plls, PERI_PLL_SEL_SHIFT)
+#define PERI_SET_A2P_RATIO(ratio)      CRU_W_MSK_SETBITS(ratio, PERI_PCLK_DIV_SHIFT, PERI_PCLK_DIV_MASK)
+#define PERI_SET_A2H_RATIO(ratio)      CRU_W_MSK_SETBITS(ratio, PERI_HCLK_DIV_SHIFT, PERI_PCLK_DIV_MASK)
+#define PERI_SET_ACLK_DIV(val)         CRU_W_MSK_SETBITS(val, PERI_ACLK_DIV_SHIFT, PERI_ACLK_DIV_MASK)
+/*******************gate BITS***************************/
+#define CLK_GATE_CLKID_CONS(i) CRU_CLKGATES_CON((i) / 16)
+
+#define CLK_GATE(i)            (1 << ((i)%16))
+#define CLK_UN_GATE(i)         (0)
+
+#define CLK_GATE_W_MSK(i)      (1 << (((i) % 16) + 16))
+#define CLK_GATE_CLKID(i)      (16 * (i))
+
+enum cru_clk_gate {
+       /* SCU CLK GATE 0 CON */
+       CLK_GATE_CORE_PERIPH = CLK_GATE_CLKID(0),
+       CLK_GATE_CPU_GPLL,
+       CLK_GATE_DDRPHY_SRC,
+       CLK_GATE_ACLK_CPU,
+
+       CLK_GATE_HCLK_CPU,
+       CLK_GATE_PCLK_CPU,
+       CLK_GATE_0RES6,
+       CLK_GATE_ACLK_CORE,
+       
+       CLK_GATE_0RES8,
+       CLK_GATE_I2S_SRC,
+       CLK_GATE_I2S_FRAC_SRC,
+       CLK_GATE_HCLK_VIO_PRE,
+       
+       CLK_GATE_0RES12,
+       CLK_GATE_0RES13,
+       CLK_GATE_0RES14,
+       CLK_GATE_TESTCLK,
+
+       CLK_GATE_TIMER0 = CLK_GATE_CLKID(1),
+       CLK_GATE_TIMER1,
+       CLK_GATE_1RES2,
+       CLK_GATE_JTAG,
+       
+       CLK_GATE_1RES4,
+       CLK_GATE_OTGPHY0,
+       CLK_GATE_OTGPHY1,
+       CLK_GATE_1RES7,
+       
+       CLK_GATE_UART0_SRC,
+       CLK_GATE_UART0_FRAC_SRC,
+       CLK_GATE_UART1_SRC,
+       CLK_GATE_UART1_FRAC_SRC,
+       
+       CLK_GATE_UART2_SRC,
+       CLK_GATE_UART2_FRAC_SRC,
+       CLK_GATE_1RES14,
+       CLK_GATE_1RES15,
+
+       CLK_GATE_PERIPH_SRC = CLK_GATE_CLKID(2),
+       CLK_GATE_ACLK_PERIPH,
+       CLK_GATE_HCLK_PERIPH,
+       CLK_GATE_PCLK_PERIPH,
+       
+       CLK_GATE_2RES4,
+       CLK_GATE_2RES5,
+       CLK_GATE_2RES6,
+       CLK_GATE_2RES7,
+       
+       CLK_GATE_SARADC_SRC,
+       CLK_GATE_SPI0_SRC,
+       CLK_GATE_2RES10,
+       CLK_GATE_MMC0_SRC,
+       
+       CLK_GATE_2RES12,
+       CLK_GATE_SDIO_SRC,
+       CLK_GATE_EMMC_SRC,
+       CLK_GATE_2RES15,
+
+       CLK_GATE_ACLK_VIO_SRC = CLK_GATE_CLKID(3),
+       CLK_GATE_DCLK_LCDC0_SRC,
+       CLK_GATE_SCLK_LCDC_SRC,
+       CLK_GATE_PCLKIN_CIF,
+       
+       CLK_GATE_ACLK_GPS,
+       CLK_GATE_3RES5,
+       CLK_GATE_3RES6,
+       CLK_GATE_CIF_OUT_SRC,
+       
+       CLK_GATE_PCLK_HDMI,
+       CLK_GATE_ACLK_VEPU_SRC,
+       CLK_GATE_HCLK_VEPU,
+       CLK_GATE_ACLK_VDPU_SRC,
+       
+       CLK_GATE_HCLK_VDPU,
+       CLK_GATE_GPU_PRE,
+       CLK_GATE_3RES14,
+       CLK_GATE_3RES15,
+
+       CLK_GATE_HCLK_PERI_AXI_MATRIX = CLK_GATE_CLKID(4),
+       CLK_GATE_PCLK_PERI_AXI_MATRIX,
+       CLK_GATE_ACLK_CPU_PERI,
+       CLK_GATE_ACLK_PERI_AXI_MATRIX,
+       
+       CLK_GATE_4RES4,
+       CLK_GATE_4RES5,
+       CLK_GATE_4RES6,
+       CLK_GATE_4RES7,
+       
+       CLK_GATE_4RES8,
+       CLK_GATE_4RES9,
+       CLK_GATE_ACLK_STRC_SYS,
+       CLK_GATE_4RES11,
+       
+       CLK_GATE_ACLK_INTMEM,
+       CLK_GATE_4RES13,
+       CLK_GATE_4RES14,
+       CLK_GATE_4RES15,
+
+       CLK_GATE_5RES0 = CLK_GATE_CLKID(5),
+       CLK_GATE_ACLK_DMAC2,
+       CLK_GATE_PCLK_EFUSE,
+       CLK_GATE_5RES3,
+       
+       CLK_GATE_PCLK_GRF,
+       CLK_GATE_5RES5,
+       CLK_GATE_HCLK_ROM,
+       CLK_GATE_PCLK_DDRUPCTL,
+       
+       CLK_GATE_5RES8,
+       CLK_GATE_HCLK_NANDC,
+       CLK_GATE_HCLK_SDMMC0,
+       CLK_GATE_HCLK_SDIO,
+       
+       CLK_GATE_5RES12,
+       CLK_GATE_HCLK_OTG0,
+       CLK_GATE_PCLK_ACODEC,
+       CLK_GATE_5RES15,
+
+       CLK_GATE_ACLK_LCDC0 = CLK_GATE_CLKID(6),
+       CLK_GATE_HCLK_LCDC0,
+       CLK_GATE_6RES2,
+       CLK_GATE_6RES3,
+
+       CLK_GATE_HCLK_CIF,
+       CLK_GATE_ACLK_CIF,
+       CLK_GATE_6RES6,
+       CLK_GATE_6RES7,
+
+       CLK_GATE_6RES8,
+       CLK_GATE_6RES9,
+       CLK_GATE_HCLK_RGA,
+       CLK_GATE_ACLK_RGA,
+       
+       CLK_GATE_HCLK_VIO_BUS,
+       CLK_GATE_ACLK_VIO0,
+       CLK_GATE_6RES14,
+       CLK_GATE_6RES15,
+
+       CLK_GATE_HCLK_EMMC = CLK_GATE_CLKID(7),
+       CLK_GATE_7RES1,
+       CLK_GATE_HCLK_I2S,
+       CLK_GATE_HCLK_OTG1,
+       
+       CLK_GATE_7RES4,
+       CLK_GATE_7RES5,
+       CLK_GATE_7RES6,
+       CLK_GATE_PCLK_TIMER0,
+
+       CLK_GATE_PCLK_TIMER1,
+       CLK_GATE_7RES9,
+       CLK_GATE_PCLK_PWM01,
+       CLK_GATE_7RES11,
+       
+       CLK_GATE_PCLK_SPI0,
+       CLK_GATE_7RES13,
+       CLK_GATE_PCLK_SARADC,
+       CLK_GATE_PCLK_WDT,
+
+       CLK_GATE_PCLK_UART0 = CLK_GATE_CLKID(8),
+       CLK_GATE_PCLK_UART1,
+       CLK_GATE_PCLK_UART2,
+       CLK_GATE_8RES3,
+
+       CLK_GATE_PCLK_I2C0,
+       CLK_GATE_PCLK_I2C1,
+       CLK_GATE_PCLK_I2C2,
+       CLK_GATE_PCLK_I2C3,
+
+       CLK_GATE_8RES8,
+       CLK_GATE_PCLK_GPIO0,
+       CLK_GATE_PCLK_GPIO1,
+       CLK_GATE_PCLK_GPIO2,
+       
+       CLK_GATE_PCLK_GPIO3,
+       CLK_GATE_8RES13,
+       CLK_GATE_8RES14,
+       CLK_GATE_8RES15,
+
+       CLK_GATE_CLK_CORE_DBG = CLK_GATE_CLKID(9),
+       CLK_GATE_PCLK_DBG,
+       CLK_GATE_9RES2,
+       CLK_GATE_9RES3,
+       
+       CLK_GATE_CLK_L2C,
+       CLK_GATE_9RES5,
+       CLK_GATE_9RES6,
+       CLK_GATE_9RES7,
+       
+       CLK_GATE_9RES8,
+       CLK_GATE_9RES9,
+       CLK_GATE_HCLK_USB_PERI,
+       CLK_GATE_HCLK_PERI_ARBI,
+       
+       CLK_GATE_ACLK_PERI_NIU,
+       CLK_GATE_9RES13,
+       CLK_GATE_9RES14,
+       CLK_GATE_9RES15,
+
+       CLK_GATE_MAX,
+};
+
+#define SOFT_RST_ID(i)         (16 * (i))
+
+enum cru_soft_reset {
+       SOFT_RST_CORE_SRST_WDT_SEL = SOFT_RST_ID(0),
+       SOFT_RST_ACLK_CORE,
+       SOFT_RST_MCORE,
+       SOFT_RST_0RES3,
+       
+       SOFT_RST_0RES4,
+       SOFT_RST_0RES5,
+       SOFT_RST_0RES6,
+       SOFT_RST_MCORE_DBG,
+       
+       SOFT_RST_0RES8,
+       SOFT_RST_0RES9,
+       SOFT_RST_0RES10,
+       SOFT_RST_0RES11,
+
+       SOFT_RST_CORE0_WDT,
+       SOFT_RST_0RES13,
+       SOFT_RST_STRC_SYS_AXI,
+       SOFT_RST_0RES15,
+
+       SOFT_RST_CPU_STRC_SYS_AXI = SOFT_RST_ID(1),
+       SOFT_RST_CPUSYS_AHB,
+       SOFT_RST_L2MEM_CON_AXI,
+       SOFT_RST_AHB2APB,
+       
+       SOFT_RST_1RES4,
+       SOFT_RST_INTMEM,
+       SOFT_RST_ROM,
+       SOFT_RST_PERI_NIU,
+       
+       SOFT_RST_I2S,
+       SOFT_RST_1RES9,
+       SOFT_RST_1RES10,
+       SOFT_RST_TIMER0,
+       
+       SOFT_RST_TIMER1,
+       SOFT_RST_1RES13,
+       SOFT_RST_EFUSE_APB,
+       SOFT_RST_ACODEC,
+
+       SOFT_RST_GPIO0 = SOFT_RST_ID(2),
+       SOFT_RST_GPIO1,
+       SOFT_RST_GPIO2,
+       SOFT_RST_GPIO3,
+
+       SOFT_RST_2RES4,
+       SOFT_RST_2RES5,
+       SOFT_RST_2RES6,
+       SOFT_RST_UART0,
+       
+       SOFT_RST_UART1,
+       SOFT_RST_UART2,
+       SOFT_RST_2RES10,
+       SOFT_RST_I2C0,
+       
+       SOFT_RST_I2C1,
+       SOFT_RST_I2C2,
+       SOFT_RST_I2C3,
+       SOFT_RST_2RES15,
+
+       SOFT_RST_PWM0 = SOFT_RST_ID(3),
+       SOFT_RST_PWM1,
+       SOFT_RST_DAP_PO,
+       SOFT_RST_DAP,
+       
+       SOFT_RST_DAP_SYS,
+       SOFT_RST_3RES5,
+       SOFT_RST_3RES6,
+       SOFT_RST_GRF,
+       
+       SOFT_RST_I2C,
+       SOFT_RST_PERIPHSYS_AXI,
+       SOFT_RST_PERIPHSYS_AHB,
+       SOFT_RST_PERIPHSYS_APB,
+       
+       SOFT_RST_PWM2,
+       SOFT_RST_CPU_PERI,
+       SOFT_RST_EMEM_PERI,
+       SOFT_RST_USB_PERI,
+
+       SOFT_RST_DMA2 = SOFT_RST_ID(4),
+       SOFT_RST_4RES1,
+       SOFT_RST_4RES2,
+       SOFT_RST_GPS,
+       
+       SOFT_RST_NANDC,
+       SOFT_RST_USBOTG0,
+       SOFT_RST_USBPHY0,
+       SOFT_RST_OTGC0,
+       
+       SOFT_RST_USBOTG1,
+       SOFT_RST_USBPHY1,
+       SOFT_RST_OTGC1,
+       SOFT_RST_4RES11,
+       
+       SOFT_RST_4RES12,
+       SOFT_RST_4RES13,
+       SOFT_RST_4RES14,
+       SOFT_RST_DDRMSCH,
+
+       SOFT_RST_5RES0 = SOFT_RST_ID(5),
+       SOFT_RST_MMC0,
+       SOFT_RST_SDIO,
+       SOFT_RST_EMMC,
+       
+       SOFT_RST_SPI0,
+       SOFT_RST_5RES5,
+       SOFT_RST_WDT,
+       SOFT_RST_SARADC,
+
+       SOFT_RST_DDRPHY,
+       SOFT_RST_DDRPHY_APB,
+       SOFT_RST_DDRCTRL,
+       SOFT_RST_DDRCTRL_APB,
+       
+       SOFT_RST_5RES12,
+       SOFT_RST_5RES13,
+       SOFT_RST_5RES14,
+       SOFT_RST_5RES15,
+
+       SOFT_RST_HDMI_PCLK = SOFT_RST_ID(6),
+       SOFT_RST_HDMI_DCLK,
+       SOFT_RST_VIO0_AXI,
+       SOFT_RST_VIO_BUS_AHB,
+       
+       SOFT_RST_LCDC0_AXI,
+       SOFT_RST_LCDC0_AHB,
+       SOFT_RST_LCDC0_DCLK,
+       SOFT_RST_UTMI0,
+       
+       SOFT_RST_UTMI1,
+       SOFT_RST_USBPOR,
+       SOFT_RST_6RES10,
+       SOFT_RST_6RES11,
+
+       SOFT_RST_RGA_AXI,
+       SOFT_RST_RGA_AHB,
+       SOFT_RST_CIF0,
+       SOFT_RST_LCDC_SCL,
+
+       SOFT_RST_VCODEC_AXI = SOFT_RST_ID(7),
+       SOFT_RST_VCODEC_AHB,
+       SOFT_RST_VIO1_AXI,
+       SOFT_RST_CPU_VCODEC,
+       
+       SOFT_RST_VCODEC_NIU_AXI,
+       SOFT_RST_7RES5,
+       SOFT_RST_7RES6,
+       SOFT_RST_7RES7,
+       
+       SOFT_RST_GPU,
+       SOFT_RST_7RES9,
+       SOFT_RST_GPU_NIU_AXI,
+       SOFT_RST_7RES11,
+       
+       SOFT_RST_7RES12,
+       SOFT_RST_7RES13,
+       SOFT_RST_7RES14,
+       SOFT_RST_7RES15,
+
+       SOFT_RST_8RES0 = SOFT_RST_ID(8),
+       SOFT_RST_8RES1,
+       SOFT_RST_CORE_DBG,
+       SOFT_RST_DBG_APB,
+       
+       SOFT_RST_8RES4,
+       SOFT_RST_8RES5,
+       SOFT_RST_8RES6,
+       SOFT_RST_8RES7,
+       
+       SOFT_RST_8RES8,
+       SOFT_RST_8RES9,
+       SOFT_RST_8RES10,
+       SOFT_RST_8RES11,
+       
+       SOFT_RST_8RES12,
+       SOFT_RST_8RES13,
+       SOFT_RST_8RES14,
+       SOFT_RST_8RES15,
+
+       SOFT_RST_MAX,
+};
+
+/*****cru reg end*****/
+static inline void cru_set_soft_reset(enum cru_soft_reset idx, bool on)
+{
+       const void __iomem *reg = RK2928_CRU_BASE + CRU_SOFTRSTS_CON(idx >> 4);
+       u32 val = on ? 0x10001U << (idx & 0xf) : 0x10000U << (idx & 0xf);
+       writel_relaxed(val, reg);
+       dsb();
+}
+
+#endif