1 // SPDX-License-Identifier: GPL-2.0+
2 /* Copyright (C) 2021 Maxlinear Corporation
3 * Copyright (C) 2020 Intel Corporation
5 * Drivers for Maxlinear Ethernet GPY
9 #include <linux/module.h>
10 #include <linux/bitfield.h>
11 #include <linux/phy.h>
12 #include <linux/netdevice.h>
15 #define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
16 #define PHY_ID_GPY21xB_MASK 0xFFFFFFF9
17 #define PHY_ID_GPY2xx 0x67C9DC00
18 #define PHY_ID_GPY115B 0x67C9DF00
19 #define PHY_ID_GPY115C 0x67C9DF10
20 #define PHY_ID_GPY211B 0x67C9DE08
21 #define PHY_ID_GPY211C 0x67C9DE10
22 #define PHY_ID_GPY212B 0x67C9DE09
23 #define PHY_ID_GPY212C 0x67C9DE20
24 #define PHY_ID_GPY215B 0x67C9DF04
25 #define PHY_ID_GPY215C 0x67C9DF20
26 #define PHY_ID_GPY241B 0x67C9DE40
27 #define PHY_ID_GPY241BM 0x67C9DE80
28 #define PHY_ID_GPY245B 0x67C9DEC0
30 #define PHY_MIISTAT 0x18 /* MII state */
31 #define PHY_IMASK 0x19 /* interrupt mask */
32 #define PHY_ISTAT 0x1A /* interrupt status */
33 #define PHY_FWV 0x1E /* firmware version */
35 #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
36 #define PHY_MIISTAT_DPX BIT(3)
37 #define PHY_MIISTAT_LS BIT(10)
39 #define PHY_MIISTAT_SPD_10 0
40 #define PHY_MIISTAT_SPD_100 1
41 #define PHY_MIISTAT_SPD_1000 2
42 #define PHY_MIISTAT_SPD_2500 4
44 #define PHY_IMASK_WOL BIT(15) /* Wake-on-LAN */
45 #define PHY_IMASK_ANC BIT(10) /* Auto-Neg complete */
46 #define PHY_IMASK_ADSC BIT(5) /* Link auto-downspeed detect */
47 #define PHY_IMASK_DXMC BIT(2) /* Duplex mode change */
48 #define PHY_IMASK_LSPC BIT(1) /* Link speed change */
49 #define PHY_IMASK_LSTC BIT(0) /* Link state change */
50 #define PHY_IMASK_MASK (PHY_IMASK_LSTC | \
56 #define PHY_FWV_REL_MASK BIT(15)
57 #define PHY_FWV_TYPE_MASK GENMASK(11, 8)
58 #define PHY_FWV_MINOR_MASK GENMASK(7, 0)
61 #define VSPEC1_SGMII_CTRL 0x08
62 #define VSPEC1_SGMII_CTRL_ANEN BIT(12) /* Aneg enable */
63 #define VSPEC1_SGMII_CTRL_ANRS BIT(9) /* Restart Aneg */
64 #define VSPEC1_SGMII_ANEN_ANRS (VSPEC1_SGMII_CTRL_ANEN | \
65 VSPEC1_SGMII_CTRL_ANRS)
68 #define VPSPEC2_WOL_CTL 0x0E06
69 #define VPSPEC2_WOL_AD01 0x0E08
70 #define VPSPEC2_WOL_AD23 0x0E09
71 #define VPSPEC2_WOL_AD45 0x0E0A
77 } ver_need_sgmii_reaneg[] = {
83 static int gpy_config_init(struct phy_device *phydev)
87 /* Mask all interrupts */
88 ret = phy_write(phydev, PHY_IMASK, 0);
92 /* Clear all pending interrupts */
93 ret = phy_read(phydev, PHY_ISTAT);
94 return ret < 0 ? ret : 0;
97 static int gpy_probe(struct phy_device *phydev)
101 if (!phydev->is_c45) {
102 ret = phy_get_c45_ids(phydev);
107 /* Show GPY PHY FW version in dmesg */
108 ret = phy_read(phydev, PHY_FWV);
112 phydev_info(phydev, "Firmware Version: 0x%04X (%s)\n", ret,
113 (ret & PHY_FWV_REL_MASK) ? "release" : "test");
118 static bool gpy_sgmii_need_reaneg(struct phy_device *phydev)
120 int fw_ver, fw_type, fw_minor;
123 fw_ver = phy_read(phydev, PHY_FWV);
127 fw_type = FIELD_GET(PHY_FWV_TYPE_MASK, fw_ver);
128 fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_ver);
130 for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) {
131 if (fw_type != ver_need_sgmii_reaneg[i].type)
133 if (fw_minor < ver_need_sgmii_reaneg[i].minor)
141 static bool gpy_2500basex_chk(struct phy_device *phydev)
145 ret = phy_read(phydev, PHY_MIISTAT);
147 phydev_err(phydev, "Error: MDIO register access failed: %d\n",
152 if (!(ret & PHY_MIISTAT_LS) ||
153 FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500)
156 phydev->speed = SPEED_2500;
157 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
158 phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
159 VSPEC1_SGMII_CTRL_ANEN, 0);
163 static bool gpy_sgmii_aneg_en(struct phy_device *phydev)
167 ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL);
169 phydev_err(phydev, "Error: MMD register access failed: %d\n",
174 return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false;
177 static int gpy_config_aneg(struct phy_device *phydev)
179 bool changed = false;
183 if (phydev->autoneg == AUTONEG_DISABLE) {
184 /* Configure half duplex with genphy_setup_forced,
185 * because genphy_c45_pma_setup_forced does not support.
187 return phydev->duplex != DUPLEX_FULL
188 ? genphy_setup_forced(phydev)
189 : genphy_c45_pma_setup_forced(phydev);
192 ret = genphy_c45_an_config_aneg(phydev);
198 adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
199 ret = phy_modify_changed(phydev, MII_CTRL1000,
200 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
207 ret = genphy_c45_check_and_restart_aneg(phydev, changed);
211 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
212 phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
215 /* No need to trigger re-ANEG if link speed is 2.5G or SGMII ANEG is
218 if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) ||
219 !gpy_sgmii_aneg_en(phydev))
222 /* There is a design constraint in GPY2xx device where SGMII AN is
223 * only triggered when there is change of speed. If, PHY link
224 * partner`s speed is still same even after PHY TPI is down and up
225 * again, SGMII AN is not triggered and hence no new in-band message
226 * from GPY to MAC side SGMII.
227 * This could cause an issue during power up, when PHY is up prior to
228 * MAC. At this condition, once MAC side SGMII is up, MAC side SGMII
229 * wouldn`t receive new in-band message from GPY with correct link
230 * status, speed and duplex info.
232 * 1) If PHY is already up and TPI link status is still down (such as
233 * hard reboot), TPI link status is polled for 4 seconds before
234 * retriggerring SGMII AN.
235 * 2) If PHY is already up and TPI link status is also up (such as soft
236 * reboot), polling of TPI link status is not needed and SGMII AN is
237 * immediately retriggered.
238 * 3) Other conditions such as PHY is down, speed change etc, skip
239 * retriggering SGMII AN. Note: in case of speed change, GPY FW will
243 if (phydev->state != PHY_UP)
246 ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS,
247 20000, 4000000, false);
248 if (ret == -ETIMEDOUT)
253 /* Trigger SGMII AN. */
254 return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
255 VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS);
258 static void gpy_update_interface(struct phy_device *phydev)
262 /* Interface mode is fixed for USXGMII and integrated PHY */
263 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
264 phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
267 /* Automatically switch SERDES interface between SGMII and 2500-BaseX
268 * according to speed. Disable ANEG in 2500-BaseX mode.
270 switch (phydev->speed) {
272 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
273 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
274 VSPEC1_SGMII_CTRL_ANEN, 0);
277 "Error: Disable of SGMII ANEG failed: %d\n",
283 phydev->interface = PHY_INTERFACE_MODE_SGMII;
284 if (gpy_sgmii_aneg_en(phydev))
286 /* Enable and restart SGMII ANEG for 10/100/1000Mbps link speed
287 * if ANEG is disabled (in 2500-BaseX mode).
289 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
290 VSPEC1_SGMII_ANEN_ANRS,
291 VSPEC1_SGMII_ANEN_ANRS);
294 "Error: Enable of SGMII ANEG failed: %d\n",
300 static int gpy_read_status(struct phy_device *phydev)
304 ret = genphy_update_link(phydev);
308 phydev->speed = SPEED_UNKNOWN;
309 phydev->duplex = DUPLEX_UNKNOWN;
311 phydev->asym_pause = 0;
313 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
314 ret = genphy_c45_read_lpa(phydev);
318 /* Read the link partner's 1G advertisement */
319 ret = phy_read(phydev, MII_STAT1000);
322 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
323 } else if (phydev->autoneg == AUTONEG_DISABLE) {
324 linkmode_zero(phydev->lp_advertising);
327 ret = phy_read(phydev, PHY_MIISTAT);
331 phydev->link = (ret & PHY_MIISTAT_LS) ? 1 : 0;
332 phydev->duplex = (ret & PHY_MIISTAT_DPX) ? DUPLEX_FULL : DUPLEX_HALF;
333 switch (FIELD_GET(PHY_MIISTAT_SPD_MASK, ret)) {
334 case PHY_MIISTAT_SPD_10:
335 phydev->speed = SPEED_10;
337 case PHY_MIISTAT_SPD_100:
338 phydev->speed = SPEED_100;
340 case PHY_MIISTAT_SPD_1000:
341 phydev->speed = SPEED_1000;
343 case PHY_MIISTAT_SPD_2500:
344 phydev->speed = SPEED_2500;
349 gpy_update_interface(phydev);
354 static int gpy_config_intr(struct phy_device *phydev)
358 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
359 mask = PHY_IMASK_MASK;
361 return phy_write(phydev, PHY_IMASK, mask);
364 static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev)
368 reg = phy_read(phydev, PHY_ISTAT);
374 if (!(reg & PHY_IMASK_MASK))
377 phy_trigger_machine(phydev);
382 static int gpy_set_wol(struct phy_device *phydev,
383 struct ethtool_wolinfo *wol)
385 struct net_device *attach_dev = phydev->attached_dev;
388 if (wol->wolopts & WAKE_MAGIC) {
389 /* MAC address - Byte0:Byte1:Byte2:Byte3:Byte4:Byte5
390 * VPSPEC2_WOL_AD45 = Byte0:Byte1
391 * VPSPEC2_WOL_AD23 = Byte2:Byte3
392 * VPSPEC2_WOL_AD01 = Byte4:Byte5
394 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
396 ((attach_dev->dev_addr[0] << 8) |
397 attach_dev->dev_addr[1]));
401 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
403 ((attach_dev->dev_addr[2] << 8) |
404 attach_dev->dev_addr[3]));
408 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
410 ((attach_dev->dev_addr[4] << 8) |
411 attach_dev->dev_addr[5]));
415 /* Enable the WOL interrupt */
416 ret = phy_write(phydev, PHY_IMASK, PHY_IMASK_WOL);
420 /* Enable magic packet matching */
421 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
427 /* Clear the interrupt status register.
428 * Only WoL is enabled so clear all.
430 ret = phy_read(phydev, PHY_ISTAT);
434 /* Disable magic packet matching */
435 ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
442 if (wol->wolopts & WAKE_PHY) {
443 /* Enable the link state change interrupt */
444 ret = phy_set_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
448 /* Clear the interrupt status register */
449 ret = phy_read(phydev, PHY_ISTAT);
453 if (ret & (PHY_IMASK_MASK & ~PHY_IMASK_LSTC))
454 phy_trigger_machine(phydev);
459 /* Disable the link state change interrupt */
460 return phy_clear_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
463 static void gpy_get_wol(struct phy_device *phydev,
464 struct ethtool_wolinfo *wol)
468 wol->supported = WAKE_MAGIC | WAKE_PHY;
471 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, VPSPEC2_WOL_CTL);
473 wol->wolopts |= WAKE_MAGIC;
475 ret = phy_read(phydev, PHY_IMASK);
476 if (ret & PHY_IMASK_LSTC)
477 wol->wolopts |= WAKE_PHY;
480 static int gpy_loopback(struct phy_device *phydev, bool enable)
484 ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
485 enable ? BMCR_LOOPBACK : 0);
487 /* It takes some time for PHY device to switch
488 * into/out-of loopback mode.
496 static int gpy115_loopback(struct phy_device *phydev, bool enable)
502 return gpy_loopback(phydev, enable);
504 ret = phy_read(phydev, PHY_FWV);
508 fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, ret);
509 if (fw_minor > 0x0076)
510 return gpy_loopback(phydev, 0);
512 return genphy_soft_reset(phydev);
515 static struct phy_driver gpy_drivers[] = {
517 PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
518 .name = "Maxlinear Ethernet GPY2xx",
519 .get_features = genphy_c45_pma_read_abilities,
520 .config_init = gpy_config_init,
522 .suspend = genphy_suspend,
523 .resume = genphy_resume,
524 .config_aneg = gpy_config_aneg,
525 .aneg_done = genphy_c45_aneg_done,
526 .read_status = gpy_read_status,
527 .config_intr = gpy_config_intr,
528 .handle_interrupt = gpy_handle_interrupt,
529 .set_wol = gpy_set_wol,
530 .get_wol = gpy_get_wol,
531 .set_loopback = gpy_loopback,
534 .phy_id = PHY_ID_GPY115B,
535 .phy_id_mask = PHY_ID_GPYx15B_MASK,
536 .name = "Maxlinear Ethernet GPY115B",
537 .get_features = genphy_c45_pma_read_abilities,
538 .config_init = gpy_config_init,
540 .suspend = genphy_suspend,
541 .resume = genphy_resume,
542 .config_aneg = gpy_config_aneg,
543 .aneg_done = genphy_c45_aneg_done,
544 .read_status = gpy_read_status,
545 .config_intr = gpy_config_intr,
546 .handle_interrupt = gpy_handle_interrupt,
547 .set_wol = gpy_set_wol,
548 .get_wol = gpy_get_wol,
549 .set_loopback = gpy115_loopback,
552 PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
553 .name = "Maxlinear Ethernet GPY115C",
554 .get_features = genphy_c45_pma_read_abilities,
555 .config_init = gpy_config_init,
557 .suspend = genphy_suspend,
558 .resume = genphy_resume,
559 .config_aneg = gpy_config_aneg,
560 .aneg_done = genphy_c45_aneg_done,
561 .read_status = gpy_read_status,
562 .config_intr = gpy_config_intr,
563 .handle_interrupt = gpy_handle_interrupt,
564 .set_wol = gpy_set_wol,
565 .get_wol = gpy_get_wol,
566 .set_loopback = gpy115_loopback,
569 .phy_id = PHY_ID_GPY211B,
570 .phy_id_mask = PHY_ID_GPY21xB_MASK,
571 .name = "Maxlinear Ethernet GPY211B",
572 .get_features = genphy_c45_pma_read_abilities,
573 .config_init = gpy_config_init,
575 .suspend = genphy_suspend,
576 .resume = genphy_resume,
577 .config_aneg = gpy_config_aneg,
578 .aneg_done = genphy_c45_aneg_done,
579 .read_status = gpy_read_status,
580 .config_intr = gpy_config_intr,
581 .handle_interrupt = gpy_handle_interrupt,
582 .set_wol = gpy_set_wol,
583 .get_wol = gpy_get_wol,
584 .set_loopback = gpy_loopback,
587 PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
588 .name = "Maxlinear Ethernet GPY211C",
589 .get_features = genphy_c45_pma_read_abilities,
590 .config_init = gpy_config_init,
592 .suspend = genphy_suspend,
593 .resume = genphy_resume,
594 .config_aneg = gpy_config_aneg,
595 .aneg_done = genphy_c45_aneg_done,
596 .read_status = gpy_read_status,
597 .config_intr = gpy_config_intr,
598 .handle_interrupt = gpy_handle_interrupt,
599 .set_wol = gpy_set_wol,
600 .get_wol = gpy_get_wol,
601 .set_loopback = gpy_loopback,
604 .phy_id = PHY_ID_GPY212B,
605 .phy_id_mask = PHY_ID_GPY21xB_MASK,
606 .name = "Maxlinear Ethernet GPY212B",
607 .get_features = genphy_c45_pma_read_abilities,
608 .config_init = gpy_config_init,
610 .suspend = genphy_suspend,
611 .resume = genphy_resume,
612 .config_aneg = gpy_config_aneg,
613 .aneg_done = genphy_c45_aneg_done,
614 .read_status = gpy_read_status,
615 .config_intr = gpy_config_intr,
616 .handle_interrupt = gpy_handle_interrupt,
617 .set_wol = gpy_set_wol,
618 .get_wol = gpy_get_wol,
619 .set_loopback = gpy_loopback,
622 PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
623 .name = "Maxlinear Ethernet GPY212C",
624 .get_features = genphy_c45_pma_read_abilities,
625 .config_init = gpy_config_init,
627 .suspend = genphy_suspend,
628 .resume = genphy_resume,
629 .config_aneg = gpy_config_aneg,
630 .aneg_done = genphy_c45_aneg_done,
631 .read_status = gpy_read_status,
632 .config_intr = gpy_config_intr,
633 .handle_interrupt = gpy_handle_interrupt,
634 .set_wol = gpy_set_wol,
635 .get_wol = gpy_get_wol,
636 .set_loopback = gpy_loopback,
639 .phy_id = PHY_ID_GPY215B,
640 .phy_id_mask = PHY_ID_GPYx15B_MASK,
641 .name = "Maxlinear Ethernet GPY215B",
642 .get_features = genphy_c45_pma_read_abilities,
643 .config_init = gpy_config_init,
645 .suspend = genphy_suspend,
646 .resume = genphy_resume,
647 .config_aneg = gpy_config_aneg,
648 .aneg_done = genphy_c45_aneg_done,
649 .read_status = gpy_read_status,
650 .config_intr = gpy_config_intr,
651 .handle_interrupt = gpy_handle_interrupt,
652 .set_wol = gpy_set_wol,
653 .get_wol = gpy_get_wol,
654 .set_loopback = gpy_loopback,
657 PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
658 .name = "Maxlinear Ethernet GPY215C",
659 .get_features = genphy_c45_pma_read_abilities,
660 .config_init = gpy_config_init,
662 .suspend = genphy_suspend,
663 .resume = genphy_resume,
664 .config_aneg = gpy_config_aneg,
665 .aneg_done = genphy_c45_aneg_done,
666 .read_status = gpy_read_status,
667 .config_intr = gpy_config_intr,
668 .handle_interrupt = gpy_handle_interrupt,
669 .set_wol = gpy_set_wol,
670 .get_wol = gpy_get_wol,
671 .set_loopback = gpy_loopback,
674 PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
675 .name = "Maxlinear Ethernet GPY241B",
676 .get_features = genphy_c45_pma_read_abilities,
677 .config_init = gpy_config_init,
679 .suspend = genphy_suspend,
680 .resume = genphy_resume,
681 .config_aneg = gpy_config_aneg,
682 .aneg_done = genphy_c45_aneg_done,
683 .read_status = gpy_read_status,
684 .config_intr = gpy_config_intr,
685 .handle_interrupt = gpy_handle_interrupt,
686 .set_wol = gpy_set_wol,
687 .get_wol = gpy_get_wol,
688 .set_loopback = gpy_loopback,
691 PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM),
692 .name = "Maxlinear Ethernet GPY241BM",
693 .get_features = genphy_c45_pma_read_abilities,
694 .config_init = gpy_config_init,
696 .suspend = genphy_suspend,
697 .resume = genphy_resume,
698 .config_aneg = gpy_config_aneg,
699 .aneg_done = genphy_c45_aneg_done,
700 .read_status = gpy_read_status,
701 .config_intr = gpy_config_intr,
702 .handle_interrupt = gpy_handle_interrupt,
703 .set_wol = gpy_set_wol,
704 .get_wol = gpy_get_wol,
705 .set_loopback = gpy_loopback,
708 PHY_ID_MATCH_MODEL(PHY_ID_GPY245B),
709 .name = "Maxlinear Ethernet GPY245B",
710 .get_features = genphy_c45_pma_read_abilities,
711 .config_init = gpy_config_init,
713 .suspend = genphy_suspend,
714 .resume = genphy_resume,
715 .config_aneg = gpy_config_aneg,
716 .aneg_done = genphy_c45_aneg_done,
717 .read_status = gpy_read_status,
718 .config_intr = gpy_config_intr,
719 .handle_interrupt = gpy_handle_interrupt,
720 .set_wol = gpy_set_wol,
721 .get_wol = gpy_get_wol,
722 .set_loopback = gpy_loopback,
725 module_phy_driver(gpy_drivers);
727 static struct mdio_device_id __maybe_unused gpy_tbl[] = {
728 {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)},
729 {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK},
730 {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)},
731 {PHY_ID_GPY211B, PHY_ID_GPY21xB_MASK},
732 {PHY_ID_MATCH_MODEL(PHY_ID_GPY211C)},
733 {PHY_ID_GPY212B, PHY_ID_GPY21xB_MASK},
734 {PHY_ID_MATCH_MODEL(PHY_ID_GPY212C)},
735 {PHY_ID_GPY215B, PHY_ID_GPYx15B_MASK},
736 {PHY_ID_MATCH_MODEL(PHY_ID_GPY215C)},
737 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)},
738 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)},
739 {PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)},
742 MODULE_DEVICE_TABLE(mdio, gpy_tbl);
744 MODULE_DESCRIPTION("Maxlinear Ethernet GPY Driver");
745 MODULE_AUTHOR("Xu Liang");
746 MODULE_LICENSE("GPL");