linux/drivers/net/phy/dp83822.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Driver for the Texas Instruments DP83822, DP83825 and DP83826 PHYs.
   3 *
   4 * Copyright (C) 2017 Texas Instruments Inc.
   5 */
   6
   7#include <linux/ethtool.h>
   8#include <linux/etherdevice.h>
   9#include <linux/kernel.h>
  10#include <linux/mii.h>
  11#include <linux/module.h>
  12#include <linux/of.h>
  13#include <linux/phy.h>
  14#include <linux/netdevice.h>
  15
  16#define DP83822_PHY_ID          0x2000a240
  17#define DP83825S_PHY_ID         0x2000a140
  18#define DP83825I_PHY_ID         0x2000a150
  19#define DP83825CM_PHY_ID        0x2000a160
  20#define DP83825CS_PHY_ID        0x2000a170
  21#define DP83826C_PHY_ID         0x2000a130
  22#define DP83826NC_PHY_ID        0x2000a110
  23
  24#define DP83822_DEVADDR         0x1f
  25
  26#define MII_DP83822_CTRL_2      0x0a
  27#define MII_DP83822_PHYSTS      0x10
  28#define MII_DP83822_PHYSCR      0x11
  29#define MII_DP83822_MISR1       0x12
  30#define MII_DP83822_MISR2       0x13
  31#define MII_DP83822_FCSCR       0x14
  32#define MII_DP83822_RCSR        0x17
  33#define MII_DP83822_RESET_CTRL  0x1f
  34#define MII_DP83822_GENCFG      0x465
  35#define MII_DP83822_SOR1        0x467
  36
  37/* GENCFG */
  38#define DP83822_SIG_DET_LOW     BIT(0)
  39
  40/* Control Register 2 bits */
  41#define DP83822_FX_ENABLE       BIT(14)
  42
  43#define DP83822_HW_RESET        BIT(15)
  44#define DP83822_SW_RESET        BIT(14)
  45
  46/* PHY STS bits */
  47#define DP83822_PHYSTS_DUPLEX                   BIT(2)
  48#define DP83822_PHYSTS_10                       BIT(1)
  49#define DP83822_PHYSTS_LINK                     BIT(0)
  50
  51/* PHYSCR Register Fields */
  52#define DP83822_PHYSCR_INT_OE           BIT(0) /* Interrupt Output Enable */
  53#define DP83822_PHYSCR_INTEN            BIT(1) /* Interrupt Enable */
  54
  55/* MISR1 bits */
  56#define DP83822_RX_ERR_HF_INT_EN        BIT(0)
  57#define DP83822_FALSE_CARRIER_HF_INT_EN BIT(1)
  58#define DP83822_ANEG_COMPLETE_INT_EN    BIT(2)
  59#define DP83822_DUP_MODE_CHANGE_INT_EN  BIT(3)
  60#define DP83822_SPEED_CHANGED_INT_EN    BIT(4)
  61#define DP83822_LINK_STAT_INT_EN        BIT(5)
  62#define DP83822_ENERGY_DET_INT_EN       BIT(6)
  63#define DP83822_LINK_QUAL_INT_EN        BIT(7)
  64
  65/* MISR2 bits */
  66#define DP83822_JABBER_DET_INT_EN       BIT(0)
  67#define DP83822_WOL_PKT_INT_EN          BIT(1)
  68#define DP83822_SLEEP_MODE_INT_EN       BIT(2)
  69#define DP83822_MDI_XOVER_INT_EN        BIT(3)
  70#define DP83822_LB_FIFO_INT_EN          BIT(4)
  71#define DP83822_PAGE_RX_INT_EN          BIT(5)
  72#define DP83822_ANEG_ERR_INT_EN         BIT(6)
  73#define DP83822_EEE_ERROR_CHANGE_INT_EN BIT(7)
  74
  75/* INT_STAT1 bits */
  76#define DP83822_WOL_INT_EN      BIT(4)
  77#define DP83822_WOL_INT_STAT    BIT(12)
  78
  79#define MII_DP83822_RXSOP1      0x04a5
  80#define MII_DP83822_RXSOP2      0x04a6
  81#define MII_DP83822_RXSOP3      0x04a7
  82
  83/* WoL Registers */
  84#define MII_DP83822_WOL_CFG     0x04a0
  85#define MII_DP83822_WOL_STAT    0x04a1
  86#define MII_DP83822_WOL_DA1     0x04a2
  87#define MII_DP83822_WOL_DA2     0x04a3
  88#define MII_DP83822_WOL_DA3     0x04a4
  89
  90/* WoL bits */
  91#define DP83822_WOL_MAGIC_EN    BIT(0)
  92#define DP83822_WOL_SECURE_ON   BIT(5)
  93#define DP83822_WOL_EN          BIT(7)
  94#define DP83822_WOL_INDICATION_SEL BIT(8)
  95#define DP83822_WOL_CLR_INDICATION BIT(11)
  96
  97/* RSCR bits */
  98#define DP83822_RX_CLK_SHIFT    BIT(12)
  99#define DP83822_TX_CLK_SHIFT    BIT(11)
 100
 101/* SOR1 mode */
 102#define DP83822_STRAP_MODE1     0
 103#define DP83822_STRAP_MODE2     BIT(0)
 104#define DP83822_STRAP_MODE3     BIT(1)
 105#define DP83822_STRAP_MODE4     GENMASK(1, 0)
 106
 107#define DP83822_COL_STRAP_MASK  GENMASK(11, 10)
 108#define DP83822_COL_SHIFT       10
 109#define DP83822_RX_ER_STR_MASK  GENMASK(9, 8)
 110#define DP83822_RX_ER_SHIFT     8
 111
 112#define MII_DP83822_FIBER_ADVERTISE    (ADVERTISED_TP | ADVERTISED_MII | \
 113                                        ADVERTISED_FIBRE | \
 114                                        ADVERTISED_Pause | ADVERTISED_Asym_Pause)
 115
 116struct dp83822_private {
 117        bool fx_signal_det_low;
 118        int fx_enabled;
 119        u16 fx_sd_enable;
 120};
 121
 122static int dp83822_set_wol(struct phy_device *phydev,
 123                           struct ethtool_wolinfo *wol)
 124{
 125        struct net_device *ndev = phydev->attached_dev;
 126        u16 value;
 127        const u8 *mac;
 128
 129        if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) {
 130                mac = (const u8 *)ndev->dev_addr;
 131
 132                if (!is_valid_ether_addr(mac))
 133                        return -EINVAL;
 134
 135                /* MAC addresses start with byte 5, but stored in mac[0].
 136                 * 822 PHYs store bytes 4|5, 2|3, 0|1
 137                 */
 138                phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA1,
 139                              (mac[1] << 8) | mac[0]);
 140                phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA2,
 141                              (mac[3] << 8) | mac[2]);
 142                phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA3,
 143                              (mac[5] << 8) | mac[4]);
 144
 145                value = phy_read_mmd(phydev, DP83822_DEVADDR,
 146                                     MII_DP83822_WOL_CFG);
 147                if (wol->wolopts & WAKE_MAGIC)
 148                        value |= DP83822_WOL_MAGIC_EN;
 149                else
 150                        value &= ~DP83822_WOL_MAGIC_EN;
 151
 152                if (wol->wolopts & WAKE_MAGICSECURE) {
 153                        phy_write_mmd(phydev, DP83822_DEVADDR,
 154                                      MII_DP83822_RXSOP1,
 155                                      (wol->sopass[1] << 8) | wol->sopass[0]);
 156                        phy_write_mmd(phydev, DP83822_DEVADDR,
 157                                      MII_DP83822_RXSOP2,
 158                                      (wol->sopass[3] << 8) | wol->sopass[2]);
 159                        phy_write_mmd(phydev, DP83822_DEVADDR,
 160                                      MII_DP83822_RXSOP3,
 161                                      (wol->sopass[5] << 8) | wol->sopass[4]);
 162                        value |= DP83822_WOL_SECURE_ON;
 163                } else {
 164                        value &= ~DP83822_WOL_SECURE_ON;
 165                }
 166
 167                /* Clear any pending WoL interrupt */
 168                phy_read(phydev, MII_DP83822_MISR2);
 169
 170                value |= DP83822_WOL_EN | DP83822_WOL_INDICATION_SEL |
 171                         DP83822_WOL_CLR_INDICATION;
 172
 173                return phy_write_mmd(phydev, DP83822_DEVADDR,
 174                                     MII_DP83822_WOL_CFG, value);
 175        } else {
 176                return phy_clear_bits_mmd(phydev, DP83822_DEVADDR,
 177                                          MII_DP83822_WOL_CFG, DP83822_WOL_EN);
 178        }
 179}
 180
 181static void dp83822_get_wol(struct phy_device *phydev,
 182                            struct ethtool_wolinfo *wol)
 183{
 184        int value;
 185        u16 sopass_val;
 186
 187        wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE);
 188        wol->wolopts = 0;
 189
 190        value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
 191
 192        if (value & DP83822_WOL_MAGIC_EN)
 193                wol->wolopts |= WAKE_MAGIC;
 194
 195        if (value & DP83822_WOL_SECURE_ON) {
 196                sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
 197                                          MII_DP83822_RXSOP1);
 198                wol->sopass[0] = (sopass_val & 0xff);
 199                wol->sopass[1] = (sopass_val >> 8);
 200
 201                sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
 202                                          MII_DP83822_RXSOP2);
 203                wol->sopass[2] = (sopass_val & 0xff);
 204                wol->sopass[3] = (sopass_val >> 8);
 205
 206                sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR,
 207                                          MII_DP83822_RXSOP3);
 208                wol->sopass[4] = (sopass_val & 0xff);
 209                wol->sopass[5] = (sopass_val >> 8);
 210
 211                wol->wolopts |= WAKE_MAGICSECURE;
 212        }
 213
 214        /* WoL is not enabled so set wolopts to 0 */
 215        if (!(value & DP83822_WOL_EN))
 216                wol->wolopts = 0;
 217}
 218
 219static int dp83822_config_intr(struct phy_device *phydev)
 220{
 221        struct dp83822_private *dp83822 = phydev->priv;
 222        int misr_status;
 223        int physcr_status;
 224        int err;
 225
 226        if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
 227                misr_status = phy_read(phydev, MII_DP83822_MISR1);
 228                if (misr_status < 0)
 229                        return misr_status;
 230
 231                misr_status |= (DP83822_RX_ERR_HF_INT_EN |
 232                                DP83822_FALSE_CARRIER_HF_INT_EN |
 233                                DP83822_LINK_STAT_INT_EN |
 234                                DP83822_ENERGY_DET_INT_EN |
 235                                DP83822_LINK_QUAL_INT_EN);
 236
 237                if (!dp83822->fx_enabled)
 238                        misr_status |= DP83822_ANEG_COMPLETE_INT_EN |
 239                                       DP83822_DUP_MODE_CHANGE_INT_EN |
 240                                       DP83822_SPEED_CHANGED_INT_EN;
 241
 242
 243                err = phy_write(phydev, MII_DP83822_MISR1, misr_status);
 244                if (err < 0)
 245                        return err;
 246
 247                misr_status = phy_read(phydev, MII_DP83822_MISR2);
 248                if (misr_status < 0)
 249                        return misr_status;
 250
 251                misr_status |= (DP83822_JABBER_DET_INT_EN |
 252                                DP83822_SLEEP_MODE_INT_EN |
 253                                DP83822_LB_FIFO_INT_EN |
 254                                DP83822_PAGE_RX_INT_EN |
 255                                DP83822_EEE_ERROR_CHANGE_INT_EN);
 256
 257                if (!dp83822->fx_enabled)
 258                        misr_status |= DP83822_MDI_XOVER_INT_EN |
 259                                       DP83822_ANEG_ERR_INT_EN |
 260                                       DP83822_WOL_PKT_INT_EN;
 261
 262                err = phy_write(phydev, MII_DP83822_MISR2, misr_status);
 263                if (err < 0)
 264                        return err;
 265
 266                physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);
 267                if (physcr_status < 0)
 268                        return physcr_status;
 269
 270                physcr_status |= DP83822_PHYSCR_INT_OE | DP83822_PHYSCR_INTEN;
 271
 272        } else {
 273                err = phy_write(phydev, MII_DP83822_MISR1, 0);
 274                if (err < 0)
 275                        return err;
 276
 277                err = phy_write(phydev, MII_DP83822_MISR1, 0);
 278                if (err < 0)
 279                        return err;
 280
 281                physcr_status = phy_read(phydev, MII_DP83822_PHYSCR);
 282                if (physcr_status < 0)
 283                        return physcr_status;
 284
 285                physcr_status &= ~DP83822_PHYSCR_INTEN;
 286        }
 287
 288        return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status);
 289}
 290
 291static irqreturn_t dp83822_handle_interrupt(struct phy_device *phydev)
 292{
 293        bool trigger_machine = false;
 294        int irq_status;
 295
 296        /* The MISR1 and MISR2 registers are holding the interrupt status in
 297         * the upper half (15:8), while the lower half (7:0) is used for
 298         * controlling the interrupt enable state of those individual interrupt
 299         * sources. To determine the possible interrupt sources, just read the
 300         * MISR* register and use it directly to know which interrupts have
 301         * been enabled previously or not.
 302         */
 303        irq_status = phy_read(phydev, MII_DP83822_MISR1);
 304        if (irq_status < 0) {
 305                phy_error(phydev);
 306                return IRQ_NONE;
 307        }
 308        if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
 309                trigger_machine = true;
 310
 311        irq_status = phy_read(phydev, MII_DP83822_MISR2);
 312        if (irq_status < 0) {
 313                phy_error(phydev);
 314                return IRQ_NONE;
 315        }
 316        if (irq_status & ((irq_status & GENMASK(7, 0)) << 8))
 317                trigger_machine = true;
 318
 319        if (!trigger_machine)
 320                return IRQ_NONE;
 321
 322        phy_trigger_machine(phydev);
 323
 324        return IRQ_HANDLED;
 325}
 326
 327static int dp8382x_disable_wol(struct phy_device *phydev)
 328{
 329        return phy_clear_bits_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG,
 330                                  DP83822_WOL_EN | DP83822_WOL_MAGIC_EN |
 331                                  DP83822_WOL_SECURE_ON);
 332}
 333
 334static int dp83822_read_status(struct phy_device *phydev)
 335{
 336        struct dp83822_private *dp83822 = phydev->priv;
 337        int status = phy_read(phydev, MII_DP83822_PHYSTS);
 338        int ctrl2;
 339        int ret;
 340
 341        if (dp83822->fx_enabled) {
 342                if (status & DP83822_PHYSTS_LINK) {
 343                        phydev->speed = SPEED_UNKNOWN;
 344                        phydev->duplex = DUPLEX_UNKNOWN;
 345                } else {
 346                        ctrl2 = phy_read(phydev, MII_DP83822_CTRL_2);
 347                        if (ctrl2 < 0)
 348                                return ctrl2;
 349
 350                        if (!(ctrl2 & DP83822_FX_ENABLE)) {
 351                                ret = phy_write(phydev, MII_DP83822_CTRL_2,
 352                                                DP83822_FX_ENABLE | ctrl2);
 353                                if (ret < 0)
 354                                        return ret;
 355                        }
 356                }
 357        }
 358
 359        ret = genphy_read_status(phydev);
 360        if (ret)
 361                return ret;
 362
 363        if (status < 0)
 364                return status;
 365
 366        if (status & DP83822_PHYSTS_DUPLEX)
 367                phydev->duplex = DUPLEX_FULL;
 368        else
 369                phydev->duplex = DUPLEX_HALF;
 370
 371        if (status & DP83822_PHYSTS_10)
 372                phydev->speed = SPEED_10;
 373        else
 374                phydev->speed = SPEED_100;
 375
 376        return 0;
 377}
 378
 379static int dp83822_config_init(struct phy_device *phydev)
 380{
 381        struct dp83822_private *dp83822 = phydev->priv;
 382        struct device *dev = &phydev->mdio.dev;
 383        int rgmii_delay;
 384        s32 rx_int_delay;
 385        s32 tx_int_delay;
 386        int err = 0;
 387        int bmcr;
 388
 389        if (phy_interface_is_rgmii(phydev)) {
 390                rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
 391                                                      true);
 392
 393                if (rx_int_delay <= 0)
 394                        rgmii_delay = 0;
 395                else
 396                        rgmii_delay = DP83822_RX_CLK_SHIFT;
 397
 398                tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
 399                                                      false);
 400                if (tx_int_delay <= 0)
 401                        rgmii_delay &= ~DP83822_TX_CLK_SHIFT;
 402                else
 403                        rgmii_delay |= DP83822_TX_CLK_SHIFT;
 404
 405                if (rgmii_delay) {
 406                        err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,
 407                                               MII_DP83822_RCSR, rgmii_delay);
 408                        if (err)
 409                                return err;
 410                }
 411        }
 412
 413        if (dp83822->fx_enabled) {
 414                err = phy_modify(phydev, MII_DP83822_CTRL_2,
 415                                 DP83822_FX_ENABLE, 1);
 416                if (err < 0)
 417                        return err;
 418
 419                /* Only allow advertising what this PHY supports */
 420                linkmode_and(phydev->advertising, phydev->advertising,
 421                             phydev->supported);
 422
 423                linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
 424                                 phydev->supported);
 425                linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
 426                                 phydev->advertising);
 427                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
 428                                 phydev->supported);
 429                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
 430                                 phydev->supported);
 431                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
 432                                 phydev->advertising);
 433                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
 434                                 phydev->advertising);
 435
 436                /* Auto neg is not supported in fiber mode */
 437                bmcr = phy_read(phydev, MII_BMCR);
 438                if (bmcr < 0)
 439                        return bmcr;
 440
 441                if (bmcr & BMCR_ANENABLE) {
 442                        err =  phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
 443                        if (err < 0)
 444                                return err;
 445                }
 446                phydev->autoneg = AUTONEG_DISABLE;
 447                linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
 448                                   phydev->supported);
 449                linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
 450                                   phydev->advertising);
 451
 452                /* Setup fiber advertisement */
 453                err = phy_modify_changed(phydev, MII_ADVERTISE,
 454                                         MII_DP83822_FIBER_ADVERTISE,
 455                                         MII_DP83822_FIBER_ADVERTISE);
 456
 457                if (err < 0)
 458                        return err;
 459
 460                if (dp83822->fx_signal_det_low) {
 461                        err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,
 462                                               MII_DP83822_GENCFG,
 463                                               DP83822_SIG_DET_LOW);
 464                        if (err)
 465                                return err;
 466                }
 467        }
 468        return dp8382x_disable_wol(phydev);
 469}
 470
 471static int dp8382x_config_init(struct phy_device *phydev)
 472{
 473        return dp8382x_disable_wol(phydev);
 474}
 475
 476static int dp83822_phy_reset(struct phy_device *phydev)
 477{
 478        int err;
 479
 480        err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_SW_RESET);
 481        if (err < 0)
 482                return err;
 483
 484        return phydev->drv->config_init(phydev);
 485}
 486
 487#ifdef CONFIG_OF_MDIO
 488static int dp83822_of_init(struct phy_device *phydev)
 489{
 490        struct dp83822_private *dp83822 = phydev->priv;
 491        struct device *dev = &phydev->mdio.dev;
 492
 493        /* Signal detection for the PHY is only enabled if the FX_EN and the
 494         * SD_EN pins are strapped. Signal detection can only enabled if FX_EN
 495         * is strapped otherwise signal detection is disabled for the PHY.
 496         */
 497        if (dp83822->fx_enabled && dp83822->fx_sd_enable)
 498                dp83822->fx_signal_det_low = device_property_present(dev,
 499                                                                     "ti,link-loss-low");
 500        if (!dp83822->fx_enabled)
 501                dp83822->fx_enabled = device_property_present(dev,
 502                                                              "ti,fiber-mode");
 503
 504        return 0;
 505}
 506#else
 507static int dp83822_of_init(struct phy_device *phydev)
 508{
 509        return 0;
 510}
 511#endif /* CONFIG_OF_MDIO */
 512
 513static int dp83822_read_straps(struct phy_device *phydev)
 514{
 515        struct dp83822_private *dp83822 = phydev->priv;
 516        int fx_enabled, fx_sd_enable;
 517        int val;
 518
 519        val = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_SOR1);
 520        if (val < 0)
 521                return val;
 522
 523        fx_enabled = (val & DP83822_COL_STRAP_MASK) >> DP83822_COL_SHIFT;
 524        if (fx_enabled == DP83822_STRAP_MODE2 ||
 525            fx_enabled == DP83822_STRAP_MODE3)
 526                dp83822->fx_enabled = 1;
 527
 528        if (dp83822->fx_enabled) {
 529                fx_sd_enable = (val & DP83822_RX_ER_STR_MASK) >> DP83822_RX_ER_SHIFT;
 530                if (fx_sd_enable == DP83822_STRAP_MODE3 ||
 531                    fx_sd_enable == DP83822_STRAP_MODE4)
 532                        dp83822->fx_sd_enable = 1;
 533        }
 534
 535        return 0;
 536}
 537
 538static int dp83822_probe(struct phy_device *phydev)
 539{
 540        struct dp83822_private *dp83822;
 541        int ret;
 542
 543        dp83822 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83822),
 544                               GFP_KERNEL);
 545        if (!dp83822)
 546                return -ENOMEM;
 547
 548        phydev->priv = dp83822;
 549
 550        ret = dp83822_read_straps(phydev);
 551        if (ret)
 552                return ret;
 553
 554        dp83822_of_init(phydev);
 555
 556        if (dp83822->fx_enabled)
 557                phydev->port = PORT_FIBRE;
 558
 559        return 0;
 560}
 561
 562static int dp83822_suspend(struct phy_device *phydev)
 563{
 564        int value;
 565
 566        value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
 567
 568        if (!(value & DP83822_WOL_EN))
 569                genphy_suspend(phydev);
 570
 571        return 0;
 572}
 573
 574static int dp83822_resume(struct phy_device *phydev)
 575{
 576        int value;
 577
 578        genphy_resume(phydev);
 579
 580        value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
 581
 582        phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value |
 583                      DP83822_WOL_CLR_INDICATION);
 584
 585        return 0;
 586}
 587
 588#define DP83822_PHY_DRIVER(_id, _name)                          \
 589        {                                                       \
 590                PHY_ID_MATCH_MODEL(_id),                        \
 591                .name           = (_name),                      \
 592                /* PHY_BASIC_FEATURES */                        \
 593                .probe          = dp83822_probe,                \
 594                .soft_reset     = dp83822_phy_reset,            \
 595                .config_init    = dp83822_config_init,          \
 596                .read_status    = dp83822_read_status,          \
 597                .get_wol = dp83822_get_wol,                     \
 598                .set_wol = dp83822_set_wol,                     \
 599                .config_intr = dp83822_config_intr,             \
 600                .handle_interrupt = dp83822_handle_interrupt,   \
 601                .suspend = dp83822_suspend,                     \
 602                .resume = dp83822_resume,                       \
 603        }
 604
 605#define DP8382X_PHY_DRIVER(_id, _name)                          \
 606        {                                                       \
 607                PHY_ID_MATCH_MODEL(_id),                        \
 608                .name           = (_name),                      \
 609                /* PHY_BASIC_FEATURES */                        \
 610                .soft_reset     = dp83822_phy_reset,            \
 611                .config_init    = dp8382x_config_init,          \
 612                .get_wol = dp83822_get_wol,                     \
 613                .set_wol = dp83822_set_wol,                     \
 614                .config_intr = dp83822_config_intr,             \
 615                .handle_interrupt = dp83822_handle_interrupt,   \
 616                .suspend = dp83822_suspend,                     \
 617                .resume = dp83822_resume,                       \
 618        }
 619
 620static struct phy_driver dp83822_driver[] = {
 621        DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"),
 622        DP8382X_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"),
 623        DP8382X_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"),
 624        DP8382X_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"),
 625        DP8382X_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"),
 626        DP8382X_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"),
 627        DP8382X_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"),
 628};
 629module_phy_driver(dp83822_driver);
 630
 631static struct mdio_device_id __maybe_unused dp83822_tbl[] = {
 632        { DP83822_PHY_ID, 0xfffffff0 },
 633        { DP83825I_PHY_ID, 0xfffffff0 },
 634        { DP83826C_PHY_ID, 0xfffffff0 },
 635        { DP83826NC_PHY_ID, 0xfffffff0 },
 636        { DP83825S_PHY_ID, 0xfffffff0 },
 637        { DP83825CM_PHY_ID, 0xfffffff0 },
 638        { DP83825CS_PHY_ID, 0xfffffff0 },
 639        { },
 640};
 641MODULE_DEVICE_TABLE(mdio, dp83822_tbl);
 642
 643MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver");
 644MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
 645MODULE_LICENSE("GPL v2");
 646