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/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);