diff options
-rw-r--r-- | drivers/clk/clk.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 8622b9de7302..593a2e42d4af 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c | |||
@@ -96,6 +96,76 @@ static const struct file_operations clk_summary_fops = { | |||
96 | .release = single_release, | 96 | .release = single_release, |
97 | }; | 97 | }; |
98 | 98 | ||
99 | static void clk_dump_one(struct seq_file *s, struct clk *c, int level) | ||
100 | { | ||
101 | if (!c) | ||
102 | return; | ||
103 | |||
104 | seq_printf(s, "\"%s\": { ", c->name); | ||
105 | seq_printf(s, "\"enable_count\": %d,", c->enable_count); | ||
106 | seq_printf(s, "\"prepare_count\": %d,", c->prepare_count); | ||
107 | seq_printf(s, "\"rate\": %lu", c->rate); | ||
108 | } | ||
109 | |||
110 | static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level) | ||
111 | { | ||
112 | struct clk *child; | ||
113 | struct hlist_node *tmp; | ||
114 | |||
115 | if (!c) | ||
116 | return; | ||
117 | |||
118 | clk_dump_one(s, c, level); | ||
119 | |||
120 | hlist_for_each_entry(child, tmp, &c->children, child_node) { | ||
121 | seq_printf(s, ","); | ||
122 | clk_dump_subtree(s, child, level + 1); | ||
123 | } | ||
124 | |||
125 | seq_printf(s, "}"); | ||
126 | } | ||
127 | |||
128 | static int clk_dump(struct seq_file *s, void *data) | ||
129 | { | ||
130 | struct clk *c; | ||
131 | struct hlist_node *tmp; | ||
132 | bool first_node = true; | ||
133 | |||
134 | seq_printf(s, "{"); | ||
135 | |||
136 | mutex_lock(&prepare_lock); | ||
137 | |||
138 | hlist_for_each_entry(c, tmp, &clk_root_list, child_node) { | ||
139 | if (!first_node) | ||
140 | seq_printf(s, ","); | ||
141 | first_node = false; | ||
142 | clk_dump_subtree(s, c, 0); | ||
143 | } | ||
144 | |||
145 | hlist_for_each_entry(c, tmp, &clk_orphan_list, child_node) { | ||
146 | seq_printf(s, ","); | ||
147 | clk_dump_subtree(s, c, 0); | ||
148 | } | ||
149 | |||
150 | mutex_unlock(&prepare_lock); | ||
151 | |||
152 | seq_printf(s, "}"); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | |||
157 | static int clk_dump_open(struct inode *inode, struct file *file) | ||
158 | { | ||
159 | return single_open(file, clk_dump, inode->i_private); | ||
160 | } | ||
161 | |||
162 | static const struct file_operations clk_dump_fops = { | ||
163 | .open = clk_dump_open, | ||
164 | .read = seq_read, | ||
165 | .llseek = seq_lseek, | ||
166 | .release = single_release, | ||
167 | }; | ||
168 | |||
99 | /* caller must hold prepare_lock */ | 169 | /* caller must hold prepare_lock */ |
100 | static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) | 170 | static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) |
101 | { | 171 | { |
@@ -241,6 +311,11 @@ static int __init clk_debug_init(void) | |||
241 | if (!d) | 311 | if (!d) |
242 | return -ENOMEM; | 312 | return -ENOMEM; |
243 | 313 | ||
314 | d = debugfs_create_file("clk_dump", S_IRUGO, rootdir, NULL, | ||
315 | &clk_dump_fops); | ||
316 | if (!d) | ||
317 | return -ENOMEM; | ||
318 | |||
244 | orphandir = debugfs_create_dir("orphans", rootdir); | 319 | orphandir = debugfs_create_dir("orphans", rootdir); |
245 | 320 | ||
246 | if (!orphandir) | 321 | if (!orphandir) |