1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Phy provider for USB 3.1 controller on HiSilicon Kirin970 platform
4 *
5 * Copyright (C) 2017-2020 Hilisicon Electronics Co., Ltd.
6 * http://www.huawei.com
7 *
8 * Authors: Yu Chen <chenyu56@huawei.com>
9 */
10
11#include <linux/bitfield.h>
12#include <linux/clk.h>
13#include <linux/kernel.h>
14#include <linux/mfd/syscon.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/phy/phy.h>
18#include <linux/platform_device.h>
19#include <linux/regmap.h>
20
21#define SCTRL_SCDEEPSLEEPED (0x0)
22#define USB_CLK_SELECTED BIT(20)
23
24#define PERI_CRG_PEREN0 (0x00)
25#define PERI_CRG_PERDIS0 (0x04)
26#define PERI_CRG_PEREN4 (0x40)
27#define PERI_CRG_PERDIS4 (0x44)
28#define PERI_CRG_PERRSTEN4 (0x90)
29#define PERI_CRG_PERRSTDIS4 (0x94)
30#define PERI_CRG_ISODIS (0x148)
31#define PERI_CRG_PEREN6 (0x410)
32#define PERI_CRG_PERDIS6 (0x414)
33
34#define USB_REFCLK_ISO_EN BIT(25)
35
36#define GT_CLK_USB2PHY_REF BIT(19)
37
38#define PCTRL_PERI_CTRL3 (0x10)
39#define PCTRL_PERI_CTRL3_MSK_START (16)
40#define USB_TCXO_EN BIT(1)
41
42#define PCTRL_PERI_CTRL24 (0x64)
43#define SC_CLK_USB3PHY_3MUX1_SEL BIT(25)
44
45#define USB3OTG_CTRL0 (0x00)
46#define USB3OTG_CTRL3 (0x0c)
47#define USB3OTG_CTRL4 (0x10)
48#define USB3OTG_CTRL5 (0x14)
49#define USB3OTG_CTRL7 (0x1c)
50#define USB_MISC_CFG50 (0x50)
51#define USB_MISC_CFG54 (0x54)
52#define USB_MISC_CFG58 (0x58)
53#define USB_MISC_CFG5C (0x5c)
54#define USB_MISC_CFGA0 (0xa0)
55#define TCA_CLK_RST (0x200)
56#define TCA_INTR_EN (0x204)
57#define TCA_INTR_STS (0x208)
58#define TCA_GCFG (0x210)
59#define TCA_TCPC (0x214)
60#define TCA_SYSMODE_CFG (0x218)
61#define TCA_VBUS_CTRL (0x240)
62
63#define CTRL0_USB3_VBUSVLD BIT(7)
64#define CTRL0_USB3_VBUSVLD_SEL BIT(6)
65
66#define CTRL3_USB2_VBUSVLDEXT0 BIT(6)
67#define CTRL3_USB2_VBUSVLDEXTSEL0 BIT(5)
68
69#define CTRL5_USB2_SIDDQ BIT(0)
70
71#define CTRL7_USB2_REFCLKSEL_MASK GENMASK(4, 3)
72#define CTRL7_USB2_REFCLKSEL_ABB (BIT(4) | BIT(3))
73#define CTRL7_USB2_REFCLKSEL_PAD BIT(4)
74
75#define CFG50_USB3_PHY_TEST_POWERDOWN BIT(23)
76
77#define CFG54_USB31PHY_CR_ADDR_MASK GENMASK(31, 16)
78
79#define CFG54_USB3PHY_REF_USE_PAD BIT(12)
80#define CFG54_PHY0_PMA_PWR_STABLE BIT(11)
81#define CFG54_PHY0_PCS_PWR_STABLE BIT(9)
82#define CFG54_USB31PHY_CR_ACK BIT(7)
83#define CFG54_USB31PHY_CR_WR_EN BIT(5)
84#define CFG54_USB31PHY_CR_SEL BIT(4)
85#define CFG54_USB31PHY_CR_RD_EN BIT(3)
86#define CFG54_USB31PHY_CR_CLK BIT(2)
87#define CFG54_USB3_PHY0_ANA_PWR_EN BIT(1)
88
89#define CFG58_USB31PHY_CR_DATA_MASK GENMASK(31, 16)
90
91#define CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN BIT(1)
92
93#define CFGA0_VAUX_RESET BIT(9)
94#define CFGA0_USB31C_RESET BIT(8)
95#define CFGA0_USB2PHY_REFCLK_SELECT BIT(4)
96#define CFGA0_USB3PHY_RESET BIT(1)
97#define CFGA0_USB2PHY_POR BIT(0)
98
99#define INTR_EN_XA_TIMEOUT_EVT_EN BIT(1)
100#define INTR_EN_XA_ACK_EVT_EN BIT(0)
101
102#define CLK_RST_TCA_REF_CLK_EN BIT(1)
103#define CLK_RST_SUSPEND_CLK_EN BIT(0)
104
105#define GCFG_ROLE_HSTDEV BIT(4)
106#define GCFG_OP_MODE GENMASK(1, 0)
107#define GCFG_OP_MODE_CTRL_SYNC_MODE BIT(0)
108
109#define TCPC_VALID BIT(4)
110#define TCPC_LOW_POWER_EN BIT(3)
111#define TCPC_MUX_CONTROL_MASK GENMASK(1, 0)
112#define TCPC_MUX_CONTROL_USB31 BIT(0)
113
114#define SYSMODE_CFG_TYPEC_DISABLE BIT(3)
115
116#define VBUS_CTRL_POWERPRESENT_OVERRD GENMASK(3, 2)
117#define VBUS_CTRL_VBUSVALID_OVERRD GENMASK(1, 0)
118
119#define KIRIN970_USB_DEFAULT_PHY_PARAM (0xfdfee4)
120#define KIRIN970_USB_DEFAULT_PHY_VBOOST (0x5)
121
122#define TX_VBOOST_LVL_REG (0xf)
123#define TX_VBOOST_LVL_START (6)
124#define TX_VBOOST_LVL_ENABLE BIT(9)
125
126struct hi3670_priv {
127 struct device *dev;
128 struct regmap *peri_crg;
129 struct regmap *pctrl;
130 struct regmap *sctrl;
131 struct regmap *usb31misc;
132
133 u32 eye_diagram_param;
134 u32 tx_vboost_lvl;
135
136 u32 peri_crg_offset;
137 u32 pctrl_offset;
138 u32 usb31misc_offset;
139};
140
141static int hi3670_phy_cr_clk(struct regmap *usb31misc)
142{
143 int ret;
144
145 /* Clock up */
146 ret = regmap_update_bits(map: usb31misc, USB_MISC_CFG54,
147 CFG54_USB31PHY_CR_CLK, CFG54_USB31PHY_CR_CLK);
148 if (ret)
149 return ret;
150
151 /* Clock down */
152 return regmap_update_bits(map: usb31misc, USB_MISC_CFG54,
153 CFG54_USB31PHY_CR_CLK, val: 0);
154}
155
156static int hi3670_phy_cr_set_sel(struct regmap *usb31misc)
157{
158 return regmap_update_bits(map: usb31misc, USB_MISC_CFG54,
159 CFG54_USB31PHY_CR_SEL, CFG54_USB31PHY_CR_SEL);
160}
161
162static int hi3670_phy_cr_start(struct regmap *usb31misc, int direction)
163{
164 int ret, reg;
165
166 if (direction)
167 reg = CFG54_USB31PHY_CR_WR_EN;
168 else
169 reg = CFG54_USB31PHY_CR_RD_EN;
170
171 ret = regmap_update_bits(map: usb31misc, USB_MISC_CFG54, mask: reg, val: reg);
172
173 if (ret)
174 return ret;
175
176 ret = hi3670_phy_cr_clk(usb31misc);
177 if (ret)
178 return ret;
179
180 return regmap_update_bits(map: usb31misc, USB_MISC_CFG54,
181 CFG54_USB31PHY_CR_RD_EN | CFG54_USB31PHY_CR_WR_EN, val: 0);
182}
183
184static int hi3670_phy_cr_wait_ack(struct regmap *usb31misc)
185{
186 u32 reg;
187 int retry = 10;
188 int ret;
189
190 while (retry-- > 0) {
191 ret = regmap_read(map: usb31misc, USB_MISC_CFG54, val: &reg);
192 if (ret)
193 return ret;
194 if ((reg & CFG54_USB31PHY_CR_ACK) == CFG54_USB31PHY_CR_ACK)
195 return 0;
196
197 ret = hi3670_phy_cr_clk(usb31misc);
198 if (ret)
199 return ret;
200
201 usleep_range(min: 10, max: 20);
202 }
203
204 return -ETIMEDOUT;
205}
206
207static int hi3670_phy_cr_set_addr(struct regmap *usb31misc, u32 addr)
208{
209 u32 reg;
210 int ret;
211
212 ret = regmap_read(map: usb31misc, USB_MISC_CFG54, val: &reg);
213 if (ret)
214 return ret;
215
216 reg = FIELD_PREP(CFG54_USB31PHY_CR_ADDR_MASK, addr);
217
218 return regmap_update_bits(map: usb31misc, USB_MISC_CFG54,
219 CFG54_USB31PHY_CR_ADDR_MASK, val: reg);
220}
221
222static int hi3670_phy_cr_read(struct regmap *usb31misc, u32 addr, u32 *val)
223{
224 int reg, i, ret;
225
226 for (i = 0; i < 100; i++) {
227 ret = hi3670_phy_cr_clk(usb31misc);
228 if (ret)
229 return ret;
230 }
231
232 ret = hi3670_phy_cr_set_sel(usb31misc);
233 if (ret)
234 return ret;
235
236 ret = hi3670_phy_cr_set_addr(usb31misc, addr);
237 if (ret)
238 return ret;
239
240 ret = hi3670_phy_cr_start(usb31misc, direction: 0);
241 if (ret)
242 return ret;
243
244 ret = hi3670_phy_cr_wait_ack(usb31misc);
245 if (ret)
246 return ret;
247
248 ret = regmap_read(map: usb31misc, USB_MISC_CFG58, val: &reg);
249 if (ret)
250 return ret;
251
252 *val = FIELD_GET(CFG58_USB31PHY_CR_DATA_MASK, reg);
253
254 return 0;
255}
256
257static int hi3670_phy_cr_write(struct regmap *usb31misc, u32 addr, u32 val)
258{
259 int i;
260 int ret;
261
262 for (i = 0; i < 100; i++) {
263 ret = hi3670_phy_cr_clk(usb31misc);
264 if (ret)
265 return ret;
266 }
267
268 ret = hi3670_phy_cr_set_sel(usb31misc);
269 if (ret)
270 return ret;
271
272 ret = hi3670_phy_cr_set_addr(usb31misc, addr);
273 if (ret)
274 return ret;
275
276 ret = regmap_write(map: usb31misc, USB_MISC_CFG58,
277 FIELD_PREP(CFG58_USB31PHY_CR_DATA_MASK, val));
278 if (ret)
279 return ret;
280
281 ret = hi3670_phy_cr_start(usb31misc, direction: 1);
282 if (ret)
283 return ret;
284
285 return hi3670_phy_cr_wait_ack(usb31misc);
286}
287
288static int hi3670_phy_set_params(struct hi3670_priv *priv)
289{
290 u32 reg;
291 int ret;
292 int retry = 3;
293
294 ret = regmap_write(map: priv->usb31misc, USB3OTG_CTRL4,
295 val: priv->eye_diagram_param);
296 if (ret) {
297 dev_err(priv->dev, "set USB3OTG_CTRL4 failed\n");
298 return ret;
299 }
300
301 while (retry-- > 0) {
302 ret = hi3670_phy_cr_read(usb31misc: priv->usb31misc,
303 TX_VBOOST_LVL_REG, val: &reg);
304 if (!ret)
305 break;
306
307 if (ret != -ETIMEDOUT) {
308 dev_err(priv->dev, "read TX_VBOOST_LVL_REG failed\n");
309 return ret;
310 }
311 }
312 if (ret)
313 return ret;
314
315 reg |= (TX_VBOOST_LVL_ENABLE | (priv->tx_vboost_lvl << TX_VBOOST_LVL_START));
316 ret = hi3670_phy_cr_write(usb31misc: priv->usb31misc, TX_VBOOST_LVL_REG, val: reg);
317 if (ret)
318 dev_err(priv->dev, "write TX_VBOOST_LVL_REG failed\n");
319
320 return ret;
321}
322
323static bool hi3670_is_abbclk_selected(struct hi3670_priv *priv)
324{
325 u32 reg;
326
327 if (!priv->sctrl) {
328 dev_err(priv->dev, "priv->sctrl is null!\n");
329 return false;
330 }
331
332 if (regmap_read(map: priv->sctrl, SCTRL_SCDEEPSLEEPED, val: &reg)) {
333 dev_err(priv->dev, "SCTRL_SCDEEPSLEEPED read failed!\n");
334 return false;
335 }
336
337 if ((reg & USB_CLK_SELECTED) == 0)
338 return false;
339
340 return true;
341}
342
343static int hi3670_config_phy_clock(struct hi3670_priv *priv)
344{
345 u32 val, mask;
346 int ret;
347
348 if (!hi3670_is_abbclk_selected(priv)) {
349 /* usb refclk iso disable */
350 ret = regmap_write(map: priv->peri_crg, PERI_CRG_ISODIS,
351 USB_REFCLK_ISO_EN);
352 if (ret)
353 goto out;
354
355 /* enable usb_tcxo_en */
356 ret = regmap_write(map: priv->pctrl, PCTRL_PERI_CTRL3,
357 USB_TCXO_EN |
358 (USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START));
359
360 /* select usbphy clk from abb */
361 mask = SC_CLK_USB3PHY_3MUX1_SEL;
362 ret = regmap_update_bits(map: priv->pctrl,
363 PCTRL_PERI_CTRL24, mask, val: 0);
364 if (ret)
365 goto out;
366
367 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFGA0,
368 CFGA0_USB2PHY_REFCLK_SELECT, val: 0);
369 if (ret)
370 goto out;
371
372 ret = regmap_read(map: priv->usb31misc, USB3OTG_CTRL7, val: &val);
373 if (ret)
374 goto out;
375 val &= ~CTRL7_USB2_REFCLKSEL_MASK;
376 val |= CTRL7_USB2_REFCLKSEL_ABB;
377 ret = regmap_write(map: priv->usb31misc, USB3OTG_CTRL7, val);
378 if (ret)
379 goto out;
380
381 return 0;
382 }
383
384 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFG54,
385 CFG54_USB3PHY_REF_USE_PAD,
386 CFG54_USB3PHY_REF_USE_PAD);
387 if (ret)
388 goto out;
389
390 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFGA0,
391 CFGA0_USB2PHY_REFCLK_SELECT,
392 CFGA0_USB2PHY_REFCLK_SELECT);
393 if (ret)
394 goto out;
395
396 ret = regmap_read(map: priv->usb31misc, USB3OTG_CTRL7, val: &val);
397 if (ret)
398 goto out;
399 val &= ~CTRL7_USB2_REFCLKSEL_MASK;
400 val |= CTRL7_USB2_REFCLKSEL_PAD;
401 ret = regmap_write(map: priv->usb31misc, USB3OTG_CTRL7, val);
402 if (ret)
403 goto out;
404
405 ret = regmap_write(map: priv->peri_crg,
406 PERI_CRG_PEREN6, GT_CLK_USB2PHY_REF);
407 if (ret)
408 goto out;
409
410 return 0;
411out:
412 dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
413 return ret;
414}
415
416static int hi3670_config_tca(struct hi3670_priv *priv)
417{
418 u32 val, mask;
419 int ret;
420
421 ret = regmap_write(map: priv->usb31misc, TCA_INTR_STS, val: 0xffff);
422 if (ret)
423 goto out;
424
425 ret = regmap_write(map: priv->usb31misc, TCA_INTR_EN,
426 INTR_EN_XA_TIMEOUT_EVT_EN | INTR_EN_XA_ACK_EVT_EN);
427 if (ret)
428 goto out;
429
430 mask = CLK_RST_TCA_REF_CLK_EN | CLK_RST_SUSPEND_CLK_EN;
431 ret = regmap_update_bits(map: priv->usb31misc, TCA_CLK_RST, mask, val: 0);
432 if (ret)
433 goto out;
434
435 ret = regmap_update_bits(map: priv->usb31misc, TCA_GCFG,
436 GCFG_ROLE_HSTDEV | GCFG_OP_MODE,
437 GCFG_ROLE_HSTDEV | GCFG_OP_MODE_CTRL_SYNC_MODE);
438 if (ret)
439 goto out;
440
441 ret = regmap_update_bits(map: priv->usb31misc, TCA_SYSMODE_CFG,
442 SYSMODE_CFG_TYPEC_DISABLE, val: 0);
443 if (ret)
444 goto out;
445
446 ret = regmap_read(map: priv->usb31misc, TCA_TCPC, val: &val);
447 if (ret)
448 goto out;
449 val &= ~(TCPC_VALID | TCPC_LOW_POWER_EN | TCPC_MUX_CONTROL_MASK);
450 val |= (TCPC_VALID | TCPC_MUX_CONTROL_USB31);
451 ret = regmap_write(map: priv->usb31misc, TCA_TCPC, val);
452 if (ret)
453 goto out;
454
455 ret = regmap_write(map: priv->usb31misc, TCA_VBUS_CTRL,
456 VBUS_CTRL_POWERPRESENT_OVERRD | VBUS_CTRL_VBUSVALID_OVERRD);
457 if (ret)
458 goto out;
459
460 return 0;
461out:
462 dev_err(priv->dev, "failed to config phy clock ret: %d\n", ret);
463 return ret;
464}
465
466static int hi3670_phy_init(struct phy *phy)
467{
468 struct hi3670_priv *priv = phy_get_drvdata(phy);
469 u32 val;
470 int ret;
471
472 /* assert controller */
473 val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET |
474 CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
475 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFGA0, mask: val, val: 0);
476 if (ret)
477 goto out;
478
479 ret = hi3670_config_phy_clock(priv);
480 if (ret)
481 goto out;
482
483 /* Exit from IDDQ mode */
484 ret = regmap_update_bits(map: priv->usb31misc, USB3OTG_CTRL5,
485 CTRL5_USB2_SIDDQ, val: 0);
486 if (ret)
487 goto out;
488
489 /* Release USB31 PHY out of TestPowerDown mode */
490 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFG50,
491 CFG50_USB3_PHY_TEST_POWERDOWN, val: 0);
492 if (ret)
493 goto out;
494
495 /* Deassert phy */
496 val = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
497 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFGA0, mask: val, val);
498 if (ret)
499 goto out;
500
501 usleep_range(min: 100, max: 120);
502
503 /* Tell the PHY power is stable */
504 val = CFG54_USB3_PHY0_ANA_PWR_EN | CFG54_PHY0_PCS_PWR_STABLE |
505 CFG54_PHY0_PMA_PWR_STABLE;
506 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFG54,
507 mask: val, val);
508 if (ret)
509 goto out;
510
511 ret = hi3670_config_tca(priv);
512 if (ret)
513 goto out;
514
515 /* Enable SSC */
516 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFG5C,
517 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN,
518 CFG5C_USB3_PHY0_SS_MPLLA_SSC_EN);
519 if (ret)
520 goto out;
521
522 /* Deassert controller */
523 val = CFGA0_VAUX_RESET | CFGA0_USB31C_RESET;
524 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFGA0, mask: val, val);
525 if (ret)
526 goto out;
527
528 usleep_range(min: 100, max: 120);
529
530 /* Set fake vbus valid signal */
531 val = CTRL0_USB3_VBUSVLD | CTRL0_USB3_VBUSVLD_SEL;
532 ret = regmap_update_bits(map: priv->usb31misc, USB3OTG_CTRL0, mask: val, val);
533 if (ret)
534 goto out;
535
536 val = CTRL3_USB2_VBUSVLDEXT0 | CTRL3_USB2_VBUSVLDEXTSEL0;
537 ret = regmap_update_bits(map: priv->usb31misc, USB3OTG_CTRL3, mask: val, val);
538 if (ret)
539 goto out;
540
541 usleep_range(min: 100, max: 120);
542
543 ret = hi3670_phy_set_params(priv);
544 if (ret)
545 goto out;
546
547 return 0;
548out:
549 dev_err(priv->dev, "failed to init phy ret: %d\n", ret);
550 return ret;
551}
552
553static int hi3670_phy_exit(struct phy *phy)
554{
555 struct hi3670_priv *priv = phy_get_drvdata(phy);
556 u32 mask;
557 int ret;
558
559 /* Assert phy */
560 mask = CFGA0_USB3PHY_RESET | CFGA0_USB2PHY_POR;
561 ret = regmap_update_bits(map: priv->usb31misc, USB_MISC_CFGA0, mask, val: 0);
562 if (ret)
563 goto out;
564
565 if (!hi3670_is_abbclk_selected(priv)) {
566 /* disable usb_tcxo_en */
567 ret = regmap_write(map: priv->pctrl, PCTRL_PERI_CTRL3,
568 USB_TCXO_EN << PCTRL_PERI_CTRL3_MSK_START);
569 } else {
570 ret = regmap_write(map: priv->peri_crg, PERI_CRG_PERDIS6,
571 GT_CLK_USB2PHY_REF);
572 if (ret)
573 goto out;
574 }
575
576 return 0;
577out:
578 dev_err(priv->dev, "failed to exit phy ret: %d\n", ret);
579 return ret;
580}
581
582static const struct phy_ops hi3670_phy_ops = {
583 .init = hi3670_phy_init,
584 .exit = hi3670_phy_exit,
585 .owner = THIS_MODULE,
586};
587
588static int hi3670_phy_probe(struct platform_device *pdev)
589{
590 struct phy_provider *phy_provider;
591 struct device *dev = &pdev->dev;
592 struct phy *phy;
593 struct hi3670_priv *priv;
594
595 priv = devm_kzalloc(dev, size: sizeof(*priv), GFP_KERNEL);
596 if (!priv)
597 return -ENOMEM;
598
599 priv->dev = dev;
600 priv->peri_crg = syscon_regmap_lookup_by_phandle(np: dev->of_node,
601 property: "hisilicon,pericrg-syscon");
602 if (IS_ERR(ptr: priv->peri_crg)) {
603 dev_err(dev, "no hisilicon,pericrg-syscon\n");
604 return PTR_ERR(ptr: priv->peri_crg);
605 }
606
607 priv->pctrl = syscon_regmap_lookup_by_phandle(np: dev->of_node,
608 property: "hisilicon,pctrl-syscon");
609 if (IS_ERR(ptr: priv->pctrl)) {
610 dev_err(dev, "no hisilicon,pctrl-syscon\n");
611 return PTR_ERR(ptr: priv->pctrl);
612 }
613
614 priv->sctrl = syscon_regmap_lookup_by_phandle(np: dev->of_node,
615 property: "hisilicon,sctrl-syscon");
616 if (IS_ERR(ptr: priv->sctrl)) {
617 dev_err(dev, "no hisilicon,sctrl-syscon\n");
618 return PTR_ERR(ptr: priv->sctrl);
619 }
620
621 /* node of hi3670 phy is a sub-node of usb3_otg_bc */
622 priv->usb31misc = syscon_node_to_regmap(np: dev->parent->of_node);
623 if (IS_ERR(ptr: priv->usb31misc)) {
624 dev_err(dev, "no hisilicon,usb3-otg-bc-syscon\n");
625 return PTR_ERR(ptr: priv->usb31misc);
626 }
627
628 if (of_property_read_u32(np: dev->of_node, propname: "hisilicon,eye-diagram-param",
629 out_value: &priv->eye_diagram_param))
630 priv->eye_diagram_param = KIRIN970_USB_DEFAULT_PHY_PARAM;
631
632 if (of_property_read_u32(np: dev->of_node, propname: "hisilicon,tx-vboost-lvl",
633 out_value: &priv->tx_vboost_lvl))
634 priv->tx_vboost_lvl = KIRIN970_USB_DEFAULT_PHY_VBOOST;
635
636 phy = devm_phy_create(dev, NULL, ops: &hi3670_phy_ops);
637 if (IS_ERR(ptr: phy))
638 return PTR_ERR(ptr: phy);
639
640 phy_set_drvdata(phy, data: priv);
641 phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
642 return PTR_ERR_OR_ZERO(ptr: phy_provider);
643}
644
645static const struct of_device_id hi3670_phy_of_match[] = {
646 { .compatible = "hisilicon,hi3670-usb-phy" },
647 { },
648};
649MODULE_DEVICE_TABLE(of, hi3670_phy_of_match);
650
651static struct platform_driver hi3670_phy_driver = {
652 .probe = hi3670_phy_probe,
653 .driver = {
654 .name = "hi3670-usb-phy",
655 .of_match_table = hi3670_phy_of_match,
656 }
657};
658module_platform_driver(hi3670_phy_driver);
659
660MODULE_AUTHOR("Yu Chen <chenyu56@huawei.com>");
661MODULE_LICENSE("GPL v2");
662MODULE_DESCRIPTION("Hilisicon Kirin970 USB31 PHY Driver");
663

source code of linux/drivers/phy/hisilicon/phy-hi3670-usb3.c