aboutsummaryrefslogtreecommitdiff
path: root/arch/arm/mach-ux500/clock-debug.c
diff options
context:
space:
mode:
authorPhilippe Langlais <philippe.langlais@linaro.org>2011-05-09 14:16:33 +0200
committerHenrik Aberg <henrik.aberg@stericsson.com>2011-05-18 09:39:55 +0200
commit2a6801f0eb95c351c46764db14f1a6ce4ba48d7f (patch)
tree4165d1818d51a81cee1b289c1ae7c08075f8af9c /arch/arm/mach-ux500/clock-debug.c
parent3924fc8e19d0d9d99a8a7c3dac58f23c3b9a7b51 (diff)
u5500: move clock debugging code to separate file
ST-Ericsson Linux next: - ST-Ericsson ID: WP257121 ST-Ericsson FOSS-OUT ID: Trivial Change-Id: Iee0feba6a076b66b3e74a433cde945e8b961335a Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/19675 Reviewed-by: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> Conflicts: arch/arm/mach-ux500/Makefile
Diffstat (limited to 'arch/arm/mach-ux500/clock-debug.c')
-rw-r--r--arch/arm/mach-ux500/clock-debug.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/arch/arm/mach-ux500/clock-debug.c b/arch/arm/mach-ux500/clock-debug.c
new file mode 100644
index 00000000000..939edfaa94a
--- /dev/null
+++ b/arch/arm/mach-ux500/clock-debug.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2011
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> for ST-Ericsson
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/uaccess.h>
+#include <linux/clk.h>
+
+#include "clock.h"
+
+struct clk_debug_info {
+ struct clk *clk;
+ struct dentry *dir;
+ struct dentry *enable;
+ struct dentry *requests;
+ int enabled;
+};
+
+#ifdef CONFIG_DEBUG_FS
+
+static struct dentry *clk_dir;
+static struct dentry *clk_show;
+static struct dentry *clk_show_enabled_only;
+
+static struct clk_debug_info *cdi;
+static int num_clks;
+
+static int clk_show_print(struct seq_file *s, void *p)
+{
+ int i;
+ int enabled_only = (int)s->private;
+
+ seq_printf(s, "\n%-20s %s\n", "name", "enabled (kernel + debug)");
+ for (i = 0; i < num_clks; i++) {
+ if (enabled_only && !cdi[i].clk->enabled)
+ continue;
+ seq_printf(s,
+ "%-20s %5d + %d\n",
+ cdi[i].clk->name,
+ cdi[i].clk->enabled - cdi[i].enabled,
+ cdi[i].enabled);
+ }
+
+ return 0;
+}
+
+static int clk_show_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_show_print, inode->i_private);
+}
+
+static int clk_enable_print(struct seq_file *s, void *p)
+{
+ struct clk_debug_info *cdi = s->private;
+
+ return seq_printf(s, "%d\n", cdi->enabled);
+}
+
+static int clk_enable_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_enable_print, inode->i_private);
+}
+
+static ssize_t clk_enable_write(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct clk_debug_info *cdi;
+ char buf[32];
+ ssize_t buf_size;
+ long user_val;
+ int err;
+
+ cdi = ((struct seq_file *)(file->private_data))->private;
+
+ buf_size = min(count, (sizeof(buf) - 1));
+ if (copy_from_user(buf, user_buf, buf_size))
+ return -EFAULT;
+ buf[buf_size] = '\0';
+
+ err = strict_strtol(buf, 0, &user_val);
+ if (err)
+ return -EINVAL;
+ if ((user_val > 0) && (!cdi->enabled)) {
+ err = clk_enable(cdi->clk);
+ if (err) {
+ pr_err("clock: clk_enable(%s) failed.\n",
+ cdi->clk->name);
+ return -EFAULT;
+ }
+ cdi->enabled = 1;
+ } else if ((user_val <= 0) && (cdi->enabled)) {
+ clk_disable(cdi->clk);
+ cdi->enabled = 0;
+ }
+ return buf_size;
+}
+
+static int clk_requests_print(struct seq_file *s, void *p)
+{
+ struct clk_debug_info *cdi = s->private;
+
+ return seq_printf(s, "%d\n", cdi->clk->enabled);
+}
+
+static int clk_requests_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clk_requests_print, inode->i_private);
+}
+
+static const struct file_operations clk_enable_fops = {
+ .open = clk_enable_open,
+ .write = clk_enable_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations clk_requests_fops = {
+ .open = clk_requests_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static const struct file_operations clk_show_fops = {
+ .open = clk_show_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .owner = THIS_MODULE,
+};
+
+static int create_clk_dirs(struct clk_debug_info *cdi, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++) {
+ cdi[i].dir = debugfs_create_dir(cdi[i].clk->name, clk_dir);
+ if (!cdi[i].dir)
+ goto no_dir;
+ }
+
+ for (i = 0; i < size; i++) {
+ cdi[i].enable = debugfs_create_file("enable",
+ (S_IRUGO | S_IWUGO),
+ cdi[i].dir, &cdi[i],
+ &clk_enable_fops);
+ if (!cdi[i].enable)
+ goto no_enable;
+ }
+ for (i = 0; i < size; i++) {
+ cdi[i].requests = debugfs_create_file("requests", S_IRUGO,
+ cdi[i].dir, &cdi[i],
+ &clk_requests_fops);
+ if (!cdi[i].requests)
+ goto no_requests;
+ }
+ return 0;
+
+no_requests:
+ while (i--)
+ debugfs_remove(cdi[i].requests);
+ i = size;
+no_enable:
+ while (i--)
+ debugfs_remove(cdi[i].enable);
+ i = size;
+no_dir:
+ while (i--)
+ debugfs_remove(cdi[i].dir);
+
+ return -ENOMEM;
+}
+
+int __init dbx500_clk_debug_init(struct clk **clks, int num)
+{
+ int i;
+
+ cdi = kcalloc(sizeof(struct clk_debug_info), num, GFP_KERNEL);
+ if (!cdi)
+ return -ENOMEM;
+
+ for (i = 0; i < num; i++)
+ cdi[i].clk = clks[i];
+
+ num_clks = num;
+
+ clk_dir = debugfs_create_dir("clk", NULL);
+ if (!clk_dir)
+ goto no_dir;
+
+ clk_show = debugfs_create_file("show", S_IRUGO, clk_dir, (void *)0,
+ &clk_show_fops);
+ if (!clk_show)
+ goto no_show;
+
+ clk_show_enabled_only = debugfs_create_file("show-enabled-only",
+ S_IRUGO, clk_dir, (void *)1,
+ &clk_show_fops);
+ if (!clk_show_enabled_only)
+ goto no_enabled_only;
+
+ if (create_clk_dirs(cdi, num))
+ goto no_clks;
+
+ return 0;
+
+no_clks:
+ debugfs_remove(clk_show_enabled_only);
+no_enabled_only:
+ debugfs_remove(clk_show);
+no_show:
+ debugfs_remove(clk_dir);
+no_dir:
+ kfree(cdi);
+ return -ENOMEM;
+}
+
+#endif /* CONFIG_DEBUG_FS */