usb: gadget: Add support for USB going into LPM on bus suspend
This change adds the ability of the msm_otg to go to LPM when
USB cable is connected and bus is suspended.
This ability is enabled by a board file parameter.
The msm_otg is notified about SUSPEND/RESUME events via the
UDC layer. New event for RESUME was defined for that.
Change-Id: Ic508f1898cc3b57ab76eccd379bea38ed363570b
Signed-off-by: Amit Blay <ablay@codeaurora.org>
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 0ff0a48..5b05c5b 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -673,8 +673,7 @@
{
struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
- if (aca_enabled() || (test_bit(ID, &motg->inputs) &&
- !test_bit(ID_A, &motg->inputs)))
+ if (aca_enabled())
return 0;
if (suspend) {
@@ -688,6 +687,14 @@
clear_bit(A_BUS_REQ, &motg->inputs);
queue_work(system_nrt_wq, &motg->sm_work);
break;
+ case OTG_STATE_B_PERIPHERAL:
+ pr_debug("peripheral bus suspend\n");
+ if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+ break;
+ set_bit(A_BUS_SUSPEND, &motg->inputs);
+ queue_work(system_nrt_wq, &motg->sm_work);
+ break;
+
default:
break;
}
@@ -701,6 +708,13 @@
/* ensure hardware is not in low power mode */
pm_runtime_resume(otg->dev);
break;
+ case OTG_STATE_B_PERIPHERAL:
+ pr_debug("peripheral bus resume\n");
+ if (!(motg->caps & ALLOW_LPM_ON_DEV_SUSPEND))
+ break;
+ clear_bit(A_BUS_SUSPEND, &motg->inputs);
+ queue_work(system_nrt_wq, &motg->sm_work);
+ break;
default:
break;
}
@@ -718,7 +732,7 @@
struct usb_bus *bus = otg->host;
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
- bool host_bus_suspend, dcp;
+ bool host_bus_suspend, device_bus_suspend, dcp;
u32 phy_ctrl_val = 0, cmd_val;
unsigned ret;
u32 portsc;
@@ -728,6 +742,9 @@
disable_irq(motg->irq);
host_bus_suspend = otg->host && !test_bit(ID, &motg->inputs);
+ device_bus_suspend = otg->gadget && test_bit(ID, &motg->inputs) &&
+ test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+ motg->caps & ALLOW_LPM_ON_DEV_SUSPEND;
dcp = motg->chg_type == USB_DCP_CHARGER;
/*
* Chipidea 45-nm PHY suspend sequence:
@@ -791,8 +808,8 @@
* PMIC notifications are unavailable.
*/
cmd_val = readl_relaxed(USB_USBCMD);
- if (host_bus_suspend || (motg->pdata->otg_control == OTG_PHY_CONTROL &&
- dcp))
+ if (host_bus_suspend || device_bus_suspend ||
+ (motg->pdata->otg_control == OTG_PHY_CONTROL && dcp))
cmd_val |= ASYNC_INTR_CTRL | ULPI_STP_CTRL;
else
cmd_val |= ULPI_STP_CTRL;
@@ -802,7 +819,8 @@
* BC1.2 spec mandates PD to enable VDP_SRC when charging from DCP.
* PHY retention and collapse can not happen with VDP_SRC enabled.
*/
- if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend && !dcp) {
+ if (motg->caps & ALLOW_PHY_RETENTION && !host_bus_suspend &&
+ !device_bus_suspend && !dcp) {
phy_ctrl_val = readl_relaxed(USB_PHY_CTRL);
if (motg->pdata->otg_control == OTG_PHY_CONTROL)
/* Enable PHY HV interrupts to wake MPM/Link */
@@ -2133,6 +2151,13 @@
*/
otg->host->is_b_host = 1;
msm_otg_start_host(otg, 1);
+ } else if (test_bit(A_BUS_SUSPEND, &motg->inputs) &&
+ test_bit(B_SESS_VLD, &motg->inputs)) {
+ pr_debug("a_bus_suspend && b_sess_vld\n");
+ if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
+ pm_runtime_put_noidle(otg->dev);
+ pm_runtime_suspend(otg->dev);
+ }
} else if (test_bit(ID_C, &motg->inputs)) {
msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);
}
@@ -2569,6 +2594,8 @@
} else {
pr_debug("BSV clear\n");
clear_bit(B_SESS_VLD, &motg->inputs);
+ clear_bit(A_BUS_SUSPEND, &motg->inputs);
+
msm_chg_check_aca_intr(motg);
}
work = 1;
@@ -3389,6 +3416,9 @@
motg->caps = ALLOW_PHY_RETENTION;
}
+ if (motg->pdata->enable_lpm_on_dev_suspend)
+ motg->caps |= ALLOW_LPM_ON_DEV_SUSPEND;
+
wake_lock(&motg->wlock);
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);