usb: gadget: Vote for SWFI when USB cable is connected

To enable better power management and entering CPU idle states while
USB cable is connected and no USB SW involvement is required
(MSM BAM2BAM mode) a new SysFS was added.
This SysFS allow controlling USB voting and gives the ability
to save power consumption while USB is active.
default behavior is high QoS. to change the new SysFS
echo high/low to /sys/class/android_usb/android0/pm_qos

Change-Id: Ia73491cfddc3968e1d04423a1750c89fab5fefeb
Signed-off-by: Ofir Cohen <ofirc@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-8064.c b/arch/arm/mach-msm/board-8064.c
index aaf1879..cfaa7da 100644
--- a/arch/arm/mach-msm/board-8064.c
+++ b/arch/arm/mach-msm/board-8064.c
@@ -2595,8 +2595,8 @@
 	if (machine_is_apq8064_liquid())
 		msm_otg_pdata.mhl_enable = true;
 
-	msm_otg_pdata.swfi_latency =
-		msm_rpmrs_levels[0].latency_us + 1;
+	android_usb_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
 
 	apq8064_device_otg.dev.platform_data = &msm_otg_pdata;
 	apq8064_ehci_host_init();
diff --git a/arch/arm/mach-msm/board-8960.c b/arch/arm/mach-msm/board-8960.c
index dddf65d..42dbbee 100644
--- a/arch/arm/mach-msm/board-8960.c
+++ b/arch/arm/mach-msm/board-8960.c
@@ -3104,7 +3104,7 @@
 			msm_otg_pdata.phy_init_seq =
 				liquid_v1_phy_init_seq;
 	}
-	msm_otg_pdata.swfi_latency =
+	android_usb_pdata.swfi_latency =
 		msm_rpmrs_levels[0].latency_us;
 	msm_device_hsic_host.dev.platform_data = &msm_hsic_pdata;
 	if (SOCINFO_VERSION_MAJOR(socinfo_get_version()) >= 2 &&
diff --git a/arch/arm/mach-msm/board-9615.c b/arch/arm/mach-msm/board-9615.c
index 434df6e..b128223 100644
--- a/arch/arm/mach-msm/board-9615.c
+++ b/arch/arm/mach-msm/board-9615.c
@@ -620,18 +620,6 @@
 	return 0;
 }
 
-static struct android_usb_platform_data android_usb_pdata = {
-	.update_pid_and_serial_num = usb_diag_update_pid_and_serial_num,
-};
-
-static struct platform_device android_usb_device = {
-	.name	= "android_usb",
-	.id	= -1,
-	.dev	= {
-		.platform_data = &android_usb_pdata,
-	},
-};
-
 static struct platform_device msm_wlan_ar6000_pm_device = {
 	.name           = "wlan_ar6000_pm_dev",
 	.id             = -1,
@@ -678,7 +666,7 @@
 	&msm_device_hsusb_host,
 	&msm_device_hsic_host,
 	&msm_device_usb_bam,
-	&android_usb_device,
+	&msm_android_usb_device,
 	&msm9615_device_uart_gsbi4,
 	&msm9615_device_ext_2p95v_vreg,
 	&msm9615_device_ssbi_pmic1,
@@ -749,6 +737,9 @@
 
 static void __init msm9615_common_init(void)
 {
+	struct android_usb_platform_data *android_pdata =
+				msm_android_usb_device.dev.platform_data;
+
 	msm9615_device_init();
 	msm9615_init_gpiomux();
 	msm9615_i2c_init();
@@ -776,6 +767,8 @@
 	msm9615_init_mmc();
 	slim_register_board_info(msm_slim_devices,
 		ARRAY_SIZE(msm_slim_devices));
+	android_pdata->update_pid_and_serial_num =
+					usb_diag_update_pid_and_serial_num;
 	msm_pm_boot_pdata.p_addr = allocate_contiguous_ebi_nomap(SZ_8, SZ_64K);
 	BUG_ON(msm_pm_boot_init(&msm_pm_boot_pdata));
 	msm_tsens_early_init(&msm_tsens_pdata);
diff --git a/arch/arm/mach-msm/devices-9615.c b/arch/arm/mach-msm/devices-9615.c
index 34298c5..c084d29 100644
--- a/arch/arm/mach-msm/devices-9615.c
+++ b/arch/arm/mach-msm/devices-9615.c
@@ -19,6 +19,7 @@
 #include <linux/dma-mapping.h>
 #include <sound/msm-dai-q6.h>
 #include <sound/apr_audio.h>
+#include <linux/usb/android.h>
 #include <asm/hardware/gic.h>
 #include <asm/mach/flash.h>
 #include <mach/board.h>
@@ -1247,11 +1248,36 @@
 	},
 };
 
+uint32_t __init msm9615_rpm_get_swfi_latency(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(msm_rpmrs_levels); i++) {
+		if (msm_rpmrs_levels[i].sleep_mode ==
+			MSM_PM_SLEEP_MODE_WAIT_FOR_INTERRUPT)
+				return msm_rpmrs_levels[i].latency_us;
+	}
+	return 0;
+}
+
+struct android_usb_platform_data msm_android_usb_pdata;
+
+struct platform_device msm_android_usb_device = {
+	.name	= "android_usb",
+	.id	= -1,
+	.dev	= {
+		.platform_data = &msm_android_usb_pdata,
+	},
+};
+
 void __init msm9615_device_init(void)
 {
 	msm_spm_init(msm_spm_data, ARRAY_SIZE(msm_spm_data));
 	BUG_ON(msm_rpm_init(&msm9615_rpm_data));
 	BUG_ON(msm_rpmrs_levels_init(&msm_rpmrs_data));
+	msm_android_usb_pdata.swfi_latency =
+		msm_rpmrs_levels[0].latency_us;
+
 }
 
 #define MSM_SHARED_RAM_PHYS 0x40000000
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 8e9beb6..f7f0611 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -109,6 +109,7 @@
 extern struct platform_device msm_device_hsic_host;
 
 extern struct platform_device msm_device_otg;
+extern struct platform_device msm_android_usb_device;
 extern struct platform_device msm_device_hsic_peripheral;
 extern struct platform_device msm8960_device_otg;
 extern struct platform_device msm8960_device_gadget_peripheral;
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index fd119c6..c017859 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/utsname.h>
 #include <linux/platform_device.h>
+#include <linux/pm_qos_params.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/composite.h>
@@ -121,6 +122,8 @@
 	struct mutex mutex;
 	bool connected;
 	bool sw_connected;
+	char pm_qos[5];
+	struct pm_qos_request_list pm_qos_req_dma;
 	struct work_struct work;
 };
 
@@ -191,6 +194,25 @@
 	USB_CONFIGURED,
 };
 
+static void android_pm_qos_update_latency(struct android_dev *dev, int vote)
+{
+	struct android_usb_platform_data *pdata = dev->pdata;
+	u32 swfi_latency = 0;
+	static int last_vote = -1;
+
+	if (!pdata || vote == last_vote)
+		return;
+
+	swfi_latency = pdata->swfi_latency + 1;
+	if (vote)
+		pm_qos_update_request(&dev->pm_qos_req_dma,
+				swfi_latency);
+	else
+		pm_qos_update_request(&dev->pm_qos_req_dma,
+				PM_QOS_DEFAULT_VALUE);
+	last_vote = vote;
+}
+
 static void android_work(struct work_struct *data)
 {
 	struct android_dev *dev = container_of(data, struct android_dev, work);
@@ -209,6 +231,10 @@
 	} else if (dev->connected != dev->sw_connected) {
 		uevent_envp = dev->connected ? connected : disconnected;
 		next_state = dev->connected ? USB_CONNECTED : USB_DISCONNECTED;
+		if (dev->connected && strncmp(dev->pm_qos, "low", 3))
+			android_pm_qos_update_latency(dev, 1);
+		else if (!dev->connected || !strncmp(dev->pm_qos, "low", 3))
+			android_pm_qos_update_latency(dev, 0);
 	}
 	dev->sw_connected = dev->connected;
 	spin_unlock_irqrestore(&cdev->lock, flags);
@@ -1313,6 +1339,25 @@
 	return size;
 }
 
+static ssize_t pm_qos_show(struct device *pdev,
+			   struct device_attribute *attr, char *buf)
+{
+	struct android_dev *dev = dev_get_drvdata(pdev);
+
+	return snprintf(buf, PAGE_SIZE, "%s\n", dev->pm_qos);
+}
+
+static ssize_t pm_qos_store(struct device *pdev,
+			   struct device_attribute *attr,
+			   const char *buff, size_t size)
+{
+	struct android_dev *dev = dev_get_drvdata(pdev);
+
+	strlcpy(dev->pm_qos, buff, sizeof(dev->pm_qos));
+
+	return size;
+}
+
 static ssize_t state_show(struct device *pdev, struct device_attribute *attr,
 			   char *buf)
 {
@@ -1387,6 +1432,8 @@
 
 static DEVICE_ATTR(functions, S_IRUGO | S_IWUSR, functions_show, functions_store);
 static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR, enable_show, enable_store);
+static DEVICE_ATTR(pm_qos, S_IRUGO | S_IWUSR,
+		pm_qos_show, pm_qos_store);
 static DEVICE_ATTR(state, S_IRUGO, state_show, NULL);
 static DEVICE_ATTR(remote_wakeup, S_IRUGO | S_IWUSR,
 		remote_wakeup_show, remote_wakeup_store);
@@ -1403,6 +1450,7 @@
 	&dev_attr_iSerial,
 	&dev_attr_functions,
 	&dev_attr_enable,
+	&dev_attr_pm_qos,
 	&dev_attr_state,
 	&dev_attr_remote_wakeup,
 	NULL
@@ -1630,6 +1678,12 @@
 		goto err_probe;
 	}
 
+	/* pm qos request to prevent apps idle power collapse */
+	if (pdata->swfi_latency)
+		pm_qos_add_request(&dev->pm_qos_req_dma,
+			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
+	strlcpy(dev->pm_qos, "high", sizeof(dev->pm_qos));
+
 	return ret;
 err_probe:
 	android_destroy_device(dev);
@@ -1641,10 +1695,14 @@
 static int android_remove(struct platform_device *pdev)
 {
 	struct android_dev *dev = _android_dev;
+	struct android_usb_platform_data *pdata = pdev->dev.platform_data;
 
 	android_destroy_device(dev);
 	class_destroy(android_class);
 	usb_composite_unregister(&android_usb_driver);
+	if (pdata->swfi_latency)
+		pm_qos_remove_request(&dev->pm_qos_req_dma);
+
 	return 0;
 }
 
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index f319eb5..4dd6aff 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -39,7 +39,6 @@
 #include <linux/regulator/consumer.h>
 #include <linux/mfd/pm8xxx/pm8921-charger.h>
 #include <linux/mfd/pm8xxx/misc.h>
-#include <linux/pm_qos_params.h>
 #include <linux/power_supply.h>
 
 #include <mach/clk.h>
@@ -71,25 +70,6 @@
 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)
-{
-	struct msm_otg_platform_data *pdata = dev->pdata;
-	u32 swfi_latency = 0;
-
-	if (!pdata || !pdata->swfi_latency)
-		return;
-
-	swfi_latency = pdata->swfi_latency + 1;
-
-	if (vote)
-		pm_qos_update_request(&dev->pm_qos_req_dma,
-				swfi_latency);
-	else
-		pm_qos_update_request(&dev->pm_qos_req_dma,
-				PM_QOS_DEFAULT_VALUE);
-}
-
 static struct regulator *hsusb_3p3;
 static struct regulator *hsusb_1p8;
 static struct regulator *hsusb_vddcx;
@@ -1308,11 +1288,7 @@
 		 */
 		if (pdata->setup_gpio)
 			pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
-		/*
-		 * vote for minimum dma_latency to prevent idle
-		 * power collapse(pc) while running in peripheral mode.
-		 */
-		otg_pm_qos_update_latency(motg, 1);
+
 		/* Configure BUS performance parameters for MAX bandwidth */
 		if (motg->bus_perf_client && debug_bus_voting_enabled) {
 			ret = msm_bus_scale_client_update_request(
@@ -1325,7 +1301,6 @@
 	} else {
 		dev_dbg(otg->dev, "gadget off\n");
 		usb_gadget_vbus_disconnect(otg->gadget);
-		otg_pm_qos_update_latency(motg, 0);
 		/* Configure BUS performance parameters to default */
 		if (motg->bus_perf_client) {
 			ret = msm_bus_scale_client_update_request(
@@ -3213,11 +3188,6 @@
 	else
 		clk_set_rate(motg->clk, 60000000);
 
-	/* pm qos request to prevent apps idle power collapse */
-	if (motg->pdata->swfi_latency)
-		pm_qos_add_request(&motg->pm_qos_req_dma,
-			PM_QOS_CPU_DMA_LATENCY, PM_QOS_DEFAULT_VALUE);
-
 	/*
 	 * USB Core is running its protocol engine based on CORE CLK,
 	 * CORE CLK  must be running at >55Mhz for correct HSUSB
@@ -3452,8 +3422,6 @@
 	if (!IS_ERR(motg->phy_reset_clk))
 		clk_put(motg->phy_reset_clk);
 free_motg:
-	if (motg->pdata->swfi_latency)
-		pm_qos_remove_request(&motg->pm_qos_req_dma);
 	kfree(motg);
 	return ret;
 }
@@ -3523,9 +3491,6 @@
 		clk_put(motg->clk);
 	clk_put(motg->core_clk);
 
-	if (motg->pdata->swfi_latency)
-		pm_qos_remove_request(&motg->pm_qos_req_dma);
-
 	if (motg->bus_perf_client)
 		msm_bus_scale_unregister_client(motg->bus_perf_client);
 
diff --git a/include/linux/usb/android.h b/include/linux/usb/android.h
index 9d7e4a8..6d3c3ad 100644
--- a/include/linux/usb/android.h
+++ b/include/linux/usb/android.h
@@ -19,6 +19,7 @@
 
 struct android_usb_platform_data {
 	int (*update_pid_and_serial_num)(uint32_t, const char *);
+	u32 swfi_latency;
 };
 
 #endif	/* __LINUX_USB_ANDROID_H */
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 4c0ae07..14d49eb 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -23,7 +23,6 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/wakelock.h>
-#include <linux/pm_qos_params.h>
 
 /*
  * The following are bit fields describing the usb_request.udc_priv word.
@@ -188,7 +187,6 @@
  * @mhl_enable: indicates MHL connector or not.
  * @disable_reset_on_disconnect: perform USB PHY and LINK reset
  *              on USB cable disconnection.
- * @swfi_latency: miminum latency to allow swfi.
  * @enable_dcd: Enable Data Contact Detection circuit. if not set
  *              wait for 600msec before proceeding to primary
  *              detection.
@@ -206,7 +204,6 @@
 	int pmic_id_irq;
 	bool mhl_enable;
 	bool disable_reset_on_disconnect;
-	u32 swfi_latency;
 	bool enable_dcd;
 	struct msm_bus_scale_pdata *bus_scale_table;
 };
@@ -277,8 +274,6 @@
  *             connected. Useful only when ACA_A charger is
  *             connected.
  * @mA_port: The amount of current drawn by the attached B-device.
- * @pm_qos_req_dma: miminum DMA latency to vote against idle power
-	collapse when cable is connected.
  * @id_timer: The timer used for polling ID line to detect ACA states.
  * @xo_handle: TCXO buffer handle
  * @bus_perf_client: Bus performance client handle to request BUS bandwidth
@@ -341,7 +336,6 @@
 	unsigned long lpm_flags;
 #define PHY_PWR_COLLAPSED		BIT(0)
 #define PHY_RETENTIONED			BIT(1)
-	struct pm_qos_request_list pm_qos_req_dma;
 	int reset_counter;
 	unsigned long b_last_se0_sess;
 	unsigned long tmouts;