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

Commit d39512aa authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "USB: PHY: msm: Improve power management handling for OTG"

parents c48e442e e8ec1217
Loading
Loading
Loading
Loading
+0 −5
Original line number Diff line number Diff line
@@ -135,10 +135,6 @@ Optional properties :
	to supply voltage to the D+ line during VDD minimization and peripheral
	bus suspend. If not exists, then VDD minimization will not be allowed
	during peripheral bus suspend.
- qcom,hsusb-otg-rw-during-lpm-workaround: If present, indicates that remote-
	wakeup during USB low-power mode SW workaround will be applied. When
	this workaround is applied, the PHCD and the FPR bits are written
	to the PORTSC register in the same register write operation.
- qcom,ahb-async-bridge-bypass: If present, indicates that enable AHB2AHB By Pass
	mode with device controller for better throughput. With this mode, USB Core
	runs using PNOC clock and synchronous to it. Hence it is must to have proper
@@ -210,7 +206,6 @@ Example HSUSB OTG controller device node :
		pinctrl-0 = <&vddmin_act>;
		pinctrl-0 = <&vddmin_sus>;
		qcom,hsusb-otg-vddmin-gpio = <&pm8019_mpps 6 0>;
		qcom,hsusb-otg-rw-during-lpm-workaround = <1>;
		qcom,disable-retention-with-vdd-min;
		qcom,usbin-vadc = <&pm8226_vadc>;
		qcom,usbid-gpio = <&msm_gpio 110 0>;
+1 −31
Original line number Diff line number Diff line
@@ -230,21 +230,6 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
	}
}

static bool ci13xxx_cancel_pending_suspend(struct ci13xxx *udc)
{
	struct msm_otg *otg;

	if (udc == NULL)
		return false;

	if (udc->transceiver == NULL)
		return false;

	otg = container_of(udc->transceiver, struct msm_otg, phy);

	return cancel_delayed_work_sync(&otg->suspend_work);
}

static bool ci13xxx_msm_in_lpm(struct ci13xxx *udc)
{
	struct msm_otg *otg;
@@ -260,20 +245,6 @@ static bool ci13xxx_msm_in_lpm(struct ci13xxx *udc)
	return (atomic_read(&otg->in_lpm) != 0);
}

static void ci13xxx_msm_set_fpr_flag(struct ci13xxx *udc)
{
	struct msm_otg *otg;

	if (udc == NULL)
		return;

	if (udc->transceiver == NULL)
		return;

	otg = container_of(udc->transceiver, struct msm_otg, phy);

	atomic_set(&otg->set_fpr_with_lpm_exit, 1);
}

static irqreturn_t ci13xxx_msm_resume_irq(int irq, void *data)
{
@@ -296,9 +267,7 @@ static struct ci13xxx_udc_driver ci13xxx_msm_udc_driver = {
				  CI13XXX_DISABLE_STREAMING,
	.nz_itc			= 0,
	.notify_event		= ci13xxx_msm_notify_event,
	.cancel_pending_suspend = ci13xxx_cancel_pending_suspend,
	.in_lpm                 = ci13xxx_msm_in_lpm,
	.set_fpr_flag           = ci13xxx_msm_set_fpr_flag,
};

static int ci13xxx_msm_install_wake_gpio(struct platform_device *pdev,
@@ -466,6 +435,7 @@ static int ci13xxx_msm_probe(struct platform_device *pdev)
							(unsigned long)NULL);

	pm_runtime_no_callbacks(&pdev->dev);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	return 0;
+12 −98
Original line number Diff line number Diff line
@@ -1653,7 +1653,6 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget)
{
	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
	unsigned long flags;
	bool skip_fpr = false;
	int ret = 0;

	trace();
@@ -1666,21 +1665,7 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget)
	}
	spin_unlock_irqrestore(udc->lock, flags);

	/* Make sure phy driver is done with its bus suspend handling */
	if (udc->udc_driver->cancel_pending_suspend)
		udc->udc_driver->cancel_pending_suspend(udc);

	if ((udc->udc_driver->in_lpm != NULL) &&
	    (udc->udc_driver->in_lpm(udc))) {
		if (udc->udc_driver->set_fpr_flag) {
			/* When USB HW is in low-power mode we set a flag
			 * for the OTG layer to set the FPR bit during the
			 * low-power mode mode exit sequence.
			 */
			udc->udc_driver->set_fpr_flag(udc);
			skip_fpr = true;
		}
	}
	pm_runtime_get_sync(&_gadget->dev);

	udc->udc_driver->notify_event(udc,
		CI13XXX_CONTROLLER_REMOTE_WAKEUP_EVENT);
@@ -1689,15 +1674,15 @@ static int ci13xxx_wakeup(struct usb_gadget *_gadget)
		usb_phy_set_suspend(udc->transceiver, 0);

	spin_lock_irqsave(udc->lock, flags);
	if (!skip_fpr) {
	if (!hw_cread(CAP_PORTSC, PORTSC_SUSP)) {
		ret = -EINVAL;
		dbg_trace("port is not suspended\n");
		pm_runtime_put_sync(&_gadget->dev);
		goto out;
	}
	hw_cwrite(CAP_PORTSC, PORTSC_FPR, PORTSC_FPR);
	}

	pm_runtime_put_sync(&_gadget->dev);
out:
	spin_unlock_irqrestore(udc->lock, flags);
	return ret;
@@ -2909,70 +2894,6 @@ delegate:
	}
}

/**
 * ci13xxx_exit_lpm: Exit controller from low power mode
 * @udc: UDC descriptor
 * @allow_sleep: Are we in preemptible context or not.
 *
 * This function check if controller is in low power mode and if so, exit from
 * the low power mode.
 *
 * In case the controller is in low power mode, registers are not accessible,
 * therefore this function can be used as utility function to ensure exit from
 * low power mode before do registers read/write operations.
 *
 * Return 0 if not in low power mode and read/write operations are safe.
 * Return -EAGAIN in case exit from low power mode was initiated, but it is not
 * safe yet to use read/write operations against the controller registers.
 */
static int ci13xxx_exit_lpm(struct ci13xxx *udc, bool allow_sleep)
{
	if (!udc)
		return -ENODEV;

	/* Make sure phy driver is done with its bus suspend handling */
	if (udc->udc_driver->cancel_pending_suspend && allow_sleep)
		udc->udc_driver->cancel_pending_suspend(udc);

	/* Check if the controller is in low power mode state */
	if (udc->udc_driver->in_lpm &&
	    udc->udc_driver->in_lpm(udc) &&
	    udc->transceiver) {

		dev_dbg(udc->transceiver->dev,
			"%s: Exit from low power mode\n",
			__func__);

		/*
		 * Resume of the controller may be done
		 * asynchronically in deffered context.
		 */
		usb_phy_set_suspend(udc->transceiver, 0);

		/*
		 * Wait for controller resume to finish in case of non atomic
		 * context or return EAGAIN otherwise.
		 */
		if (allow_sleep) {
			while (udc->udc_driver->in_lpm(udc))
				usleep_range(1, 10);
		} else {
			/*
			 * Return EAGAIN only in case controller resume
			 * was done asynchronically.
			 */
			if (udc->udc_driver->in_lpm(udc)) {
				dev_err(udc->transceiver->dev,
					"%s: Unable to exit lpm\n",
					__func__);
				return -EAGAIN;
			}
		}
	}

	return 0;
}

/******************************************************************************
 * ENDPT block
 *****************************************************************************/
@@ -3507,7 +3428,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)

	if (gadget_ready) {
		if (is_active) {
			pm_runtime_get_sync(&_gadget->dev);
			hw_device_reset(udc);
			if (udc->udc_driver->notify_event)
				udc->udc_driver->notify_event(udc,
@@ -3520,7 +3440,6 @@ static int ci13xxx_vbus_session(struct usb_gadget *_gadget, int is_active)
			if (udc->udc_driver->notify_event)
				udc->udc_driver->notify_event(udc,
					CI13XXX_CONTROLLER_DISCONNECT_EVENT);
			pm_runtime_put_sync(&_gadget->dev);
		}
	}

@@ -3556,7 +3475,6 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_active)
{
	struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
	unsigned long flags;
	int ret;

	spin_lock_irqsave(udc->lock, flags);
	udc->softconnect = is_active;
@@ -3567,17 +3485,12 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_active)
	}
	spin_unlock_irqrestore(udc->lock, flags);

	ret = ci13xxx_exit_lpm(udc, true);
	if (ret) {
		dev_err(udc->transceiver->dev,
			"%s: Unable to exit lpm %d, ignore pullup\n",
			__func__, ret);
		return ret;
	}
	pm_runtime_get_sync(&_gadget->dev);

	spin_lock_irqsave(udc->lock, flags);
	if (!udc->vbus_active) {
		spin_unlock_irqrestore(udc->lock, flags);
		pm_runtime_put_sync(&_gadget->dev);
		return 0;
	}
	if (is_active) {
@@ -3590,6 +3503,8 @@ static int ci13xxx_pullup(struct usb_gadget *_gadget, int is_active)
	}
	spin_unlock_irqrestore(udc->lock, flags);

	pm_runtime_put_sync(&_gadget->dev);

	return 0;
}

@@ -3736,7 +3651,6 @@ static int ci13xxx_stop(struct usb_gadget *gadget,
		spin_unlock_irqrestore(udc->lock, flags);
		_gadget_stop_activity(&udc->gadget);
		spin_lock_irqsave(udc->lock, flags);
		pm_runtime_put(&udc->gadget.dev);
	}

	spin_unlock_irqrestore(udc->lock, flags);
+0 −2
Original line number Diff line number Diff line
@@ -148,9 +148,7 @@ struct ci13xxx_udc_driver {
#define CI13XXX_CONTROLLER_ERROR_EVENT			7

	void	(*notify_event)(struct ci13xxx *udc, unsigned event);
	bool (*cancel_pending_suspend)(struct ci13xxx *udc);
	bool    (*in_lpm)(struct ci13xxx *udc);
	void    (*set_fpr_flag)(struct ci13xxx *udc);
	struct clk *system_clk;
};

+4 −40
Original line number Diff line number Diff line
@@ -149,6 +149,7 @@ static int ehci_msm_probe(struct platform_device *pdev)

	hcd->usb_phy = phy;
	device_init_wakeup(&pdev->dev, 1);
	pm_runtime_set_active(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	msm_bam_set_usb_host_dev(&pdev->dev);
@@ -180,69 +181,32 @@ static int ehci_msm_remove(struct platform_device *pdev)
}

#ifdef CONFIG_PM_RUNTIME
static int ehci_msm_runtime_idle(struct device *dev)
{
	dev_dbg(dev, "ehci runtime idle\n");
	return 0;
}

static int ehci_msm_runtime_suspend(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);

	dev_dbg(dev, "ehci runtime suspend\n");
	/*
	 * Notify OTG about suspend.  It takes care of
	 * putting the hardware in LPM.
	 */
	return usb_phy_set_suspend(hcd->usb_phy, 1);

	return 0;
}

static int ehci_msm_runtime_resume(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);
	int ret;
	u32 portsc;

	dev_dbg(dev, "ehci runtime resume\n");
	ret = usb_phy_set_suspend(hcd->usb_phy, 0);
	if (ret)
		return ret;

	portsc = readl_relaxed(USB_PORTSC);
	portsc &= ~PORT_RWC_BITS;
	portsc |= PORT_RESUME;
	writel_relaxed(portsc, USB_PORTSC);

	return ret;
}
#endif

#ifdef CONFIG_PM_SLEEP
static int ehci_msm_pm_suspend(struct device *dev)
{
	struct usb_hcd *hcd = dev_get_drvdata(dev);

	dev_dbg(dev, "ehci-msm PM suspend\n");

	if (!hcd->rh_registered)
		return 0;

	return usb_phy_set_suspend(hcd->usb_phy, 1);
}

static int ehci_msm_pm_resume(struct device *dev)
{
	dev_dbg(dev, "ehci-msm PM resume\n");

	return 0;
}
#endif

static const struct dev_pm_ops ehci_msm_dev_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(ehci_msm_pm_suspend, ehci_msm_pm_resume)
	SET_RUNTIME_PM_OPS(ehci_msm_runtime_suspend, ehci_msm_runtime_resume,
				ehci_msm_runtime_idle)
			   NULL)
};

static const struct of_device_id msm_ehci_dt_match[] = {
Loading