Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0+
0002 /*
0003  * Marvell 88x2222 dual-port multi-speed ethernet transceiver.
0004  *
0005  * Supports:
0006  *  XAUI on the host side.
0007  *  1000Base-X or 10GBase-R on the line side.
0008  *  SGMII over 1000Base-X.
0009  */
0010 #include <linux/module.h>
0011 #include <linux/phy.h>
0012 #include <linux/gpio.h>
0013 #include <linux/delay.h>
0014 #include <linux/mdio.h>
0015 #include <linux/marvell_phy.h>
0016 #include <linux/of.h>
0017 #include <linux/of_device.h>
0018 #include <linux/of_gpio.h>
0019 #include <linux/sfp.h>
0020 #include <linux/netdevice.h>
0021 
0022 /* Port PCS Configuration */
0023 #define MV_PCS_CONFIG       0xF002
0024 #define MV_PCS_HOST_XAUI    0x73
0025 #define MV_PCS_LINE_10GBR   (0x71 << 8)
0026 #define MV_PCS_LINE_1GBX_AN (0x7B << 8)
0027 #define MV_PCS_LINE_SGMII_AN    (0x7F << 8)
0028 
0029 /* Port Reset and Power Down */
0030 #define MV_PORT_RST 0xF003
0031 #define MV_LINE_RST_SW  BIT(15)
0032 #define MV_HOST_RST_SW  BIT(7)
0033 #define MV_PORT_RST_SW  (MV_LINE_RST_SW | MV_HOST_RST_SW)
0034 
0035 /* PMD Receive Signal Detect */
0036 #define MV_RX_SIGNAL_DETECT     0x000A
0037 #define MV_RX_SIGNAL_DETECT_GLOBAL  BIT(0)
0038 
0039 /* 1000Base-X/SGMII Control Register */
0040 #define MV_1GBX_CTRL        (0x2000 + MII_BMCR)
0041 
0042 /* 1000BASE-X/SGMII Status Register */
0043 #define MV_1GBX_STAT        (0x2000 + MII_BMSR)
0044 
0045 /* 1000Base-X Auto-Negotiation Advertisement Register */
0046 #define MV_1GBX_ADVERTISE   (0x2000 + MII_ADVERTISE)
0047 
0048 /* 1000Base-X PHY Specific Status Register */
0049 #define MV_1GBX_PHY_STAT        0xA003
0050 #define MV_1GBX_PHY_STAT_AN_RESOLVED    BIT(11)
0051 #define MV_1GBX_PHY_STAT_DUPLEX     BIT(13)
0052 #define MV_1GBX_PHY_STAT_SPEED100   BIT(14)
0053 #define MV_1GBX_PHY_STAT_SPEED1000  BIT(15)
0054 
0055 #define AUTONEG_TIMEOUT 3
0056 
0057 struct mv2222_data {
0058     phy_interface_t line_interface;
0059     __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
0060     bool sfp_link;
0061 };
0062 
0063 /* SFI PMA transmit enable */
0064 static int mv2222_tx_enable(struct phy_device *phydev)
0065 {
0066     return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
0067                   MDIO_PMD_TXDIS_GLOBAL);
0068 }
0069 
0070 /* SFI PMA transmit disable */
0071 static int mv2222_tx_disable(struct phy_device *phydev)
0072 {
0073     return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
0074                 MDIO_PMD_TXDIS_GLOBAL);
0075 }
0076 
0077 static int mv2222_soft_reset(struct phy_device *phydev)
0078 {
0079     int val, ret;
0080 
0081     ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
0082                 MV_PORT_RST_SW);
0083     if (ret < 0)
0084         return ret;
0085 
0086     return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
0087                      val, !(val & MV_PORT_RST_SW),
0088                      5000, 1000000, true);
0089 }
0090 
0091 static int mv2222_disable_aneg(struct phy_device *phydev)
0092 {
0093     int ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL,
0094                      BMCR_ANENABLE | BMCR_ANRESTART);
0095     if (ret < 0)
0096         return ret;
0097 
0098     return mv2222_soft_reset(phydev);
0099 }
0100 
0101 static int mv2222_enable_aneg(struct phy_device *phydev)
0102 {
0103     int ret = phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL,
0104                    BMCR_ANENABLE | BMCR_RESET);
0105     if (ret < 0)
0106         return ret;
0107 
0108     return mv2222_soft_reset(phydev);
0109 }
0110 
0111 static int mv2222_set_sgmii_speed(struct phy_device *phydev)
0112 {
0113     struct mv2222_data *priv = phydev->priv;
0114 
0115     switch (phydev->speed) {
0116     default:
0117     case SPEED_1000:
0118         if ((linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
0119                        priv->supported) ||
0120              linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
0121                        priv->supported)))
0122             return phy_modify_mmd(phydev, MDIO_MMD_PCS,
0123                           MV_1GBX_CTRL,
0124                           BMCR_SPEED1000 | BMCR_SPEED100,
0125                           BMCR_SPEED1000);
0126 
0127         fallthrough;
0128     case SPEED_100:
0129         if ((linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
0130                        priv->supported) ||
0131              linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
0132                        priv->supported)))
0133             return phy_modify_mmd(phydev, MDIO_MMD_PCS,
0134                           MV_1GBX_CTRL,
0135                           BMCR_SPEED1000 | BMCR_SPEED100,
0136                           BMCR_SPEED100);
0137         fallthrough;
0138     case SPEED_10:
0139         if ((linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
0140                        priv->supported) ||
0141              linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
0142                        priv->supported)))
0143             return phy_modify_mmd(phydev, MDIO_MMD_PCS,
0144                           MV_1GBX_CTRL,
0145                           BMCR_SPEED1000 | BMCR_SPEED100,
0146                           BMCR_SPEED10);
0147 
0148         return -EINVAL;
0149     }
0150 }
0151 
0152 static bool mv2222_is_10g_capable(struct phy_device *phydev)
0153 {
0154     struct mv2222_data *priv = phydev->priv;
0155 
0156     return (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
0157                   priv->supported) ||
0158         linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
0159                   priv->supported) ||
0160         linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
0161                   priv->supported) ||
0162         linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
0163                   priv->supported) ||
0164         linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
0165                   priv->supported) ||
0166         linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
0167                   priv->supported));
0168 }
0169 
0170 static bool mv2222_is_1gbx_capable(struct phy_device *phydev)
0171 {
0172     struct mv2222_data *priv = phydev->priv;
0173 
0174     return linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
0175                  priv->supported);
0176 }
0177 
0178 static bool mv2222_is_sgmii_capable(struct phy_device *phydev)
0179 {
0180     struct mv2222_data *priv = phydev->priv;
0181 
0182     return (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
0183                   priv->supported) ||
0184         linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
0185                   priv->supported) ||
0186         linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
0187                   priv->supported) ||
0188         linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
0189                   priv->supported) ||
0190         linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
0191                   priv->supported) ||
0192         linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
0193                   priv->supported));
0194 }
0195 
0196 static int mv2222_config_line(struct phy_device *phydev)
0197 {
0198     struct mv2222_data *priv = phydev->priv;
0199 
0200     switch (priv->line_interface) {
0201     case PHY_INTERFACE_MODE_10GBASER:
0202         return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
0203                      MV_PCS_HOST_XAUI | MV_PCS_LINE_10GBR);
0204     case PHY_INTERFACE_MODE_1000BASEX:
0205         return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
0206                      MV_PCS_HOST_XAUI | MV_PCS_LINE_1GBX_AN);
0207     case PHY_INTERFACE_MODE_SGMII:
0208         return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
0209                      MV_PCS_HOST_XAUI | MV_PCS_LINE_SGMII_AN);
0210     default:
0211         return -EINVAL;
0212     }
0213 }
0214 
0215 /* Switch between 1G (1000Base-X/SGMII) and 10G (10GBase-R) modes */
0216 static int mv2222_swap_line_type(struct phy_device *phydev)
0217 {
0218     struct mv2222_data *priv = phydev->priv;
0219     bool changed = false;
0220     int ret;
0221 
0222     switch (priv->line_interface) {
0223     case PHY_INTERFACE_MODE_10GBASER:
0224         if (mv2222_is_1gbx_capable(phydev)) {
0225             priv->line_interface = PHY_INTERFACE_MODE_1000BASEX;
0226             changed = true;
0227         }
0228 
0229         if (mv2222_is_sgmii_capable(phydev)) {
0230             priv->line_interface = PHY_INTERFACE_MODE_SGMII;
0231             changed = true;
0232         }
0233 
0234         break;
0235     case PHY_INTERFACE_MODE_1000BASEX:
0236     case PHY_INTERFACE_MODE_SGMII:
0237         if (mv2222_is_10g_capable(phydev)) {
0238             priv->line_interface = PHY_INTERFACE_MODE_10GBASER;
0239             changed = true;
0240         }
0241 
0242         break;
0243     default:
0244         return -EINVAL;
0245     }
0246 
0247     if (changed) {
0248         ret = mv2222_config_line(phydev);
0249         if (ret < 0)
0250             return ret;
0251     }
0252 
0253     return 0;
0254 }
0255 
0256 static int mv2222_setup_forced(struct phy_device *phydev)
0257 {
0258     struct mv2222_data *priv = phydev->priv;
0259     int ret;
0260 
0261     if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER) {
0262         if (phydev->speed < SPEED_10000 &&
0263             phydev->speed != SPEED_UNKNOWN) {
0264             ret = mv2222_swap_line_type(phydev);
0265             if (ret < 0)
0266                 return ret;
0267         }
0268     }
0269 
0270     if (priv->line_interface == PHY_INTERFACE_MODE_SGMII) {
0271         ret = mv2222_set_sgmii_speed(phydev);
0272         if (ret < 0)
0273             return ret;
0274     }
0275 
0276     return mv2222_disable_aneg(phydev);
0277 }
0278 
0279 static int mv2222_config_aneg(struct phy_device *phydev)
0280 {
0281     struct mv2222_data *priv = phydev->priv;
0282     int ret, adv;
0283 
0284     /* SFP is not present, do nothing */
0285     if (priv->line_interface == PHY_INTERFACE_MODE_NA)
0286         return 0;
0287 
0288     if (phydev->autoneg == AUTONEG_DISABLE ||
0289         priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
0290         return mv2222_setup_forced(phydev);
0291 
0292     adv = linkmode_adv_to_mii_adv_x(priv->supported,
0293                     ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
0294 
0295     ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_ADVERTISE,
0296                  ADVERTISE_1000XFULL |
0297                  ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,
0298                  adv);
0299     if (ret < 0)
0300         return ret;
0301 
0302     return mv2222_enable_aneg(phydev);
0303 }
0304 
0305 static int mv2222_aneg_done(struct phy_device *phydev)
0306 {
0307     int ret;
0308 
0309     if (mv2222_is_10g_capable(phydev)) {
0310         ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
0311         if (ret < 0)
0312             return ret;
0313 
0314         if (ret & MDIO_STAT1_LSTATUS)
0315             return 1;
0316     }
0317 
0318     ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
0319     if (ret < 0)
0320         return ret;
0321 
0322     return (ret & BMSR_ANEGCOMPLETE);
0323 }
0324 
0325 /* Returns negative on error, 0 if link is down, 1 if link is up */
0326 static int mv2222_read_status_10g(struct phy_device *phydev)
0327 {
0328     static int timeout;
0329     int val, link = 0;
0330 
0331     val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
0332     if (val < 0)
0333         return val;
0334 
0335     if (val & MDIO_STAT1_LSTATUS) {
0336         link = 1;
0337 
0338         /* 10GBASE-R do not support auto-negotiation */
0339         phydev->autoneg = AUTONEG_DISABLE;
0340         phydev->speed = SPEED_10000;
0341         phydev->duplex = DUPLEX_FULL;
0342     } else {
0343         if (phydev->autoneg == AUTONEG_ENABLE) {
0344             timeout++;
0345 
0346             if (timeout > AUTONEG_TIMEOUT) {
0347                 timeout = 0;
0348 
0349                 val = mv2222_swap_line_type(phydev);
0350                 if (val < 0)
0351                     return val;
0352 
0353                 return mv2222_config_aneg(phydev);
0354             }
0355         }
0356     }
0357 
0358     return link;
0359 }
0360 
0361 /* Returns negative on error, 0 if link is down, 1 if link is up */
0362 static int mv2222_read_status_1g(struct phy_device *phydev)
0363 {
0364     static int timeout;
0365     int val, link = 0;
0366 
0367     val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
0368     if (val < 0)
0369         return val;
0370 
0371     if (phydev->autoneg == AUTONEG_ENABLE &&
0372         !(val & BMSR_ANEGCOMPLETE)) {
0373         timeout++;
0374 
0375         if (timeout > AUTONEG_TIMEOUT) {
0376             timeout = 0;
0377 
0378             val = mv2222_swap_line_type(phydev);
0379             if (val < 0)
0380                 return val;
0381 
0382             return mv2222_config_aneg(phydev);
0383         }
0384 
0385         return 0;
0386     }
0387 
0388     if (!(val & BMSR_LSTATUS))
0389         return 0;
0390 
0391     link = 1;
0392 
0393     val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_PHY_STAT);
0394     if (val < 0)
0395         return val;
0396 
0397     if (val & MV_1GBX_PHY_STAT_AN_RESOLVED) {
0398         if (val & MV_1GBX_PHY_STAT_DUPLEX)
0399             phydev->duplex = DUPLEX_FULL;
0400         else
0401             phydev->duplex = DUPLEX_HALF;
0402 
0403         if (val & MV_1GBX_PHY_STAT_SPEED1000)
0404             phydev->speed = SPEED_1000;
0405         else if (val & MV_1GBX_PHY_STAT_SPEED100)
0406             phydev->speed = SPEED_100;
0407         else
0408             phydev->speed = SPEED_10;
0409     }
0410 
0411     return link;
0412 }
0413 
0414 static bool mv2222_link_is_operational(struct phy_device *phydev)
0415 {
0416     struct mv2222_data *priv = phydev->priv;
0417     int val;
0418 
0419     val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_RX_SIGNAL_DETECT);
0420     if (val < 0 || !(val & MV_RX_SIGNAL_DETECT_GLOBAL))
0421         return false;
0422 
0423     if (phydev->sfp_bus && !priv->sfp_link)
0424         return false;
0425 
0426     return true;
0427 }
0428 
0429 static int mv2222_read_status(struct phy_device *phydev)
0430 {
0431     struct mv2222_data *priv = phydev->priv;
0432     int link;
0433 
0434     phydev->link = 0;
0435     phydev->speed = SPEED_UNKNOWN;
0436     phydev->duplex = DUPLEX_UNKNOWN;
0437 
0438     if (!mv2222_link_is_operational(phydev))
0439         return 0;
0440 
0441     if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
0442         link = mv2222_read_status_10g(phydev);
0443     else
0444         link = mv2222_read_status_1g(phydev);
0445 
0446     if (link < 0)
0447         return link;
0448 
0449     phydev->link = link;
0450 
0451     return 0;
0452 }
0453 
0454 static int mv2222_resume(struct phy_device *phydev)
0455 {
0456     return mv2222_tx_enable(phydev);
0457 }
0458 
0459 static int mv2222_suspend(struct phy_device *phydev)
0460 {
0461     return mv2222_tx_disable(phydev);
0462 }
0463 
0464 static int mv2222_get_features(struct phy_device *phydev)
0465 {
0466     /* All supported linkmodes are set at probe */
0467 
0468     return 0;
0469 }
0470 
0471 static int mv2222_config_init(struct phy_device *phydev)
0472 {
0473     if (phydev->interface != PHY_INTERFACE_MODE_XAUI)
0474         return -EINVAL;
0475 
0476     return 0;
0477 }
0478 
0479 static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
0480 {
0481     struct phy_device *phydev = upstream;
0482     phy_interface_t sfp_interface;
0483     struct mv2222_data *priv;
0484     struct device *dev;
0485     int ret;
0486 
0487     __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_supported) = { 0, };
0488 
0489     priv = (struct mv2222_data *)phydev->priv;
0490     dev = &phydev->mdio.dev;
0491 
0492     sfp_parse_support(phydev->sfp_bus, id, sfp_supported);
0493     phydev->port = sfp_parse_port(phydev->sfp_bus, id, sfp_supported);
0494     sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported);
0495 
0496     dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface));
0497 
0498     if (sfp_interface != PHY_INTERFACE_MODE_10GBASER &&
0499         sfp_interface != PHY_INTERFACE_MODE_1000BASEX &&
0500         sfp_interface != PHY_INTERFACE_MODE_SGMII) {
0501         dev_err(dev, "Incompatible SFP module inserted\n");
0502 
0503         return -EINVAL;
0504     }
0505 
0506     priv->line_interface = sfp_interface;
0507     linkmode_and(priv->supported, phydev->supported, sfp_supported);
0508 
0509     ret = mv2222_config_line(phydev);
0510     if (ret < 0)
0511         return ret;
0512 
0513     if (mutex_trylock(&phydev->lock)) {
0514         ret = mv2222_config_aneg(phydev);
0515         mutex_unlock(&phydev->lock);
0516     }
0517 
0518     return ret;
0519 }
0520 
0521 static void mv2222_sfp_remove(void *upstream)
0522 {
0523     struct phy_device *phydev = upstream;
0524     struct mv2222_data *priv;
0525 
0526     priv = (struct mv2222_data *)phydev->priv;
0527 
0528     priv->line_interface = PHY_INTERFACE_MODE_NA;
0529     linkmode_zero(priv->supported);
0530     phydev->port = PORT_NONE;
0531 }
0532 
0533 static void mv2222_sfp_link_up(void *upstream)
0534 {
0535     struct phy_device *phydev = upstream;
0536     struct mv2222_data *priv;
0537 
0538     priv = phydev->priv;
0539     priv->sfp_link = true;
0540 }
0541 
0542 static void mv2222_sfp_link_down(void *upstream)
0543 {
0544     struct phy_device *phydev = upstream;
0545     struct mv2222_data *priv;
0546 
0547     priv = phydev->priv;
0548     priv->sfp_link = false;
0549 }
0550 
0551 static const struct sfp_upstream_ops sfp_phy_ops = {
0552     .module_insert = mv2222_sfp_insert,
0553     .module_remove = mv2222_sfp_remove,
0554     .link_up = mv2222_sfp_link_up,
0555     .link_down = mv2222_sfp_link_down,
0556     .attach = phy_sfp_attach,
0557     .detach = phy_sfp_detach,
0558 };
0559 
0560 static int mv2222_probe(struct phy_device *phydev)
0561 {
0562     struct device *dev = &phydev->mdio.dev;
0563     struct mv2222_data *priv = NULL;
0564 
0565     __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
0566 
0567     linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
0568     linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
0569     linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
0570     linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
0571     linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
0572     linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, supported);
0573     linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, supported);
0574     linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, supported);
0575     linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, supported);
0576     linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, supported);
0577     linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, supported);
0578     linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, supported);
0579     linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, supported);
0580     linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, supported);
0581     linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported);
0582     linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported);
0583     linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, supported);
0584     linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported);
0585 
0586     linkmode_copy(phydev->supported, supported);
0587 
0588     priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0589     if (!priv)
0590         return -ENOMEM;
0591 
0592     priv->line_interface = PHY_INTERFACE_MODE_NA;
0593     phydev->priv = priv;
0594 
0595     return phy_sfp_probe(phydev, &sfp_phy_ops);
0596 }
0597 
0598 static struct phy_driver mv2222_drivers[] = {
0599     {
0600         .phy_id = MARVELL_PHY_ID_88X2222,
0601         .phy_id_mask = MARVELL_PHY_ID_MASK,
0602         .name = "Marvell 88X2222",
0603         .get_features = mv2222_get_features,
0604         .soft_reset = mv2222_soft_reset,
0605         .config_init = mv2222_config_init,
0606         .config_aneg = mv2222_config_aneg,
0607         .aneg_done = mv2222_aneg_done,
0608         .probe = mv2222_probe,
0609         .suspend = mv2222_suspend,
0610         .resume = mv2222_resume,
0611         .read_status = mv2222_read_status,
0612     },
0613 };
0614 module_phy_driver(mv2222_drivers);
0615 
0616 static struct mdio_device_id __maybe_unused mv2222_tbl[] = {
0617     { MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK },
0618     { }
0619 };
0620 MODULE_DEVICE_TABLE(mdio, mv2222_tbl);
0621 
0622 MODULE_DESCRIPTION("Marvell 88x2222 ethernet transceiver driver");
0623 MODULE_LICENSE("GPL");