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

Commit 7b17a372 authored by Jack Pham's avatar Jack Pham
Browse files

usb: phy: dwc3-msm: Add VBUS valid override sequences



On some SoCs USB VBUS is not connected to the PHY VBUS pin, and
software instead must rely on external (often PMIC) notification
of cable connection and write to the controller's register bits to
manually indicate VBUS valid condition. The controller will then
be able to pull up the D+ line on the HSPHY which will allow a
host to enumerate properly.

This change adds two sets of MSM-specific sequences, differentiated
by core version number, to allow the controller to notify the PHYs
to perform additional steps in the presence of VBUS, such as manually
applying D+ pull-up in the case of high speed.

Change-Id: Ic2448f72031f8ace7de68ee0d59cd1135c62da39
Signed-off-by: default avatarJack Pham <jackp@codeaurora.org>
parent 6af721c6
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -26,6 +26,9 @@ Optional properties:
		bits 13-19 PARAMETER_OVERRIDE_C
		bits 20-25 PARAMETER_OVERRIDE_D
 - qcom,ext-vbus-id: If present then PHY does not handle VBUS and ID changes.
 - qcom,vbus-valid-override: If present, indicates VBUS pin is not connected to
   the USB PHY and the controller must rely on external VBUS notification in
   order to manually enable the D+ pull-up resistor.

Example:
	hsphy@f9200000 {
@@ -51,6 +54,11 @@ Required properties:
   values (no, min, max) where each value represents either a voltage in
   microvolts or a value corresponding to voltage corner

Optional properties:
 - qcom,vbus-valid-override: If present, indicates VBUS pin is not connected to
   the USB PHY and the controller must rely on external VBUS notification in
   order to manually relay the notification to the SSPHY.

Example:
	ssphy@f9200000 {
		compatible = "qcom,usb-ssphy";
+5 −0
Original line number Diff line number Diff line
@@ -305,6 +305,9 @@ static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on)
		dev_dbg(otg->phy->dev, "%s: turn on gadget %s\n",
					__func__, otg->gadget->name);

		usb_phy_notify_connect(dotg->dwc->usb2_phy, USB_SPEED_HIGH);
		usb_phy_notify_connect(dotg->dwc->usb3_phy, USB_SPEED_SUPER);

		/* Core reset is not required during start peripheral. Only
		 * DBM reset is required, hence perform only DBM reset here */
		if (ext_xceiv && ext_xceiv->otg_capability &&
@@ -317,6 +320,8 @@ static int dwc3_otg_start_peripheral(struct usb_otg *otg, int on)
		dev_dbg(otg->phy->dev, "%s: turn off gadget %s\n",
					__func__, otg->gadget->name);
		usb_gadget_vbus_disconnect(otg->gadget);
		usb_phy_notify_disconnect(dotg->dwc->usb2_phy, USB_SPEED_HIGH);
		usb_phy_notify_disconnect(dotg->dwc->usb3_phy, USB_SPEED_SUPER);
	}

	return 0;
+90 −4
Original line number Diff line number Diff line
@@ -28,11 +28,15 @@ static int override_phy_init;
module_param(override_phy_init, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(override_phy_init, "Override HSPHY Init Seq");

/* QSCRATCH register settings differ based on MSM core ver */
#define MSM_CORE_VER_120		0x10020061

/* QSCRATCH register offsets */
#define HS_PHY_CTRL_REG			(0x10)
#define PARAMETER_OVERRIDE_X_REG	(0x14)
#define ALT_INTERRUPT_EN_REG		(0x20)
#define HS_PHY_IRQ_STAT_REG		(0x24)
#define HS_PHY_CTRL_COMMON_REG		(0xEC)	/* ver >= MSM_CORE_VER_120 */

/* HS_PHY_CTRL_REG bits */
#define RETENABLEN			BIT(1)
@@ -43,14 +47,21 @@ MODULE_PARM_DESC(override_phy_init, "Override HSPHY Init Seq");
#define ID_HV_CLAMP_EN_N		BIT(9)
#define COMMONONN			BIT(11)
#define OTGDISABLE0			BIT(12)
#define VBUSVLDEXT0			BIT(13)
#define VBUSVLDEXTSEL0			BIT(14)
#define OTGSESSVLDHV_INTEN		BIT(15)
#define IDHV_INTEN			BIT(16)
#define DPSEHV_CLAMP_EN_N		BIT(17)
#define UTMI_OTG_VBUS_VALID		BIT(20)
#define USB2_UTMI_CLK_EN		BIT(21)
#define USB2_SUSPEND_N			BIT(22)
#define USB2_SUSPEND_N_SEL		BIT(23)
#define DMSEHV_CLAMP_EN_N		BIT(24)
#define CLAMP_MPM_DPSE_DMSE_EN_N	BIT(26)
#define SW_SESSVLD_SEL			BIT(28)	/* ver >= MSM_CORE_VER_120 */

/* HS_PHY_CTRL_COMMON_REG bits */
#define COMMON_VBUSVLDEXTSEL0		BIT(12)	/* ver >= MSM_CORE_VER_120 */

/* ALT_INTERRUPT_EN/HS_PHY_IRQ_STAT bits */
#define ACAINTEN			BIT(0)
@@ -331,6 +342,76 @@ static int msm_hsphy_set_suspend(struct usb_phy *uphy, int suspend)
	return 0;
}

static int msm_hsphy_notify_connect(struct usb_phy *uphy,
				    enum usb_device_speed speed)
{
	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
	u32 core_ver;

	if (uphy->flags & PHY_HOST_MODE)
		return 0;

	if (!(uphy->flags & PHY_VBUS_VALID_OVERRIDE))
		return 0;

	/* different sequences based on core version */
	core_ver = readl_relaxed(phy->base);

	/* Set External VBUS Valid Select. Set once, can be left on */
	if (core_ver >= MSM_CORE_VER_120) {
		msm_usb_write_readback(phy->base, HS_PHY_CTRL_COMMON_REG,
					COMMON_VBUSVLDEXTSEL0,
					COMMON_VBUSVLDEXTSEL0);
	} else {
		msm_usb_write_readback(phy->base, HS_PHY_CTRL_REG,
					VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
	}

	/* Enable D+ pull-up resistor */
	msm_usb_write_readback(phy->base, HS_PHY_CTRL_REG,
				VBUSVLDEXT0, VBUSVLDEXT0);

	/* Set OTG VBUS Valid from HSPHY to controller */
	msm_usb_write_readback(phy->base, HS_PHY_CTRL_REG,
				UTMI_OTG_VBUS_VALID, UTMI_OTG_VBUS_VALID);

	/* Indicate value is driven by UTMI_OTG_VBUS_VALID bit */
	if (core_ver >= MSM_CORE_VER_120)
		msm_usb_write_readback(phy->base, HS_PHY_CTRL_REG,
					SW_SESSVLD_SEL, SW_SESSVLD_SEL);

	return 0;
}

static int msm_hsphy_notify_disconnect(struct usb_phy *uphy,
				       enum usb_device_speed speed)
{
	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
	u32 core_ver;

	if (uphy->flags & PHY_HOST_MODE)
		return 0;

	if (!(uphy->flags & PHY_VBUS_VALID_OVERRIDE))
		return 0;

	core_ver = readl_relaxed(phy->base);

	/* Clear OTG VBUS Valid to Controller */
	msm_usb_write_readback(phy->base, HS_PHY_CTRL_REG,
				UTMI_OTG_VBUS_VALID, 0);

	/* Disable D+ pull-up resistor */
	msm_usb_write_readback(phy->base, HS_PHY_CTRL_REG, VBUSVLDEXT0, 0);

	/* Indicate value is no longer driven by UTMI_OTG_VBUS_VALID bit */
	if (core_ver >= MSM_CORE_VER_120)
		msm_usb_write_readback(phy->base, HS_PHY_CTRL_REG,
					SW_SESSVLD_SEL, 0);

	return 0;
}

static int msm_hsphy_probe(struct platform_device *pdev)
{
	struct msm_hsphy *phy;
@@ -430,9 +511,14 @@ static int msm_hsphy_probe(struct platform_device *pdev)

	platform_set_drvdata(pdev, phy);

	if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override"))
		phy->phy.flags |= PHY_VBUS_VALID_OVERRIDE;

	phy->phy.dev			= dev;
	phy->phy.init			= msm_hsphy_init;
	phy->phy.set_suspend		= msm_hsphy_set_suspend;
	phy->phy.notify_connect		= msm_hsphy_notify_connect;
	phy->phy.notify_disconnect	= msm_hsphy_notify_disconnect;
	/*FIXME: this conflicts with dwc3_otg */
	/*phy->phy.type			= USB_PHY_TYPE_USB2; */

+43 −5
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/phy.h>
#include <linux/usb/msm_hsusb.h>

/* QSCRATCH SSPHY control registers */
#define SS_PHY_CTRL_REG			0x30
@@ -333,6 +334,38 @@ static int msm_ssphy_set_suspend(struct usb_phy *uphy, int suspend)
	return ret;
}

static int msm_ssphy_notify_connect(struct usb_phy *uphy,
				       enum usb_device_speed speed)
{
	struct msm_ssphy *phy = container_of(uphy, struct msm_ssphy, phy);

	if (uphy->flags & PHY_HOST_MODE)
		return 0;

	if (uphy->flags & PHY_VBUS_VALID_OVERRIDE)
		/* Indicate power present to SS phy */
		msm_usb_write_readback(phy->base, SS_PHY_CTRL_REG,
					LANE0_PWR_PRESENT, LANE0_PWR_PRESENT);

	return 0;
}

static int msm_ssphy_notify_disconnect(struct usb_phy *uphy,
				       enum usb_device_speed speed)
{
	struct msm_ssphy *phy = container_of(uphy, struct msm_ssphy, phy);

	if (uphy->flags & PHY_HOST_MODE)
		return 0;

	if (uphy->flags & PHY_VBUS_VALID_OVERRIDE)
		/* Clear power indication to SS phy */
		msm_usb_write_readback(phy->base, SS_PHY_CTRL_REG,
					LANE0_PWR_PRESENT, 0);

	return 0;
}

static int msm_ssphy_probe(struct platform_device *pdev)
{
	struct msm_ssphy *phy;
@@ -396,10 +429,15 @@ static int msm_ssphy_probe(struct platform_device *pdev)

	platform_set_drvdata(pdev, phy);

	if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override"))
		phy->phy.flags |= PHY_VBUS_VALID_OVERRIDE;

	phy->phy.dev			= dev;
	phy->phy.init			= msm_ssphy_init;
	phy->phy.set_suspend		= msm_ssphy_set_suspend;
	phy->phy.set_params		= msm_ssphy_set_params;
	phy->phy.notify_connect		= msm_ssphy_notify_connect;
	phy->phy.notify_disconnect	= msm_ssphy_notify_disconnect;
	phy->phy.type			= USB_PHY_TYPE_USB3;

	ret = usb_add_phy_dev(&phy->phy);
+1 −0
Original line number Diff line number Diff line
@@ -273,6 +273,7 @@ struct msm_otg_platform_data {
#define ENABLE_SECONDARY_PHY		BIT(1)
#define PHY_HOST_MODE			BIT(2)
#define PHY_CHARGER_CONNECTED		BIT(3)
#define PHY_VBUS_VALID_OVERRIDE		BIT(4)

/* Timeout (in msec) values (min - max) associated with OTG timers */