linux/drivers/net/phy/marvell-88x2222.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Marvell 88x2222 dual-port multi-speed ethernet transceiver.
   4 *
   5 * Supports:
   6 *      XAUI on the host side.
   7 *      1000Base-X or 10GBase-R on the line side.
   8 *      SGMII over 1000Base-X.
   9 */
  10#include <linux/module.h>
  11#include <linux/phy.h>
  12#include <linux/gpio.h>
  13#include <linux/delay.h>
  14#include <linux/mdio.h>
  15#include <linux/marvell_phy.h>
  16#include <linux/of.h>
  17#include <linux/of_device.h>
  18#include <linux/of_gpio.h>
  19#include <linux/sfp.h>
  20#include <linux/netdevice.h>
  21
  22/* Port PCS Configuration */
  23#define MV_PCS_CONFIG           0xF002
  24#define MV_PCS_HOST_XAUI        0x73
  25#define MV_PCS_LINE_10GBR       (0x71 << 8)
  26#define MV_PCS_LINE_1GBX_AN     (0x7B << 8)
  27#define MV_PCS_LINE_SGMII_AN    (0x7F << 8)
  28
  29/* Port Reset and Power Down */
  30#define MV_PORT_RST     0xF003
  31#define MV_LINE_RST_SW  BIT(15)
  32#define MV_HOST_RST_SW  BIT(7)
  33#define MV_PORT_RST_SW  (MV_LINE_RST_SW | MV_HOST_RST_SW)
  34
  35/* PMD Receive Signal Detect */
  36#define MV_RX_SIGNAL_DETECT             0x000A
  37#define MV_RX_SIGNAL_DETECT_GLOBAL      BIT(0)
  38
  39/* 1000Base-X/SGMII Control Register */
  40#define MV_1GBX_CTRL            (0x2000 + MII_BMCR)
  41
  42/* 1000BASE-X/SGMII Status Register */
  43#define MV_1GBX_STAT            (0x2000 + MII_BMSR)
  44
  45/* 1000Base-X Auto-Negotiation Advertisement Register */
  46#define MV_1GBX_ADVERTISE       (0x2000 + MII_ADVERTISE)
  47
  48/* 1000Base-X PHY Specific Status Register */
  49#define MV_1GBX_PHY_STAT                0xA003
  50#define MV_1GBX_PHY_STAT_AN_RESOLVED    BIT(11)
  51#define MV_1GBX_PHY_STAT_DUPLEX         BIT(13)
  52#define MV_1GBX_PHY_STAT_SPEED100       BIT(14)
  53#define MV_1GBX_PHY_STAT_SPEED1000      BIT(15)
  54
  55#define AUTONEG_TIMEOUT 3
  56
  57struct mv2222_data {
  58        phy_interface_t line_interface;
  59        __ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
  60        bool sfp_link;
  61};
  62
  63/* SFI PMA transmit enable */
  64static int mv2222_tx_enable(struct phy_device *phydev)
  65{
  66        return phy_clear_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
  67                                  MDIO_PMD_TXDIS_GLOBAL);
  68}
  69
  70/* SFI PMA transmit disable */
  71static int mv2222_tx_disable(struct phy_device *phydev)
  72{
  73        return phy_set_bits_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_TXDIS,
  74                                MDIO_PMD_TXDIS_GLOBAL);
  75}
  76
  77static int mv2222_soft_reset(struct phy_device *phydev)
  78{
  79        int val, ret;
  80
  81        ret = phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
  82                            MV_PORT_RST_SW);
  83        if (ret < 0)
  84                return ret;
  85
  86        return phy_read_mmd_poll_timeout(phydev, MDIO_MMD_VEND2, MV_PORT_RST,
  87                                         val, !(val & MV_PORT_RST_SW),
  88                                         5000, 1000000, true);
  89}
  90
  91static int mv2222_disable_aneg(struct phy_device *phydev)
  92{
  93        int ret = phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL,
  94                                     BMCR_ANENABLE | BMCR_ANRESTART);
  95        if (ret < 0)
  96                return ret;
  97
  98        return mv2222_soft_reset(phydev);
  99}
 100
 101static int mv2222_enable_aneg(struct phy_device *phydev)
 102{
 103        int ret = phy_set_bits_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_CTRL,
 104                                   BMCR_ANENABLE | BMCR_RESET);
 105        if (ret < 0)
 106                return ret;
 107
 108        return mv2222_soft_reset(phydev);
 109}
 110
 111static int mv2222_set_sgmii_speed(struct phy_device *phydev)
 112{
 113        struct mv2222_data *priv = phydev->priv;
 114
 115        switch (phydev->speed) {
 116        default:
 117        case SPEED_1000:
 118                if ((linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
 119                                       priv->supported) ||
 120                     linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
 121                                       priv->supported)))
 122                        return phy_modify_mmd(phydev, MDIO_MMD_PCS,
 123                                              MV_1GBX_CTRL,
 124                                              BMCR_SPEED1000 | BMCR_SPEED100,
 125                                              BMCR_SPEED1000);
 126
 127                fallthrough;
 128        case SPEED_100:
 129                if ((linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
 130                                       priv->supported) ||
 131                     linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
 132                                       priv->supported)))
 133                        return phy_modify_mmd(phydev, MDIO_MMD_PCS,
 134                                              MV_1GBX_CTRL,
 135                                              BMCR_SPEED1000 | BMCR_SPEED100,
 136                                              BMCR_SPEED100);
 137                fallthrough;
 138        case SPEED_10:
 139                if ((linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
 140                                       priv->supported) ||
 141                     linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
 142                                       priv->supported)))
 143                        return phy_modify_mmd(phydev, MDIO_MMD_PCS,
 144                                              MV_1GBX_CTRL,
 145                                              BMCR_SPEED1000 | BMCR_SPEED100,
 146                                              BMCR_SPEED10);
 147
 148                return -EINVAL;
 149        }
 150}
 151
 152static bool mv2222_is_10g_capable(struct phy_device *phydev)
 153{
 154        struct mv2222_data *priv = phydev->priv;
 155
 156        return (linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
 157                                  priv->supported) ||
 158                linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT,
 159                                  priv->supported) ||
 160                linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
 161                                  priv->supported) ||
 162                linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
 163                                  priv->supported) ||
 164                linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
 165                                  priv->supported) ||
 166                linkmode_test_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
 167                                  priv->supported));
 168}
 169
 170static bool mv2222_is_1gbx_capable(struct phy_device *phydev)
 171{
 172        struct mv2222_data *priv = phydev->priv;
 173
 174        return linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
 175                                 priv->supported);
 176}
 177
 178static bool mv2222_is_sgmii_capable(struct phy_device *phydev)
 179{
 180        struct mv2222_data *priv = phydev->priv;
 181
 182        return (linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
 183                                  priv->supported) ||
 184                linkmode_test_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
 185                                  priv->supported) ||
 186                linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
 187                                  priv->supported) ||
 188                linkmode_test_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
 189                                  priv->supported) ||
 190                linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
 191                                  priv->supported) ||
 192                linkmode_test_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
 193                                  priv->supported));
 194}
 195
 196static int mv2222_config_line(struct phy_device *phydev)
 197{
 198        struct mv2222_data *priv = phydev->priv;
 199
 200        switch (priv->line_interface) {
 201        case PHY_INTERFACE_MODE_10GBASER:
 202                return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
 203                                     MV_PCS_HOST_XAUI | MV_PCS_LINE_10GBR);
 204        case PHY_INTERFACE_MODE_1000BASEX:
 205                return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
 206                                     MV_PCS_HOST_XAUI | MV_PCS_LINE_1GBX_AN);
 207        case PHY_INTERFACE_MODE_SGMII:
 208                return phy_write_mmd(phydev, MDIO_MMD_VEND2, MV_PCS_CONFIG,
 209                                     MV_PCS_HOST_XAUI | MV_PCS_LINE_SGMII_AN);
 210        default:
 211                return -EINVAL;
 212        }
 213}
 214
 215/* Switch between 1G (1000Base-X/SGMII) and 10G (10GBase-R) modes */
 216static int mv2222_swap_line_type(struct phy_device *phydev)
 217{
 218        struct mv2222_data *priv = phydev->priv;
 219        bool changed = false;
 220        int ret;
 221
 222        switch (priv->line_interface) {
 223        case PHY_INTERFACE_MODE_10GBASER:
 224                if (mv2222_is_1gbx_capable(phydev)) {
 225                        priv->line_interface = PHY_INTERFACE_MODE_1000BASEX;
 226                        changed = true;
 227                }
 228
 229                if (mv2222_is_sgmii_capable(phydev)) {
 230                        priv->line_interface = PHY_INTERFACE_MODE_SGMII;
 231                        changed = true;
 232                }
 233
 234                break;
 235        case PHY_INTERFACE_MODE_1000BASEX:
 236        case PHY_INTERFACE_MODE_SGMII:
 237                if (mv2222_is_10g_capable(phydev)) {
 238                        priv->line_interface = PHY_INTERFACE_MODE_10GBASER;
 239                        changed = true;
 240                }
 241
 242                break;
 243        default:
 244                return -EINVAL;
 245        }
 246
 247        if (changed) {
 248                ret = mv2222_config_line(phydev);
 249                if (ret < 0)
 250                        return ret;
 251        }
 252
 253        return 0;
 254}
 255
 256static int mv2222_setup_forced(struct phy_device *phydev)
 257{
 258        struct mv2222_data *priv = phydev->priv;
 259        int ret;
 260
 261        if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER) {
 262                if (phydev->speed < SPEED_10000 &&
 263                    phydev->speed != SPEED_UNKNOWN) {
 264                        ret = mv2222_swap_line_type(phydev);
 265                        if (ret < 0)
 266                                return ret;
 267                }
 268        }
 269
 270        if (priv->line_interface == PHY_INTERFACE_MODE_SGMII) {
 271                ret = mv2222_set_sgmii_speed(phydev);
 272                if (ret < 0)
 273                        return ret;
 274        }
 275
 276        return mv2222_disable_aneg(phydev);
 277}
 278
 279static int mv2222_config_aneg(struct phy_device *phydev)
 280{
 281        struct mv2222_data *priv = phydev->priv;
 282        int ret, adv;
 283
 284        /* SFP is not present, do nothing */
 285        if (priv->line_interface == PHY_INTERFACE_MODE_NA)
 286                return 0;
 287
 288        if (phydev->autoneg == AUTONEG_DISABLE ||
 289            priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
 290                return mv2222_setup_forced(phydev);
 291
 292        adv = linkmode_adv_to_mii_adv_x(priv->supported,
 293                                        ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
 294
 295        ret = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_ADVERTISE,
 296                             ADVERTISE_1000XFULL |
 297                             ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM,
 298                             adv);
 299        if (ret < 0)
 300                return ret;
 301
 302        return mv2222_enable_aneg(phydev);
 303}
 304
 305static int mv2222_aneg_done(struct phy_device *phydev)
 306{
 307        int ret;
 308
 309        if (mv2222_is_10g_capable(phydev)) {
 310                ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
 311                if (ret < 0)
 312                        return ret;
 313
 314                if (ret & MDIO_STAT1_LSTATUS)
 315                        return 1;
 316        }
 317
 318        ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
 319        if (ret < 0)
 320                return ret;
 321
 322        return (ret & BMSR_ANEGCOMPLETE);
 323}
 324
 325/* Returns negative on error, 0 if link is down, 1 if link is up */
 326static int mv2222_read_status_10g(struct phy_device *phydev)
 327{
 328        static int timeout;
 329        int val, link = 0;
 330
 331        val = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_STAT1);
 332        if (val < 0)
 333                return val;
 334
 335        if (val & MDIO_STAT1_LSTATUS) {
 336                link = 1;
 337
 338                /* 10GBASE-R do not support auto-negotiation */
 339                phydev->autoneg = AUTONEG_DISABLE;
 340                phydev->speed = SPEED_10000;
 341                phydev->duplex = DUPLEX_FULL;
 342        } else {
 343                if (phydev->autoneg == AUTONEG_ENABLE) {
 344                        timeout++;
 345
 346                        if (timeout > AUTONEG_TIMEOUT) {
 347                                timeout = 0;
 348
 349                                val = mv2222_swap_line_type(phydev);
 350                                if (val < 0)
 351                                        return val;
 352
 353                                return mv2222_config_aneg(phydev);
 354                        }
 355                }
 356        }
 357
 358        return link;
 359}
 360
 361/* Returns negative on error, 0 if link is down, 1 if link is up */
 362static int mv2222_read_status_1g(struct phy_device *phydev)
 363{
 364        static int timeout;
 365        int val, link = 0;
 366
 367        val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_STAT);
 368        if (val < 0)
 369                return val;
 370
 371        if (phydev->autoneg == AUTONEG_ENABLE &&
 372            !(val & BMSR_ANEGCOMPLETE)) {
 373                timeout++;
 374
 375                if (timeout > AUTONEG_TIMEOUT) {
 376                        timeout = 0;
 377
 378                        val = mv2222_swap_line_type(phydev);
 379                        if (val < 0)
 380                                return val;
 381
 382                        return mv2222_config_aneg(phydev);
 383                }
 384
 385                return 0;
 386        }
 387
 388        if (!(val & BMSR_LSTATUS))
 389                return 0;
 390
 391        link = 1;
 392
 393        val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_1GBX_PHY_STAT);
 394        if (val < 0)
 395                return val;
 396
 397        if (val & MV_1GBX_PHY_STAT_AN_RESOLVED) {
 398                if (val & MV_1GBX_PHY_STAT_DUPLEX)
 399                        phydev->duplex = DUPLEX_FULL;
 400                else
 401                        phydev->duplex = DUPLEX_HALF;
 402
 403                if (val & MV_1GBX_PHY_STAT_SPEED1000)
 404                        phydev->speed = SPEED_1000;
 405                else if (val & MV_1GBX_PHY_STAT_SPEED100)
 406                        phydev->speed = SPEED_100;
 407                else
 408                        phydev->speed = SPEED_10;
 409        }
 410
 411        return link;
 412}
 413
 414static bool mv2222_link_is_operational(struct phy_device *phydev)
 415{
 416        struct mv2222_data *priv = phydev->priv;
 417        int val;
 418
 419        val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MV_RX_SIGNAL_DETECT);
 420        if (val < 0 || !(val & MV_RX_SIGNAL_DETECT_GLOBAL))
 421                return false;
 422
 423        if (phydev->sfp_bus && !priv->sfp_link)
 424                return false;
 425
 426        return true;
 427}
 428
 429static int mv2222_read_status(struct phy_device *phydev)
 430{
 431        struct mv2222_data *priv = phydev->priv;
 432        int link;
 433
 434        phydev->link = 0;
 435        phydev->speed = SPEED_UNKNOWN;
 436        phydev->duplex = DUPLEX_UNKNOWN;
 437
 438        if (!mv2222_link_is_operational(phydev))
 439                return 0;
 440
 441        if (priv->line_interface == PHY_INTERFACE_MODE_10GBASER)
 442                link = mv2222_read_status_10g(phydev);
 443        else
 444                link = mv2222_read_status_1g(phydev);
 445
 446        if (link < 0)
 447                return link;
 448
 449        phydev->link = link;
 450
 451        return 0;
 452}
 453
 454static int mv2222_resume(struct phy_device *phydev)
 455{
 456        return mv2222_tx_enable(phydev);
 457}
 458
 459static int mv2222_suspend(struct phy_device *phydev)
 460{
 461        return mv2222_tx_disable(phydev);
 462}
 463
 464static int mv2222_get_features(struct phy_device *phydev)
 465{
 466        /* All supported linkmodes are set at probe */
 467
 468        return 0;
 469}
 470
 471static int mv2222_config_init(struct phy_device *phydev)
 472{
 473        if (phydev->interface != PHY_INTERFACE_MODE_XAUI)
 474                return -EINVAL;
 475
 476        return 0;
 477}
 478
 479static int mv2222_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
 480{
 481        struct phy_device *phydev = upstream;
 482        phy_interface_t sfp_interface;
 483        struct mv2222_data *priv;
 484        struct device *dev;
 485        int ret;
 486
 487        __ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_supported) = { 0, };
 488
 489        priv = (struct mv2222_data *)phydev->priv;
 490        dev = &phydev->mdio.dev;
 491
 492        sfp_parse_support(phydev->sfp_bus, id, sfp_supported);
 493        sfp_interface = sfp_select_interface(phydev->sfp_bus, sfp_supported);
 494
 495        dev_info(dev, "%s SFP module inserted\n", phy_modes(sfp_interface));
 496
 497        if (sfp_interface != PHY_INTERFACE_MODE_10GBASER &&
 498            sfp_interface != PHY_INTERFACE_MODE_1000BASEX &&
 499            sfp_interface != PHY_INTERFACE_MODE_SGMII) {
 500                dev_err(dev, "Incompatible SFP module inserted\n");
 501
 502                return -EINVAL;
 503        }
 504
 505        priv->line_interface = sfp_interface;
 506        linkmode_and(priv->supported, phydev->supported, sfp_supported);
 507
 508        ret = mv2222_config_line(phydev);
 509        if (ret < 0)
 510                return ret;
 511
 512        if (mutex_trylock(&phydev->lock)) {
 513                ret = mv2222_config_aneg(phydev);
 514                mutex_unlock(&phydev->lock);
 515        }
 516
 517        return ret;
 518}
 519
 520static void mv2222_sfp_remove(void *upstream)
 521{
 522        struct phy_device *phydev = upstream;
 523        struct mv2222_data *priv;
 524
 525        priv = (struct mv2222_data *)phydev->priv;
 526
 527        priv->line_interface = PHY_INTERFACE_MODE_NA;
 528        linkmode_zero(priv->supported);
 529}
 530
 531static void mv2222_sfp_link_up(void *upstream)
 532{
 533        struct phy_device *phydev = upstream;
 534        struct mv2222_data *priv;
 535
 536        priv = phydev->priv;
 537        priv->sfp_link = true;
 538}
 539
 540static void mv2222_sfp_link_down(void *upstream)
 541{
 542        struct phy_device *phydev = upstream;
 543        struct mv2222_data *priv;
 544
 545        priv = phydev->priv;
 546        priv->sfp_link = false;
 547}
 548
 549static const struct sfp_upstream_ops sfp_phy_ops = {
 550        .module_insert = mv2222_sfp_insert,
 551        .module_remove = mv2222_sfp_remove,
 552        .link_up = mv2222_sfp_link_up,
 553        .link_down = mv2222_sfp_link_down,
 554        .attach = phy_sfp_attach,
 555        .detach = phy_sfp_detach,
 556};
 557
 558static int mv2222_probe(struct phy_device *phydev)
 559{
 560        struct device *dev = &phydev->mdio.dev;
 561        struct mv2222_data *priv = NULL;
 562
 563        __ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
 564
 565        linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
 566        linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
 567        linkmode_set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
 568        linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
 569        linkmode_set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
 570        linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT, supported);
 571        linkmode_set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT, supported);
 572        linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT, supported);
 573        linkmode_set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT, supported);
 574        linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT, supported);
 575        linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT, supported);
 576        linkmode_set_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT, supported);
 577        linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT, supported);
 578        linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseCR_Full_BIT, supported);
 579        linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported);
 580        linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported);
 581        linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT, supported);
 582        linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported);
 583
 584        linkmode_copy(phydev->supported, supported);
 585
 586        priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
 587        if (!priv)
 588                return -ENOMEM;
 589
 590        priv->line_interface = PHY_INTERFACE_MODE_NA;
 591        phydev->priv = priv;
 592
 593        return phy_sfp_probe(phydev, &sfp_phy_ops);
 594}
 595
 596static struct phy_driver mv2222_drivers[] = {
 597        {
 598                .phy_id = MARVELL_PHY_ID_88X2222,
 599                .phy_id_mask = MARVELL_PHY_ID_MASK,
 600                .name = "Marvell 88X2222",
 601                .get_features = mv2222_get_features,
 602                .soft_reset = mv2222_soft_reset,
 603                .config_init = mv2222_config_init,
 604                .config_aneg = mv2222_config_aneg,
 605                .aneg_done = mv2222_aneg_done,
 606                .probe = mv2222_probe,
 607                .suspend = mv2222_suspend,
 608                .resume = mv2222_resume,
 609                .read_status = mv2222_read_status,
 610        },
 611};
 612module_phy_driver(mv2222_drivers);
 613
 614static struct mdio_device_id __maybe_unused mv2222_tbl[] = {
 615        { MARVELL_PHY_ID_88X2222, MARVELL_PHY_ID_MASK },
 616        { }
 617};
 618MODULE_DEVICE_TABLE(mdio, mv2222_tbl);
 619
 620MODULE_DESCRIPTION("Marvell 88x2222 ethernet transceiver driver");
 621MODULE_LICENSE("GPL");
 622