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

Commit cddaf1ee authored by Sriharsha Allenki's avatar Sriharsha Allenki
Browse files

usb: phy: Clean up phy-msm-ssusb driver of dead code



The phy-msm-ssusb driver used for QCS405 SS PHY
does not uses the CR protocol to configure the PHY.
Remove this unused code and add the proper registers
for configuring and initializing the SS PHY.
Also add the support for necessary clocks needed
for SS PHY on QCS405.

Change-Id: Ibeb14800bbe171b5f3ecb1727227f60735172b54
Signed-off-by: default avatarSriharsha Allenki <sallenki@codeaurora.org>
parent 45744bac
Loading
Loading
Loading
Loading
+14 −15
Original line number Diff line number Diff line
Qualcomm Technologies, Inc. MSM PHY Transceivers

Required properties:
- compatible: Should be "qcom,usb-ssphy" or "qcom,usb-ssphy-qmp-v2"
- compatible: Should be "qcom,usb-ssphy"
- reg: Address and length of the register set for the device
- clocks: a list of handles to the PHY clocks. Use as per
  Documentation/devicetree/bindings/clock/clock-bindings.txt
- clock-names: Names of the clocks in 1-1 correspondence with the "clocks"
  property. "ref_clk", "cfg_ahb_clk" and "pipe_clk" are mandatory.
- <supply-name>-supply: phandle to the regulator device tree node
Required "supply-name" examples are:
"vdd" : vdd supply for SSPHY digital circuit operation
@@ -15,14 +19,6 @@ 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.
- qcom,deemphasis-value: This property if present represents ss phy
deemphasis value to be used for overriding into SSPHY register.
- qcom,primary-phy: If present, indicates this is a secondary PHY and is
dependent on the primary PHY referenced by this phandle.
- qcom,override-pll-calibration: If present, program PHY register to overrride
the automatic PHY PLL calibration settings.
- qcom,qmp-misc-config: If present, program PHY miscellaneous device-specific
registers.

Example:
ssphy@f9200000 {
@@ -31,5 +27,8 @@ reg = <0xf9200000 0xfc000>;
	vdd-supply = <&pm8841_s2_corner>;
	vdda18-supply = <&pm8941_l6>;
	qcom,vdd-voltage-level = <1 5 7>;
qcom,deemphasis-value = <26>;
	clocks = <&clock_gcc USB_PHY_REF_CLK>,
		 <&clock_gcc USB_PHY_CFG_AHB_CLK>,
		 <&clock_gcc USB_PHY_PIPE_CLK>;
	clock-names = "ref_clk", "cfg_ahb_clk", "pipe_clk";
};
+81 −223
Original line number Diff line number Diff line
@@ -23,34 +23,24 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/usb/phy.h>
//#include <linux/usb/msm_hsusb.h>
#include <linux/reset.h>

static int ss_phy_override_deemphasis;
module_param(ss_phy_override_deemphasis, int, 0644);
MODULE_PARM_DESC(ss_phy_override_deemphasis, "Override SSPHY demphasis value");

/* QSCRATCH SSPHY control registers */
#define SS_PHY_CTRL_REG			0x30
#define SS_PHY_PARAM_CTRL_1		0x34
#define SS_PHY_PARAM_CTRL_2		0x38
#define SS_CR_PROTOCOL_DATA_IN_REG	0x3C
#define SS_CR_PROTOCOL_DATA_OUT_REG	0x40
#define SS_CR_PROTOCOL_CAP_ADDR_REG	0x44
#define SS_CR_PROTOCOL_CAP_DATA_REG	0x48
#define SS_CR_PROTOCOL_READ_REG		0x4C
#define SS_CR_PROTOCOL_WRITE_REG	0x50

#define ENABLE_SECONDARY_PHY		BIT(1)
/* SSPHY control registers */
#define SS_PHY_CTRL0			0x6C
#define SS_PHY_CTRL1			0x70
#define SS_PHY_CTRL2			0x74
#define SS_PHY_CTRL4			0x7C

#define PHY_HOST_MODE			BIT(2)
#define PHY_VBUS_VALID_OVERRIDE		BIT(4)

/* SS_PHY_CTRL_REG bits */
#define REF_SS_PHY_EN			BIT(0)
#define LANE0_PWR_PRESENT		BIT(2)
#define SWI_PCS_CLK_SEL			BIT(4)
#define TEST_POWERDOWN			BIT(4)
#define REF_USE_PAD			BIT(6)
#define SS_PHY_RESET			BIT(7)
#define REF_SS_PHY_EN			BIT(8)
#define LANE0_PWR_PRESENT		BIT(24)
#define TEST_POWERDOWN			BIT(26)
#define REF_USE_PAD			BIT(28)

#define USB_SSPHY_1P8_VOL_MIN		1800000 /* uV */
#define USB_SSPHY_1P8_VOL_MAX		1800000 /* uV */
@@ -59,18 +49,52 @@ MODULE_PARM_DESC(ss_phy_override_deemphasis, "Override SSPHY demphasis value");
struct msm_ssphy {
	struct usb_phy		phy;
	void __iomem		*base;

	struct clk		*ref_clk;
	struct clk		*cfg_ahb_clk;
	struct clk		*pipe_clk;
	bool			clocks_enabled;

	struct reset_control	*phy_com_reset;
	struct reset_control	*phy_reset;
	struct regulator	*vdd;
	struct regulator	*vdda18;
	bool			suspended;
	int			vdd_levels[3]; /* none, low, high */
	int			deemphasis_val;

	int			power_enabled;
};

static void msm_ssusb_enable_clocks(struct msm_ssphy *phy)
{
	dev_dbg(phy->phy.dev, "%s: clocks_enabled:%d\n",
			__func__, phy->clocks_enabled);

	if (phy->clocks_enabled)
		return;

	clk_prepare_enable(phy->cfg_ahb_clk);
	clk_prepare_enable(phy->ref_clk);
	clk_prepare_enable(phy->pipe_clk);

	phy->clocks_enabled = true;
}

static void msm_ssusb_disable_clocks(struct msm_ssphy *phy)
{
	dev_dbg(phy->phy.dev, "%s: clocks_enabled:%d\n",
			__func__, phy->clocks_enabled);

	if (!phy->clocks_enabled)
		return;

	clk_disable_unprepare(phy->pipe_clk);
	clk_disable_unprepare(phy->ref_clk);
	clk_disable_unprepare(phy->cfg_ahb_clk);

	phy->clocks_enabled = false;
}

static int msm_ssusb_config_vdd(struct msm_ssphy *phy, int high)
{
	int min, ret;
@@ -189,142 +213,14 @@ static void msm_usb_write_readback(void *base, u32 offset,
			__func__, val, offset);
}

/**
 * Write SSPHY register with debug info.
 *
 * @base - base virtual address.
 * @addr - SSPHY address to write.
 * @val - value to write.
 *
 */
static void msm_ssusb_write_phycreg(void *base, u32 addr, u32 val)
{
	writel_relaxed(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
	writel_relaxed(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
	while (readl_relaxed(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
		cpu_relax();

	writel_relaxed(val, base + SS_CR_PROTOCOL_DATA_IN_REG);
	writel_relaxed(0x1, base + SS_CR_PROTOCOL_CAP_DATA_REG);
	while (readl_relaxed(base + SS_CR_PROTOCOL_CAP_DATA_REG))
		cpu_relax();

	writel_relaxed(0x1, base + SS_CR_PROTOCOL_WRITE_REG);
	while (readl_relaxed(base + SS_CR_PROTOCOL_WRITE_REG))
		cpu_relax();
}

/**
 * Read SSPHY register with debug info.
 *
 * @base - base virtual address.
 * @addr - SSPHY address to read.
 *
 */
static u32 msm_ssusb_read_phycreg(void *base, u32 addr)
{
	bool first_read = true;

	writel_relaxed(addr, base + SS_CR_PROTOCOL_DATA_IN_REG);
	writel_relaxed(0x1, base + SS_CR_PROTOCOL_CAP_ADDR_REG);
	while (readl_relaxed(base + SS_CR_PROTOCOL_CAP_ADDR_REG))
		cpu_relax();

	/*
	 * Due to hardware bug, first read of SSPHY register might be
	 * incorrect. Hence as workaround, SW should perform SSPHY register
	 * read twice, but use only second read and ignore first read.
	 */
retry:
	writel_relaxed(0x1, base + SS_CR_PROTOCOL_READ_REG);
	while (readl_relaxed(base + SS_CR_PROTOCOL_READ_REG))
		cpu_relax();

	if (first_read) {
		readl_relaxed(base + SS_CR_PROTOCOL_DATA_OUT_REG);
		first_read = false;
		goto retry;
	}

	return readl_relaxed(base + SS_CR_PROTOCOL_DATA_OUT_REG);
}

static int msm_ssphy_set_params(struct usb_phy *uphy)
{
	struct msm_ssphy *phy = container_of(uphy, struct msm_ssphy, phy);
	u32 data = 0;

	/*
	 * WORKAROUND: There is SSPHY suspend bug due to which USB enumerates
	 * in HS mode instead of SS mode. Workaround it by asserting
	 * LANE0.TX_ALT_BLOCK.EN_ALT_BUS to enable TX to use alt bus mode
	 */
	data = msm_ssusb_read_phycreg(phy->base, 0x102D);
	data |= (1 << 7);
	msm_ssusb_write_phycreg(phy->base, 0x102D, data);

	data = msm_ssusb_read_phycreg(phy->base, 0x1010);
	data &= ~0xFF0;
	data |= 0x20;
	msm_ssusb_write_phycreg(phy->base, 0x1010, data);

	/*
	 * Fix RX Equalization setting as follows
	 * LANE0.RX_OVRD_IN_HI. RX_EQ_EN set to 0
	 * LANE0.RX_OVRD_IN_HI.RX_EQ_EN_OVRD set to 1
	 * LANE0.RX_OVRD_IN_HI.RX_EQ set to 3
	 * LANE0.RX_OVRD_IN_HI.RX_EQ_OVRD set to 1
	 */
	data = msm_ssusb_read_phycreg(phy->base, 0x1006);
	data &= ~(1 << 6);
	data |= (1 << 7);
	data &= ~(0x7 << 8);
	data |= (0x3 << 8);
	data |= (0x1 << 11);
	msm_ssusb_write_phycreg(phy->base, 0x1006, data);

	/*
	 * Set EQ and TX launch amplitudes as follows
	 * LANE0.TX_OVRD_DRV_LO.PREEMPH set to 22
	 * LANE0.TX_OVRD_DRV_LO.AMPLITUDE set to 127
	 * LANE0.TX_OVRD_DRV_LO.EN set to 1.
	 */
	data = msm_ssusb_read_phycreg(phy->base, 0x1002);
	data &= ~0x3F80;
	if (ss_phy_override_deemphasis)
		phy->deemphasis_val = ss_phy_override_deemphasis;
	if (phy->deemphasis_val)
		data |= (phy->deemphasis_val << 7);
	else
		data |= (0x16 << 7);
	data &= ~0x7F;
	data |= (0x7F | (1 << 14));
	msm_ssusb_write_phycreg(phy->base, 0x1002, data);

	/*
	 * Set the QSCRATCH SS_PHY_PARAM_CTRL1 parameters as follows
	 * TX_FULL_SWING [26:20] amplitude to 127
	 * TX_DEEMPH_3_5DB [13:8] to 22
	 * LOS_BIAS [2:0] to 0x5
	 */
	msm_usb_write_readback(phy->base, SS_PHY_PARAM_CTRL_1,
				0x07f03f07, 0x07f01605);

	return 0;
}

/* SSPHY Initialization */
static int msm_ssphy_init(struct usb_phy *uphy)
{
	struct msm_ssphy *phy = container_of(uphy, struct msm_ssphy, phy);
	u32 val;

	msm_ssusb_ldo_enable(phy, 1);

	clk_prepare_enable(phy->ref_clk);

	/* read initial value */
	val = readl_relaxed(phy->base + SS_PHY_CTRL_REG);
	msm_ssusb_enable_clocks(phy);

	/* Use clk reset, if available; otherwise use SS_PHY_RESET bit */
	if (phy->phy_com_reset) {
@@ -334,26 +230,19 @@ static int msm_ssphy_init(struct usb_phy *uphy)
		reset_control_deassert(phy->phy_com_reset);
		reset_control_deassert(phy->phy_reset);
	} else {
		writel_relaxed(val | SS_PHY_RESET, phy->base + SS_PHY_CTRL_REG);
		msm_usb_write_readback(phy->base, SS_PHY_CTRL1,
						SS_PHY_RESET, SS_PHY_RESET);
		udelay(10); /* 10us required before de-asserting */
		writel_relaxed(val, phy->base + SS_PHY_CTRL_REG);
		msm_usb_write_readback(phy->base, SS_PHY_CTRL1,
						SS_PHY_RESET, 0);
	}

	/* Use ref_clk from pads and set its parameters */
	val |= REF_USE_PAD;
	writel_relaxed(val, phy->base + SS_PHY_CTRL_REG);
	msleep(30);
	writeb_relaxed(SWI_PCS_CLK_SEL, phy->base + SS_PHY_CTRL0);

	/* Ref clock must be stable now, enable ref clock for HS mode */
	val |= LANE0_PWR_PRESENT | REF_SS_PHY_EN;
	writel_relaxed(val, phy->base + SS_PHY_CTRL_REG);
	usleep_range(2000, 2200);
	msm_usb_write_readback(phy->base, SS_PHY_CTRL4,
					LANE0_PWR_PRESENT, LANE0_PWR_PRESENT);

	/*
	 * Reinitialize SSPHY parameters as SS_PHY RESET will reset
	 * the internal registers to default values.
	 */
	msm_ssphy_set_params(uphy);
	writeb_relaxed(REF_SS_PHY_EN, phy->base + SS_PHY_CTRL2);

	return 0;
}
@@ -361,7 +250,6 @@ static int msm_ssphy_init(struct usb_phy *uphy)
static int msm_ssphy_set_suspend(struct usb_phy *uphy, int suspend)
{
	struct msm_ssphy *phy = container_of(uphy, struct msm_ssphy, phy);
	void __iomem *base = phy->base;

	dev_dbg(uphy->dev, "%s: phy->suspended:%d suspend:%d", __func__,
					phy->suspended, suspend);
@@ -374,56 +262,23 @@ static int msm_ssphy_set_suspend(struct usb_phy *uphy, int suspend)

	if (suspend) {

		/* Clear REF_SS_PHY_EN */
		msm_usb_write_readback(base, SS_PHY_CTRL_REG, REF_SS_PHY_EN, 0);
		/* Clear REF_USE_PAD */
		msm_usb_write_readback(base, SS_PHY_CTRL_REG, REF_USE_PAD, 0);
		/* Set TEST_POWERDOWN (enables PHY retention) */
		msm_usb_write_readback(base, SS_PHY_CTRL_REG, TEST_POWERDOWN,
								TEST_POWERDOWN);
		if (phy->phy_com_reset &&
			!(phy->phy.flags & ENABLE_SECONDARY_PHY)) {
			/* leave these asserted until resuming */
			reset_control_assert(phy->phy_com_reset);
			reset_control_assert(phy->phy_reset);
		}
		msm_usb_write_readback(phy->base, SS_PHY_CTRL2,
					REF_SS_PHY_EN, 0);
		msm_usb_write_readback(phy->base, SS_PHY_CTRL4,
					TEST_POWERDOWN, TEST_POWERDOWN);

		clk_disable_unprepare(phy->ref_clk);
		msm_ssusb_disable_clocks(phy);
		msm_ssusb_ldo_enable(phy, 0);
		phy->suspended = true;
	} else {

		msm_ssusb_ldo_enable(phy, 1);
		clk_prepare_enable(phy->ref_clk);
		msm_ssusb_enable_clocks(phy);

		if (phy->phy.flags & ENABLE_SECONDARY_PHY) {
			dev_err(uphy->dev, "secondary PHY, skipping reset\n");
			return 0;
		}

		if (phy->phy_com_reset) {
			reset_control_deassert(phy->phy_com_reset);
			reset_control_deassert(phy->phy_reset);
		} else {
			/* Assert SS PHY RESET */
			msm_usb_write_readback(base, SS_PHY_CTRL_REG,
						SS_PHY_RESET, SS_PHY_RESET);
		}

		/* Set REF_USE_PAD */
		msm_usb_write_readback(base, SS_PHY_CTRL_REG, REF_USE_PAD,
								REF_USE_PAD);
		/* Set REF_SS_PHY_EN */
		msm_usb_write_readback(base, SS_PHY_CTRL_REG, REF_SS_PHY_EN,
								REF_SS_PHY_EN);
		/* Clear TEST_POWERDOWN */
		msm_usb_write_readback(base, SS_PHY_CTRL_REG, TEST_POWERDOWN,
								0);
		if (!phy->phy_com_reset) {
			udelay(10); /* 10us required before de-asserting */
			msm_usb_write_readback(base, SS_PHY_CTRL_REG,
						SS_PHY_RESET, 0);
		}
		msm_usb_write_readback(phy->base, SS_PHY_CTRL2,
					REF_SS_PHY_EN, REF_SS_PHY_EN);
		msm_usb_write_readback(phy->base, SS_PHY_CTRL4,
					TEST_POWERDOWN, 0);

		phy->suspended = false;
	}
@@ -441,7 +296,7 @@ static int msm_ssphy_notify_connect(struct usb_phy *uphy,

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

	return 0;
@@ -457,7 +312,7 @@ static int msm_ssphy_notify_disconnect(struct usb_phy *uphy,

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

	return 0;
@@ -492,6 +347,18 @@ static int msm_ssphy_probe(struct platform_device *pdev)
		return PTR_ERR(phy->ref_clk);
	}

	phy->cfg_ahb_clk = devm_clk_get(dev, "cfg_ahb_clk");
	if (IS_ERR(phy->cfg_ahb_clk)) {
		dev_err(dev, "unable to get cfg_ahb_clk\n");
		return PTR_ERR(phy->cfg_ahb_clk);
	}

	phy->pipe_clk = devm_clk_get(dev, "pipe_clk");
	if (IS_ERR(phy->pipe_clk)) {
		dev_err(dev, "unable to get pipe_clk\n");
		return PTR_ERR(phy->pipe_clk);
	}

	phy->phy_com_reset = devm_reset_control_get(dev, "phy_com_reset");
	if (IS_ERR(phy->phy_com_reset)) {
		ret = PTR_ERR(phy->phy_com_reset);
@@ -506,11 +373,6 @@ static int msm_ssphy_probe(struct platform_device *pdev)
		phy->phy_reset = NULL;
	}

	if (of_get_property(dev->of_node, "qcom,primary-phy", NULL)) {
		dev_dbg(dev, "secondary HSPHY\n");
		phy->phy.flags |= ENABLE_SECONDARY_PHY;
	}

	ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
					 (u32 *) phy->vdd_levels,
					 ARRAY_SIZE(phy->vdd_levels));
@@ -537,10 +399,6 @@ static int msm_ssphy_probe(struct platform_device *pdev)
	if (of_property_read_bool(dev->of_node, "qcom,vbus-valid-override"))
		phy->phy.flags |= PHY_VBUS_VALID_OVERRIDE;

	if (of_property_read_u32(dev->of_node, "qcom,deemphasis-value",
						&phy->deemphasis_val))
		dev_dbg(dev, "unable to read ssphy deemphasis value\n");

	phy->phy.init			= msm_ssphy_init;
	phy->phy.set_suspend		= msm_ssphy_set_suspend;
	phy->phy.notify_connect		= msm_ssphy_notify_connect;