aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrashant Gaikwad <pgaikwad@nvidia.com>2012-12-26 19:16:23 +0530
committerHaojian Zhuang <haojian.zhuang@linaro.org>2013-04-03 20:23:46 +0800
commit7f0b242a45fee8abc8e2568f2d1c27442ef656ef (patch)
tree3be6f58f75009759c413a0543bede747886392e8
parentfdb5363b312af9d6e671d45185c1a4b89312e44c (diff)
clk: JSON debugfs clock tree summary
Clock information is dumped in JSON format which is easy for machines to parse. Each clock is represented as an object which has same name as clock and following properties - enable_count - prepare_count - rate Output is verified using online JSON editor. Signed-off-by: Prashant Gaikwad <pgaikwad@nvidia.com> Signed-off-by: Mike Turquette <mturquette@linaro.org>
-rw-r--r--drivers/clk/clk.c75
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 8622b9de730..593a2e42d4a 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -96,6 +96,76 @@ static const struct file_operations clk_summary_fops = {
.release = single_release,
};
+static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+{
+ if (!c)
+ return;
+
+ seq_printf(s, "\"%s\": { ", c->name);
+ seq_printf(s, "\"enable_count\": %d,", c->enable_count);
+ seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
+ seq_printf(s, "\"rate\": %lu", c->rate);
+}
+
+static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+{
+ struct clk *child;
+ struct hlist_node *tmp;
+
+ if (!c)
+ return;
+
+ clk_dump_one(s, c, level);
+
+ hlist_for_each_entry(child, tmp, &c->children, child_node) {
+ seq_printf(s, ",");
+ clk_dump_subtree(s, child, level + 1);
+ }
+
+ seq_printf(s, "}");
+}
+
+static int clk_dump(struct seq_file *s, void *data)
+{
+ struct clk *c;
+ struct hlist_node *tmp;
+ bool first_node = true;
+
+ seq_printf(s, "{");
+
+ mutex_lock(&prepare_lock);
+
+ hlist_for_each_entry(c, tmp, &clk_root_list, child_node) {
+ if (!first_node)
+ seq_printf(s, ",");
+ first_node = false;
+ clk_dump_subtree(s, c, 0);
+ }
+
+ hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node) {
+ seq_printf(s, ",");
+ clk_dump_subtree(s, c, 0);
+ }
+
+ mutex_unlock(&prepare_lock);
+
+ seq_printf(s, "}");
+ return 0;
+}
+
+
+static int clk_dump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_dump, inode->i_private);
+}
+
+static const struct file_operations clk_dump_fops = {
+ .open = clk_dump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* caller must hold prepare_lock */
static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
{
@@ -241,6 +311,11 @@ static int __init clk_debug_init(void)
if (!d)
return -ENOMEM;
+ d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, NULL,
+ &clk_dump_fops);
+ if (!d)
+ return -ENOMEM;
+
orphandir = debugfs_create_dir("orphans", rootdir);
if (!orphandir)