aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorVincent Guittot <vincent.guittot@stericsson.com>2010-12-03 12:18:39 -0500
committerLinus Walleij <linus.walleij@stericsson.com>2010-12-20 07:32:45 -0500
commit763eef8b5b64dbbfc0f6273af9a57024069785a9 (patch)
tree3e24b74aad069a1d3248ac78d53da3bd8944a233 /arch
parentabda3a24a99998279fe890ea8a789ebe4d605d78 (diff)
ux500: add debugfs support for powerdebug
Signed-off-by: Vincent Guittot <vincent.guittot@stericsson.com> Signed-off-by: Linus Walleij <linus.walleij@stericsson.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-ux500/clock.c195
-rw-r--r--arch/arm/mach-ux500/clock.h4
2 files changed, 198 insertions, 1 deletions
diff --git a/arch/arm/mach-ux500/clock.c b/arch/arm/mach-ux500/clock.c
index 00e9ab304ca7..912d1cc18c57 100644
--- a/arch/arm/mach-ux500/clock.c
+++ b/arch/arm/mach-ux500/clock.c
@@ -20,6 +20,12 @@
20#include <mach/hardware.h> 20#include <mach/hardware.h>
21#include "clock.h" 21#include "clock.h"
22 22
23#ifdef CONFIG_DEBUG_FS
24#include <linux/debugfs.h>
25#include <linux/uaccess.h> /* for copy_from_user */
26static LIST_HEAD(clk_list);
27#endif
28
23#define PRCC_PCKEN 0x00 29#define PRCC_PCKEN 0x00
24#define PRCC_PCKDIS 0x04 30#define PRCC_PCKDIS 0x04
25#define PRCC_KCKEN 0x08 31#define PRCC_KCKEN 0x08
@@ -286,6 +292,7 @@ static struct clkops clk_prcc_ops = {
286}; 292};
287 293
288static struct clk clk_32khz = { 294static struct clk clk_32khz = {
295 .name = "clk_32khz",
289 .rate = 32000, 296 .rate = 32000,
290}; 297};
291 298
@@ -422,7 +429,9 @@ static DEFINE_PRCC_CLK_CUSTOM(7, mtu0_ed, 2, -1, NULL, clk_mtu_get_rate, 0);
422static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL); 429static DEFINE_PRCC_CLK(7, wdg_ed, 1, -1, NULL);
423static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL); 430static DEFINE_PRCC_CLK(7, cfgreg_ed, 0, -1, NULL);
424 431
425static struct clk clk_dummy_apb_pclk; 432static struct clk clk_dummy_apb_pclk = {
433 .name = "apb_pclk",
434};
426 435
427static struct clk_lookup u8500_common_clks[] = { 436static struct clk_lookup u8500_common_clks[] = {
428 CLK(dummy_apb_pclk, NULL, "apb_pclk"), 437 CLK(dummy_apb_pclk, NULL, "apb_pclk"),
@@ -568,6 +577,183 @@ static struct clk_lookup u8500_v1_clks[] = {
568 CLK(uiccclk, "uicc", NULL), 577 CLK(uiccclk, "uicc", NULL),
569}; 578};
570 579
580#ifdef CONFIG_DEBUG_FS
581/*
582 * debugfs support to trace clock tree hierarchy and attributes with
583 * powerdebug
584 */
585static struct dentry *clk_debugfs_root;
586
587void __init clk_debugfs_add_table(struct clk_lookup *cl, size_t num)
588{
589 while (num--) {
590 /* Check that the clock has not been already registered */
591 if (!(cl->clk->list.prev != cl->clk->list.next))
592 list_add_tail(&cl->clk->list, &clk_list);
593
594 cl++;
595 }
596}
597
598static ssize_t usecount_dbg_read(struct file *file, char __user *buf,
599 size_t size, loff_t *off)
600{
601 struct clk *clk = file->f_dentry->d_inode->i_private;
602 char cusecount[128];
603 unsigned int len;
604
605 len = sprintf(cusecount, "%u\n", clk->enabled);
606 return simple_read_from_buffer(buf, size, off, cusecount, len);
607}
608
609static ssize_t rate_dbg_read(struct file *file, char __user *buf,
610 size_t size, loff_t *off)
611{
612 struct clk *clk = file->f_dentry->d_inode->i_private;
613 char crate[128];
614 unsigned int rate;
615 unsigned int len;
616
617 rate = clk_get_rate(clk);
618 len = sprintf(crate, "%u\n", rate);
619 return simple_read_from_buffer(buf, size, off, crate, len);
620}
621
622static const struct file_operations usecount_fops = {
623 .read = usecount_dbg_read,
624};
625
626static const struct file_operations set_rate_fops = {
627 .read = rate_dbg_read,
628};
629
630static struct dentry *clk_debugfs_register_dir(struct clk *c,
631 struct dentry *p_dentry)
632{
633 struct dentry *d, *clk_d, *child, *child_tmp;
634 char s[255];
635 char *p = s;
636
637 if (c->name == NULL)
638 p += sprintf(p, "BUG");
639 else
640 p += sprintf(p, "%s", c->name);
641
642 clk_d = debugfs_create_dir(s, p_dentry);
643 if (!clk_d)
644 return NULL;
645
646 d = debugfs_create_file("usecount", S_IRUGO,
647 clk_d, c, &usecount_fops);
648 if (!d)
649 goto err_out;
650 d = debugfs_create_file("rate", S_IRUGO,
651 clk_d, c, &set_rate_fops);
652 if (!d)
653 goto err_out;
654 /*
655 * TODO : not currently available in ux500
656 * d = debugfs_create_x32("flags", S_IRUGO, clk_d, (u32 *)&c->flags);
657 * if (!d)
658 * goto err_out;
659 */
660
661 return clk_d;
662
663err_out:
664 d = clk_d;
665 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
666 debugfs_remove(child);
667 debugfs_remove(clk_d);
668 return NULL;
669}
670
671static void clk_debugfs_remove_dir(struct dentry *cdentry)
672{
673 struct dentry *d, *child, *child_tmp;
674
675 d = cdentry;
676 list_for_each_entry_safe(child, child_tmp, &d->d_subdirs, d_u.d_child)
677 debugfs_remove(child);
678 debugfs_remove(cdentry);
679 return ;
680}
681
682static int clk_debugfs_register_one(struct clk *c)
683{
684 struct clk *pa = c->parent_periph;
685 struct clk *bpa = c->parent_cluster;
686
687 if (!(bpa && !pa)) {
688 c->dent = clk_debugfs_register_dir(c,
689 pa ? pa->dent : clk_debugfs_root);
690 if (!c->dent)
691 return -ENOMEM;
692 }
693
694 if (bpa) {
695 c->dent_bus = clk_debugfs_register_dir(c,
696 bpa->dent_bus ? bpa->dent_bus : bpa->dent);
697 if ((!c->dent_bus) && (c->dent)) {
698 clk_debugfs_remove_dir(c->dent);
699 c->dent = NULL;
700 return -ENOMEM;
701 }
702 }
703 return 0;
704}
705
706static int clk_debugfs_register(struct clk *c)
707{
708 int err;
709 struct clk *pa = c->parent_periph;
710 struct clk *bpa = c->parent_cluster;
711
712 if (pa && (!pa->dent && !pa->dent_bus)) {
713 err = clk_debugfs_register(pa);
714 if (err)
715 return err;
716 }
717
718 if (bpa && (!bpa->dent && !bpa->dent_bus)) {
719 err = clk_debugfs_register(bpa);
720 if (err)
721 return err;
722 }
723
724 if ((!c->dent) && (!c->dent_bus)) {
725 err = clk_debugfs_register_one(c);
726 if (err)
727 return err;
728 }
729 return 0;
730}
731
732static int __init clk_debugfs_init(void)
733{
734 struct clk *c;
735 struct dentry *d;
736 int err;
737
738 d = debugfs_create_dir("clock", NULL);
739 if (!d)
740 return -ENOMEM;
741 clk_debugfs_root = d;
742
743 list_for_each_entry(c, &clk_list, list) {
744 err = clk_debugfs_register(c);
745 if (err)
746 goto err_out;
747 }
748 return 0;
749err_out:
750 debugfs_remove_recursive(clk_debugfs_root);
751 return err;
752}
753
754late_initcall(clk_debugfs_init);
755#endif /* defined(CONFIG_DEBUG_FS) */
756
571int __init clk_init(void) 757int __init clk_init(void)
572{ 758{
573 if (cpu_is_u8500ed()) { 759 if (cpu_is_u8500ed()) {
@@ -588,5 +774,12 @@ int __init clk_init(void)
588 else 774 else
589 clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks)); 775 clkdev_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
590 776
777#ifdef CONFIG_DEBUG_FS
778 clk_debugfs_add_table(u8500_common_clks, ARRAY_SIZE(u8500_common_clks));
779 if (cpu_is_u8500ed())
780 clk_debugfs_add_table(u8500_ed_clks, ARRAY_SIZE(u8500_ed_clks));
781 else
782 clk_debugfs_add_table(u8500_v1_clks, ARRAY_SIZE(u8500_v1_clks));
783#endif
591 return 0; 784 return 0;
592} 785}
diff --git a/arch/arm/mach-ux500/clock.h b/arch/arm/mach-ux500/clock.h
index a05802501527..074490705229 100644
--- a/arch/arm/mach-ux500/clock.h
+++ b/arch/arm/mach-ux500/clock.h
@@ -90,6 +90,10 @@ struct clk {
90 90
91 struct clk *parent_cluster; 91 struct clk *parent_cluster;
92 struct clk *parent_periph; 92 struct clk *parent_periph;
93#if defined(CONFIG_DEBUG_FS)
94 struct dentry *dent; /* For visible tree hierarchy */
95 struct dentry *dent_bus; /* For visible tree hierarchy */
96#endif
93}; 97};
94 98
95#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \ 99#define DEFINE_PRCMU_CLK(_name, _cg_off, _cg_bit, _reg) \