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

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

Merge "usb: dwc3: Fix recovery from power collapse"

parents 0f92a315 eb16984a
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -52,8 +52,10 @@ Optional properties :
- qcom,usb-dbm : phandle for the DBM device
- qcom,usbin-vadc: Corresponding vadc device's phandle to read usbin voltage using VADC.
	This will be used to get value of usb power supply's VOLTAGE_NOW property,
- qcom,no-power-collapse: If present, the USB core will not perform power collapse

- qcom,power-collapse-on-cable-disconnect: If present, USB core will perform
	power collapse when cable is disconencted.
- qcom,por-after-power-collapse: If present, a partial POR sequence will be performed
  when recovering from power collapse.
Sub nodes:
- Sub node for "DWC3- USB3 controller".
  This sub node is required property for device node. The properties of this subnode
+75 −7
Original line number Diff line number Diff line
@@ -183,6 +183,7 @@ struct dwc3_msm {
#define MDWC3_PHY_REF_AND_CORECLK_OFF	BIT(0)
#define MDWC3_TCXO_SHUTDOWN		BIT(1)
#define MDWC3_ASYNC_IRQ_WAKE_CAPABILITY	BIT(2)
#define MDWC3_POWER_COLLAPSE		BIT(7)

	u32 qscratch_ctl_val;
	dev_t ext_chg_dev;
@@ -195,7 +196,9 @@ struct dwc3_msm {
	unsigned int scm_dev_id;
	bool reset_hsphy_sleep_clk;
	bool suspend_resume_no_support;
	bool disable_power_collapse;

	bool power_collapse; /* power collapse on cable disconnect */
	bool power_collapse_por; /* perform POR sequence after power collapse */
	bool enable_suspend_event;
};

@@ -1392,6 +1395,50 @@ reset_hsphy_exit:
	return ret;
}

static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc)
{
	u32		reg;
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);

	/* Put Core in Reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GCTL);
	reg |= DWC3_GCTL_CORESOFTRESET;
	dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg);

	usb_phy_init(dwc->usb2_phy);

	/* Assert USB3 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0));
	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), reg);

	/* Assert USB2 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0));
	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0), reg);

	udelay(100);

	/* Clear USB3 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB3PIPECTL(0));
	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB3PIPECTL(0), reg);

	/* Clear USB2 PHY reset */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GUSB2PHYCFG(0));
	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
	dwc3_msm_write_reg(mdwc->base, DWC3_GUSB2PHYCFG(0), reg);

	udelay(100);
	/* After PHYs are stable we can take Core out of reset state */
	reg = dwc3_msm_read_reg(mdwc->base, DWC3_GCTL);
	reg &= ~DWC3_GCTL_CORESOFTRESET;
	dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg);

	udelay(100);
}


static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
{
	int ret, i;
@@ -1400,6 +1447,7 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
	bool host_ss_active;
	bool can_suspend_ssphy;
	bool device_bus_suspend;
	bool cable_connected = mdwc->vbus_active;

	dev_dbg(mdwc->dev, "%s: entering lpm. usb_lpm_override:%d\n",
					 __func__, usb_lpm_override);
@@ -1487,9 +1535,12 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
	/* make sure above writes are completed before turning off clocks */
	wmb();

	/* remove vote for controller power collapse */
	if (!host_bus_suspend && !mdwc->disable_power_collapse)
	/* Perform controller power collapse */
	if (!host_bus_suspend && mdwc->power_collapse && !cable_connected) {
		mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE;
		dev_dbg(mdwc->dev, "%s: power collapse\n", __func__);
		dwc3_msm_config_gdsc(mdwc, 0);
	}

	clk_disable_unprepare(mdwc->iface_clk);
	clk_disable_unprepare(mdwc->utmi_clk);
@@ -1576,9 +1627,11 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
		mdwc->lpm_flags &= ~MDWC3_TCXO_SHUTDOWN;
	}

	/* add vote for controller power collapse */
	if (!host_bus_suspend && !mdwc->disable_power_collapse)
	/* Restore controller power collapse */
	if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) {
		dev_dbg(mdwc->dev, "%s: exit power collapse\n", __func__);
		dwc3_msm_config_gdsc(mdwc, 1);
	}

	clk_prepare_enable(mdwc->utmi_clk);

@@ -1617,6 +1670,15 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
			return ret;
	}

	/* Recover from controller power collapse */
	if (mdwc->lpm_flags & MDWC3_POWER_COLLAPSE) {
		dev_dbg(mdwc->dev, "%s: exit power collapse (POR=%d)\n",
			__func__, mdwc->power_collapse_por);
		if (mdwc->power_collapse_por)
			dwc3_msm_power_collapse_por(mdwc);
		mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE;
	}

	if (resume_from_core_clk_off)
		usb_phy_set_suspend(mdwc->ss_phy, 0);
	atomic_set(&mdwc->in_lpm, 0);
@@ -2538,8 +2600,14 @@ static int dwc3_msm_probe(struct platform_device *pdev)
	mdwc->suspend_resume_no_support = of_property_read_bool(node,
				"qcom,no-suspend-resume");

	mdwc->disable_power_collapse = of_property_read_bool(node,
				"qcom,no-power-collapse");
	mdwc->power_collapse_por = of_property_read_bool(node,
		"qcom,por-after-power-collapse");

	mdwc->power_collapse = of_property_read_bool(node,
		"qcom,power-collapse-on-cable-disconnect");

	dev_dbg(&pdev->dev, "power collapse=%d, POR=%d\n",
		mdwc->power_collapse, mdwc->power_collapse_por);

	mdwc->enable_suspend_event = of_property_read_bool(node,
				"qcom,suspend_event_enable");