Hi Yong, > Yes, it's also nice to have a file containing all the clock information > which you have implemented in the email. > Since we expect more features like enable/disable clocks in the debugfs, we > also like to have tree-like debugfs for clock information.
Sure; if you want the extended functionality, I think your tree approach is best. > Below is my draft implementation. Original implementation is from omap > platform clock code, and I adopted to common clock device. A couple of comments inline... > diff --git a/arch/arm/common/clkdev.c b/arch/arm/common/clkdev.c > index 9e4c4d9..e7a629a 100644 > --- a/arch/arm/common/clkdev.c > +++ b/arch/arm/common/clkdev.c > @@ -19,6 +19,7 @@ > > #include <linux/mutex.h> > #include <linux/clk.h> > #include <linux/slab.h> > > +#include <linux/debugfs.h> Minor nitpick: no need to put this #inlude on its own. > > #include <asm/clkdev.h> > > @@ -186,3 +187,128 @@ void clkdev_drop(struct clk_lookup *cl) > > kfree(cl); > > } > EXPORT_SYMBOL(clkdev_drop); > > + > +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) Might be good to add CONFIG_CLK_DEBUG (which would depend on CONFIG_PM_DEBUG and CONFIG_DEBUG_FS), so we can enable/disable it separately. > +/* > + * debugfs support to trace clock tree hierarchy and attributes > + */ > + > +static int open_file(struct inode *inode, struct file *file) I think you can replace this (and read_file, and rate_fops) with something like: 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, "%lu\n"); and then in clk_debugfs_register_one: debugfs_create_file("rate", S_IRUGO, clk->dentry, clk, &clk_debug_rate_fops); > +static struct dentry *clk_debugfs_root; > + > +static int clk_debugfs_register_one(struct clk *clk) > +{ > + int err; > + struct dentry *d, *child, *child_tmp; > + struct clk *pa = clk_get_parent(clk); > + > + if ((pa != ERR_PTR(-ENOSYS)) && pa) I'd suggest: if (pa && !IS_ERR(pa)) > + d = debugfs_create_dir(clk ? clk->name : "null", pa->dentry); > + else > + d = debugfs_create_dir(clk ? clk->name : "null", clk_debugfs_root); Why do you need to check for clk == NULL here? We probably don't want 'null' directories hanging around. > + > + 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, > &rate_fops); > + if (!d) { > + err = -ENOMEM; > + goto err_out; > + } > + > + return 0; > + > +err_out: > + d = clk->dentry; > + list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child) > + debugfs_remove(child); > + debugfs_remove(clk->dentry); > + return err; > +} > + > +static int clk_debugfs_register(struct clk *clk) > +{ > + int err; > + struct clk *pa; > + > + if (clk == ERR_PTR(-ENOSYS)) > + return -1; > + > + if (!clk) > + return -1; Do we need these checks? > + > + pa = clk_get_parent(clk); > + > + if ((pa != ERR_PTR(-ENOSYS)) && pa && !pa->dentry) { Again, this might be better: if (pa && !IS_ERR(pa) && !pa->dentry) .. but this makes me think we should probably drop the -ENOSYS return code from clk_get_parent, but that's a patch for another time.. :) > + err = clk_debugfs_register(pa); > + if (err) > + return err; > + } > + > + if (!clk->dentry) { > + err = clk_debugfs_register_one(clk); > + if (err) > + return err; > + } > + return 0; > +} > + > +static int __init clk_debugfs_init(void) > +{ > + struct clk_lookup *cl; > + struct dentry *d; > + int err; > + > + d = debugfs_create_dir("clock", NULL); I'd suggest "clocks" instead of "clock", but this is fairly minor. > diff --git a/arch/arm/plat-mxc/clock-common.c > b/arch/arm/plat-mxc/clock-common.c > index 8911813..96e19a4 100644 > --- a/arch/arm/plat-mxc/clock-common.c > +++ b/arch/arm/plat-mxc/clock-common.c > @@ -93,11 +93,14 @@ void clk_mxc_disable(struct clk *_clk) > > unsigned long clk_mxc_get_rate(struct clk *_clk) > { > > struct clk_mxc *clk = to_clk_mxc(_clk); > > - > + > > if (clk->get_rate) > return clk->get_rate(clk); > > - return clk_get_rate(clk->parent); > + if (clk->parent) > + return clk_get_rate(clk->parent); > + > + return 0; I see you found this oops too :) > diff --git a/include/linux/clk.h b/include/linux/clk.h > index 56416b7..0dc3443 100644 > --- a/include/linux/clk.h > +++ b/include/linux/clk.h > @@ -44,16 +44,22 @@ struct device; > > * registered with the arch-specific clock management code; the clock > > driver > > * code does not need to handle these. > */ > > +#define CLK_NAME_LEN 16 > > struct clk { > > const struct clk_ops *ops; > unsigned int enable_count; > struct mutex mutex; > > + char name[CLK_NAME_LEN]; > +#if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS) > + struct dentry *dentry; > +#endif Probably best to put 'name' into the CLK_DEBUG case; then you'll just need to use the __INIT_CLK_DEBUG macros in my previous patch. BTW, the spacing in the patch seems to be a little off; not sure if this is due to your mailer or the patch itself. If it's the latter, you might want to clean this up before submitting. Cheers, Jeremy _______________________________________________ linaro-dev mailing list linaro-dev@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-dev