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

Commit 531ef5eb authored by Amelie Delaunay's avatar Amelie Delaunay Committed by Felipe Balbi
Browse files

usb: dwc2: add support for host mode external vbus supply

This patch adds a way to enable an external vbus supply in host mode,
when dwc2 drvvbus signal is not used.

This patch is very similar to the one done in U-Boot dwc2 driver [1]. It
also adds dynamic vbus supply management depending on the role and state
of the core.

[1] https://lists.denx.de/pipermail/u-boot/2017-March/283434.html



Signed-off-by: default avatarAmelie Delaunay <amelie.delaunay@st.com>
Signed-off-by: default avatarFelipe Balbi <felipe.balbi@linux.intel.com>
parent 13b1f8e2
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -819,6 +819,7 @@ struct dwc2_hregs_backup {
 * @plat:               The platform specific configuration data. This can be
 *                      removed once all SoCs support usb transceiver.
 * @supplies:           Definition of USB power supplies
 * @vbus_supply:        Regulator supplying vbus.
 * @phyif:              PHY interface width
 * @lock:		Spinlock that protects all the driver data structures
 * @priv:		Stores a pointer to the struct usb_hcd
@@ -958,6 +959,7 @@ struct dwc2_hsotg {
	struct usb_phy *uphy;
	struct dwc2_hsotg_plat *plat;
	struct regulator_bulk_data supplies[DWC2_NUM_SUPPLIES];
	struct regulator *vbus_supply;
	u32 phyif;

	spinlock_t lock;
+26 −0
Original line number Diff line number Diff line
@@ -356,6 +356,23 @@ static void dwc2_gusbcfg_init(struct dwc2_hsotg *hsotg)
	dwc2_writel(usbcfg, hsotg->regs + GUSBCFG);
}

static int dwc2_vbus_supply_init(struct dwc2_hsotg *hsotg)
{
	hsotg->vbus_supply = devm_regulator_get_optional(hsotg->dev, "vbus");
	if (IS_ERR(hsotg->vbus_supply))
		return 0;

	return regulator_enable(hsotg->vbus_supply);
}

static int dwc2_vbus_supply_exit(struct dwc2_hsotg *hsotg)
{
	if (hsotg->vbus_supply)
		return regulator_disable(hsotg->vbus_supply);

	return 0;
}

/**
 * dwc2_enable_host_interrupts() - Enables the Host mode interrupts
 *
@@ -3275,6 +3292,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)

	/* B-Device connector (Device Mode) */
	if (gotgctl & GOTGCTL_CONID_B) {
		dwc2_vbus_supply_exit(hsotg);
		/* Wait for switch to device mode */
		dev_dbg(hsotg->dev, "connId B\n");
		if (hsotg->bus_suspended) {
@@ -4323,6 +4341,9 @@ static int _dwc2_hcd_start(struct usb_hcd *hcd)
	}

	spin_unlock_irqrestore(&hsotg->lock, flags);

	dwc2_vbus_supply_init(hsotg);

	return 0;
}

@@ -4350,6 +4371,8 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
	spin_unlock_irqrestore(&hsotg->lock, flags);

	dwc2_vbus_supply_exit(hsotg);

	usleep_range(1000, 3000);
}

@@ -4386,6 +4409,7 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
		hprt0 |= HPRT0_SUSP;
		hprt0 &= ~HPRT0_PWR;
		dwc2_writel(hprt0, hsotg->regs + HPRT0);
		dwc2_vbus_supply_exit(hsotg);
	}

	/* Enter partial_power_down */
@@ -4466,6 +4490,8 @@ static int _dwc2_hcd_resume(struct usb_hcd *hcd)
		spin_unlock_irqrestore(&hsotg->lock, flags);
		dwc2_port_resume(hsotg);
	} else {
		dwc2_vbus_supply_init(hsotg);

		/* Wait for controller to correctly update D+/D- level */
		usleep_range(3000, 5000);