Initial commit from HTC m7ul-3.4.10-jb-crc-ddcfb8c
diff --git a/arch/arm/mach-msm/clock-debug.c b/arch/arm/mach-msm/clock-debug.c
new file mode 100644
index 0000000..3433356
--- /dev/null
+++ b/arch/arm/mach-msm/clock-debug.c
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2007 Google, Inc.
+ * Copyright (c) 2007-2012, 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
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#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)
+{
+	struct clk *clock = data;
+	int ret;
+
+	if (clock->flags & CLKFLAG_MAX)
+		clk_set_max_rate(clock, val);
+	ret = clk_set_rate(clock, val);
+	if (ret)
+		pr_err("clk_set_rate failed (%d)\n", ret);
+
+	return ret;
+}
+
+static int clock_debug_rate_get(void *data, u64 *val)
+{
+	struct clk *clock = data;
+	*val = clk_get_rate(clock);
+	return 0;
+}
+
+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)
+{
+	struct clk *clock = data;
+	int ret, is_hw_gated;
+
+	
+	if (clock->flags & CLKFLAG_HWCG)
+		is_hw_gated = clock->ops->in_hwcg_mode(clock);
+	else
+		is_hw_gated = 0;
+
+	ret = clk_set_parent(measure, clock);
+	if (!ret) {
+		if (is_hw_gated && clock->count)
+			clock->ops->disable_hwcg(clock);
+		*val = clk_get_rate(measure);
+		
+		if (is_hw_gated && clock->count)
+			clock->ops->enable_hwcg(clock);
+	}
+
+	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 = clk_prepare_enable(clock);
+	else
+		clk_disable_unprepare(clock);
+
+	return rc;
+}
+
+static int clock_debug_enable_get(void *data, u64 *val)
+{
+	struct clk *clock = data;
+	int enabled;
+
+	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, "%lld\n");
+
+static int clock_debug_local_get(void *data, u64 *val)
+{
+	struct clk *clock = data;
+
+	if (!clock->ops->is_local)
+		*val = true;
+	else
+		*val = clock->ops->is_local(clock);
+
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_local_fops, clock_debug_local_get,
+			NULL, "%llu\n");
+
+static int clock_debug_hwcg_get(void *data, u64 *val)
+{
+	struct clk *clock = data;
+	*val = !!(clock->flags & CLKFLAG_HWCG);
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(clock_hwcg_fops, clock_debug_hwcg_get,
+			NULL, "%llu\n");
+
+static struct dentry *debugfs_base;
+static u32 debug_suspend;
+static struct clk_lookup *msm_clocks;
+static size_t num_msm_clocks;
+
+struct clk *clock_debug_parent_get(void *data)
+{
+	struct clk *clock = data;
+
+	if (clock->ops->get_parent)
+		return clock->ops->get_parent(clock);
+
+	return NULL;
+}
+
+int htc_clock_dump(struct clk *clock, struct seq_file *m)
+{
+	int len = 0;
+	u64 value = 0;
+	struct clk *parent;
+	char nam_buf[20], en_buf[20], hz_buf[20], loc_buf[20], par_buf[20];
+
+	if (!clock)
+		return 0;
+
+	memset(nam_buf,  ' ', sizeof(nam_buf));
+	nam_buf[19] = 0;
+	memset(en_buf, 0, sizeof(en_buf));
+	memset(hz_buf, 0, sizeof(hz_buf));
+	memset(loc_buf, 0, sizeof(loc_buf));
+	memset(par_buf,  ' ', sizeof(par_buf));
+	par_buf[19] = 0;
+
+	len = strlen(clock->dbg_name);
+	if (len > 19)
+		len = 19;
+	memcpy(nam_buf, clock->dbg_name, len);
+
+	clock_debug_enable_get(clock, &value);
+	if (value)
+		sprintf(en_buf, "Y");
+	else
+		sprintf(en_buf, "N");
+
+	clock_debug_rate_get(clock, &value);
+	sprintf(hz_buf, "%llu", value);
+
+	clock_debug_local_get(clock, &value);
+	if (value)
+		sprintf(loc_buf, "Y");
+	else
+		sprintf(loc_buf, "N");
+
+	parent = clock_debug_parent_get(clock);
+	if (parent) {
+		len = strlen(parent->dbg_name);
+		if (len > 19)
+			len = 19;
+		memcpy(par_buf, parent->dbg_name, len);
+	} else
+		memcpy(par_buf, "NULL", 4);
+
+	if (m)
+		seq_printf(m, "%s: [EN]%s, [LOC]%s, [SRC]%s, [FREQ]%s\n", nam_buf, en_buf, loc_buf, par_buf, hz_buf);
+	else
+		pr_info("%s: [EN]%s, [LOC]%s, [SRC]%s, [FREQ]%s\n", nam_buf, en_buf, loc_buf, par_buf, hz_buf);
+
+	return 0;
+}
+
+static int list_clocks_show(struct seq_file *m, void *unused)
+{
+	int index;
+	char *title_msg = "------------ HTC Clock -------------\n";
+
+	seq_printf(m, title_msg);
+	for (index = 0; index < num_msm_clocks; index++)
+		htc_clock_dump(msm_clocks[index].clk, m);
+	return 0;
+}
+
+static int list_clocks_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, list_clocks_show, inode->i_private);
+}
+
+static const struct file_operations list_clocks_fops = {
+	.open		= list_clocks_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
+};
+
+static struct dentry *debugfs_clock_base;
+
+int htc_clock_status_debug_init(void)
+{
+	debugfs_clock_base = debugfs_create_dir("htc_clock", NULL);
+	if (!debugfs_clock_base)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("list_clocks", S_IRUGO, debugfs_clock_base,
+				&msm_clocks, &list_clocks_fops))
+		return -ENOMEM;
+
+	return 0;
+}
+
+int __init clock_debug_init(struct clock_init_data *data)
+{
+	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 = data->table;
+	num_msm_clocks = data->size;
+
+	measure = clk_get_sys("debug", "measure");
+	if (IS_ERR(measure))
+		measure = NULL;
+
+	htc_clock_status_debug_init();
+	return 0;
+}
+
+
+static int clock_debug_print_clock(struct clk *c)
+{
+	char *start = "";
+
+	if (!c || !c->count)
+		return 0;
+
+	pr_info("\t");
+	do {
+		if (c->vdd_class)
+			pr_cont("%s%s [%ld, %lu]", start, c->dbg_name, c->rate,
+				c->vdd_class->cur_level);
+		else
+			pr_cont("%s%s [%ld]", start, c->dbg_name, c->rate);
+		start = " -> ";
+	} while ((c = clk_get_parent(c)));
+
+	pr_cont("\n");
+
+	return 1;
+}
+
+void clock_debug_print_enabled(void)
+{
+	unsigned i;
+	int cnt = 0;
+
+	if (likely(!debug_suspend))
+		return;
+
+	pr_info("Enabled clocks:\n");
+	for (i = 0; i < num_msm_clocks; i++)
+		cnt += clock_debug_print_clock(msm_clocks[i].clk);
+
+	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, level, fmax = 0, i = 0;
+
+	
+	if (!clock->vdd_class) {
+		fmax = INT_MAX;
+	} else {
+		for (level = 0; level < ARRAY_SIZE(clock->fmax); level++)
+			if (clock->fmax[level])
+				fmax = clock->fmax[level];
+	}
+
+	while ((rate = clock->ops->list_rate(clock, i++)) >= 0) {
+		if (rate <= fmax)
+			seq_printf(m, "%u\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;
+	struct dentry *clk_dir;
+
+	if (!debugfs_base)
+		return -ENOMEM;
+
+	strlcpy(temp, clock->dbg_name, ARRAY_SIZE(temp));
+	for (ptr = temp; *ptr; ptr++)
+		*ptr = tolower(*ptr);
+
+	clk_dir = debugfs_create_dir(temp, debugfs_base);
+	if (!clk_dir)
+		return -ENOMEM;
+
+	if (!debugfs_create_file("rate", S_IRUGO | S_IWUSR, clk_dir,
+				clock, &clock_rate_fops))
+		goto error;
+
+	if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR, clk_dir,
+				clock, &clock_enable_fops))
+		goto error;
+
+	if (!debugfs_create_file("is_local", S_IRUGO, clk_dir, clock,
+				&clock_local_fops))
+		goto error;
+
+	if (!debugfs_create_file("has_hw_gating", S_IRUGO, clk_dir, clock,
+				&clock_hwcg_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);
+	return -ENOMEM;
+}