xref: /openbmc/linux/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
151e8114fSWesley Cheng // SPDX-License-Identifier: GPL-2.0
251e8114fSWesley Cheng /*
351e8114fSWesley Cheng  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
451e8114fSWesley Cheng  */
551e8114fSWesley Cheng 
651e8114fSWesley Cheng #include <linux/clk.h>
751e8114fSWesley Cheng #include <linux/delay.h>
851e8114fSWesley Cheng #include <linux/err.h>
951e8114fSWesley Cheng #include <linux/io.h>
1051e8114fSWesley Cheng #include <linux/kernel.h>
1151e8114fSWesley Cheng #include <linux/module.h>
1251e8114fSWesley Cheng #include <linux/of.h>
1351e8114fSWesley Cheng #include <linux/phy/phy.h>
1451e8114fSWesley Cheng #include <linux/platform_device.h>
1551e8114fSWesley Cheng #include <linux/regmap.h>
1651e8114fSWesley Cheng #include <linux/regulator/consumer.h>
1751e8114fSWesley Cheng #include <linux/reset.h>
1851e8114fSWesley Cheng #include <linux/slab.h>
1951e8114fSWesley Cheng 
2051e8114fSWesley Cheng #define USB2_PHY_USB_PHY_UTMI_CTRL0		(0x3c)
2151e8114fSWesley Cheng #define SLEEPM					BIT(0)
2251e8114fSWesley Cheng #define OPMODE_MASK				GENMASK(4, 3)
2351e8114fSWesley Cheng #define OPMODE_NORMAL				(0x00)
2451e8114fSWesley Cheng #define OPMODE_NONDRIVING			BIT(3)
2551e8114fSWesley Cheng #define TERMSEL					BIT(5)
2651e8114fSWesley Cheng 
2751e8114fSWesley Cheng #define USB2_PHY_USB_PHY_UTMI_CTRL1		(0x40)
2851e8114fSWesley Cheng #define XCVRSEL					BIT(0)
2951e8114fSWesley Cheng 
3051e8114fSWesley Cheng #define USB2_PHY_USB_PHY_UTMI_CTRL5		(0x50)
3151e8114fSWesley Cheng #define POR					BIT(1)
3251e8114fSWesley Cheng 
3351e8114fSWesley Cheng #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0	(0x54)
347addff40SBjorn Andersson #define SIDDQ					BIT(2)
3551e8114fSWesley Cheng #define RETENABLEN				BIT(3)
36b475bf0eSSandeep Maheswaram #define FSEL_MASK				GENMASK(6, 4)
3751e8114fSWesley Cheng #define FSEL_DEFAULT				(0x3 << 4)
3851e8114fSWesley Cheng 
3951e8114fSWesley Cheng #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1	(0x58)
4051e8114fSWesley Cheng #define VBUSVLDEXTSEL0				BIT(4)
4151e8114fSWesley Cheng #define PLLBTUNE				BIT(5)
4251e8114fSWesley Cheng 
4351e8114fSWesley Cheng #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2	(0x5c)
4451e8114fSWesley Cheng #define VREGBYPASS				BIT(0)
4551e8114fSWesley Cheng 
4651e8114fSWesley Cheng #define USB2_PHY_USB_PHY_HS_PHY_CTRL1		(0x60)
4751e8114fSWesley Cheng #define VBUSVLDEXT0				BIT(0)
4851e8114fSWesley Cheng 
4951e8114fSWesley Cheng #define USB2_PHY_USB_PHY_HS_PHY_CTRL2		(0x64)
5051e8114fSWesley Cheng #define USB2_AUTO_RESUME			BIT(0)
5151e8114fSWesley Cheng #define USB2_SUSPEND_N				BIT(2)
5251e8114fSWesley Cheng #define USB2_SUSPEND_N_SEL			BIT(3)
5351e8114fSWesley Cheng 
54df2217ffSKrishna Kurapati #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0		(0x6c)
55df2217ffSKrishna Kurapati #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1		(0x70)
56df2217ffSKrishna Kurapati #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2		(0x74)
57df2217ffSKrishna Kurapati #define USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X3		(0x78)
58df2217ffSKrishna Kurapati #define PARAM_OVRD_MASK				0xFF
59df2217ffSKrishna Kurapati 
6051e8114fSWesley Cheng #define USB2_PHY_USB_PHY_CFG0			(0x94)
6151e8114fSWesley Cheng #define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN	BIT(0)
6251e8114fSWesley Cheng #define UTMI_PHY_CMN_CTRL_OVERRIDE_EN		BIT(1)
6351e8114fSWesley Cheng 
6451e8114fSWesley Cheng #define USB2_PHY_USB_PHY_REFCLK_CTRL		(0xa0)
6551e8114fSWesley Cheng #define REFCLK_SEL_MASK				GENMASK(1, 0)
6651e8114fSWesley Cheng #define REFCLK_SEL_DEFAULT			(0x2 << 0)
6751e8114fSWesley Cheng 
68df2217ffSKrishna Kurapati #define HS_DISCONNECT_MASK			GENMASK(2, 0)
69df2217ffSKrishna Kurapati #define SQUELCH_DETECTOR_MASK			GENMASK(7, 5)
70df2217ffSKrishna Kurapati 
71df2217ffSKrishna Kurapati #define HS_AMPLITUDE_MASK			GENMASK(3, 0)
72df2217ffSKrishna Kurapati #define PREEMPHASIS_DURATION_MASK		BIT(5)
73df2217ffSKrishna Kurapati #define PREEMPHASIS_AMPLITUDE_MASK		GENMASK(7, 6)
74df2217ffSKrishna Kurapati 
75df2217ffSKrishna Kurapati #define HS_RISE_FALL_MASK			GENMASK(1, 0)
76df2217ffSKrishna Kurapati #define HS_CROSSOVER_VOLTAGE_MASK		GENMASK(3, 2)
77df2217ffSKrishna Kurapati #define HS_OUTPUT_IMPEDANCE_MASK		GENMASK(5, 4)
78df2217ffSKrishna Kurapati 
79df2217ffSKrishna Kurapati #define LS_FS_OUTPUT_IMPEDANCE_MASK		GENMASK(3, 0)
80df2217ffSKrishna Kurapati 
8151e8114fSWesley Cheng static const char * const qcom_snps_hsphy_vreg_names[] = {
8251e8114fSWesley Cheng 	"vdda-pll", "vdda33", "vdda18",
8351e8114fSWesley Cheng };
8451e8114fSWesley Cheng 
8551e8114fSWesley Cheng #define SNPS_HS_NUM_VREGS		ARRAY_SIZE(qcom_snps_hsphy_vreg_names)
8651e8114fSWesley Cheng 
87df2217ffSKrishna Kurapati struct override_param {
88df2217ffSKrishna Kurapati 	s32	value;
89df2217ffSKrishna Kurapati 	u8	reg_val;
90df2217ffSKrishna Kurapati };
91df2217ffSKrishna Kurapati 
92df2217ffSKrishna Kurapati struct override_param_map {
93df2217ffSKrishna Kurapati 	const char *prop_name;
94df2217ffSKrishna Kurapati 	const struct override_param *param_table;
95df2217ffSKrishna Kurapati 	u8 table_size;
96df2217ffSKrishna Kurapati 	u8 reg_offset;
97df2217ffSKrishna Kurapati 	u8 param_mask;
98df2217ffSKrishna Kurapati };
99df2217ffSKrishna Kurapati 
100df2217ffSKrishna Kurapati struct phy_override_seq {
101df2217ffSKrishna Kurapati 	bool	need_update;
102df2217ffSKrishna Kurapati 	u8	offset;
103df2217ffSKrishna Kurapati 	u8	value;
104df2217ffSKrishna Kurapati 	u8	mask;
105df2217ffSKrishna Kurapati };
106df2217ffSKrishna Kurapati 
107df2217ffSKrishna Kurapati #define NUM_HSPHY_TUNING_PARAMS	(9)
108df2217ffSKrishna Kurapati 
10951e8114fSWesley Cheng /**
11051e8114fSWesley Cheng  * struct qcom_snps_hsphy - snps hs phy attributes
11151e8114fSWesley Cheng  *
1128a0eb8f9SAdrien Thierry  * @dev: device structure
1138a0eb8f9SAdrien Thierry  *
11451e8114fSWesley Cheng  * @phy: generic phy
11551e8114fSWesley Cheng  * @base: iomapped memory space for snps hs phy
11651e8114fSWesley Cheng  *
1178a0eb8f9SAdrien Thierry  * @num_clks: number of clocks
1188a0eb8f9SAdrien Thierry  * @clks: array of clocks
11951e8114fSWesley Cheng  * @phy_reset: phy reset control
12051e8114fSWesley Cheng  * @vregs: regulator supplies bulk data
12151e8114fSWesley Cheng  * @phy_initialized: if PHY has been initialized correctly
122dcbec046SWesley Cheng  * @mode: contains the current mode the PHY is in
1232a881183SKrzysztof Kozlowski  * @update_seq_cfg: tuning parameters for phy init
12451e8114fSWesley Cheng  */
12551e8114fSWesley Cheng struct qcom_snps_hsphy {
1268a0eb8f9SAdrien Thierry 	struct device *dev;
1278a0eb8f9SAdrien Thierry 
12851e8114fSWesley Cheng 	struct phy *phy;
12951e8114fSWesley Cheng 	void __iomem *base;
13051e8114fSWesley Cheng 
1318a0eb8f9SAdrien Thierry 	int num_clks;
1328a0eb8f9SAdrien Thierry 	struct clk_bulk_data *clks;
13351e8114fSWesley Cheng 	struct reset_control *phy_reset;
13451e8114fSWesley Cheng 	struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS];
13551e8114fSWesley Cheng 
13651e8114fSWesley Cheng 	bool phy_initialized;
137dcbec046SWesley Cheng 	enum phy_mode mode;
138df2217ffSKrishna Kurapati 	struct phy_override_seq update_seq_cfg[NUM_HSPHY_TUNING_PARAMS];
13951e8114fSWesley Cheng };
14051e8114fSWesley Cheng 
qcom_snps_hsphy_clk_init(struct qcom_snps_hsphy * hsphy)1418a0eb8f9SAdrien Thierry static int qcom_snps_hsphy_clk_init(struct qcom_snps_hsphy *hsphy)
1428a0eb8f9SAdrien Thierry {
1438a0eb8f9SAdrien Thierry 	struct device *dev = hsphy->dev;
1448a0eb8f9SAdrien Thierry 
1458a0eb8f9SAdrien Thierry 	hsphy->num_clks = 2;
1468a0eb8f9SAdrien Thierry 	hsphy->clks = devm_kcalloc(dev, hsphy->num_clks, sizeof(*hsphy->clks), GFP_KERNEL);
1478a0eb8f9SAdrien Thierry 	if (!hsphy->clks)
1488a0eb8f9SAdrien Thierry 		return -ENOMEM;
1498a0eb8f9SAdrien Thierry 
1508a0eb8f9SAdrien Thierry 	/*
1518a0eb8f9SAdrien Thierry 	 * TODO: Currently no device tree instantiation of the PHY is using the clock.
1528a0eb8f9SAdrien Thierry 	 * This needs to be fixed in order for this code to be able to use devm_clk_bulk_get().
1538a0eb8f9SAdrien Thierry 	 */
1548a0eb8f9SAdrien Thierry 	hsphy->clks[0].id = "cfg_ahb";
1558a0eb8f9SAdrien Thierry 	hsphy->clks[0].clk = devm_clk_get_optional(dev, "cfg_ahb");
1568a0eb8f9SAdrien Thierry 	if (IS_ERR(hsphy->clks[0].clk))
1578a0eb8f9SAdrien Thierry 		return dev_err_probe(dev, PTR_ERR(hsphy->clks[0].clk),
1588a0eb8f9SAdrien Thierry 				     "failed to get cfg_ahb clk\n");
1598a0eb8f9SAdrien Thierry 
1608a0eb8f9SAdrien Thierry 	hsphy->clks[1].id = "ref";
1618a0eb8f9SAdrien Thierry 	hsphy->clks[1].clk = devm_clk_get(dev, "ref");
1628a0eb8f9SAdrien Thierry 	if (IS_ERR(hsphy->clks[1].clk))
1638a0eb8f9SAdrien Thierry 		return dev_err_probe(dev, PTR_ERR(hsphy->clks[1].clk),
1648a0eb8f9SAdrien Thierry 				     "failed to get ref clk\n");
1658a0eb8f9SAdrien Thierry 
1668a0eb8f9SAdrien Thierry 	return 0;
1678a0eb8f9SAdrien Thierry }
1688a0eb8f9SAdrien Thierry 
qcom_snps_hsphy_write_mask(void __iomem * base,u32 offset,u32 mask,u32 val)16951e8114fSWesley Cheng static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
17051e8114fSWesley Cheng 						u32 mask, u32 val)
17151e8114fSWesley Cheng {
17251e8114fSWesley Cheng 	u32 reg;
17351e8114fSWesley Cheng 
17451e8114fSWesley Cheng 	reg = readl_relaxed(base + offset);
17551e8114fSWesley Cheng 	reg &= ~mask;
17651e8114fSWesley Cheng 	reg |= val & mask;
17751e8114fSWesley Cheng 	writel_relaxed(reg, base + offset);
17851e8114fSWesley Cheng 
17951e8114fSWesley Cheng 	/* Ensure above write is completed */
18051e8114fSWesley Cheng 	readl_relaxed(base + offset);
18151e8114fSWesley Cheng }
18251e8114fSWesley Cheng 
qcom_snps_hsphy_suspend(struct qcom_snps_hsphy * hsphy)1830d75f508SWesley Cheng static int qcom_snps_hsphy_suspend(struct qcom_snps_hsphy *hsphy)
1840d75f508SWesley Cheng {
1850d75f508SWesley Cheng 	dev_dbg(&hsphy->phy->dev, "Suspend QCOM SNPS PHY\n");
1860d75f508SWesley Cheng 
1870d75f508SWesley Cheng 	if (hsphy->mode == PHY_MODE_USB_HOST) {
1880d75f508SWesley Cheng 		/* Enable auto-resume to meet remote wakeup timing */
1890d75f508SWesley Cheng 		qcom_snps_hsphy_write_mask(hsphy->base,
1900d75f508SWesley Cheng 					   USB2_PHY_USB_PHY_HS_PHY_CTRL2,
1910d75f508SWesley Cheng 					   USB2_AUTO_RESUME,
1920d75f508SWesley Cheng 					   USB2_AUTO_RESUME);
1930d75f508SWesley Cheng 		usleep_range(500, 1000);
1940d75f508SWesley Cheng 		qcom_snps_hsphy_write_mask(hsphy->base,
1950d75f508SWesley Cheng 					   USB2_PHY_USB_PHY_HS_PHY_CTRL2,
1960d75f508SWesley Cheng 					   0, USB2_AUTO_RESUME);
1970d75f508SWesley Cheng 	}
1980d75f508SWesley Cheng 
1990d75f508SWesley Cheng 	return 0;
2000d75f508SWesley Cheng }
2010d75f508SWesley Cheng 
qcom_snps_hsphy_resume(struct qcom_snps_hsphy * hsphy)2020d75f508SWesley Cheng static int qcom_snps_hsphy_resume(struct qcom_snps_hsphy *hsphy)
2030d75f508SWesley Cheng {
2040d75f508SWesley Cheng 	dev_dbg(&hsphy->phy->dev, "Resume QCOM SNPS PHY, mode\n");
2050d75f508SWesley Cheng 
2060d75f508SWesley Cheng 	return 0;
2070d75f508SWesley Cheng }
2080d75f508SWesley Cheng 
qcom_snps_hsphy_runtime_suspend(struct device * dev)2090d75f508SWesley Cheng static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev)
2100d75f508SWesley Cheng {
2110d75f508SWesley Cheng 	struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
2120d75f508SWesley Cheng 
2130d75f508SWesley Cheng 	if (!hsphy->phy_initialized)
2140d75f508SWesley Cheng 		return 0;
2150d75f508SWesley Cheng 
216*8932089bSAdrien Thierry 	return qcom_snps_hsphy_suspend(hsphy);
2170d75f508SWesley Cheng }
2180d75f508SWesley Cheng 
qcom_snps_hsphy_runtime_resume(struct device * dev)2190d75f508SWesley Cheng static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev)
2200d75f508SWesley Cheng {
2210d75f508SWesley Cheng 	struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
2220d75f508SWesley Cheng 
2230d75f508SWesley Cheng 	if (!hsphy->phy_initialized)
2240d75f508SWesley Cheng 		return 0;
2250d75f508SWesley Cheng 
226*8932089bSAdrien Thierry 	return qcom_snps_hsphy_resume(hsphy);
2270d75f508SWesley Cheng }
2280d75f508SWesley Cheng 
qcom_snps_hsphy_set_mode(struct phy * phy,enum phy_mode mode,int submode)229dcbec046SWesley Cheng static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
230dcbec046SWesley Cheng 				    int submode)
231dcbec046SWesley Cheng {
232dcbec046SWesley Cheng 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
233dcbec046SWesley Cheng 
234dcbec046SWesley Cheng 	hsphy->mode = mode;
235dcbec046SWesley Cheng 	return 0;
236dcbec046SWesley Cheng }
237dcbec046SWesley Cheng 
238df2217ffSKrishna Kurapati static const struct override_param hs_disconnect_sc7280[] = {
239df2217ffSKrishna Kurapati 	{ -272, 0 },
240df2217ffSKrishna Kurapati 	{ 0, 1 },
241df2217ffSKrishna Kurapati 	{ 317, 2 },
242df2217ffSKrishna Kurapati 	{ 630, 3 },
243df2217ffSKrishna Kurapati 	{ 973, 4 },
244df2217ffSKrishna Kurapati 	{ 1332, 5 },
245df2217ffSKrishna Kurapati 	{ 1743, 6 },
246df2217ffSKrishna Kurapati 	{ 2156, 7 },
247df2217ffSKrishna Kurapati };
248df2217ffSKrishna Kurapati 
249df2217ffSKrishna Kurapati static const struct override_param squelch_det_threshold_sc7280[] = {
250df2217ffSKrishna Kurapati 	{ -2090, 7 },
251df2217ffSKrishna Kurapati 	{ -1560, 6 },
252df2217ffSKrishna Kurapati 	{ -1030, 5 },
253df2217ffSKrishna Kurapati 	{ -530, 4 },
254df2217ffSKrishna Kurapati 	{ 0, 3 },
255df2217ffSKrishna Kurapati 	{ 530, 2 },
256df2217ffSKrishna Kurapati 	{ 1060, 1 },
257df2217ffSKrishna Kurapati 	{ 1590, 0 },
258df2217ffSKrishna Kurapati };
259df2217ffSKrishna Kurapati 
260df2217ffSKrishna Kurapati static const struct override_param hs_amplitude_sc7280[] = {
261df2217ffSKrishna Kurapati 	{ -660, 0 },
262df2217ffSKrishna Kurapati 	{ -440, 1 },
263df2217ffSKrishna Kurapati 	{ -220, 2 },
264df2217ffSKrishna Kurapati 	{ 0, 3 },
265df2217ffSKrishna Kurapati 	{ 230, 4 },
266df2217ffSKrishna Kurapati 	{ 440, 5 },
267df2217ffSKrishna Kurapati 	{ 650, 6 },
268df2217ffSKrishna Kurapati 	{ 890, 7 },
269df2217ffSKrishna Kurapati 	{ 1110, 8 },
270df2217ffSKrishna Kurapati 	{ 1330, 9 },
271df2217ffSKrishna Kurapati 	{ 1560, 10 },
272df2217ffSKrishna Kurapati 	{ 1780, 11 },
273df2217ffSKrishna Kurapati 	{ 2000, 12 },
274df2217ffSKrishna Kurapati 	{ 2220, 13 },
275df2217ffSKrishna Kurapati 	{ 2430, 14 },
276df2217ffSKrishna Kurapati 	{ 2670, 15 },
277df2217ffSKrishna Kurapati };
278df2217ffSKrishna Kurapati 
279df2217ffSKrishna Kurapati static const struct override_param preemphasis_duration_sc7280[] = {
280df2217ffSKrishna Kurapati 	{ 10000, 1 },
281df2217ffSKrishna Kurapati 	{ 20000, 0 },
282df2217ffSKrishna Kurapati };
283df2217ffSKrishna Kurapati 
284df2217ffSKrishna Kurapati static const struct override_param preemphasis_amplitude_sc7280[] = {
285df2217ffSKrishna Kurapati 	{ 10000, 1 },
286df2217ffSKrishna Kurapati 	{ 20000, 2 },
287df2217ffSKrishna Kurapati 	{ 30000, 3 },
288df2217ffSKrishna Kurapati 	{ 40000, 0 },
289df2217ffSKrishna Kurapati };
290df2217ffSKrishna Kurapati 
291df2217ffSKrishna Kurapati static const struct override_param hs_rise_fall_time_sc7280[] = {
292df2217ffSKrishna Kurapati 	{ -4100, 3 },
293df2217ffSKrishna Kurapati 	{ 0, 2 },
294df2217ffSKrishna Kurapati 	{ 2810, 1 },
295df2217ffSKrishna Kurapati 	{ 5430, 0 },
296df2217ffSKrishna Kurapati };
297df2217ffSKrishna Kurapati 
298df2217ffSKrishna Kurapati static const struct override_param hs_crossover_voltage_sc7280[] = {
299df2217ffSKrishna Kurapati 	{ -31000, 1 },
300df2217ffSKrishna Kurapati 	{ 0, 3 },
301df2217ffSKrishna Kurapati 	{ 28000, 2 },
302df2217ffSKrishna Kurapati };
303df2217ffSKrishna Kurapati 
304df2217ffSKrishna Kurapati static const struct override_param hs_output_impedance_sc7280[] = {
305df2217ffSKrishna Kurapati 	{ -2300000, 3 },
306df2217ffSKrishna Kurapati 	{ 0, 2 },
307df2217ffSKrishna Kurapati 	{ 2600000, 1 },
308df2217ffSKrishna Kurapati 	{ 6100000, 0 },
309df2217ffSKrishna Kurapati };
310df2217ffSKrishna Kurapati 
311df2217ffSKrishna Kurapati static const struct override_param ls_fs_output_impedance_sc7280[] = {
312df2217ffSKrishna Kurapati 	{ -1053, 15 },
313df2217ffSKrishna Kurapati 	{ -557, 7 },
314df2217ffSKrishna Kurapati 	{ 0, 3 },
315df2217ffSKrishna Kurapati 	{ 612, 1 },
316df2217ffSKrishna Kurapati 	{ 1310, 0 },
317df2217ffSKrishna Kurapati };
318df2217ffSKrishna Kurapati 
319df2217ffSKrishna Kurapati static const struct override_param_map sc7280_snps_7nm_phy[] = {
320df2217ffSKrishna Kurapati 	{
321df2217ffSKrishna Kurapati 		"qcom,hs-disconnect-bp",
322df2217ffSKrishna Kurapati 		hs_disconnect_sc7280,
323df2217ffSKrishna Kurapati 		ARRAY_SIZE(hs_disconnect_sc7280),
324df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0,
325df2217ffSKrishna Kurapati 		HS_DISCONNECT_MASK
326df2217ffSKrishna Kurapati 	},
327df2217ffSKrishna Kurapati 	{
328df2217ffSKrishna Kurapati 		"qcom,squelch-detector-bp",
329df2217ffSKrishna Kurapati 		squelch_det_threshold_sc7280,
330df2217ffSKrishna Kurapati 		ARRAY_SIZE(squelch_det_threshold_sc7280),
331df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X0,
332df2217ffSKrishna Kurapati 		SQUELCH_DETECTOR_MASK
333df2217ffSKrishna Kurapati 	},
334df2217ffSKrishna Kurapati 	{
335df2217ffSKrishna Kurapati 		"qcom,hs-amplitude-bp",
336df2217ffSKrishna Kurapati 		hs_amplitude_sc7280,
337df2217ffSKrishna Kurapati 		ARRAY_SIZE(hs_amplitude_sc7280),
338df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1,
339df2217ffSKrishna Kurapati 		HS_AMPLITUDE_MASK
340df2217ffSKrishna Kurapati 	},
341df2217ffSKrishna Kurapati 	{
342df2217ffSKrishna Kurapati 		"qcom,pre-emphasis-duration-bp",
343df2217ffSKrishna Kurapati 		preemphasis_duration_sc7280,
344df2217ffSKrishna Kurapati 		ARRAY_SIZE(preemphasis_duration_sc7280),
345df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1,
346df2217ffSKrishna Kurapati 		PREEMPHASIS_DURATION_MASK,
347df2217ffSKrishna Kurapati 	},
348df2217ffSKrishna Kurapati 	{
349df2217ffSKrishna Kurapati 		"qcom,pre-emphasis-amplitude-bp",
350df2217ffSKrishna Kurapati 		preemphasis_amplitude_sc7280,
351df2217ffSKrishna Kurapati 		ARRAY_SIZE(preemphasis_amplitude_sc7280),
352df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X1,
353df2217ffSKrishna Kurapati 		PREEMPHASIS_AMPLITUDE_MASK,
354df2217ffSKrishna Kurapati 	},
355df2217ffSKrishna Kurapati 	{
356df2217ffSKrishna Kurapati 		"qcom,hs-rise-fall-time-bp",
357df2217ffSKrishna Kurapati 		hs_rise_fall_time_sc7280,
358df2217ffSKrishna Kurapati 		ARRAY_SIZE(hs_rise_fall_time_sc7280),
359df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2,
360df2217ffSKrishna Kurapati 		HS_RISE_FALL_MASK
361df2217ffSKrishna Kurapati 	},
362df2217ffSKrishna Kurapati 	{
363df2217ffSKrishna Kurapati 		"qcom,hs-crossover-voltage-microvolt",
364df2217ffSKrishna Kurapati 		hs_crossover_voltage_sc7280,
365df2217ffSKrishna Kurapati 		ARRAY_SIZE(hs_crossover_voltage_sc7280),
366df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2,
367df2217ffSKrishna Kurapati 		HS_CROSSOVER_VOLTAGE_MASK
368df2217ffSKrishna Kurapati 	},
369df2217ffSKrishna Kurapati 	{
370df2217ffSKrishna Kurapati 		"qcom,hs-output-impedance-micro-ohms",
371df2217ffSKrishna Kurapati 		hs_output_impedance_sc7280,
372df2217ffSKrishna Kurapati 		ARRAY_SIZE(hs_output_impedance_sc7280),
373df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X2,
374df2217ffSKrishna Kurapati 		HS_OUTPUT_IMPEDANCE_MASK,
375df2217ffSKrishna Kurapati 	},
376df2217ffSKrishna Kurapati 	{
377df2217ffSKrishna Kurapati 		"qcom,ls-fs-output-impedance-bp",
378df2217ffSKrishna Kurapati 		ls_fs_output_impedance_sc7280,
379df2217ffSKrishna Kurapati 		ARRAY_SIZE(ls_fs_output_impedance_sc7280),
380df2217ffSKrishna Kurapati 		USB2_PHY_USB_PHY_HS_PHY_OVERRIDE_X3,
381df2217ffSKrishna Kurapati 		LS_FS_OUTPUT_IMPEDANCE_MASK,
382df2217ffSKrishna Kurapati 	},
383df2217ffSKrishna Kurapati 	{},
384df2217ffSKrishna Kurapati };
385df2217ffSKrishna Kurapati 
qcom_snps_hsphy_init(struct phy * phy)38651e8114fSWesley Cheng static int qcom_snps_hsphy_init(struct phy *phy)
38751e8114fSWesley Cheng {
38851e8114fSWesley Cheng 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
389df2217ffSKrishna Kurapati 	int ret, i;
39051e8114fSWesley Cheng 
39151e8114fSWesley Cheng 	dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__);
39251e8114fSWesley Cheng 
39351e8114fSWesley Cheng 	ret = regulator_bulk_enable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
39451e8114fSWesley Cheng 	if (ret)
39551e8114fSWesley Cheng 		return ret;
39651e8114fSWesley Cheng 
3978a0eb8f9SAdrien Thierry 	ret = clk_bulk_prepare_enable(hsphy->num_clks, hsphy->clks);
39851e8114fSWesley Cheng 	if (ret) {
3998a0eb8f9SAdrien Thierry 		dev_err(&phy->dev, "failed to enable clocks, %d\n", ret);
40051e8114fSWesley Cheng 		goto poweroff_phy;
40151e8114fSWesley Cheng 	}
40251e8114fSWesley Cheng 
40351e8114fSWesley Cheng 	ret = reset_control_assert(hsphy->phy_reset);
40451e8114fSWesley Cheng 	if (ret) {
40551e8114fSWesley Cheng 		dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
4068a0eb8f9SAdrien Thierry 		goto disable_clks;
40751e8114fSWesley Cheng 	}
40851e8114fSWesley Cheng 
40951e8114fSWesley Cheng 	usleep_range(100, 150);
41051e8114fSWesley Cheng 
41151e8114fSWesley Cheng 	ret = reset_control_deassert(hsphy->phy_reset);
41251e8114fSWesley Cheng 	if (ret) {
41351e8114fSWesley Cheng 		dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
4148a0eb8f9SAdrien Thierry 		goto disable_clks;
41551e8114fSWesley Cheng 	}
41651e8114fSWesley Cheng 
41751e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
41851e8114fSWesley Cheng 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
41951e8114fSWesley Cheng 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
42051e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
42151e8114fSWesley Cheng 							POR, POR);
42251e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base,
42351e8114fSWesley Cheng 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
42451e8114fSWesley Cheng 					FSEL_MASK, 0);
42551e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base,
42651e8114fSWesley Cheng 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
42751e8114fSWesley Cheng 					PLLBTUNE, PLLBTUNE);
42851e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_REFCLK_CTRL,
42951e8114fSWesley Cheng 					REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK);
43051e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base,
43151e8114fSWesley Cheng 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
43251e8114fSWesley Cheng 					VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
43351e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
43451e8114fSWesley Cheng 					VBUSVLDEXT0, VBUSVLDEXT0);
43551e8114fSWesley Cheng 
436df2217ffSKrishna Kurapati 	for (i = 0; i < ARRAY_SIZE(hsphy->update_seq_cfg); i++) {
437df2217ffSKrishna Kurapati 		if (hsphy->update_seq_cfg[i].need_update)
438df2217ffSKrishna Kurapati 			qcom_snps_hsphy_write_mask(hsphy->base,
439df2217ffSKrishna Kurapati 					hsphy->update_seq_cfg[i].offset,
440df2217ffSKrishna Kurapati 					hsphy->update_seq_cfg[i].mask,
441df2217ffSKrishna Kurapati 					hsphy->update_seq_cfg[i].value);
442df2217ffSKrishna Kurapati 	}
443df2217ffSKrishna Kurapati 
44451e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base,
44551e8114fSWesley Cheng 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
44651e8114fSWesley Cheng 					VREGBYPASS, VREGBYPASS);
44751e8114fSWesley Cheng 
44851e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
44951e8114fSWesley Cheng 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
45051e8114fSWesley Cheng 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
45151e8114fSWesley Cheng 
45251e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
45351e8114fSWesley Cheng 					SLEEPM, SLEEPM);
45451e8114fSWesley Cheng 
4557addff40SBjorn Andersson 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
4567addff40SBjorn Andersson 				   SIDDQ, 0);
4577addff40SBjorn Andersson 
45851e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
45951e8114fSWesley Cheng 					POR, 0);
46051e8114fSWesley Cheng 
46151e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
46251e8114fSWesley Cheng 					USB2_SUSPEND_N_SEL, 0);
46351e8114fSWesley Cheng 
46451e8114fSWesley Cheng 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
46551e8114fSWesley Cheng 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0);
46651e8114fSWesley Cheng 
46751e8114fSWesley Cheng 	hsphy->phy_initialized = true;
46851e8114fSWesley Cheng 
46951e8114fSWesley Cheng 	return 0;
47051e8114fSWesley Cheng 
4718a0eb8f9SAdrien Thierry disable_clks:
4728a0eb8f9SAdrien Thierry 	clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
47351e8114fSWesley Cheng poweroff_phy:
47451e8114fSWesley Cheng 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
47551e8114fSWesley Cheng 
47651e8114fSWesley Cheng 	return ret;
47751e8114fSWesley Cheng }
47851e8114fSWesley Cheng 
qcom_snps_hsphy_exit(struct phy * phy)47951e8114fSWesley Cheng static int qcom_snps_hsphy_exit(struct phy *phy)
48051e8114fSWesley Cheng {
48151e8114fSWesley Cheng 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
48251e8114fSWesley Cheng 
48351e8114fSWesley Cheng 	reset_control_assert(hsphy->phy_reset);
4848a0eb8f9SAdrien Thierry 	clk_bulk_disable_unprepare(hsphy->num_clks, hsphy->clks);
48551e8114fSWesley Cheng 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
48651e8114fSWesley Cheng 	hsphy->phy_initialized = false;
48751e8114fSWesley Cheng 
48851e8114fSWesley Cheng 	return 0;
48951e8114fSWesley Cheng }
49051e8114fSWesley Cheng 
49151e8114fSWesley Cheng static const struct phy_ops qcom_snps_hsphy_gen_ops = {
49251e8114fSWesley Cheng 	.init		= qcom_snps_hsphy_init,
49351e8114fSWesley Cheng 	.exit		= qcom_snps_hsphy_exit,
494dcbec046SWesley Cheng 	.set_mode	= qcom_snps_hsphy_set_mode,
49551e8114fSWesley Cheng 	.owner		= THIS_MODULE,
49651e8114fSWesley Cheng };
49751e8114fSWesley Cheng 
49851e8114fSWesley Cheng static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
49951e8114fSWesley Cheng 	{ .compatible	= "qcom,sm8150-usb-hs-phy", },
5007addff40SBjorn Andersson 	{ .compatible	= "qcom,usb-snps-hs-5nm-phy", },
501df2217ffSKrishna Kurapati 	{
502df2217ffSKrishna Kurapati 		.compatible	= "qcom,usb-snps-hs-7nm-phy",
503df2217ffSKrishna Kurapati 		.data		= &sc7280_snps_7nm_phy,
504df2217ffSKrishna Kurapati 	},
50551e8114fSWesley Cheng 	{ .compatible	= "qcom,usb-snps-femto-v2-phy",	},
50651e8114fSWesley Cheng 	{ }
50751e8114fSWesley Cheng };
50851e8114fSWesley Cheng MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table);
50951e8114fSWesley Cheng 
5100d75f508SWesley Cheng static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = {
5110d75f508SWesley Cheng 	SET_RUNTIME_PM_OPS(qcom_snps_hsphy_runtime_suspend,
5120d75f508SWesley Cheng 			   qcom_snps_hsphy_runtime_resume, NULL)
5130d75f508SWesley Cheng };
5140d75f508SWesley Cheng 
qcom_snps_hsphy_override_param_update_val(const struct override_param_map map,s32 dt_val,struct phy_override_seq * seq_entry)515df2217ffSKrishna Kurapati static void qcom_snps_hsphy_override_param_update_val(
516df2217ffSKrishna Kurapati 			const struct override_param_map map,
517df2217ffSKrishna Kurapati 			s32 dt_val, struct phy_override_seq *seq_entry)
518df2217ffSKrishna Kurapati {
519df2217ffSKrishna Kurapati 	int i;
520df2217ffSKrishna Kurapati 
521df2217ffSKrishna Kurapati 	/*
522df2217ffSKrishna Kurapati 	 * Param table for each param is in increasing order
523df2217ffSKrishna Kurapati 	 * of dt values. We need to iterate over the list to
524df2217ffSKrishna Kurapati 	 * select the entry that matches the dt value and pick
525df2217ffSKrishna Kurapati 	 * up the corresponding register value.
526df2217ffSKrishna Kurapati 	 */
527df2217ffSKrishna Kurapati 	for (i = 0; i < map.table_size - 1; i++) {
528df2217ffSKrishna Kurapati 		if (map.param_table[i].value == dt_val)
529df2217ffSKrishna Kurapati 			break;
530df2217ffSKrishna Kurapati 	}
531df2217ffSKrishna Kurapati 
532df2217ffSKrishna Kurapati 	seq_entry->need_update = true;
533df2217ffSKrishna Kurapati 	seq_entry->offset = map.reg_offset;
534df2217ffSKrishna Kurapati 	seq_entry->mask = map.param_mask;
535df2217ffSKrishna Kurapati 	seq_entry->value = map.param_table[i].reg_val << __ffs(map.param_mask);
536df2217ffSKrishna Kurapati }
537df2217ffSKrishna Kurapati 
qcom_snps_hsphy_read_override_param_seq(struct device * dev)538df2217ffSKrishna Kurapati static void qcom_snps_hsphy_read_override_param_seq(struct device *dev)
539df2217ffSKrishna Kurapati {
540df2217ffSKrishna Kurapati 	struct device_node *node = dev->of_node;
541df2217ffSKrishna Kurapati 	s32 val;
542df2217ffSKrishna Kurapati 	int ret, i;
543df2217ffSKrishna Kurapati 	struct qcom_snps_hsphy *hsphy;
544df2217ffSKrishna Kurapati 	const struct override_param_map *cfg = of_device_get_match_data(dev);
545df2217ffSKrishna Kurapati 
546df2217ffSKrishna Kurapati 	if (!cfg)
547df2217ffSKrishna Kurapati 		return;
548df2217ffSKrishna Kurapati 
549df2217ffSKrishna Kurapati 	hsphy = dev_get_drvdata(dev);
550df2217ffSKrishna Kurapati 
551df2217ffSKrishna Kurapati 	for (i = 0; cfg[i].prop_name != NULL; i++) {
552df2217ffSKrishna Kurapati 		ret = of_property_read_s32(node, cfg[i].prop_name, &val);
553df2217ffSKrishna Kurapati 		if (ret)
554df2217ffSKrishna Kurapati 			continue;
555df2217ffSKrishna Kurapati 
556df2217ffSKrishna Kurapati 		qcom_snps_hsphy_override_param_update_val(cfg[i], val,
557df2217ffSKrishna Kurapati 					&hsphy->update_seq_cfg[i]);
558df2217ffSKrishna Kurapati 		dev_dbg(&hsphy->phy->dev, "Read param: %s dt_val: %d reg_val: 0x%x\n",
559df2217ffSKrishna Kurapati 			cfg[i].prop_name, val, hsphy->update_seq_cfg[i].value);
560df2217ffSKrishna Kurapati 
561df2217ffSKrishna Kurapati 	}
562df2217ffSKrishna Kurapati }
563df2217ffSKrishna Kurapati 
qcom_snps_hsphy_probe(struct platform_device * pdev)56451e8114fSWesley Cheng static int qcom_snps_hsphy_probe(struct platform_device *pdev)
56551e8114fSWesley Cheng {
56651e8114fSWesley Cheng 	struct device *dev = &pdev->dev;
56751e8114fSWesley Cheng 	struct qcom_snps_hsphy *hsphy;
56851e8114fSWesley Cheng 	struct phy_provider *phy_provider;
56951e8114fSWesley Cheng 	struct phy *generic_phy;
57051e8114fSWesley Cheng 	int ret, i;
57151e8114fSWesley Cheng 	int num;
57251e8114fSWesley Cheng 
57351e8114fSWesley Cheng 	hsphy = devm_kzalloc(dev, sizeof(*hsphy), GFP_KERNEL);
57451e8114fSWesley Cheng 	if (!hsphy)
57551e8114fSWesley Cheng 		return -ENOMEM;
57651e8114fSWesley Cheng 
5778a0eb8f9SAdrien Thierry 	hsphy->dev = dev;
5788a0eb8f9SAdrien Thierry 
57951e8114fSWesley Cheng 	hsphy->base = devm_platform_ioremap_resource(pdev, 0);
58051e8114fSWesley Cheng 	if (IS_ERR(hsphy->base))
58151e8114fSWesley Cheng 		return PTR_ERR(hsphy->base);
58251e8114fSWesley Cheng 
5838a0eb8f9SAdrien Thierry 	ret = qcom_snps_hsphy_clk_init(hsphy);
5848a0eb8f9SAdrien Thierry 	if (ret)
5858a0eb8f9SAdrien Thierry 		return dev_err_probe(dev, ret, "failed to initialize clocks\n");
58651e8114fSWesley Cheng 
58751e8114fSWesley Cheng 	hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
58851e8114fSWesley Cheng 	if (IS_ERR(hsphy->phy_reset)) {
58951e8114fSWesley Cheng 		dev_err(dev, "failed to get phy core reset\n");
59051e8114fSWesley Cheng 		return PTR_ERR(hsphy->phy_reset);
59151e8114fSWesley Cheng 	}
59251e8114fSWesley Cheng 
59351e8114fSWesley Cheng 	num = ARRAY_SIZE(hsphy->vregs);
59451e8114fSWesley Cheng 	for (i = 0; i < num; i++)
59551e8114fSWesley Cheng 		hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i];
59651e8114fSWesley Cheng 
59751e8114fSWesley Cheng 	ret = devm_regulator_bulk_get(dev, num, hsphy->vregs);
598668dc8afSYuan Can 	if (ret)
599668dc8afSYuan Can 		return dev_err_probe(dev, ret,
600668dc8afSYuan Can 				     "failed to get regulator supplies\n");
60151e8114fSWesley Cheng 
6020d75f508SWesley Cheng 	pm_runtime_set_active(dev);
6030d75f508SWesley Cheng 	pm_runtime_enable(dev);
6040d75f508SWesley Cheng 	/*
6050d75f508SWesley Cheng 	 * Prevent runtime pm from being ON by default. Users can enable
6060d75f508SWesley Cheng 	 * it using power/control in sysfs.
6070d75f508SWesley Cheng 	 */
6080d75f508SWesley Cheng 	pm_runtime_forbid(dev);
6090d75f508SWesley Cheng 
61051e8114fSWesley Cheng 	generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
61151e8114fSWesley Cheng 	if (IS_ERR(generic_phy)) {
61251e8114fSWesley Cheng 		ret = PTR_ERR(generic_phy);
61351e8114fSWesley Cheng 		dev_err(dev, "failed to create phy, %d\n", ret);
61451e8114fSWesley Cheng 		return ret;
61551e8114fSWesley Cheng 	}
61651e8114fSWesley Cheng 	hsphy->phy = generic_phy;
61751e8114fSWesley Cheng 
61851e8114fSWesley Cheng 	dev_set_drvdata(dev, hsphy);
61951e8114fSWesley Cheng 	phy_set_drvdata(generic_phy, hsphy);
620df2217ffSKrishna Kurapati 	qcom_snps_hsphy_read_override_param_seq(dev);
62151e8114fSWesley Cheng 
62251e8114fSWesley Cheng 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
62351e8114fSWesley Cheng 	if (!IS_ERR(phy_provider))
62451e8114fSWesley Cheng 		dev_dbg(dev, "Registered Qcom-SNPS HS phy\n");
6250d75f508SWesley Cheng 	else
6260d75f508SWesley Cheng 		pm_runtime_disable(dev);
62751e8114fSWesley Cheng 
62851e8114fSWesley Cheng 	return PTR_ERR_OR_ZERO(phy_provider);
62951e8114fSWesley Cheng }
63051e8114fSWesley Cheng 
63151e8114fSWesley Cheng static struct platform_driver qcom_snps_hsphy_driver = {
63251e8114fSWesley Cheng 	.probe		= qcom_snps_hsphy_probe,
63351e8114fSWesley Cheng 	.driver = {
63451e8114fSWesley Cheng 		.name	= "qcom-snps-hs-femto-v2-phy",
6350d75f508SWesley Cheng 		.pm = &qcom_snps_hsphy_pm_ops,
63651e8114fSWesley Cheng 		.of_match_table = qcom_snps_hsphy_of_match_table,
63751e8114fSWesley Cheng 	},
63851e8114fSWesley Cheng };
63951e8114fSWesley Cheng 
64051e8114fSWesley Cheng module_platform_driver(qcom_snps_hsphy_driver);
64151e8114fSWesley Cheng 
64251e8114fSWesley Cheng MODULE_DESCRIPTION("Qualcomm SNPS FEMTO USB HS PHY V2 driver");
64351e8114fSWesley Cheng MODULE_LICENSE("GPL v2");
644