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