diff options
author | Eric Miao <eric.miao@canonical.com> | 2011-08-23 22:58:33 +0800 |
---|---|---|
committer | Eric Miao <eric.miao@linaro.org> | 2011-10-14 09:56:47 +0800 |
commit | aaa07fd52ad4d41cb1f11831d68e0229a3f8383e (patch) | |
tree | 4c5ec15b18327bd02e33b67f435e887edbe7d7fb | |
parent | eb760591e788cebcb45c003ab3e04fd2d0372bf6 (diff) |
imx: add clock debug implementation
Signed-off-by: Yong Shen <yong.shen@linaro.org>
Signed-off-by: Eric Miao <eric.miao@linaro.org>
-rw-r--r-- | arch/arm/plat-mxc/Kconfig | 7 | ||||
-rw-r--r-- | arch/arm/plat-mxc/clock.c | 123 | ||||
-rw-r--r-- | arch/arm/plat-mxc/include/mach/clock.h | 13 |
3 files changed, 141 insertions, 2 deletions
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig index a5353fc0793..39f4d768aea 100644 --- a/arch/arm/plat-mxc/Kconfig +++ b/arch/arm/plat-mxc/Kconfig @@ -122,4 +122,11 @@ config IRAM_ALLOC bool select GENERIC_ALLOCATOR +config CLK_DEBUG + bool "clock debug information export to user space" + depends on PM_DEBUG && DEBUG_FS + default n + help + export clk debug information to user space + endif diff --git a/arch/arm/plat-mxc/clock.c b/arch/arm/plat-mxc/clock.c index 2ed3ab173ad..cf04908ec84 100644 --- a/arch/arm/plat-mxc/clock.c +++ b/arch/arm/plat-mxc/clock.c @@ -4,7 +4,7 @@ * Copyright (C) 2004 - 2005 Nokia corporation * Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com> * Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com> - * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2007-2011 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * This program is free software; you can redistribute it and/or @@ -37,6 +37,8 @@ #include <linux/proc_fs.h> #include <linux/semaphore.h> #include <linux/string.h> +#include <linux/slab.h> +#include <linux/debugfs.h> #include <mach/clock.h> #include <mach/hardware.h> @@ -244,3 +246,122 @@ unsigned long mxc_decode_pll(unsigned int reg_val, u32 freq) return ll; } + +#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("clock", NULL); + if (!clk_root) + return -ENOMEM; + d = debugfs_create_dir(clk->name, clk_root); + } + + if (!d) + return -ENOMEM; + + clk->dentry = d; + + d = debugfs_create_u8("enable_count", S_IRUGO, clk->dentry, + (u8 *)&clk->usecount); + 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, child_tmp, &d->d_subdirs, d_u.d_child) + debugfs_remove(child); + debugfs_remove(clk->dentry); + return err; +} + +struct preinit_clk { + struct list_head list; + struct clk *clk; +}; +static LIST_HEAD(preinit_clks); +static DEFINE_MUTEX(preinit_lock); +static int init_done; + +void clk_debug_register(struct clk *clk) +{ + int err; + struct clk *pa; + + if (init_done) { + pa = clk_get_parent(clk); + + if (pa && !IS_ERR(pa) && !pa->dentry) + clk_debug_register(pa); + + if (!clk->dentry) { + err = clk_debug_register_one(clk); + if (err) + return; + } + } else { + struct preinit_clk *p; + mutex_lock(&preinit_lock); + p = kmalloc(sizeof(*p), GFP_KERNEL); + if (p) { + p->clk = clk; + list_add(&p->list, &preinit_clks); + } + mutex_unlock(&preinit_lock); + } +} +EXPORT_SYMBOL_GPL(clk_debug_register); + +static int __init clk_debugfs_init(void) +{ + struct preinit_clk *pclk, *tmp; + + init_done = 1; + + mutex_lock(&preinit_lock); + list_for_each_entry(pclk, &preinit_clks, list) { + clk_debug_register(pclk->clk); + } + + list_for_each_entry_safe(pclk, tmp, &preinit_clks, list) { + list_del(&pclk->list); + kfree(pclk); + } + mutex_unlock(&preinit_lock); + return 0; +} +late_initcall(clk_debugfs_init); +#endif diff --git a/arch/arm/plat-mxc/include/mach/clock.h b/arch/arm/plat-mxc/include/mach/clock.h index 753a5988d85..2b4bb90a29c 100644 --- a/arch/arm/plat-mxc/include/mach/clock.h +++ b/arch/arm/plat-mxc/include/mach/clock.h @@ -1,5 +1,5 @@ /* - * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved. + * Copyright 2005-2011 Freescale Semiconductor, Inc. All Rights Reserved. * Copyright 2008 Juergen Beisert, kernel@pengutronix.de * * This program is free software; you can redistribute it and/or @@ -23,9 +23,14 @@ #ifndef __ASSEMBLY__ #include <linux/list.h> +#define CLK_NAME_LEN 32 struct module; struct clk { +#ifdef CONFIG_CLK_DEBUG + char name[CLK_NAME_LEN]; + struct dentry *dentry; +#endif int id; /* Source clock this clk depends on */ struct clk *parent; @@ -62,5 +67,11 @@ void clk_unregister(struct clk *clk); unsigned long mxc_decode_pll(unsigned int pll, u32 f_ref); +#ifdef CONFIG_CLK_DEBUG +void clk_debug_register(struct clk *clk); +#else +static inline void clk_debug_register(struct clk *clk) {} +#endif + #endif /* __ASSEMBLY__ */ #endif /* __ASM_ARCH_MXC_CLOCK_H__ */ |