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