1 /* arch/arm/mach-rk30/rk30_dvfs.c
\r
3 * Copyright (C) 2012 ROCKCHIP, Inc.
\r
5 * This software is licensed under the terms of the GNU General Public
\r
6 * License version 2, as published by the Free Software Foundation, and
\r
7 * may be copied, distributed, and modified under those terms.
\r
9 * This program is distributed in the hope that it will be useful,
\r
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
12 * GNU General Public License for more details.
\r
16 #include <linux/kernel.h>
\r
17 #include <linux/err.h>
\r
18 #include <linux/spinlock.h>
\r
19 #include <linux/list.h>
\r
20 #include <linux/slab.h>
\r
21 #include <linux/clk.h>
\r
22 #include <linux/cpufreq.h>
\r
23 #include <mach/dvfs.h>
\r
24 #include <mach/clock.h>
\r
25 #include <linux/regulator/consumer.h>
\r
26 #include <linux/delay.h>
\r
27 #include <linux/io.h>
\r
28 #include <linux/hrtimer.h>
\r
30 #define MHz (1000 * 1000)
\r
31 static LIST_HEAD(rk_dvfs_tree);
\r
32 static DEFINE_MUTEX(mutex);
\r
33 static DEFINE_MUTEX(rk_dvfs_mutex);
\r
35 static int dump_dbg_map(char *buf);
\r
39 #define DVFS_STR_DISABLE(on) ((on)?"enable":"disable")
\r
41 #define get_volt_up_delay(new_volt, old_volt) \
\r
42 ((new_volt) > (old_volt) ? (((new_volt) - (old_volt)) >> 9) : 0)
\r
46 /**************************************vd regulator functions***************************************/
\r
47 static void dvfs_volt_up_delay(struct vd_node *vd,int new_volt, int old_volt)
\r
50 if(new_volt<=old_volt)
\r
52 if(vd->volt_time_flag>0)
\r
53 u_time=regulator_set_voltage_time(vd->regulator,old_volt,new_volt);
\r
56 if(u_time<0)// regulator is not suported time,useing default time
\r
58 DVFS_DBG("%s:vd %s is not suported getting delay time,so we use default\n",
\r
59 __FUNCTION__,vd->name);
\r
60 u_time=((new_volt) - (old_volt)) >> 9;
\r
62 DVFS_DBG("%s:vd %s volt %d to %d delay %d us\n",__FUNCTION__,vd->name,
\r
63 old_volt,new_volt,u_time);
\r
64 if (u_time >= 1000) {
\r
65 mdelay(u_time / 1000);
\r
66 udelay(u_time % 1000);
\r
67 DVFS_ERR("regulator set vol delay is larger 1ms,old is %d,new is %d\n",old_volt,new_volt);
\r
68 } else if (u_time) {
\r
72 int dvfs_regulator_set_voltage_readback(struct regulator *regulator, int min_uV, int max_uV)
\r
74 int ret = 0, read_back = 0;
\r
75 ret = dvfs_regulator_set_voltage(regulator, max_uV, max_uV);
\r
77 DVFS_ERR("%s now read back to check voltage\n", __func__);
\r
79 /* read back to judge if it is already effect */
\r
81 read_back = dvfs_regulator_get_voltage(regulator);
\r
82 if (read_back == max_uV) {
\r
83 DVFS_ERR("%s set ERROR but already effected, volt=%d\n", __func__, read_back);
\r
86 DVFS_ERR("%s set ERROR AND NOT effected, volt=%d\n", __func__, read_back);
\r
91 // for clk enable case to get vd regulator info
\r
92 void clk_enable_dvfs_regulator_check(struct vd_node *vd)
\r
94 vd->cur_volt = dvfs_regulator_get_voltage(vd->regulator);
\r
97 vd->volt_set_flag = DVFS_SET_VOLT_FAILURE;
\r
99 vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS;
\r
102 static void dvfs_get_vd_regulator_volt_list(struct vd_node *vd)
\r
104 unsigned i,selector=dvfs_regulator_count_voltages(vd->regulator);
\r
107 if(selector>VD_VOL_LIST_CNT)
\r
108 selector=VD_VOL_LIST_CNT;
\r
110 mutex_lock(&mutex);
\r
111 for (i = 0; i<selector; i++) {
\r
112 sel_volt=dvfs_regulator_list_voltage(vd->regulator,i);
\r
115 DVFS_WARNING("%s : selector=%u,but volt <=0\n",vd->name,i);
\r
118 vd->volt_list[i]=sel_volt;
\r
119 DVFS_DBG("%s:selector=%u,volt %d\n",vd->name,i,sel_volt);
\r
121 vd->n_voltages=selector;
\r
122 mutex_unlock(&mutex);
\r
126 static int vd_regulator_round_volt_max(struct vd_node *vd, int volt)
\r
131 for (i = 0; i<vd->n_voltages; i++) {
\r
132 sel_volt=vd->volt_list[i];
\r
135 DVFS_WARNING("%s:list_volt : selector=%u,but volt <=0\n",__FUNCTION__,i);
\r
144 static int vd_regulator_round_volt_min(struct vd_node *vd, int volt)
\r
149 for (i = 0; i<vd->n_voltages; i++) {
\r
150 sel_volt=vd->volt_list[i];
\r
153 DVFS_WARNING("%s:list_volt : selector=%u,but volt <=0\n",__FUNCTION__,i);
\r
159 return vd->volt_list[i-1];
\r
168 int vd_regulator_round_volt(struct vd_node *vd, int volt,int flags)
\r
170 if(!vd->n_voltages)
\r
172 if(flags==VD_LIST_RELATION_L)
\r
173 return vd_regulator_round_volt_min(vd,volt);
\r
175 return vd_regulator_round_volt_max(vd,volt);
\r
177 EXPORT_SYMBOL(vd_regulator_round_volt);
\r
180 static void dvfs_table_round_volt(struct clk_node *dvfs_clk)
\r
184 if(!dvfs_clk->dvfs_table||!dvfs_clk->vd||IS_ERR_OR_NULL(dvfs_clk->vd->regulator))
\r
186 mutex_lock(&mutex);
\r
187 for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {
\r
189 test_volt=vd_regulator_round_volt(dvfs_clk->vd,dvfs_clk->dvfs_table[i].index,VD_LIST_RELATION_H);
\r
192 DVFS_WARNING("clk %s:round_volt : is %d,but list <=0\n",dvfs_clk->name,dvfs_clk->dvfs_table[i].index);
\r
195 DVFS_DBG("clk %s:round_volt %d to %d\n",dvfs_clk->name,dvfs_clk->dvfs_table[i].index,test_volt);
\r
196 dvfs_clk->dvfs_table[i].index=test_volt;
\r
198 mutex_unlock(&mutex);
\r
200 void dvfs_vd_get_regulator_volt_time_info(struct vd_node *vd)
\r
202 if(vd->volt_time_flag<=0)// check regulator support get uping vol timer
\r
204 vd->volt_time_flag=dvfs_regulator_set_voltage_time(vd->regulator,vd->cur_volt,vd->cur_volt+200*1000);
\r
205 if(vd->volt_time_flag<0)
\r
207 DVFS_DBG("%s,vd %s volt_time is no support\n",__FUNCTION__,vd->name);
\r
211 DVFS_DBG("%s,vd %s volt_time is support,up 200mv need delay %d us\n",__FUNCTION__,vd->name,vd->volt_time_flag);
\r
217 void dvfs_vd_get_regulator_mode_info(struct vd_node *vd)
\r
219 //REGULATOR_MODE_FAST
\r
220 if(vd->mode_flag<=0)// check regulator support get uping vol timer
\r
222 vd->mode_flag=dvfs_regulator_get_mode(vd->regulator);
\r
223 if(vd->mode_flag==REGULATOR_MODE_FAST||vd->mode_flag==REGULATOR_MODE_NORMAL
\r
224 ||vd->mode_flag==REGULATOR_MODE_IDLE||vd->mode_flag==REGULATOR_MODE_STANDBY)
\r
226 if(dvfs_regulator_set_mode(vd->regulator,vd->mode_flag)<0)
\r
228 vd->mode_flag=0;// check again
\r
232 if(vd->mode_flag>0)
\r
234 DVFS_DBG("%s,vd %s mode(now is %d) support\n",__FUNCTION__,vd->name,vd->mode_flag);
\r
238 DVFS_DBG("%s,vd %s mode is not support now check\n",__FUNCTION__,vd->name);
\r
244 struct regulator *dvfs_get_regulator(char *regulator_name)
\r
246 struct vd_node *vd;
\r
247 list_for_each_entry(vd, &rk_dvfs_tree, node) {
\r
248 if (strcmp(regulator_name, vd->regulator_name) == 0) {
\r
249 return vd->regulator;
\r
255 /**************************************dvfs clocks functions***************************************/
\r
256 int dvfs_clk_enable_limit(struct clk *clk, unsigned int min_rate, unsigned max_rate)
\r
258 struct clk_node *dvfs_clk;
\r
260 dvfs_clk = clk->dvfs_info;
\r
262 dvfs_clk->freq_limit_en = 1;
\r
263 dvfs_clk->min_rate = min_rate;
\r
264 dvfs_clk->max_rate = max_rate;
\r
266 rate = clk_get_rate(clk);
\r
267 if (rate < min_rate)
\r
268 dvfs_clk_set_rate(clk, min_rate);
\r
269 else if (rate > max_rate)
\r
270 dvfs_clk_set_rate(clk, max_rate);
\r
274 int dvfs_clk_disable_limit(struct clk *clk)
\r
276 struct clk_node *dvfs_clk;
\r
277 dvfs_clk = clk->dvfs_info;
\r
279 dvfs_clk->freq_limit_en = 0;
\r
284 int dvfs_vd_clk_set_rate(struct clk *clk, unsigned long rate)
\r
287 struct clk_node *dvfs_info=clk_get_dvfs_info(clk);
\r
289 DVFS_DBG("%s(%s(%lu))\n", __func__, dvfs_info->name, rate);
\r
291 #if 0 // judge by reference func in rk
\r
292 if (dvfs_support_clk_set_rate(dvfs_info)==false) {
\r
293 DVFS_ERR("dvfs func:%s is not support!\n", __func__);
\r
298 if(dvfs_info->vd&&dvfs_info->vd->vd_dvfs_target){
\r
299 // mutex_lock(&vd->dvfs_mutex);
\r
300 mutex_lock(&rk_dvfs_mutex);
\r
301 ret = dvfs_info->vd->vd_dvfs_target(clk, rate);
\r
302 mutex_unlock(&rk_dvfs_mutex);
\r
303 // mutex_unlock(&vd->dvfs_mutex);
\r
307 DVFS_WARNING("%s(%s),vd is no target callback\n", __func__, clk->name);
\r
310 DVFS_DBG("%s(%s(%lu)),is end\n", __func__, clk->name, rate);
\r
313 EXPORT_SYMBOL(dvfs_vd_clk_set_rate);
\r
315 int dvfs_vd_clk_disable(struct clk *clk, int on)
\r
318 struct clk_node *dvfs_info=clk_get_dvfs_info(clk);
\r
319 DVFS_DBG("%s(%s(%s,%lu))\n", __func__, dvfs_info->name, DVFS_STR_DISABLE(on),clk_get_rate(clk));
\r
322 #if 0 // judge by reference func in rk
\r
323 if (dvfs_support_clk_disable(dvfs_info)==false) {
\r
324 DVFS_ERR("dvfs func:%s is not support!\n", __func__);
\r
329 if(dvfs_info->vd&&dvfs_info->vd->vd_clk_disable_target){
\r
330 // mutex_lock(&vd->dvfs_mutex);
\r
331 mutex_lock(&rk_dvfs_mutex);
\r
332 ret = dvfs_info->vd->vd_clk_disable_target(clk, on);
\r
333 mutex_unlock(&rk_dvfs_mutex);
\r
334 // mutex_unlock(&vd->dvfs_mutex);
\r
338 DVFS_WARNING("%s(%s),vd is no target callback\n", __func__, clk->name);
\r
341 DVFS_DBG("%s(%s(%s)),is end\n", __func__, dvfs_info->name, DVFS_STR_DISABLE(on));
\r
346 EXPORT_SYMBOL(dvfs_vd_clk_disable);
\r
348 static void dvfs_table_round_clk_rate(struct clk_node *dvfs_clk)
\r
351 unsigned long temp_rate;
\r
355 if(!dvfs_clk->dvfs_table||dvfs_clk->clk==NULL||is_suport_round_rate(dvfs_clk->clk)<0)
\r
358 mutex_lock(&mutex);
\r
359 for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {
\r
360 //ddr rate = real rate+flags
\r
361 flags=dvfs_clk->dvfs_table[i].frequency%1000;
\r
362 rate=(dvfs_clk->dvfs_table[i].frequency/1000)*1000;
\r
363 temp_rate=clk_round_rate(dvfs_clk->clk,rate*1000);
\r
366 DVFS_WARNING("clk %s:round_clk_rate : is %d,but round <=0",dvfs_clk->name,dvfs_clk->dvfs_table[i].frequency);
\r
370 /* Set rate unit as MHZ */
\r
371 if (temp_rate % MHz != 0)
\r
372 temp_rate = (temp_rate / MHz + 1) * MHz;
\r
374 temp_rate = (temp_rate / 1000) + flags;
\r
376 DVFS_DBG("clk %s round_clk_rate %d to %d\n",
\r
377 dvfs_clk->name,dvfs_clk->dvfs_table[i].frequency,(int)(temp_rate));
\r
379 dvfs_clk->dvfs_table[i].frequency=temp_rate;
\r
381 mutex_unlock(&mutex);
\r
384 /***************************************************************************************************/
\r
385 static int dvfs_clk_get_ref_volt_depend(struct depend_list *depend, int rate_khz,
\r
386 struct cpufreq_frequency_table *clk_fv)
\r
389 if (rate_khz == 0 || !depend || !depend->dep_table) {
\r
392 clk_fv->frequency = rate_khz;
\r
395 for (i = 0; (depend->dep_table[i].frequency != CPUFREQ_TABLE_END); i++) {
\r
396 if (depend->dep_table[i].frequency >= rate_khz) {
\r
397 clk_fv->frequency = depend->dep_table[i].frequency;
\r
398 clk_fv->index = depend->dep_table[i].index;
\r
402 clk_fv->frequency = 0;
\r
406 int dvfs_clk_get_ref_volt(struct clk_node *dvfs_clk, int rate_khz,
\r
407 struct cpufreq_frequency_table *clk_fv)
\r
410 if (rate_khz == 0 || !dvfs_clk || !dvfs_clk->dvfs_table) {
\r
411 /* since no need */
\r
414 clk_fv->frequency = rate_khz;
\r
417 for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {
\r
418 if (dvfs_clk->dvfs_table[i].frequency >= rate_khz) {
\r
419 clk_fv->frequency = dvfs_clk->dvfs_table[i].frequency;
\r
420 clk_fv->index = dvfs_clk->dvfs_table[i].index;
\r
421 // DVFS_DBG("%s,%s rate=%ukhz(vol=%d)\n",__func__,dvfs_clk->name,
\r
422 // clk_fv->frequency, clk_fv->index);
\r
426 clk_fv->frequency = 0;
\r
428 // DVFS_DBG("%s get corresponding voltage error! out of bound\n", dvfs_clk->name);
\r
432 static int dvfs_pd_get_newvolt_byclk(struct pd_node *pd, struct clk_node *dvfs_clk)
\r
434 struct clk_list *child;
\r
437 if (!pd || !dvfs_clk)
\r
440 if (dvfs_clk->set_volt >= pd->cur_volt) {
\r
441 return dvfs_clk->set_volt;
\r
444 list_for_each_entry(child, &pd->clk_list, node) {
\r
445 // DVFS_DBG("%s ,pd(%s),dvfs(%s),volt(%u)\n",__func__,pd->name,
\r
446 // dvfs_clk->name,dvfs_clk->set_volt);
\r
447 volt_max = max(volt_max, child->dvfs_clk->set_volt);
\r
452 void dvfs_update_clk_pds_volt(struct clk_node *dvfs_clk)
\r
454 struct pd_node *pd;
\r
458 for (i = 0; (dvfs_clk->pds[i].pd != NULL); i++) {
\r
459 pd = dvfs_clk->pds[i].pd;
\r
460 // DVFS_DBG("%s dvfs(%s),pd(%s)\n",__func__,dvfs_clk->name,pd->name);
\r
461 pd->cur_volt = dvfs_pd_get_newvolt_byclk(pd, dvfs_clk);
\r
465 int dvfs_vd_get_newvolt_bypd(struct vd_node *vd)
\r
467 struct pd_node *pd;
\r
468 struct depend_list *depend;
\r
469 int volt_max_vd = 0;
\r
470 list_for_each_entry(pd, &vd->pd_list, node) {
\r
471 // DVFS_DBG("%s pd(%s,%u)\n",__func__,pd->name,pd->cur_volt);
\r
472 volt_max_vd = max(volt_max_vd, pd->cur_volt);
\r
475 /* some clks depend on this voltage domain */
\r
476 if (!list_empty(&vd->req_volt_list)) {
\r
477 list_for_each_entry(depend, &vd->req_volt_list, node2vd) {
\r
478 volt_max_vd = max(volt_max_vd, depend->req_volt);
\r
481 return volt_max_vd;
\r
484 int dvfs_vd_get_newvolt_byclk(struct clk_node *dvfs_clk)
\r
488 dvfs_update_clk_pds_volt(dvfs_clk);
\r
489 return dvfs_vd_get_newvolt_bypd(dvfs_clk->vd);
\r
492 void dvfs_clk_register_set_rate_callback(struct clk *clk, clk_dvfs_target_callback clk_dvfs_target)
\r
494 struct clk_node *dvfs_clk = clk_get_dvfs_info(clk);
\r
495 if (IS_ERR_OR_NULL(dvfs_clk)) {
\r
496 DVFS_ERR("%s %s get dvfs_clk err\n", __func__, clk->name);
\r
499 dvfs_clk->clk_dvfs_target = clk_dvfs_target;
\r
502 /************************************************ freq volt table************************************/
\r
503 struct cpufreq_frequency_table *dvfs_get_freq_volt_table(struct clk *clk)
\r
505 struct clk_node *info = clk_get_dvfs_info(clk);
\r
506 struct cpufreq_frequency_table *table;
\r
507 if (!info || !info->dvfs_table) {
\r
510 mutex_lock(&mutex);
\r
511 table = info->dvfs_table;
\r
512 mutex_unlock(&mutex);
\r
515 EXPORT_SYMBOL(dvfs_get_freq_volt_table);
\r
517 int dvfs_set_freq_volt_table(struct clk *clk, struct cpufreq_frequency_table *table)
\r
519 struct clk_node *info = clk_get_dvfs_info(clk);
\r
531 mutex_lock(&mutex);
\r
532 info->dvfs_table = table;
\r
533 if(table[0].frequency!= CPUFREQ_TABLE_END)
\r
536 info->min_rate=(table[0].frequency/1000)*1000*1000;//to hz
\r
545 for(i=0;table[i].frequency!= CPUFREQ_TABLE_END;i++)
\r
549 info->max_rate=(table[i-1].frequency/1000)*1000*1000;
\r
551 DVFS_DBG("%s,clk %s,limit max=%lu,min=%lu\n",__FUNCTION__,info->name,info->max_rate,info->min_rate);
\r
553 mutex_unlock(&mutex);
\r
554 dvfs_table_round_clk_rate(info);
\r
555 dvfs_table_round_volt(info);
\r
558 EXPORT_SYMBOL(dvfs_set_freq_volt_table);
\r
560 int dvfs_set_depend_table(struct clk *clk, char *vd_name, struct cpufreq_frequency_table *table)
\r
562 struct vd_node *vd;
\r
563 struct depend_list *depend;
\r
564 struct clk_node *info;
\r
566 info = clk_get_dvfs_info(clk);
\r
567 if (!table || !info || !vd_name) {
\r
568 DVFS_ERR("%s :DVFS SET DEPEND TABLE ERROR! table or info or name empty\n", __func__);
\r
572 list_for_each_entry(vd, &rk_dvfs_tree, node) {
\r
573 if (0 == strcmp(vd->name, vd_name)) {
\r
574 DVFS_DBG("FOUND A MATCH\n");
\r
575 mutex_lock(&mutex);
\r
576 list_for_each_entry(depend, &info->depend_list, node2clk) {
\r
577 if (vd == depend->dep_vd && info == depend->dvfs_clk) {
\r
578 depend->dep_table = table;
\r
582 mutex_unlock(&mutex);
\r
586 DVFS_ERR("%s :DVFS SET DEPEND TABLE ERROR! can not find vd:%s\n", __func__, vd_name);
\r
591 int dvfs_set_arm_logic_volt(struct dvfs_arm_table *dvfs_cpu_logic_table,
\r
592 struct cpufreq_frequency_table *cpu_dvfs_table,
\r
593 struct cpufreq_frequency_table *dep_cpu2core_table)
\r
596 for (i = 0; dvfs_cpu_logic_table[i].frequency != CPUFREQ_TABLE_END; i++) {
\r
597 cpu_dvfs_table[i].frequency = dvfs_cpu_logic_table[i].frequency;
\r
598 cpu_dvfs_table[i].index = dvfs_cpu_logic_table[i].cpu_volt;
\r
600 dep_cpu2core_table[i].frequency = dvfs_cpu_logic_table[i].frequency;
\r
601 dep_cpu2core_table[i].index = dvfs_cpu_logic_table[i].logic_volt;
\r
604 cpu_dvfs_table[i].frequency = CPUFREQ_TABLE_END;
\r
605 dep_cpu2core_table[i].frequency = CPUFREQ_TABLE_END;
\r
607 dvfs_set_freq_volt_table(clk_get(NULL, "cpu"), cpu_dvfs_table);
\r
608 dvfs_set_depend_table(clk_get(NULL, "cpu"), "vd_core", dep_cpu2core_table);
\r
613 int clk_enable_dvfs(struct clk *clk)
\r
615 struct clk_node *dvfs_clk;
\r
616 struct cpufreq_frequency_table clk_fv;
\r
618 DVFS_ERR("clk enable dvfs error\n");
\r
621 dvfs_clk = clk_get_dvfs_info(clk);
\r
622 if (!dvfs_clk || !dvfs_clk->vd) {
\r
623 DVFS_ERR("%s clk(%s) not support dvfs!\n", __func__, clk->name);
\r
626 if (dvfs_clk->enable_dvfs == 0) {
\r
628 if (IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {
\r
629 //regulator = NULL;
\r
630 if (dvfs_clk->vd->regulator_name)
\r
631 dvfs_clk->vd->regulator = dvfs_regulator_get(NULL, dvfs_clk->vd->regulator_name);
\r
632 if (!IS_ERR_OR_NULL(dvfs_clk->vd->regulator)) {
\r
633 // DVFS_DBG("dvfs_regulator_get(%s)\n",dvfs_clk->vd->regulator_name);
\r
634 clk_enable_dvfs_regulator_check(dvfs_clk->vd);
\r
635 dvfs_get_vd_regulator_volt_list(dvfs_clk->vd);
\r
636 dvfs_vd_get_regulator_volt_time_info(dvfs_clk->vd);
\r
637 //dvfs_vd_get_regulator_mode_info(dvfs_clk->vd);
\r
639 //dvfs_clk->vd->regulator = NULL;
\r
640 dvfs_clk->enable_dvfs = 0;
\r
641 DVFS_ERR("%s can't get regulator in %s\n", dvfs_clk->name, __func__);
\r
645 clk_enable_dvfs_regulator_check(dvfs_clk->vd);
\r
646 // DVFS_DBG("%s(%s) vd volt=%u\n",__func__,dvfs_clk->name,dvfs_clk->vd->cur_volt);
\r
649 dvfs_table_round_clk_rate(dvfs_clk);
\r
650 dvfs_table_round_volt(dvfs_clk);
\r
651 dvfs_clk->set_freq = dvfs_clk_get_rate_kz(clk);
\r
652 // DVFS_DBG("%s ,%s get freq%u!\n",__func__,dvfs_clk->name,dvfs_clk->set_freq);
\r
654 if (dvfs_clk_get_ref_volt(dvfs_clk, dvfs_clk->set_freq, &clk_fv)) {
\r
655 if (dvfs_clk->dvfs_table[0].frequency == CPUFREQ_TABLE_END) {
\r
656 DVFS_ERR("%s table empty\n", __func__);
\r
657 dvfs_clk->enable_dvfs = 0;
\r
660 DVFS_WARNING("%s table all value are smaller than default, use default, just enable dvfs\n", __func__);
\r
661 dvfs_clk->enable_dvfs++;
\r
666 dvfs_clk->set_volt = clk_fv.index;
\r
667 dvfs_vd_get_newvolt_byclk(dvfs_clk);
\r
668 // DVFS_DBG("%s,%s,freq%u(ref vol %u)\n",__func__,dvfs_clk->name,
\r
669 // dvfs_clk->set_freq,dvfs_clk->set_volt);
\r
671 if (dvfs_clk->dvfs_nb) {
\r
672 // must unregister when clk disable
\r
673 clk_notifier_register(clk, dvfs_clk->dvfs_nb);
\r
678 if(dvfs_clk->vd->cur_volt < dvfs_clk->set_volt) {
\r
680 mutex_lock(&rk_dvfs_mutex);
\r
681 ret = dvfs_regulator_set_voltage_readback(dvfs_clk->vd->regulator, dvfs_clk->set_volt, dvfs_clk->set_volt);
\r
683 dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_FAILURE;
\r
684 dvfs_clk->enable_dvfs = 0;
\r
685 DVFS_ERR("dvfs enable clk %s,set volt error \n", dvfs_clk->name);
\r
686 mutex_unlock(&rk_dvfs_mutex);
\r
689 dvfs_clk->vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS;
\r
690 mutex_unlock(&rk_dvfs_mutex);
\r
693 dvfs_clk->enable_dvfs++;
\r
695 DVFS_ERR("dvfs already enable clk enable = %d!\n", dvfs_clk->enable_dvfs);
\r
696 dvfs_clk->enable_dvfs++;
\r
701 int clk_disable_dvfs(struct clk *clk)
\r
703 struct clk_node *dvfs_clk;
\r
704 dvfs_clk = clk->dvfs_info;
\r
705 if (!dvfs_clk->enable_dvfs) {
\r
706 DVFS_DBG("clk is already closed!\n");
\r
709 dvfs_clk->enable_dvfs--;
\r
710 if (0 == dvfs_clk->enable_dvfs) {
\r
711 DVFS_ERR("clk closed!\n");
\r
713 clk_notifier_unregister(clk, dvfs_clk->dvfs_nb);
\r
714 DVFS_DBG("clk unregister nb!\n");
\r
720 struct clk_node *dvfs_get_dvfs_clk_byname(char *name)
\r
722 struct vd_node *vd;
\r
723 struct pd_node *pd;
\r
724 struct clk_list *child;
\r
725 list_for_each_entry(vd, &rk_dvfs_tree, node) {
\r
726 list_for_each_entry(pd, &vd->pd_list, node) {
\r
727 list_for_each_entry(child, &pd->clk_list, node) {
\r
728 if (0 == strcmp(child->dvfs_clk->name, name)) {
\r
729 return child->dvfs_clk;
\r
736 int rk_regist_vd(struct vd_node *vd)
\r
740 mutex_lock(&mutex);
\r
741 //mutex_init(&vd->dvfs_mutex);
\r
742 list_add(&vd->node, &rk_dvfs_tree);
\r
743 INIT_LIST_HEAD(&vd->pd_list);
\r
744 INIT_LIST_HEAD(&vd->req_volt_list);
\r
746 vd->volt_time_flag=0;
\r
748 mutex_unlock(&mutex);
\r
752 int rk_regist_pd(struct pd_node_lookup *pd_lookup)
\r
754 struct vd_node *vd;
\r
755 struct pd_node *pd;
\r
757 mutex_lock(&mutex);
\r
758 pd = pd_lookup->pd;
\r
760 list_for_each_entry(vd, &rk_dvfs_tree, node) {
\r
761 if (vd == pd->vd) {
\r
762 list_add(&pd->node, &vd->pd_list);
\r
763 INIT_LIST_HEAD(&pd->clk_list);
\r
767 mutex_unlock(&mutex);
\r
771 int rk_regist_clk(struct clk_node *dvfs_clk)
\r
773 struct pd_node *pd;
\r
774 struct clk_list *child;
\r
781 if (!dvfs_clk->pds)
\r
783 mutex_lock(&mutex);
\r
784 dvfs_clk->enable_dvfs = 0;
\r
785 dvfs_clk->vd = dvfs_clk->pds[0].pd->vd;
\r
786 for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {
\r
787 child = &(dvfs_clk->pds[i].clk_list);
\r
788 child->dvfs_clk = dvfs_clk;
\r
789 pd = dvfs_clk->pds[i].pd;
\r
790 list_add(&child->node, &pd->clk_list);
\r
792 clk = dvfs_clk_get(NULL, dvfs_clk->name);
\r
793 dvfs_clk->clk = clk;
\r
794 clk_register_dvfs(dvfs_clk, clk);
\r
795 INIT_LIST_HEAD(&dvfs_clk->depend_list);
\r
796 mutex_unlock(&mutex);
\r
800 int rk_regist_depends(struct depend_lookup *dep_node)
\r
802 struct depend_list *depend_list;
\r
803 struct clk_node *dvfs_clk;
\r
806 DVFS_ERR("%s : DVFS BAD depend node!\n", __func__);
\r
810 if (!dep_node->clk_name || !dep_node->dep_vd) {
\r
811 DVFS_ERR("%s : DVFS BAD depend members!\n", __func__);
\r
815 depend_list = &dep_node->dep_list;
\r
816 dvfs_clk = dvfs_get_dvfs_clk_byname(dep_node->clk_name);
\r
818 mutex_lock(&mutex);
\r
820 depend_list->dvfs_clk = dvfs_clk;
\r
821 depend_list->dep_vd = dep_node->dep_vd;
\r
822 depend_list->dep_table = dep_node->dep_table;
\r
824 list_add(&depend_list->node2clk, &dvfs_clk->depend_list);
\r
825 list_add(&depend_list->node2vd, &depend_list->dep_vd->req_volt_list);
\r
827 mutex_unlock(&mutex);
\r
831 int correct_volt(int *volt_clk, int *volt_dep, int clk_biger_than_dep, int dep_biger_than_clk)
\r
833 int up_boundary = 0, low_boundary = 0;
\r
835 up_boundary = *volt_clk + dep_biger_than_clk;
\r
836 low_boundary = *volt_clk - clk_biger_than_dep;
\r
838 if (*volt_dep < low_boundary || *volt_dep > up_boundary) {
\r
840 if (*volt_dep < low_boundary) {
\r
841 *volt_dep = low_boundary;
\r
843 } else if (*volt_dep > up_boundary) {
\r
844 *volt_clk = *volt_dep - dep_biger_than_clk;
\r
851 int dvfs_scale_volt(struct vd_node *vd_clk, struct vd_node *vd_dep,
\r
852 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
854 struct regulator *regulator, *regulator_dep;
\r
855 int volt = 0, volt_dep = 0, step = 0, step_dep = 0;
\r
856 int volt_pre = 0, volt_dep_pre = 0;
\r
859 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
860 regulator = vd_clk->regulator;
\r
861 regulator_dep = vd_dep->regulator;
\r
863 if (IS_ERR_OR_NULL(regulator) || IS_ERR(regulator_dep)) {
\r
864 DVFS_ERR("%s dvfs_clk->vd->regulator or depend->dep_vd->regulator == NULL\n", __func__);
\r
869 volt_dep = volt_dep_old;
\r
871 step = volt_new - volt_old > 0 ? 1 : (-1);
\r
872 step_dep = volt_dep_new - volt_dep_old > 0 ? 1 : (-1);
\r
874 DVFS_DBG("step=%d step_dep=%d %d\n", step, step_dep, step * step_dep);
\r
876 DVFS_DBG("Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n",
\r
877 volt_new, volt_old, volt_dep_new, volt_dep_old);
\r
880 volt_dep_pre = volt_dep;
\r
881 if (step * step_dep < 0) {
\r
882 // target is between volt_old and volt_dep_old, just
\r
884 DVFS_DBG("step * step_dep < 0\n");
\r
886 volt_dep = volt_dep_new;
\r
888 } else if (step > 0) {
\r
890 DVFS_DBG("step > 0\n");
\r
892 if (volt > volt_dep) {
\r
893 if (volt_dep == volt_dep_new) {
\r
894 volt = volt_dep + clk_biger_than_dep;
\r
896 volt_dep = volt + dep_biger_than_clk;
\r
898 } else if (volt < volt_dep){
\r
899 if (volt == volt_new) {
\r
900 volt_dep = volt + dep_biger_than_clk;
\r
902 volt = volt_dep + clk_biger_than_dep;
\r
905 if (volt != volt_new)
\r
906 volt = volt_dep + clk_biger_than_dep;
\r
907 if (volt_dep != volt_dep_new)
\r
908 volt_dep = volt + dep_biger_than_clk;
\r
910 volt = volt > volt_new ? volt_new : volt;
\r
911 volt_dep = volt_dep > volt_dep_new ? volt_dep_new : volt_dep;
\r
913 } else if (step < 0) {
\r
915 DVFS_DBG("step < 0\n");
\r
916 if (volt > volt_dep) {
\r
917 if (volt == volt_new) {
\r
918 volt_dep = volt - clk_biger_than_dep;
\r
920 volt = volt_dep - dep_biger_than_clk;
\r
922 } else if (volt < volt_dep){
\r
923 if (volt_dep == volt_dep_new) {
\r
924 volt = volt_dep - dep_biger_than_clk;
\r
926 volt_dep = volt - clk_biger_than_dep;
\r
929 if (volt != volt_new)
\r
930 volt = volt_dep - dep_biger_than_clk;
\r
931 if (volt_dep != volt_dep_new)
\r
932 volt_dep = volt - clk_biger_than_dep;
\r
934 volt = volt < volt_new ? volt_new : volt;
\r
935 volt_dep = volt_dep < volt_dep_new ? volt_dep_new : volt_dep;
\r
938 DVFS_ERR("Oops, some bugs here:Volt_new=%d(old=%d), volt_dep_new=%d(dep_old=%d)\n",
\r
939 volt_new, volt_old, volt_dep_new, volt_dep_old);
\r
943 if (vd_clk->cur_volt != volt) {
\r
944 DVFS_DBG("\t\t%s:%d->%d\n", vd_clk->name, vd_clk->cur_volt, volt);
\r
945 ret = dvfs_regulator_set_voltage_readback(regulator, volt, volt);
\r
946 //udelay(get_volt_up_delay(volt, volt_pre));
\r
947 dvfs_volt_up_delay(vd_clk,volt, volt_pre);
\r
949 DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n",
\r
950 __func__, vd_clk->name, ret, volt_new, volt_old);
\r
953 vd_clk->cur_volt = volt;
\r
955 if (vd_dep->cur_volt != volt_dep) {
\r
956 DVFS_DBG("\t\t%s:%d->%d\n", vd_dep->name, vd_dep->cur_volt, volt_dep);
\r
957 ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep, volt_dep);
\r
958 //udelay(get_volt_up_delay(volt_dep, volt_dep_pre));
\r
959 dvfs_volt_up_delay(vd_dep,volt_dep, volt_dep_pre);
\r
961 DVFS_ERR("depend %s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n",
\r
962 __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old);
\r
965 vd_dep->cur_volt = volt_dep;
\r
968 DVFS_DBG("\t\tNOW:Volt=%d, volt_dep=%d\n", volt, volt_dep);
\r
970 } while (volt != volt_new || volt_dep != volt_dep_new);
\r
972 vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS;
\r
973 vd_clk->cur_volt = volt_new;
\r
977 DVFS_ERR("+++++++++++++++++FAIL AREA\n");
\r
978 vd_clk->cur_volt = volt_old;
\r
979 vd_dep->cur_volt = volt_dep_old;
\r
980 vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;
\r
981 ret = dvfs_regulator_set_voltage_readback(regulator, volt_old, volt_old);
\r
983 vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;
\r
984 DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n",
\r
985 __func__, vd_clk->name, ret, volt_new, volt_old);
\r
988 ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep_old, volt_dep_old);
\r
990 vd_dep->volt_set_flag = DVFS_SET_VOLT_FAILURE;
\r
991 DVFS_ERR("%s %s set callback voltage err ret = %d, Vnew = %d(was %d)mV\n",
\r
992 __func__, vd_dep->name, ret, volt_dep_new, volt_dep_old);
\r
998 int dvfs_scale_volt_direct(struct vd_node *vd_clk, int volt_new)
\r
1001 DVFS_DBG("ENTER %s, volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt);
\r
1002 if (IS_ERR_OR_NULL(vd_clk)) {
\r
1003 DVFS_ERR("%s vd_node error\n", __func__);
\r
1007 DVFS_DBG("ENTER %s, volt=%d(old=%d)\n", __func__, volt_new, vd_clk->cur_volt);
\r
1008 if (!IS_ERR_OR_NULL(vd_clk->regulator)) {
\r
1009 ret = dvfs_regulator_set_voltage_readback(vd_clk->regulator, volt_new, volt_new);
\r
1010 //udelay(get_volt_up_delay(volt_new, vd_clk->cur_volt));
\r
1011 dvfs_volt_up_delay(vd_clk,volt_new, vd_clk->cur_volt);
\r
1013 vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;
\r
1014 DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n",
\r
1015 __func__, vd_clk->name, ret, volt_new, vd_clk->cur_volt);
\r
1020 DVFS_ERR("%s up volt dvfs_clk->vd->regulator == NULL\n", __func__);
\r
1024 vd_clk->volt_set_flag = DVFS_SET_VOLT_SUCCESS;
\r
1025 vd_clk->cur_volt = volt_new;
\r
1031 int dvfs_scale_volt_bystep(struct vd_node *vd_clk, struct vd_node *vd_dep, int volt_new, int volt_dep_new,
\r
1032 int cur_clk_biger_than_dep, int cur_dep_biger_than_clk, int new_clk_biger_than_dep, int new_dep_biger_than_clk)
\r
1035 struct regulator *regulator, *regulator_dep;
\r
1036 int volt_new_corrected = 0, volt_dep_new_corrected = 0;
\r
1037 int volt_old = 0, volt_dep_old = 0;
\r
1040 volt_old = vd_clk->cur_volt;
\r
1041 volt_dep_old = vd_dep->cur_volt;
\r
1043 DVFS_DBG("ENTER %s, volt=%d(old=%d) vd_dep=%d(dep_old=%d)\n", __func__,
\r
1044 volt_new, volt_old, volt_dep_new, volt_dep_old);
\r
1045 DVFS_DBG("ENTER %s, VOLT_DIFF: clk_cur=%d(clk_new=%d) dep_cur=%d(dep_new=%d)\n", __func__,
\r
1046 cur_clk_biger_than_dep, new_clk_biger_than_dep,
\r
1047 cur_dep_biger_than_clk, new_dep_biger_than_clk);
\r
1049 volt_new_corrected = volt_new;
\r
1050 volt_dep_new_corrected = volt_dep_new;
\r
1051 correct_volt(&volt_new_corrected, &volt_dep_new_corrected, cur_clk_biger_than_dep, cur_dep_biger_than_clk);
\r
1052 ret = dvfs_scale_volt(vd_clk, vd_dep, volt_old, volt_new_corrected, volt_dep_old, volt_dep_new_corrected,
\r
1053 cur_clk_biger_than_dep, cur_dep_biger_than_clk);
\r
1055 vd_clk->volt_set_flag = DVFS_SET_VOLT_FAILURE;
\r
1056 DVFS_ERR("set volt error\n");
\r
1060 if (cur_clk_biger_than_dep != new_clk_biger_than_dep || cur_dep_biger_than_clk != new_dep_biger_than_clk) {
\r
1061 regulator = vd_clk->regulator;
\r
1062 regulator_dep = vd_dep->regulator;
\r
1064 volt_new_corrected = volt_new;
\r
1065 volt_dep_new_corrected = volt_dep_new;
\r
1066 correct_volt(&volt_new_corrected, &volt_dep_new_corrected, new_clk_biger_than_dep, new_dep_biger_than_clk);
\r
1068 if (vd_clk->cur_volt != volt_new_corrected) {
\r
1069 DVFS_DBG("%s:%d->%d\n", vd_clk->name, vd_clk->cur_volt, volt_new_corrected);
\r
1070 ret = dvfs_regulator_set_voltage_readback(regulator, volt_new_corrected, volt_new_corrected);
\r
1071 //udelay(get_volt_up_delay(volt_new_corrected, vd_clk->cur_volt));
\r
1072 dvfs_volt_up_delay(vd_clk,volt_new_corrected, vd_clk->cur_volt);
\r
1074 DVFS_ERR("%s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n",
\r
1075 __func__, vd_clk->name, ret, volt_new_corrected, vd_clk->cur_volt);
\r
1078 vd_clk->cur_volt = volt_new_corrected;
\r
1080 if (vd_dep->cur_volt != volt_dep_new_corrected) {
\r
1081 DVFS_DBG("%s:%d->%d\n", vd_clk->name, vd_clk->cur_volt, volt_dep_new_corrected);
\r
1082 ret = dvfs_regulator_set_voltage_readback(regulator_dep, volt_dep_new_corrected, volt_dep_new_corrected);
\r
1083 //udelay(get_volt_up_delay(volt_dep_new_corrected, vd_dep->cur_volt));
\r
1084 dvfs_volt_up_delay(vd_dep,volt_dep_new_corrected, vd_dep->cur_volt);
\r
1086 DVFS_ERR("depend %s %s set voltage up err ret = %d, Vnew = %d(was %d)mV\n",
\r
1087 __func__, vd_dep->name, ret, volt_dep_new_corrected, vd_dep->cur_volt);
\r
1090 vd_dep->cur_volt = volt_dep_new_corrected;
\r
1097 int dvfs_reset_volt(struct vd_node *dvfs_vd)
\r
1099 int flag_set_volt_correct = 0;
\r
1100 if (!IS_ERR_OR_NULL(dvfs_vd->regulator))
\r
1101 flag_set_volt_correct = dvfs_regulator_get_voltage(dvfs_vd->regulator);
\r
1103 DVFS_ERR("dvfs regulator is ERROR\n");
\r
1106 if (flag_set_volt_correct <= 0) {
\r
1107 DVFS_ERR("%s (vd:%s), try to reload volt ,by it is error again(%d)!!! stop scaling\n",
\r
1108 __func__, dvfs_vd->name, flag_set_volt_correct);
\r
1111 dvfs_vd->volt_set_flag = DVFS_SET_VOLT_SUCCESS;
\r
1112 DVFS_WARNING("%s (vd:%s), try to reload volt = %d\n",
\r
1113 __func__, dvfs_vd->name, flag_set_volt_correct);
\r
1115 /* Reset vd's voltage */
\r
1116 dvfs_vd->cur_volt = flag_set_volt_correct;
\r
1118 return dvfs_vd->cur_volt;
\r
1121 int dvfs_get_depend_volt(struct clk_node *dvfs_clk, struct vd_node *dvfs_vd_dep, int rate_new)
\r
1123 struct depend_list *depend;
\r
1124 struct cpufreq_frequency_table clk_fv_dep;
\r
1127 DVFS_DBG("ENTER %s, rate_new=%d\n", __func__, rate_new);
\r
1128 list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) {
\r
1129 DVFS_DBG("--round depend clk:%s(depend:%s)\n", depend->dvfs_clk->name, depend->dep_vd->name);
\r
1130 // this place just consider ONE depend voltage domain,
\r
1131 // multi-depends must have some differece
\r
1132 clk_fv_dep.index = 0;
\r
1133 if (depend->dep_vd == dvfs_vd_dep) {
\r
1134 ret = dvfs_clk_get_ref_volt_depend(depend, rate_new / 1000, &clk_fv_dep);
\r
1136 DVFS_ERR("%s get dvfs_ref_volt_depend error\n", __func__);
\r
1139 depend->req_volt = clk_fv_dep.index;
\r
1140 return depend->req_volt;
\r
1144 DVFS_ERR("%s can not find vd node %s\n", __func__, dvfs_vd_dep->name);
\r
1149 * dump_dbg_map() : Draw all informations of dvfs while debug
\r
1151 static int dump_dbg_map(char *buf)
\r
1154 struct vd_node *vd;
\r
1155 struct pd_node *pd, *clkparent;
\r
1156 struct clk_list *child;
\r
1157 struct clk_node *dvfs_clk;
\r
1158 struct depend_list *depend;
\r
1160 mutex_lock(&rk_dvfs_mutex);
\r
1162 printk( "-------------DVFS TREE-----------\n\n\n");
\r
1163 printk( "DVFS TREE:\n");
\r
1164 list_for_each_entry(vd, &rk_dvfs_tree, node) {
\r
1165 printk( "|\n|- voltage domain:%s\n", vd->name);
\r
1166 printk( "|- current voltage:%d\n", vd->cur_volt);
\r
1167 list_for_each_entry(depend, &vd->req_volt_list, node2vd) {
\r
1168 printk( "|- request voltage:%d, clk:%s\n", depend->req_volt, depend->dvfs_clk->name);
\r
1171 list_for_each_entry(pd, &vd->pd_list, node) {
\r
1172 printk( "| |\n| |- power domain:%s, status = %s, current volt = %d\n",
\r
1173 pd->name, (pd->pd_status == PD_ON) ? "ON" : "OFF", pd->cur_volt);
\r
1175 list_for_each_entry(child, &pd->clk_list, node) {
\r
1176 dvfs_clk = child->dvfs_clk;
\r
1177 printk( "| | |\n| | |- clock: %s current: rate %d, volt = %d, enable_dvfs = %s\n",
\r
1178 dvfs_clk->name, dvfs_clk->set_freq, dvfs_clk->set_volt,
\r
1179 dvfs_clk->enable_dvfs == 0 ? "DISABLE" : "ENABLE");
\r
1180 for (i = 0; dvfs_clk->pds[i].pd != NULL; i++) {
\r
1181 clkparent = dvfs_clk->pds[i].pd;
\r
1182 printk( "| | | |- clock parents: %s, vd_parent = %s\n",
\r
1183 clkparent->name, clkparent->vd->name);
\r
1186 for (i = 0; (dvfs_clk->dvfs_table[i].frequency != CPUFREQ_TABLE_END); i++) {
\r
1187 printk( "| | | |- freq = %d, volt = %d\n",
\r
1188 dvfs_clk->dvfs_table[i].frequency,
\r
1189 dvfs_clk->dvfs_table[i].index);
\r
1193 list_for_each_entry(depend, &dvfs_clk->depend_list, node2clk) {
\r
1194 printk( "| | | | |- DEPEND VD: %s\n", depend->dep_vd->name);
\r
1195 for (i = 0; (depend->dep_table[i].frequency != CPUFREQ_TABLE_END); i++) {
\r
1196 printk( "| | | | |- freq = %d, req_volt = %d\n",
\r
1197 depend->dep_table[i].frequency,
\r
1199 depend->dep_table[i].index);
\r
1205 printk( "-------------DVFS TREE END------------\n");
\r
1207 mutex_unlock(&rk_dvfs_mutex);
\r
1210 /*******************************AVS AREA****************************************/
\r
1212 * To use AVS function, you must call avs_init in machine_rk30_board_init(void)(board-rk30-sdk.c)
\r
1213 * And then call(vdd_log):
\r
1214 * regulator_set_voltage(dcdc, 1100000, 1100000);
\r
1215 * avs_init_val_get(1,1100000,"wm8326 init");
\r
1217 * avs_set_scal_val(AVS_BASE);
\r
1218 * in wm831x_post_init(board-rk30-sdk-wm8326.c)
\r
1219 * AVS_BASE can use 172
\r
1222 static struct avs_ctr_st *avs_ctr_data=NULL;
\r
1223 #define init_avs_times 10
\r
1224 #define init_avs_st_num 5
\r
1226 struct init_avs_st {
\r
1228 u8 paramet[init_avs_times];
\r
1233 static struct init_avs_st init_avs_paramet[init_avs_st_num];
\r
1235 void avs_board_init(struct avs_ctr_st *data)
\r
1238 avs_ctr_data=data;
\r
1240 void avs_init(void)
\r
1242 memset(&init_avs_paramet[0].is_set, 0, sizeof(init_avs_paramet));
\r
1243 if(avs_ctr_data&&avs_ctr_data->avs_init)
\r
1244 avs_ctr_data->avs_init();
\r
1245 avs_init_val_get(0, 1200000,"board_init");
\r
1247 static u8 rk_get_avs_val(void)
\r
1250 if(avs_ctr_data&&avs_ctr_data->avs_get_val)
\r
1252 return avs_ctr_data->avs_get_val();
\r
1257 /******************************int val get**************************************/
\r
1258 void avs_init_val_get(int index, int vol, char *s)
\r
1261 if(index >= init_avs_times)
\r
1263 init_avs_paramet[index].vol = vol;
\r
1264 init_avs_paramet[index].s = s;
\r
1265 init_avs_paramet[index].is_set++;
\r
1266 printk("DVFS MSG:\tAVS Value(index=%d): ", index);
\r
1267 for(i = 0; i < init_avs_times; i++) {
\r
1268 init_avs_paramet[index].paramet[i] = rk_get_avs_val();
\r
1270 printk("%d ", init_avs_paramet[index].paramet[i]);
\r
1274 int avs_set_scal_val(u8 avs_base)
\r
1279 /*************************interface to get avs value and dvfs tree*************************/
\r
1280 #define USE_NORMAL_TIME
\r
1281 #ifdef USE_NORMAL_TIME
\r
1282 static struct timer_list avs_timer;
\r
1284 static struct hrtimer dvfs_hrtimer;
\r
1287 static u32 avs_dyn_start = 0;
\r
1288 static u32 avs_dyn_data_cnt;
\r
1289 static u8 *avs_dyn_data = NULL;
\r
1290 static u32 show_line_cnt = 0;
\r
1291 static u8 dly_min;
\r
1292 static u8 dly_max;
\r
1294 #define val_per_line (30)
\r
1295 #define line_pre_show (30)
\r
1296 #define avs_dyn_data_num (3*1000*1000)
\r
1298 static u32 print_avs_init(char *buf)
\r
1303 for(j = 0; j < init_avs_st_num; j++) {
\r
1304 if(init_avs_paramet[j].vol <= 0)
\r
1306 s += sprintf(s, "%s ,vol=%d,paramet following\n",
\r
1307 init_avs_paramet[j].s, init_avs_paramet[j].vol);
\r
1308 for(i = 0; i < init_avs_times; i++) {
\r
1309 s += sprintf(s, "%d ", init_avs_paramet[j].paramet[i]);
\r
1312 s += sprintf(s, "\n");
\r
1317 static ssize_t avs_init_show(struct kobject *kobj, struct kobj_attribute *attr,
\r
1320 return print_avs_init(buf);
\r
1323 static ssize_t avs_init_store(struct kobject *kobj, struct kobj_attribute *attr,
\r
1324 const char *buf, size_t n)
\r
1329 static ssize_t avs_now_show(struct kobject *kobj, struct kobj_attribute *attr,
\r
1332 return sprintf(buf, "%d\n", rk_get_avs_val());
\r
1335 static ssize_t avs_now_store(struct kobject *kobj, struct kobj_attribute *attr,
\r
1336 const char *buf, size_t n)
\r
1340 static ssize_t avs_dyn_show(struct kobject *kobj, struct kobj_attribute *attr,
\r
1346 if(avs_dyn_data == NULL)
\r
1349 if(avs_dyn_start) {
\r
1352 end_cnt = (avs_dyn_data_cnt ? (avs_dyn_data_cnt - 1) : 0);
\r
1353 if(end_cnt > (line_pre_show * val_per_line))
\r
1354 start_cnt = end_cnt - (line_pre_show * val_per_line);
\r
1358 dly_min = avs_dyn_data[start_cnt];
\r
1359 dly_max = avs_dyn_data[start_cnt];
\r
1361 //s += sprintf(s,"data start=%d\n",i);
\r
1362 for(i = start_cnt; i <= end_cnt;) {
\r
1363 s += sprintf(s, "%d", avs_dyn_data[i]);
\r
1364 dly_min = min(dly_min, avs_dyn_data[i]);
\r
1365 dly_max = max(dly_max, avs_dyn_data[i]);
\r
1367 if(!(i % val_per_line)) {
\r
1368 s += sprintf(s, "\n");
\r
1370 s += sprintf(s, " ");
\r
1373 s += sprintf(s, "\n");
\r
1375 s += sprintf(s, "new data is from=%d to %d\n", start_cnt, end_cnt);
\r
1376 //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
1380 if(show_line_cnt == 0) {
\r
1381 dly_min = avs_dyn_data[0];
\r
1382 dly_max = avs_dyn_data[0];
\r
1386 for(i = show_line_cnt * (line_pre_show * val_per_line); i < avs_dyn_data_cnt;) {
\r
1387 s += sprintf(s, "%d", avs_dyn_data[i]);
\r
1388 dly_min = min(dly_min, avs_dyn_data[i]);
\r
1389 dly_max = max(dly_max, avs_dyn_data[i]);
\r
1391 if(!(i % val_per_line)) {
\r
1392 s += sprintf(s, "\n");
\r
1394 s += sprintf(s, " ");
\r
1395 if(i >= ((show_line_cnt + 1)*line_pre_show * val_per_line))
\r
1399 s += sprintf(s, "\n");
\r
1401 s += sprintf(s, "max=%d,min=%d,totolcnt=%d,line=%d\n",
\r
1402 dly_max, dly_min, avs_dyn_data_cnt, show_line_cnt);
\r
1404 if(((show_line_cnt * line_pre_show)*val_per_line) >= avs_dyn_data_cnt) {
\r
1406 show_line_cnt = 0;
\r
1408 s += sprintf(s, "data is over\n");
\r
1414 static ssize_t avs_dyn_store(struct kobject *kobj, struct kobj_attribute *attr,
\r
1415 const char *buf, size_t n)
\r
1419 if((strncmp(buf, "start", strlen("start")) == 0)) {
\r
1420 if(avs_dyn_data == NULL)
\r
1421 avs_dyn_data = kmalloc(avs_dyn_data_num, GFP_KERNEL);
\r
1422 if(avs_dyn_data == NULL)
\r
1425 pbuf = &buf[strlen("start")];
\r
1426 avs_dyn_data_cnt = 0;
\r
1427 show_line_cnt = 0;
\r
1428 if(avs_dyn_data) {
\r
1429 #ifdef USE_NORMAL_TIME
\r
1430 mod_timer(&avs_timer, jiffies + msecs_to_jiffies(5));
\r
1432 hrtimer_start(&dvfs_hrtimer, ktime_set(0, 5 * 1000 * 1000), HRTIMER_MODE_REL);
\r
1434 avs_dyn_start = 1;
\r
1436 //sscanf(pbuf, "%d %d", &number, &voltage);
\r
1437 //DVFS_DBG("---------ldo %d %d\n", number, voltage);
\r
1439 } else if((strncmp(buf, "stop", strlen("stop")) == 0)) {
\r
1440 pbuf = &buf[strlen("stop")];
\r
1441 avs_dyn_start = 0;
\r
1442 show_line_cnt = 0;
\r
1443 //sscanf(pbuf, "%d %d", &number, &voltage);
\r
1444 //DVFS_DBG("---------dcdc %d %d\n", number, voltage);
\r
1452 static ssize_t dvfs_tree_store(struct kobject *kobj, struct kobj_attribute *attr,
\r
1453 const char *buf, size_t n)
\r
1457 static ssize_t dvfs_tree_show(struct kobject *kobj, struct kobj_attribute *attr,
\r
1460 return dump_dbg_map(buf);
\r
1464 static void avs_timer_fn(unsigned long data)
\r
1467 for(i = 0; i < 1; i++) {
\r
1468 if(avs_dyn_data_cnt >= avs_dyn_data_num)
\r
1470 avs_dyn_data[avs_dyn_data_cnt] = rk_get_avs_val();
\r
1471 avs_dyn_data_cnt++;
\r
1474 mod_timer(&avs_timer, jiffies + msecs_to_jiffies(10));
\r
1477 struct hrtimer dvfs_hrtimer;
\r
1478 static enum hrtimer_restart dvfs_hrtimer_timer_func(struct hrtimer *timer)
\r
1481 for(i = 0; i < 1; i++) {
\r
1482 if(avs_dyn_data_cnt >= avs_dyn_data_num)
\r
1483 return HRTIMER_NORESTART;
\r
1484 avs_dyn_data[avs_dyn_data_cnt] = rk_get_avs_val();
\r
1485 avs_dyn_data_cnt++;
\r
1488 hrtimer_start(timer, ktime_set(0, 1 * 1000 * 1000), HRTIMER_MODE_REL);
\r
1492 /*********************************************************************************/
\r
1493 static struct kobject *dvfs_kobj;
\r
1494 struct dvfs_attribute {
\r
1495 struct attribute attr;
\r
1496 ssize_t (*show)(struct kobject *kobj, struct kobj_attribute *attr,
\r
1498 ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
\r
1499 const char *buf, size_t n);
\r
1502 static struct dvfs_attribute dvfs_attrs[] = {
\r
1503 /* node_name permision show_func store_func */
\r
1504 #ifdef CONFIG_RK_CLOCK_PROC
\r
1505 __ATTR(dvfs_tree, S_IRUSR | S_IRGRP | S_IWUSR, dvfs_tree_show, dvfs_tree_store),
\r
1506 __ATTR(avs_init, S_IRUSR | S_IRGRP | S_IWUSR, avs_init_show, avs_init_store),
\r
1507 // __ATTR(avs_dyn, S_IRUSR | S_IRGRP | S_IWUSR, avs_dyn_show, avs_dyn_store),
\r
1508 __ATTR(avs_now, S_IRUSR | S_IRGRP | S_IWUSR, avs_now_show, avs_now_store),
\r
1512 static int __init dvfs_init(void)
\r
1515 #ifdef USE_NORMAL_TIME
\r
1516 init_timer(&avs_timer);
\r
1517 //avs_timer.expires = jiffies+msecs_to_jiffies(1);
\r
1518 avs_timer.function = avs_timer_fn;
\r
1519 //mod_timer(&avs_timer,jiffies+msecs_to_jiffies(1));
\r
1521 hrtimer_init(&dvfs_hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
\r
1522 dvfs_hrtimer.function = dvfs_hrtimer_timer_func;
\r
1523 //hrtimer_start(&dvfs_hrtimer,ktime_set(0, 5*1000*1000),HRTIMER_MODE_REL);
\r
1526 dvfs_kobj = kobject_create_and_add("dvfs", NULL);
\r
1529 for (i = 0; i < ARRAY_SIZE(dvfs_attrs); i++) {
\r
1530 ret = sysfs_create_file(dvfs_kobj, &dvfs_attrs[i].attr);
\r
1532 DVFS_ERR("create index %d error\n", i);
\r
1539 subsys_initcall(dvfs_init);
\r