xref: /OK3568_Linux_fs/kernel/drivers/phy/qualcomm/phy-qcom-snps-femto-v2.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (c) 2020, The Linux Foundation. All rights reserved.
4*4882a593Smuzhiyun  */
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun #include <linux/clk.h>
7*4882a593Smuzhiyun #include <linux/delay.h>
8*4882a593Smuzhiyun #include <linux/err.h>
9*4882a593Smuzhiyun #include <linux/io.h>
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/module.h>
12*4882a593Smuzhiyun #include <linux/of.h>
13*4882a593Smuzhiyun #include <linux/of_device.h>
14*4882a593Smuzhiyun #include <linux/phy/phy.h>
15*4882a593Smuzhiyun #include <linux/platform_device.h>
16*4882a593Smuzhiyun #include <linux/regmap.h>
17*4882a593Smuzhiyun #include <linux/regulator/consumer.h>
18*4882a593Smuzhiyun #include <linux/reset.h>
19*4882a593Smuzhiyun #include <linux/slab.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_UTMI_CTRL0		(0x3c)
22*4882a593Smuzhiyun #define SLEEPM					BIT(0)
23*4882a593Smuzhiyun #define OPMODE_MASK				GENMASK(4, 3)
24*4882a593Smuzhiyun #define OPMODE_NORMAL				(0x00)
25*4882a593Smuzhiyun #define OPMODE_NONDRIVING			BIT(3)
26*4882a593Smuzhiyun #define TERMSEL					BIT(5)
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_UTMI_CTRL1		(0x40)
29*4882a593Smuzhiyun #define XCVRSEL					BIT(0)
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_UTMI_CTRL5		(0x50)
32*4882a593Smuzhiyun #define POR					BIT(1)
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0	(0x54)
35*4882a593Smuzhiyun #define RETENABLEN				BIT(3)
36*4882a593Smuzhiyun #define FSEL_MASK				GENMASK(6, 4)
37*4882a593Smuzhiyun #define FSEL_DEFAULT				(0x3 << 4)
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1	(0x58)
40*4882a593Smuzhiyun #define VBUSVLDEXTSEL0				BIT(4)
41*4882a593Smuzhiyun #define PLLBTUNE				BIT(5)
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2	(0x5c)
44*4882a593Smuzhiyun #define VREGBYPASS				BIT(0)
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_HS_PHY_CTRL1		(0x60)
47*4882a593Smuzhiyun #define VBUSVLDEXT0				BIT(0)
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_HS_PHY_CTRL2		(0x64)
50*4882a593Smuzhiyun #define USB2_AUTO_RESUME			BIT(0)
51*4882a593Smuzhiyun #define USB2_SUSPEND_N				BIT(2)
52*4882a593Smuzhiyun #define USB2_SUSPEND_N_SEL			BIT(3)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_CFG0			(0x94)
55*4882a593Smuzhiyun #define UTMI_PHY_DATAPATH_CTRL_OVERRIDE_EN	BIT(0)
56*4882a593Smuzhiyun #define UTMI_PHY_CMN_CTRL_OVERRIDE_EN		BIT(1)
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define USB2_PHY_USB_PHY_REFCLK_CTRL		(0xa0)
59*4882a593Smuzhiyun #define REFCLK_SEL_MASK				GENMASK(1, 0)
60*4882a593Smuzhiyun #define REFCLK_SEL_DEFAULT			(0x2 << 0)
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun static const char * const qcom_snps_hsphy_vreg_names[] = {
63*4882a593Smuzhiyun 	"vdda-pll", "vdda33", "vdda18",
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define SNPS_HS_NUM_VREGS		ARRAY_SIZE(qcom_snps_hsphy_vreg_names)
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /**
69*4882a593Smuzhiyun  * struct qcom_snps_hsphy - snps hs phy attributes
70*4882a593Smuzhiyun  *
71*4882a593Smuzhiyun  * @phy: generic phy
72*4882a593Smuzhiyun  * @base: iomapped memory space for snps hs phy
73*4882a593Smuzhiyun  *
74*4882a593Smuzhiyun  * @cfg_ahb_clk: AHB2PHY interface clock
75*4882a593Smuzhiyun  * @ref_clk: phy reference clock
76*4882a593Smuzhiyun  * @iface_clk: phy interface clock
77*4882a593Smuzhiyun  * @phy_reset: phy reset control
78*4882a593Smuzhiyun  * @vregs: regulator supplies bulk data
79*4882a593Smuzhiyun  * @phy_initialized: if PHY has been initialized correctly
80*4882a593Smuzhiyun  * @mode: contains the current mode the PHY is in
81*4882a593Smuzhiyun  */
82*4882a593Smuzhiyun struct qcom_snps_hsphy {
83*4882a593Smuzhiyun 	struct phy *phy;
84*4882a593Smuzhiyun 	void __iomem *base;
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 	struct clk *cfg_ahb_clk;
87*4882a593Smuzhiyun 	struct clk *ref_clk;
88*4882a593Smuzhiyun 	struct reset_control *phy_reset;
89*4882a593Smuzhiyun 	struct regulator_bulk_data vregs[SNPS_HS_NUM_VREGS];
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun 	bool phy_initialized;
92*4882a593Smuzhiyun 	enum phy_mode mode;
93*4882a593Smuzhiyun };
94*4882a593Smuzhiyun 
qcom_snps_hsphy_write_mask(void __iomem * base,u32 offset,u32 mask,u32 val)95*4882a593Smuzhiyun static inline void qcom_snps_hsphy_write_mask(void __iomem *base, u32 offset,
96*4882a593Smuzhiyun 						u32 mask, u32 val)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun 	u32 reg;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	reg = readl_relaxed(base + offset);
101*4882a593Smuzhiyun 	reg &= ~mask;
102*4882a593Smuzhiyun 	reg |= val & mask;
103*4882a593Smuzhiyun 	writel_relaxed(reg, base + offset);
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* Ensure above write is completed */
106*4882a593Smuzhiyun 	readl_relaxed(base + offset);
107*4882a593Smuzhiyun }
108*4882a593Smuzhiyun 
qcom_snps_hsphy_suspend(struct qcom_snps_hsphy * hsphy)109*4882a593Smuzhiyun static int qcom_snps_hsphy_suspend(struct qcom_snps_hsphy *hsphy)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun 	dev_dbg(&hsphy->phy->dev, "Suspend QCOM SNPS PHY\n");
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	if (hsphy->mode == PHY_MODE_USB_HOST) {
114*4882a593Smuzhiyun 		/* Enable auto-resume to meet remote wakeup timing */
115*4882a593Smuzhiyun 		qcom_snps_hsphy_write_mask(hsphy->base,
116*4882a593Smuzhiyun 					   USB2_PHY_USB_PHY_HS_PHY_CTRL2,
117*4882a593Smuzhiyun 					   USB2_AUTO_RESUME,
118*4882a593Smuzhiyun 					   USB2_AUTO_RESUME);
119*4882a593Smuzhiyun 		usleep_range(500, 1000);
120*4882a593Smuzhiyun 		qcom_snps_hsphy_write_mask(hsphy->base,
121*4882a593Smuzhiyun 					   USB2_PHY_USB_PHY_HS_PHY_CTRL2,
122*4882a593Smuzhiyun 					   0, USB2_AUTO_RESUME);
123*4882a593Smuzhiyun 	}
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
126*4882a593Smuzhiyun 	return 0;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun 
qcom_snps_hsphy_resume(struct qcom_snps_hsphy * hsphy)129*4882a593Smuzhiyun static int qcom_snps_hsphy_resume(struct qcom_snps_hsphy *hsphy)
130*4882a593Smuzhiyun {
131*4882a593Smuzhiyun 	int ret;
132*4882a593Smuzhiyun 
133*4882a593Smuzhiyun 	dev_dbg(&hsphy->phy->dev, "Resume QCOM SNPS PHY, mode\n");
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
136*4882a593Smuzhiyun 	if (ret) {
137*4882a593Smuzhiyun 		dev_err(&hsphy->phy->dev, "failed to enable cfg ahb clock\n");
138*4882a593Smuzhiyun 		return ret;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun 
qcom_snps_hsphy_runtime_suspend(struct device * dev)144*4882a593Smuzhiyun static int __maybe_unused qcom_snps_hsphy_runtime_suspend(struct device *dev)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	if (!hsphy->phy_initialized)
149*4882a593Smuzhiyun 		return 0;
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	qcom_snps_hsphy_suspend(hsphy);
152*4882a593Smuzhiyun 	return 0;
153*4882a593Smuzhiyun }
154*4882a593Smuzhiyun 
qcom_snps_hsphy_runtime_resume(struct device * dev)155*4882a593Smuzhiyun static int __maybe_unused qcom_snps_hsphy_runtime_resume(struct device *dev)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun 	struct qcom_snps_hsphy *hsphy = dev_get_drvdata(dev);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	if (!hsphy->phy_initialized)
160*4882a593Smuzhiyun 		return 0;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	qcom_snps_hsphy_resume(hsphy);
163*4882a593Smuzhiyun 	return 0;
164*4882a593Smuzhiyun }
165*4882a593Smuzhiyun 
qcom_snps_hsphy_set_mode(struct phy * phy,enum phy_mode mode,int submode)166*4882a593Smuzhiyun static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
167*4882a593Smuzhiyun 				    int submode)
168*4882a593Smuzhiyun {
169*4882a593Smuzhiyun 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	hsphy->mode = mode;
172*4882a593Smuzhiyun 	return 0;
173*4882a593Smuzhiyun }
174*4882a593Smuzhiyun 
qcom_snps_hsphy_init(struct phy * phy)175*4882a593Smuzhiyun static int qcom_snps_hsphy_init(struct phy *phy)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
178*4882a593Smuzhiyun 	int ret;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	dev_vdbg(&phy->dev, "%s(): Initializing SNPS HS phy\n", __func__);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	ret = regulator_bulk_enable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
183*4882a593Smuzhiyun 	if (ret)
184*4882a593Smuzhiyun 		return ret;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	ret = clk_prepare_enable(hsphy->cfg_ahb_clk);
187*4882a593Smuzhiyun 	if (ret) {
188*4882a593Smuzhiyun 		dev_err(&phy->dev, "failed to enable cfg ahb clock, %d\n", ret);
189*4882a593Smuzhiyun 		goto poweroff_phy;
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 
192*4882a593Smuzhiyun 	ret = reset_control_assert(hsphy->phy_reset);
193*4882a593Smuzhiyun 	if (ret) {
194*4882a593Smuzhiyun 		dev_err(&phy->dev, "failed to assert phy_reset, %d\n", ret);
195*4882a593Smuzhiyun 		goto disable_ahb_clk;
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	usleep_range(100, 150);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	ret = reset_control_deassert(hsphy->phy_reset);
201*4882a593Smuzhiyun 	if (ret) {
202*4882a593Smuzhiyun 		dev_err(&phy->dev, "failed to de-assert phy_reset, %d\n", ret);
203*4882a593Smuzhiyun 		goto disable_ahb_clk;
204*4882a593Smuzhiyun 	}
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
207*4882a593Smuzhiyun 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN,
208*4882a593Smuzhiyun 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN);
209*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
210*4882a593Smuzhiyun 							POR, POR);
211*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base,
212*4882a593Smuzhiyun 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON0,
213*4882a593Smuzhiyun 					FSEL_MASK, 0);
214*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base,
215*4882a593Smuzhiyun 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
216*4882a593Smuzhiyun 					PLLBTUNE, PLLBTUNE);
217*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_REFCLK_CTRL,
218*4882a593Smuzhiyun 					REFCLK_SEL_DEFAULT, REFCLK_SEL_MASK);
219*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base,
220*4882a593Smuzhiyun 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON1,
221*4882a593Smuzhiyun 					VBUSVLDEXTSEL0, VBUSVLDEXTSEL0);
222*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL1,
223*4882a593Smuzhiyun 					VBUSVLDEXT0, VBUSVLDEXT0);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base,
226*4882a593Smuzhiyun 					USB2_PHY_USB_PHY_HS_PHY_CTRL_COMMON2,
227*4882a593Smuzhiyun 					VREGBYPASS, VREGBYPASS);
228*4882a593Smuzhiyun 
229*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
230*4882a593Smuzhiyun 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N,
231*4882a593Smuzhiyun 					USB2_SUSPEND_N_SEL | USB2_SUSPEND_N);
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL0,
234*4882a593Smuzhiyun 					SLEEPM, SLEEPM);
235*4882a593Smuzhiyun 
236*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_UTMI_CTRL5,
237*4882a593Smuzhiyun 					POR, 0);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_HS_PHY_CTRL2,
240*4882a593Smuzhiyun 					USB2_SUSPEND_N_SEL, 0);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	qcom_snps_hsphy_write_mask(hsphy->base, USB2_PHY_USB_PHY_CFG0,
243*4882a593Smuzhiyun 					UTMI_PHY_CMN_CTRL_OVERRIDE_EN, 0);
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	hsphy->phy_initialized = true;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	return 0;
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun disable_ahb_clk:
250*4882a593Smuzhiyun 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
251*4882a593Smuzhiyun poweroff_phy:
252*4882a593Smuzhiyun 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	return ret;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun 
qcom_snps_hsphy_exit(struct phy * phy)257*4882a593Smuzhiyun static int qcom_snps_hsphy_exit(struct phy *phy)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	struct qcom_snps_hsphy *hsphy = phy_get_drvdata(phy);
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	reset_control_assert(hsphy->phy_reset);
262*4882a593Smuzhiyun 	clk_disable_unprepare(hsphy->cfg_ahb_clk);
263*4882a593Smuzhiyun 	regulator_bulk_disable(ARRAY_SIZE(hsphy->vregs), hsphy->vregs);
264*4882a593Smuzhiyun 	hsphy->phy_initialized = false;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return 0;
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun static const struct phy_ops qcom_snps_hsphy_gen_ops = {
270*4882a593Smuzhiyun 	.init		= qcom_snps_hsphy_init,
271*4882a593Smuzhiyun 	.exit		= qcom_snps_hsphy_exit,
272*4882a593Smuzhiyun 	.set_mode	= qcom_snps_hsphy_set_mode,
273*4882a593Smuzhiyun 	.owner		= THIS_MODULE,
274*4882a593Smuzhiyun };
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun static const struct of_device_id qcom_snps_hsphy_of_match_table[] = {
277*4882a593Smuzhiyun 	{ .compatible	= "qcom,sm8150-usb-hs-phy", },
278*4882a593Smuzhiyun 	{ .compatible	= "qcom,usb-snps-hs-7nm-phy", },
279*4882a593Smuzhiyun 	{ .compatible	= "qcom,usb-snps-femto-v2-phy",	},
280*4882a593Smuzhiyun 	{ }
281*4882a593Smuzhiyun };
282*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_of_match_table);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun static const struct dev_pm_ops qcom_snps_hsphy_pm_ops = {
285*4882a593Smuzhiyun 	SET_RUNTIME_PM_OPS(qcom_snps_hsphy_runtime_suspend,
286*4882a593Smuzhiyun 			   qcom_snps_hsphy_runtime_resume, NULL)
287*4882a593Smuzhiyun };
288*4882a593Smuzhiyun 
qcom_snps_hsphy_probe(struct platform_device * pdev)289*4882a593Smuzhiyun static int qcom_snps_hsphy_probe(struct platform_device *pdev)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun 	struct device *dev = &pdev->dev;
292*4882a593Smuzhiyun 	struct qcom_snps_hsphy *hsphy;
293*4882a593Smuzhiyun 	struct phy_provider *phy_provider;
294*4882a593Smuzhiyun 	struct phy *generic_phy;
295*4882a593Smuzhiyun 	int ret, i;
296*4882a593Smuzhiyun 	int num;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	hsphy = devm_kzalloc(dev, sizeof(*hsphy), GFP_KERNEL);
299*4882a593Smuzhiyun 	if (!hsphy)
300*4882a593Smuzhiyun 		return -ENOMEM;
301*4882a593Smuzhiyun 
302*4882a593Smuzhiyun 	hsphy->base = devm_platform_ioremap_resource(pdev, 0);
303*4882a593Smuzhiyun 	if (IS_ERR(hsphy->base))
304*4882a593Smuzhiyun 		return PTR_ERR(hsphy->base);
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 	hsphy->ref_clk = devm_clk_get(dev, "ref");
307*4882a593Smuzhiyun 	if (IS_ERR(hsphy->ref_clk)) {
308*4882a593Smuzhiyun 		ret = PTR_ERR(hsphy->ref_clk);
309*4882a593Smuzhiyun 		if (ret != -EPROBE_DEFER)
310*4882a593Smuzhiyun 			dev_err(dev, "failed to get ref clk, %d\n", ret);
311*4882a593Smuzhiyun 		return ret;
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	hsphy->phy_reset = devm_reset_control_get_exclusive(&pdev->dev, NULL);
315*4882a593Smuzhiyun 	if (IS_ERR(hsphy->phy_reset)) {
316*4882a593Smuzhiyun 		dev_err(dev, "failed to get phy core reset\n");
317*4882a593Smuzhiyun 		return PTR_ERR(hsphy->phy_reset);
318*4882a593Smuzhiyun 	}
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	num = ARRAY_SIZE(hsphy->vregs);
321*4882a593Smuzhiyun 	for (i = 0; i < num; i++)
322*4882a593Smuzhiyun 		hsphy->vregs[i].supply = qcom_snps_hsphy_vreg_names[i];
323*4882a593Smuzhiyun 
324*4882a593Smuzhiyun 	ret = devm_regulator_bulk_get(dev, num, hsphy->vregs);
325*4882a593Smuzhiyun 	if (ret) {
326*4882a593Smuzhiyun 		if (ret != -EPROBE_DEFER)
327*4882a593Smuzhiyun 			dev_err(dev, "failed to get regulator supplies: %d\n",
328*4882a593Smuzhiyun 				ret);
329*4882a593Smuzhiyun 		return ret;
330*4882a593Smuzhiyun 	}
331*4882a593Smuzhiyun 
332*4882a593Smuzhiyun 	pm_runtime_set_active(dev);
333*4882a593Smuzhiyun 	pm_runtime_enable(dev);
334*4882a593Smuzhiyun 	/*
335*4882a593Smuzhiyun 	 * Prevent runtime pm from being ON by default. Users can enable
336*4882a593Smuzhiyun 	 * it using power/control in sysfs.
337*4882a593Smuzhiyun 	 */
338*4882a593Smuzhiyun 	pm_runtime_forbid(dev);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	generic_phy = devm_phy_create(dev, NULL, &qcom_snps_hsphy_gen_ops);
341*4882a593Smuzhiyun 	if (IS_ERR(generic_phy)) {
342*4882a593Smuzhiyun 		ret = PTR_ERR(generic_phy);
343*4882a593Smuzhiyun 		dev_err(dev, "failed to create phy, %d\n", ret);
344*4882a593Smuzhiyun 		return ret;
345*4882a593Smuzhiyun 	}
346*4882a593Smuzhiyun 	hsphy->phy = generic_phy;
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun 	dev_set_drvdata(dev, hsphy);
349*4882a593Smuzhiyun 	phy_set_drvdata(generic_phy, hsphy);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
352*4882a593Smuzhiyun 	if (!IS_ERR(phy_provider))
353*4882a593Smuzhiyun 		dev_dbg(dev, "Registered Qcom-SNPS HS phy\n");
354*4882a593Smuzhiyun 	else
355*4882a593Smuzhiyun 		pm_runtime_disable(dev);
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	return PTR_ERR_OR_ZERO(phy_provider);
358*4882a593Smuzhiyun }
359*4882a593Smuzhiyun 
360*4882a593Smuzhiyun static struct platform_driver qcom_snps_hsphy_driver = {
361*4882a593Smuzhiyun 	.probe		= qcom_snps_hsphy_probe,
362*4882a593Smuzhiyun 	.driver = {
363*4882a593Smuzhiyun 		.name	= "qcom-snps-hs-femto-v2-phy",
364*4882a593Smuzhiyun 		.pm = &qcom_snps_hsphy_pm_ops,
365*4882a593Smuzhiyun 		.of_match_table = qcom_snps_hsphy_of_match_table,
366*4882a593Smuzhiyun 	},
367*4882a593Smuzhiyun };
368*4882a593Smuzhiyun 
369*4882a593Smuzhiyun module_platform_driver(qcom_snps_hsphy_driver);
370*4882a593Smuzhiyun 
371*4882a593Smuzhiyun MODULE_DESCRIPTION("Qualcomm SNPS FEMTO USB HS PHY V2 driver");
372*4882a593Smuzhiyun MODULE_LICENSE("GPL v2");
373