aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/plat-omap/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-omap/clock.c')
-rw-r--r--arch/arm/plat-omap/clock.c129
1 files changed, 93 insertions, 36 deletions
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index 2946c193a7d..c2e741de020 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -1,7 +1,7 @@
/*
* linux/arch/arm/plat-omap/clock.c
*
- * Copyright (C) 2004 - 2005 Nokia corporation
+ * Copyright (C) 2004 - 2008 Nokia corporation
* Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
*
* Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
@@ -21,6 +21,8 @@
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/platform_device.h>
+#include <linux/cpufreq.h>
+#include <linux/debugfs.h>
#include <asm/io.h>
@@ -32,41 +34,6 @@ static DEFINE_SPINLOCK(clockfw_lock);
static struct clk_functions *arch_clock;
-#ifdef CONFIG_PM_DEBUG
-
-static void print_parents(struct clk *clk)
-{
- struct clk *p;
- int printed = 0;
-
- list_for_each_entry(p, &clocks, node) {
- if (p->parent == clk && p->usecount) {
- if (!clk->usecount && !printed) {
- printk("MISMATCH: %s\n", clk->name);
- printed = 1;
- }
- printk("\t%-15s\n", p->name);
- }
- }
-}
-
-void clk_print_usecounts(void)
-{
- unsigned long flags;
- struct clk *p;
-
- spin_lock_irqsave(&clockfw_lock, flags);
- list_for_each_entry(p, &clocks, node) {
- if (p->usecount)
- printk("%-15s: %d\n", p->name, p->usecount);
- print_parents(p);
-
- }
- spin_unlock_irqrestore(&clockfw_lock, flags);
-}
-
-#endif
-
/*-------------------------------------------------------------------------
* Standard clock functions defined in include/linux/clk.h
*-------------------------------------------------------------------------*/
@@ -445,3 +412,93 @@ int __init clk_init(struct clk_functions * custom_clocks)
return 0;
}
+#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)
+/*
+ * debugfs support to trace clock tree hierarchy and attributes
+ */
+static struct dentry *clk_debugfs_root;
+
+static int clk_debugfs_register_one(struct clk *c)
+{
+ int err;
+ struct dentry *d, *child;
+ struct clk *pa = c->parent;
+ char s[255];
+ char *p = s;
+
+ p += sprintf(p, "%s", c->name);
+ if (c->id != 0)
+ sprintf(p, ":%d", c->id);
+ d = debugfs_create_dir(s, pa ? pa->dent : clk_debugfs_root);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+ c->dent = d;
+
+ d = debugfs_create_u8("usecount", S_IRUGO, c->dent, (u8 *)&c->usecount);
+ if (IS_ERR(d)) {
+ err = PTR_ERR(d);
+ goto err_out;
+ }
+ d = debugfs_create_u32("rate", S_IRUGO, c->dent, (u32 *)&c->rate);
+ if (IS_ERR(d)) {
+ err = PTR_ERR(d);
+ goto err_out;
+ }
+ d = debugfs_create_x32("flags", S_IRUGO, c->dent, (u32 *)&c->flags);
+ if (IS_ERR(d)) {
+ err = PTR_ERR(d);
+ goto err_out;
+ }
+ return 0;
+
+err_out:
+ d = c->dent;
+ list_for_each_entry(child, &d->d_subdirs, d_u.d_child)
+ debugfs_remove(child);
+ debugfs_remove(c->dent);
+ return err;
+}
+
+static int clk_debugfs_register(struct clk *c)
+{
+ int err;
+ struct clk *pa = c->parent;
+
+ if (pa && !pa->dent) {
+ err = clk_debugfs_register(pa);
+ if (err)
+ return err;
+ }
+
+ if (!c->dent) {
+ err = clk_debugfs_register_one(c);
+ if (err)
+ return err;
+ }
+ return 0;
+}
+
+static int __init clk_debugfs_init(void)
+{
+ struct clk *c;
+ struct dentry *d;
+ int err;
+
+ d = debugfs_create_dir("clock", NULL);
+ if (IS_ERR(d))
+ return PTR_ERR(d);
+ clk_debugfs_root = d;
+
+ list_for_each_entry(c, &clocks, node) {
+ err = clk_debugfs_register(c);
+ if (err)
+ goto err_out;
+ }
+ return 0;
+err_out:
+ debugfs_remove(clk_debugfs_root); /* REVISIT: Cleanup correctly */
+ return err;
+}
+late_initcall(clk_debugfs_init);
+
+#endif /* defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) */