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

Commit b1caa809 authored by Udipto Goswami's avatar Udipto Goswami
Browse files

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



Some USB host PCs switch the downstream port mode from
CDP to SDP if the device does not pull DP up within certain
duration (~2s).
This limits the current drawn by the device to 500mA(or 900mA)
as opposed to the possible 1.5A resulting in slow charging of
the battery.
Fix this by driving a DP pulse when there is a connect
notification from PMIC and detected the charger type as CDP.

change-Id: Ib1e18a8d40301c553efe0919e11c89ad87d9cfca
Signed-off-by: default avatarUdipto Goswami <ugoswami@codeaurora.org>
parent 771efa0c
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -2989,6 +2989,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)
{
@@ -3155,6 +3156,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)
{
@@ -3178,6 +3181,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 (dwc3_is_otg_or_drd(dwc) && !mdwc->in_restart)
		queue_work(mdwc->dwc3_wq, &mdwc->resume_work);

+62 −0
Original line number Diff line number Diff line
@@ -25,6 +25,11 @@
#define OPMODE_MASK				(0x3 << 3)
#define OPMODE_NONDRIVING			(0x1 << 3)
#define SLEEPM					BIT(0)
#define OPMODE_NORMAL				(0x00)
#define TERMSEL					BIT(5)

#define USB2_PHY_USB_PHY_UTMI_CTRL1		(0x40)
#define XCVRSEL					BIT(0)

#define USB2_PHY_USB_PHY_UTMI_CTRL5		(0x50)
#define POR					BIT(1)
@@ -516,6 +521,62 @@ static int msm_hsphy_notify_disconnect(struct usb_phy *uphy,
	return 0;
}

static int msm_hsphy_drive_dp_pulse(struct usb_phy *uphy,
					unsigned int interval_ms)
{
	struct msm_hsphy *phy = container_of(uphy, struct msm_hsphy, phy);
	int ret;

	ret = msm_hsphy_enable_power(phy, true);
	if (ret < 0) {
		dev_dbg(uphy->dev,
			"dpdm regulator enable failed:%d\n", ret);
		return ret;
	}
	msm_hsphy_enable_clocks(phy, true);
	/* set utmi_phy_cmn_cntrl_override_en &
	 * utmi_phy_datapath_ctrl_override_en
	 */
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0,
				UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
				UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0,
				UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN,
				UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN);
	/* set opmode to normal i.e. 0x0 & termsel to fs */
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
				OPMODE_MASK, OPMODE_NORMAL);
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
				TERMSEL, TERMSEL);
	/* set xcvrsel to fs */
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL1,
					XCVRSEL, XCVRSEL);
	msleep(interval_ms);
	/* clear termsel to fs */
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
				TERMSEL, 0x00);
	/* clear xcvrsel */
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_UTMI_CTRL1,
					XCVRSEL, 0x00);
	/* clear utmi_phy_cmn_cntrl_override_en &
	 * utmi_phy_datapath_ctrl_override_en
	 */
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0,
				UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0x00);
	msm_usb_write_readback(phy->base, USB2_PHY_USB_PHY_CFG0,
				UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN, 0x00);

	msleep(20);

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

static int msm_hsphy_dpdm_regulator_enable(struct regulator_dev *rdev)
{
	int ret = 0;
@@ -788,6 +849,7 @@ static int msm_hsphy_probe(struct platform_device *pdev)
	phy->phy.notify_connect		= msm_hsphy_notify_connect;
	phy->phy.notify_disconnect	= msm_hsphy_notify_disconnect;
	phy->phy.type			= USB_PHY_TYPE_USB2;
	phy->phy.drive_dp_pulse		= msm_hsphy_drive_dp_pulse;

	ret = usb_add_phy_dev(&phy->phy);
	if (ret)
+10 −0
Original line number Diff line number Diff line
@@ -174,6 +174,7 @@ 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);
};

/* for board-specific init logic */
@@ -241,6 +242,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);