blob: fc62fb5fc20bc44b5a76cb9e56d1344c7b4841e8 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Tony Lindgrenb9158552005-07-10 19:58:14 +01002 * linux/arch/arm/plat-omap/clock.c
Linus Torvalds1da177e2005-04-16 15:20:36 -07003 *
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +03004 * Copyright (C) 2004 - 2008 Nokia corporation
Linus Torvalds1da177e2005-04-16 15:20:36 -07005 * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
6 *
Tony Lindgren1a8bfa12005-11-10 14:26:50 +00007 * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
8 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/kernel.h>
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000014#include <linux/init.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/list.h>
16#include <linux/errno.h>
17#include <linux/err.h>
Tim Schmielau4e57b682005-10-30 15:03:48 -080018#include <linux/string.h>
Russell Kingf8ce2542006-01-07 16:15:52 +000019#include <linux/clk.h>
Arjan van de Ven00431702006-01-12 18:42:23 +000020#include <linux/mutex.h>
Russell Kingb851cb22008-05-22 16:38:50 +010021#include <linux/cpufreq.h>
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +030022#include <linux/debugfs.h>
Russell Kingfced80c2008-09-06 12:10:45 +010023#include <linux/io.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Tony Lindgrence491cf2009-10-20 09:40:47 -070025#include <plat/clock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Juha Yrjola7df34502006-06-26 16:16:22 -070027static LIST_HEAD(clocks);
Arjan van de Ven00431702006-01-12 18:42:23 +000028static DEFINE_MUTEX(clocks_mutex);
Juha Yrjola7df34502006-06-26 16:16:22 -070029static DEFINE_SPINLOCK(clockfw_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000031static struct clk_functions *arch_clock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070032
Paul Walmsley3587aeb2010-05-18 18:40:26 -060033/*
Tony Lindgrenf07adc52006-01-17 15:27:09 -080034 * Standard clock functions defined in include/linux/clk.h
Paul Walmsley3587aeb2010-05-18 18:40:26 -060035 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070036
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000037int clk_enable(struct clk *clk)
38{
39 unsigned long flags;
40 int ret = 0;
41
Tony Lindgrenb824efa2006-04-02 17:46:20 +010042 if (clk == NULL || IS_ERR(clk))
43 return -EINVAL;
44
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000045 spin_lock_irqsave(&clockfw_lock, flags);
Tony Lindgrenf07adc52006-01-17 15:27:09 -080046 if (arch_clock->clk_enable)
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000047 ret = arch_clock->clk_enable(clk);
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000048 spin_unlock_irqrestore(&clockfw_lock, flags);
49
50 return ret;
51}
52EXPORT_SYMBOL(clk_enable);
53
54void clk_disable(struct clk *clk)
55{
56 unsigned long flags;
57
Tony Lindgrenb824efa2006-04-02 17:46:20 +010058 if (clk == NULL || IS_ERR(clk))
59 return;
60
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000061 spin_lock_irqsave(&clockfw_lock, flags);
Tony Lindgren7cf95772007-08-07 05:20:00 -070062 if (clk->usecount == 0) {
Paul Walmsley6041c272010-10-08 11:40:20 -060063 pr_err("Trying disable clock %s with 0 usecount\n",
Tony Lindgren7cf95772007-08-07 05:20:00 -070064 clk->name);
65 WARN_ON(1);
66 goto out;
67 }
68
Tony Lindgrenf07adc52006-01-17 15:27:09 -080069 if (arch_clock->clk_disable)
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000070 arch_clock->clk_disable(clk);
Tony Lindgren7cf95772007-08-07 05:20:00 -070071
72out:
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000073 spin_unlock_irqrestore(&clockfw_lock, flags);
74}
75EXPORT_SYMBOL(clk_disable);
76
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000077unsigned long clk_get_rate(struct clk *clk)
78{
79 unsigned long flags;
80 unsigned long ret = 0;
81
Tony Lindgrenb824efa2006-04-02 17:46:20 +010082 if (clk == NULL || IS_ERR(clk))
83 return 0;
84
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000085 spin_lock_irqsave(&clockfw_lock, flags);
86 ret = clk->rate;
87 spin_unlock_irqrestore(&clockfw_lock, flags);
88
89 return ret;
90}
91EXPORT_SYMBOL(clk_get_rate);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092
Paul Walmsley3587aeb2010-05-18 18:40:26 -060093/*
Tony Lindgrenf07adc52006-01-17 15:27:09 -080094 * Optional clock functions defined in include/linux/clk.h
Paul Walmsley3587aeb2010-05-18 18:40:26 -060095 */
Tony Lindgrenbb13b5f2005-07-10 19:58:18 +010096
Linus Torvalds1da177e2005-04-16 15:20:36 -070097long clk_round_rate(struct clk *clk, unsigned long rate)
98{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +000099 unsigned long flags;
100 long ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100102 if (clk == NULL || IS_ERR(clk))
103 return ret;
104
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000105 spin_lock_irqsave(&clockfw_lock, flags);
106 if (arch_clock->clk_round_rate)
107 ret = arch_clock->clk_round_rate(clk, rate);
108 spin_unlock_irqrestore(&clockfw_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000110 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111}
112EXPORT_SYMBOL(clk_round_rate);
113
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114int clk_set_rate(struct clk *clk, unsigned long rate)
115{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000116 unsigned long flags;
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100117 int ret = -EINVAL;
118
119 if (clk == NULL || IS_ERR(clk))
120 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000122 spin_lock_irqsave(&clockfw_lock, flags);
123 if (arch_clock->clk_set_rate)
124 ret = arch_clock->clk_set_rate(clk, rate);
Russell Kingb5088c02009-01-29 19:33:19 +0000125 if (ret == 0) {
126 if (clk->recalc)
Russell King8b9dbc12009-02-12 10:12:59 +0000127 clk->rate = clk->recalc(clk);
Russell King3f0a8202009-01-31 10:05:51 +0000128 propagate_rate(clk);
Russell Kingb5088c02009-01-29 19:33:19 +0000129 }
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000130 spin_unlock_irqrestore(&clockfw_lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131
132 return ret;
133}
134EXPORT_SYMBOL(clk_set_rate);
135
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000136int clk_set_parent(struct clk *clk, struct clk *parent)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000138 unsigned long flags;
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100139 int ret = -EINVAL;
140
141 if (clk == NULL || IS_ERR(clk) || parent == NULL || IS_ERR(parent))
142 return ret;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000144 spin_lock_irqsave(&clockfw_lock, flags);
Russell King4da37822009-02-24 12:46:31 +0000145 if (clk->usecount == 0) {
146 if (arch_clock->clk_set_parent)
147 ret = arch_clock->clk_set_parent(clk, parent);
148 if (ret == 0) {
149 if (clk->recalc)
150 clk->rate = clk->recalc(clk);
151 propagate_rate(clk);
152 }
153 } else
154 ret = -EBUSY;
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000155 spin_unlock_irqrestore(&clockfw_lock, flags);
156
157 return ret;
158}
159EXPORT_SYMBOL(clk_set_parent);
160
161struct clk *clk_get_parent(struct clk *clk)
162{
Russell King2e777bf2009-02-08 17:49:22 +0000163 return clk->parent;
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000164}
165EXPORT_SYMBOL(clk_get_parent);
166
Paul Walmsley3587aeb2010-05-18 18:40:26 -0600167/*
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000168 * OMAP specific clock functions shared between omap1 and omap2
Paul Walmsley3587aeb2010-05-18 18:40:26 -0600169 */
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000170
Paul Walmsleyd3730192010-01-26 20:13:11 -0700171int __initdata mpurate;
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000172
173/*
174 * By default we use the rate set by the bootloader.
175 * You can override this with mpurate= cmdline option.
176 */
177static int __init omap_clk_setup(char *str)
178{
179 get_option(&str, &mpurate);
180
181 if (!mpurate)
182 return 1;
183
184 if (mpurate < 1000)
185 mpurate *= 1000000;
186
187 return 1;
188}
189__setup("mpurate=", omap_clk_setup);
190
191/* Used for clocks that always have same value as the parent clock */
Russell King8b9dbc12009-02-12 10:12:59 +0000192unsigned long followparent_recalc(struct clk *clk)
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000193{
Russell King8b9dbc12009-02-12 10:12:59 +0000194 return clk->parent->rate;
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000195}
196
Paul Walmsleye9b98f62010-01-26 20:12:57 -0700197/*
198 * Used for clocks that have the same value as the parent clock,
199 * divided by some factor
200 */
201unsigned long omap_fixed_divisor_recalc(struct clk *clk)
202{
203 WARN_ON(!clk->fixed_div);
204
205 return clk->parent->rate / clk->fixed_div;
206}
207
Russell King3f0a8202009-01-31 10:05:51 +0000208void clk_reparent(struct clk *child, struct clk *parent)
209{
210 list_del_init(&child->sibling);
211 if (parent)
212 list_add(&child->sibling, &parent->children);
213 child->parent = parent;
214
215 /* now do the debugfs renaming to reattach the child
216 to the proper parent */
217}
218
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000219/* Propagate rate to children */
Paul Walmsley3587aeb2010-05-18 18:40:26 -0600220void propagate_rate(struct clk *tclk)
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000221{
222 struct clk *clkp;
223
Russell King3f0a8202009-01-31 10:05:51 +0000224 list_for_each_entry(clkp, &tclk->children, sibling) {
Russell King9a5feda2008-11-13 13:44:15 +0000225 if (clkp->recalc)
Russell King8b9dbc12009-02-12 10:12:59 +0000226 clkp->rate = clkp->recalc(clkp);
Russell King3f0a8202009-01-31 10:05:51 +0000227 propagate_rate(clkp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229}
230
Russell King3f0a8202009-01-31 10:05:51 +0000231static LIST_HEAD(root_clks);
232
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200233/**
234 * recalculate_root_clocks - recalculate and propagate all root clocks
235 *
236 * Recalculates all root clocks (clocks with no parent), which if the
237 * clock's .recalc is set correctly, should also propagate their rates.
238 * Called at init.
239 */
240void recalculate_root_clocks(void)
241{
242 struct clk *clkp;
243
Russell King3f0a8202009-01-31 10:05:51 +0000244 list_for_each_entry(clkp, &root_clks, sibling) {
245 if (clkp->recalc)
Russell King8b9dbc12009-02-12 10:12:59 +0000246 clkp->rate = clkp->recalc(clkp);
Russell King3f0a8202009-01-31 10:05:51 +0000247 propagate_rate(clkp);
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200248 }
249}
250
Paul Walmsleyc8088112009-04-22 19:48:53 -0600251/**
Paul Walmsley79716872009-05-12 17:50:30 -0600252 * clk_preinit - initialize any fields in the struct clk before clk init
Paul Walmsleyc8088112009-04-22 19:48:53 -0600253 * @clk: struct clk * to initialize
254 *
255 * Initialize any struct clk fields needed before normal clk initialization
256 * can run. No return value.
257 */
Paul Walmsley79716872009-05-12 17:50:30 -0600258void clk_preinit(struct clk *clk)
Russell King3f0a8202009-01-31 10:05:51 +0000259{
260 INIT_LIST_HEAD(&clk->children);
261}
262
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263int clk_register(struct clk *clk)
264{
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100265 if (clk == NULL || IS_ERR(clk))
266 return -EINVAL;
267
Russell Kingdbb674d2009-01-22 16:08:04 +0000268 /*
269 * trap out already registered clocks
270 */
271 if (clk->node.next || clk->node.prev)
272 return 0;
273
Arjan van de Ven00431702006-01-12 18:42:23 +0000274 mutex_lock(&clocks_mutex);
Russell King3f0a8202009-01-31 10:05:51 +0000275 if (clk->parent)
276 list_add(&clk->sibling, &clk->parent->children);
277 else
278 list_add(&clk->sibling, &root_clks);
279
Linus Torvalds1da177e2005-04-16 15:20:36 -0700280 list_add(&clk->node, &clocks);
281 if (clk->init)
282 clk->init(clk);
Arjan van de Ven00431702006-01-12 18:42:23 +0000283 mutex_unlock(&clocks_mutex);
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000284
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 return 0;
286}
287EXPORT_SYMBOL(clk_register);
288
289void clk_unregister(struct clk *clk)
290{
Tony Lindgrenb824efa2006-04-02 17:46:20 +0100291 if (clk == NULL || IS_ERR(clk))
292 return;
293
Arjan van de Ven00431702006-01-12 18:42:23 +0000294 mutex_lock(&clocks_mutex);
Russell King3f0a8202009-01-31 10:05:51 +0000295 list_del(&clk->sibling);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700296 list_del(&clk->node);
Arjan van de Ven00431702006-01-12 18:42:23 +0000297 mutex_unlock(&clocks_mutex);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298}
299EXPORT_SYMBOL(clk_unregister);
300
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200301void clk_enable_init_clocks(void)
302{
303 struct clk *clkp;
304
305 list_for_each_entry(clkp, &clocks, node) {
306 if (clkp->flags & ENABLE_ON_INIT)
307 clk_enable(clkp);
308 }
309}
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200310
Paul Walmsley74be8422010-02-22 22:09:29 -0700311/**
312 * omap_clk_get_by_name - locate OMAP struct clk by its name
313 * @name: name of the struct clk to locate
314 *
315 * Locate an OMAP struct clk by its name. Assumes that struct clk
316 * names are unique. Returns NULL if not found or a pointer to the
317 * struct clk if found.
318 */
319struct clk *omap_clk_get_by_name(const char *name)
320{
321 struct clk *c;
322 struct clk *ret = NULL;
323
324 mutex_lock(&clocks_mutex);
325
326 list_for_each_entry(c, &clocks, node) {
327 if (!strcmp(c->name, name)) {
328 ret = c;
329 break;
330 }
331 }
332
333 mutex_unlock(&clocks_mutex);
334
335 return ret;
336}
337
Russell King897dcde2008-11-04 16:35:03 +0000338/*
339 * Low level helpers
340 */
341static int clkll_enable_null(struct clk *clk)
342{
343 return 0;
344}
345
346static void clkll_disable_null(struct clk *clk)
347{
348}
349
350const struct clkops clkops_null = {
351 .enable = clkll_enable_null,
352 .disable = clkll_disable_null,
353};
354
Santosh Shilimkar7c43d542010-02-22 22:09:40 -0700355/*
356 * Dummy clock
357 *
358 * Used for clock aliases that are needed on some OMAPs, but not others
359 */
360struct clk dummy_ck = {
361 .name = "dummy",
362 .ops = &clkops_null,
363};
364
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200365#ifdef CONFIG_CPU_FREQ
366void clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
367{
368 unsigned long flags;
369
370 spin_lock_irqsave(&clockfw_lock, flags);
371 if (arch_clock->clk_init_cpufreq_table)
372 arch_clock->clk_init_cpufreq_table(table);
373 spin_unlock_irqrestore(&clockfw_lock, flags);
374}
Paul Walmsley4e37c102010-01-08 15:23:16 -0700375
376void clk_exit_cpufreq_table(struct cpufreq_frequency_table **table)
377{
378 unsigned long flags;
379
380 spin_lock_irqsave(&clockfw_lock, flags);
381 if (arch_clock->clk_exit_cpufreq_table)
382 arch_clock->clk_exit_cpufreq_table(table);
383 spin_unlock_irqrestore(&clockfw_lock, flags);
384}
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200385#endif
386
Paul Walmsley3587aeb2010-05-18 18:40:26 -0600387/*
388 *
389 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300391#ifdef CONFIG_OMAP_RESET_CLOCKS
392/*
393 * Disable any unused clocks left on by the bootloader
394 */
395static int __init clk_disable_unused(void)
396{
397 struct clk *ck;
398 unsigned long flags;
399
Paul Walmsley6041c272010-10-08 11:40:20 -0600400 pr_info("clock: disabling unused clocks to save power\n");
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300401 list_for_each_entry(ck, &clocks, node) {
Russell King897dcde2008-11-04 16:35:03 +0000402 if (ck->ops == &clkops_null)
403 continue;
404
Paul Walmsley3587aeb2010-05-18 18:40:26 -0600405 if (ck->usecount > 0 || !ck->enable_reg)
Tony Lindgren90afd5c2006-09-25 13:27:20 +0300406 continue;
407
408 spin_lock_irqsave(&clockfw_lock, flags);
409 if (arch_clock->clk_disable_unused)
410 arch_clock->clk_disable_unused(ck);
411 spin_unlock_irqrestore(&clockfw_lock, flags);
412 }
413
414 return 0;
415}
416late_initcall(clk_disable_unused);
417#endif
418
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000419int __init clk_init(struct clk_functions * custom_clocks)
420{
421 if (!custom_clocks) {
Paul Walmsley6041c272010-10-08 11:40:20 -0600422 pr_err("No custom clock functions registered\n");
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000423 BUG();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700424 }
425
Tony Lindgren1a8bfa12005-11-10 14:26:50 +0000426 arch_clock = custom_clocks;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427
428 return 0;
429}
Paul Walmsley6b8858a2008-03-18 10:35:15 +0200430
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300431#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
432/*
433 * debugfs support to trace clock tree hierarchy and attributes
434 */
435static struct dentry *clk_debugfs_root;
436
437static int clk_debugfs_register_one(struct clk *c)
438{
439 int err;
Marek Skuczynski0825cc82010-01-31 10:00:54 +0000440 struct dentry *d, *child, *child_tmp;
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300441 struct clk *pa = c->parent;
442 char s[255];
443 char *p = s;
444
445 p += sprintf(p, "%s", c->name);
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300446 d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
Zhaoleie621f262008-11-04 13:35:07 -0800447 if (!d)
448 return -ENOMEM;
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300449 c->dent = d;
450
451 d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
Zhaoleie621f262008-11-04 13:35:07 -0800452 if (!d) {
453 err = -ENOMEM;
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300454 goto err_out;
455 }
456 d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
Zhaoleie621f262008-11-04 13:35:07 -0800457 if (!d) {
458 err = -ENOMEM;
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300459 goto err_out;
460 }
461 d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
Zhaoleie621f262008-11-04 13:35:07 -0800462 if (!d) {
463 err = -ENOMEM;
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300464 goto err_out;
465 }
466 return 0;
467
468err_out:
469 d = c->dent;
Marek Skuczynski0825cc82010-01-31 10:00:54 +0000470 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300471 debugfs_remove(child);
472 debugfs_remove(c->dent);
473 return err;
474}
475
476static int clk_debugfs_register(struct clk *c)
477{
478 int err;
479 struct clk *pa = c->parent;
480
481 if (pa && !pa->dent) {
482 err = clk_debugfs_register(pa);
483 if (err)
484 return err;
485 }
486
487 if (!c->dent) {
488 err = clk_debugfs_register_one(c);
489 if (err)
490 return err;
491 }
492 return 0;
493}
494
495static int __init clk_debugfs_init(void)
496{
497 struct clk *c;
498 struct dentry *d;
499 int err;
500
501 d = debugfs_create_dir("clock", NULL);
Zhaoleie621f262008-11-04 13:35:07 -0800502 if (!d)
503 return -ENOMEM;
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300504 clk_debugfs_root = d;
505
506 list_for_each_entry(c, &clocks, node) {
507 err = clk_debugfs_register(c);
508 if (err)
509 goto err_out;
510 }
511 return 0;
512err_out:
Hiroshi DOYUca4caa42009-09-03 20:14:06 +0300513 debugfs_remove_recursive(clk_debugfs_root);
Hiroshi DOYU137b3ee2008-07-03 12:24:41 +0300514 return err;
515}
516late_initcall(clk_debugfs_init);
517
518#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */