xref: /linux/drivers/phy/qualcomm/phy-qcom-usb-hs-28nm.c (revision 67b27dbeac4dc86d8f09789861bc8eda6f3538c4)
1*67b27dbeSShawn Guo // SPDX-License-Identifier: GPL-2.0
2*67b27dbeSShawn Guo /*
3*67b27dbeSShawn Guo  * Copyright (c) 2009-2018, Linux Foundation. All rights reserved.
4*67b27dbeSShawn Guo  * Copyright (c) 2018-2020, Linaro Limited
5*67b27dbeSShawn Guo  */
6*67b27dbeSShawn Guo 
7*67b27dbeSShawn Guo #include <linux/clk.h>
8*67b27dbeSShawn Guo #include <linux/delay.h>
9*67b27dbeSShawn Guo #include <linux/io.h>
10*67b27dbeSShawn Guo #include <linux/kernel.h>
11*67b27dbeSShawn Guo #include <linux/module.h>
12*67b27dbeSShawn Guo #include <linux/of.h>
13*67b27dbeSShawn Guo #include <linux/of_graph.h>
14*67b27dbeSShawn Guo #include <linux/phy/phy.h>
15*67b27dbeSShawn Guo #include <linux/platform_device.h>
16*67b27dbeSShawn Guo #include <linux/regulator/consumer.h>
17*67b27dbeSShawn Guo #include <linux/reset.h>
18*67b27dbeSShawn Guo #include <linux/slab.h>
19*67b27dbeSShawn Guo 
20*67b27dbeSShawn Guo /* PHY register and bit definitions */
21*67b27dbeSShawn Guo #define PHY_CTRL_COMMON0		0x078
22*67b27dbeSShawn Guo #define SIDDQ				BIT(2)
23*67b27dbeSShawn Guo #define PHY_IRQ_CMD			0x0d0
24*67b27dbeSShawn Guo #define PHY_INTR_MASK0			0x0d4
25*67b27dbeSShawn Guo #define PHY_INTR_CLEAR0			0x0dc
26*67b27dbeSShawn Guo #define DPDM_MASK			0x1e
27*67b27dbeSShawn Guo #define DP_1_0				BIT(4)
28*67b27dbeSShawn Guo #define DP_0_1				BIT(3)
29*67b27dbeSShawn Guo #define DM_1_0				BIT(2)
30*67b27dbeSShawn Guo #define DM_0_1				BIT(1)
31*67b27dbeSShawn Guo 
32*67b27dbeSShawn Guo enum hsphy_voltage {
33*67b27dbeSShawn Guo 	VOL_NONE,
34*67b27dbeSShawn Guo 	VOL_MIN,
35*67b27dbeSShawn Guo 	VOL_MAX,
36*67b27dbeSShawn Guo 	VOL_NUM,
37*67b27dbeSShawn Guo };
38*67b27dbeSShawn Guo 
39*67b27dbeSShawn Guo enum hsphy_vreg {
40*67b27dbeSShawn Guo 	VDD,
41*67b27dbeSShawn Guo 	VDDA_1P8,
42*67b27dbeSShawn Guo 	VDDA_3P3,
43*67b27dbeSShawn Guo 	VREG_NUM,
44*67b27dbeSShawn Guo };
45*67b27dbeSShawn Guo 
46*67b27dbeSShawn Guo struct hsphy_init_seq {
47*67b27dbeSShawn Guo 	int offset;
48*67b27dbeSShawn Guo 	int val;
49*67b27dbeSShawn Guo 	int delay;
50*67b27dbeSShawn Guo };
51*67b27dbeSShawn Guo 
52*67b27dbeSShawn Guo struct hsphy_data {
53*67b27dbeSShawn Guo 	const struct hsphy_init_seq *init_seq;
54*67b27dbeSShawn Guo 	unsigned int init_seq_num;
55*67b27dbeSShawn Guo };
56*67b27dbeSShawn Guo 
57*67b27dbeSShawn Guo struct hsphy_priv {
58*67b27dbeSShawn Guo 	void __iomem *base;
59*67b27dbeSShawn Guo 	struct clk_bulk_data *clks;
60*67b27dbeSShawn Guo 	int num_clks;
61*67b27dbeSShawn Guo 	struct reset_control *phy_reset;
62*67b27dbeSShawn Guo 	struct reset_control *por_reset;
63*67b27dbeSShawn Guo 	struct regulator_bulk_data vregs[VREG_NUM];
64*67b27dbeSShawn Guo 	const struct hsphy_data *data;
65*67b27dbeSShawn Guo 	enum phy_mode mode;
66*67b27dbeSShawn Guo };
67*67b27dbeSShawn Guo 
68*67b27dbeSShawn Guo static int qcom_snps_hsphy_set_mode(struct phy *phy, enum phy_mode mode,
69*67b27dbeSShawn Guo 				    int submode)
70*67b27dbeSShawn Guo {
71*67b27dbeSShawn Guo 	struct hsphy_priv *priv = phy_get_drvdata(phy);
72*67b27dbeSShawn Guo 
73*67b27dbeSShawn Guo 	priv->mode = PHY_MODE_INVALID;
74*67b27dbeSShawn Guo 
75*67b27dbeSShawn Guo 	if (mode > 0)
76*67b27dbeSShawn Guo 		priv->mode = mode;
77*67b27dbeSShawn Guo 
78*67b27dbeSShawn Guo 	return 0;
79*67b27dbeSShawn Guo }
80*67b27dbeSShawn Guo 
81*67b27dbeSShawn Guo static void qcom_snps_hsphy_enable_hv_interrupts(struct hsphy_priv *priv)
82*67b27dbeSShawn Guo {
83*67b27dbeSShawn Guo 	u32 val;
84*67b27dbeSShawn Guo 
85*67b27dbeSShawn Guo 	/* Clear any existing interrupts before enabling the interrupts */
86*67b27dbeSShawn Guo 	val = readb(priv->base + PHY_INTR_CLEAR0);
87*67b27dbeSShawn Guo 	val |= DPDM_MASK;
88*67b27dbeSShawn Guo 	writeb(val, priv->base + PHY_INTR_CLEAR0);
89*67b27dbeSShawn Guo 
90*67b27dbeSShawn Guo 	writeb(0x0, priv->base + PHY_IRQ_CMD);
91*67b27dbeSShawn Guo 	usleep_range(200, 220);
92*67b27dbeSShawn Guo 	writeb(0x1, priv->base + PHY_IRQ_CMD);
93*67b27dbeSShawn Guo 
94*67b27dbeSShawn Guo 	/* Make sure the interrupts are cleared */
95*67b27dbeSShawn Guo 	usleep_range(200, 220);
96*67b27dbeSShawn Guo 
97*67b27dbeSShawn Guo 	val = readb(priv->base + PHY_INTR_MASK0);
98*67b27dbeSShawn Guo 	switch (priv->mode) {
99*67b27dbeSShawn Guo 	case PHY_MODE_USB_HOST_HS:
100*67b27dbeSShawn Guo 	case PHY_MODE_USB_HOST_FS:
101*67b27dbeSShawn Guo 	case PHY_MODE_USB_DEVICE_HS:
102*67b27dbeSShawn Guo 	case PHY_MODE_USB_DEVICE_FS:
103*67b27dbeSShawn Guo 		val |= DP_1_0 | DM_0_1;
104*67b27dbeSShawn Guo 		break;
105*67b27dbeSShawn Guo 	case PHY_MODE_USB_HOST_LS:
106*67b27dbeSShawn Guo 	case PHY_MODE_USB_DEVICE_LS:
107*67b27dbeSShawn Guo 		val |= DP_0_1 | DM_1_0;
108*67b27dbeSShawn Guo 		break;
109*67b27dbeSShawn Guo 	default:
110*67b27dbeSShawn Guo 		/* No device connected */
111*67b27dbeSShawn Guo 		val |= DP_0_1 | DM_0_1;
112*67b27dbeSShawn Guo 		break;
113*67b27dbeSShawn Guo 	}
114*67b27dbeSShawn Guo 	writeb(val, priv->base + PHY_INTR_MASK0);
115*67b27dbeSShawn Guo }
116*67b27dbeSShawn Guo 
117*67b27dbeSShawn Guo static void qcom_snps_hsphy_disable_hv_interrupts(struct hsphy_priv *priv)
118*67b27dbeSShawn Guo {
119*67b27dbeSShawn Guo 	u32 val;
120*67b27dbeSShawn Guo 
121*67b27dbeSShawn Guo 	val = readb(priv->base + PHY_INTR_MASK0);
122*67b27dbeSShawn Guo 	val &= ~DPDM_MASK;
123*67b27dbeSShawn Guo 	writeb(val, priv->base + PHY_INTR_MASK0);
124*67b27dbeSShawn Guo 
125*67b27dbeSShawn Guo 	/* Clear any pending interrupts */
126*67b27dbeSShawn Guo 	val = readb(priv->base + PHY_INTR_CLEAR0);
127*67b27dbeSShawn Guo 	val |= DPDM_MASK;
128*67b27dbeSShawn Guo 	writeb(val, priv->base + PHY_INTR_CLEAR0);
129*67b27dbeSShawn Guo 
130*67b27dbeSShawn Guo 	writeb(0x0, priv->base + PHY_IRQ_CMD);
131*67b27dbeSShawn Guo 	usleep_range(200, 220);
132*67b27dbeSShawn Guo 
133*67b27dbeSShawn Guo 	writeb(0x1, priv->base + PHY_IRQ_CMD);
134*67b27dbeSShawn Guo 	usleep_range(200, 220);
135*67b27dbeSShawn Guo }
136*67b27dbeSShawn Guo 
137*67b27dbeSShawn Guo static void qcom_snps_hsphy_enter_retention(struct hsphy_priv *priv)
138*67b27dbeSShawn Guo {
139*67b27dbeSShawn Guo 	u32 val;
140*67b27dbeSShawn Guo 
141*67b27dbeSShawn Guo 	val = readb(priv->base + PHY_CTRL_COMMON0);
142*67b27dbeSShawn Guo 	val |= SIDDQ;
143*67b27dbeSShawn Guo 	writeb(val, priv->base + PHY_CTRL_COMMON0);
144*67b27dbeSShawn Guo }
145*67b27dbeSShawn Guo 
146*67b27dbeSShawn Guo static void qcom_snps_hsphy_exit_retention(struct hsphy_priv *priv)
147*67b27dbeSShawn Guo {
148*67b27dbeSShawn Guo 	u32 val;
149*67b27dbeSShawn Guo 
150*67b27dbeSShawn Guo 	val = readb(priv->base + PHY_CTRL_COMMON0);
151*67b27dbeSShawn Guo 	val &= ~SIDDQ;
152*67b27dbeSShawn Guo 	writeb(val, priv->base + PHY_CTRL_COMMON0);
153*67b27dbeSShawn Guo }
154*67b27dbeSShawn Guo 
155*67b27dbeSShawn Guo static int qcom_snps_hsphy_power_on(struct phy *phy)
156*67b27dbeSShawn Guo {
157*67b27dbeSShawn Guo 	struct hsphy_priv *priv = phy_get_drvdata(phy);
158*67b27dbeSShawn Guo 	int ret;
159*67b27dbeSShawn Guo 
160*67b27dbeSShawn Guo 	ret = regulator_bulk_enable(VREG_NUM, priv->vregs);
161*67b27dbeSShawn Guo 	if (ret)
162*67b27dbeSShawn Guo 		return ret;
163*67b27dbeSShawn Guo 	ret = clk_bulk_prepare_enable(priv->num_clks, priv->clks);
164*67b27dbeSShawn Guo 	if (ret)
165*67b27dbeSShawn Guo 		goto err_disable_regulator;
166*67b27dbeSShawn Guo 	qcom_snps_hsphy_disable_hv_interrupts(priv);
167*67b27dbeSShawn Guo 	qcom_snps_hsphy_exit_retention(priv);
168*67b27dbeSShawn Guo 
169*67b27dbeSShawn Guo 	return 0;
170*67b27dbeSShawn Guo 
171*67b27dbeSShawn Guo err_disable_regulator:
172*67b27dbeSShawn Guo 	regulator_bulk_disable(VREG_NUM, priv->vregs);
173*67b27dbeSShawn Guo 
174*67b27dbeSShawn Guo 	return ret;
175*67b27dbeSShawn Guo }
176*67b27dbeSShawn Guo 
177*67b27dbeSShawn Guo static int qcom_snps_hsphy_power_off(struct phy *phy)
178*67b27dbeSShawn Guo {
179*67b27dbeSShawn Guo 	struct hsphy_priv *priv = phy_get_drvdata(phy);
180*67b27dbeSShawn Guo 
181*67b27dbeSShawn Guo 	qcom_snps_hsphy_enter_retention(priv);
182*67b27dbeSShawn Guo 	qcom_snps_hsphy_enable_hv_interrupts(priv);
183*67b27dbeSShawn Guo 	clk_bulk_disable_unprepare(priv->num_clks, priv->clks);
184*67b27dbeSShawn Guo 	regulator_bulk_disable(VREG_NUM, priv->vregs);
185*67b27dbeSShawn Guo 
186*67b27dbeSShawn Guo 	return 0;
187*67b27dbeSShawn Guo }
188*67b27dbeSShawn Guo 
189*67b27dbeSShawn Guo static int qcom_snps_hsphy_reset(struct hsphy_priv *priv)
190*67b27dbeSShawn Guo {
191*67b27dbeSShawn Guo 	int ret;
192*67b27dbeSShawn Guo 
193*67b27dbeSShawn Guo 	ret = reset_control_assert(priv->phy_reset);
194*67b27dbeSShawn Guo 	if (ret)
195*67b27dbeSShawn Guo 		return ret;
196*67b27dbeSShawn Guo 
197*67b27dbeSShawn Guo 	usleep_range(10, 15);
198*67b27dbeSShawn Guo 
199*67b27dbeSShawn Guo 	ret = reset_control_deassert(priv->phy_reset);
200*67b27dbeSShawn Guo 	if (ret)
201*67b27dbeSShawn Guo 		return ret;
202*67b27dbeSShawn Guo 
203*67b27dbeSShawn Guo 	usleep_range(80, 100);
204*67b27dbeSShawn Guo 
205*67b27dbeSShawn Guo 	return 0;
206*67b27dbeSShawn Guo }
207*67b27dbeSShawn Guo 
208*67b27dbeSShawn Guo static void qcom_snps_hsphy_init_sequence(struct hsphy_priv *priv)
209*67b27dbeSShawn Guo {
210*67b27dbeSShawn Guo 	const struct hsphy_data *data = priv->data;
211*67b27dbeSShawn Guo 	const struct hsphy_init_seq *seq;
212*67b27dbeSShawn Guo 	int i;
213*67b27dbeSShawn Guo 
214*67b27dbeSShawn Guo 	/* Device match data is optional. */
215*67b27dbeSShawn Guo 	if (!data)
216*67b27dbeSShawn Guo 		return;
217*67b27dbeSShawn Guo 
218*67b27dbeSShawn Guo 	seq = data->init_seq;
219*67b27dbeSShawn Guo 
220*67b27dbeSShawn Guo 	for (i = 0; i < data->init_seq_num; i++, seq++) {
221*67b27dbeSShawn Guo 		writeb(seq->val, priv->base + seq->offset);
222*67b27dbeSShawn Guo 		if (seq->delay)
223*67b27dbeSShawn Guo 			usleep_range(seq->delay, seq->delay + 10);
224*67b27dbeSShawn Guo 	}
225*67b27dbeSShawn Guo }
226*67b27dbeSShawn Guo 
227*67b27dbeSShawn Guo static int qcom_snps_hsphy_por_reset(struct hsphy_priv *priv)
228*67b27dbeSShawn Guo {
229*67b27dbeSShawn Guo 	int ret;
230*67b27dbeSShawn Guo 
231*67b27dbeSShawn Guo 	ret = reset_control_assert(priv->por_reset);
232*67b27dbeSShawn Guo 	if (ret)
233*67b27dbeSShawn Guo 		return ret;
234*67b27dbeSShawn Guo 
235*67b27dbeSShawn Guo 	/*
236*67b27dbeSShawn Guo 	 * The Femto PHY is POR reset in the following scenarios.
237*67b27dbeSShawn Guo 	 *
238*67b27dbeSShawn Guo 	 * 1. After overriding the parameter registers.
239*67b27dbeSShawn Guo 	 * 2. Low power mode exit from PHY retention.
240*67b27dbeSShawn Guo 	 *
241*67b27dbeSShawn Guo 	 * Ensure that SIDDQ is cleared before bringing the PHY
242*67b27dbeSShawn Guo 	 * out of reset.
243*67b27dbeSShawn Guo 	 */
244*67b27dbeSShawn Guo 	qcom_snps_hsphy_exit_retention(priv);
245*67b27dbeSShawn Guo 
246*67b27dbeSShawn Guo 	/*
247*67b27dbeSShawn Guo 	 * As per databook, 10 usec delay is required between
248*67b27dbeSShawn Guo 	 * PHY POR assert and de-assert.
249*67b27dbeSShawn Guo 	 */
250*67b27dbeSShawn Guo 	usleep_range(10, 20);
251*67b27dbeSShawn Guo 	ret = reset_control_deassert(priv->por_reset);
252*67b27dbeSShawn Guo 	if (ret)
253*67b27dbeSShawn Guo 		return ret;
254*67b27dbeSShawn Guo 
255*67b27dbeSShawn Guo 	/*
256*67b27dbeSShawn Guo 	 * As per databook, it takes 75 usec for PHY to stabilize
257*67b27dbeSShawn Guo 	 * after the reset.
258*67b27dbeSShawn Guo 	 */
259*67b27dbeSShawn Guo 	usleep_range(80, 100);
260*67b27dbeSShawn Guo 
261*67b27dbeSShawn Guo 	return 0;
262*67b27dbeSShawn Guo }
263*67b27dbeSShawn Guo 
264*67b27dbeSShawn Guo static int qcom_snps_hsphy_init(struct phy *phy)
265*67b27dbeSShawn Guo {
266*67b27dbeSShawn Guo 	struct hsphy_priv *priv = phy_get_drvdata(phy);
267*67b27dbeSShawn Guo 	int ret;
268*67b27dbeSShawn Guo 
269*67b27dbeSShawn Guo 	ret = qcom_snps_hsphy_reset(priv);
270*67b27dbeSShawn Guo 	if (ret)
271*67b27dbeSShawn Guo 		return ret;
272*67b27dbeSShawn Guo 
273*67b27dbeSShawn Guo 	qcom_snps_hsphy_init_sequence(priv);
274*67b27dbeSShawn Guo 
275*67b27dbeSShawn Guo 	ret = qcom_snps_hsphy_por_reset(priv);
276*67b27dbeSShawn Guo 	if (ret)
277*67b27dbeSShawn Guo 		return ret;
278*67b27dbeSShawn Guo 
279*67b27dbeSShawn Guo 	return 0;
280*67b27dbeSShawn Guo }
281*67b27dbeSShawn Guo 
282*67b27dbeSShawn Guo static const struct phy_ops qcom_snps_hsphy_ops = {
283*67b27dbeSShawn Guo 	.init = qcom_snps_hsphy_init,
284*67b27dbeSShawn Guo 	.power_on = qcom_snps_hsphy_power_on,
285*67b27dbeSShawn Guo 	.power_off = qcom_snps_hsphy_power_off,
286*67b27dbeSShawn Guo 	.set_mode = qcom_snps_hsphy_set_mode,
287*67b27dbeSShawn Guo 	.owner = THIS_MODULE,
288*67b27dbeSShawn Guo };
289*67b27dbeSShawn Guo 
290*67b27dbeSShawn Guo static const char * const qcom_snps_hsphy_clks[] = {
291*67b27dbeSShawn Guo 	"ref",
292*67b27dbeSShawn Guo 	"ahb",
293*67b27dbeSShawn Guo 	"sleep",
294*67b27dbeSShawn Guo };
295*67b27dbeSShawn Guo 
296*67b27dbeSShawn Guo static int qcom_snps_hsphy_probe(struct platform_device *pdev)
297*67b27dbeSShawn Guo {
298*67b27dbeSShawn Guo 	struct device *dev = &pdev->dev;
299*67b27dbeSShawn Guo 	struct phy_provider *provider;
300*67b27dbeSShawn Guo 	struct hsphy_priv *priv;
301*67b27dbeSShawn Guo 	struct phy *phy;
302*67b27dbeSShawn Guo 	int ret;
303*67b27dbeSShawn Guo 	int i;
304*67b27dbeSShawn Guo 
305*67b27dbeSShawn Guo 	priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
306*67b27dbeSShawn Guo 	if (!priv)
307*67b27dbeSShawn Guo 		return -ENOMEM;
308*67b27dbeSShawn Guo 
309*67b27dbeSShawn Guo 	priv->base = devm_platform_ioremap_resource(pdev, 0);
310*67b27dbeSShawn Guo 	if (IS_ERR(priv->base))
311*67b27dbeSShawn Guo 		return PTR_ERR(priv->base);
312*67b27dbeSShawn Guo 
313*67b27dbeSShawn Guo 	priv->num_clks = ARRAY_SIZE(qcom_snps_hsphy_clks);
314*67b27dbeSShawn Guo 	priv->clks = devm_kcalloc(dev, priv->num_clks, sizeof(*priv->clks),
315*67b27dbeSShawn Guo 				  GFP_KERNEL);
316*67b27dbeSShawn Guo 	if (!priv->clks)
317*67b27dbeSShawn Guo 		return -ENOMEM;
318*67b27dbeSShawn Guo 
319*67b27dbeSShawn Guo 	for (i = 0; i < priv->num_clks; i++)
320*67b27dbeSShawn Guo 		priv->clks[i].id = qcom_snps_hsphy_clks[i];
321*67b27dbeSShawn Guo 
322*67b27dbeSShawn Guo 	ret = devm_clk_bulk_get(dev, priv->num_clks, priv->clks);
323*67b27dbeSShawn Guo 	if (ret)
324*67b27dbeSShawn Guo 		return ret;
325*67b27dbeSShawn Guo 
326*67b27dbeSShawn Guo 	priv->phy_reset = devm_reset_control_get_exclusive(dev, "phy");
327*67b27dbeSShawn Guo 	if (IS_ERR(priv->phy_reset))
328*67b27dbeSShawn Guo 		return PTR_ERR(priv->phy_reset);
329*67b27dbeSShawn Guo 
330*67b27dbeSShawn Guo 	priv->por_reset = devm_reset_control_get_exclusive(dev, "por");
331*67b27dbeSShawn Guo 	if (IS_ERR(priv->por_reset))
332*67b27dbeSShawn Guo 		return PTR_ERR(priv->por_reset);
333*67b27dbeSShawn Guo 
334*67b27dbeSShawn Guo 	priv->vregs[VDD].supply = "vdd";
335*67b27dbeSShawn Guo 	priv->vregs[VDDA_1P8].supply = "vdda1p8";
336*67b27dbeSShawn Guo 	priv->vregs[VDDA_3P3].supply = "vdda3p3";
337*67b27dbeSShawn Guo 
338*67b27dbeSShawn Guo 	ret = devm_regulator_bulk_get(dev, VREG_NUM, priv->vregs);
339*67b27dbeSShawn Guo 	if (ret)
340*67b27dbeSShawn Guo 		return ret;
341*67b27dbeSShawn Guo 
342*67b27dbeSShawn Guo 	/* Get device match data */
343*67b27dbeSShawn Guo 	priv->data = device_get_match_data(dev);
344*67b27dbeSShawn Guo 
345*67b27dbeSShawn Guo 	phy = devm_phy_create(dev, dev->of_node, &qcom_snps_hsphy_ops);
346*67b27dbeSShawn Guo 	if (IS_ERR(phy))
347*67b27dbeSShawn Guo 		return PTR_ERR(phy);
348*67b27dbeSShawn Guo 
349*67b27dbeSShawn Guo 	phy_set_drvdata(phy, priv);
350*67b27dbeSShawn Guo 
351*67b27dbeSShawn Guo 	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
352*67b27dbeSShawn Guo 	if (IS_ERR(provider))
353*67b27dbeSShawn Guo 		return PTR_ERR(provider);
354*67b27dbeSShawn Guo 
355*67b27dbeSShawn Guo 	ret = regulator_set_load(priv->vregs[VDDA_1P8].consumer, 19000);
356*67b27dbeSShawn Guo 	if (ret < 0)
357*67b27dbeSShawn Guo 		return ret;
358*67b27dbeSShawn Guo 
359*67b27dbeSShawn Guo 	ret = regulator_set_load(priv->vregs[VDDA_3P3].consumer, 16000);
360*67b27dbeSShawn Guo 	if (ret < 0)
361*67b27dbeSShawn Guo 		goto unset_1p8_load;
362*67b27dbeSShawn Guo 
363*67b27dbeSShawn Guo 	return 0;
364*67b27dbeSShawn Guo 
365*67b27dbeSShawn Guo unset_1p8_load:
366*67b27dbeSShawn Guo 	regulator_set_load(priv->vregs[VDDA_1P8].consumer, 0);
367*67b27dbeSShawn Guo 
368*67b27dbeSShawn Guo 	return ret;
369*67b27dbeSShawn Guo }
370*67b27dbeSShawn Guo 
371*67b27dbeSShawn Guo /*
372*67b27dbeSShawn Guo  * The macro is used to define an initialization sequence.  Each tuple
373*67b27dbeSShawn Guo  * is meant to program 'value' into phy register at 'offset' with 'delay'
374*67b27dbeSShawn Guo  * in us followed.
375*67b27dbeSShawn Guo  */
376*67b27dbeSShawn Guo #define HSPHY_INIT_CFG(o, v, d)	{ .offset = o, .val = v, .delay = d, }
377*67b27dbeSShawn Guo 
378*67b27dbeSShawn Guo static const struct hsphy_init_seq init_seq_femtophy[] = {
379*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0xc0, 0x01, 0),
380*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0xe8, 0x0d, 0),
381*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x74, 0x12, 0),
382*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x98, 0x63, 0),
383*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x9c, 0x03, 0),
384*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0xa0, 0x1d, 0),
385*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0xa4, 0x03, 0),
386*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x8c, 0x23, 0),
387*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x78, 0x08, 0),
388*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x7c, 0xdc, 0),
389*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x90, 0xe0, 20),
390*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x74, 0x10, 0),
391*67b27dbeSShawn Guo 	HSPHY_INIT_CFG(0x90, 0x60, 0),
392*67b27dbeSShawn Guo };
393*67b27dbeSShawn Guo 
394*67b27dbeSShawn Guo static const struct hsphy_data hsphy_data_femtophy = {
395*67b27dbeSShawn Guo 	.init_seq = init_seq_femtophy,
396*67b27dbeSShawn Guo 	.init_seq_num = ARRAY_SIZE(init_seq_femtophy),
397*67b27dbeSShawn Guo };
398*67b27dbeSShawn Guo 
399*67b27dbeSShawn Guo static const struct of_device_id qcom_snps_hsphy_match[] = {
400*67b27dbeSShawn Guo 	{ .compatible = "qcom,usb-hs-28nm-femtophy", .data = &hsphy_data_femtophy, },
401*67b27dbeSShawn Guo 	{ },
402*67b27dbeSShawn Guo };
403*67b27dbeSShawn Guo MODULE_DEVICE_TABLE(of, qcom_snps_hsphy_match);
404*67b27dbeSShawn Guo 
405*67b27dbeSShawn Guo static struct platform_driver qcom_snps_hsphy_driver = {
406*67b27dbeSShawn Guo 	.probe = qcom_snps_hsphy_probe,
407*67b27dbeSShawn Guo 	.driver	= {
408*67b27dbeSShawn Guo 		.name = "qcom,usb-hs-28nm-phy",
409*67b27dbeSShawn Guo 		.of_match_table = qcom_snps_hsphy_match,
410*67b27dbeSShawn Guo 	},
411*67b27dbeSShawn Guo };
412*67b27dbeSShawn Guo module_platform_driver(qcom_snps_hsphy_driver);
413*67b27dbeSShawn Guo 
414*67b27dbeSShawn Guo MODULE_DESCRIPTION("Qualcomm 28nm Hi-Speed USB PHY driver");
415*67b27dbeSShawn Guo MODULE_LICENSE("GPL v2");
416