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