rk2928:sdk: add cpufreq and dvfs support, BUT NOT compile
authorchenxing <chenxing@rock-chips.com>
Tue, 14 Aug 2012 10:45:41 +0000 (18:45 +0800)
committerchenxing <chenxing@rock-chips.com>
Tue, 14 Aug 2012 10:45:41 +0000 (18:45 +0800)
arch/arm/mach-rk2928/Makefile
arch/arm/mach-rk2928/board-rk2928-sdk.c
arch/arm/mach-rk2928/clock.c [changed mode: 0755->0644]
arch/arm/mach-rk2928/clock_data.c
arch/arm/mach-rk2928/cpufreq.c [new file with mode: 0644]
arch/arm/mach-rk2928/dvfs.c [new file with mode: 0644]
arch/arm/mach-rk2928/include/mach/dvfs.h [new file with mode: 0644]

index 13a891691d1d41a06b264c4295506f9744936f49..6acd3f120855edf8d9f5b8099eb0bac843adf731 100644 (file)
@@ -6,6 +6,8 @@ obj-y += devices.o
 obj-y += iomux.o
 obj-y += clock.o
 obj-y += clock_data.o
+obj-$(CONFIG_CPU_FREQ) += cpufreq.o
+obj-$(CONFIG_DVFS) += dvfs.o
 obj-$(CONFIG_PM) += pm.o
 CFLAGS_pm.o += -Os -mthumb
 
index b44fdc5b503803f77a4a0a9c879ee7893e52af1d..fb48103c02459db78845286584486cd13d96e6a4 100755 (executable)
@@ -33,7 +33,7 @@
 #include <asm/mach/map.h>
 #include <asm/mach/flash.h>
 #include <asm/hardware/gic.h>
-//#include <mach/dvfs.h>
+#include <mach/dvfs.h>
 
 #include <mach/board.h>
 #include <mach/hardware.h>
@@ -762,10 +762,56 @@ static void __init rk2928_reserve(void)
 #endif
        board_mem_reserved();
 }
+/**
+ * dvfs_cpu_logic_table: table for arm and logic dvfs 
+ * @frequency  : arm frequency
+ * @cpu_volt   : arm voltage depend on frequency
+ * @logic_volt : logic voltage arm requests depend on frequency
+ * comments    : min arm/logic voltage
+ */
+static struct dvfs_arm_table dvfs_cpu_logic_table[] = {
+       {.frequency = 216 * 1000,       .cpu_volt = 1200 * 1000,        .logic_volt = 1200 * 1000},//0.975V/1.000V
+       {.frequency = 312 * 1000,       .cpu_volt = 1200 * 1000,        .logic_volt = 1200 * 1000},//0.975V/1.000V
+       {.frequency = 408 * 1000,       .cpu_volt = 1200 * 1000,        .logic_volt = 1200 * 1000},//1.000V/1.025V
+       {.frequency = 504 * 1000,       .cpu_volt = 1200 * 1000,        .logic_volt = 1200 * 1000},//1.000V/1.025V
+       {.frequency = 600 * 1000,       .cpu_volt = 1200 * 1000,        .logic_volt = 1200 * 1000},//1.025V/1.050V
+       {.frequency = 696 * 1000,       .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.000V/1.025V
+       {.frequency = 816 * 1000,       .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.100V/1.050V
+       {.frequency = 912 * 1000,       .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.100V/1.050V
+#if 0
+       {.frequency = 1008 * 1000,      .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.100V/1.050V
+       {.frequency = 1104 * 1000,      .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.100V/1.050V
+       {.frequency = 1200 * 1000,      .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.100V/1.050V
+       {.frequency = 1104 * 1000,      .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.100V/1.050V
+       {.frequency = 1248 * 1000,      .cpu_volt = 1400 * 1000,        .logic_volt = 1200 * 1000},//1.100V/1.050V
+#endif
+       //{.frequency = 1000 * 1000,    .cpu_volt = 1225 * 1000,        .logic_volt = 1200 * 1000},//1.150V/1.100V
+       {.frequency = CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table dvfs_gpu_table[] = {
+       {.frequency = 266 * 1000,       .index = 1050 * 1000},
+       {.frequency = 400 * 1000,       .index = 1275 * 1000},
+       {.frequency = CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table dvfs_ddr_table[] = {
+       {.frequency = 300 * 1000,       .index = 1050 * 1000},
+       {.frequency = 400 * 1000,       .index = 1125 * 1000},
+       {.frequency = CPUFREQ_TABLE_END},
+};
+
+#define DVFS_CPU_TABLE_SIZE    (ARRAY_SIZE(dvfs_cpu_logic_table))
+static struct cpufreq_frequency_table cpu_dvfs_table[DVFS_CPU_TABLE_SIZE];
+static struct cpufreq_frequency_table dep_cpu2core_table[DVFS_CPU_TABLE_SIZE];
 
 void __init board_clock_init(void)
 {
        rk2928_clock_data_init(periph_pll_default, codec_pll_default, RK30_CLOCKS_DEFAULT_FLAGS);
+       dvfs_set_arm_logic_volt(dvfs_cpu_logic_table, cpu_dvfs_table, dep_cpu2core_table);
+       dvfs_set_freq_volt_table(clk_get(NULL, "gpu"), dvfs_gpu_table);
+       //dvfs_set_freq_volt_table(clk_get(NULL, "ddr"), dvfs_ddr_table);
+       printk("%s end\n", __func__);
 }
 
 
old mode 100755 (executable)
new mode 100644 (file)
index 9fe7ae4..b9bb52d
@@ -23,7 +23,7 @@
 #include <linux/delay.h>
 #include <mach/clock.h>
 #include "clock.h"
-//#include <mach/dvfs.h>
+#include <mach/dvfs.h>
 #include <linux/delay.h>
 
 #define CLOCK_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args);
@@ -126,6 +126,7 @@ int clk_register(struct clk *clk)
                return -EINVAL;
        //INIT_LIST_HEAD(&clk->sibling);
        INIT_LIST_HEAD(&clk->children);
+
        /*
         * trap out already registered clocks
         */
@@ -138,11 +139,10 @@ int clk_register(struct clk *clk)
        else if (clk->parents)
                clk->parent =clk_default_get_parent(clk);
        
-       if (clk->parent){
+       if (clk->parent)
                list_add(&clk->sibling, &clk->parent->children);
-       } else {
+       else
                list_add(&clk->sibling, &root_clks);
-       }
        list_add(&clk->node, &clocks);
        mutex_unlock(&clocks_mutex);    
        return 0;
@@ -318,7 +318,7 @@ int clk_set_parent_nolock(struct clk *clk, struct clk *parent)
        return ret;
 }
 /**********************************dvfs****************************************************/
-#if 0
+
 struct clk_node *clk_get_dvfs_info(struct clk *clk)
 {
     return clk->dvfs_info;
@@ -338,7 +338,7 @@ 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
@@ -398,10 +398,9 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        }
        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();
@@ -703,7 +702,8 @@ void clk_register_dump_ops(struct clk_dump_ops *ops)
 {
        dump_def_ops=ops;
 }
-       
+
+#ifdef CONFIG_RK_CLOCK_PROC
 static int proc_clk_show(struct seq_file *s, void *v)
 {
        struct clk* clk;
@@ -747,4 +747,5 @@ static int __init clk_proc_init(void)
 
 }
 late_initcall(clk_proc_init);
+#endif /* CONFIG_RK_CLOCK_PROC */
 
index 8584e6d4d955552edfe21eef262cd743ce98a5dd..8b311cc9577686b41340ed1bc9c807dc0963c9b4 100644 (file)
@@ -24,6 +24,7 @@
 #include <mach/cru.h>
 #include <mach/iomux.h>
 #include <mach/clock.h>
+#include <mach/dvfs.h>
 #include "clock.h"
 //#include <mach/pmu.h>
 
@@ -126,8 +127,19 @@ struct pll_clk_set {
 }
 
 static const struct apll_clk_set apll_clks[] = {
-       _APLL_SET_CLKS( 650, 6, 325, 2, 1, 1, 0, 41, 21, 81, 21, 21),
-       _APLL_SET_CLKS(1000, 3, 125, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS(1248, 1, 52, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS(1200, 1, 50, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS(1104, 1, 46, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS(1008, 1, 42, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 912, 1, 38, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 816, 1, 34, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 696, 1, 29, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 600, 1, 25, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 504, 1, 21, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 408, 1, 17, 1, 1, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 312, 1, 52, 2, 2, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS( 216, 1, 36, 2, 2, 1, 0, 41, 21, 41, 21, 21),
+       _APLL_SET_CLKS(   0, 1, 0, 1, 1, 1, 0, 41, 21, 41, 21, 21),
 };
 
 #define _PLL_SET_CLKS(_mhz, _refdiv, _fbdiv, _postdiv1, _postdiv2, _dsmpd, _frac) \
@@ -734,7 +746,7 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate)
        CLKDATA_DBG("pllcon0 %08x\n", cru_readl(PLL_CONS(0,0)));
        CLKDATA_DBG("pllcon1 %08x\n", cru_readl(PLL_CONS(0,1)));
        CLKDATA_DBG("pllcon2 %08x\n", cru_readl(PLL_CONS(0,2)));
-       CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3)));
+       //CLKDATA_DBG("pllcon3 %08x\n", cru_readl(PLL_CONS(0,3)));
        CLKDATA_DBG("clksel0 %08x\n", cru_readl(CRU_CLKSELS_CON(0)));
        CLKDATA_DBG("clksel1 %08x\n", cru_readl(CRU_CLKSELS_CON(1)));
        if(clk_set->rate==rate) {
@@ -761,7 +773,7 @@ static int apll_clk_set_rate(struct clk *clk, unsigned long rate)
                //rk2928_clock_udelay(5);
 
                //wating lock state
-               rk2928_clock_udelay(clk_set->rst_dly);
+               rk2928_clock_udelay(clk_set->rst_dly);  
                pll_wait_lock(pll_id);
 
                //return form slow
@@ -1003,7 +1015,7 @@ static int arm_core_clk_set_rate(struct clk *c, unsigned long rate)
        //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);
+       CLKDATA_DBG("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);
@@ -1013,6 +1025,7 @@ static int arm_core_clk_set_rate(struct clk *c, unsigned long rate)
        return 0;
 }
 static struct clk clk_core_pre = {
+       //.name         = "cpu",
        .name           = "core_pre",
        .parent         = &arm_pll_clk,
        .recalc         = clksel_recalc_div,
@@ -1599,6 +1612,7 @@ static struct clk clk_saradc = {
 // name: gpu_aclk
 static struct clk *clk_gpu_pre_parents[]               = SELECT_FROM_2PLLS_CG;
 static struct clk clk_gpu_pre = {
+       //.name         = "gpu",
        .name           = "gpu_pre",
        .parent         = &general_pll_clk,
        .mode           = gate_mode,
@@ -2428,7 +2442,7 @@ static void __init rk2928_clock_common_init(unsigned long gpll_rate,unsigned lon
 {
        CLKDATA_DBG("ENTER %s\n", __func__);
 
-       clk_set_rate_nolock(&clk_core_pre, 1000 * MHZ);//816
+       clk_set_rate_nolock(&clk_core_pre, 816 * MHZ);//816
        //general
        clk_set_rate_nolock(&general_pll_clk, gpll_rate);
        //code pll
@@ -2530,8 +2544,8 @@ void __init _rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,int fl
 
 void __init rk2928_clock_data_init(unsigned long gpll,unsigned long cpll,u32 flags)
 {
-       printk("%s version:     2012-8-7\n", __func__);
+       printk("%s version:     2012-8-14\n", __func__);
        _rk2928_clock_data_init(gpll,cpll,flags);
-       //rk2928_dvfs_init();
+       rk30_dvfs_init();
 }
 
diff --git a/arch/arm/mach-rk2928/cpufreq.c b/arch/arm/mach-rk2928/cpufreq.c
new file mode 100644 (file)
index 0000000..4f79671
--- /dev/null
@@ -0,0 +1,711 @@
+/*
+ * 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.
+ *
+ */
+//#define DEBUG 1
+#define pr_fmt(fmt) "cpufreq: " fmt
+#include <linux/clk.h>
+#include <linux/cpufreq.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/suspend.h>
+#include <linux/tick.h>
+#include <linux/workqueue.h>
+#include <asm/smp_plat.h>
+#include <asm/cpu.h>
+#include <mach/dvfs.h>
+#include <linux/delay.h>
+#include <linux/regulator/consumer.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/earlysuspend.h>
+#include <asm/unistd.h>
+#include <asm/uaccess.h>
+#ifdef DEBUG
+#define FREQ_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args)
+#define FREQ_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args)
+#else
+#define FREQ_PRINTK_DBG(fmt, args...) do {} while(0)
+#define FREQ_PRINTK_LOG(fmt, args...) do {} while(0)
+#endif
+#define FREQ_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args)
+
+/* Frequency table index must be sequential starting at 0 */
+static struct cpufreq_frequency_table default_freq_table[] = {
+       {.frequency = 816 * 1000, .index = 1100 * 1000},
+       {.frequency = CPUFREQ_TABLE_END},
+};
+
+static struct cpufreq_frequency_table *freq_table = default_freq_table;
+static unsigned int max_freq = -1;
+
+/*********************************************************/
+
+/* additional symantics for "relation" in cpufreq with pm */
+#define DISABLE_FURTHER_CPUFREQ         0x10
+#define ENABLE_FURTHER_CPUFREQ          0x20
+#define MASK_FURTHER_CPUFREQ            0x30
+/* With 0x00(NOCHANGE), it depends on the previous "further" status */
+static int no_cpufreq_access;
+static unsigned int suspend_freq = 816 * 1000;
+
+static struct workqueue_struct *freq_wq;
+static struct clk *cpu_clk;
+static struct clk *cpu_pll;
+static struct clk *cpu_gpll;
+
+
+static DEFINE_MUTEX(cpufreq_mutex);
+
+static struct clk *gpu_clk;
+#define GPU_MAX_RATE 350*1000*1000
+
+static int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate);
+
+/*******************************************************/
+static unsigned int rk30_getspeed(unsigned int cpu)
+{
+       unsigned long rate;
+
+       if (cpu >= NR_CPUS)
+               return 0;
+
+       rate = clk_get_rate(cpu_clk) / 1000;
+       return rate;
+}
+
+static bool rk30_cpufreq_is_ondemand_policy(struct cpufreq_policy *policy)
+{
+       char c = 0;
+       if (policy && policy->governor)
+               c = policy->governor->name[0];
+       return (c == 'o' || c == 'i' || c == 'c' || c == 'h');
+}
+
+/**********************thermal limit**************************/
+#define CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP
+
+#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP
+static void rk30_cpufreq_temp_limit_work_func(struct work_struct *work);
+
+static DECLARE_DELAYED_WORK(rk30_cpufreq_temp_limit_work, rk30_cpufreq_temp_limit_work_func);
+
+static unsigned int temp_limt_freq = -1;
+module_param(temp_limt_freq, uint, 0444);
+
+#define TEMP_LIMIT_FREQ 816000
+
+static const struct cpufreq_frequency_table temp_limits[] = {
+       {.frequency = 1416 * 1000, .index = 50},
+       {.frequency = 1200 * 1000, .index = 55},
+       {.frequency = 1008 * 1000, .index = 60},
+       {.frequency =  816 * 1000, .index = 75},
+};
+
+//extern int rk30_tsadc_get_temp(unsigned int chn);
+
+//#define get_cpu_thermal() rk30_tsadc_get_temp(0)
+static void rk30_cpufreq_temp_limit_work_func(struct work_struct *work)
+{
+       struct cpufreq_policy *policy;
+       int temp = 25, i;
+       unsigned int new = -1;
+
+       if (clk_get_rate(gpu_clk) > GPU_MAX_RATE)
+               goto out;
+
+       //temp = max(rk30_tsadc_get_temp(0), rk30_tsadc_get_temp(1));
+       FREQ_PRINTK_LOG("cpu_thermal(%d)\n", temp);
+
+       for (i = 0; i < ARRAY_SIZE(temp_limits); i++) {
+               if (temp > temp_limits[i].index) {
+                       new = temp_limits[i].frequency;
+               }
+       }
+       if (temp_limt_freq != new) {
+               temp_limt_freq = new;
+               if (new != -1) {
+                       FREQ_PRINTK_DBG("temp_limit set rate %d kHz\n", temp_limt_freq);
+                       policy = cpufreq_cpu_get(0);
+                       cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L);
+                       cpufreq_cpu_put(policy);
+               }
+       }
+
+out:
+       queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, HZ);
+}
+
+static int rk30_cpufreq_notifier_policy(struct notifier_block *nb,
+                                       unsigned long val, void *data)
+{
+       struct cpufreq_policy *policy = data;
+
+       if (val != CPUFREQ_NOTIFY)
+               return 0;
+
+       if (rk30_cpufreq_is_ondemand_policy(policy)) {
+               FREQ_PRINTK_DBG("queue work\n");
+               queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, 0);
+       } else {
+               FREQ_PRINTK_DBG("cancel work\n");
+               cancel_delayed_work_sync(&rk30_cpufreq_temp_limit_work);
+       }
+
+       return 0;
+}
+
+static struct notifier_block notifier_policy_block = {
+       .notifier_call = rk30_cpufreq_notifier_policy
+};
+#endif
+
+/************************************dvfs tst************************************/
+//#define CPU_FREQ_DVFS_TST
+#ifdef CPU_FREQ_DVFS_TST
+static unsigned int freq_dvfs_tst_rate;
+static void rk30_cpufreq_dvsf_tst_work_func(struct work_struct *work);
+static DECLARE_DELAYED_WORK(rk30_cpufreq_dvsf_tst_work, rk30_cpufreq_dvsf_tst_work_func);
+static int test_count;
+#define TEST_FRE_NUM 11
+static int test_tlb_rate[TEST_FRE_NUM] = { 504, 1008, 504, 1200, 252, 816, 1416, 252, 1512, 252, 816 };
+//static int test_tlb_rate[TEST_FRE_NUM]={504,1008,504,1200,252,816,1416,126,1512,126,816};
+
+#define TEST_GPU_NUM 3
+
+static int test_tlb_gpu[TEST_GPU_NUM] = { 360, 400, 180 };
+static int test_tlb_ddr[TEST_GPU_NUM] = { 401, 200, 500 };
+
+static int gpu_ddr = 0;
+
+static void rk30_cpufreq_dvsf_tst_work_func(struct work_struct *work)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+
+       gpu_ddr++;
+
+#if 0
+       FREQ_PRINTK_LOG("cpufreq_dvsf_tst,ddr%u,gpu%u\n",
+                       test_tlb_ddr[gpu_ddr % TEST_GPU_NUM],
+                       test_tlb_gpu[gpu_ddr % TEST_GPU_NUM]);
+       clk_set_rate(ddr_clk, test_tlb_ddr[gpu_ddr % TEST_GPU_NUM] * 1000 * 1000);
+       clk_set_rate(gpu_clk, test_tlb_gpu[gpu_ddr % TEST_GPU_NUM] * 1000 * 1000);
+#endif
+
+       test_count++;
+       freq_dvfs_tst_rate = test_tlb_rate[test_count % TEST_FRE_NUM] * 1000;
+       FREQ_PRINTK_LOG("cpufreq_dvsf_tst,cpu set rate %d\n", freq_dvfs_tst_rate);
+       cpufreq_driver_target(policy, policy->cur, CPUFREQ_RELATION_L);
+       cpufreq_cpu_put(policy);
+
+       queue_delayed_work(freq_wq, &rk30_cpufreq_dvsf_tst_work, msecs_to_jiffies(1000));
+}
+#endif /* CPU_FREQ_DVFS_TST */
+
+/***********************************************************************/
+static int rk30_verify_speed(struct cpufreq_policy *policy)
+{
+       if (!freq_table)
+               return -EINVAL;
+       return cpufreq_frequency_table_verify(policy, freq_table);
+}
+
+static int rk30_cpu_init(struct cpufreq_policy *policy)
+{
+       if (policy->cpu == 0) {
+               int i;
+               struct clk *ddr_clk;
+               gpu_clk = clk_get(NULL, "gpu");
+               if (!IS_ERR(gpu_clk))
+                       clk_enable_dvfs(gpu_clk);
+#if 0  
+
+               ddr_clk = clk_get(NULL, "ddr");
+               if (!IS_ERR(ddr_clk))
+               {
+                       clk_enable_dvfs(ddr_clk);
+                       clk_set_rate(ddr_clk,clk_get_rate(ddr_clk)-1);
+               }
+               
+#endif
+               cpu_clk = clk_get(NULL, "cpu");
+               cpu_pll = clk_get(NULL, "arm_pll");
+               
+               cpu_gpll = clk_get(NULL, "arm_gpll");
+               if (IS_ERR(cpu_clk))
+                       return PTR_ERR(cpu_clk);
+               
+               dvfs_clk_register_set_rate_callback(cpu_clk, cpufreq_scale_rate_for_dvfs);
+               freq_table = dvfs_get_freq_volt_table(cpu_clk);
+               if (freq_table == NULL) {
+                       freq_table = default_freq_table;
+               }
+               max_freq = freq_table[0].frequency;
+               for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
+                       max_freq = max(max_freq, freq_table[i].frequency);
+               }
+               clk_enable_dvfs(cpu_clk);
+
+               /* Limit gpu frequency between 133M to 400M */
+#if 0
+               dvfs_clk_enable_limit(gpu_clk, 133000000, 400000000);
+#endif
+
+               freq_wq = create_singlethread_workqueue("rk30_cpufreqd");
+#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP
+               if (rk30_cpufreq_is_ondemand_policy(policy)) {
+                       queue_delayed_work(freq_wq, &rk30_cpufreq_temp_limit_work, 0*HZ);
+               }
+               cpufreq_register_notifier(&notifier_policy_block, CPUFREQ_POLICY_NOTIFIER);
+#endif
+#ifdef CPU_FREQ_DVFS_TST
+               queue_delayed_work(freq_wq, &rk30_cpufreq_dvsf_tst_work, msecs_to_jiffies(20 * 1000));
+#endif
+       }
+       //set freq min max
+       cpufreq_frequency_table_cpuinfo(policy, freq_table);
+       //sys nod
+       cpufreq_frequency_table_get_attr(freq_table, policy->cpu);
+
+       policy->cur = rk30_getspeed(0);
+
+       policy->cpuinfo.transition_latency = 40 * NSEC_PER_USEC;        // make ondemand default sampling_rate to 40000
+
+       /*
+        * On rk30 SMP configuartion, both processors share the voltage
+        * and clock. So both CPUs needs to be scaled together and hence
+        * needs software co-ordination. Use cpufreq affected_cpus
+        * interface to handle this scenario. Additional is_smp() check
+        * is to keep SMP_ON_UP build working.
+        */
+       if (is_smp())
+               cpumask_setall(policy->cpus);
+
+       return 0;
+}
+
+static int rk30_cpu_exit(struct cpufreq_policy *policy)
+{
+       if (policy->cpu != 0)
+               return 0;
+
+       cpufreq_frequency_table_cpuinfo(policy, freq_table);
+       clk_put(cpu_clk);
+#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP
+       cpufreq_unregister_notifier(&notifier_policy_block, CPUFREQ_POLICY_NOTIFIER);
+       if (freq_wq)
+               cancel_delayed_work(&rk30_cpufreq_temp_limit_work);
+#endif
+       if (freq_wq) {
+               flush_workqueue(freq_wq);
+               destroy_workqueue(freq_wq);
+               freq_wq = NULL;
+       }
+
+       return 0;
+}
+
+static struct freq_attr *rk30_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
+/**************************earlysuspend freeze cpu frequency******************************/
+static struct early_suspend ff_early_suspend;
+
+#define FILE_GOV_MODE "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
+#define FILE_SETSPEED "/sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed"
+#define FILE_CUR_FREQ "/sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq"
+
+#define FF_DEBUG(fmt, args...) printk(KERN_DEBUG "FREEZE FREQ DEBUG:\t"fmt, ##args)
+#define FF_ERROR(fmt, args...) printk(KERN_ERR "FREEZE FREQ ERROR:\t"fmt, ##args)
+
+static int ff_read(char *file_path, char *buf)
+{
+       struct file *file = NULL;
+       mm_segment_t old_fs;
+       loff_t offset = 0;
+
+       FF_DEBUG("read %s\n", file_path);
+       file = filp_open(file_path, O_RDONLY, 0);
+
+       if (IS_ERR(file)) {
+               FF_ERROR("%s error open file  %s\n", __func__, file_path);
+               return -1;
+       }
+
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+
+       file->f_op->read(file, (char *)buf, 32, &offset);
+       sscanf(buf, "%s", buf);
+
+       set_fs(old_fs);
+       filp_close(file, NULL);  
+
+       file = NULL;
+
+       return 0;
+
+}
+
+static int ff_write(char *file_path, char *buf)
+{
+       struct file *file = NULL;
+       mm_segment_t old_fs;
+       loff_t offset = 0;
+
+       FF_DEBUG("write %s %s size = %d\n", file_path, buf, strlen(buf));
+       file = filp_open(file_path, O_RDWR, 0);
+
+       if (IS_ERR(file)) {
+               FF_ERROR("%s error open file  %s\n", __func__, file_path);
+               return -1;
+       }
+
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+
+       file->f_op->write(file, (char *)buf, strlen(buf), &offset);
+
+       set_fs(old_fs);
+       filp_close(file, NULL);  
+
+       file = NULL;
+
+       return 0;
+
+}
+
+static void ff_scale_votlage(char *name, int volt)
+{
+       struct regulator* regulator;
+       int ret = 0;
+
+       FF_DEBUG("enter %s\n", __func__);
+       regulator = dvfs_get_regulator(name);
+       if (!regulator) {
+               FF_ERROR("get regulator %s ERROR\n", name);
+               return ;
+       }
+
+       ret = regulator_set_voltage(regulator, volt, volt);
+       if (ret != 0) {
+               FF_ERROR("set voltage error %s %d, ret = %d\n", name, volt, ret);
+       }
+
+}
+int clk_set_parent_force(struct clk *clk, struct clk *parent);
+static void ff_early_suspend_func(struct early_suspend *h)
+{
+       char buf[32];
+       FF_DEBUG("enter %s\n", __func__);
+       if (ff_read(FILE_GOV_MODE, buf) != 0) {
+               FF_ERROR("read current governor error\n");
+               return ;
+       } else {
+               FF_DEBUG("current governor = %s\n", buf);
+       }
+
+       strcpy(buf, "userspace");
+       if (ff_write(FILE_GOV_MODE, buf) != 0) {
+               FF_ERROR("set current governor error\n");
+               return ;
+       }
+
+       strcpy(buf, "252000");
+       if (ff_write(FILE_SETSPEED, buf) != 0) {
+               FF_ERROR("set speed to 252MHz error\n");
+               return ;
+       }
+       
+       if (!IS_ERR(cpu_pll)&&!IS_ERR(cpu_gpll)&&!IS_ERR(cpu_clk))
+       {
+               clk_set_parent_force(cpu_clk,cpu_gpll);
+               clk_set_rate(cpu_clk,300*1000*1000);
+               
+               clk_disable_dvfs(cpu_clk);
+       }       
+       if (!IS_ERR(gpu_clk))
+               dvfs_clk_enable_limit(gpu_clk,75*1000*1000,133*1000*1000);
+       
+       //ff_scale_votlage("vdd_cpu", 1000000);
+       //ff_scale_votlage("vdd_core", 1000000);
+#ifdef CONFIG_HOTPLUG_CPU
+       cpu_down(1);
+#endif
+}
+
+static void ff_early_resume_func(struct early_suspend *h)
+{
+       char buf[32];
+       FF_DEBUG("enter %s\n", __func__);
+
+       if (!IS_ERR(cpu_pll)&&!IS_ERR(cpu_gpll)&&!IS_ERR(cpu_clk))
+       {
+               clk_set_parent_force(cpu_clk,cpu_pll);
+               clk_set_rate(cpu_clk,300*1000*1000);
+               clk_enable_dvfs(cpu_clk);
+       }       
+       
+       if (!IS_ERR(gpu_clk))
+               dvfs_clk_disable_limit(gpu_clk);
+#ifdef CONFIG_HOTPLUG_CPU
+       cpu_up(1);
+#endif
+       if (ff_read(FILE_GOV_MODE, buf) != 0) {
+               FF_ERROR("read current governor error\n");
+               return ;
+       } else {
+               FF_DEBUG("current governor = %s\n", buf);
+       }
+
+       if (ff_read(FILE_CUR_FREQ, buf) != 0) {
+               FF_ERROR("read current frequency error\n");
+               return ;
+       } else {
+               FF_DEBUG("current frequency = %s\n", buf);
+       }
+
+       strcpy(buf, "interactive");
+       if (ff_write(FILE_GOV_MODE, buf) != 0) {
+               FF_ERROR("set current governor error\n");
+               return ;
+       }
+       
+       strcpy(buf, "interactive");
+       if (ff_write(FILE_GOV_MODE, buf) != 0) {
+               FF_ERROR("set current governor error\n");
+               return ;
+       }
+}
+
+static int __init ff_init(void)
+{
+       FF_DEBUG("enter %s\n", __func__);
+       ff_early_suspend.suspend = ff_early_suspend_func;
+       ff_early_suspend.resume = ff_early_resume_func;
+       ff_early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB + 100;
+       register_early_suspend(&ff_early_suspend);
+       return 0;
+}
+
+static void __exit ff_exit(void)
+{
+       FF_DEBUG("enter %s\n", __func__);
+       unregister_early_suspend(&ff_early_suspend);
+}
+
+
+/**************************target freq******************************/
+static unsigned int cpufreq_scale_limt(unsigned int target_freq, struct cpufreq_policy *policy)
+{
+       bool is_ondemand = rk30_cpufreq_is_ondemand_policy(policy);
+       static bool is_booting = true;
+
+       if (is_ondemand && clk_get_rate(gpu_clk) > GPU_MAX_RATE) // high performance?
+               return max_freq;
+       if (is_ondemand && is_booting && target_freq >= 1600 * 1000) {
+               s64 boottime_ms = ktime_to_ms(ktime_get_boottime());
+               if (boottime_ms > 30 * MSEC_PER_SEC) {
+                       is_booting = false;
+               } else {
+                       target_freq = 1416 * 1000;
+               }
+       }
+#ifdef CONFIG_RK30_CPU_FREQ_LIMIT_BY_TEMP
+       if (is_ondemand && target_freq > policy->cur && policy->cur >= TEMP_LIMIT_FREQ) {
+               unsigned int i;
+               if (cpufreq_frequency_table_target(policy, freq_table, policy->cur + 1, CPUFREQ_RELATION_L, &i) == 0) {
+                       unsigned int f = freq_table[i].frequency;
+                       if (f < target_freq) {
+                               target_freq = f;
+                       }
+               }
+       }
+       /*
+        * If the new frequency is more than the thermal max allowed
+        * frequency, go ahead and scale the mpu device to proper frequency.
+        */
+       if (is_ondemand) {
+               target_freq = min(target_freq, temp_limt_freq);
+       }
+#endif
+#ifdef CPU_FREQ_DVFS_TST
+       if (freq_dvfs_tst_rate) {
+               target_freq = freq_dvfs_tst_rate;
+               freq_dvfs_tst_rate = 0;
+       }
+#endif
+       return target_freq;
+}
+
+int cpufreq_scale_rate_for_dvfs(struct clk *clk, unsigned long rate, dvfs_set_rate_callback set_rate)
+{
+       unsigned int i;
+       int ret = -EINVAL;
+       struct cpufreq_freqs freqs;
+
+       freqs.new = rate / 1000;
+       freqs.old = rk30_getspeed(0);
+
+       for_each_online_cpu(freqs.cpu) {
+               cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+       }
+       FREQ_PRINTK_DBG("cpufreq_scale_rate_for_dvfs(%lu)\n", rate);
+       ret = set_rate(clk, rate);
+
+#ifdef CONFIG_SMP
+       /*
+        * Note that loops_per_jiffy is not updated on SMP systems in
+        * cpufreq driver. So, update the per-CPU loops_per_jiffy value
+        * on frequency transition. We need to update all dependent CPUs.
+        */
+       for_each_possible_cpu(i) {
+               per_cpu(cpu_data, i).loops_per_jiffy = loops_per_jiffy;
+       }
+#endif
+
+       freqs.new = rk30_getspeed(0);
+       /* notifiers */
+       for_each_online_cpu(freqs.cpu) {
+               cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+       }
+       return ret;
+
+}
+
+static int rk30_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation)
+{
+       unsigned int i, new_rate = 0;
+       int ret = 0;
+
+       if (!freq_table) {
+               FREQ_PRINTK_ERR("no freq table!\n");
+               return -EINVAL;
+       }
+
+       mutex_lock(&cpufreq_mutex);
+
+       if (relation & ENABLE_FURTHER_CPUFREQ)
+               no_cpufreq_access--;
+       if (no_cpufreq_access) {
+#ifdef CONFIG_PM_VERBOSE
+               pr_err("denied access to %s as it is disabled temporarily\n", __func__);
+#endif
+               ret = -EINVAL;
+               goto out;
+       }
+       if (relation & DISABLE_FURTHER_CPUFREQ)
+               no_cpufreq_access++;
+       relation &= ~MASK_FURTHER_CPUFREQ;
+
+       ret = cpufreq_frequency_table_target(policy, freq_table, target_freq, relation, &i);
+       if (ret) {
+               FREQ_PRINTK_ERR("no freq match for %d(ret=%d)\n", target_freq, ret);
+               goto out;
+       }
+       new_rate = freq_table[i].frequency;
+       if (!no_cpufreq_access)
+               new_rate = cpufreq_scale_limt(new_rate, policy);
+
+       FREQ_PRINTK_LOG("cpufreq req=%u,new=%u(was=%u)\n", target_freq, new_rate, rk30_getspeed(0));
+       if (new_rate == rk30_getspeed(0))
+               goto out;
+       ret = clk_set_rate(cpu_clk, new_rate * 1000);
+out:
+       mutex_unlock(&cpufreq_mutex);
+       FREQ_PRINTK_DBG("cpureq set rate (%u) end\n", new_rate);
+       return ret;
+}
+
+static int rk30_cpufreq_pm_notifier_event(struct notifier_block *this,
+                                         unsigned long event, void *ptr)
+{
+       int ret = NOTIFY_DONE;
+       struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+
+       if (!policy)
+               return ret;
+
+       if (!rk30_cpufreq_is_ondemand_policy(policy))
+               goto out;
+
+       switch (event) {
+       case PM_SUSPEND_PREPARE:
+               ret = cpufreq_driver_target(policy, suspend_freq, DISABLE_FURTHER_CPUFREQ | CPUFREQ_RELATION_H);
+               if (ret < 0) {
+                       ret = NOTIFY_BAD;
+                       goto out;
+               }
+               ret = NOTIFY_OK;
+               break;
+       case PM_POST_RESTORE:
+       case PM_POST_SUSPEND:
+               cpufreq_driver_target(policy, suspend_freq, ENABLE_FURTHER_CPUFREQ | CPUFREQ_RELATION_H);
+               ret = NOTIFY_OK;
+               break;
+       }
+out:
+       cpufreq_cpu_put(policy);
+       return ret;
+}
+
+static struct notifier_block rk30_cpufreq_pm_notifier = {
+       .notifier_call = rk30_cpufreq_pm_notifier_event,
+};
+
+static int rk30_cpufreq_reboot_notifier_event(struct notifier_block *this,
+                                             unsigned long event, void *ptr)
+{
+       struct cpufreq_policy *policy = cpufreq_cpu_get(0);
+
+       if (policy) {
+               cpufreq_driver_target(policy, suspend_freq, DISABLE_FURTHER_CPUFREQ | CPUFREQ_RELATION_H);
+               cpufreq_cpu_put(policy);
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block rk30_cpufreq_reboot_notifier = {
+       .notifier_call = rk30_cpufreq_reboot_notifier_event,
+};
+
+static struct cpufreq_driver rk30_cpufreq_driver = {
+       .flags = CPUFREQ_CONST_LOOPS,
+       .verify = rk30_verify_speed,
+       .target = rk30_target,
+       .get = rk30_getspeed,
+       .init = rk30_cpu_init,
+       .exit = rk30_cpu_exit,
+       .name = "rk30",
+       .attr = rk30_cpufreq_attr,
+};
+
+static int __init rk30_cpufreq_init(void)
+{
+       register_pm_notifier(&rk30_cpufreq_pm_notifier);
+       register_reboot_notifier(&rk30_cpufreq_reboot_notifier);
+       return cpufreq_register_driver(&rk30_cpufreq_driver);
+}
+
+static void __exit rk30_cpufreq_exit(void)
+{
+       cpufreq_unregister_driver(&rk30_cpufreq_driver);
+}
+
+MODULE_DESCRIPTION("cpufreq driver for rock chip rk30");
+MODULE_LICENSE("GPL");
+device_initcall(rk30_cpufreq_init);
+module_exit(rk30_cpufreq_exit);
diff --git a/arch/arm/mach-rk2928/dvfs.c b/arch/arm/mach-rk2928/dvfs.c
new file mode 100644 (file)
index 0000000..5e11119
--- /dev/null
@@ -0,0 +1,1923 @@
+/* arch/arm/mach-rk30/rk30_dvfs.c\r
+ *\r
+ * Copyright (C) 2012 ROCKCHIP, Inc.\r
+ *\r
+ * This software is licensed under the terms of the GNU General Public\r
+ * License version 2, as published by the Free Software Foundation, and\r
+ * may be copied, distributed, and modified under those terms.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ */\r
+\r
+#include <linux/kernel.h>\r
+#include <linux/err.h>\r
+#include <linux/spinlock.h>\r
+#include <linux/list.h>\r
+#include <linux/slab.h>\r
+#include <linux/clk.h>\r
+#include <linux/cpufreq.h>\r
+#include "clock.h"\r
+#include <mach/dvfs.h>\r
+#include <mach/clock.h>\r
+#include <linux/regulator/consumer.h>\r
+#include <linux/delay.h>\r
+#include <linux/io.h>\r
+#include <linux/hrtimer.h>\r
+\r
+#if 1\r
+#define DVFS_DBG(fmt, args...) {while(0);}\r
+#else\r
+#define DVFS_DBG(fmt, args...) printk(KERN_DEBUG "DVFS DBG:\t"fmt, ##args)\r
+#endif\r
+#define DVFS_ERR(fmt, args...) printk(KERN_ERR "DVFS ERR:\t"fmt, ##args)\r
+#define DVFS_LOG(fmt, args...) printk(KERN_DEBUG "DVFS LOG:\t"fmt, ##args)\r
+\r
+#define dvfs_regulator_get(dev,id) regulator_get((dev),(id))\r
+#define dvfs_regulator_put(regu) regulator_put((regu))\r
+#define dvfs_regulator_set_voltage(regu,min_uV,max_uV) regulator_set_voltage((regu),(min_uV),(max_uV))\r
+#define dvfs_regulator_get_voltage(regu) regulator_get_voltage((regu))\r
+\r
+#define dvfs_clk_get(a,b) clk_get((a),(b))\r
+#define dvfs_clk_get_rate_kz(a) (clk_get_rate((a))/1000)\r
+#define dvfs_clk_set_rate(a,b) clk_set_rate((a),(b))\r
+#define dvfs_clk_enable(a) clk_enable((a))\r
+#define dvfs_clk_disable(a) clk_disable((a))\r
+\r
+#define DVFS_MHZ (1000*1000)\r
+#define DVFS_KHZ (1000)\r
+\r
+#define DVFS_V (1000*1000)\r
+#define DVFS_MV (1000)\r
+\r
+static LIST_HEAD(rk_dvfs_tree);\r
+static DEFINE_MUTEX(mutex);\r
+static DEFINE_MUTEX(rk_dvfs_mutex);\r
+\r
+extern int rk30_clk_notifier_register(struct clk *clk, struct notifier_block *nb);\r
+extern int rk30_clk_notifier_unregister(struct clk *clk, struct notifier_block *nb);\r
+\r
+static int dump_dbg_map(char* buf);\r
+\r
+#define PD_ON  1\r
+#define PD_OFF 0\r
+\r
+#define get_volt_up_delay(new_volt, old_volt)  \\r
+       ((new_volt) > (old_volt) ? (((new_volt) - (old_volt)) >> 9) : 0)\r
+\r
+int dvfs_regulator_set_voltage_readback(struct regulator *regulator, int min_uV, int max_uV)\r
+{\r
+       int ret = 0, read_back = 0;\r
+       ret = dvfs_regulator_set_voltage(regulator, max_uV, max_uV);\r
+       if (ret < 0) {\r
+               DVFS_ERR("%s now read back to check voltage\n", __func__);\r
+\r
+               /* read back to judge if it is already effect */\r
+               mdelay(2);\r
+               read_back = dvfs_regulator_get_voltage(regulator); \r
+               if (read_back == max_uV) {\r
+                       DVFS_ERR("%s set ERROR but already effected, volt=%d\n", __func__, read_back);\r
+                       ret = 0;\r
+               } else {\r
+                       DVFS_ERR("%s set ERROR AND NOT effected, volt=%d\n", __func__, read_back);\r
+               }\r
+       }\r
+       return ret;\r
+}\r
+\r
+struct regulator* dvfs_get_regulator(char *regulator_name)\r
+{\r
+       struct vd_node *vd;\r
+       list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+               if (strcmp(regulator_name, vd->regulator_name) == 0) {\r
+                       return vd->regulator;\r
+               }\r
+       }\r
+       return NULL;\r
+}\r
+\r
+int dvfs_clk_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate)\r
+{\r
+       struct clk_node* dvfs_clk;\r
+       dvfs_clk = clk->dvfs_info;\r
+\r
+       dvfs_clk->freq_limit_en = 1;\r
+       dvfs_clk->min_rate = min_rate;\r
+       dvfs_clk->max_rate = max_rate;\r
+       \r
+       return 0;\r
+}\r
+\r
+int dvfs_clk_disable_limit(struct clk *clk)\r
+{\r
+       struct clk_node* dvfs_clk;\r
+       dvfs_clk = clk->dvfs_info;\r
+       \r
+       dvfs_clk->freq_limit_en = 0;\r
+       \r
+       return 0;\r
+}\r
+\r
+int is_support_dvfs(struct clk_node *dvfs_info)\r
+{\r
+       return (dvfs_info->vd && dvfs_info->vd->vd_dvfs_target && dvfs_info->enable_dvfs);\r
+}\r
+\r
+int dvfs_set_rate(struct clk *clk, unsigned long rate)\r
+{\r
+       int ret = 0;\r
+       struct vd_node *vd;\r
+       DVFS_DBG("%s(%s(%lu))\n", __func__, clk->name, rate);\r
+       if (!clk->dvfs_info) {\r
+               DVFS_ERR("%s :This clk do not support dvfs!\n", __func__);\r
+               ret = -1;\r
+       } else {\r
+               vd = clk->dvfs_info->vd;\r
+               // mutex_lock(&vd->dvfs_mutex);\r
+               mutex_lock(&rk_dvfs_mutex);\r
+               ret = vd->vd_dvfs_target(clk, rate);\r
+               mutex_unlock(&rk_dvfs_mutex);\r
+               // mutex_unlock(&vd->dvfs_mutex);\r
+       }\r
+       DVFS_DBG("%s(%s(%lu)),is end\n", __func__, clk->name, rate);\r
+       return ret;\r
+}\r
+\r
+static int dvfs_clk_get_ref_volt_depend(struct depend_list *depend, int rate_khz,\r
+               struct cpufreq_frequency_table *clk_fv)\r
+{\r
+       int i = 0;\r
+       if (rate_khz == 0 || !depend || !depend->dep_table) {\r
+               return -1;\r
+       }\r
+       clk_fv->frequency = rate_khz;\r
+       clk_fv->index = 0;\r
+\r
+       for (i = 0; (depend->dep_table[i].frequency != CPUFREQ_TABLE_END); i++) {\r
+               if (depend->dep_table[i].frequency >= rate_khz) {\r
+                       clk_fv->frequency = depend->dep_table[i].frequency;\r
+                       clk_fv->index = depend->dep_table[i].index;\r
+                       return 0;\r
+               }\r
+       }\r
+       clk_fv->frequency = 0;\r
+       clk_fv->index = 0;\r
+       return -1;\r
+}\r
+static int dvfs_clk_get_ref_volt(struct clk_node *dvfs_clk, int rate_khz,\r
+               struct cpufreq_frequency_table *clk_fv)\r
+{\r
+       int i = 0;\r
+       if (rate_khz == 0 || !dvfs_clk || !dvfs_clk->dvfs_table) {\r
+               /* since no need */\r
+               return -1;\r
+       }\r
+       clk_fv->frequency = rate_khz;\r
+       clk_fv->index = 0;\r
+\r
+       for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {\r
+               if (dvfs_clk->dvfs_table[i].frequency >= rate_khz) {\r
+                       clk_fv->frequency = dvfs_clk->dvfs_table[i].frequency;\r
+                       clk_fv->index = dvfs_clk->dvfs_table[i].index;\r
+                       // DVFS_DBG("%s,%s rate=%ukhz(vol=%d)\n",__func__,dvfs_clk->name, \r
+                       // clk_fv->frequency, clk_fv->index);\r
+                       return 0;\r
+               }\r
+       }\r
+       clk_fv->frequency = 0;\r
+       clk_fv->index = 0;\r
+       // DVFS_DBG("%s get corresponding voltage error! out of bound\n", dvfs_clk->name);\r
+       return -1;\r
+}\r
+\r
+static int dvfs_pd_get_newvolt_byclk(struct pd_node *pd, struct clk_node *dvfs_clk)\r
+{\r
+       struct clk_list *child;\r
+       int volt_max = 0;\r
+\r
+       if (!pd || !dvfs_clk)\r
+               return 0;\r
+\r
+       if (dvfs_clk->set_volt >= pd->cur_volt) {\r
+               return dvfs_clk->set_volt;\r
+       }\r
+\r
+       list_for_each_entry(child, &pd->clk_list, node) {\r
+               // DVFS_DBG("%s ,pd(%s),dvfs(%s),volt(%u)\n",__func__,pd->name,\r
+               // dvfs_clk->name,dvfs_clk->set_volt);\r
+               volt_max = max(volt_max, child->dvfs_clk->set_volt);\r
+       }\r
+       return volt_max;\r
+}\r
+\r
+void dvfs_update_clk_pds_volt(struct clk_node *dvfs_clk)\r
+{\r
+       struct pd_node   *pd;\r
+       int i;\r
+       if (!dvfs_clk)\r
+               return;\r
+       for (i = 0; (dvfs_clk->pds[i].pd != NULL); i++) {\r
+               pd = dvfs_clk->pds[i].pd;\r
+               // DVFS_DBG("%s dvfs(%s),pd(%s)\n",__func__,dvfs_clk->name,pd->name);\r
+               pd->cur_volt = dvfs_pd_get_newvolt_byclk(pd, dvfs_clk);\r
+       }\r
+}\r
+\r
+static int dvfs_vd_get_newvolt_bypd(struct vd_node *vd)\r
+{\r
+       struct pd_node          *pd;\r
+       struct depend_list      *depend;\r
+       int     volt_max_vd = 0;\r
+       list_for_each_entry(pd, &vd->pd_list, node) {\r
+               // DVFS_DBG("%s pd(%s,%u)\n",__func__,pd->name,pd->cur_volt);\r
+               volt_max_vd = max(volt_max_vd, pd->cur_volt);\r
+       }\r
+\r
+       /* some clks depend on this voltage domain */\r
+       if (!list_empty(&vd->req_volt_list)) {\r
+               list_for_each_entry(depend, &vd->req_volt_list, node2vd) {\r
+                       volt_max_vd = max(volt_max_vd, depend->req_volt);\r
+               }\r
+       }\r
+       return volt_max_vd;\r
+}\r
+\r
+static int dvfs_vd_get_newvolt_byclk(struct clk_node *dvfs_clk)\r
+{\r
+       if (!dvfs_clk)\r
+               return -1;\r
+       dvfs_update_clk_pds_volt(dvfs_clk);\r
+       return  dvfs_vd_get_newvolt_bypd(dvfs_clk->vd);\r
+}\r
+\r
+void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target)\r
+{\r
+       struct clk_node *dvfs_clk = clk_get_dvfs_info(clk);\r
+       dvfs_clk->clk_dvfs_target = clk_dvfs_target;\r
+}\r
+\r
+struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk) \r
+{\r
+       struct clk_node *info = clk_get_dvfs_info(clk);\r
+       struct cpufreq_frequency_table *table;\r
+       if (!info || !info->dvfs_table) {\r
+               return NULL;\r
+       }\r
+       mutex_lock(&mutex);\r
+       table = info->dvfs_table;\r
+       mutex_unlock(&mutex);\r
+       return table;\r
+}\r
+\r
+int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table)\r
+{\r
+       struct clk_node *info = clk_get_dvfs_info(clk);\r
+       if (!table || !info)\r
+               return -1;\r
+\r
+       mutex_lock(&mutex);\r
+       info->dvfs_table = table;\r
+       mutex_unlock(&mutex);\r
+       return 0;\r
+}\r
+\r
+int dvfs_set_depend_table(struct clk *clk, char *vd_name, struct cpufreq_frequency_table *table)\r
+{\r
+       struct vd_node          *vd;\r
+       struct depend_list      *depend;\r
+       struct clk_node         *info;\r
+\r
+       info = clk_get_dvfs_info(clk);\r
+       if (!table || !info || !vd_name) {\r
+               DVFS_ERR("%s :DVFS SET DEPEND TABLE ERROR! table or info or name empty\n", __func__);\r
+               return -1;\r
+       }\r
+       \r
+       list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+               if (0 == strcmp(vd->name, vd_name)) {\r
+                       DVFS_DBG("FOUND A MATCH\n");\r
+                       mutex_lock(&mutex);\r
+                       list_for_each_entry(depend, &info->depend_list, node2clk) {\r
+                               if (vd == depend->dep_vd && info == depend->dvfs_clk) {\r
+                                       depend->dep_table = table;\r
+                                       break;\r
+                               }\r
+                       }\r
+                       mutex_unlock(&mutex);\r
+                       return 0;\r
+               }\r
+       }\r
+       DVFS_ERR("%s :DVFS SET DEPEND TABLE ERROR! can not find vd:%s\n", __func__, vd_name);\r
+\r
+       return 0;\r
+}\r
+\r
+int dvfs_set_arm_logic_volt(struct dvfs_arm_table *dvfs_cpu_logic_table, \r
+               struct cpufreq_frequency_table *cpu_dvfs_table,\r
+               struct cpufreq_frequency_table *dep_cpu2core_table)\r
+{\r
+       int i = 0;\r
+       for (i = 0; dvfs_cpu_logic_table[i].frequency != CPUFREQ_TABLE_END; i++) {\r
+               cpu_dvfs_table[i].frequency = dvfs_cpu_logic_table[i].frequency;\r
+               cpu_dvfs_table[i].index = dvfs_cpu_logic_table[i].cpu_volt;\r
+\r
+               dep_cpu2core_table[i].frequency = dvfs_cpu_logic_table[i].frequency;\r
+               dep_cpu2core_table[i].index = dvfs_cpu_logic_table[i].logic_volt;\r
+       }\r
+\r
+       cpu_dvfs_table[i].frequency = CPUFREQ_TABLE_END;\r
+       dep_cpu2core_table[i].frequency = CPUFREQ_TABLE_END;\r
+\r
+       dvfs_set_freq_volt_table(clk_get(NULL, "cpu"), cpu_dvfs_table);\r
+       dvfs_set_depend_table(clk_get(NULL, "cpu"), "vd_core", dep_cpu2core_table);\r
+       return 0;\r
+}\r
+\r
+int clk_enable_dvfs(struct clk *clk)\r
+{\r
+       struct clk_node *dvfs_clk;\r
+       struct cpufreq_frequency_table clk_fv;\r
+       if (!clk) {\r
+               DVFS_ERR("clk enable dvfs error\n");\r
+               return -1;\r
+       }\r
+       dvfs_clk = clk_get_dvfs_info(clk);\r
+       if (!dvfs_clk || !dvfs_clk->vd) {\r
+               DVFS_ERR("%s clk(%s) not support dvfs!\n", __func__, clk->name);\r
+               return -1;\r
+       }\r
+       if (dvfs_clk->enable_dvfs == 0) {\r
+\r
+               if (IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {\r
+                       //regulator = NULL;\r
+                       if (dvfs_clk->vd->regulator_name)\r
+                               dvfs_clk->vd->regulator = dvfs_regulator_get(NULL, dvfs_clk->vd->regulator_name);\r
+                       if (!IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {\r
+                               // DVFS_DBG("dvfs_regulator_get(%s)\n",dvfs_clk->vd->regulator_name);\r
+                               dvfs_clk->vd->cur_volt = dvfs_regulator_get_voltage(dvfs_clk->vd->regulator);\r
+                       } else {\r
+                               //dvfs_clk->vd->regulator = NULL;\r
+                               dvfs_clk->enable_dvfs = 0;\r
+                               DVFS_ERR("%s can't get regulator in %s\n", dvfs_clk->name, __func__);\r
+                               return -1;\r
+                       }\r
+               } else {\r
+                       dvfs_clk->vd->cur_volt = dvfs_regulator_get_voltage(dvfs_clk->vd->regulator);\r
+                       // DVFS_DBG("%s(%s) vd volt=%u\n",__func__,dvfs_clk->name,dvfs_clk->vd->cur_volt);\r
+               }\r
+\r
+               dvfs_clk->set_freq = dvfs_clk_get_rate_kz(clk);\r
+               // DVFS_DBG("%s ,%s get freq%u!\n",__func__,dvfs_clk->name,dvfs_clk->set_freq);\r
+               \r
+               if (dvfs_clk_get_ref_volt(dvfs_clk, dvfs_clk->set_freq, &clk_fv)) {\r
+                       if (dvfs_clk->dvfs_table[0].frequency == CPUFREQ_TABLE_END) {\r
+                               DVFS_ERR("%s table empty\n", __func__);\r
+                               dvfs_clk->enable_dvfs = 0;\r
+                               return -1;\r
+                       } else {\r
+                               DVFS_ERR("WARNING: %s table all value are smaller than default, use default, just enable dvfs\n", __func__);\r
+                               dvfs_clk->enable_dvfs++;\r
+                               return 0;\r
+                       }\r
+               }\r
+\r
+               dvfs_clk->set_volt = clk_fv.index;\r
+               // DVFS_DBG("%s,%s,freq%u(ref vol %u)\n",__func__,dvfs_clk->name,\r
+               //       dvfs_clk->set_freq,dvfs_clk->set_volt);\r
+#if 0\r
+               if (dvfs_clk->dvfs_nb) {\r
+                       // must unregister when clk disable\r
+                       rk30_clk_notifier_register(clk, dvfs_clk->dvfs_nb);\r
+               }\r
+#endif\r
+               dvfs_vd_get_newvolt_byclk(dvfs_clk);\r
+               dvfs_clk->enable_dvfs++;\r
+       } else {\r
+               DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs);\r
+               dvfs_clk->enable_dvfs++;\r
+       }\r
+       return 0;\r
+}\r
+\r
+int clk_disable_dvfs(struct clk *clk)\r
+{\r
+       struct clk_node *dvfs_clk;\r
+       dvfs_clk = clk->dvfs_info;\r
+       if (!dvfs_clk->enable_dvfs) {\r
+               DVFS_DBG("clk is already closed!\n");\r
+               return -1;\r
+       } else {\r
+               dvfs_clk->enable_dvfs--;\r
+               if (0 == dvfs_clk->enable_dvfs) {\r
+                       DVFS_ERR("clk closed!\n");\r
+                       rk30_clk_notifier_unregister(clk, dvfs_clk->dvfs_nb);\r
+                       DVFS_DBG("clk unregister nb!\n");\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+static int rk_dvfs_clk_notifier_event(struct notifier_block *this,\r
+               unsigned long event, void *ptr)\r
+{\r
+       struct clk_notifier_data *noti_info;\r
+       struct clk *clk;\r
+       struct clk_node *dvfs_clk;\r
+       noti_info = (struct clk_notifier_data *)ptr;\r
+       clk = noti_info->clk;\r
+       dvfs_clk = clk->dvfs_info;\r
+\r
+       switch (event) {\r
+               case CLK_PRE_RATE_CHANGE:\r
+                       DVFS_DBG("%s CLK_PRE_RATE_CHANGE\n", __func__);\r
+                       break;\r
+               case CLK_POST_RATE_CHANGE:\r
+                       DVFS_DBG("%s CLK_POST_RATE_CHANGE\n", __func__);\r
+                       break;\r
+               case CLK_ABORT_RATE_CHANGE:\r
+                       DVFS_DBG("%s CLK_ABORT_RATE_CHANGE\n", __func__);\r
+                       break;\r
+               case CLK_PRE_ENABLE:\r
+                       DVFS_DBG("%s CLK_PRE_ENABLE\n", __func__);\r
+                       break;\r
+               case CLK_POST_ENABLE:\r
+                       DVFS_DBG("%s CLK_POST_ENABLE\n", __func__);\r
+                       break;\r
+               case CLK_ABORT_ENABLE:\r
+                       DVFS_DBG("%s CLK_ABORT_ENABLE\n", __func__);\r
+                       break;\r
+               case CLK_PRE_DISABLE:\r
+                       DVFS_DBG("%s CLK_PRE_DISABLE\n", __func__);\r
+                       break;\r
+               case CLK_POST_DISABLE:\r
+                       DVFS_DBG("%s CLK_POST_DISABLE\n", __func__);\r
+                       dvfs_clk->set_freq = 0;\r
+                       break;\r
+               case CLK_ABORT_DISABLE:\r
+                       DVFS_DBG("%s CLK_ABORT_DISABLE\n", __func__);\r
+\r
+                       break;\r
+               default:\r
+                       break;\r
+       }\r
+       return 0;\r
+}\r
+\r
+static struct notifier_block rk_dvfs_clk_notifier = {\r
+       .notifier_call = rk_dvfs_clk_notifier_event,\r
+};\r
+\r
+static struct clk_node *dvfs_get_dvfs_clk_byname(char *name)\r
+{\r
+       struct vd_node *vd;\r
+       struct pd_node *pd;\r
+       struct clk_list *child;\r
+       list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+               list_for_each_entry(pd, &vd->pd_list, node) {\r
+                       list_for_each_entry(child, &pd->clk_list, node) {\r
+                               if (0 == strcmp(child->dvfs_clk->name, name)) {\r
+                                       return child->dvfs_clk;\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       return NULL;\r
+}\r
+static int rk_regist_vd(struct vd_node *vd)\r
+{\r
+       if (!vd)\r
+               return -1;\r
+       mutex_lock(&mutex);\r
+       //mutex_init(&vd->dvfs_mutex);\r
+       list_add(&vd->node, &rk_dvfs_tree);\r
+       INIT_LIST_HEAD(&vd->pd_list);\r
+       INIT_LIST_HEAD(&vd->req_volt_list);\r
+\r
+       mutex_unlock(&mutex);\r
+       return 0;\r
+}\r
+\r
+static int rk_regist_pd(struct pd_node_lookup *pd_lookup)\r
+{\r
+       struct vd_node  *vd;\r
+       struct pd_node  *pd;\r
+\r
+       mutex_lock(&mutex);\r
+       pd = pd_lookup->pd;\r
+\r
+       list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+               if (vd == pd->vd) {\r
+                       list_add(&pd->node, &vd->pd_list);\r
+                       INIT_LIST_HEAD(&pd->clk_list);\r
+                       break;\r
+               }\r
+       }\r
+       mutex_unlock(&mutex);\r
+       return 0;\r
+}\r
+\r
+static int rk_regist_clk(struct clk_node *dvfs_clk)\r
+{\r
+       struct pd_node  *pd;\r
+       struct clk_list *child;\r
+       struct clk      *clk;\r
+       int i = 0;\r
+\r
+       if (!dvfs_clk)\r
+               return -1;\r
+\r
+       if (!dvfs_clk->pds)\r
+               return -1;\r
+       mutex_lock(&mutex);\r
+       dvfs_clk->enable_dvfs = 0;\r
+       dvfs_clk->vd = dvfs_clk->pds[0].pd->vd;\r
+       for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {\r
+               child = &(dvfs_clk->pds[i].clk_list);\r
+               child->dvfs_clk = dvfs_clk;\r
+               pd = dvfs_clk->pds[i].pd;\r
+               list_add(&child->node, &pd->clk_list);\r
+       }\r
+       clk = dvfs_clk_get(NULL, dvfs_clk->name);\r
+       dvfs_clk->clk = clk;\r
+       clk_register_dvfs(dvfs_clk, clk);\r
+       INIT_LIST_HEAD(&dvfs_clk->depend_list);\r
+       mutex_unlock(&mutex);\r
+       return 0;\r
+}\r
+\r
+static int rk_regist_depends(struct depend_lookup *dep_node)\r
+{\r
+       struct depend_list      *depend_list;\r
+       struct clk_node         *dvfs_clk;\r
+\r
+       if (!dep_node) {\r
+               DVFS_ERR("%s : DVFS BAD depend node!\n", __func__);\r
+               return -1;\r
+       }\r
+\r
+       if (!dep_node->clk_name || !dep_node->dep_vd) {\r
+               DVFS_ERR("%s : DVFS BAD depend members!\n", __func__);\r
+               return -1;\r
+       }\r
+\r
+       depend_list = &dep_node->dep_list;\r
+       dvfs_clk = dvfs_get_dvfs_clk_byname(dep_node->clk_name);\r
+\r
+       mutex_lock(&mutex);\r
+\r
+       depend_list->dvfs_clk = dvfs_clk;\r
+       depend_list->dep_vd = dep_node->dep_vd;\r
+       depend_list->dep_table = dep_node->dep_table;\r
+\r
+       list_add(&depend_list->node2clk, &dvfs_clk->depend_list);\r
+       list_add(&depend_list->node2vd, &depend_list->dep_vd->req_volt_list);\r
+\r
+       mutex_unlock(&mutex);\r
+       return 0;\r
+}\r
+#if 0\r
+static int dvfs_set_depend_pre(struct clk_node *dvfs_clk, unsigned long rate_old, unsigned long rate_new)\r
+{\r
+       struct depend_list      *depend;\r
+       struct cpufreq_frequency_table  clk_fv;\r
+       int ret = -1;\r
+       int volt = 0;\r
+       struct regulator *regulator;\r
+\r
+       if (rate_old >= rate_new) {\r
+               return 0;\r
+       }\r
+       list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) {\r
+               ret = dvfs_clk_get_ref_volt_depend(depend, rate_new / 1000, &clk_fv);\r
+               if (ret != 0) {\r
+                       DVFS_ERR("%s LOGIC DVFS CAN NOT GET REF VOLT!, frequency too large!\n", __func__);\r
+                       return -1;\r
+               }\r
+\r
+               if (!depend->dep_vd->regulator) {\r
+                       DVFS_DBG("%s regulator empty\n", __func__);\r
+                       regulator = dvfs_regulator_get(NULL, depend->dep_vd->regulator_name);\r
+                       if (!regulator) {\r
+                               DVFS_ERR("%s get regulator err\n", __func__);\r
+                               return -1;\r
+                       }\r
+\r
+                       depend->dep_vd->regulator = regulator;\r
+               }\r
+               if (IS_ERR_OR_NULL(depend->dep_vd->regulator)) {\r
+                       DVFS_ERR("%s vd's(%s) regulator not NULL but error\n", __func__, depend->dep_vd->name);\r
+                       return -1;\r
+               }\r
+\r
+               if (clk_fv.index == dvfs_regulator_get_voltage(depend->dep_vd->regulator)) {\r
+                       depend->req_volt = clk_fv.index;\r
+                       DVFS_DBG("%s same voltage\n", __func__);\r
+                       return 0;\r
+               }\r
+\r
+               depend->req_volt = clk_fv.index;\r
+               volt = dvfs_vd_get_newvolt_bypd(depend->dep_vd);\r
+               DVFS_DBG("%s setting voltage = %d\n", __func__, volt);\r
+               ret = dvfs_regulator_set_voltage_readback(depend->dep_vd->regulator, volt, volt);\r
+               if (0 != ret) {\r
+                       DVFS_ERR("%s set voltage = %d ERROR, ret = %d\n", __func__, volt, ret);\r
+                       return -1;\r
+               }\r
+               udelay(200);\r
+               DVFS_DBG("%s set voltage = %d OK, ret = %d\n", __func__, volt, ret);\r
+               if (ret != 0) {\r
+                       DVFS_ERR("%s err, ret = %d\n", __func__, ret);\r
+                       return -1;\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+static int dvfs_set_depend_post(struct clk_node *dvfs_clk, unsigned long rate_old, unsigned long rate_new)\r
+{\r
+       struct depend_list      *depend;\r
+       struct cpufreq_frequency_table  clk_fv;\r
+       int ret = -1;\r
+       int volt = 0;\r
+       struct regulator *regulator;\r
+\r
+       if (rate_old <= rate_new) \r
+               return 0;\r
+       list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) {\r
+               ret = dvfs_clk_get_ref_volt_depend(depend, rate_new / 1000, &clk_fv);\r
+               if (ret != 0) {\r
+                       DVFS_ERR("%s LOGIC DVFS CAN NOT GET REF VOLT!, frequency too large!\n", __func__);\r
+                       return -1;\r
+               }\r
+\r
+               if (!depend->dep_vd->regulator) {\r
+                       DVFS_DBG("%s regulator empty\n", __func__);\r
+                       regulator = dvfs_regulator_get(NULL, depend->dep_vd->regulator_name);\r
+                       if (!regulator) {\r
+                               DVFS_ERR("%s get regulator err\n", __func__);\r
+                               return -1;\r
+                       }\r
+\r
+                       depend->dep_vd->regulator = regulator;\r
+               }\r
+               if (IS_ERR_OR_NULL(depend->dep_vd->regulator)) {\r
+                       DVFS_ERR("%s vd's(%s) regulator not NULL but error\n", __func__, depend->dep_vd->name);\r
+                       return -1;\r
+               }\r
+\r
+               if (clk_fv.index == dvfs_regulator_get_voltage(depend->dep_vd->regulator)) {\r
+                       depend->req_volt = clk_fv.index;\r
+                       DVFS_DBG("%s same voltage\n", __func__);\r
+                       return 0;\r
+               }\r
+\r
+               depend->req_volt = clk_fv.index;\r
+               volt = dvfs_vd_get_newvolt_bypd(depend->dep_vd);\r
+               DVFS_DBG("%s setting voltage = %d\n", __func__, volt);\r
+               ret = dvfs_regulator_set_voltage_readback(depend->dep_vd->regulator, volt, volt);\r
+               if (0 != ret) {\r
+                       DVFS_ERR("%s set voltage = %d ERROR, ret = %d\n", __func__, volt, ret);\r
+                       return -1;\r
+               }\r
+               udelay(200);\r
+               DVFS_DBG("%s set voltage = %d OK, ret = %d\n", __func__, volt, ret);\r
+               if (ret != 0) {\r
+                       DVFS_ERR("%s err, ret = %d\n", __func__, ret);\r
+                       return -1;\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+#endif\r
+#define DVFS_SET_VOLT_FAILURE  1\r
+#define DVFS_SET_VOLT_SUCCESS  0\r
+#define ARM_HIGHER_LOGIC       (150 * 1000)\r
+#define LOGIC_HIGHER_ARM       (100 * 1000)\r
+\r
+int check_volt_correct(int volt_old, int *volt_new, int volt_dep_old, int *volt_dep_new, \r
+               int clk_biger_than_dep, int dep_biger_than_clk)\r
+{\r
+       int up_boundary = 0, low_boundary = 0;\r
+       DVFS_DBG("%d %d\n", clk_biger_than_dep, dep_biger_than_clk);\r
+       up_boundary = volt_old + dep_biger_than_clk;\r
+       low_boundary = volt_old - clk_biger_than_dep;\r
+       \r
+       if (volt_dep_old < low_boundary || volt_dep_old > up_boundary) {\r
+               DVFS_ERR("%s current volt out of bondary volt=%d(old=%d), volt_dep=%d(dep_old=%d), up_bnd=%d(dn=%d)\n",\r
+                               __func__, *volt_new, volt_old, *volt_dep_new, volt_dep_old, up_boundary, low_boundary);\r
+               return -1;\r
+       }\r
+       \r
+       up_boundary = *volt_new + dep_biger_than_clk;\r
+       low_boundary = *volt_new - clk_biger_than_dep;\r
+       \r
+       if (*volt_dep_new < low_boundary || *volt_dep_new > up_boundary) {\r
+\r
+               if (*volt_dep_new < low_boundary) {\r
+                       *volt_dep_new = low_boundary;\r
+                       \r
+               } else if (*volt_dep_new > up_boundary) {\r
+                       *volt_new = *volt_dep_new - dep_biger_than_clk;\r
+               }\r
+               DVFS_LOG("%s target volt out of bondary volt=%d(old=%d), volt_dep=%d(dep_old=%d), up_bnd=%d(dn=%d)\n",\r
+                               __func__, *volt_new, volt_old, *volt_dep_new, volt_dep_old, up_boundary, low_boundary);         \r
+               return 0;\r
+       }\r
+       return 0;\r
+\r
+}\r
+int dvfs_scale_volt(struct vd_node *vd_clk, struct vd_node *vd_dep, \r
+               int volt_old, int volt_new, int volt_dep_old, int volt_dep_new, int clk_biger_than_dep, int dep_biger_than_clk)\r
+{\r
+       struct regulator *regulator, *regulator_dep;\r
+       int volt = 0, volt_dep = 0, step = 0, step_dep = 0;\r
+       int volt_pre = 0, volt_dep_pre = 0;\r
+       int ret = 0;\r
+\r
+       DVFS_DBG("ENTER %s, volt=%d(old=%d), volt_dep=%d(dep_old=%d)\n", __func__, volt_new, volt_old, volt_dep_new, volt_dep_old);\r
+       regulator = vd_clk->regulator;\r
+       regulator_dep = vd_dep->regulator;\r
+\r
+       if (IS_ERR_OR_NULL(regulator) || IS_ERR(regulator_dep)) {       \r
+               DVFS_ERR("%s dvfs_clk->vd->regulator or depend->dep_vd->regulator == NULL\n", __func__);\r
+               return -1;\r
+       }\r
+\r
+       volt = volt_old;\r
+       volt_dep = volt_dep_old;\r
+\r
+       step = volt_new - volt_old > 0 ? 1 : (-1);\r
+       step_dep = volt_dep_new - volt_dep_old > 0 ? 1 : (-1);\r
+\r
+       DVFS_DBG("step=%d step_dep=%d %d\n", step, step_dep, step * step_dep);\r
+\r
+       DVFS_DBG("Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n",\r
+                       volt_new, volt_old, volt_dep_new, volt_dep_old);\r
+       do {\r
+               volt_pre = volt;\r
+               volt_dep_pre = volt_dep;\r
+               if (step * step_dep < 0) {\r
+                       // target is between volt_old and volt_dep_old, just\r
+                       // need one step\r
+                       DVFS_DBG("step * step_dep < 0\n");\r
+                       volt = volt_new;\r
+                       volt_dep = volt_dep_new;\r
+               \r
+               } else if (step > 0) {\r
+                       // up voltage\r
+                       DVFS_DBG("step > 0\n");\r
+\r
+                       if (volt > volt_dep) {\r
+                               if (volt_dep == volt_dep_new) {\r
+                                       volt = volt_dep + clk_biger_than_dep;\r
+                               } else {\r
+                                       volt_dep = volt + dep_biger_than_clk;\r
+                               }\r
+                       } else {\r
+                               if (volt == volt_new) {\r
+                                       volt_dep = volt + dep_biger_than_clk;\r
+                               } else {\r
+                                       volt = volt_dep + clk_biger_than_dep;\r
+                               }\r
+                       }\r
+                       volt = volt > volt_new ? volt_new : volt;\r
+                       volt_dep = volt_dep > volt_dep_new ? volt_dep_new : volt_dep;\r
+\r
+               } else if (step < 0) {\r
+                       // down voltage\r
+                       DVFS_DBG("step < 0\n");\r
+                       if (volt > volt_dep) {\r
+                               if (volt == volt_new) {\r
+                                       volt_dep = volt - clk_biger_than_dep;\r
+                               } else {\r
+                                       volt = volt_dep - dep_biger_than_clk;\r
+                               }\r
+                       } else {\r
+                               if (volt_dep == volt_dep_new) {\r
+                                       volt = volt_dep - dep_biger_than_clk;\r
+                               } else {\r
+                                       volt_dep = volt - clk_biger_than_dep;\r
+                               }\r
+                       }\r
+                       volt = volt < volt_new ? volt_new : volt;\r
+                       volt_dep = volt_dep < volt_dep_new ? volt_dep_new : volt_dep;\r
+\r
+               } else {\r
+                       DVFS_ERR("Oops, some bugs here:Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n", \r
+                                       volt_new, volt_old, volt_dep_new, volt_dep_old);\r
+                       goto fail;\r
+               }\r
+\r
+               DVFS_DBG("\t\tNOW:Volt=%d, volt_dep=%d\n", volt, volt_dep);\r
+\r
+               if (vd_clk->cur_volt != volt) {\r
+                       ret = dvfs_regulator_set_voltage_readback(regulator, volt, volt);\r
+                       udelay(get_volt_up_delay(volt, volt_pre));\r
+                       if (ret < 0) {\r
+                               DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", \r
+                                               __func__, vd_clk->name, ret, volt_new, volt_old);\r
+                               goto fail;\r
+                       }\r
+                       vd_clk->cur_volt = volt;\r
+               }\r
+\r
+               if (vd_dep->cur_volt != volt_dep) {\r
+                       ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep, volt_dep);\r
+                       udelay(get_volt_up_delay(volt_dep, volt_dep_pre));\r
+                       if (ret < 0) {\r
+                               DVFS_ERR("depend %s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", \r
+                                               __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old);\r
+                               goto fail;\r
+                       }\r
+                       vd_dep->cur_volt = volt_dep;\r
+               }\r
+\r
+       } while (volt != volt_new || volt_dep!= volt_dep_new);\r
+       \r
+       vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS;\r
+       vd_clk->cur_volt = volt_new;\r
+       \r
+       return 0;\r
+fail:\r
+       DVFS_ERR("+++++++++++++++++FAIL AREA\n");       \r
+       vd_clk->cur_volt = volt_old;\r
+       vd_dep->cur_volt = volt_dep_old;\r
+       vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;\r
+       ret = dvfs_regulator_set_voltage_readback(regulator, volt_old, volt_old);\r
+       if (ret < 0) {\r
+               vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;\r
+               DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n", \r
+                               __func__, vd_clk->name, ret, volt_new, volt_old);\r
+       }\r
+       \r
+       ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep_old, volt_dep_old);\r
+       if (ret < 0) {\r
+               vd_dep->volt_set_flag = DVFS_SET_VOLT_FAILURE;\r
+               DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n", \r
+                               __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old);\r
+       }\r
+\r
+       return -1;\r
+}\r
+\r
+int dvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new)\r
+{\r
+       int ret = 0;\r
+       DVFS_DBG("ENTER %s, volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt);\r
+       if (IS_ERR_OR_NULL(vd_clk)) {\r
+               DVFS_ERR("%s vd_node error\n", __func__);\r
+               return -1;\r
+       }\r
+\r
+       DVFS_DBG("ENTER %s, volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt);\r
+       if (!IS_ERR_OR_NULL(vd_clk->regulator)) {\r
+               ret = dvfs_regulator_set_voltage_readback(vd_clk->regulator, volt_new, volt_new);\r
+               if (ret < 0) {\r
+                       vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;\r
+                       DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n", \r
+                                       __func__, vd_clk->name, ret, volt_new, vd_clk->cur_volt);\r
+                       return -1;\r
+               }\r
+\r
+       } else {\r
+               DVFS_ERR("%s up volt dvfs_clk->vd->regulator == NULL\n", __func__);\r
+               return -1;\r
+       }\r
+\r
+       vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS;\r
+       vd_clk->cur_volt = volt_new;\r
+\r
+       return 0;\r
+\r
+}\r
+\r
+int dvfs_scale_volt_bystep(struct vd_node *vd_clk, struct vd_node *vd_dep, int volt_new, int volt_dep_new, \r
+               int clk_biger_than_dep, int dep_biger_than_clk)\r
+\r
+{\r
+       int ret = 0;\r
+       int volt_old = 0, volt_dep_old = 0;\r
+\r
+       volt_old = vd_clk->cur_volt;\r
+       volt_dep_old = vd_dep->cur_volt;\r
+\r
+       DVFS_DBG("ENTER %s, volt=%d(old=%d) vd_dep=%d(dep_old=%d)\n", __func__, \r
+                       volt_new, volt_old, volt_dep_new, volt_dep_old);\r
+\r
+       if (check_volt_correct(volt_old, &volt_new, volt_dep_old, &volt_dep_new, \r
+                               clk_biger_than_dep, dep_biger_than_clk) < 0) {\r
+               DVFS_ERR("CURRENT VOLT INCORRECT, VD=%s, VD_DEP=%s\n", vd_clk->name, vd_dep->name);\r
+               return -1;\r
+       }\r
+       DVFS_DBG("ENTER %s, volt=%d(old=%d), volt_dep=%d(dep_old=%d)\n", __func__, \r
+                       volt_new, volt_old, volt_dep_new, volt_dep_old);\r
+       ret = dvfs_scale_volt(vd_clk, vd_dep, volt_old, volt_new, volt_dep_old, volt_dep_new, \r
+                       clk_biger_than_dep, dep_biger_than_clk);\r
+       if (ret < 0) {\r
+               vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;\r
+               DVFS_ERR("set volt error\n");\r
+               return -1;\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+int dvfs_reset_volt(struct vd_node *dvfs_vd)\r
+{      \r
+       int flag_set_volt_correct = 0;\r
+       if (!IS_ERR_OR_NULL(dvfs_vd->regulator))\r
+               flag_set_volt_correct = dvfs_regulator_get_voltage(dvfs_vd->regulator);\r
+       else {\r
+               DVFS_ERR("dvfs regulator is ERROR\n");\r
+               return -1;\r
+       }\r
+       if (flag_set_volt_correct <= 0) {\r
+               DVFS_ERR("%s (clk:%s), try to reload arm_volt error %d!!! stop scaling\n", \r
+                               __func__, dvfs_vd->name, flag_set_volt_correct);\r
+               return -1;\r
+       }\r
+       dvfs_vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS;\r
+       DVFS_ERR("%s (clk:%s), try to reload arm_volt! arm_volt_correct = %d\n", \r
+                       __func__, dvfs_vd->name, flag_set_volt_correct);\r
+\r
+       /* Reset vd's voltage */\r
+       dvfs_vd->cur_volt = flag_set_volt_correct;\r
+\r
+       return dvfs_vd->cur_volt;\r
+}\r
+\r
+int dvfs_get_depend_volt(struct clk_node *dvfs_clk, struct vd_node *dvfs_vd_dep, int rate_new)\r
+{\r
+       struct depend_list      *depend;\r
+       struct cpufreq_frequency_table clk_fv_dep;\r
+       int ret = 0;\r
+\r
+       DVFS_DBG("ENTER %s, rate_new=%d\n", __func__, rate_new);\r
+       list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) {\r
+               DVFS_DBG("--round depend clk:%s(depend:%s)\n", depend->dvfs_clk->name, depend->dep_vd->name);\r
+               // this place just consider ONE depend voltage domain,\r
+               // multi-depends must have some differece\r
+               clk_fv_dep.index = 0;\r
+               if (depend->dep_vd == dvfs_vd_dep) {\r
+                       ret = dvfs_clk_get_ref_volt_depend(depend, rate_new / 1000, &clk_fv_dep);\r
+                       if (ret < 0) {\r
+                               DVFS_ERR("%s get dvfs_ref_volt_depend error\n", __func__);\r
+                               return -1;\r
+                       }\r
+                       depend->req_volt = clk_fv_dep.index;\r
+                       return depend->req_volt;\r
+               }\r
+       }\r
+\r
+       DVFS_ERR("%s can not find vd node %s\n", __func__, dvfs_vd_dep->name);\r
+       return -1;\r
+}\r
+static struct clk_node *dvfs_clk_cpu;\r
+static struct vd_node vd_core;\r
+int dvfs_target_cpu(struct clk *clk, unsigned long rate_hz)\r
+{\r
+       struct clk_node *dvfs_clk;\r
+       int volt_new = 0, volt_dep_new = 0, clk_volt_store = 0;\r
+       struct cpufreq_frequency_table clk_fv;\r
+       int ret = 0;\r
+       unsigned long rate_new, rate_old;\r
+       \r
+       if (!clk) {\r
+               DVFS_ERR("%s is not a clk\n", __func__);\r
+               return -1;\r
+       }\r
+       dvfs_clk = clk_get_dvfs_info(clk);\r
+       DVFS_DBG("enter %s: clk(%s) rate = %lu Hz\n", __func__, dvfs_clk->name, rate_hz);\r
+\r
+       if (!dvfs_clk || dvfs_clk->vd == NULL || IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {\r
+               DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name);\r
+               return -1;\r
+       }\r
+\r
+       if (dvfs_clk->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) {\r
+               /* It means the last time set voltage error */\r
+               ret = dvfs_reset_volt(dvfs_clk->vd);\r
+               if (ret < 0) {\r
+                       return -1;\r
+               }\r
+       }\r
+\r
+       /* Check limit rate */\r
+       if (dvfs_clk->freq_limit_en) {\r
+               if (rate_hz < dvfs_clk->min_rate) {\r
+                       rate_hz = dvfs_clk->min_rate;\r
+               } else if (rate_hz > dvfs_clk->max_rate) {\r
+                       rate_hz = dvfs_clk->max_rate;\r
+               }\r
+       }\r
+               \r
+       /* need round rate */\r
+       rate_old = clk_get_rate(clk);\r
+       rate_new = clk_round_rate_nolock(clk, rate_hz);\r
+       DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", \r
+                       dvfs_clk->name, rate_hz, rate_new, rate_old);\r
+\r
+       /* find the clk corresponding voltage */\r
+       if (0 != dvfs_clk_get_ref_volt(dvfs_clk, rate_new / 1000, &clk_fv)) {\r
+               DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n", dvfs_clk->name, rate_hz);\r
+               return -1;\r
+       }\r
+       clk_volt_store = dvfs_clk->set_volt;\r
+       dvfs_clk->set_volt = clk_fv.index;\r
+       volt_new = dvfs_vd_get_newvolt_byclk(dvfs_clk);\r
+\r
+       /* if up the rate */\r
+       if (rate_new > rate_old) {\r
+               if (!list_empty(&dvfs_clk->depend_list)) {\r
+                       // update depend's req_volt\r
+                       ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_new);\r
+                       if (ret <= 0)\r
+                               goto fail_roll_back;\r
+                       \r
+                       volt_dep_new = dvfs_vd_get_newvolt_bypd(&vd_core);\r
+                       if (volt_dep_new <= 0) \r
+                               goto fail_roll_back;\r
+                       ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);\r
+\r
+                       //ret = dvfs_scale_volt_bystep(dvfs_clk->vd, &vd_core, volt_new, volt_dep_new, \r
+                       //              ARM_HIGHER_LOGIC, LOGIC_HIGHER_ARM); \r
+                       if (ret < 0) \r
+                               goto fail_roll_back;\r
+               } else {\r
+                       ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);\r
+                       if (ret < 0) \r
+                               goto fail_roll_back;\r
+               }\r
+       }\r
+\r
+       /* scale rate */\r
+       if (dvfs_clk->clk_dvfs_target) {\r
+               ret = dvfs_clk->clk_dvfs_target(clk, rate_new, clk_set_rate_locked);\r
+       } else {\r
+               ret = clk_set_rate_locked(clk, rate_new);\r
+       }\r
+\r
+       if (ret < 0) {\r
+               DVFS_ERR("%s set rate err\n", __func__);\r
+               goto fail_roll_back;\r
+       }\r
+       dvfs_clk->set_freq      = rate_new / 1000;\r
+\r
+       DVFS_DBG("dvfs %s set rate %lu ok\n", dvfs_clk->name, clk_get_rate(clk));\r
+\r
+       /* if down the rate */\r
+       if (rate_new < rate_old) {\r
+               if (!list_empty(&dvfs_clk->depend_list)) {\r
+                       // update depend's req_volt\r
+                       ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_new);\r
+                       if (ret <= 0)\r
+                               goto out;\r
+                       \r
+                       volt_dep_new = dvfs_vd_get_newvolt_bypd(&vd_core);\r
+                       if (volt_dep_new <= 0) \r
+                               goto out;\r
+                       ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);\r
+\r
+                       //ret = dvfs_scale_volt_bystep(dvfs_clk->vd, &vd_core, volt_new, volt_dep_new, \r
+                       //              ARM_HIGHER_LOGIC, LOGIC_HIGHER_ARM); \r
+                       if (ret < 0) \r
+                               goto out;\r
+               } else {\r
+                       ret = dvfs_scale_volt_direct(dvfs_clk->vd, volt_new);\r
+                       if (ret < 0) \r
+                               goto out;\r
+               }\r
+       }\r
+\r
+       return ret;\r
+fail_roll_back:\r
+       dvfs_clk->set_volt = clk_volt_store;\r
+       ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_old);\r
+       if (ret <= 0) {\r
+               DVFS_ERR("%s dvfs_get_depend_volt error when roll back!\n", __func__);\r
+       }\r
+out:\r
+       return -1;\r
+}\r
+\r
+int dvfs_target_core(struct clk *clk, unsigned long rate_hz)\r
+{\r
+       struct clk_node *dvfs_clk;\r
+       int volt_new = 0, volt_dep_new = 0, clk_volt_store = 0;\r
+       \r
+       struct cpufreq_frequency_table clk_fv;\r
+       \r
+       int ret = 0;\r
+       unsigned long rate_new, rate_old;\r
+               \r
+       if (!clk) {\r
+               DVFS_ERR("%s is not a clk\n", __func__);\r
+               return -1;\r
+       }\r
+       dvfs_clk = clk_get_dvfs_info(clk);\r
+       DVFS_DBG("enter %s: clk(%s) rate = %lu Hz\n", __func__, dvfs_clk->name, rate_hz);\r
+\r
+       if (!dvfs_clk || dvfs_clk->vd == NULL || IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {\r
+               DVFS_ERR("dvfs(%s) is not register regulator\n", dvfs_clk->name);\r
+               return -1;\r
+       }\r
+\r
+       if (dvfs_clk->vd->volt_set_flag == DVFS_SET_VOLT_FAILURE) {\r
+               /* It means the last time set voltage error */\r
+               ret = dvfs_reset_volt(dvfs_clk->vd);\r
+               if (ret < 0) {\r
+                       return -1;\r
+               }\r
+       }\r
+\r
+       /* Check limit rate */\r
+       if (dvfs_clk->freq_limit_en) {\r
+               if (rate_hz < dvfs_clk->min_rate) {\r
+                       rate_hz = dvfs_clk->min_rate;\r
+               } else if (rate_hz > dvfs_clk->max_rate) {\r
+                       rate_hz = dvfs_clk->max_rate;\r
+               }\r
+       }\r
+               \r
+       /* need round rate */\r
+       rate_old = clk_get_rate(clk);\r
+       rate_new = clk_round_rate_nolock(clk, rate_hz);\r
+       DVFS_DBG("dvfs(%s) round rate (%lu)(rount %lu) old (%lu)\n", \r
+                       dvfs_clk->name, rate_hz, rate_new, rate_old);\r
+\r
+       /* find the clk corresponding voltage */\r
+       if (0 != dvfs_clk_get_ref_volt(dvfs_clk, rate_new / 1000, &clk_fv)) {\r
+               DVFS_ERR("dvfs(%s) rate %luhz is larger,not support\n", dvfs_clk->name, rate_hz);\r
+               return -1;\r
+       }\r
+       clk_volt_store = dvfs_clk->set_volt;\r
+       dvfs_clk->set_volt = clk_fv.index;\r
+       volt_new = dvfs_vd_get_newvolt_byclk(dvfs_clk);\r
+\r
+       /* if up the rate */\r
+       if (rate_new > rate_old) {\r
+               DVFS_DBG("-----------------------------rate_new > rate_old\n");\r
+               volt_dep_new = dvfs_vd_get_newvolt_byclk(dvfs_clk_cpu);\r
+\r
+               if (volt_dep_new < 0) \r
+                       goto fail_roll_back;\r
+\r
+               ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, \r
+                                       LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); \r
+               if (ret < 0) \r
+                       goto fail_roll_back;\r
+       }\r
+\r
+       /* scale rate */\r
+       if (dvfs_clk->clk_dvfs_target) {\r
+               ret = dvfs_clk->clk_dvfs_target(clk, rate_new, clk_set_rate_locked);\r
+       } else {\r
+               \r
+               ret = clk_set_rate_locked(clk, rate_new);\r
+       }\r
+\r
+       if (ret < 0) {\r
+               DVFS_ERR("%s set rate err\n", __func__);\r
+               goto fail_roll_back;\r
+       }\r
+       dvfs_clk->set_freq      = rate_new / 1000;\r
+\r
+       DVFS_DBG("dvfs %s set rate %lu ok\n", dvfs_clk->name, clk_get_rate(clk));\r
+\r
+       /* if down the rate */\r
+       if (rate_new < rate_old) {\r
+               DVFS_DBG("-----------------------------rate_new < rate_old\n");\r
+               volt_dep_new = dvfs_vd_get_newvolt_byclk(dvfs_clk_cpu);\r
+\r
+               if (volt_dep_new < 0) \r
+                       goto out;\r
+\r
+               ret = dvfs_scale_volt_bystep(dvfs_clk->vd, dvfs_clk_cpu->vd, volt_new, volt_dep_new, \r
+                                       LOGIC_HIGHER_ARM, ARM_HIGHER_LOGIC); \r
+               if (ret < 0) \r
+                       goto out;\r
+       }\r
+\r
+       return ret;\r
+fail_roll_back:        \r
+       dvfs_clk->set_volt = clk_volt_store;\r
+       ret = dvfs_get_depend_volt(dvfs_clk, &vd_core, rate_old);\r
+       if (ret <= 0) {\r
+               DVFS_ERR("%s dvfs_get_depend_volt error when roll back!\n", __func__);\r
+       }\r
+\r
+out:\r
+       return -1;\r
+}\r
+\r
+/*****************************init**************************/\r
+/**\r
+ * rate must be raising sequence\r
+ */\r
+static struct cpufreq_frequency_table cpu_dvfs_table[] = {\r
+       // {.frequency  = 48 * DVFS_KHZ, .index = 920*DVFS_MV},\r
+       // {.frequency  = 126 * DVFS_KHZ, .index        = 970 * DVFS_MV},\r
+       // {.frequency  = 252 * DVFS_KHZ, .index        = 1040 * DVFS_MV},\r
+       // {.frequency  = 504 * DVFS_KHZ, .index        = 1050 * DVFS_MV},\r
+       {.frequency     = 816 * DVFS_KHZ, .index        = 1050 * DVFS_MV},\r
+       // {.frequency  = 1008 * DVFS_KHZ, .index       = 1100 * DVFS_MV},\r
+       {.frequency     = CPUFREQ_TABLE_END},\r
+};\r
+\r
+static struct cpufreq_frequency_table ddr_dvfs_table[] = {\r
+       // {.frequency = 100 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
+       {.frequency = 200 * DVFS_KHZ, .index = 1000 * DVFS_MV},\r
+       {.frequency = 300 * DVFS_KHZ, .index = 1050 * DVFS_MV},\r
+       {.frequency = 400 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
+       {.frequency = 500 * DVFS_KHZ, .index = 1150 * DVFS_MV},\r
+       {.frequency = 600 * DVFS_KHZ, .index = 1200 * DVFS_MV},\r
+       {.frequency = CPUFREQ_TABLE_END},\r
+};\r
+\r
+static struct cpufreq_frequency_table gpu_dvfs_table[] = {\r
+       {.frequency = 90 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
+       {.frequency = 180 * DVFS_KHZ, .index = 1150 * DVFS_MV},\r
+       {.frequency = 300 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
+       {.frequency = 400 * DVFS_KHZ, .index = 1150 * DVFS_MV},\r
+       {.frequency = 500 * DVFS_KHZ, .index = 1200 * DVFS_MV},\r
+       {.frequency = CPUFREQ_TABLE_END},\r
+};\r
+\r
+static struct cpufreq_frequency_table peri_aclk_dvfs_table[] = {\r
+       {.frequency = 100 * DVFS_KHZ, .index = 1000 * DVFS_MV},\r
+       {.frequency = 200 * DVFS_KHZ, .index = 1050 * DVFS_MV},\r
+       {.frequency = 300 * DVFS_KHZ, .index = 1070 * DVFS_MV},\r
+       {.frequency = 500 * DVFS_KHZ, .index = 1100 * DVFS_MV},\r
+       {.frequency = CPUFREQ_TABLE_END},\r
+};\r
+\r
+static struct cpufreq_frequency_table dep_cpu2core_table[] = {\r
+       // {.frequency = 252 * DVFS_KHZ, .index    = 1025 * DVFS_MV},\r
+       // {.frequency = 504 * DVFS_KHZ, .index    = 1025 * DVFS_MV},\r
+       {.frequency = 816 * DVFS_KHZ, .index    = 1050 * DVFS_MV},//logic 1.050V\r
+       // {.frequency = 1008 * DVFS_KHZ,.index    = 1050 * DVFS_MV},\r
+       // {.frequency = 1200 * DVFS_KHZ,.index    = 1050 * DVFS_MV},\r
+       // {.frequency = 1272 * DVFS_KHZ,.index    = 1050 * DVFS_MV},//logic 1.050V\r
+       // {.frequency = 1416 * DVFS_KHZ,.index    = 1100 * DVFS_MV},//logic 1.100V\r
+       // {.frequency = 1512 * DVFS_KHZ,.index    = 1125 * DVFS_MV},//logic 1.125V\r
+       // {.frequency = 1608 * DVFS_KHZ,.index    = 1175 * DVFS_MV},//logic 1.175V\r
+       {.frequency     = CPUFREQ_TABLE_END},\r
+};\r
+\r
+static struct vd_node vd_cpu = {\r
+       .name           = "vd_cpu",\r
+       .regulator_name = "vdd_cpu",\r
+       .vd_dvfs_target = dvfs_target_cpu,\r
+};\r
+\r
+static struct vd_node vd_core = {\r
+       .name           = "vd_core",\r
+       .regulator_name = "vdd_core",\r
+       .vd_dvfs_target = dvfs_target_core,\r
+};\r
+\r
+static struct vd_node vd_rtc = {\r
+       .name           = "vd_rtc",\r
+       .regulator_name = "vdd_rtc",\r
+       .vd_dvfs_target = NULL,\r
+};\r
+\r
+static struct vd_node *rk30_vds[] = {&vd_cpu, &vd_core, &vd_rtc};\r
+\r
+static struct pd_node pd_a9_0 = {\r
+       .name                   = "pd_a9_0",\r
+       .vd                     = &vd_cpu,\r
+};\r
+static struct pd_node pd_a9_1 = {\r
+       .name                   = "pd_a9_1",\r
+       .vd                     = &vd_cpu,\r
+};\r
+static struct pd_node pd_debug = {\r
+       .name                   = "pd_debug",\r
+       .vd                     = &vd_cpu,\r
+};\r
+static struct pd_node pd_scu = {\r
+       .name                   = "pd_scu",\r
+       .vd                     = &vd_cpu,\r
+};\r
+static struct pd_node pd_video = {\r
+       .name                   = "pd_video",\r
+       .vd                     = &vd_core,\r
+};\r
+static struct pd_node pd_vio = {\r
+       .name                   = "pd_vio",\r
+       .vd                     = &vd_core,\r
+};\r
+static struct pd_node pd_gpu = {\r
+       .name                   = "pd_gpu",\r
+       .vd                     = &vd_core,\r
+};\r
+static struct pd_node pd_peri = {\r
+       .name                   = "pd_peri",\r
+       .vd                     = &vd_core,\r
+};\r
+static struct pd_node pd_cpu = {\r
+       .name                   = "pd_cpu",\r
+       .vd                     = &vd_core,\r
+};\r
+static struct pd_node pd_alive = {\r
+       .name                   = "pd_alive",\r
+       .vd                     = &vd_core,\r
+};\r
+static struct pd_node pd_rtc = {\r
+       .name                   = "pd_rtc",\r
+       .vd                     = &vd_rtc,\r
+};\r
+#define LOOKUP_PD(_ppd)        \\r
+{      \\r
+       .pd     = _ppd, \\r
+}\r
+static struct pd_node_lookup rk30_pds[] = {\r
+       LOOKUP_PD(&pd_a9_0),\r
+       LOOKUP_PD(&pd_a9_1),\r
+       LOOKUP_PD(&pd_debug),\r
+       LOOKUP_PD(&pd_scu),\r
+       LOOKUP_PD(&pd_video),\r
+       LOOKUP_PD(&pd_vio),\r
+       LOOKUP_PD(&pd_gpu),\r
+       LOOKUP_PD(&pd_peri),\r
+       LOOKUP_PD(&pd_cpu),\r
+       LOOKUP_PD(&pd_alive),\r
+       LOOKUP_PD(&pd_rtc),\r
+};\r
+\r
+#define CLK_PDS(_ppd) \\r
+{      \\r
+       .pd     = _ppd, \\r
+}\r
+\r
+static struct pds_list cpu_pds[] = {\r
+       CLK_PDS(&pd_a9_0),\r
+       CLK_PDS(&pd_a9_1),\r
+       CLK_PDS(NULL),\r
+};\r
+\r
+static struct pds_list ddr_pds[] = {\r
+       CLK_PDS(&pd_cpu),\r
+       CLK_PDS(NULL),\r
+};\r
+\r
+static struct pds_list gpu_pds[] = {\r
+       CLK_PDS(&pd_gpu),\r
+       CLK_PDS(NULL),\r
+};\r
+\r
+static struct pds_list aclk_periph_pds[] = {\r
+       CLK_PDS(&pd_peri),\r
+       CLK_PDS(NULL),\r
+};\r
+\r
+#define RK_CLKS(_clk_name, _ppds, _dvfs_table, _dvfs_nb) \\r
+{ \\r
+       .name   = _clk_name, \\r
+       .pds = _ppds,\\r
+       .dvfs_table = _dvfs_table,      \\r
+       .dvfs_nb        = _dvfs_nb,     \\r
+}\r
+\r
+static struct clk_node rk30_clks[] = {\r
+       RK_CLKS("cpu", cpu_pds, cpu_dvfs_table, &rk_dvfs_clk_notifier),\r
+       //RK_CLKS("ddr", ddr_pds, ddr_dvfs_table, &rk_dvfs_clk_notifier),\r
+       RK_CLKS("gpu", gpu_pds, gpu_dvfs_table, &rk_dvfs_clk_notifier),\r
+       //RK_CLKS("aclk_periph", aclk_periph_pds, peri_aclk_dvfs_table, &rk_dvfs_clk_notifier),\r
+};\r
+\r
+#define RK_DEPPENDS(_clk_name, _pvd, _dep_table) \\r
+{ \\r
+       .clk_name       = _clk_name, \\r
+       .dep_vd         = _pvd,\\r
+       .dep_table      = _dep_table,   \\r
+}\r
+\r
+static struct depend_lookup rk30_depends[] = {\r
+       RK_DEPPENDS("cpu", &vd_core, dep_cpu2core_table),\r
+       //RK_DEPPENDS("gpu", &vd_cpu, NULL),\r
+       //RK_DEPPENDS("gpu", &vd_cpu, NULL),\r
+};\r
+\r
+int rk30_dvfs_init(void)\r
+{\r
+       int i = 0;\r
+       for (i = 0; i < ARRAY_SIZE(rk30_vds); i++) {\r
+               rk_regist_vd(rk30_vds[i]);\r
+       }\r
+       for (i = 0; i < ARRAY_SIZE(rk30_pds); i++) {\r
+               rk_regist_pd(&rk30_pds[i]);\r
+       }\r
+       for (i = 0; i < ARRAY_SIZE(rk30_clks); i++) {\r
+               rk_regist_clk(&rk30_clks[i]);\r
+       }\r
+       for (i = 0; i < ARRAY_SIZE(rk30_depends); i++) {\r
+               rk_regist_depends(&rk30_depends[i]);\r
+       }\r
+       dvfs_clk_cpu = dvfs_get_dvfs_clk_byname("cpu");\r
+       return 0;\r
+}\r
+\r
+/*******************************AVS AREA****************************************/\r
+/*\r
+ * To use AVS function, you must call avs_init in machine_rk30_board_init(void)(board-rk30-sdk.c)\r
+ * And then call(vdd_log):\r
+ *     regulator_set_voltage(dcdc, 1100000, 1100000);\r
+ *     avs_init_val_get(1,1100000,"wm8326 init");\r
+ *     udelay(600);\r
+ *     avs_set_scal_val(AVS_BASE);\r
+ * in wm831x_post_init(board-rk30-sdk-wm8326.c)\r
+ * AVS_BASE can use 172\r
+ */\r
+\r
+static int avs_scale_volt = 0;\r
+static int avs_get_scal_val(int vol);\r
+\r
+int dvfs_avs_scale_table(struct clk *clk, char *depend_vd_name)\r
+{\r
+       /* if depend_vd_name == NULL scale clk table\r
+        * else scale clk's depend table, named depend_vd_name\r
+        * */\r
+       struct vd_node          *vd;\r
+       struct depend_list      *depend;\r
+       struct clk_node *info = clk_get_dvfs_info(clk);\r
+       struct cpufreq_frequency_table  *table = NULL;\r
+       int i;\r
+\r
+       if (NULL == depend_vd_name) {\r
+               table = info->dvfs_table;\r
+       } else {\r
+               list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+                       if (0 == strcmp(vd->name, depend_vd_name)) {\r
+                               DVFS_DBG("%s FOUND A MATCH vd\n", __func__);\r
+                               mutex_lock(&mutex);\r
+                               list_for_each_entry(depend, &info->depend_list, node2clk) {\r
+                                       if (vd == depend->dep_vd && info == depend->dvfs_clk) {\r
+                                               DVFS_DBG("%s FOUND A MATCH table\n", __func__);\r
+                                               table = depend->dep_table;\r
+                                               break;\r
+                                       }\r
+                               }\r
+                               mutex_unlock(&mutex);\r
+                       }\r
+               }\r
+       }\r
+\r
+       if (table == NULL) {\r
+               DVFS_ERR("%s can not find match table\n", __func__);\r
+               return -1;\r
+       }\r
+       if (avs_scale_volt != 0) {\r
+               DVFS_DBG("AVS scale %s, depend name = %s, voltage = %d\n",\r
+                               info->name, depend_vd_name, avs_scale_volt);\r
+               for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {\r
+                       table[i].index = avs_get_scal_val(table[i].index);\r
+               }\r
+       }\r
+       return 0;\r
+}\r
+\r
+static void __iomem *rk30_nandc_base;\r
+\r
+#define nandc_readl(offset)    readl_relaxed(rk30_nandc_base + offset)\r
+#define nandc_writel(v, offset) do { writel_relaxed(v, rk30_nandc_base + offset); dsb(); } while (0)\r
+static u8 rk30_get_avs_val(void)\r
+{\r
+       u32 nanc_save_reg[4];\r
+       unsigned long flags;\r
+       u32 paramet = 0;\r
+       u32 count = 100;\r
+       preempt_disable();\r
+       local_irq_save(flags);\r
+\r
+       nanc_save_reg[0] = nandc_readl(0);\r
+       nanc_save_reg[1] = nandc_readl(0x130);\r
+       nanc_save_reg[2] = nandc_readl(0x134);\r
+       nanc_save_reg[3] = nandc_readl(0x158);\r
+\r
+       nandc_writel(nanc_save_reg[0] | 0x1 << 14, 0);\r
+       nandc_writel(0x5, 0x130);\r
+\r
+       nandc_writel(7, 0x158);\r
+       nandc_writel(1, 0x134);\r
+\r
+       while(count--) {\r
+               paramet = nandc_readl(0x138);\r
+               if((paramet & 0x1))\r
+                       break;\r
+               udelay(1);\r
+       };\r
+       paramet = (paramet >> 1) & 0xff;\r
+       nandc_writel(nanc_save_reg[0], 0);\r
+       nandc_writel(nanc_save_reg[1], 0x130);\r
+       nandc_writel(nanc_save_reg[2], 0x134);\r
+       nandc_writel(nanc_save_reg[3], 0x158);\r
+\r
+       local_irq_restore(flags);\r
+       preempt_enable();\r
+       return (u8)paramet;\r
+\r
+}\r
+#define init_avs_times 10\r
+#define init_avs_st_num 5\r
+\r
+struct init_avs_st {\r
+       int is_set;\r
+       u8 paramet[init_avs_times];\r
+       int vol;\r
+       char *s;\r
+};\r
+\r
+static struct init_avs_st init_avs_paramet[init_avs_st_num];\r
+\r
+void avs_init_val_get(int index, int vol, char *s)\r
+{\r
+       int i;\r
+       if(index >= init_avs_times)\r
+               return;\r
+       init_avs_paramet[index].vol = vol;\r
+       init_avs_paramet[index].s = s;\r
+       init_avs_paramet[index].is_set++;\r
+       for(i = 0; i < init_avs_times; i++) {\r
+               init_avs_paramet[index].paramet[i] = rk30_get_avs_val();\r
+               mdelay(1);\r
+       }\r
+}\r
+\r
+void avs_init(void)\r
+{\r
+       memset(&init_avs_paramet[0].is_set, 0, sizeof(init_avs_paramet));\r
+       rk30_nandc_base = ioremap(RK2928_NANDC_PHYS, RK2928_NANDC_SIZE);\r
+       //avs_init_val_get(0,1150000,"board_init");\r
+}\r
+\r
+#define VOL_DYN_STEP (12500)  //mv\r
+#define AVS_VAL_PER_STEP (4)  //mv\r
+\r
+static u8 avs_init_get_min_val(void)\r
+{\r
+       int i, j;\r
+       u8 min_avs = 0xff;\r
+       for(i = 0; i < init_avs_st_num; i++) {\r
+               if(init_avs_paramet[i].is_set && init_avs_paramet[i].vol == (1100 * 1000)) {\r
+                       for(j = 0; j < init_avs_times; j++)\r
+                               min_avs = (u8)min(min_avs, init_avs_paramet[i].paramet[j]);\r
+               }\r
+\r
+       }\r
+       return min_avs;\r
+}\r
+\r
+static int avs_get_scal_val(int vol)\r
+{\r
+       vol += avs_scale_volt;\r
+       if(vol < 1000 * 1000)\r
+               vol = 1000 * 1000;\r
+       if(vol > 1400 * 1000)\r
+               vol = 1400 * 1000;\r
+       return vol;\r
+}\r
+#if 0\r
+u8 avs_test_date[] = {172, 175, 176, 179, 171, 168, 165, 162, 199, 0};\r
+u8 avs_test_date_cunt = 0;\r
+#endif\r
+int avs_set_scal_val(u8 avs_base)\r
+{\r
+       u8 avs_test = avs_init_get_min_val();\r
+       s8 step = 0;\r
+\r
+       if (avs_base < avs_test) {\r
+               DVFS_DBG("AVS down voltage, ignore\n");\r
+               return 0;\r
+       }\r
+       step = (avs_base - avs_test) / AVS_VAL_PER_STEP;\r
+       step = (avs_base > avs_test) ? (step + 1) : step;\r
+       if (step > 2)\r
+               step += 1;\r
+       avs_scale_volt = (step) * (VOL_DYN_STEP);\r
+\r
+       DVFS_DBG("avs_set_scal_val test=%d,base=%d,step=%d,scale_vol=%d\n",\r
+                       avs_test, avs_base, step, avs_scale_volt);\r
+       return 0;\r
+}\r
+\r
+/*************************interface to get avs value and dvfs tree*************************/\r
+#define USE_NORMAL_TIME\r
+#ifdef USE_NORMAL_TIME\r
+static struct timer_list avs_timer;\r
+#else\r
+static struct hrtimer dvfs_hrtimer;\r
+#endif\r
+\r
+static u32 avs_dyn_start = 0;\r
+static u32 avs_dyn_data_cnt;\r
+static u8 *avs_dyn_data = NULL;\r
+static u32 show_line_cnt = 0;\r
+static u8 dly_min;\r
+static u8 dly_max;\r
+\r
+#define val_per_line (30)\r
+#define line_pre_show (30)\r
+#define avs_dyn_data_num (3*1000*1000)\r
+\r
+static u32 print_avs_init(char *buf)\r
+{\r
+       char *s = buf;\r
+       int i, j;\r
+\r
+       for(j = 0; j < init_avs_st_num; j++) {\r
+               if(init_avs_paramet[j].vol <= 0)\r
+                       continue;\r
+               s += sprintf(s, "%s ,vol=%d,paramet following\n", \r
+                               init_avs_paramet[j].s, init_avs_paramet[j].vol);\r
+               for(i = 0; i < init_avs_times; i++) {\r
+                       s += sprintf(s, "%d ", init_avs_paramet[j].paramet[i]);\r
+               }\r
+\r
+               s += sprintf(s, "\n");\r
+       }\r
+       return (s - buf);\r
+}\r
+\r
+static ssize_t avs_init_show(struct kobject *kobj, struct kobj_attribute *attr,\r
+               char *buf)\r
+{\r
+       return print_avs_init(buf);\r
+}\r
+\r
+static ssize_t avs_init_store(struct kobject *kobj, struct kobj_attribute *attr,\r
+               const char *buf, size_t n)\r
+{\r
+\r
+       return n;\r
+}\r
+static ssize_t avs_now_show(struct kobject *kobj, struct kobj_attribute *attr,\r
+               char *buf)\r
+{\r
+       return sprintf(buf, "%d\n", rk30_get_avs_val());\r
+}\r
+\r
+static ssize_t avs_now_store(struct kobject *kobj, struct kobj_attribute *attr,\r
+               const char *buf, size_t n)\r
+{\r
+       return n;\r
+}\r
+static ssize_t avs_dyn_show(struct kobject *kobj, struct kobj_attribute *attr,\r
+               char *buf)\r
+{\r
+       char *s = buf;\r
+       u32 i;\r
+\r
+       if(avs_dyn_start) {\r
+               int start_cnt;\r
+               int end_cnt;\r
+               end_cnt = (avs_dyn_data_cnt ? (avs_dyn_data_cnt - 1) : 0);\r
+               if(end_cnt > (line_pre_show * val_per_line))\r
+                       start_cnt = end_cnt - (line_pre_show * val_per_line);\r
+               else\r
+                       start_cnt = 0;\r
+\r
+               dly_min = avs_dyn_data[start_cnt];\r
+               dly_max = avs_dyn_data[start_cnt];\r
+\r
+               //s += sprintf(s,"data start=%d\n",i);\r
+               for(i = start_cnt; i <= end_cnt;) {\r
+                       s += sprintf(s, "%d", avs_dyn_data[i]);\r
+                       dly_min = min(dly_min, avs_dyn_data[i]);\r
+                       dly_max = max(dly_max, avs_dyn_data[i]);\r
+                       i++;\r
+                       if(!(i % val_per_line)) {\r
+                               s += sprintf(s, "\n");\r
+                       } else\r
+                               s += sprintf(s, " ");\r
+               }\r
+\r
+               s += sprintf(s, "\n");\r
+\r
+               s += sprintf(s, "new data is from=%d to %d\n", start_cnt, end_cnt);\r
+               //s += sprintf(s,"\n max=%d,min=%d,totolcnt=%d,line=%d\n",dly_max,dly_min,avs_dyn_data_cnt,show_line_cnt);\r
+\r
+\r
+       } else {\r
+               if(show_line_cnt == 0) {\r
+                       dly_min = avs_dyn_data[0];\r
+                       dly_max = avs_dyn_data[0];\r
+               }\r
+\r
+\r
+               for(i = show_line_cnt * (line_pre_show * val_per_line); i < avs_dyn_data_cnt;) {\r
+                       s += sprintf(s, "%d", avs_dyn_data[i]);\r
+                       dly_min = min(dly_min, avs_dyn_data[i]);\r
+                       dly_max = max(dly_max, avs_dyn_data[i]);\r
+                       i++;\r
+                       if(!(i % val_per_line)) {\r
+                               s += sprintf(s, "\n");\r
+                       } else\r
+                               s += sprintf(s, " ");\r
+                       if(i >= ((show_line_cnt + 1)*line_pre_show * val_per_line))\r
+                               break;\r
+               }\r
+\r
+               s += sprintf(s, "\n");\r
+\r
+               s += sprintf(s, "max=%d,min=%d,totolcnt=%d,line=%d\n", \r
+                               dly_max, dly_min, avs_dyn_data_cnt, show_line_cnt);\r
+               show_line_cnt++;\r
+               if(((show_line_cnt * line_pre_show)*val_per_line) >= avs_dyn_data_cnt) {\r
+\r
+                       show_line_cnt = 0;\r
+\r
+                       s += sprintf(s, "data is over\n");\r
+               }\r
+       }\r
+       return (s - buf);\r
+}\r
+\r
+static ssize_t avs_dyn_store(struct kobject *kobj, struct kobj_attribute *attr,\r
+               const char *buf, size_t n)\r
+{\r
+       const char *pbuf;\r
+\r
+       if((strncmp(buf, "start", strlen("start")) == 0)) {\r
+               pbuf = &buf[strlen("start")];\r
+               avs_dyn_data_cnt = 0;\r
+               show_line_cnt = 0;\r
+               if(avs_dyn_data) {\r
+#ifdef USE_NORMAL_TIME\r
+                       mod_timer(&avs_timer, jiffies + msecs_to_jiffies(5));\r
+#else\r
+                       hrtimer_start(&dvfs_hrtimer, ktime_set(0, 5 * 1000 * 1000), HRTIMER_MODE_REL);\r
+#endif\r
+                       avs_dyn_start = 1;\r
+               }\r
+               //sscanf(pbuf, "%d %d", &number, &voltage);\r
+               //DVFS_DBG("---------ldo %d %d\n", number, voltage);\r
+\r
+       } else if((strncmp(buf, "stop", strlen("stop")) == 0)) {\r
+               pbuf = &buf[strlen("stop")];\r
+               avs_dyn_start = 0;\r
+               show_line_cnt = 0;\r
+               //sscanf(pbuf, "%d %d", &number, &voltage);\r
+               //DVFS_DBG("---------dcdc %d %d\n", number, voltage);\r
+       }\r
+\r
+\r
+\r
+       return n;\r
+}\r
+\r
+static ssize_t dvfs_tree_store(struct kobject *kobj, struct kobj_attribute *attr,\r
+               const char *buf, size_t n)\r
+{\r
+       return n;\r
+}\r
+static ssize_t dvfs_tree_show(struct kobject *kobj, struct kobj_attribute *attr,\r
+               char *buf)\r
+{\r
+       return dump_dbg_map(buf);\r
+\r
+}\r
+\r
+static void avs_timer_fn(unsigned long data)\r
+{\r
+       int i;\r
+       for(i = 0; i < 1; i++) {\r
+               if(avs_dyn_data_cnt >= avs_dyn_data_num)\r
+                       return;\r
+               avs_dyn_data[avs_dyn_data_cnt] = rk30_get_avs_val();\r
+               avs_dyn_data_cnt++;\r
+       }\r
+       if(avs_dyn_start)\r
+               mod_timer(&avs_timer, jiffies + msecs_to_jiffies(10));\r
+}\r
+#if 0\r
+struct hrtimer dvfs_hrtimer;\r
+static enum hrtimer_restart dvfs_hrtimer_timer_func(struct hrtimer *timer)\r
+{\r
+       int i;\r
+       for(i = 0; i < 1; i++) {\r
+               if(avs_dyn_data_cnt >= avs_dyn_data_num)\r
+                       return HRTIMER_NORESTART;\r
+               avs_dyn_data[avs_dyn_data_cnt] = rk30_get_avs_val();\r
+               avs_dyn_data_cnt++;\r
+       }\r
+       if(avs_dyn_start)\r
+               hrtimer_start(timer, ktime_set(0, 1 * 1000 * 1000), HRTIMER_MODE_REL);\r
+\r
+}\r
+#endif\r
+/*********************************************************************************/\r
+static struct kobject *dvfs_kobj;\r
+struct dvfs_attribute {\r
+       struct attribute        attr;\r
+       ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,\r
+                       char *buf);\r
+       ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,\r
+                       const char *buf, size_t n);\r
+};\r
+\r
+static struct dvfs_attribute dvfs_attrs[] = {\r
+       /*     node_name        permision               show_func       store_func */\r
+       __ATTR(dvfs_tree,       S_IRUGO | S_IWUSR,      dvfs_tree_show, dvfs_tree_store),\r
+       __ATTR(avs_init,        S_IRUGO | S_IWUSR,      avs_init_show,  avs_init_store),\r
+       //__ATTR(avs_dyn,               S_IRUGO | S_IWUSR,      avs_dyn_show,   avs_dyn_store),\r
+       __ATTR(avs_now,         S_IRUGO | S_IWUSR,      avs_now_show,   avs_now_store),\r
+};\r
+\r
+static int __init dvfs_init(void)\r
+{\r
+       int i, ret = 0;\r
+#ifdef USE_NORMAL_TIME\r
+       init_timer(&avs_timer);\r
+       //avs_timer.expires = jiffies+msecs_to_jiffies(1);\r
+       avs_timer.function = avs_timer_fn;\r
+       //mod_timer(&avs_timer,jiffies+msecs_to_jiffies(1));\r
+#else\r
+       hrtimer_init(&dvfs_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);\r
+       dvfs_hrtimer.function = dvfs_hrtimer_timer_func;\r
+       //hrtimer_start(&dvfs_hrtimer,ktime_set(0, 5*1000*1000),HRTIMER_MODE_REL);\r
+#endif\r
+       avs_dyn_data = kmalloc(avs_dyn_data_num, GFP_KERNEL);\r
+\r
+       dvfs_kobj = kobject_create_and_add("dvfs", NULL);\r
+       if (!dvfs_kobj)\r
+               return -ENOMEM;\r
+       for (i = 0; i < ARRAY_SIZE(dvfs_attrs); i++) {\r
+               ret = sysfs_create_file(dvfs_kobj, &dvfs_attrs[i].attr);\r
+               if (ret != 0) {\r
+                       DVFS_ERR("create index %d error\n", i);\r
+                       return ret;\r
+               }\r
+       }\r
+\r
+       return ret;\r
+}\r
+subsys_initcall(dvfs_init);\r
+\r
+/**\r
+ * dump_dbg_map() : Draw all informations of dvfs while debug\r
+ */\r
+static int dump_dbg_map(char *buf)\r
+{\r
+       int i;\r
+       struct vd_node  *vd;\r
+       struct pd_node  *pd, *clkparent;\r
+       struct clk_list *child;\r
+       struct clk_node *dvfs_clk;\r
+       struct depend_list *depend;\r
+       char* s = buf;\r
+       \r
+       s += sprintf(s, "-------------DVFS TREE-----------\n\n\n");\r
+       s += sprintf(s, "RK30 DVFS TREE:\n");\r
+       list_for_each_entry(vd, &rk_dvfs_tree, node) {\r
+               s += sprintf(s, "|\n|- voltage domain:%s\n", vd->name);\r
+               s += sprintf(s, "|- current voltage:%d\n", vd->cur_volt);\r
+               list_for_each_entry(depend, &vd->req_volt_list, node2vd) {\r
+                       s += sprintf(s, "|- request voltage:%d, clk:%s\n", depend->req_volt, depend->dvfs_clk->name);\r
+               }\r
+\r
+               list_for_each_entry(pd, &vd->pd_list, node) {\r
+                       s += sprintf(s, "|  |\n|  |- power domain:%s, status = %s, current volt = %d\n",\r
+                                       pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt);\r
+\r
+                       list_for_each_entry(child, &pd->clk_list, node) {\r
+                               dvfs_clk = child->dvfs_clk;\r
+                               s += sprintf(s, "|  |  |\n|  |  |- clock: %s current: rate %d, volt = %d, enable_dvfs = %s\n",\r
+                                               dvfs_clk->name, dvfs_clk->set_freq, dvfs_clk->set_volt, \r
+                                               dvfs_clk->enable_dvfs == 0 ? "DISABLE" : "ENABLE");\r
+                               for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {\r
+                                       clkparent = dvfs_clk->pds[i].pd;\r
+                                       s += sprintf(s, "|  |  |  |- clock parents: %s, vd_parent = %s\n", \r
+                                                       clkparent->name, clkparent->vd->name);\r
+                               }\r
+\r
+                               for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {\r
+                                       s += sprintf(s, "|  |  |  |- freq = %d, volt = %d\n", \r
+                                                       dvfs_clk->dvfs_table[i].frequency, \r
+                                                       dvfs_clk->dvfs_table[i].index);\r
+\r
+                               }\r
+\r
+                               list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) {\r
+                                       s += sprintf(s, "|  |  |  |  |- DEPEND VD: %s\n", depend->dep_vd->name); \r
+                                       for (i = 0; (depend->dep_table[i].frequency != CPUFREQ_TABLE_END); i++) {\r
+                                               s += sprintf(s, "|  |  |  |  |- freq = %d, req_volt = %d\n", \r
+                                                               depend->dep_table[i].frequency, \r
+\r
+                                                               depend->dep_table[i].index);\r
+                                       }\r
+                               }\r
+                       }\r
+               }\r
+       }\r
+       s += sprintf(s, "-------------DVFS TREE END------------\n");\r
+       return s - buf;\r
+}\r
+\r
+\r
diff --git a/arch/arm/mach-rk2928/include/mach/dvfs.h b/arch/arm/mach-rk2928/include/mach/dvfs.h
new file mode 100644 (file)
index 0000000..59ec37d
--- /dev/null
@@ -0,0 +1,183 @@
+/* arch/arm/mach-rk30/rk30_dvfs.h\r
+ *\r
+ * Copyright (C) 2012 ROCKCHIP, Inc.\r
+ *\r
+ * This software is licensed under the terms of the GNU General Public\r
+ * License version 2, as published by the Free Software Foundation, and\r
+ * may be copied, distributed, and modified under those terms.\r
+ *\r
+ * This program is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ */\r
+#ifndef _RK30_DVFS_H_\r
+#define _RK30_DVFS_H_\r
+\r
+#include <mach/clock.h>\r
+\r
+typedef int (*vd_dvfs_target_callback)(struct clk *clk, unsigned long rate);\r
+\r
+typedef int (*dvfs_set_rate_callback)(struct clk *clk, unsigned long rate);\r
+\r
+typedef int (*clk_dvfs_target_callback)(struct clk *clk, unsigned long rate,\r
+                                        dvfs_set_rate_callback set_rate);\r
+\r
+/**\r
+ * struct vd_node:     To Store All Voltage Domains' info\r
+ * @name:              Voltage Domain's Name\r
+ * @regulator_name:    Voltage domain's regulator name\r
+ * @cur_volt:          Voltage Domain's Current Voltage\r
+ * @regulator:         Voltage Domain's regulator point\r
+ * @node:              Point of he Voltage Domain List Node\r
+ * @pd_list:           Head of Power Domain List Belongs to This Voltage Domain\r
+ * @req_volt_list:     The list of clocks requests\r
+ * @dvfs_mutex:                Lock\r
+ * @vd_dvfs_target:    Callback function       \r
+ */\r
+\r
+struct vd_node {\r
+       char                    *name;\r
+       char                    *regulator_name;\r
+       int                     cur_volt;\r
+       int                     volt_set_flag;\r
+       struct regulator        *regulator;\r
+       struct list_head        node;\r
+       struct list_head        pd_list;\r
+       struct list_head        req_volt_list;\r
+       //struct mutex          dvfs_mutex;\r
+       vd_dvfs_target_callback vd_dvfs_target;\r
+};\r
+\r
+/**\r
+ * struct pd_node:     To Store All Power Domains' info\r
+ * @name:              Power Domain's Name\r
+ * @cur_volt:          Power Domain's Current Voltage\r
+ * @pd_status:         Power Domain's status\r
+ * @vd:                        Voltage Domain the power domain belongs to\r
+ * @pd_clk:            Look power domain as a clock\r
+ * @node:              List node to Voltage Domain\r
+ * @clk_list:          Head of Power Domain's Clocks List\r
+ */\r
+struct pd_node {\r
+       char                    *name;\r
+       int                     cur_volt;\r
+       unsigned char           pd_status;\r
+       struct vd_node          *vd;\r
+       //struct clk            *pd_clk;\r
+       struct list_head        node;\r
+       struct list_head        clk_list;\r
+};\r
+\r
+struct pd_node_lookup {\r
+       struct pd_node          *pd;\r
+};\r
+\r
+struct clk_list{\r
+       struct clk_node         *dvfs_clk;\r
+       struct list_head        node;\r
+};\r
+\r
+struct pds_list {\r
+       struct clk_list         clk_list;\r
+       struct pd_node          *pd;\r
+};\r
+\r
+struct depend_list {\r
+       int                     req_volt;\r
+       struct clk_node         *dvfs_clk;\r
+       struct vd_node          *dep_vd;\r
+       struct list_head        node2clk;\r
+       struct list_head        node2vd;\r
+       struct cpufreq_frequency_table  *dep_table;\r
+};\r
+\r
+struct depend_lookup {\r
+       char                    *clk_name;\r
+       struct clk_node         *dvfs_clk;\r
+       struct vd_node          *dep_vd;\r
+       struct depend_list      dep_list;\r
+       struct cpufreq_frequency_table  *dep_table;\r
+};\r
+\r
+/**\r
+ * struct clk_node:    To Store All dvfs clocks' info\r
+ * @name:              Dvfs clock's Name\r
+ * @set_freq:          Dvfs clock's Current Frequency\r
+ * @set_volt:          Dvfs clock's Current Voltage\r
+ * @enable_dvfs:       Sign if DVFS clock enable\r
+ * @clk:               System clk's point\r
+ * @pds:               Power Domains dvfs clock belongs to\r
+ * @vd:                        Voltage Domains dvfs clock belongs to\r
+ * @depend_list:       Dvfs Clock depend list\r
+ * @dvfs_nb:           Notify list\r
+ * @dvfs_table:                Frequency and voltage table for dvfs\r
+ * @clk_dvfs_target:   Callback function\r
+ */\r
+struct clk_node {\r
+       char                    *name;\r
+       int                     set_freq;       //KHZ\r
+       int                     set_volt;       //MV\r
+       int                     enable_dvfs;\r
+       int                     freq_limit_en;  //sign if use limit frequency\r
+       unsigned int            min_rate;       //limit min frequency\r
+       unsigned int            max_rate;       //limit max frequency\r
+       struct clk              *clk;\r
+       struct pds_list         *pds;\r
+       struct vd_node          *vd;\r
+       struct list_head        depend_list;\r
+       struct notifier_block   *dvfs_nb;\r
+       struct cpufreq_frequency_table  *dvfs_table;\r
+       clk_dvfs_target_callback        clk_dvfs_target;\r
+};\r
+\r
+struct dvfs_arm_table {\r
+       unsigned int    frequency; /* kHz - doesn't need to be in ascending\r
+                                   * order */\r
+       unsigned int    cpu_volt;     /* any */\r
+\r
+       unsigned int    logic_volt;\r
+};\r
+\r
+#ifdef CONFIG_DVFS\r
+int rk30_dvfs_init(void);\r
+int is_support_dvfs(struct clk_node *dvfs_info);\r
+int dvfs_set_rate(struct clk *clk, unsigned long rate);\r
+int clk_enable_dvfs(struct clk *clk);\r
+int clk_disable_dvfs(struct clk *clk);\r
+void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target);\r
+struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk);\r
+int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table);\r
+int dvfs_set_depend_table(struct clk *clk, char *vd_name, struct cpufreq_frequency_table *table);\r
+int dvfs_set_arm_logic_volt(struct dvfs_arm_table *dvfs_cpu_logic_table, struct cpufreq_frequency_table *cpu_dvfs_table, struct cpufreq_frequency_table *dep_cpu2core_table);\r
+struct regulator* dvfs_get_regulator(char *regulator_name);\r
+int dvfs_clk_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate);\r
+int dvfs_clk_disable_limit(struct clk *clk);\r
+\r
+void avs_init(void);\r
+void avs_init_val_get(int index,int vol,char *s);\r
+int avs_set_scal_val(u8 avs_base);\r
+int dvfs_avs_scale_table(struct clk* clk, char* depend_vd_name);\r
+#else\r
+static inline int rk30_dvfs_init(void) { return 0; }\r
+static inline int is_support_dvfs(struct clk_node *dvfs_info) { return 0; }\r
+static inline int dvfs_set_rate(struct clk *clk, unsigned long rate) { return 0; }\r
+static inline int clk_enable_dvfs(struct clk *clk) { return 0; }\r
+static inline int clk_disable_dvfs(struct clk *clk) { return 0; }\r
+static inline void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target) {}\r
+static inline struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk) { return NULL; }\r
+static inline int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table) { return 0; }\r
+static inline int dvfs_set_depend_table(struct clk *clk, char *vd_name, struct cpufreq_frequency_table *table) {return 0;}\r
+static inline int dvfs_set_arm_logic_volt(struct dvfs_arm_table *dvfs_cpu_logic_table, struct cpufreq_frequency_table *cpu_dvfs_table, struct cpufreq_frequency_table *dep_cpu2core_table){ return 0; }\r
+static inline struct regulator* dvfs_get_regulator(char *regulator_name){ return NULL; }\r
+static inline int dvfs_clk_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate){ return 0; }\r
+static inline int dvfs_clk_disable_limit(struct clk *clk){ return 0; };\r
+\r
+static inline void avs_init(void){};\r
+static inline void avs_init_val_get(int index, int vol, char *s){};\r
+static inline int avs_set_scal_val(u8 avs_base){ return 0; };\r
+static inline int dvfs_avs_scale_table(struct clk* clk, char* depend_vd_name){ return 0; };\r
+#endif\r
+\r
+#endif\r