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

Commit b8430ab5 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: dwc3: Drive a pulse on DP on CDP detection"

parents 513a515f a7365063
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -3041,6 +3041,7 @@ static irqreturn_t msm_dwc3_pwr_irq(int irq, void *data)
}

static void dwc3_otg_sm_work(struct work_struct *w);
static int get_psy_type(struct dwc3_msm *mdwc);

static int dwc3_msm_get_clk_gdsc(struct dwc3_msm *mdwc)
{
@@ -3207,6 +3208,8 @@ static void check_for_sdp_connection(struct work_struct *w)
	}
}

#define DP_PULSE_WIDTH_MSEC 200

static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
	unsigned long event, void *ptr)
{
@@ -3230,6 +3233,13 @@ static int dwc3_msm_vbus_notifier(struct notifier_block *nb,
	dev_dbg(mdwc->dev, "vbus:%ld event received\n", event);

	mdwc->vbus_active = event;

	if (get_psy_type(mdwc) == POWER_SUPPLY_TYPE_USB_CDP &&
			mdwc->vbus_active) {
		dev_dbg(mdwc->dev, "Connected to CDP, pull DP up\n");
		usb_phy_drive_dp_pulse(mdwc->hs_phy, DP_PULSE_WIDTH_MSEC);
	}

	if ((dwc->dr_mode == USB_DR_MODE_OTG) && !mdwc->in_restart)
		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);

+93 −0
Original line number Diff line number Diff line
@@ -27,6 +27,17 @@
#include <linux/usb/phy.h>
#include <linux/reset.h>

#define QUSB2PHY_PLL_PWR_CTL		0x18
#define REF_BUF_EN			BIT(0)
#define REXT_EN				BIT(1)
#define PLL_BYPASSNL			BIT(2)
#define REXT_TRIM_0			BIT(4)

#define QUSB2PHY_PLL_AUTOPGM_CTL1	0x1C
#define PLL_RESET_N_CNT_5		0x5
#define PLL_RESET_N			BIT(4)
#define PLL_AUTOPGM_EN			BIT(7)

#define QUSB2PHY_PLL_STATUS	0x38
#define QUSB2PHY_PLL_LOCK	BIT(5)

@@ -55,6 +66,7 @@
#define CORE_READY_STATUS		BIT(0)

#define QUSB2PHY_PORT_UTMI_CTRL1	0xC0
#define SUSPEND_N			BIT(5)
#define TERM_SELECT			BIT(4)
#define XCVR_SELECT_FS			BIT(2)
#define OP_MODE_NON_DRIVE		BIT(0)
@@ -781,6 +793,86 @@ static int qusb_phy_notify_disconnect(struct usb_phy *phy,
	return 0;
}

static int qusb_phy_drive_dp_pulse(struct usb_phy *phy,
						unsigned int pulse_width)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
	int ret;

	dev_dbg(qphy->phy.dev, "connected to a CDP, drive DP up\n");
	ret = qusb_phy_enable_power(qphy, true);
	if (ret < 0) {
		dev_dbg(qphy->phy.dev,
			"dpdm regulator enable failed:%d\n", ret);
		return ret;
	}
	qusb_phy_gdsc(qphy, true);
	qusb_phy_enable_clocks(qphy, true);

	ret = reset_control_assert(qphy->phy_reset);
	if (ret)
		dev_err(qphy->phy.dev, "phyassert failed\n");
	usleep_range(100, 150);
	ret = reset_control_deassert(qphy->phy_reset);
	if (ret)
		dev_err(qphy->phy.dev, "deassert failed\n");

	/* Configure PHY to enable control on DP/DM lines */
	writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN,
				qphy->base + QUSB2PHY_PORT_POWERDOWN);

	writel_relaxed(TERM_SELECT | XCVR_SELECT_FS | OP_MODE_NON_DRIVE |
			SUSPEND_N, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);

	writel_relaxed(UTMI_ULPI_SEL | UTMI_TEST_MUX_SEL,
				qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);

	writel_relaxed(PLL_RESET_N_CNT_5,
			qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1);

	writel_relaxed(CLAMP_N_EN | FREEZIO_N,
			qphy->base + QUSB2PHY_PORT_POWERDOWN);

	writel_relaxed(REF_BUF_EN | REXT_EN | PLL_BYPASSNL | REXT_TRIM_0,
			qphy->base + QUSB2PHY_PLL_PWR_CTL);

	usleep_range(5, 10);

	writel_relaxed(0x15, qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1);
	writel_relaxed(PLL_RESET_N | PLL_RESET_N_CNT_5,
			qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1);

	writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC1);
	writel_relaxed(0x00, qphy->base + QUSB2PHY_PORT_QC2);

	usleep_range(50, 60);
	/* Enable Rdp_en to pull DP up to 3V */
	writel_relaxed(RDP_UP_EN, qphy->base + QUSB2PHY_PORT_QC2);
	msleep(pulse_width);

	/* Put the PHY and DP back to normal state */
	writel_relaxed(CLAMP_N_EN | FREEZIO_N | POWER_DOWN,
			qphy->base + QUSB2PHY_PORT_POWERDOWN);  /* 23 */

	writel_relaxed(PLL_AUTOPGM_EN | PLL_RESET_N | PLL_RESET_N_CNT_5,
			qphy->base + QUSB2PHY_PLL_AUTOPGM_CTL1);

	writel_relaxed(UTMI_ULPI_SEL, qphy->base + QUSB2PHY_PORT_UTMI_CTRL2);

	writel_relaxed(TERM_SELECT, qphy->base + QUSB2PHY_PORT_UTMI_CTRL1);

	qusb_phy_enable_clocks(qphy, false);
	qusb_phy_gdsc(qphy, false);

	ret = qusb_phy_enable_power(qphy, false);
	if (ret < 0) {
		dev_dbg(qphy->phy.dev,
			"dpdm regulator disable failed:%d\n", ret);
		return ret;
	}
	return 0;
}

static int qusb_phy_dpdm_regulator_enable(struct regulator_dev *rdev)
{
	int ret = 0;
@@ -1239,6 +1331,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
	qphy->phy.type			= USB_PHY_TYPE_USB2;
	qphy->phy.notify_connect        = qusb_phy_notify_connect;
	qphy->phy.notify_disconnect     = qusb_phy_notify_disconnect;
	qphy->phy.drive_dp_pulse	= qusb_phy_drive_dp_pulse;

	/*
	 * On some platforms multiple QUSB PHYs are available. If QUSB PHY is
+11 −0
Original line number Diff line number Diff line
@@ -176,6 +176,8 @@ struct usb_phy {

	/* reset the PHY clocks */
	int     (*reset)(struct usb_phy *x);

	int	(*drive_dp_pulse)(struct usb_phy *x, unsigned int pulse_width);
};

/**
@@ -259,6 +261,15 @@ usb_phy_reset(struct usb_phy *x)
	return 0;
}

static inline int
usb_phy_drive_dp_pulse(struct usb_phy *x, unsigned int pulse_width)
{
	if (x && x->drive_dp_pulse)
		return x->drive_dp_pulse(x, pulse_width);

	return 0;
}

/* for usb host and peripheral controller drivers */
#if IS_ENABLED(CONFIG_USB_PHY)
extern struct usb_phy *usb_get_phy(enum usb_phy_type type);