Initial Contribution

msm-2.6.38: tag AU_LINUX_ANDROID_GINGERBREAD.02.03.04.00.142

Signed-off-by: Bryan Huntsman <bryanh@codeaurora.org>
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
index 4886404..36bc124 100644
--- a/arch/arm/mach-msm/clock-debug.c
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2007-2010, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2007-2011, Code Aurora Forum. All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -17,7 +17,11 @@
 #include <linux/module.h>
 #include <linux/ctype.h>
 #include <linux/debugfs.h>
+#include <linux/seq_file.h>
 #include <linux/clk.h>
+#include <linux/list.h>
+#include <linux/clkdev.h>
+
 #include "clock.h"
 
 static int clock_debug_rate_set(void *data, u64 val)
@@ -27,15 +31,15 @@
 
 	/* Only increases to max rate will succeed, but that's actually good
 	 * for debugging purposes so we don't check for error. */
-	if (clock->flags & CLK_MAX)
+	if (clock->flags & CLKFLAG_MAX)
 		clk_set_max_rate(clock, val);
-	if (clock->flags & CLK_MIN)
+	if (clock->flags & CLKFLAG_MIN)
 		ret = clk_set_min_rate(clock, val);
 	else
 		ret = clk_set_rate(clock, val);
 	if (ret != 0)
 		printk(KERN_ERR "clk_set%s_rate failed (%d)\n",
-			(clock->flags & CLK_MIN) ? "_min" : "", ret);
+			(clock->flags & CLKFLAG_MIN) ? "_min" : "", ret);
 	return ret;
 }
 
@@ -49,15 +53,32 @@
 DEFINE_SIMPLE_ATTRIBUTE(clock_rate_fops, clock_debug_rate_get,
 			clock_debug_rate_set, "%llu\n");
 
+static struct clk *measure;
+
+static int clock_debug_measure_get(void *data, u64 *val)
+{
+	int ret;
+	struct clk *clock = data;
+
+	ret = clk_set_parent(measure, clock);
+	if (!ret)
+		*val = clk_get_rate(measure);
+
+	return ret;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_measure_fops, clock_debug_measure_get,
+			NULL, "%lld\n");
+
 static int clock_debug_enable_set(void *data, u64 val)
 {
 	struct clk *clock = data;
 	int rc = 0;
 
 	if (val)
-		rc = clock->ops->enable(clock->id);
+		rc = clk_enable(clock);
 	else
-		clock->ops->disable(clock->id);
+		clk_disable(clock);
 
 	return rc;
 }
@@ -65,20 +86,25 @@
 static int clock_debug_enable_get(void *data, u64 *val)
 {
 	struct clk *clock = data;
+	int enabled;
 
-	*val = clock->ops->is_enabled(clock->id);
+	if (clock->ops->is_enabled)
+		enabled = clock->ops->is_enabled(clock);
+	else
+		enabled = !!(clock->count);
 
+	*val = enabled;
 	return 0;
 }
 
 DEFINE_SIMPLE_ATTRIBUTE(clock_enable_fops, clock_debug_enable_get,
-			clock_debug_enable_set, "%llu\n");
+			clock_debug_enable_set, "%lld\n");
 
 static int clock_debug_local_get(void *data, u64 *val)
 {
 	struct clk *clock = data;
 
-	*val = clock->ops->is_local(clock->id);
+	*val = clock->ops->is_local(clock);
 
 	return 0;
 }
@@ -87,15 +113,83 @@
 			NULL, "%llu\n");
 
 static struct dentry *debugfs_base;
+static u32 debug_suspend;
+static struct clk_lookup *msm_clocks;
+static unsigned num_msm_clocks;
 
-int __init clock_debug_init(void)
+int __init clock_debug_init(struct clk_lookup *clocks, unsigned num_clocks)
 {
+	int ret = 0;
+
 	debugfs_base = debugfs_create_dir("clk", NULL);
 	if (!debugfs_base)
 		return -ENOMEM;
+	if (!debugfs_create_u32("debug_suspend", S_IRUGO | S_IWUSR,
+				debugfs_base, &debug_suspend)) {
+		debugfs_remove_recursive(debugfs_base);
+		return -ENOMEM;
+	}
+	msm_clocks = clocks;
+	num_msm_clocks = num_clocks;
+
+	measure = clk_get_sys("debug", "measure");
+	if (IS_ERR(measure)) {
+		ret = PTR_ERR(measure);
+		measure = NULL;
+	}
+
+	return ret;
+}
+
+void clock_debug_print_enabled(void)
+{
+	struct clk *clk;
+	unsigned i;
+	int cnt = 0;
+
+	if (likely(!debug_suspend))
+		return;
+
+	pr_info("Enabled clocks:\n");
+	for (i = 0; i < num_msm_clocks; i++) {
+		clk = msm_clocks[i].clk;
+
+		if (clk && clk->ops->is_enabled(clk)) {
+			pr_info("\t%s\n", clk->dbg_name);
+			cnt++;
+		}
+	}
+
+	if (cnt)
+		pr_info("Enabled clock count: %d\n", cnt);
+	else
+		pr_info("No clocks enabled.\n");
+
+}
+
+static int list_rates_show(struct seq_file *m, void *unused)
+{
+	struct clk *clock = m->private;
+	int rate, i = 0;
+
+	while ((rate = clock->ops->list_rate(clock, i++)) >= 0)
+		seq_printf(m, "%d\n", rate);
+
 	return 0;
 }
 
+static int list_rates_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, list_rates_show, inode->i_private);
+}
+
+static const struct file_operations list_rates_fops = {
+	.open		= list_rates_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
 int __init clock_debug_add(struct clk *clock)
 {
 	char temp[50], *ptr;
@@ -123,6 +217,18 @@
 	if (!debugfs_create_file("is_local", S_IRUGO, clk_dir, clock,
 				&clock_local_fops))
 		goto error;
+
+	if (measure &&
+	    !clk_set_parent(measure, clock) &&
+	    !debugfs_create_file("measure", S_IRUGO, clk_dir, clock,
+				&clock_measure_fops))
+		goto error;
+
+	if (clock->ops->list_rate)
+		if (!debugfs_create_file("list_rates",
+				S_IRUGO, clk_dir, clock, &list_rates_fops))
+			goto error;
+
 	return 0;
 error:
 	debugfs_remove_recursive(clk_dir);