static int msm_ssphy_qmp_reset(struct usb_phy *uphy)
{
	struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
					phy);
	int ret;

	dev_dbg(uphy->dev, "Resetting QMP phy\n");

	if (!phy->clk_enabled) {
		ret = msm_ssphy_qmp_init_clocks(phy);
		if (ret) {
			dev_err(uphy->dev, "failed to init clocks %d\n", ret);
			return ret;
		}
	}

	/* Assert USB3 PHY reset */
	ret = clk_reset(phy->phy_com_reset, CLK_RESET_ASSERT);
	if (ret && ret != -EINVAL) {
		dev_err(uphy->dev, "phy_com_reset clk assert failed\n");
		return ret;
	}
	ret = clk_reset(phy->phy_reset, CLK_RESET_ASSERT);
	if (ret) {
		dev_err(uphy->dev, "phy_reset clk assert failed\n");
		goto deassert_phy_com_reset;
	}
	ret = clk_reset(phy->pipe_clk, CLK_RESET_ASSERT);
	if (ret && ret != -ENOSYS) {
		dev_err(uphy->dev, "pipe_clk reset assert failed\n");
		goto deassert_phy_reset;
	}

	/* Clear USB3 PHY reset */
	ret = clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT);
	if (ret && ret != -ENOSYS) {
		dev_err(uphy->dev, "pipe_clk reset assert failed\n");
		goto deassert_phy_reset;
	}
	ret = clk_reset(phy->phy_reset, CLK_RESET_DEASSERT);
	if (ret) {
		dev_err(uphy->dev, "phy_reset clk deassert failed\n");
		goto deassert_phy_com_reset;
	}
	ret = clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT);
	if (ret && ret != -EINVAL) {
		dev_err(uphy->dev, "phy_com_reset clk deassert failed\n");
		return ret;
	}

	return 0;

deassert_phy_reset:
	clk_reset(phy->phy_reset, CLK_RESET_DEASSERT);
deassert_phy_com_reset:
	clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT);

	phy->in_suspend = false;

	return ret;
}
/* SSPHY Initialization */
static int msm_ssphy_qmp_init(struct usb_phy *uphy)
{
	struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
					phy);
	int ret;
	unsigned init_timeout_usec = INIT_MAX_TIME_USEC;
	u32 revid;
	const struct qmp_reg_val *reg = NULL;

	dev_dbg(uphy->dev, "Initializing QMP phy\n");

	if (!phy->clk_enabled) {
		ret = msm_ssphy_qmp_init_clocks(phy);
		if (ret) {
			dev_err(uphy->dev, "failed to init clocks %d\n", ret);
			return ret;
		}
	}

	/* Rev ID is made up each of the LSBs of REVISION_ID[0-3] */
	revid = (readl_relaxed(phy->base +
			PCIE_USB3_PHY_REVISION_ID3) & 0xFF) << 24;
	revid |= (readl_relaxed(phy->base +
			PCIE_USB3_PHY_REVISION_ID2) & 0xFF) << 16;
	revid |= (readl_relaxed(phy->base +
			PCIE_USB3_PHY_REVISION_ID1) & 0xFF) << 8;
	revid |= readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID0) & 0xFF;

	switch (revid) {
	case 0x10000000:
		reg = qmp_settings_rev0;
		break;
	case 0x10000001:
		reg = qmp_settings_rev1;
		break;
	default:
		dev_err(uphy->dev, "Unknown revid 0x%x, cannot initialize PHY\n",
			revid);
		return -ENODEV;
	}

	/* Configure AHB2PHY for one wait state reads/writes */
	if (phy->ahb2phy)
		writel_relaxed(0x11, phy->ahb2phy + PERIPH_SS_AHB2PHY_TOP_CFG);

	writel_relaxed(0x01, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL);

	while (reg && reg->offset != -1 && reg->val != -1) {
		writel_relaxed(reg->val, phy->base + reg->offset);
		reg++;
	}

	if (phy->override_pll_cal) {
		reg = qmp_override_pll;
		while (reg->offset != -1 && reg->val != -1) {
			writel_relaxed(reg->val, phy->base + reg->offset);
			reg++;
		}
	}

	writel_relaxed(0x00, phy->base + PCIE_USB3_PHY_SW_RESET);
	writel_relaxed(0x03, phy->base + PCIE_USB3_PHY_START);

	if (!phy->switch_pipe_clk_src)
		/* this clock wasn't enabled before, enable it now */
		clk_prepare_enable(phy->pipe_clk);

	/* Wait for PHY initialization to be done */
	do {
		if (readl_relaxed(phy->base + PCIE_USB3_PHY_PCS_STATUS) &
			PHYSTATUS)
			usleep(1);
		else
			break;
	} while (--init_timeout_usec);

	if (!init_timeout_usec) {
		dev_err(uphy->dev, "QMP PHY initialization timeout\n");
		return -EBUSY;
	};

	/*
	 * After PHY initilization above, the PHY is generating
	 * the usb3_pipe_clk in 125MHz. Therefore now we can (if needed)
	 * switch the gcc_usb3_pipe_clk to 125MHz as well, so the
	 * gcc_usb3_pipe_clk is sourced now from the usb3_pipe3_clk
	 * instead of from the xo clock.
	 */
	if (phy->switch_pipe_clk_src)
		clk_set_rate(phy->pipe_clk, 125000000);

	return 0;
}
static int msm_ssphy_qmp_reset(struct usb_phy *uphy)
{
	struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
					phy);
	int ret;

	dev_info(uphy->dev, "Resetting QMP phy\n");

	if (!phy->clk_enabled) {
		ret = msm_ssphy_qmp_init_clocks(phy);
		if (ret) {
			dev_err(uphy->dev, "failed to init clocks %d\n", ret);
			return ret;
		}
	}

	
	if (phy->phy_com_reset) {
		ret = clk_reset(phy->phy_com_reset, CLK_RESET_ASSERT);
		if (ret) {
			dev_err(uphy->dev, "phy_com_reset clk assert failed\n");
			return ret;
		}
	}

	
	if (phy->phy_phy_reset) {
		ret = clk_reset(phy->phy_phy_reset, CLK_RESET_ASSERT);
		if (ret) {
			dev_err(uphy->dev, "phy_phy reset assert failed\n");
			goto deassert_phy_com_reset;
		}
	} else {
		ret = clk_reset(phy->pipe_clk, CLK_RESET_ASSERT);
		if (ret) {
			dev_err(uphy->dev, "pipe_clk reset assert failed\n");
			goto deassert_phy_com_reset;
		}
	}

	
	ret = clk_reset(phy->phy_reset, CLK_RESET_ASSERT);
	if (ret) {
		dev_err(uphy->dev, "phy_reset clk assert failed\n");
		goto deassert_phy_phy_reset;
	}

	
	ret = clk_reset(phy->phy_reset, CLK_RESET_DEASSERT);
	if (ret) {
		dev_err(uphy->dev, "phy_reset clk deassert failed\n");
		goto deassert_phy_phy_reset;
	}

	
	if (phy->phy_phy_reset) {
		ret = clk_reset(phy->phy_phy_reset, CLK_RESET_DEASSERT);
		if (ret) {
			dev_err(uphy->dev, "phy_phy reset deassert failed\n");
			goto deassert_phy_com_reset;
		}
	} else {
		ret = clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT);
		if (ret) {
			dev_err(uphy->dev, "pipe_clk reset deassert failed\n");
			goto deassert_phy_com_reset;
		}
	}

	if (phy->phy_com_reset) {
		ret = clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT);
		if (ret) {
			dev_err(uphy->dev, "phy_com_reset clk deassert failed\n");
			return ret;
		}
	}
	return 0;

deassert_phy_phy_reset:
	if (phy->phy_phy_reset)
		clk_reset(phy->phy_phy_reset, CLK_RESET_DEASSERT);
	else
		clk_reset(phy->pipe_clk, CLK_RESET_DEASSERT);
deassert_phy_com_reset:
	if (phy->phy_com_reset)
		clk_reset(phy->phy_com_reset, CLK_RESET_DEASSERT);

	phy->in_suspend = false;

	return ret;
}
static int msm_ssphy_qmp_probe(struct platform_device *pdev)
{
	struct msm_ssphy_qmp *phy;
	struct device *dev = &pdev->dev;
	struct resource *res;
	int ret = 0;

	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
	if (!phy)
		return -ENOMEM;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(dev, "missing memory base resource\n");
		return -ENODEV;
	}

	phy->base = devm_ioremap_nocache(dev, res->start, resource_size(res));
	if (!phy->base) {
		dev_err(dev, "ioremap failed\n");
		return -ENODEV;
	}

	ret = of_property_read_u32_array(dev->of_node, "qcom,vdd-voltage-level",
					 (u32 *) phy->vdd_levels,
					 ARRAY_SIZE(phy->vdd_levels));
	if (ret) {
		dev_err(dev, "error reading qcom,vdd-voltage-level property\n");
		return ret;
	}

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

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

	ret = msm_ssusb_qmp_config_vdd(phy, 1);
	if (ret) {
		dev_err(dev, "ssusb vdd_dig configuration failed\n");
		return ret;
	}

	ret = regulator_enable(phy->vdd);
	if (ret) {
		dev_err(dev, "unable to enable the ssusb vdd_dig\n");
		goto unconfig_ss_vdd;
	}

	ret = msm_ssusb_qmp_ldo_enable(phy, 1);
	if (ret) {
		dev_err(dev, "ssusb vreg enable failed\n");
		goto disable_ss_vdd;
	}

	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_qmp_init;
	phy->phy.set_suspend		= msm_ssphy_qmp_set_suspend;
	phy->phy.set_params		= msm_ssphy_qmp_set_params;
	phy->phy.notify_connect		= msm_ssphy_qmp_notify_connect;
	phy->phy.notify_disconnect	= msm_ssphy_qmp_notify_disconnect;
	phy->phy.reset			= msm_ssphy_qmp_reset;
	phy->phy.type			= USB_PHY_TYPE_USB3;

	ret = msm_ssphy_qmp_init_clocks(phy);
	if (ret) {
		dev_err(dev, "Fail to init qmp phy clocks\n");
		goto disable_ss_ldo;
	}

	ret = usb_add_phy_dev(&phy->phy);
	if (ret)
		goto disable_ss_ldo;
	return 0;

disable_ss_ldo:
	msm_ssusb_qmp_ldo_enable(phy, 0);
disable_ss_vdd:
	regulator_disable(phy->vdd);
unconfig_ss_vdd:
	msm_ssusb_qmp_config_vdd(phy, 0);

	return ret;
}
static int msm_ssphy_qmp_init(struct usb_phy *uphy)
{
	struct msm_ssphy_qmp *phy = container_of(uphy, struct msm_ssphy_qmp,
					phy);
	int ret;
	unsigned init_timeout_usec = INIT_MAX_TIME_USEC;
	u32 revid;
	const struct qmp_reg_val *reg = NULL, *misc = NULL;

	dev_info(uphy->dev, "Initializing QMP phy\n");

	if (phy->emulation)
		return 0;

	if (!phy->clk_enabled) {
		ret = msm_ssphy_qmp_init_clocks(phy);
		if (ret) {
			dev_err(uphy->dev, "failed to init clocks %d\n", ret);
			return ret;
		}
	}

	
	revid = (readl_relaxed(phy->base +
			PCIE_USB3_PHY_REVISION_ID3) & 0xFF) << 24;
	revid |= (readl_relaxed(phy->base +
			PCIE_USB3_PHY_REVISION_ID2) & 0xFF) << 16;
	revid |= (readl_relaxed(phy->base +
			PCIE_USB3_PHY_REVISION_ID1) & 0xFF) << 8;
	revid |= readl_relaxed(phy->base + PCIE_USB3_PHY_REVISION_ID0) & 0xFF;

	dev_info(uphy->dev, "QMP phy revid = %x\n", revid);

	switch (revid) {
	case 0x10000000:
		reg = qmp_settings_rev0;
		misc = qmp_settings_rev0_misc;
		break;
	case 0x10000001:
		reg = qmp_settings_rev1;
		misc = qmp_settings_rev1_misc;
		break;
	default:
		dev_err(uphy->dev, "Unknown revid 0x%x, cannot initialize PHY\n",
			revid);
		return -ENODEV;
	}

	
	if (phy->ahb2phy)
		writel_relaxed(0x11, phy->ahb2phy + PERIPH_SS_AHB2PHY_TOP_CFG);

	writel_relaxed(0x01, phy->base + PCIE_USB3_PHY_POWER_DOWN_CONTROL);

	
	ret = configure_phy_regs(uphy, reg);
	if (ret) {
		dev_err(uphy->dev, "Failed the main PHY configuration\n");
		return ret;
	}

	
	if (phy->override_pll_cal) {
		reg = qmp_override_pll;
		ret = configure_phy_regs(uphy, reg);
		if (ret) {
			dev_err(uphy->dev,
				"Failed the PHY PLL override configuration\n");
			return ret;
		}
	}
	if (phy->misc_config) {
		ret = configure_phy_regs(uphy, misc);
		if (ret) {
			dev_err(uphy->dev, "Failed the misc PHY configuration\n");
			return ret;
		}
	}

	writel_relaxed(0x00, phy->base + PCIE_USB3_PHY_SW_RESET);
	writel_relaxed(0x03, phy->base + PCIE_USB3_PHY_START);

	if (!phy->switch_pipe_clk_src)
		
		clk_prepare_enable(phy->pipe_clk);

	
	do {
		if (readl_relaxed(phy->base + PCIE_USB3_PHY_PCS_STATUS) &
			PHYSTATUS)
			usleep(1);
		else
			break;
	} while (--init_timeout_usec);

	if (!init_timeout_usec) {
		dev_err(uphy->dev, "QMP PHY initialization timeout\n");
		return -EBUSY;
	};

	if (phy->switch_pipe_clk_src)
		clk_set_rate(phy->pipe_clk, 125000000);

	return 0;
}