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

Commit 164cc1b4 authored by Hemant Kumar's avatar Hemant Kumar Committed by Mayank Rana
Browse files

usb: phy-msm-qusb-v2: Add support for reference counting of regulators



Upon cable disconnect PMI calls qusb_phy_update_dpdm() to turn off phy
regulators before notifying vbus off to usb. As a result phy power down
sequence is executed with phy regulators turned off. This may result into
improper phy line state.  Fix this issue by adding a reference counter to
keep track of all regulator enable and disable requests and only disable
regulator when ref count becomes zero. Also add a mutex in
qusb_phy_enable_power() API to prevent any race condition in enabling and
disabling phy regulators between the callers i.e. PMI and phy driver.

Change-Id: I620f2b8cbf4f9271db81d5a517f1ee2a13c57f27
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
Signed-off-by: default avatarMayank Rana <mrana@codeaurora.org>
parent 7dc6372c
Loading
Loading
Loading
Loading
+33 −11
Original line number Diff line number Diff line
@@ -79,6 +79,7 @@ enum qusb_phy_reg {

struct qusb_phy {
	struct usb_phy		phy;
	struct mutex		lock;
	void __iomem		*base;
	void __iomem		*efuse_reg;

@@ -103,7 +104,7 @@ struct qusb_phy {
	int			efuse_bit_pos;
	int			efuse_num_of_bits;

	bool			power_enabled;
	int			power_enabled_ref;
	bool			clocks_enabled;
	bool			cable_connected;
	bool			suspended;
@@ -175,17 +176,32 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
{
	int ret = 0;

	dev_dbg(qphy->phy.dev, "%s turn %s regulators. power_enabled:%d\n",
			__func__, on ? "on" : "off", qphy->power_enabled);
	mutex_lock(&qphy->lock);

	if (qphy->power_enabled == on) {
		dev_dbg(qphy->phy.dev, "PHYs' regulators are already ON.\n");
		return 0;
	dev_dbg(qphy->phy.dev,
		"%s:req to turn %s regulators. power_enabled_ref:%d\n",
			__func__, on ? "on" : "off", qphy->power_enabled_ref);

	if (on && ++qphy->power_enabled_ref > 1) {
		dev_dbg(qphy->phy.dev, "PHYs' regulators are already on\n");
		goto done;
	}

	if (!on) {
		if (on == qphy->power_enabled_ref) {
			dev_dbg(qphy->phy.dev,
				"PHYs' regulators are already off\n");
			goto done;
		}

	if (!on)
		qphy->power_enabled_ref--;
		if (!qphy->power_enabled_ref)
			goto disable_vdda33;

		dev_dbg(qphy->phy.dev, "Skip turning off PHYs' regulators\n");
		goto done;
	}

	ret = qusb_phy_config_vdd(qphy, true);
	if (ret) {
		dev_err(qphy->phy.dev, "Unable to config VDD:%d\n",
@@ -239,9 +255,9 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
		goto unset_vdd33;
	}

	qphy->power_enabled = true;

	pr_debug("%s(): QUSB PHY's regulators are turned ON.\n", __func__);

	mutex_unlock(&qphy->lock);
	return ret;

disable_vdda33:
@@ -288,8 +304,13 @@ static int qusb_phy_enable_power(struct qusb_phy *qphy, bool on)
		dev_err(qphy->phy.dev, "Unable unconfig VDD:%d\n",
							ret);
err_vdd:
	qphy->power_enabled = false;
	dev_dbg(qphy->phy.dev, "QUSB PHY's regulators are turned OFF.\n");

	/* in case of error in turning on regulators */
	if (qphy->power_enabled_ref)
		qphy->power_enabled_ref--;
done:
	mutex_unlock(&qphy->lock);
	return ret;
}

@@ -960,6 +981,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
		return PTR_ERR(qphy->vdda18);
	}

	mutex_init(&qphy->lock);
	platform_set_drvdata(pdev, qphy);

	qphy->phy.label			= "msm-qusb-phy-v2";