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

Commit 72097316 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-msm: Handle erratic event with full POR sequence"

parents 32d0ae45 ecb5fa75
Loading
Loading
Loading
Loading
+34 −86
Original line number Diff line number Diff line
@@ -167,7 +167,7 @@ struct dwc3_msm {
	int			hs_phy_irq;
	struct delayed_work	resume_work;
	struct work_struct	restart_usb_work;
	struct work_struct	usb_block_reset_work;
	bool			in_restart;
	struct dwc3_charger	charger;
	struct usb_phy		*otg_xceiv;
	struct delayed_work	chg_work;
@@ -203,7 +203,6 @@ struct dwc3_msm {
#define MDWC3_PHY_REF_AND_CORECLK_OFF	\
			(MDWC3_PHY_REF_CLK_OFF | MDWC3_CORECLK_OFF)

	u32 gctl_val;
	u32 qscratch_ctl_val;
	dev_t ext_chg_dev;
	struct cdev ext_chg_cdev;
@@ -879,11 +878,15 @@ void dwc3_tx_fifo_resize_request(struct usb_ep *ep, bool qdss_enabled)
}
EXPORT_SYMBOL(dwc3_tx_fifo_resize_request);

static void dwc3_resume_work(struct work_struct *w);

static void dwc3_restart_usb_work(struct work_struct *w)
{
	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
						restart_usb_work);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	enum dwc3_chg_type chg_type;
	unsigned timeout = 50;

	dev_dbg(mdwc->dev, "%s\n", __func__);

@@ -892,21 +895,41 @@ static void dwc3_restart_usb_work(struct work_struct *w)
		return;
	}

	/* guard against concurrent VBUS handling */
	mdwc->in_restart = true;

	if (!mdwc->ext_xceiv.bsv) {
		dev_dbg(mdwc->dev, "%s bailing out in disconnect\n", __func__);
		dwc->err_evt_seen = false;
		mdwc->in_restart = false;
		return;
	}

	dbg_event(0xFF, "RestartUSB", 0);
	chg_type = mdwc->charger.chg_type;

	/* Reset active USB connection */
	mdwc->ext_xceiv.bsv = false;
	queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
	dwc3_resume_work(&mdwc->resume_work.work);

	/* Make sure disconnect is processed before sending connect */
	flush_delayed_work(&mdwc->resume_work);
	while (--timeout && !pm_runtime_suspended(mdwc->dev))
		msleep(20);

	if (!timeout) {
		dev_warn(mdwc->dev, "Not in LPM after disconnect, forcing suspend...\n");
		pm_runtime_suspend(mdwc->dev);
	}

	/* Force reconnect only if cable is still connected */
	if (mdwc->vbus_active) {
		mdwc->ext_xceiv.bsv = true;
	queue_delayed_work(system_nrt_wq, &mdwc->resume_work, 0);
		mdwc->charger.chg_type = chg_type;
		dwc3_resume_work(&mdwc->resume_work.work);
	}

	dwc->err_evt_seen = false;
	mdwc->in_restart = false;
}

/**
@@ -1140,11 +1163,8 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
		reg |= DWC3_GCTL_CORESOFTRESET;
		dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, reg);

		/*
		 * schedule work for doing block reset for recovery from erratic
		 * error event.
		 */
		queue_work(system_nrt_wq, &mdwc->usb_block_reset_work);
		/* restart USB which performs full reset and reconnect */
		queue_work(system_nrt_wq, &mdwc->restart_usb_work);
		break;
	case DWC3_CONTROLLER_RESET_EVENT:
		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESET_EVENT received\n");
@@ -1220,24 +1240,6 @@ static void dwc3_msm_block_reset(struct dwc3_ext_xceiv *xceiv, bool core_reset)

}

static void dwc3_block_reset_usb_work(struct work_struct *w)
{
	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
						usb_block_reset_work);
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	unsigned long flags;

	dev_dbg(mdwc->dev, "%s\n", __func__);
	dwc3_msm_block_reset(&mdwc->ext_xceiv, true);
	if (mdwc->ext_xceiv.bsv) {
		dbg_event(0xFF, "BR EnEVT", 0);
		dwc3_gadget_enable_irq(dwc);
	}
	spin_lock_irqsave(&dwc->lock, flags);
	dwc->err_evt_seen = 0;
	spin_unlock_irqrestore(&dwc->lock, flags);
}

static void dwc3_chg_enable_secondary_det(struct dwc3_msm *mdwc)
{
	u32 chg_ctrl;
@@ -1472,6 +1474,7 @@ static void dwc3_msm_power_collapse_por(struct dwc3_msm *mdwc)
	dwc3_core_init(dwc);
	/* Re-configure event buffers */
	dwc3_event_buffers_setup(dwc);
	dwc3_msm_notify_event(dwc, DWC3_CONTROLLER_POST_INITIALIZATION_EVENT);
}

static int dwc3_msm_prepare_suspend(struct dwc3_msm *mdwc)
@@ -1690,9 +1693,6 @@ static int dwc3_msm_suspend(struct dwc3_msm *mdwc)
	/* make sure above writes are completed before turning off clocks */
	wmb();

	/* Save value of GCTL to rewrite upon resume */
	mdwc->gctl_val = dwc3_msm_read_reg(mdwc->base, DWC3_GCTL);

	/* Perform controller power collapse */
	if (!host_bus_suspend && !device_bus_suspend && mdwc->power_collapse) {
		mdwc->lpm_flags |= MDWC3_POWER_COLLAPSE;
@@ -1865,8 +1865,6 @@ static int dwc3_msm_resume(struct dwc3_msm *mdwc)
		mdwc->lpm_flags &= ~MDWC3_POWER_COLLAPSE;
	}

	dwc3_msm_write_reg(mdwc->base, DWC3_GCTL, mdwc->gctl_val);

	atomic_set(&dwc->in_lpm, 0);

	msm_bam_notify_lpm_resume(DWC3_CTRL);
@@ -1928,43 +1926,6 @@ static void dwc3_wait_for_ext_chg_done(struct dwc3_msm *mdwc)

}

static void dwc3_flush_event_buffers(struct dwc3_msm *mdwc)
{
	struct dwc3 *dwc = platform_get_drvdata(mdwc->dwc3);
	int i;
	unsigned long flags;

	/* Only disable/flush all events when cable is disconnected */
	if (mdwc->ext_xceiv.bsv)
		return;

	/* Disable all events on cable disconnect */
	dbg_event(0xFF, "Dis EVT", 0);
	dwc3_gadget_disable_irq(dwc);

	/* Skip remaining events on disconnect */
	spin_lock_irqsave(&dwc->lock, flags);
	for (i = 0; i < dwc->num_event_buffers; i++) {
		struct dwc3_event_buffer *evt;
		evt = dwc->ev_buffs[i];
		evt->lpos = (evt->lpos + evt->count) %
			DWC3_EVENT_BUFFERS_SIZE;
		evt->count = 0;
		evt->flags &= ~DWC3_EVENT_PENDING;
	}
	spin_unlock_irqrestore(&dwc->lock, flags);

	/*
	 * If there is a pending block reset due to erratic event,
	 * wait for it to complete
	 */
	if (dwc->err_evt_seen) {
		dbg_event(0xFF, "Flush BR", 0);
		flush_work(&mdwc->usb_block_reset_work);
		dwc->err_evt_seen = 0;
	}
}

static void dwc3_resume_work(struct work_struct *w)
{
	struct dwc3_msm *mdwc = container_of(w, struct dwc3_msm,
@@ -1978,8 +1939,6 @@ static void dwc3_resume_work(struct work_struct *w)
		dbg_event(0xFF, "RWrk !lpm", 0);
		if (mdwc->otg_xceiv) {
			dwc3_wait_for_ext_chg_done(mdwc);
			/* Handle erratic events during cable disconnect */
			dwc3_flush_event_buffers(mdwc);
			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
							DWC3_EVENT_XCEIV_STATE);
		}
@@ -1994,11 +1953,6 @@ static void dwc3_resume_work(struct work_struct *w)
		dbg_event(0xFF, "RWrk !PMSus", mdwc->otg_xceiv ? 1 : 0);
		pm_runtime_get_sync(mdwc->dev);
		if (mdwc->otg_xceiv) {
			/*
			 * Handle erratic events during bus suspend and cable
			 * disconnect
			 */
			dwc3_flush_event_buffers(mdwc);
			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
							DWC3_EVENT_PHY_RESUME);
		} else if (mdwc->scope == POWER_SUPPLY_SCOPE_SYSTEM) {
@@ -2302,7 +2256,8 @@ static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
	/* Process PMIC notification in PRESENT prop */
	case POWER_SUPPLY_PROP_PRESENT:
		dev_dbg(mdwc->dev, "%s: notify xceiv event\n", __func__);
		if (mdwc->otg_xceiv && !mdwc->ext_inuse) {
		mdwc->vbus_active = val->intval;
		if (mdwc->otg_xceiv && !mdwc->ext_inuse && !mdwc->in_restart) {
			if (mdwc->ext_xceiv.bsv == val->intval)
				break;

@@ -2315,7 +2270,6 @@ static int dwc3_msm_power_set_property_usb(struct power_supply *psy,
			queue_delayed_work(system_nrt_wq,
							&mdwc->resume_work, 12);
		}
		mdwc->vbus_active = val->intval;
		break;
	case POWER_SUPPLY_PROP_ONLINE:
		mdwc->online = val->intval;
@@ -2849,7 +2803,6 @@ static int dwc3_msm_probe(struct platform_device *pdev)
	INIT_DELAYED_WORK(&mdwc->chg_work, dwc3_chg_detect_work);
	INIT_DELAYED_WORK(&mdwc->resume_work, dwc3_resume_work);
	INIT_WORK(&mdwc->restart_usb_work, dwc3_restart_usb_work);
	INIT_WORK(&mdwc->usb_block_reset_work, dwc3_block_reset_usb_work);
	INIT_WORK(&mdwc->id_work, dwc3_id_work);
	INIT_DELAYED_WORK(&mdwc->init_adc_work, dwc3_init_adc_work);
	init_completion(&mdwc->ext_chg_wait);
@@ -3487,11 +3440,6 @@ static int dwc3_msm_pm_resume(struct device *dev)

		/* Let OTG know about resume event and update pm_count */
		if (mdwc->otg_xceiv) {
			/*
			 * Handle erratic events on bus suspend, PM suspend
			 * and cable disconnect
			 */
			dwc3_flush_event_buffers(mdwc);
			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,
							DWC3_EVENT_PHY_RESUME);
			mdwc->ext_xceiv.notify_ext_events(mdwc->otg_xceiv->otg,