USB: OTG: msm: Add debugfs entry to disable MSM BUS bandwidth voting

OTG driver requests for high bus bandwidth as long as USB cable is
connected to improve USB throughput. This vote causes scaling up of
fabric frequencies and increase in the over system power consumption.

Some users might not be interested in this feature or may want to
disable this at runtime for profiling the system performance with USB
cable attached.
Hence, add a debugfs entry to allow users to disable this voting.
By default this feature is enabled.

Command to disable BUS voting from USB:
echo "disable" > <debugfs>/msm_otg/bus_voting

Change-Id: Icdd9c56623a9c91ff3a130d80983c3ddeb0f91c4
CRs-fixed: 341452
Signed-off-by: Manu Gautam <mgautam@codeaurora.org>
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 6964835..dd07d4e 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -67,6 +67,7 @@
 static DECLARE_COMPLETION(pmic_vbus_init);
 static struct msm_otg *the_msm_otg;
 static bool debug_aca_enabled;
+static bool debug_bus_voting_enabled;
 
 /* Prevent idle power collapse(pc) while operating in peripheral mode */
 static void otg_pm_qos_update_latency(struct msm_otg *dev, int vote)
@@ -1155,7 +1156,7 @@
 		 */
 		otg_pm_qos_update_latency(motg, 1);
 		/* Configure BUS performance parameters for MAX bandwidth */
-		if (motg->bus_perf_client) {
+		if (motg->bus_perf_client && debug_bus_voting_enabled) {
 			ret = msm_bus_scale_client_update_request(
 					motg->bus_perf_client, 1);
 			if (ret)
@@ -2232,13 +2233,64 @@
 	.release = single_release,
 };
 
+static int msm_otg_bus_show(struct seq_file *s, void *unused)
+{
+	if (debug_bus_voting_enabled)
+		seq_printf(s, "enabled\n");
+	else
+		seq_printf(s, "disabled\n");
+
+	return 0;
+}
+
+static int msm_otg_bus_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, msm_otg_bus_show, inode->i_private);
+}
+
+static ssize_t msm_otg_bus_write(struct file *file, const char __user *ubuf,
+				size_t count, loff_t *ppos)
+{
+	char buf[8];
+	int ret;
+	struct seq_file *s = file->private_data;
+	struct msm_otg *motg = s->private;
+
+	memset(buf, 0x00, sizeof(buf));
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "enable", 6)) {
+		/* Do not vote here. Let OTG statemachine decide when to vote */
+		debug_bus_voting_enabled = true;
+	} else {
+		debug_bus_voting_enabled = false;
+		if (motg->bus_perf_client) {
+			ret = msm_bus_scale_client_update_request(
+					motg->bus_perf_client, 0);
+			if (ret)
+				dev_err(motg->otg.dev, "%s: Failed to devote "
+					   "for bus bw %d\n", __func__, ret);
+		}
+	}
+
+	return count;
+}
+
+const struct file_operations msm_otg_bus_fops = {
+	.open = msm_otg_bus_open,
+	.read = seq_read,
+	.write = msm_otg_bus_write,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static struct dentry *msm_otg_dbg_root;
-static struct dentry *msm_otg_dbg_mode;
-static struct dentry *msm_otg_chg_type;
-static struct dentry *msm_otg_dbg_aca;
 
 static int msm_otg_debugfs_init(struct msm_otg *motg)
 {
+	struct dentry *msm_otg_dentry;
 
 	msm_otg_dbg_root = debugfs_create_dir("msm_otg", NULL);
 
@@ -2248,35 +2300,43 @@
 	if (motg->pdata->mode == USB_OTG &&
 		motg->pdata->otg_control == OTG_USER_CONTROL) {
 
-		msm_otg_dbg_mode = debugfs_create_file("mode", S_IRUGO |
+		msm_otg_dentry = debugfs_create_file("mode", S_IRUGO |
 			S_IWUSR, msm_otg_dbg_root, motg,
 			&msm_otg_mode_fops);
 
-		if (!msm_otg_dbg_mode) {
+		if (!msm_otg_dentry) {
 			debugfs_remove(msm_otg_dbg_root);
 			msm_otg_dbg_root = NULL;
 			return -ENODEV;
 		}
 	}
 
-	msm_otg_chg_type = debugfs_create_file("chg_type", S_IRUGO,
+	msm_otg_dentry = debugfs_create_file("chg_type", S_IRUGO,
 		msm_otg_dbg_root, motg,
 		&msm_otg_chg_fops);
 
-	if (!msm_otg_chg_type) {
+	if (!msm_otg_dentry) {
 		debugfs_remove_recursive(msm_otg_dbg_root);
 		return -ENODEV;
 	}
 
-	msm_otg_dbg_aca = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
+	msm_otg_dentry = debugfs_create_file("aca", S_IRUGO | S_IWUSR,
 		msm_otg_dbg_root, motg,
 		&msm_otg_aca_fops);
 
-	if (!msm_otg_dbg_aca) {
+	if (!msm_otg_dentry) {
 		debugfs_remove_recursive(msm_otg_dbg_root);
 		return -ENODEV;
 	}
 
+	msm_otg_dentry = debugfs_create_file("bus_voting", S_IRUGO | S_IWUSR,
+		msm_otg_dbg_root, motg,
+		&msm_otg_bus_fops);
+
+	if (!msm_otg_dentry) {
+		debugfs_remove_recursive(msm_otg_dbg_root);
+		return -ENODEV;
+	}
 	return 0;
 }
 
@@ -2642,6 +2702,8 @@
 		if (!motg->bus_perf_client)
 			dev_err(motg->otg.dev, "%s: Failed to register BUS "
 						"scaling client!!\n", __func__);
+		else
+			debug_bus_voting_enabled = true;
 	}
 
 	return 0;