msm: qdss: sysfs interface for the qdss driver

Make the qdss driver configurable via sysfs. Remove the previous
device node based interface that provided limited ETM configuration
options.

This makes ETM, Funnel and ETB highly configurable and extensible
for future configuration options.

Change-Id: Ib95b522dde443adde83483ee58a4dbb07ab0e311
Signed-off-by: Pratik Patel <pratikp@codeaurora.org>
diff --git a/arch/arm/mach-msm/qdss.c b/arch/arm/mach-msm/qdss.c
index b9ba4ce..ab28c82 100644
--- a/arch/arm/mach-msm/qdss.c
+++ b/arch/arm/mach-msm/qdss.c
@@ -29,6 +29,18 @@
 	QDSS_CLK_ON_HSDBG,
 };
 
+struct qdss_ctx {
+	struct kobject	*modulekobj;
+	uint8_t		max_clk;
+};
+
+static struct qdss_ctx qdss;
+
+
+struct kobject *qdss_get_modulekobj(void)
+{
+	return qdss.modulekobj;
+}
 
 int qdss_clk_enable(void)
 {
@@ -36,13 +48,15 @@
 
 	struct msm_rpm_iv_pair iv;
 	iv.id = MSM_RPM_ID_QDSS_CLK;
-	iv.value = QDSS_CLK_ON_DBG;
+	if (qdss.max_clk)
+		iv.value = QDSS_CLK_ON_HSDBG;
+	else
+		iv.value = QDSS_CLK_ON_DBG;
 	ret = msm_rpmrs_set(MSM_RPM_CTX_SET_0, &iv, 1);
 	if (WARN(ret, "qdss clks not enabled (%d)\n", ret))
 		goto err_clk;
 
 	return 0;
-
 err_clk:
 	return ret;
 }
@@ -58,10 +72,65 @@
 	WARN(ret, "qdss clks not disabled (%d)\n", ret);
 }
 
+#define QDSS_ATTR(name)						\
+static struct kobj_attribute name##_attr =				\
+		__ATTR(name, S_IRUGO | S_IWUSR, name##_show, name##_store)
+
+static ssize_t max_clk_store(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			const char *buf, size_t n)
+{
+	unsigned long val;
+
+	if (sscanf(buf, "%lx", &val) != 1)
+		return -EINVAL;
+
+	qdss.max_clk = val;
+	return n;
+}
+static ssize_t max_clk_show(struct kobject *kobj,
+			struct kobj_attribute *attr,
+			char *buf)
+{
+	unsigned long val = qdss.max_clk;
+	return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
+}
+QDSS_ATTR(max_clk);
+
+static int __init qdss_sysfs_init(void)
+{
+	int ret;
+
+	qdss.modulekobj = kset_find_obj(module_kset, KBUILD_MODNAME);
+	if (!qdss.modulekobj) {
+		pr_err("failed to find QDSS sysfs module kobject\n");
+		ret = -ENOENT;
+		goto err;
+	}
+
+	ret = sysfs_create_file(qdss.modulekobj, &max_clk_attr.attr);
+	if (ret) {
+		pr_err("failed to create QDSS sysfs max_clk attribute\n");
+		goto err;
+	}
+
+	return 0;
+err:
+	return ret;
+}
+
+static void qdss_sysfs_exit(void)
+{
+	sysfs_remove_file(qdss.modulekobj, &max_clk_attr.attr);
+}
+
 static int __init qdss_init(void)
 {
 	int ret;
 
+	ret = qdss_sysfs_init();
+	if (ret)
+		goto err_sysfs;
 	ret = etb_init();
 	if (ret)
 		goto err_etb;
@@ -84,6 +153,8 @@
 err_tpiu:
 	etb_exit();
 err_etb:
+	qdss_sysfs_exit();
+err_sysfs:
 	pr_err("QDSS init failed\n");
 	return ret;
 }
@@ -91,6 +162,7 @@
 
 static void __exit qdss_exit(void)
 {
+	qdss_sysfs_exit();
 	etm_exit();
 	funnel_exit();
 	tpiu_exit();