xref: /linux/drivers/phy/freescale/phy-fsl-imx8mq-usb.c (revision 3271b25e3d127bb9f45bce1e71c0f8987486a070)
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2017 NXP. */
3 
4 #include <linux/bitfield.h>
5 #include <linux/clk.h>
6 #include <linux/delay.h>
7 #include <linux/io.h>
8 #include <linux/module.h>
9 #include <linux/of.h>
10 #include <linux/phy/phy.h>
11 #include <linux/platform_device.h>
12 #include <linux/regulator/consumer.h>
13 #include <linux/usb/typec_mux.h>
14 
15 #define PHY_CTRL0			0x0
16 #define PHY_CTRL0_REF_SSP_EN		BIT(2)
17 #define PHY_CTRL0_FSEL_MASK		GENMASK(10, 5)
18 #define PHY_CTRL0_FSEL_24M		0x2a
19 #define PHY_CTRL0_FSEL_100M		0x27
20 
21 #define PHY_CTRL1			0x4
22 #define PHY_CTRL1_RESET			BIT(0)
23 #define PHY_CTRL1_COMMONONN		BIT(1)
24 #define PHY_CTRL1_ATERESET		BIT(3)
25 #define PHY_CTRL1_VDATSRCENB0		BIT(19)
26 #define PHY_CTRL1_VDATDETENB0		BIT(20)
27 
28 #define PHY_CTRL2			0x8
29 #define PHY_CTRL2_TXENABLEN0		BIT(8)
30 #define PHY_CTRL2_OTG_DISABLE		BIT(9)
31 
32 #define PHY_CTRL3			0xc
33 #define PHY_CTRL3_COMPDISTUNE_MASK	GENMASK(2, 0)
34 #define PHY_CTRL3_TXPREEMP_TUNE_MASK	GENMASK(16, 15)
35 #define PHY_CTRL3_TXRISE_TUNE_MASK	GENMASK(21, 20)
36 #define PHY_CTRL3_TXVREF_TUNE_MASK	GENMASK(25, 22)
37 #define PHY_CTRL3_TX_VBOOST_LEVEL_MASK	GENMASK(31, 29)
38 
39 #define PHY_CTRL4			0x10
40 #define PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK	GENMASK(20, 15)
41 
42 #define PHY_CTRL5			0x14
43 #define PHY_CTRL5_DMPWD_OVERRIDE_SEL	BIT(23)
44 #define PHY_CTRL5_DMPWD_OVERRIDE	BIT(22)
45 #define PHY_CTRL5_DPPWD_OVERRIDE_SEL	BIT(21)
46 #define PHY_CTRL5_DPPWD_OVERRIDE	BIT(20)
47 #define PHY_CTRL5_PCS_TX_SWING_FULL_MASK	GENMASK(6, 0)
48 
49 #define PHY_CTRL6			0x18
50 #define PHY_CTRL6_ALT_CLK_EN		BIT(1)
51 #define PHY_CTRL6_ALT_CLK_SEL		BIT(0)
52 
53 #define PHY_TUNE_DEFAULT		0xffffffff
54 
55 #define TCA_CLK_RST			0x00
56 #define TCA_CLK_RST_SW			BIT(9)
57 #define TCA_CLK_RST_REF_CLK_EN		BIT(1)
58 #define TCA_CLK_RST_SUSPEND_CLK_EN	BIT(0)
59 
60 #define TCA_INTR_EN			0x04
61 #define TCA_INTR_STS			0x08
62 
63 #define TCA_GCFG			0x10
64 #define TCA_GCFG_ROLE_HSTDEV		BIT(4)
65 #define TCA_GCFG_OP_MODE		GENMASK(1, 0)
66 #define TCA_GCFG_OP_MODE_SYSMODE	0
67 #define TCA_GCFG_OP_MODE_SYNCMODE	1
68 
69 #define TCA_TCPC			0x14
70 #define TCA_TCPC_VALID			BIT(4)
71 #define TCA_TCPC_LOW_POWER_EN		BIT(3)
72 #define TCA_TCPC_ORIENTATION_NORMAL	BIT(2)
73 #define TCA_TCPC_MUX_CONTRL		GENMASK(1, 0)
74 #define TCA_TCPC_MUX_CONTRL_NO_CONN	0
75 #define TCA_TCPC_MUX_CONTRL_USB_CONN	1
76 
77 #define TCA_SYSMODE_CFG			0x18
78 #define TCA_SYSMODE_TCPC_DISABLE	BIT(3)
79 #define TCA_SYSMODE_TCPC_FLIP		BIT(2)
80 
81 #define TCA_CTRLSYNCMODE_CFG0		0x20
82 #define TCA_CTRLSYNCMODE_CFG1           0x20
83 
84 #define TCA_PSTATE			0x30
85 #define TCA_PSTATE_CM_STS		BIT(4)
86 #define TCA_PSTATE_TX_STS		BIT(3)
87 #define TCA_PSTATE_RX_PLL_STS		BIT(2)
88 #define TCA_PSTATE_PIPE0_POWER_DOWN	GENMASK(1, 0)
89 
90 #define TCA_GEN_STATUS			0x34
91 #define TCA_GEN_DEV_POR			BIT(12)
92 #define TCA_GEN_REF_CLK_SEL		BIT(8)
93 #define TCA_GEN_TYPEC_FLIP_INVERT	BIT(4)
94 #define TCA_GEN_PHY_TYPEC_DISABLE	BIT(3)
95 #define TCA_GEN_PHY_TYPEC_FLIP		BIT(2)
96 
97 #define TCA_VBUS_CTRL			0x40
98 #define TCA_VBUS_STATUS			0x44
99 
100 #define TCA_INFO			0xfc
101 
102 struct tca_blk {
103 	struct typec_switch_dev *sw;
104 	void __iomem *base;
105 	struct mutex mutex;
106 	enum typec_orientation orientation;
107 };
108 
109 struct imx8mq_usb_phy {
110 	struct phy *phy;
111 	struct clk *clk;
112 	struct clk *alt_clk;
113 	void __iomem *base;
114 	struct regulator *vbus;
115 	struct tca_blk *tca;
116 	u32 pcs_tx_swing_full;
117 	u32 pcs_tx_deemph_3p5db;
118 	u32 tx_vref_tune;
119 	u32 tx_rise_tune;
120 	u32 tx_preemp_amp_tune;
121 	u32 tx_vboost_level;
122 	u32 comp_dis_tune;
123 };
124 
125 
126 static void tca_blk_orientation_set(struct tca_blk *tca,
127 				enum typec_orientation orientation);
128 
tca_blk_typec_switch_set(struct typec_switch_dev * sw,enum typec_orientation orientation)129 static int tca_blk_typec_switch_set(struct typec_switch_dev *sw,
130 				enum typec_orientation orientation)
131 {
132 	struct imx8mq_usb_phy *imx_phy = typec_switch_get_drvdata(sw);
133 	struct tca_blk *tca = imx_phy->tca;
134 	int ret;
135 
136 	if (tca->orientation == orientation)
137 		return 0;
138 
139 	ret = clk_prepare_enable(imx_phy->clk);
140 	if (ret)
141 		return ret;
142 
143 	tca_blk_orientation_set(tca, orientation);
144 	clk_disable_unprepare(imx_phy->clk);
145 
146 	return 0;
147 }
148 
tca_blk_get_typec_switch(struct platform_device * pdev,struct imx8mq_usb_phy * imx_phy)149 static struct typec_switch_dev *tca_blk_get_typec_switch(struct platform_device *pdev,
150 					struct imx8mq_usb_phy *imx_phy)
151 {
152 	struct device *dev = &pdev->dev;
153 	struct typec_switch_dev *sw;
154 	struct typec_switch_desc sw_desc = { };
155 
156 	sw_desc.drvdata = imx_phy;
157 	sw_desc.fwnode = dev->fwnode;
158 	sw_desc.set = tca_blk_typec_switch_set;
159 	sw_desc.name = NULL;
160 
161 	sw = typec_switch_register(dev, &sw_desc);
162 	if (IS_ERR(sw)) {
163 		dev_err(dev, "Error register tca orientation switch: %ld",
164 				PTR_ERR(sw));
165 		return NULL;
166 	}
167 
168 	return sw;
169 }
170 
tca_blk_put_typec_switch(struct typec_switch_dev * sw)171 static void tca_blk_put_typec_switch(struct typec_switch_dev *sw)
172 {
173 	typec_switch_unregister(sw);
174 }
175 
tca_blk_orientation_set(struct tca_blk * tca,enum typec_orientation orientation)176 static void tca_blk_orientation_set(struct tca_blk *tca,
177 				enum typec_orientation orientation)
178 {
179 	u32 val;
180 
181 	mutex_lock(&tca->mutex);
182 
183 	if (orientation == TYPEC_ORIENTATION_NONE) {
184 		/*
185 		 * use Controller Synced Mode for TCA low power enable and
186 		 * put PHY to USB safe state.
187 		 */
188 		val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYNCMODE);
189 		writel(val, tca->base + TCA_GCFG);
190 
191 		val = TCA_TCPC_VALID | TCA_TCPC_LOW_POWER_EN;
192 		writel(val, tca->base + TCA_TCPC);
193 
194 		goto out;
195 	}
196 
197 	/* use System Configuration Mode for TCA mux control. */
198 	val = FIELD_PREP(TCA_GCFG_OP_MODE, TCA_GCFG_OP_MODE_SYSMODE);
199 	writel(val, tca->base + TCA_GCFG);
200 
201 	/* Disable TCA module */
202 	val = readl(tca->base + TCA_SYSMODE_CFG);
203 	val |= TCA_SYSMODE_TCPC_DISABLE;
204 	writel(val, tca->base + TCA_SYSMODE_CFG);
205 
206 	if (orientation == TYPEC_ORIENTATION_REVERSE)
207 		val |= TCA_SYSMODE_TCPC_FLIP;
208 	else if (orientation == TYPEC_ORIENTATION_NORMAL)
209 		val &= ~TCA_SYSMODE_TCPC_FLIP;
210 
211 	writel(val, tca->base + TCA_SYSMODE_CFG);
212 
213 	/* Enable TCA module */
214 	val &= ~TCA_SYSMODE_TCPC_DISABLE;
215 	writel(val, tca->base + TCA_SYSMODE_CFG);
216 
217 out:
218 	tca->orientation = orientation;
219 	mutex_unlock(&tca->mutex);
220 }
221 
tca_blk_init(struct tca_blk * tca)222 static void tca_blk_init(struct tca_blk *tca)
223 {
224 	u32 val;
225 
226 	/* reset XBar block */
227 	val = readl(tca->base + TCA_CLK_RST);
228 	val &= ~TCA_CLK_RST_SW;
229 	writel(val, tca->base + TCA_CLK_RST);
230 
231 	udelay(100);
232 
233 	/* clear reset */
234 	val |= TCA_CLK_RST_SW;
235 	writel(val, tca->base + TCA_CLK_RST);
236 
237 	tca_blk_orientation_set(tca, tca->orientation);
238 }
239 
imx95_usb_phy_get_tca(struct platform_device * pdev,struct imx8mq_usb_phy * imx_phy)240 static struct tca_blk *imx95_usb_phy_get_tca(struct platform_device *pdev,
241 				struct imx8mq_usb_phy *imx_phy)
242 {
243 	struct device *dev = &pdev->dev;
244 	struct resource *res;
245 	struct tca_blk *tca;
246 
247 	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
248 	if (!res)
249 		return NULL;
250 
251 	tca = devm_kzalloc(dev, sizeof(*tca), GFP_KERNEL);
252 	if (!tca)
253 		return ERR_PTR(-ENOMEM);
254 
255 	tca->base = devm_ioremap_resource(&pdev->dev, res);
256 	if (IS_ERR(tca->base))
257 		return ERR_CAST(tca->base);
258 
259 	mutex_init(&tca->mutex);
260 
261 	tca->orientation = TYPEC_ORIENTATION_NORMAL;
262 	tca->sw = tca_blk_get_typec_switch(pdev, imx_phy);
263 
264 	return tca;
265 }
266 
imx95_usb_phy_put_tca(struct imx8mq_usb_phy * imx_phy)267 static void imx95_usb_phy_put_tca(struct imx8mq_usb_phy *imx_phy)
268 {
269 	struct tca_blk *tca = imx_phy->tca;
270 
271 	if (!tca)
272 		return;
273 
274 	tca_blk_put_typec_switch(tca->sw);
275 }
276 
phy_tx_vref_tune_from_property(u32 percent)277 static u32 phy_tx_vref_tune_from_property(u32 percent)
278 {
279 	percent = clamp(percent, 94U, 124U);
280 
281 	return DIV_ROUND_CLOSEST(percent - 94U, 2);
282 }
283 
imx95_phy_tx_vref_tune_from_property(u32 percent)284 static u32 imx95_phy_tx_vref_tune_from_property(u32 percent)
285 {
286 	percent = clamp(percent, 90U, 108U);
287 
288 	switch (percent) {
289 	case 90 ... 91:
290 		percent = 0;
291 		break;
292 	case 92 ... 96:
293 		percent -= 91;
294 		break;
295 	case 97 ... 104:
296 		percent -= 92;
297 		break;
298 	case 105 ... 108:
299 		percent -= 93;
300 		break;
301 	}
302 
303 	return percent;
304 }
305 
phy_tx_rise_tune_from_property(u32 percent)306 static u32 phy_tx_rise_tune_from_property(u32 percent)
307 {
308 	switch (percent) {
309 	case 0 ... 98:
310 		return 3;
311 	case 99:
312 		return 2;
313 	case 100 ... 101:
314 		return 1;
315 	default:
316 		return 0;
317 	}
318 }
319 
imx95_phy_tx_rise_tune_from_property(u32 percent)320 static u32 imx95_phy_tx_rise_tune_from_property(u32 percent)
321 {
322 	percent = clamp(percent, 90U, 120U);
323 
324 	switch (percent) {
325 	case 90 ... 99:
326 		return 3;
327 	case 101 ... 115:
328 		return 1;
329 	case 116 ... 120:
330 		return 0;
331 	default:
332 		return 2;
333 	}
334 }
335 
phy_tx_preemp_amp_tune_from_property(u32 microamp)336 static u32 phy_tx_preemp_amp_tune_from_property(u32 microamp)
337 {
338 	microamp = min(microamp, 1800U);
339 
340 	return microamp / 600;
341 }
342 
phy_tx_vboost_level_from_property(u32 microvolt)343 static u32 phy_tx_vboost_level_from_property(u32 microvolt)
344 {
345 	switch (microvolt) {
346 	case 1156:
347 		return 5;
348 	case 844:
349 		return 3;
350 	default:
351 		return 4;
352 	}
353 }
354 
phy_pcs_tx_deemph_3p5db_from_property(u32 decibel)355 static u32 phy_pcs_tx_deemph_3p5db_from_property(u32 decibel)
356 {
357 	return min(decibel, 36U);
358 }
359 
phy_comp_dis_tune_from_property(u32 percent)360 static u32 phy_comp_dis_tune_from_property(u32 percent)
361 {
362 	switch (percent) {
363 	case 0 ... 92:
364 		return 0;
365 	case 93 ... 95:
366 		return 1;
367 	case 96 ... 97:
368 		return 2;
369 	case 98 ... 102:
370 		return 3;
371 	case 103 ... 105:
372 		return 4;
373 	case 106 ... 109:
374 		return 5;
375 	case 110 ... 113:
376 		return 6;
377 	default:
378 		return 7;
379 	}
380 }
381 
imx95_phy_comp_dis_tune_from_property(u32 percent)382 static u32 imx95_phy_comp_dis_tune_from_property(u32 percent)
383 {
384 	percent = clamp(percent, 94, 104);
385 
386 	switch (percent) {
387 	case 94 ... 95:
388 		percent = 0;
389 		break;
390 	case 96 ... 98:
391 		percent -= 95;
392 		break;
393 	case 99 ... 102:
394 		percent -= 96;
395 		break;
396 	case 103 ... 104:
397 		percent -= 97;
398 		break;
399 	}
400 
401 	return percent;
402 }
403 
phy_pcs_tx_swing_full_from_property(u32 percent)404 static u32 phy_pcs_tx_swing_full_from_property(u32 percent)
405 {
406 	percent = min(percent, 100U);
407 
408 	return (percent * 127) / 100;
409 }
410 
imx8m_get_phy_tuning_data(struct imx8mq_usb_phy * imx_phy)411 static void imx8m_get_phy_tuning_data(struct imx8mq_usb_phy *imx_phy)
412 {
413 	struct device *dev = imx_phy->phy->dev.parent;
414 	bool is_imx95 = false;
415 
416 	if (device_is_compatible(dev, "fsl,imx95-usb-phy"))
417 		is_imx95 = true;
418 
419 	if (device_property_read_u32(dev, "fsl,phy-tx-vref-tune-percent",
420 				     &imx_phy->tx_vref_tune))
421 		imx_phy->tx_vref_tune = PHY_TUNE_DEFAULT;
422 	else if (is_imx95)
423 		imx_phy->tx_vref_tune =
424 			imx95_phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune);
425 	else
426 		imx_phy->tx_vref_tune =
427 			phy_tx_vref_tune_from_property(imx_phy->tx_vref_tune);
428 
429 	if (device_property_read_u32(dev, "fsl,phy-tx-rise-tune-percent",
430 				     &imx_phy->tx_rise_tune))
431 		imx_phy->tx_rise_tune = PHY_TUNE_DEFAULT;
432 	else if (is_imx95)
433 		imx_phy->tx_rise_tune =
434 			imx95_phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune);
435 	else
436 		imx_phy->tx_rise_tune =
437 			phy_tx_rise_tune_from_property(imx_phy->tx_rise_tune);
438 
439 	if (device_property_read_u32(dev, "fsl,phy-tx-preemp-amp-tune-microamp",
440 				     &imx_phy->tx_preemp_amp_tune))
441 		imx_phy->tx_preemp_amp_tune = PHY_TUNE_DEFAULT;
442 	else
443 		imx_phy->tx_preemp_amp_tune =
444 			phy_tx_preemp_amp_tune_from_property(imx_phy->tx_preemp_amp_tune);
445 
446 	if (device_property_read_u32(dev, "fsl,phy-tx-vboost-level-microvolt",
447 				     &imx_phy->tx_vboost_level))
448 		imx_phy->tx_vboost_level = PHY_TUNE_DEFAULT;
449 	else
450 		imx_phy->tx_vboost_level =
451 			phy_tx_vboost_level_from_property(imx_phy->tx_vboost_level);
452 
453 	if (device_property_read_u32(dev, "fsl,phy-comp-dis-tune-percent",
454 				     &imx_phy->comp_dis_tune))
455 		imx_phy->comp_dis_tune = PHY_TUNE_DEFAULT;
456 	else if (is_imx95)
457 		imx_phy->comp_dis_tune =
458 			imx95_phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune);
459 	else
460 		imx_phy->comp_dis_tune =
461 			phy_comp_dis_tune_from_property(imx_phy->comp_dis_tune);
462 
463 	if (device_property_read_u32(dev, "fsl,phy-pcs-tx-deemph-3p5db-attenuation-db",
464 				     &imx_phy->pcs_tx_deemph_3p5db))
465 		imx_phy->pcs_tx_deemph_3p5db = PHY_TUNE_DEFAULT;
466 	else
467 		imx_phy->pcs_tx_deemph_3p5db =
468 			phy_pcs_tx_deemph_3p5db_from_property(imx_phy->pcs_tx_deemph_3p5db);
469 
470 	if (device_property_read_u32(dev, "fsl,phy-pcs-tx-swing-full-percent",
471 				     &imx_phy->pcs_tx_swing_full))
472 		imx_phy->pcs_tx_swing_full = PHY_TUNE_DEFAULT;
473 	else
474 		imx_phy->pcs_tx_swing_full =
475 			phy_pcs_tx_swing_full_from_property(imx_phy->pcs_tx_swing_full);
476 }
477 
imx8m_phy_tune(struct imx8mq_usb_phy * imx_phy)478 static void imx8m_phy_tune(struct imx8mq_usb_phy *imx_phy)
479 {
480 	u32 value;
481 
482 	/* PHY tuning */
483 	if (imx_phy->pcs_tx_deemph_3p5db != PHY_TUNE_DEFAULT) {
484 		value = readl(imx_phy->base + PHY_CTRL4);
485 		value &= ~PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK;
486 		value |= FIELD_PREP(PHY_CTRL4_PCS_TX_DEEMPH_3P5DB_MASK,
487 				   imx_phy->pcs_tx_deemph_3p5db);
488 		writel(value, imx_phy->base + PHY_CTRL4);
489 	}
490 
491 	if (imx_phy->pcs_tx_swing_full != PHY_TUNE_DEFAULT) {
492 		value = readl(imx_phy->base + PHY_CTRL5);
493 		value &= ~PHY_CTRL5_PCS_TX_SWING_FULL_MASK;
494 		value |= FIELD_PREP(PHY_CTRL5_PCS_TX_SWING_FULL_MASK,
495 				   imx_phy->pcs_tx_swing_full);
496 		writel(value, imx_phy->base + PHY_CTRL5);
497 	}
498 
499 	if ((imx_phy->tx_vref_tune & imx_phy->tx_rise_tune &
500 	     imx_phy->tx_preemp_amp_tune & imx_phy->comp_dis_tune &
501 	     imx_phy->tx_vboost_level) == PHY_TUNE_DEFAULT)
502 		/* If all are the default values, no need update. */
503 		return;
504 
505 	value = readl(imx_phy->base + PHY_CTRL3);
506 
507 	if (imx_phy->tx_vref_tune != PHY_TUNE_DEFAULT) {
508 		value &= ~PHY_CTRL3_TXVREF_TUNE_MASK;
509 		value |= FIELD_PREP(PHY_CTRL3_TXVREF_TUNE_MASK,
510 				   imx_phy->tx_vref_tune);
511 	}
512 
513 	if (imx_phy->tx_rise_tune != PHY_TUNE_DEFAULT) {
514 		value &= ~PHY_CTRL3_TXRISE_TUNE_MASK;
515 		value |= FIELD_PREP(PHY_CTRL3_TXRISE_TUNE_MASK,
516 				    imx_phy->tx_rise_tune);
517 	}
518 
519 	if (imx_phy->tx_preemp_amp_tune != PHY_TUNE_DEFAULT) {
520 		value &= ~PHY_CTRL3_TXPREEMP_TUNE_MASK;
521 		value |= FIELD_PREP(PHY_CTRL3_TXPREEMP_TUNE_MASK,
522 				imx_phy->tx_preemp_amp_tune);
523 	}
524 
525 	if (imx_phy->comp_dis_tune != PHY_TUNE_DEFAULT) {
526 		value &= ~PHY_CTRL3_COMPDISTUNE_MASK;
527 		value |= FIELD_PREP(PHY_CTRL3_COMPDISTUNE_MASK,
528 				    imx_phy->comp_dis_tune);
529 	}
530 
531 	if (imx_phy->tx_vboost_level != PHY_TUNE_DEFAULT) {
532 		value &= ~PHY_CTRL3_TX_VBOOST_LEVEL_MASK;
533 		value |= FIELD_PREP(PHY_CTRL3_TX_VBOOST_LEVEL_MASK,
534 				    imx_phy->tx_vboost_level);
535 	}
536 
537 	writel(value, imx_phy->base + PHY_CTRL3);
538 }
539 
imx8mq_usb_phy_init(struct phy * phy)540 static int imx8mq_usb_phy_init(struct phy *phy)
541 {
542 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
543 	u32 value;
544 
545 	value = readl(imx_phy->base + PHY_CTRL1);
546 	value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0 |
547 		   PHY_CTRL1_COMMONONN);
548 	value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
549 	writel(value, imx_phy->base + PHY_CTRL1);
550 
551 	value = readl(imx_phy->base + PHY_CTRL0);
552 	value |= PHY_CTRL0_REF_SSP_EN;
553 	writel(value, imx_phy->base + PHY_CTRL0);
554 
555 	value = readl(imx_phy->base + PHY_CTRL2);
556 	value |= PHY_CTRL2_TXENABLEN0;
557 	writel(value, imx_phy->base + PHY_CTRL2);
558 
559 	value = readl(imx_phy->base + PHY_CTRL1);
560 	value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
561 	writel(value, imx_phy->base + PHY_CTRL1);
562 
563 	return 0;
564 }
565 
imx8mp_usb_phy_init(struct phy * phy)566 static int imx8mp_usb_phy_init(struct phy *phy)
567 {
568 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
569 	u32 value;
570 
571 	/* USB3.0 PHY signal fsel for 24M ref */
572 	value = readl(imx_phy->base + PHY_CTRL0);
573 	value &= ~PHY_CTRL0_FSEL_MASK;
574 	value |= FIELD_PREP(PHY_CTRL0_FSEL_MASK, imx_phy->alt_clk ?
575 			    PHY_CTRL0_FSEL_100M : PHY_CTRL0_FSEL_24M);
576 	writel(value, imx_phy->base + PHY_CTRL0);
577 
578 	/* Disable alt_clk_en and use internal MPLL clocks */
579 	value = readl(imx_phy->base + PHY_CTRL6);
580 	value &= ~(PHY_CTRL6_ALT_CLK_SEL | PHY_CTRL6_ALT_CLK_EN);
581 	writel(value, imx_phy->base + PHY_CTRL6);
582 
583 	value = readl(imx_phy->base + PHY_CTRL1);
584 	value &= ~(PHY_CTRL1_VDATSRCENB0 | PHY_CTRL1_VDATDETENB0);
585 	value |= PHY_CTRL1_RESET | PHY_CTRL1_ATERESET;
586 	writel(value, imx_phy->base + PHY_CTRL1);
587 
588 	value = readl(imx_phy->base + PHY_CTRL0);
589 	value |= PHY_CTRL0_REF_SSP_EN;
590 	writel(value, imx_phy->base + PHY_CTRL0);
591 
592 	value = readl(imx_phy->base + PHY_CTRL2);
593 	value |= PHY_CTRL2_TXENABLEN0 | PHY_CTRL2_OTG_DISABLE;
594 	writel(value, imx_phy->base + PHY_CTRL2);
595 
596 	udelay(10);
597 
598 	value = readl(imx_phy->base + PHY_CTRL1);
599 	value &= ~(PHY_CTRL1_RESET | PHY_CTRL1_ATERESET);
600 	writel(value, imx_phy->base + PHY_CTRL1);
601 
602 	imx8m_phy_tune(imx_phy);
603 
604 	if (imx_phy->tca)
605 		tca_blk_init(imx_phy->tca);
606 
607 	return 0;
608 }
609 
imx8mq_phy_power_on(struct phy * phy)610 static int imx8mq_phy_power_on(struct phy *phy)
611 {
612 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
613 	int ret;
614 
615 	ret = regulator_enable(imx_phy->vbus);
616 	if (ret)
617 		return ret;
618 
619 	ret = clk_prepare_enable(imx_phy->clk);
620 	if (ret)
621 		return ret;
622 
623 	ret = clk_prepare_enable(imx_phy->alt_clk);
624 	if (ret) {
625 		clk_disable_unprepare(imx_phy->clk);
626 		return ret;
627 	}
628 
629 	return ret;
630 }
631 
imx8mq_phy_power_off(struct phy * phy)632 static int imx8mq_phy_power_off(struct phy *phy)
633 {
634 	struct imx8mq_usb_phy *imx_phy = phy_get_drvdata(phy);
635 
636 	clk_disable_unprepare(imx_phy->alt_clk);
637 	clk_disable_unprepare(imx_phy->clk);
638 	regulator_disable(imx_phy->vbus);
639 
640 	return 0;
641 }
642 
643 static const struct phy_ops imx8mq_usb_phy_ops = {
644 	.init		= imx8mq_usb_phy_init,
645 	.power_on	= imx8mq_phy_power_on,
646 	.power_off	= imx8mq_phy_power_off,
647 	.owner		= THIS_MODULE,
648 };
649 
650 static const struct phy_ops imx8mp_usb_phy_ops = {
651 	.init		= imx8mp_usb_phy_init,
652 	.power_on	= imx8mq_phy_power_on,
653 	.power_off	= imx8mq_phy_power_off,
654 	.owner		= THIS_MODULE,
655 };
656 
657 static const struct of_device_id imx8mq_usb_phy_of_match[] = {
658 	{.compatible = "fsl,imx8mq-usb-phy",
659 	 .data = &imx8mq_usb_phy_ops,},
660 	{.compatible = "fsl,imx8mp-usb-phy",
661 	 .data = &imx8mp_usb_phy_ops,},
662 	{.compatible = "fsl,imx95-usb-phy",
663 	 .data = &imx8mp_usb_phy_ops,},
664 	{ }
665 };
666 MODULE_DEVICE_TABLE(of, imx8mq_usb_phy_of_match);
667 
imx8mq_usb_phy_probe(struct platform_device * pdev)668 static int imx8mq_usb_phy_probe(struct platform_device *pdev)
669 {
670 	struct phy_provider *phy_provider;
671 	struct device *dev = &pdev->dev;
672 	struct imx8mq_usb_phy *imx_phy;
673 	const struct phy_ops *phy_ops;
674 
675 	imx_phy = devm_kzalloc(dev, sizeof(*imx_phy), GFP_KERNEL);
676 	if (!imx_phy)
677 		return -ENOMEM;
678 
679 	imx_phy->clk = devm_clk_get(dev, "phy");
680 	if (IS_ERR(imx_phy->clk)) {
681 		dev_err(dev, "failed to get imx8mq usb phy clock\n");
682 		return PTR_ERR(imx_phy->clk);
683 	}
684 
685 	imx_phy->alt_clk = devm_clk_get_optional(dev, "alt");
686 	if (IS_ERR(imx_phy->alt_clk))
687 		return dev_err_probe(dev, PTR_ERR(imx_phy->alt_clk),
688 				    "Failed to get alt clk\n");
689 
690 	imx_phy->base = devm_platform_ioremap_resource(pdev, 0);
691 	if (IS_ERR(imx_phy->base))
692 		return PTR_ERR(imx_phy->base);
693 
694 	phy_ops = of_device_get_match_data(dev);
695 	if (!phy_ops)
696 		return -EINVAL;
697 
698 	imx_phy->phy = devm_phy_create(dev, NULL, phy_ops);
699 	if (IS_ERR(imx_phy->phy))
700 		return PTR_ERR(imx_phy->phy);
701 
702 	imx_phy->vbus = devm_regulator_get(dev, "vbus");
703 	if (IS_ERR(imx_phy->vbus))
704 		return dev_err_probe(dev, PTR_ERR(imx_phy->vbus), "failed to get vbus\n");
705 
706 	phy_set_drvdata(imx_phy->phy, imx_phy);
707 
708 	imx_phy->tca = imx95_usb_phy_get_tca(pdev, imx_phy);
709 	if (IS_ERR(imx_phy->tca))
710 		return dev_err_probe(dev, PTR_ERR(imx_phy->tca),
711 					"failed to get tca\n");
712 
713 	imx8m_get_phy_tuning_data(imx_phy);
714 
715 	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
716 
717 	return PTR_ERR_OR_ZERO(phy_provider);
718 }
719 
imx8mq_usb_phy_remove(struct platform_device * pdev)720 static void imx8mq_usb_phy_remove(struct platform_device *pdev)
721 {
722 	struct imx8mq_usb_phy *imx_phy = platform_get_drvdata(pdev);
723 
724 	imx95_usb_phy_put_tca(imx_phy);
725 }
726 
727 static struct platform_driver imx8mq_usb_phy_driver = {
728 	.probe	= imx8mq_usb_phy_probe,
729 	.remove = imx8mq_usb_phy_remove,
730 	.driver = {
731 		.name	= "imx8mq-usb-phy",
732 		.of_match_table	= imx8mq_usb_phy_of_match,
733 	}
734 };
735 module_platform_driver(imx8mq_usb_phy_driver);
736 
737 MODULE_DESCRIPTION("FSL IMX8MQ USB PHY driver");
738 MODULE_LICENSE("GPL");
739