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