Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 50319b7a authored by Pavankumar Kondeti's avatar Pavankumar Kondeti Committed by Gerrit - the friendly Code Review server
Browse files

usb: phy-msm-usb: Improve the PHY suspend sequence



The controller aborts the PHY suspend during device bus suspend if
there is an incoming reset/resume from the host. Abort the LPM
sequence and enable the interrupt to handle the reset/resume.
The current code resets the USB hardware and it would result in
device disconnection in this scenario.

It is observed that PHCD bit is not getting set with in the specified
time during multiple plug in and plug out tests. If the LPM is not
initiated in the device bus suspend, retry setting the PHCD bit again.
The results indicate that the PHY suspend works after the 1st attempt.
If this fails for 3 times, reset the USB hardware and retry the LPM
sequence.

The PHY suspend timeout value is modified from 500 msec to 100 usec
for device bus suspend and 5 msec for other other scenarios as per the
databook recommendation.

CRs-Fixed: 747392
Change-Id: Ie76d7a0eaff2fe40357e3af92014aa0b3b17a88c
Signed-off-by: default avatarPavankumar Kondeti <pkondeti@codeaurora.org>
parent 29b31d57
Loading
Loading
Loading
Loading
+64 −18
Original line number Diff line number Diff line
@@ -1191,9 +1191,12 @@ static irqreturn_t msm_otg_phy_irq_handler(int irq, void *data)
	return IRQ_HANDLED;
}

#define PHY_SUSPEND_TIMEOUT_USEC	(500 * 1000)
#define PHY_SUSPEND_TIMEOUT_USEC (5 * 1000)
#define PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC 100
#define PHY_RESUME_TIMEOUT_USEC	(100 * 1000)

#define PHY_SUSPEND_RETRIES_MAX 3

#ifdef CONFIG_PM_SLEEP
static int msm_otg_suspend(struct msm_otg *motg)
{
@@ -1206,9 +1209,9 @@ static int msm_otg_suspend(struct msm_otg *motg)
	u32 cmd_val;
	u32 portsc, config2;
	u32 func_ctrl;
	int phcd_retry_cnt = 0;
	int phcd_retry_cnt = 0, ret;
	unsigned phy_suspend_timeout;

phcd_retry:
	cnt = 0;

	if (atomic_read(&motg->in_lpm))
@@ -1226,6 +1229,7 @@ phcd_retry:

	motg->ui_enabled = 0;
	disable_irq(motg->irq);
lpm_start:
	host_bus_suspend = !test_bit(MHL, &motg->inputs) && phy->otg->host &&
		!test_bit(ID, &motg->inputs);
	device_bus_suspend = phy->otg->gadget && test_bit(ID, &motg->inputs) &&
@@ -1277,16 +1281,39 @@ phcd_retry:
						ULPI_CLR(ULPI_IFC_CTRL));
	}

	/* Set the PHCD bit, only if it is not set by the controller.
	 * PHY may take some time or even fail to enter into low power
	 * mode (LPM). Hence poll for 500 msec and reset the PHY and link
	 * in failure case.
	/*
	 * PHY suspend sequence as mentioned in the databook.
	 *
	 * Device bus suspend: The controller may abort PHY suspend if
	 * there is an incoming reset or resume from the host. If PHCD
	 * is not set within 100 usec. Abort the LPM sequence.
	 *
	 * Host bus suspend: If the peripheral is attached, PHY is already
	 * put into suspend along with the peripheral bus suspend. poll for
	 * PHCD upto 5 msec. If the peripheral is not attached i.e entering
	 * LPM with Micro-A cable, set the PHCD and poll for it for 5 msec.
	 *
	 * No cable connected: Set the PHCD to suspend the PHY. Poll for PHCD
	 * upto 5 msec.
	 *
	 * The controller aborts PHY suspend only in device bus suspend case.
	 * In other cases, it is observed that PHCD may not get set within
	 * the timeout. If so, set the PHCD again and poll for it before
	 * reset recovery.
	 */

phcd_retry:
	if (device_bus_suspend)
		phy_suspend_timeout = PHY_DEVICE_BUS_SUSPEND_TIMEOUT_USEC;
	else
		phy_suspend_timeout = PHY_SUSPEND_TIMEOUT_USEC;

	cnt = 0;
	portsc = readl_relaxed(USB_PORTSC);
	if (!(portsc & PORTSC_PHCD)) {
		writel_relaxed(portsc | PORTSC_PHCD,
				USB_PORTSC);
		while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
		while (cnt < phy_suspend_timeout) {
			if (readl_relaxed(USB_PORTSC) & PORTSC_PHCD)
				break;
			udelay(1);
@@ -1294,16 +1321,29 @@ phcd_retry:
		}
	}

	if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
		dev_err(phy->dev, "Unable to suspend PHY\n");
	if (cnt >= phy_suspend_timeout) {
		if (phcd_retry_cnt > PHY_SUSPEND_RETRIES_MAX) {
			dev_err(phy->dev, "PHY suspend failed\n");
			ret = -EBUSY;
			goto phy_suspend_fail;
		}

		if (device_bus_suspend) {
			dev_dbg(phy->dev, "PHY suspend aborted\n");
			ret = -EBUSY;
			goto phy_suspend_fail;
		} else {
			if (phcd_retry_cnt++ < PHY_SUSPEND_RETRIES_MAX) {
				dev_dbg(phy->dev, "PHY suspend retry\n");
				goto phcd_retry;
			} else {
				dev_err(phy->dev, "reset attempt during PHY suspend\n");
				phcd_retry_cnt++;
				motg->reset_counter = 0;
				msm_otg_reset(phy);
		motg->ui_enabled = 1;
		enable_irq(motg->irq);
		if (phcd_retry_cnt++ < 3)
			goto phcd_retry;
		else
			return -EBUSY;
				goto lpm_start;
			}
		}
	}

	/*
@@ -1484,6 +1524,11 @@ phcd_retry:
	dev_info(phy->dev, "USB in low power mode\n");

	return 0;

phy_suspend_fail:
	motg->ui_enabled = 1;
	enable_irq(motg->irq);
	return ret;
}

static int msm_otg_resume(struct msm_otg *motg)
@@ -3258,6 +3303,7 @@ static void msm_otg_sm_work(struct work_struct *w)
			if (motg->caps & ALLOW_LPM_ON_DEV_SUSPEND) {
				pm_runtime_put_noidle(otg->phy->dev);
				pm_runtime_suspend(otg->phy->dev);
				motg->pm_done = 1;
			}
		} else if (test_bit(ID_C, &motg->inputs)) {
			msm_otg_notify_charger(motg, IDEV_ACA_CHG_MAX);