[PATCHv2] export clock debug information to user space

2010-12-13 Thread yong.shen
Change log:
1. rebased on the latest code of git://kernel.ubuntu.com/jk/dt/linux-2.6.git
2. changes according last round of comments



___
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev


[PATCHv2] export clock debug information to user space

2010-12-13 Thread yong.shen
From: Yong Shen 

create a tree-like directory structure in debugfs so user space
tools like powerdebug can generate readable clock information.
more functions tend to be add in, like individual clock enable/disable
by writing to this debug interface.

Signed-off-by: Yong Shen 
---
 arch/arm/common/Kconfig  |6 ++
 arch/arm/common/clkdev.c |3 +
 include/linux/clk.h  |   18 +++
 kernel/clk.c |  124 ++
 4 files changed, 151 insertions(+), 0 deletions(-)

diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
index 0a34c81..13d7cf9 100644
--- a/arch/arm/common/Kconfig
+++ b/arch/arm/common/Kconfig
@@ -41,3 +41,9 @@ config SHARP_SCOOP
 config COMMON_CLKDEV
bool
select HAVE_CLK
+
+config CLK_DEBUG
+   bool "clock debug information export to user space"
+   depends on USE_COMMON_STRUCT_CLK && PM_DEBUG && DEBUG_FS
+   help
+ export clk debug information to user space
diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c
index 9e4c4d9..1d08fb3 100644
--- a/arch/arm/common/clkdev.c
+++ b/arch/arm/common/clkdev.c
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -104,6 +105,7 @@ EXPORT_SYMBOL(clk_put);
 
 void clkdev_add(struct clk_lookup *cl)
 {
+   clk_debug_register(cl->clk);
mutex_lock(&clocks_mutex);
list_add_tail(&cl->node, &clocks);
mutex_unlock(&clocks_mutex);
@@ -114,6 +116,7 @@ void __init clkdev_add_table(struct clk_lookup *cl, size_t 
num)
 {
mutex_lock(&clocks_mutex);
while (num--) {
+   clk_debug_register(cl->clk);
list_add_tail(&cl->node, &clocks);
cl++;
}
diff --git a/include/linux/clk.h b/include/linux/clk.h
index ae7e4ed..bf9396a 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -64,14 +64,26 @@ struct clk {
struct mutexmutex;
spinlock_t  spinlock;
} lock;
+#ifdef CONFIG_CLK_DEBUG
+#define CLK_NAME_LEN 32
+   char name[CLK_NAME_LEN];
+   struct dentry   *dentry;
+#endif
 };
 
+#ifdef CONFIG_CLK_DEBUG
+#define __INIT_CLK_DEBUG(n) .name = #n,
+#else
+#define __INIT_CLK_DEBUG(n)
+#endif
+
 /* static initialiser for non-atomic clocks */
 #define INIT_CLK(name, o) {\
.ops= &o,   \
.enable_count   = 0,\
.flags  = 0,\
.lock.mutex = __MUTEX_INITIALIZER(name.lock.mutex), \
+   __INIT_CLK_DEBUG(name)  \
 }
 
 /* static initialiser for atomic clocks */
@@ -308,4 +320,10 @@ struct clk *clk_get_sys(const char *dev_id, const char 
*con_id);
 int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
struct device *dev);
 
+#ifdef CONFIG_CLK_DEBUG
+void clk_debug_register(struct clk *clk);
+#else
+static inline void clk_debug_register(struct clk *clk) {}
+#endif
+
 #endif
diff --git a/kernel/clk.c b/kernel/clk.c
index 2779abb..89996f3 100644
--- a/kernel/clk.c
+++ b/kernel/clk.c
@@ -10,6 +10,8 @@
 
 #include 
 #include 
+#include 
+#include 
 
 int clk_enable(struct clk *clk)
 {
@@ -112,3 +114,125 @@ struct clk_ops clk_fixed_ops = {
.get_rate = clk_fixed_get_rate,
 };
 EXPORT_SYMBOL_GPL(clk_fixed_ops);
+
+#ifdef CONFIG_CLK_DEBUG
+/*
+ * debugfs support to trace clock tree hierarchy and attributes
+ */
+static int clk_debug_rate_get(void *data, u64 *val)
+{
+   struct clk *clk = data;
+
+   *val = (u64)clk_get_rate(clk);
+   return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(clk_debug_rate_fops, clk_debug_rate_get, NULL,
+   "%llu\n");
+
+
+static struct dentry *clk_root;
+static int clk_debug_register_one(struct clk *clk)
+{
+   int err;
+   struct dentry *d, *child, *child_tmp;
+   struct clk *pa = clk_get_parent(clk);
+
+   if (pa && !IS_ERR(pa))
+   d = debugfs_create_dir(clk->name, pa->dentry);
+   else {
+   if (!clk_root)
+   clk_root = debugfs_create_dir("clocks", NULL);
+   if (!clk_root)
+   return -ENOMEM;
+   d = debugfs_create_dir(clk->name, clk_root);
+   }
+
+   if (!d)
+   return -ENOMEM;
+
+   clk->dentry = d;
+
+   d = debugfs_create_u32("enable_count", S_IRUGO, clk->dentry,
+   (u32 *)&clk->enable_count);
+   if (!d) {
+   err = -ENOMEM;
+   goto err_out;
+   }
+
+   d = debugfs_create_file("rate", S_IRUGO, clk->dentry, (void *)clk,
+   &clk_debug_rate_fops);
+   if (!d) {
+   err = -ENOMEM;
+   goto err_out;
+   }
+
+   return 0;
+
+err_out:
+   d = clk->dentry;
+   list_for_each_entry_safe(child, chi