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

Commit f937641b authored by Hemant Kumar's avatar Hemant Kumar
Browse files

usb: dwc3: Add support for POR upon composition switch



Composition switch to GSI transport based composition from
another GSI transport based composition requires power on
reset of USB controller to synchronize operation with USB
wrapper for GSI. Specifically GSI_EN bit cannot be
cleared without performing usb controller reset. Hence
introduce gadget restart operation to simulate vbus off
and vbus on and perform  this operation from gsi bind
config.

Change-Id: Ie4695807c73c2d14c0d9e17c486f34a90fd93ddb
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
parent 58be1b1f
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -743,6 +743,7 @@ struct dwc3_scratchpad_array {
#define DWC3_CONTROLLER_CONNDONE_EVENT			8
#define DWC3_CONTROLLER_NOTIFY_OTG_EVENT		9
#define DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT		10
#define DWC3_CONTROLLER_RESTART_USB_SESSION		11

#define MAX_INTR_STATS					10
/**
+10 −2
Original line number Diff line number Diff line
@@ -1437,7 +1437,7 @@ static void dwc3_restart_usb_work(struct work_struct *w)
	dev_dbg(mdwc->dev, "%s\n", __func__);

	if (atomic_read(&dwc->in_lpm) || !dwc->is_drd) {
		dev_err(mdwc->dev, "%s failed!!!\n", __func__);
		dev_dbg(mdwc->dev, "%s failed!!!\n", __func__);
		return;
	}

@@ -1462,7 +1462,10 @@ static void dwc3_restart_usb_work(struct work_struct *w)
		msleep(20);

	if (!timeout) {
		dev_warn(mdwc->dev, "Not in LPM after disconnect, forcing suspend...\n");
		dev_dbg(mdwc->dev,
			"Not in LPM after disconnect, forcing suspend...\n");
		dbg_event(0xFF, "ReStart:RT SUSP",
			atomic_read(&mdwc->dev->power.usage_count));
		pm_runtime_suspend(mdwc->dev);
	}

@@ -1474,6 +1477,7 @@ static void dwc3_restart_usb_work(struct work_struct *w)
	}

	dwc->err_evt_seen = false;
	flush_delayed_work(&mdwc->sm_work);
}

/**
@@ -1743,6 +1747,10 @@ static void dwc3_msm_notify_event(struct dwc3 *dwc, unsigned event)
		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_SET_CURRENT_DRAW_EVENT received\n");
		dwc3_msm_gadget_vbus_draw(mdwc, dwc->vbus_draw);
		break;
	case DWC3_CONTROLLER_RESTART_USB_SESSION:
		dev_dbg(mdwc->dev, "DWC3_CONTROLLER_RESTART_USB_SESSION received\n");
		dwc3_restart_usb_work(&mdwc->restart_usb_work);
		break;
	default:
		dev_dbg(mdwc->dev, "unknown dwc3 event\n");
		break;
+8 −0
Original line number Diff line number Diff line
@@ -2226,6 +2226,13 @@ static int dwc3_gadget_stop(struct usb_gadget *g,
	return 0;
}

static int dwc3_gadget_restart_usb_session(struct usb_gadget *g)
{
	struct dwc3		*dwc = gadget_to_dwc(g);

	return dwc3_notify_event(dwc, DWC3_CONTROLLER_RESTART_USB_SESSION);
}

static const struct usb_gadget_ops dwc3_gadget_ops = {
	.get_frame		= dwc3_gadget_get_frame,
	.wakeup			= dwc3_gadget_wakeup,
@@ -2236,6 +2243,7 @@ static const struct usb_gadget_ops dwc3_gadget_ops = {
	.pullup			= dwc3_gadget_pullup,
	.udc_start		= dwc3_gadget_start,
	.udc_stop		= dwc3_gadget_stop,
	.restart		= dwc3_gadget_restart_usb_session,
};

/* -------------------------------------------------------------------------- */
+7 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ MODULE_PARM_DESC(num_out_bufs,
		"Number of OUT buffers");

static struct workqueue_struct *ipa_usb_wq;
static bool gadget_restarted;

struct usb_gsi_debugfs {
	struct dentry *debugfs_root;
@@ -2591,6 +2592,7 @@ static void gsi_unbind(struct usb_configuration *c, struct usb_function *f)
	 */
	flush_workqueue(gsi->d_port.ipa_usb_wq);
	ipa_usb_deinit_teth_prot(gsi->prot_id);
	gadget_restarted = false;

	if (gsi->prot_id == IPA_USB_RNDIS) {
		gsi->d_port.sm_state = STATE_UNINITIALIZED;
@@ -2643,6 +2645,11 @@ int gsi_bind_config(struct usb_configuration *c, enum ipa_usb_teth_prot prot_id)
		return -EINVAL;
	}

	if (!gadget_restarted) {
		usb_gadget_restart(c->cdev->gadget);
		gadget_restarted = true;
	}

	switch (prot_id) {
	case IPA_USB_RNDIS:
		gsi->function.name = "rndis";
+15 −0
Original line number Diff line number Diff line
@@ -588,6 +588,7 @@ struct usb_gadget_ops {
	int	(*vbus_session) (struct usb_gadget *, int is_active);
	int	(*vbus_draw) (struct usb_gadget *, unsigned mA);
	int	(*pullup) (struct usb_gadget *, int is_on);
	int	(*restart)(struct usb_gadget *);
	int	(*ioctl)(struct usb_gadget *,
				unsigned code, unsigned long param);
	void	(*get_config_params)(struct usb_dcd_config_params *);
@@ -934,6 +935,20 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
	return gadget->ops->pullup(gadget, 0);
}

/**
 * usb_gadget_restart - software-controlled reset of USB peripheral connection
 * @gadget:the peripheral being reset
 *
 * Informs controller driver for Vbus LOW followed by Vbus HIGH notification.
 * This performs full hardware reset and re-initialization.
  */
static inline int usb_gadget_restart(struct usb_gadget *gadget)
{
	if (!gadget->ops->restart)
		return -EOPNOTSUPP;
	return gadget->ops->restart(gadget);
}

/**
 * usb_gadget_autopm_get - increment PM-usage counter of usb gadget's parent
 * device.