aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-mx5/clock-mx51-mx53.c41
-rw-r--r--arch/arm/plat-mxc/Kconfig6
-rw-r--r--arch/arm/plat-mxc/clock.c121
-rw-r--r--arch/arm/plat-mxc/include/mach/clock.h11
4 files changed, 177 insertions, 2 deletions
diff --git a/arch/arm/mach-mx5/clock-mx51-mx53.c b/arch/arm/mach-mx5/clock-mx51-mx53.c
index 0a19e7567c0..d8a65daa8be 100644
--- a/arch/arm/mach-mx5/clock-mx51-mx53.c
+++ b/arch/arm/mach-mx5/clock-mx51-mx53.c
@@ -464,7 +464,14 @@ static int _clk_main_bus_set_parent(struct clk *clk, struct clk *parent)
return 0;
}
+#ifdef CONFIG_CLK_DEBUG
+#define __INIT_CLK_DEBUG(n) .name = #n,
+#else
+#define __INIT_CLK_DEBUG(n)
+#endif
+
static struct clk main_bus_clk = {
+ __INIT_CLK_DEBUG(main_bus_clk)
.parent = &pll2_sw_clk,
.set_parent = _clk_main_bus_set_parent,
};
@@ -728,23 +735,28 @@ static unsigned long _clk_ddr_hf_get_rate(struct clk *clk)
/* External high frequency clock */
static struct clk ckih_clk = {
+ __INIT_CLK_DEBUG(ckih_clk)
.get_rate = get_high_reference_clock_rate,
};
static struct clk ckih2_clk = {
+ __INIT_CLK_DEBUG(ckih2_clk)
.get_rate = get_ckih2_reference_clock_rate,
};
static struct clk osc_clk = {
+ __INIT_CLK_DEBUG(osc_clk)
.get_rate = get_oscillator_reference_clock_rate,
};
/* External low frequency (32kHz) clock */
static struct clk ckil_clk = {
+ __INIT_CLK_DEBUG(ckil_clk)
.get_rate = get_low_reference_clock_rate,
};
static struct clk pll1_main_clk = {
+ __INIT_CLK_DEBUG(pll1_main_clk)
.parent = &osc_clk,
.get_rate = clk_pll_get_rate,
.enable = _clk_pll_enable,
@@ -762,6 +774,7 @@ static struct clk pll1_main_clk = {
/* PLL1 SW supplies to ARM core */
static struct clk pll1_sw_clk = {
+ __INIT_CLK_DEBUG(pll1_sw_clk)
.parent = &pll1_main_clk,
.set_parent = _clk_pll1_sw_set_parent,
.get_rate = clk_pll1_sw_get_rate,
@@ -769,6 +782,7 @@ static struct clk pll1_sw_clk = {
/* PLL2 SW supplies to AXI/AHB/IP buses */
static struct clk pll2_sw_clk = {
+ __INIT_CLK_DEBUG(pll2_sw_clk)
.parent = &osc_clk,
.get_rate = clk_pll_get_rate,
.set_rate = _clk_pll_set_rate,
@@ -779,6 +793,7 @@ static struct clk pll2_sw_clk = {
/* PLL3 SW supplies to serial clocks like USB, SSI, etc. */
static struct clk pll3_sw_clk = {
+ __INIT_CLK_DEBUG(pll3_sw_clk)
.parent = &osc_clk,
.set_rate = _clk_pll_set_rate,
.get_rate = clk_pll_get_rate,
@@ -788,6 +803,7 @@ static struct clk pll3_sw_clk = {
/* PLL4 SW supplies to LVDS Display Bridge(LDB) */
static struct clk mx53_pll4_sw_clk = {
+ __INIT_CLK_DEBUG(mx53_pll4_clk)
.parent = &osc_clk,
.set_rate = _clk_pll_set_rate,
.enable = _clk_pll_enable,
@@ -796,22 +812,26 @@ static struct clk mx53_pll4_sw_clk = {
/* Low-power Audio Playback Mode clock */
static struct clk lp_apm_clk = {
+ __INIT_CLK_DEBUG(lp_apm_clk)
.parent = &osc_clk,
.set_parent = _clk_lp_apm_set_parent,
};
static struct clk periph_apm_clk = {
+ __INIT_CLK_DEBUG(periph_apm_clk)
.parent = &pll1_sw_clk,
.set_parent = _clk_periph_apm_set_parent,
};
static struct clk cpu_clk = {
+ __INIT_CLK_DEBUG(cpu_clk)
.parent = &pll1_sw_clk,
.get_rate = clk_cpu_get_rate,
.set_rate = clk_cpu_set_rate,
};
static struct clk ahb_clk = {
+ __INIT_CLK_DEBUG(ahb_clk)
.parent = &main_bus_clk,
.get_rate = clk_ahb_get_rate,
.set_rate = _clk_ahb_set_rate,
@@ -819,6 +839,7 @@ static struct clk ahb_clk = {
};
static struct clk iim_clk = {
+ __INIT_CLK_DEBUG(iim_clk)
.parent = &ipg_clk,
.enable_reg = MXC_CCM_CCGR0,
.enable_shift = MXC_CCM_CCGRx_CG15_OFFSET,
@@ -826,17 +847,20 @@ static struct clk iim_clk = {
/* Main IP interface clock for access to registers */
static struct clk ipg_clk = {
+ __INIT_CLK_DEBUG(ipg_clk)
.parent = &ahb_clk,
.get_rate = clk_ipg_get_rate,
};
static struct clk ipg_perclk = {
+ __INIT_CLK_DEBUG(ipg_clk)
.parent = &lp_apm_clk,
.get_rate = clk_ipg_per_get_rate,
.set_parent = _clk_ipg_per_set_parent,
};
static struct clk ahb_max_clk = {
+ __INIT_CLK_DEBUG(ahb_max_clk)
.parent = &ahb_clk,
.enable_reg = MXC_CCM_CCGR0,
.enable_shift = MXC_CCM_CCGRx_CG14_OFFSET,
@@ -845,6 +869,7 @@ static struct clk ahb_max_clk = {
};
static struct clk aips_tz1_clk = {
+ __INIT_CLK_DEBUG(aips_tz1_clk)
.parent = &ahb_clk,
.secondary = &ahb_max_clk,
.enable_reg = MXC_CCM_CCGR0,
@@ -854,6 +879,7 @@ static struct clk aips_tz1_clk = {
};
static struct clk aips_tz2_clk = {
+ __INIT_CLK_DEBUG(aips_tz2_clk)
.parent = &ahb_clk,
.secondary = &ahb_max_clk,
.enable_reg = MXC_CCM_CCGR0,
@@ -863,11 +889,13 @@ static struct clk aips_tz2_clk = {
};
static struct clk gpt_32k_clk = {
+ __INIT_CLK_DEBUG(gpt_32k_clk)
.id = 0,
.parent = &ckil_clk,
};
static struct clk kpp_clk = {
+ __INIT_CLK_DEBUG(kpp_clk)
.id = 0,
};
@@ -876,6 +904,7 @@ static struct clk dummy_clk = {
};
static struct clk emi_slow_clk = {
+ __INIT_CLK_DEBUG(emi_slow_clk)
.parent = &pll2_sw_clk,
.enable_reg = MXC_CCM_CCGR5,
.enable_shift = MXC_CCM_CCGRx_CG8_OFFSET,
@@ -989,6 +1018,7 @@ static struct clk mipi_hsp_clk = {
#define DEFINE_CLOCK_CCGR(name, i, er, es, pfx, p, s) \
static struct clk name = { \
+ __INIT_CLK_DEBUG(name) \
.id = i, \
.enable_reg = er, \
.enable_shift = es, \
@@ -1004,6 +1034,7 @@ static struct clk mipi_hsp_clk = {
#define DEFINE_CLOCK_MAX(name, i, er, es, pfx, p, s) \
static struct clk name = { \
+ __INIT_CLK_DEBUG(name) \
.id = i, \
.enable_reg = er, \
.enable_shift = es, \
@@ -1082,6 +1113,7 @@ CLK_GET_RATE(uart, 1, UART)
CLK_SET_PARENT(uart, 1, UART)
static struct clk uart_root_clk = {
+ __INIT_CLK_DEBUG(uart_root_clk)
.parent = &pll2_sw_clk,
.get_rate = clk_uart_get_rate,
.set_parent = clk_uart_set_parent,
@@ -1092,6 +1124,7 @@ CLK_GET_RATE(usboh3, 1, USBOH3)
CLK_SET_PARENT(usboh3, 1, USBOH3)
static struct clk usboh3_clk = {
+ __INIT_CLK_DEBUG(usboh3_clk)
.parent = &pll2_sw_clk,
.get_rate = clk_usboh3_get_rate,
.set_parent = clk_usboh3_set_parent,
@@ -1137,6 +1170,7 @@ CLK_GET_RATE(ecspi, 2, CSPI)
CLK_SET_PARENT(ecspi, 1, CSPI)
static struct clk ecspi_main_clk = {
+ __INIT_CLK_DEBUG(ecspi_main_clk)
.parent = &pll3_sw_clk,
.get_rate = clk_ecspi_get_rate,
.set_parent = clk_ecspi_set_parent,
@@ -1152,7 +1186,8 @@ CLK_SET_PARENT(esdhc2, 1, ESDHC2_MSHC2)
CLK_SET_RATE(esdhc2, 1, ESDHC2_MSHC2)
#define DEFINE_CLOCK_FULL(name, i, er, es, gr, sr, e, d, p, s) \
- static struct clk name = { \
+static struct clk name = { \
+ __INIT_CLK_DEBUG(name) \
.id = i, \
.enable_reg = er, \
.enable_shift = es, \
@@ -1372,8 +1407,10 @@ int __init mx51_clocks_init(unsigned long ckil, unsigned long osc,
ckih2_reference = ckih2;
oscillator_reference = osc;
- for (i = 0; i < ARRAY_SIZE(mx51_lookups); i++)
+ for (i = 0; i < ARRAY_SIZE(mx51_lookups); i++) {
clkdev_add(&mx51_lookups[i]);
+ clk_debug_register(mx51_lookups[i].clk);
+ }
clk_tree_init();
diff --git a/arch/arm/plat-mxc/Kconfig b/arch/arm/plat-mxc/Kconfig
index 389f2179501..a97f7334bc7 100644
--- a/arch/arm/plat-mxc/Kconfig
+++ b/arch/arm/plat-mxc/Kconfig
@@ -119,4 +119,10 @@ 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..190bce1221a 100644
--- a/arch/arm/plat-mxc/clock.c
+++ b/arch/arm/plat-mxc/clock.c
@@ -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_u32("enable_count", S_IRUGO, clk->dentry,
+ (u32 *)&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..fb0e0bd3f51 100644
--- a/arch/arm/plat-mxc/include/mach/clock.h
+++ b/arch/arm/plat-mxc/include/mach/clock.h
@@ -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__ */