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

Commit 2bb3bdf3 authored by Hemant Kumar's avatar Hemant Kumar Committed by Vamsi Krishna Samavedam
Browse files

usb: phy-msm-qusb-v2: Add support to control external pull down



Add phy driver call back to enable external pull down on D+
line in host mode. External pull-down is only needed during
port reset before enabling high speed terminations. Pull-down
will be disabled 20ms after its enabled in timer function.

Change-Id: Id2a4e34b4937dc63d3e20cd48f5d586bbcb7599a
Signed-off-by: default avatarHemant Kumar <hemantk@codeaurora.org>
Signed-off-by: default avatarVamsi Krishna Samavedam <vskrishn@codeaurora.org>
parent d91ef6f6
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -176,6 +176,8 @@ Optional properties:
 - qcom,hold-reset: Indicates that hold QUSB PHY into reset state.
 - qcom,phy-clk-scheme: Should be one of "cml" or "cmos" if ref_clk_addr is provided.
 - qcom,major-rev: provide major revision number to differentiate power up sequence. default is 2.0
 - pinctrl-names/pinctrl-0/1: The GPIOs configured as output function. Names represents "active"
   state when attached in host mode and "suspend" state when detached.

Example:
	qusb_phy: qusb@f9b39000 {
+68 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/usb/phy.h>
#include <linux/reset.h>
#include <linux/debugfs.h>
#include <linux/hrtimer.h>

/* QUSB2PHY_PWR_CTRL1 register related bits */
#define PWR_CTRL1_POWR_DOWN		BIT(0)
@@ -126,6 +127,10 @@ struct qusb_phy {
	u32			sq_ctrl2_default;
	bool			chirp_disable;

	struct pinctrl		*pinctrl;
	struct pinctrl_state	*atest_usb13_suspend;
	struct pinctrl_state	*atest_usb13_active;

	/* emulation targets specific */
	void __iomem		*emu_phy_base;
	bool			emulation;
@@ -139,6 +144,8 @@ struct qusb_phy {
	/* override TUNEX registers value */
	struct dentry		*root;
	u8			tune[5];

	struct hrtimer		timer;
};

static void qusb_phy_enable_clocks(struct qusb_phy *qphy, bool on)
@@ -511,6 +518,42 @@ static int qusb_phy_init(struct usb_phy *phy)
	return 0;
}

static enum hrtimer_restart qusb_dis_ext_pulldown_timer(struct hrtimer *timer)
{
	struct qusb_phy *qphy = container_of(timer, struct qusb_phy, timer);
	int ret = 0;

	if (qphy->pinctrl && qphy->atest_usb13_suspend) {
		ret = pinctrl_select_state(qphy->pinctrl,
				qphy->atest_usb13_suspend);
		if (ret < 0)
			dev_err(qphy->phy.dev,
				"pinctrl state suspend select failed\n");
	}

	return HRTIMER_NORESTART;
}

static void qusb_phy_enable_ext_pulldown(struct usb_phy *phy)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
	int ret = 0;

	dev_dbg(phy->dev, "%s\n", __func__);

	if (qphy->pinctrl && qphy->atest_usb13_active) {
		ret = pinctrl_select_state(qphy->pinctrl,
				qphy->atest_usb13_active);
		if (ret < 0) {
			dev_err(phy->dev,
					"pinctrl state active select failed\n");
			return;
		}

		hrtimer_start(&qphy->timer, ms_to_ktime(10), HRTIMER_MODE_REL);
	}
}

static void qusb_phy_shutdown(struct usb_phy *phy)
{
	struct qusb_phy *qphy = container_of(phy, struct qusb_phy, phy);
@@ -1082,6 +1125,30 @@ static int qusb_phy_probe(struct platform_device *pdev)
		return PTR_ERR(qphy->vdda18);
	}

	qphy->pinctrl = devm_pinctrl_get(dev);
	if (IS_ERR(qphy->pinctrl)) {
		ret = PTR_ERR(qphy->pinctrl);
		if (ret == -EPROBE_DEFER)
			return ret;
		dev_err(dev, "pinctrl not available\n");
		goto skip_pinctrl_config;
	}
	qphy->atest_usb13_suspend = pinctrl_lookup_state(qphy->pinctrl,
							"atest_usb13_suspend");
	if (IS_ERR(qphy->atest_usb13_suspend)) {
		dev_err(dev, "pinctrl lookup atest_usb13_suspend failed\n");
		goto skip_pinctrl_config;
	}

	qphy->atest_usb13_active = pinctrl_lookup_state(qphy->pinctrl,
							"atest_usb13_active");
	if (IS_ERR(qphy->atest_usb13_active))
		dev_err(dev, "pinctrl lookup atest_usb13_active failed\n");

	hrtimer_init(&qphy->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
	qphy->timer.function = qusb_dis_ext_pulldown_timer;

skip_pinctrl_config:
	mutex_init(&qphy->lock);
	platform_set_drvdata(pdev, qphy);

@@ -1093,6 +1160,7 @@ static int qusb_phy_probe(struct platform_device *pdev)
	qphy->phy.notify_connect        = qusb_phy_notify_connect;
	qphy->phy.notify_disconnect     = qusb_phy_notify_disconnect;
	qphy->phy.disable_chirp		= qusb_phy_disable_chirp;
	qphy->phy.start_port_reset	= qusb_phy_enable_ext_pulldown;

	ret = usb_add_phy_dev(&qphy->phy);
	if (ret)
+11 −0
Original line number Diff line number Diff line
@@ -114,6 +114,8 @@ struct usb_phy {

	/* enable/disable VBUS */
	int	(*set_vbus)(struct usb_phy *x, int on);
	/* callback to indicate port is being reset or reset the port */
	void	(*start_port_reset)(struct usb_phy *x);

	/* effective for B devices, ignored for A-peripheral */
	int	(*set_power)(struct usb_phy *x,
@@ -213,6 +215,15 @@ usb_phy_vbus_off(struct usb_phy *x)
	return x->set_vbus(x, false);
}

static inline void
usb_phy_start_port_reset(struct usb_phy *x)
{
	if (!x || !x->start_port_reset)
		return;

	x->start_port_reset(x);
}

static inline int
usb_phy_reset(struct usb_phy *x)
{