1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (c) 2021-2022 NXP. */
4 #include <linux/module.h>
7 #include <linux/phy/phy.h>
8 #include <linux/platform_device.h>
9 #include <linux/workqueue.h>
11 #define LYNX_28G_NUM_LANE 8
12 #define LYNX_28G_NUM_PLL 2
14 /* General registers per SerDes block */
15 #define LYNX_28G_PCC8 0x10a0
16 #define LYNX_28G_PCC8_SGMII 0x1
17 #define LYNX_28G_PCC8_SGMII_DIS 0x0
19 #define LYNX_28G_PCCC 0x10b0
20 #define LYNX_28G_PCCC_10GBASER 0x9
21 #define LYNX_28G_PCCC_USXGMII 0x1
22 #define LYNX_28G_PCCC_SXGMII_DIS 0x0
24 #define LYNX_28G_LNa_PCC_OFFSET(lane) (4 * (LYNX_28G_NUM_LANE - (lane->id) - 1))
26 /* Per PLL registers */
27 #define LYNX_28G_PLLnRSTCTL(pll) (0x400 + (pll) * 0x100 + 0x0)
28 #define LYNX_28G_PLLnRSTCTL_DIS(rstctl) (((rstctl) & BIT(24)) >> 24)
29 #define LYNX_28G_PLLnRSTCTL_LOCK(rstctl) (((rstctl) & BIT(23)) >> 23)
31 #define LYNX_28G_PLLnCR0(pll) (0x400 + (pll) * 0x100 + 0x4)
32 #define LYNX_28G_PLLnCR0_REFCLK_SEL(cr0) (((cr0) & GENMASK(20, 16)))
33 #define LYNX_28G_PLLnCR0_REFCLK_SEL_100MHZ 0x0
34 #define LYNX_28G_PLLnCR0_REFCLK_SEL_125MHZ 0x10000
35 #define LYNX_28G_PLLnCR0_REFCLK_SEL_156MHZ 0x20000
36 #define LYNX_28G_PLLnCR0_REFCLK_SEL_150MHZ 0x30000
37 #define LYNX_28G_PLLnCR0_REFCLK_SEL_161MHZ 0x40000
39 #define LYNX_28G_PLLnCR1(pll) (0x400 + (pll) * 0x100 + 0x8)
40 #define LYNX_28G_PLLnCR1_FRATE_SEL(cr1) (((cr1) & GENMASK(28, 24)))
41 #define LYNX_28G_PLLnCR1_FRATE_5G_10GVCO 0x0
42 #define LYNX_28G_PLLnCR1_FRATE_5G_25GVCO 0x10000000
43 #define LYNX_28G_PLLnCR1_FRATE_10G_20GVCO 0x6000000
45 /* Per SerDes lane registers */
46 /* Lane a General Control Register */
47 #define LYNX_28G_LNaGCR0(lane) (0x800 + (lane) * 0x100 + 0x0)
48 #define LYNX_28G_LNaGCR0_PROTO_SEL_MSK GENMASK(7, 3)
49 #define LYNX_28G_LNaGCR0_PROTO_SEL_SGMII 0x8
50 #define LYNX_28G_LNaGCR0_PROTO_SEL_XFI 0x50
51 #define LYNX_28G_LNaGCR0_IF_WIDTH_MSK GENMASK(2, 0)
52 #define LYNX_28G_LNaGCR0_IF_WIDTH_10_BIT 0x0
53 #define LYNX_28G_LNaGCR0_IF_WIDTH_20_BIT 0x2
55 /* Lane a Tx Reset Control Register */
56 #define LYNX_28G_LNaTRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x20)
57 #define LYNX_28G_LNaTRSTCTL_HLT_REQ BIT(27)
58 #define LYNX_28G_LNaTRSTCTL_RST_DONE BIT(30)
59 #define LYNX_28G_LNaTRSTCTL_RST_REQ BIT(31)
61 /* Lane a Tx General Control Register */
62 #define LYNX_28G_LNaTGCR0(lane) (0x800 + (lane) * 0x100 + 0x24)
63 #define LYNX_28G_LNaTGCR0_USE_PLLF 0x0
64 #define LYNX_28G_LNaTGCR0_USE_PLLS BIT(28)
65 #define LYNX_28G_LNaTGCR0_USE_PLL_MSK BIT(28)
66 #define LYNX_28G_LNaTGCR0_N_RATE_FULL 0x0
67 #define LYNX_28G_LNaTGCR0_N_RATE_HALF 0x1000000
68 #define LYNX_28G_LNaTGCR0_N_RATE_QUARTER 0x2000000
69 #define LYNX_28G_LNaTGCR0_N_RATE_MSK GENMASK(26, 24)
71 #define LYNX_28G_LNaTECR0(lane) (0x800 + (lane) * 0x100 + 0x30)
73 /* Lane a Rx Reset Control Register */
74 #define LYNX_28G_LNaRRSTCTL(lane) (0x800 + (lane) * 0x100 + 0x40)
75 #define LYNX_28G_LNaRRSTCTL_HLT_REQ BIT(27)
76 #define LYNX_28G_LNaRRSTCTL_RST_DONE BIT(30)
77 #define LYNX_28G_LNaRRSTCTL_RST_REQ BIT(31)
78 #define LYNX_28G_LNaRRSTCTL_CDR_LOCK BIT(12)
80 /* Lane a Rx General Control Register */
81 #define LYNX_28G_LNaRGCR0(lane) (0x800 + (lane) * 0x100 + 0x44)
82 #define LYNX_28G_LNaRGCR0_USE_PLLF 0x0
83 #define LYNX_28G_LNaRGCR0_USE_PLLS BIT(28)
84 #define LYNX_28G_LNaRGCR0_USE_PLL_MSK BIT(28)
85 #define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
86 #define LYNX_28G_LNaRGCR0_N_RATE_FULL 0x0
87 #define LYNX_28G_LNaRGCR0_N_RATE_HALF 0x1000000
88 #define LYNX_28G_LNaRGCR0_N_RATE_QUARTER 0x2000000
89 #define LYNX_28G_LNaRGCR0_N_RATE_MSK GENMASK(26, 24)
91 #define LYNX_28G_LNaRGCR1(lane) (0x800 + (lane) * 0x100 + 0x48)
93 #define LYNX_28G_LNaRECR0(lane) (0x800 + (lane) * 0x100 + 0x50)
94 #define LYNX_28G_LNaRECR1(lane) (0x800 + (lane) * 0x100 + 0x54)
95 #define LYNX_28G_LNaRECR2(lane) (0x800 + (lane) * 0x100 + 0x58)
97 #define LYNX_28G_LNaRSCCR0(lane) (0x800 + (lane) * 0x100 + 0x74)
99 #define LYNX_28G_LNaPSS(lane) (0x1000 + (lane) * 0x4)
100 #define LYNX_28G_LNaPSS_TYPE(pss) (((pss) & GENMASK(30, 24)) >> 24)
101 #define LYNX_28G_LNaPSS_TYPE_SGMII 0x4
102 #define LYNX_28G_LNaPSS_TYPE_XFI 0x28
104 #define LYNX_28G_SGMIIaCR1(lane) (0x1804 + (lane) * 0x10)
105 #define LYNX_28G_SGMIIaCR1_SGPCS_EN BIT(11)
106 #define LYNX_28G_SGMIIaCR1_SGPCS_DIS 0x0
107 #define LYNX_28G_SGMIIaCR1_SGPCS_MSK BIT(11)
109 struct lynx_28g_priv;
111 struct lynx_28g_pll {
112 struct lynx_28g_priv *priv;
113 u32 rstctl, cr0, cr1;
115 DECLARE_PHY_INTERFACE_MASK(supported);
118 struct lynx_28g_lane {
119 struct lynx_28g_priv *priv;
124 phy_interface_t interface;
127 struct lynx_28g_priv {
130 struct lynx_28g_pll pll[LYNX_28G_NUM_PLL];
131 struct lynx_28g_lane lane[LYNX_28G_NUM_LANE];
133 struct delayed_work cdr_check;
136 static void lynx_28g_rmw(struct lynx_28g_priv *priv, unsigned long off,
139 void __iomem *reg = priv->base + off;
142 orig = ioread32(reg);
148 #define lynx_28g_lane_rmw(lane, reg, val, mask) \
149 lynx_28g_rmw((lane)->priv, LYNX_28G_##reg(lane->id), \
150 LYNX_28G_##reg##_##val, LYNX_28G_##reg##_##mask)
151 #define lynx_28g_lane_read(lane, reg) \
152 ioread32((lane)->priv->base + LYNX_28G_##reg((lane)->id))
153 #define lynx_28g_pll_read(pll, reg) \
154 ioread32((pll)->priv->base + LYNX_28G_##reg((pll)->id))
156 static bool lynx_28g_supports_interface(struct lynx_28g_priv *priv, int intf)
160 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
161 if (LYNX_28G_PLLnRSTCTL_DIS(priv->pll[i].rstctl))
164 if (test_bit(intf, priv->pll[i].supported))
171 static struct lynx_28g_pll *lynx_28g_pll_get(struct lynx_28g_priv *priv,
172 phy_interface_t intf)
174 struct lynx_28g_pll *pll;
177 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
180 if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
183 if (test_bit(intf, pll->supported))
190 static void lynx_28g_lane_set_nrate(struct lynx_28g_lane *lane,
191 struct lynx_28g_pll *pll,
192 phy_interface_t intf)
194 switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
195 case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
196 case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
198 case PHY_INTERFACE_MODE_SGMII:
199 case PHY_INTERFACE_MODE_1000BASEX:
200 lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_QUARTER, N_RATE_MSK);
201 lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_QUARTER, N_RATE_MSK);
207 case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
209 case PHY_INTERFACE_MODE_10GBASER:
210 case PHY_INTERFACE_MODE_USXGMII:
211 lynx_28g_lane_rmw(lane, LNaTGCR0, N_RATE_FULL, N_RATE_MSK);
212 lynx_28g_lane_rmw(lane, LNaRGCR0, N_RATE_FULL, N_RATE_MSK);
223 static void lynx_28g_lane_set_pll(struct lynx_28g_lane *lane,
224 struct lynx_28g_pll *pll)
227 lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLF, USE_PLL_MSK);
228 lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLF, USE_PLL_MSK);
230 lynx_28g_lane_rmw(lane, LNaTGCR0, USE_PLLS, USE_PLL_MSK);
231 lynx_28g_lane_rmw(lane, LNaRGCR0, USE_PLLS, USE_PLL_MSK);
235 static void lynx_28g_cleanup_lane(struct lynx_28g_lane *lane)
237 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
238 struct lynx_28g_priv *priv = lane->priv;
240 /* Cleanup the protocol configuration registers of the current protocol */
241 switch (lane->interface) {
242 case PHY_INTERFACE_MODE_10GBASER:
243 lynx_28g_rmw(priv, LYNX_28G_PCCC,
244 LYNX_28G_PCCC_SXGMII_DIS << lane_offset,
245 GENMASK(3, 0) << lane_offset);
247 case PHY_INTERFACE_MODE_SGMII:
248 case PHY_INTERFACE_MODE_1000BASEX:
249 lynx_28g_rmw(priv, LYNX_28G_PCC8,
250 LYNX_28G_PCC8_SGMII_DIS << lane_offset,
251 GENMASK(3, 0) << lane_offset);
258 static void lynx_28g_lane_set_sgmii(struct lynx_28g_lane *lane)
260 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
261 struct lynx_28g_priv *priv = lane->priv;
262 struct lynx_28g_pll *pll;
264 lynx_28g_cleanup_lane(lane);
266 /* Setup the lane to run in SGMII */
267 lynx_28g_rmw(priv, LYNX_28G_PCC8,
268 LYNX_28G_PCC8_SGMII << lane_offset,
269 GENMASK(3, 0) << lane_offset);
271 /* Setup the protocol select and SerDes parallel interface width */
272 lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_SGMII, PROTO_SEL_MSK);
273 lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_10_BIT, IF_WIDTH_MSK);
275 /* Switch to the PLL that works with this interface type */
276 pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_SGMII);
277 lynx_28g_lane_set_pll(lane, pll);
279 /* Choose the portion of clock net to be used on this lane */
280 lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_SGMII);
282 /* Enable the SGMII PCS */
283 lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_EN, SGPCS_MSK);
285 /* Configure the appropriate equalization parameters for the protocol */
286 iowrite32(0x00808006, priv->base + LYNX_28G_LNaTECR0(lane->id));
287 iowrite32(0x04310000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
288 iowrite32(0x9f800000, priv->base + LYNX_28G_LNaRECR0(lane->id));
289 iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
290 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR2(lane->id));
291 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
294 static void lynx_28g_lane_set_10gbaser(struct lynx_28g_lane *lane)
296 u32 lane_offset = LYNX_28G_LNa_PCC_OFFSET(lane);
297 struct lynx_28g_priv *priv = lane->priv;
298 struct lynx_28g_pll *pll;
300 lynx_28g_cleanup_lane(lane);
302 /* Enable the SXGMII lane */
303 lynx_28g_rmw(priv, LYNX_28G_PCCC,
304 LYNX_28G_PCCC_10GBASER << lane_offset,
305 GENMASK(3, 0) << lane_offset);
307 /* Setup the protocol select and SerDes parallel interface width */
308 lynx_28g_lane_rmw(lane, LNaGCR0, PROTO_SEL_XFI, PROTO_SEL_MSK);
309 lynx_28g_lane_rmw(lane, LNaGCR0, IF_WIDTH_20_BIT, IF_WIDTH_MSK);
311 /* Switch to the PLL that works with this interface type */
312 pll = lynx_28g_pll_get(priv, PHY_INTERFACE_MODE_10GBASER);
313 lynx_28g_lane_set_pll(lane, pll);
315 /* Choose the portion of clock net to be used on this lane */
316 lynx_28g_lane_set_nrate(lane, pll, PHY_INTERFACE_MODE_10GBASER);
318 /* Disable the SGMII PCS */
319 lynx_28g_lane_rmw(lane, SGMIIaCR1, SGPCS_DIS, SGPCS_MSK);
321 /* Configure the appropriate equalization parameters for the protocol */
322 iowrite32(0x10808307, priv->base + LYNX_28G_LNaTECR0(lane->id));
323 iowrite32(0x10000000, priv->base + LYNX_28G_LNaRGCR1(lane->id));
324 iowrite32(0x00000000, priv->base + LYNX_28G_LNaRECR0(lane->id));
325 iowrite32(0x001f0000, priv->base + LYNX_28G_LNaRECR1(lane->id));
326 iowrite32(0x81000020, priv->base + LYNX_28G_LNaRECR2(lane->id));
327 iowrite32(0x00002000, priv->base + LYNX_28G_LNaRSCCR0(lane->id));
330 static int lynx_28g_power_off(struct phy *phy)
332 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
333 u32 trstctl, rrstctl;
335 if (!lane->powered_up)
338 /* Issue a halt request */
339 lynx_28g_lane_rmw(lane, LNaTRSTCTL, HLT_REQ, HLT_REQ);
340 lynx_28g_lane_rmw(lane, LNaRRSTCTL, HLT_REQ, HLT_REQ);
342 /* Wait until the halting process is complete */
344 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
345 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
346 } while ((trstctl & LYNX_28G_LNaTRSTCTL_HLT_REQ) ||
347 (rrstctl & LYNX_28G_LNaRRSTCTL_HLT_REQ));
349 lane->powered_up = false;
354 static int lynx_28g_power_on(struct phy *phy)
356 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
357 u32 trstctl, rrstctl;
359 if (lane->powered_up)
362 /* Issue a reset request on the lane */
363 lynx_28g_lane_rmw(lane, LNaTRSTCTL, RST_REQ, RST_REQ);
364 lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
366 /* Wait until the reset sequence is completed */
368 trstctl = lynx_28g_lane_read(lane, LNaTRSTCTL);
369 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
370 } while (!(trstctl & LYNX_28G_LNaTRSTCTL_RST_DONE) ||
371 !(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
373 lane->powered_up = true;
378 static int lynx_28g_set_mode(struct phy *phy, enum phy_mode mode, int submode)
380 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
381 struct lynx_28g_priv *priv = lane->priv;
382 int powered_up = lane->powered_up;
385 if (mode != PHY_MODE_ETHERNET)
388 if (lane->interface == PHY_INTERFACE_MODE_NA)
391 if (!lynx_28g_supports_interface(priv, submode))
394 /* If the lane is powered up, put the lane into the halt state while
395 * the reconfiguration is being done.
398 lynx_28g_power_off(phy);
401 case PHY_INTERFACE_MODE_SGMII:
402 case PHY_INTERFACE_MODE_1000BASEX:
403 lynx_28g_lane_set_sgmii(lane);
405 case PHY_INTERFACE_MODE_10GBASER:
406 lynx_28g_lane_set_10gbaser(lane);
413 lane->interface = submode;
416 /* Power up the lane if necessary */
418 lynx_28g_power_on(phy);
423 static int lynx_28g_validate(struct phy *phy, enum phy_mode mode, int submode,
424 union phy_configure_opts *opts __always_unused)
426 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
427 struct lynx_28g_priv *priv = lane->priv;
429 if (mode != PHY_MODE_ETHERNET)
432 if (!lynx_28g_supports_interface(priv, submode))
438 static int lynx_28g_init(struct phy *phy)
440 struct lynx_28g_lane *lane = phy_get_drvdata(phy);
442 /* Mark the fact that the lane was init */
445 /* SerDes lanes are powered on at boot time. Any lane that is managed
446 * by this driver will get powered down at init time aka at dpaa2-eth
449 lane->powered_up = true;
450 lynx_28g_power_off(phy);
455 static const struct phy_ops lynx_28g_ops = {
456 .init = lynx_28g_init,
457 .power_on = lynx_28g_power_on,
458 .power_off = lynx_28g_power_off,
459 .set_mode = lynx_28g_set_mode,
460 .validate = lynx_28g_validate,
461 .owner = THIS_MODULE,
464 static void lynx_28g_pll_read_configuration(struct lynx_28g_priv *priv)
466 struct lynx_28g_pll *pll;
469 for (i = 0; i < LYNX_28G_NUM_PLL; i++) {
474 pll->rstctl = lynx_28g_pll_read(pll, PLLnRSTCTL);
475 pll->cr0 = lynx_28g_pll_read(pll, PLLnCR0);
476 pll->cr1 = lynx_28g_pll_read(pll, PLLnCR1);
478 if (LYNX_28G_PLLnRSTCTL_DIS(pll->rstctl))
481 switch (LYNX_28G_PLLnCR1_FRATE_SEL(pll->cr1)) {
482 case LYNX_28G_PLLnCR1_FRATE_5G_10GVCO:
483 case LYNX_28G_PLLnCR1_FRATE_5G_25GVCO:
485 __set_bit(PHY_INTERFACE_MODE_1000BASEX, pll->supported);
486 __set_bit(PHY_INTERFACE_MODE_SGMII, pll->supported);
488 case LYNX_28G_PLLnCR1_FRATE_10G_20GVCO:
489 /* 10.3125GHz clock net */
490 __set_bit(PHY_INTERFACE_MODE_10GBASER, pll->supported);
493 /* 6GHz, 12.890625GHz, 8GHz */
499 #define work_to_lynx(w) container_of((w), struct lynx_28g_priv, cdr_check.work)
501 static void lynx_28g_cdr_lock_check(struct work_struct *work)
503 struct lynx_28g_priv *priv = work_to_lynx(work);
504 struct lynx_28g_lane *lane;
508 for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
509 lane = &priv->lane[i];
514 if (!lane->powered_up)
517 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
518 if (!(rrstctl & LYNX_28G_LNaRRSTCTL_CDR_LOCK)) {
519 lynx_28g_lane_rmw(lane, LNaRRSTCTL, RST_REQ, RST_REQ);
521 rrstctl = lynx_28g_lane_read(lane, LNaRRSTCTL);
522 } while (!(rrstctl & LYNX_28G_LNaRRSTCTL_RST_DONE));
525 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
526 msecs_to_jiffies(1000));
529 static void lynx_28g_lane_read_configuration(struct lynx_28g_lane *lane)
533 pss = lynx_28g_lane_read(lane, LNaPSS);
534 protocol = LYNX_28G_LNaPSS_TYPE(pss);
536 case LYNX_28G_LNaPSS_TYPE_SGMII:
537 lane->interface = PHY_INTERFACE_MODE_SGMII;
539 case LYNX_28G_LNaPSS_TYPE_XFI:
540 lane->interface = PHY_INTERFACE_MODE_10GBASER;
543 lane->interface = PHY_INTERFACE_MODE_NA;
547 static struct phy *lynx_28g_xlate(struct device *dev,
548 struct of_phandle_args *args)
550 struct lynx_28g_priv *priv = dev_get_drvdata(dev);
551 int idx = args->args[0];
553 if (WARN_ON(idx >= LYNX_28G_NUM_LANE))
554 return ERR_PTR(-EINVAL);
556 return priv->lane[idx].phy;
559 static int lynx_28g_probe(struct platform_device *pdev)
561 struct device *dev = &pdev->dev;
562 struct phy_provider *provider;
563 struct lynx_28g_priv *priv;
566 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
569 priv->dev = &pdev->dev;
571 priv->base = devm_platform_ioremap_resource(pdev, 0);
572 if (IS_ERR(priv->base))
573 return PTR_ERR(priv->base);
575 lynx_28g_pll_read_configuration(priv);
577 for (i = 0; i < LYNX_28G_NUM_LANE; i++) {
578 struct lynx_28g_lane *lane = &priv->lane[i];
581 memset(lane, 0, sizeof(*lane));
583 phy = devm_phy_create(&pdev->dev, NULL, &lynx_28g_ops);
590 phy_set_drvdata(phy, lane);
591 lynx_28g_lane_read_configuration(lane);
594 dev_set_drvdata(dev, priv);
596 INIT_DELAYED_WORK(&priv->cdr_check, lynx_28g_cdr_lock_check);
598 queue_delayed_work(system_power_efficient_wq, &priv->cdr_check,
599 msecs_to_jiffies(1000));
601 dev_set_drvdata(&pdev->dev, priv);
602 provider = devm_of_phy_provider_register(&pdev->dev, lynx_28g_xlate);
604 return PTR_ERR_OR_ZERO(provider);
607 static const struct of_device_id lynx_28g_of_match_table[] = {
608 { .compatible = "fsl,lynx-28g" },
611 MODULE_DEVICE_TABLE(of, lynx_28g_of_match_table);
613 static struct platform_driver lynx_28g_driver = {
614 .probe = lynx_28g_probe,
617 .of_match_table = lynx_28g_of_match_table,
620 module_platform_driver(lynx_28g_driver);
622 MODULE_AUTHOR("Ioana Ciornei <ioana.ciornei@nxp.com>");
623 MODULE_DESCRIPTION("Lynx 28G SerDes PHY driver for Layerscape SoCs");
624 MODULE_LICENSE("GPL v2");