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

Commit d759a98e authored by Vamsi Krishna Samavedam's avatar Vamsi Krishna Samavedam
Browse files

dwc3-msm: reset hardware on bootup if cable not connected



commit b8177195 ("usb: dwc3: Start the core in host mode only if
there is no extcon") removed starting usb state machine from probe which
will reset controller/phy and put them in low power mode. Without it,
HW will be in POR state which might not be optimal low power state.
Also, check for dpdm regulator status before starting state machine
as it might interfere with apsd (automatic power source detection).

Change-Id: I178ec1e115a79ee19a1c43c74f01dd72c8b12a4b
Signed-off-by: default avatarVamsi Krishna Samavedam <vskrishn@codeaurora.org>
parent 2625e6e7
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -46,6 +46,8 @@ Optional properties :
- vbus_dwc3-supply: phandle to the 5V VBUS supply regulator used for host mode.
- USB3_GDSC-supply : phandle to the globally distributed switch controller
  regulator node to the USB controller.
- dpdm-supply: phandle to dpdm supply which will be used to drive dp/dm lines
  in high-z state.
- qcom,dwc-usb3-msm-tx-fifo-size: If present, represents RAM size available for
		TX fifo allocation in bytes
- qcom,lpm-to-suspend-delay-ms: Indicates timeout (in milliseconds) to release wakeup source
+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
		interrupts = <0 25 0>, <0 319 0>;
		interrupt-names = "pwr_event_irq", "hs_phy_irq";

		dpdm-supply = <&usb2_phy0>;
		clocks = <&clock_gcc GCC_USB30_MASTER_CLK>,
			 <&clock_gcc GCC_SYS_NOC_USB3_CLK>,
			 <&clock_gcc GCC_USB30_SLEEP_CLK>,
+1 −0
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@
		qcom,use-pdc-interrupts;

		USB3_GDSC-supply = <&usb30_prim_gdsc>;
		dpdm-supply = <&usb2_phy0>;
		clocks = <&clock_gcc GCC_USB30_PRIM_MASTER_CLK>,
			<&clock_gcc GCC_CFG_NOC_USB3_PRIM_AXI_CLK>,
			<&clock_gcc GCC_AGGRE_USB3_PRIM_AXI_CLK>,
+74 −0
Original line number Diff line number Diff line
@@ -37,6 +37,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/of.h>
#include <linux/regulator/consumer.h>
#include <linux/regulator/driver.h>
#include <linux/pm_wakeup.h>
#include <linux/power_supply.h>
#include <linux/cdev.h>
@@ -320,6 +321,10 @@ struct dwc3_msm {
	enum usb_device_speed override_usb_speed;
	u32			*gsi_reg;
	int			gsi_reg_offset_cnt;

	struct notifier_block	dpdm_nb;
	struct regulator	*dpdm_reg;

};

#define USB_HSPHY_3P3_VOL_MIN		3050000 /* uV */
@@ -2776,6 +2781,17 @@ static void dwc3_resume_work(struct work_struct *w)
			dwc->gadget.is_selfpowered = 0;
	}

	/*
	 * Skip scheduling sm work if no work is pending. When boot-up
	 * with USB cable connected, usb state m/c is skipped to avoid
	 * any changes to dp/dm lines. As PM supsend and resume can
	 * happen while charger is connected, scheduling sm work during
	 * pm resume will reset the controller and phy which might impact
	 * dp/dm lines (and charging voltage).
	 */
	if (mdwc->drd_state == DRD_STATE_UNDEFINED &&
		!edev && !mdwc->resume_pending)
		return;
	/*
	 * exit LPM first to meet resume timeline from device side.
	 * resume_pending flag would prevent calling
@@ -3389,6 +3405,29 @@ static ssize_t bus_vote_store(struct device *dev,
}
static DEVICE_ATTR_RW(bus_vote);

static int dwc_dpdm_cb(struct notifier_block *nb, unsigned long evt, void *p)
{
	struct dwc3_msm *mdwc = container_of(nb, struct dwc3_msm, dpdm_nb);

	switch (evt) {
	case REGULATOR_EVENT_ENABLE:
		dev_dbg(mdwc->dev, "%s: enable state:%s\n", __func__,
				dwc3_drd_state_string(mdwc->drd_state));
		break;
	case REGULATOR_EVENT_DISABLE:
		dev_dbg(mdwc->dev, "%s: disable state:%s\n", __func__,
				dwc3_drd_state_string(mdwc->drd_state));
		if (mdwc->drd_state == DRD_STATE_UNDEFINED)
			schedule_delayed_work(&mdwc->sm_work, 0);
		break;
	default:
		dev_dbg(mdwc->dev, "%s: unknown event state:%s\n", __func__,
				dwc3_drd_state_string(mdwc->drd_state));
		break;
	}

	return NOTIFY_OK;
}
static int dwc3_msm_probe(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node, *dwc3_node;
@@ -3696,6 +3735,29 @@ static int dwc3_msm_probe(struct platform_device *pdev)
		ret = dwc3_msm_extcon_register(mdwc);
		if (ret)
			goto put_dwc3;

		/*
		 * dpdm regulator will be turned on to perform apsd
		 * (automatic power source detection). dpdm regulator is
		 * used to float (or high-z) dp/dm lines. Do not reset
		 * controller/phy if regulator is turned on.
		 * if dpdm is not present controller can be reset
		 * as this controller may not be used for charger detection.
		 */
		mdwc->dpdm_reg = devm_regulator_get(&pdev->dev, "dpdm");
		if (IS_ERR(mdwc->dpdm_reg)) {
			dev_dbg(mdwc->dev, "assume cable is not connected\n");
			mdwc->dpdm_reg = NULL;
		}

		if (!mdwc->vbus_active && mdwc->dpdm_reg &&
				regulator_is_enabled(mdwc->dpdm_reg)) {
			mdwc->dpdm_nb.notifier_call = dwc_dpdm_cb;
			regulator_register_notifier(mdwc->dpdm_reg,
					&mdwc->dpdm_nb);
		} else {
			queue_delayed_work(mdwc->sm_usb_wq, &mdwc->sm_work, 0);
		}
	} else {
		if ((dwc->dr_mode == USB_DR_MODE_OTG &&
		     !of_property_read_bool(node, "qcom,default-mode-host")) ||
@@ -3743,6 +3805,12 @@ static int dwc3_msm_remove(struct platform_device *pdev)
	int ret_pm;

	device_remove_file(&pdev->dev, &dev_attr_mode);

	if (mdwc->dpdm_nb.notifier_call) {
		regulator_unregister_notifier(mdwc->dpdm_reg, &mdwc->dpdm_nb);
		mdwc->dpdm_nb.notifier_call = NULL;
	}

	if (mdwc->usb_psy)
		power_supply_put(mdwc->usb_psy);

@@ -4299,6 +4367,12 @@ static void dwc3_otg_sm_work(struct work_struct *w)
	/* Check OTG state */
	switch (mdwc->drd_state) {
	case DRD_STATE_UNDEFINED:
		if (mdwc->dpdm_nb.notifier_call) {
			regulator_unregister_notifier(mdwc->dpdm_reg,
					&mdwc->dpdm_nb);
			mdwc->dpdm_nb.notifier_call = NULL;
		}

		/* put controller and phy in suspend if no cable connected */
		if (test_bit(ID, &mdwc->inputs) &&
				!test_bit(B_SESS_VLD, &mdwc->inputs)) {