dvfs add disable clk interfacet
[firefly-linux-kernel-4.4.55.git] / arch / arm / plat-rk / clock.c
1 /* linux/arch/arm/mach-rk30/clock.c
2  *
3  * Copyright (C) 2012 ROCKCHIP, Inc.
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 #include <linux/clk.h>
16 #include <linux/clkdev.h>
17 #include <linux/err.h>
18 #include <linux/init.h>
19 #include <linux/kernel.h>
20 #include <linux/list.h>
21 #include <linux/module.h>
22 #include <linux/hardirq.h>
23 #include <linux/delay.h>
24 #include <mach/clock.h>
25 #include <mach/dvfs.h>
26 #include <linux/delay.h>
27
28 #define CLOCK_PRINTK_DBG(fmt, args...) pr_debug(fmt, ## args);
29 #define CLOCK_PRINTK_ERR(fmt, args...) pr_err(fmt, ## args);
30 #define CLOCK_PRINTK_LOG(fmt, args...) pr_debug(fmt, ## args);
31
32 /* Clock flags */
33 /* bit 0 is free */
34 #define RATE_FIXED              (1 << 1)        /* Fixed clock rate */
35 #define CONFIG_PARTICIPANT      (1 << 10)       /* Fundamental clock */
36
37 #define MHZ                     (1000*1000)
38 #define KHZ                     (1000)
39
40 static void __clk_recalc(struct clk *clk);
41 static void __propagate_rate(struct clk *tclk);
42 static void __clk_reparent(struct clk *child, struct clk *parent);
43
44 static LIST_HEAD(clocks);
45 static DEFINE_MUTEX(clocks_mutex);
46 static DEFINE_SPINLOCK(clockfw_lock);
47 static LIST_HEAD(root_clks);
48 static void clk_notify(struct clk *clk, unsigned long msg,
49                        unsigned long old_rate, unsigned long new_rate);
50
51 #define LOCK() do { WARN_ON(in_irq()); if (!irqs_disabled()) spin_lock_bh(&clockfw_lock); } while (0)
52 #define UNLOCK() do { if (!irqs_disabled()) spin_unlock_bh(&clockfw_lock); } while (0)
53 /**********************************************for clock data****************************************************/
54 struct list_head *get_rk_clocks_head(void)
55 {
56         return &clocks;
57 }
58
59 static struct clk *def_ops_clk=NULL;
60
61 void clk_register_default_ops_clk(struct clk *clk)
62 {
63         def_ops_clk=clk;
64 }
65
66 static struct clk *clk_default_get_parent(struct clk *clk)
67 {
68         if(def_ops_clk&&def_ops_clk->get_parent)
69                 return def_ops_clk->get_parent(clk);
70         else return NULL;
71
72
73
74 }
75 static int clk_default_set_parent(struct clk *clk, struct clk *parent)
76 {
77         if(def_ops_clk&&def_ops_clk->set_parent)
78                 return def_ops_clk->set_parent(clk,parent);
79         else
80                 return -EINVAL;
81 }
82
83 int __init clk_disable_unused(void)
84 {
85         struct clk *ck;
86         list_for_each_entry(ck, &clocks, node) {
87         if (ck->usecount > 0 || ck->mode == NULL || (ck->flags & IS_PD))
88                 continue;
89                 LOCK();
90                 clk_enable_nolock(ck);
91                 clk_disable_nolock(ck);
92                 UNLOCK();
93         }
94         return 0;
95 }
96 /**
97  * recalculate_root_clocks - recalculate and propagate all root clocks
98  *
99  * Recalculates all root clocks (clocks with no parent), which if the
100  * clock's .recalc is set correctly, should also propagate their rates.
101  * Called at init.
102  */
103 void clk_recalculate_root_clocks_nolock(void)
104 {
105         struct clk *clkp;
106
107         list_for_each_entry(clkp, &root_clks, sibling) {
108                 __clk_recalc(clkp);
109                 __propagate_rate(clkp);
110         }
111 }
112 /*
113 void clk_recalculate_root_clocks(void)
114 {
115         LOCK();
116         clk_recalculate_root_clocks_nolock();
117         UNLOCK();
118 }*/
119         
120 /**
121  * clk_preinit - initialize any fields in the struct clk before clk init
122  * @clk: struct clk * to initialize
123  *
124  * Initialize any struct clk fields needed before normal clk initialization
125  * can run.  No return value.
126  */
127 int clk_register(struct clk *clk)
128 {
129         if (clk == NULL || IS_ERR(clk))
130                 return -EINVAL;
131         //INIT_LIST_HEAD(&clk->sibling);
132         INIT_LIST_HEAD(&clk->children);
133
134         /*
135          * trap out already registered clocks
136          */
137         if (clk->node.next || clk->node.prev)
138                 return 0;
139
140         mutex_lock(&clocks_mutex);
141         if (clk->get_parent)
142                 clk->parent = clk->get_parent(clk);
143         else if (clk->parents)
144                 clk->parent =clk_default_get_parent(clk);
145         
146         if (clk->parent)
147                 list_add(&clk->sibling, &clk->parent->children);
148         else
149                 list_add(&clk->sibling, &root_clks);
150         list_add(&clk->node, &clocks);
151         mutex_unlock(&clocks_mutex);    
152         return 0;
153 }
154
155 /************************************************************/
156 static void __clk_recalc(struct clk *clk)
157 {
158         if (unlikely(clk->flags & RATE_FIXED))
159                 return;
160         if (clk->recalc)
161                 clk->rate = clk->recalc(clk);
162         else if (clk->parent)
163                 clk->rate = clk->parent->rate;
164 }
165 static void __clk_reparent(struct clk *child, struct clk *parent)
166 {
167         if (child->parent == parent)
168                 return;
169         //CLOCK_PRINTK_DBG("%s reparent to %s (was %s)\n", child->name, parent->name, ((child->parent) ? child->parent->name : "NULL"));
170
171         list_del_init(&child->sibling);
172         if (parent)
173                 list_add(&child->sibling, &parent->children);
174         child->parent = parent;
175 }
176
177 /* Propagate rate to children */
178 static void __propagate_rate(struct clk *tclk)
179 {
180         struct clk *clkp;
181         
182         //CLOCK_PRINTK_DBG("propagate_rate clk %s\n",clkp->name);
183         
184         list_for_each_entry(clkp, &tclk->children, sibling) {
185                 __clk_recalc(clkp);
186                 __propagate_rate(clkp);
187         }
188         //CLOCK_PRINTK_DBG("propagate_rate clk %s end\n",clkp->name);
189 }
190
191 int clk_enable_nolock(struct clk *clk)
192 {
193         int ret = 0;
194
195         if (clk->usecount == 0) {
196                 if (clk->parent) {
197                         ret = clk_enable_nolock(clk->parent);
198                         if (ret)
199                                 return ret;
200                 }
201
202                 if (clk->notifier_count)
203                         clk_notify(clk, CLK_PRE_ENABLE, clk->rate, clk->rate);
204                 if (clk->mode)
205                         ret = clk->mode(clk, 1);
206                 if (clk->notifier_count)
207                         clk_notify(clk, ret ? CLK_ABORT_ENABLE : CLK_POST_ENABLE, clk->rate, clk->rate);
208                 if (ret) {
209                         if (clk->parent)
210                                 clk_disable_nolock(clk->parent);
211                         return ret;
212                 }
213                 pr_debug("%s enabled\n", clk->name);
214         }
215         clk->usecount++;
216
217         return ret;
218 }
219  
220 void clk_disable_nolock(struct clk *clk)
221 {
222         if (clk->usecount == 0) {
223                 CLOCK_PRINTK_ERR(KERN_ERR "Trying disable clock %s with 0 usecount\n", clk->name);
224                 WARN_ON(1);
225                 return;
226         }
227         if (--clk->usecount == 0) {
228                 int ret = 0;
229                 if (clk->notifier_count)
230                         clk_notify(clk, CLK_PRE_DISABLE, clk->rate, clk->rate);
231                 if (clk->mode)
232                         ret = clk->mode(clk, 0);
233                 if (clk->notifier_count)
234                         clk_notify(clk, ret ? CLK_ABORT_DISABLE : CLK_POST_DISABLE, clk->rate, clk->rate);
235                 pr_debug("%s disabled\n", clk->name);
236                 if (ret == 0 && clk->parent)
237                         clk_disable_nolock(clk->parent);
238         }
239 }
240 /* Given a clock and a rate apply a clock specific rounding function */
241 long clk_round_rate_nolock(struct clk *clk, unsigned long rate)
242 {
243         if (clk->round_rate)
244                 return clk->round_rate(clk, rate);
245
246         if (clk->flags & RATE_FIXED)
247                 CLOCK_PRINTK_ERR("clock: clk_round_rate called on fixed-rate clock %s\n", clk->name);
248
249         return clk->rate;
250 }
251 int is_suport_round_rate(struct clk *clk)
252 {
253         return (clk->round_rate) ? 0:(-1);
254 }
255
256 int clk_set_rate_nolock(struct clk *clk, unsigned long rate)
257 {
258         int ret;
259         unsigned long old_rate;
260
261         if (rate == clk->rate)
262                 return 0;
263         if (clk->flags & CONFIG_PARTICIPANT)
264                 return -EINVAL;
265
266         if (!clk->set_rate)
267                 return -EINVAL;
268         
269         //CLOCK_PRINTK_LOG("**will set %s rate %lu\n", clk->name, rate);
270
271         old_rate = clk->rate;
272         if (clk->notifier_count)
273                 clk_notify(clk, CLK_PRE_RATE_CHANGE, old_rate, rate);
274
275         ret = clk->set_rate(clk, rate);
276
277         if (ret == 0) {
278                 __clk_recalc(clk);
279                 CLOCK_PRINTK_LOG("**set %s rate recalc=%lu\n",clk->name,clk->rate);
280                 __propagate_rate(clk);
281         }
282
283         if (clk->notifier_count)
284                 clk_notify(clk, ret ? CLK_ABORT_RATE_CHANGE : CLK_POST_RATE_CHANGE, old_rate, clk->rate);
285
286         return ret;
287 }
288  
289 int clk_set_parent_nolock(struct clk *clk, struct clk *parent)
290 {
291         int ret;
292         int enabled = clk->usecount > 0;
293         struct clk *old_parent = clk->parent;
294
295         if (clk->parent == parent)
296                 return 0;
297
298         /* if clk is already enabled, enable new parent first and disable old parent later. */
299         if (enabled)
300                 clk_enable_nolock(parent);
301
302         if (clk->set_parent)
303                 ret = clk->set_parent(clk, parent);
304         else
305                 ret = clk_default_set_parent(clk,parent);
306
307         if (ret == 0) {
308                 /* OK */
309                 
310                 //CLOCK_PRINTK_DBG("set_parent %s reparent\n",clk->name,parent->name);
311                 __clk_reparent(clk, parent);
312                 __clk_recalc(clk);
313                 __propagate_rate(clk);
314                 if (enabled)
315                         clk_disable_nolock(old_parent);
316         } else {
317                 //CLOCK_PRINTK_DBG("set_parent err\n",clk->name,parent->name);
318                 if (enabled)
319                         clk_disable_nolock(parent);
320         }
321
322         return ret;
323 }
324 /**********************************dvfs****************************************************/
325 int clk_set_rate_locked(struct clk * clk,unsigned long rate)
326 {
327         int ret;
328         //CLOCK_PRINTK_DBG("%s dvfs clk_set_locked\n",clk->name);
329         LOCK();
330     ret=clk_set_rate_nolock(clk, rate);;
331     UNLOCK();
332         return ret;
333         
334 }
335 void clk_register_dvfs(struct clk_node *dvfs_clk, struct clk *clk)
336 {
337     clk->dvfs_info = dvfs_clk;
338 }
339 int clk_set_enable_locked(struct clk * clk,int on)
340 {
341         int ret=0;
342         LOCK();
343         if(on)
344                 ret=clk_enable_nolock(clk);
345         else    
346                 clk_disable_nolock(clk);
347         UNLOCK();
348         return ret;
349 }
350 EXPORT_SYMBOL(clk_set_enable_locked);
351 /*-------------------------------------------------------------------------
352  * Optional clock functions defined in include/linux/clk.h
353  *-------------------------------------------------------------------------*/
354 #ifdef RK30_CLK_OFFBOARD_TEST
355 long rk30_clk_round_rate(struct clk *clk, unsigned long rate)
356 #else
357 long clk_round_rate(struct clk *clk, unsigned long rate)
358 #endif
359 {
360         long ret = 0;
361
362         if (clk == NULL || IS_ERR(clk))
363                 return ret;
364
365         LOCK();
366         ret = clk_round_rate_nolock(clk, rate);
367         UNLOCK();
368
369         return ret;
370 }
371
372 #ifdef RK30_CLK_OFFBOARD_TEST
373 EXPORT_SYMBOL(rk30_clk_round_rate);
374 #else
375 EXPORT_SYMBOL(clk_round_rate);
376 #endif
377
378 #ifdef RK30_CLK_OFFBOARD_TEST
379 unsigned long rk30_clk_get_rate(struct clk *clk)
380 #else
381 unsigned long clk_get_rate(struct clk *clk)
382 #endif
383 {
384         if (clk == NULL || IS_ERR(clk))
385                 return 0;
386
387         return clk->rate;
388 }
389 #ifdef RK30_CLK_OFFBOARD_TEST
390 EXPORT_SYMBOL(rk30_clk_get_rate);
391 #else
392 EXPORT_SYMBOL(clk_get_rate);
393 #endif
394
395
396 /* Set the clock rate for a clock source */
397 #ifdef RK30_CLK_OFFBOARD_TEST
398 int rk30_clk_set_rate(struct clk *clk, unsigned long rate)
399 #else
400 int clk_set_rate(struct clk *clk, unsigned long rate)
401 #endif
402 {
403         int ret = -EINVAL;
404         if (clk == NULL || IS_ERR(clk)){
405                 return ret;
406         }
407         if (rate == clk->rate)
408                 return 0;
409         if (dvfs_support_clk_set_rate(clk->dvfs_info)==true)
410                 return dvfs_vd_clk_set_rate(clk, rate);
411
412         LOCK();
413         ret = clk_set_rate_nolock(clk, rate);
414         UNLOCK();
415
416         return ret;
417 }
418 #ifdef RK30_CLK_OFFBOARD_TEST
419 EXPORT_SYMBOL(rk30_clk_set_rate);
420 #else
421 EXPORT_SYMBOL(clk_set_rate);
422 #endif
423
424
425 #ifdef RK30_CLK_OFFBOARD_TEST
426 int rk30_clk_set_parent(struct clk *clk, struct clk *parent)
427 #else
428 int clk_set_parent(struct clk *clk, struct clk *parent)
429 #endif
430 {
431         int ret = -EINVAL;
432
433         if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
434                 return ret;
435
436         if (clk->parents == NULL)
437                 return ret;
438
439         LOCK();
440         if (clk->usecount == 0)
441                 ret = clk_set_parent_nolock(clk, parent);
442         else
443                 ret = -EBUSY;
444         UNLOCK();
445
446         return ret;
447 }
448 int clk_set_parent_force(struct clk *clk, struct clk *parent)
449 {
450         int ret = -EINVAL;
451
452         if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
453                 return ret;
454
455         if (clk->parents == NULL)
456                 return ret;
457         LOCK();
458                 ret = clk_set_parent_nolock(clk, parent);       
459         UNLOCK();
460         return ret;
461 }
462
463 #ifdef RK30_CLK_OFFBOARD_TEST
464 EXPORT_SYMBOL(rk30_clk_set_parent);
465 #else
466 EXPORT_SYMBOL(clk_set_parent);
467 #endif
468
469 #ifdef RK30_CLK_OFFBOARD_TEST
470 struct clk *rk30_clk_get_parent(struct clk *clk)
471 #else
472 struct clk *clk_get_parent(struct clk *clk)
473 #endif
474 {
475         if (clk == NULL || IS_ERR(clk)) {
476                 return ERR_PTR(-EINVAL);
477         }
478         return clk->parent;
479 }
480
481 #ifdef RK30_CLK_OFFBOARD_TEST
482 EXPORT_SYMBOL(rk30_clk_get_parent);
483 #else
484 EXPORT_SYMBOL(clk_get_parent);
485 #endif
486
487 #ifdef RK30_CLK_OFFBOARD_TEST
488 void rk30_clk_disable(struct clk *clk)
489 #else
490 void clk_disable(struct clk *clk)
491 #endif
492 {
493         if (clk == NULL || IS_ERR(clk))
494                 return;
495         if (dvfs_support_clk_disable(clk->dvfs_info)==true)
496                 return dvfs_vd_clk_disable(clk, 0);
497
498         LOCK();
499         clk_disable_nolock(clk);
500         UNLOCK();
501 }
502 #ifdef RK30_CLK_OFFBOARD_TEST
503 EXPORT_SYMBOL(rk30_clk_disable);
504 #else
505 EXPORT_SYMBOL(clk_disable);
506 #endif
507
508 #ifdef RK30_CLK_OFFBOARD_TEST
509 int rk30_clk_enable(struct clk *clk)
510 #else
511 int  clk_enable(struct clk *clk)
512 #endif
513 {
514         int ret = 0;
515
516         if (clk == NULL || IS_ERR(clk))
517                 return -EINVAL;
518         if (dvfs_support_clk_disable(clk->dvfs_info)==true)
519                 return dvfs_vd_clk_disable(clk, 1);
520
521         LOCK();
522         ret = clk_enable_nolock(clk);
523         UNLOCK();
524
525         return ret;
526 }
527 #ifdef RK30_CLK_OFFBOARD_TEST
528 EXPORT_SYMBOL(rk30_clk_enable);
529 #else
530 EXPORT_SYMBOL(clk_enable);
531 #endif
532
533 /* Clk notifier implementation */
534
535 /**
536  * struct clk_notifier - associate a clk with a notifier
537  * @clk: struct clk * to associate the notifier with
538  * @notifier_head: a raw_notifier_head for this clk
539  * @node: linked list pointers
540  *
541  * A list of struct clk_notifier is maintained by the notifier code.
542  * An entry is created whenever code registers the first notifier on a
543  * particular @clk.  Future notifiers on that @clk are added to the
544  * @notifier_head.
545  */
546 struct clk_notifier {
547         struct clk                      *clk;
548         struct raw_notifier_head        notifier_head;
549         struct list_head                node;
550 };
551 static LIST_HEAD(clk_notifier_list);
552 /**
553  * _clk_free_notifier_chain - safely remove struct clk_notifier
554  * @cn: struct clk_notifier *
555  *
556  * Removes the struct clk_notifier @cn from the clk_notifier_list and
557  * frees it.
558  */
559 static void _clk_free_notifier_chain(struct clk_notifier *cn)
560 {
561         list_del(&cn->node);
562         kfree(cn);
563 }
564
565 /**
566  * clk_notify - call clk notifier chain
567  * @clk: struct clk * that is changing rate
568  * @msg: clk notifier type (i.e., CLK_POST_RATE_CHANGE; see mach/clock.h)
569  * @old_rate: old rate
570  * @new_rate: new rate
571  *
572  * Triggers a notifier call chain on the post-clk-rate-change notifier
573  * for clock 'clk'.  Passes a pointer to the struct clk and the
574  * previous and current rates to the notifier callback.  Intended to be
575  * called by internal clock code only.  No return value.
576  */
577 static void clk_notify(struct clk *clk, unsigned long msg,
578                        unsigned long old_rate, unsigned long new_rate)
579 {
580         struct clk_notifier *cn;
581         struct clk_notifier_data cnd;
582
583         cnd.clk = clk;
584         cnd.old_rate = old_rate;
585         cnd.new_rate = new_rate;
586
587         UNLOCK();
588         list_for_each_entry(cn, &clk_notifier_list, node) {
589                 if (cn->clk == clk) {
590                         pr_debug("%s msg %lu rate %lu -> %lu\n", clk->name, msg, old_rate, new_rate);
591                         raw_notifier_call_chain(&cn->notifier_head, msg, &cnd);
592                         break;
593                 }
594         }
595         LOCK();
596 }
597
598 /**
599  * clk_notifier_register - add a clock parameter change notifier
600  * @clk: struct clk * to watch
601  * @nb: struct notifier_block * with callback info
602  *
603  * Request notification for changes to the clock 'clk'.  This uses a
604  * blocking notifier.  Callback code must not call into the clock
605  * framework, as clocks_mutex is held.  Pre-notifier callbacks will be
606  * passed the previous and new rate of the clock.
607  *
608  * clk_notifier_register() must be called from process
609  * context.  Returns -EINVAL if called with null arguments, -ENOMEM
610  * upon allocation failure; otherwise, passes along the return value
611  * of blocking_notifier_chain_register().
612  */
613 int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
614 {
615         struct clk_notifier *cn = NULL, *cn_new = NULL;
616         int r;
617         struct clk *clkp;
618
619         if (!clk || IS_ERR(clk) || !nb)
620                 return -EINVAL;
621
622         mutex_lock(&clocks_mutex);
623
624         list_for_each_entry(cn, &clk_notifier_list, node)
625                 if (cn->clk == clk)
626                         break;
627
628         if (cn->clk != clk) {
629                 cn_new = kzalloc(sizeof(struct clk_notifier), GFP_KERNEL);
630                 if (!cn_new) {
631                         r = -ENOMEM;
632                         goto cnr_out;
633                 };
634
635                 cn_new->clk = clk;
636                 RAW_INIT_NOTIFIER_HEAD(&cn_new->notifier_head);
637
638                 list_add(&cn_new->node, &clk_notifier_list);
639                 cn = cn_new;
640         }
641
642         r = raw_notifier_chain_register(&cn->notifier_head, nb);
643         if (!IS_ERR_VALUE(r)) {
644                 clkp = clk;
645                 do {
646                         clkp->notifier_count++;
647                 } while ((clkp = clkp->parent));
648         } else {
649                 if (cn_new)
650                         _clk_free_notifier_chain(cn);
651         }
652
653 cnr_out:
654         mutex_unlock(&clocks_mutex);
655
656         return r;
657 }
658 EXPORT_SYMBOL(clk_notifier_register);
659
660 /**
661  * clk_notifier_unregister - remove a clock change notifier
662  * @clk: struct clk *
663  * @nb: struct notifier_block * with callback info
664  *
665  * Request no further notification for changes to clock 'clk'.
666  * Returns -EINVAL if called with null arguments; otherwise, passes
667  * along the return value of blocking_notifier_chain_unregister().
668  */
669 int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
670 {
671         struct clk_notifier *cn = NULL;
672         struct clk *clkp;
673         int r = -EINVAL;
674
675         if (!clk || IS_ERR(clk) || !nb)
676                 return -EINVAL;
677
678         mutex_lock(&clocks_mutex);
679
680         list_for_each_entry(cn, &clk_notifier_list, node)
681                 if (cn->clk == clk)
682                         break;
683
684         if (cn->clk != clk) {
685                 r = -ENOENT;
686                 goto cnu_out;
687         };
688
689         r = raw_notifier_chain_unregister(&cn->notifier_head, nb);
690         if (!IS_ERR_VALUE(r)) {
691                 clkp = clk;
692                 do {
693                         clkp->notifier_count--;
694                 } while ((clkp = clkp->parent));
695         }
696
697         /*
698          * XXX ugh, layering violation.  There should be some
699          * support in the notifier code for this.
700          */
701         if (!cn->notifier_head.head)
702                 _clk_free_notifier_chain(cn);
703
704 cnu_out:
705         mutex_unlock(&clocks_mutex);
706
707         return r;
708 }
709 EXPORT_SYMBOL(clk_notifier_unregister);
710
711 static struct clk_dump_ops *dump_def_ops;
712
713 void clk_register_dump_ops(struct clk_dump_ops *ops)
714 {
715         dump_def_ops=ops;
716 }
717
718 #ifdef CONFIG_RK_CLOCK_PROC
719 static int proc_clk_show(struct seq_file *s, void *v)
720 {
721         struct clk* clk;
722         
723         if(!dump_def_ops)
724                 return 0;
725
726         if(dump_def_ops->dump_clk)
727         {
728                 mutex_lock(&clocks_mutex);
729                 list_for_each_entry(clk, &clocks, node) {
730                         if (!clk->parent)
731                         {
732                                 dump_def_ops->dump_clk(s, clk, 0,&clocks);
733                         }
734                 }
735                 mutex_unlock(&clocks_mutex);
736         }
737         if(dump_def_ops->dump_regs)
738                 dump_def_ops->dump_regs(s);
739         return 0;
740 }
741
742
743 static int proc_clk_open(struct inode *inode, struct file *file)
744 {
745         return single_open(file, proc_clk_show, NULL);
746 }
747
748 static const struct file_operations proc_clk_fops = {
749         .open           = proc_clk_open,
750         .read           = seq_read,
751         .llseek         = seq_lseek,
752         .release        = single_release,
753 };
754
755 static int __init clk_proc_init(void)
756 {
757         proc_create("clocks", 0, NULL, &proc_clk_fops);
758         return 0;
759
760 }
761 late_initcall(clk_proc_init);
762 #endif /* CONFIG_RK_CLOCK_PROC */
763