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        int value = DP83822_WOL_EN | DP83822_WOL_MAGIC_EN |
 330                    DP83822_WOL_SECURE_ON;
 331
 332        return phy_clear_bits_mmd(phydev, DP83822_DEVADDR,
 333                                  MII_DP83822_WOL_CFG, value);
 334}
 335
 336static int dp83822_read_status(struct phy_device *phydev)
 337{
 338        struct dp83822_private *dp83822 = phydev->priv;
 339        int status = phy_read(phydev, MII_DP83822_PHYSTS);
 340        int ctrl2;
 341        int ret;
 342
 343        if (dp83822->fx_enabled) {
 344                if (status & DP83822_PHYSTS_LINK) {
 345                        phydev->speed = SPEED_UNKNOWN;
 346                        phydev->duplex = DUPLEX_UNKNOWN;
 347                } else {
 348                        ctrl2 = phy_read(phydev, MII_DP83822_CTRL_2);
 349                        if (ctrl2 < 0)
 350                                return ctrl2;
 351
 352                        if (!(ctrl2 & DP83822_FX_ENABLE)) {
 353                                ret = phy_write(phydev, MII_DP83822_CTRL_2,
 354                                                DP83822_FX_ENABLE | ctrl2);
 355                                if (ret < 0)
 356                                        return ret;
 357                        }
 358                }
 359        }
 360
 361        ret = genphy_read_status(phydev);
 362        if (ret)
 363                return ret;
 364
 365        if (status < 0)
 366                return status;
 367
 368        if (status & DP83822_PHYSTS_DUPLEX)
 369                phydev->duplex = DUPLEX_FULL;
 370        else
 371                phydev->duplex = DUPLEX_HALF;
 372
 373        if (status & DP83822_PHYSTS_10)
 374                phydev->speed = SPEED_10;
 375        else
 376                phydev->speed = SPEED_100;
 377
 378        return 0;
 379}
 380
 381static int dp83822_config_init(struct phy_device *phydev)
 382{
 383        struct dp83822_private *dp83822 = phydev->priv;
 384        struct device *dev = &phydev->mdio.dev;
 385        int rgmii_delay;
 386        s32 rx_int_delay;
 387        s32 tx_int_delay;
 388        int err = 0;
 389        int bmcr;
 390
 391        if (phy_interface_is_rgmii(phydev)) {
 392                rx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
 393                                                      true);
 394
 395                if (rx_int_delay <= 0)
 396                        rgmii_delay = 0;
 397                else
 398                        rgmii_delay = DP83822_RX_CLK_SHIFT;
 399
 400                tx_int_delay = phy_get_internal_delay(phydev, dev, NULL, 0,
 401                                                      false);
 402                if (tx_int_delay <= 0)
 403                        rgmii_delay &= ~DP83822_TX_CLK_SHIFT;
 404                else
 405                        rgmii_delay |= DP83822_TX_CLK_SHIFT;
 406
 407                if (rgmii_delay) {
 408                        err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,
 409                                               MII_DP83822_RCSR, rgmii_delay);
 410                        if (err)
 411                                return err;
 412                }
 413        }
 414
 415        if (dp83822->fx_enabled) {
 416                err = phy_modify(phydev, MII_DP83822_CTRL_2,
 417                                 DP83822_FX_ENABLE, 1);
 418                if (err < 0)
 419                        return err;
 420
 421                /* Only allow advertising what this PHY supports */
 422                linkmode_and(phydev->advertising, phydev->advertising,
 423                             phydev->supported);
 424
 425                linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
 426                                 phydev->supported);
 427                linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT,
 428                                 phydev->advertising);
 429                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
 430                                 phydev->supported);
 431                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
 432                                 phydev->supported);
 433                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Full_BIT,
 434                                 phydev->advertising);
 435                linkmode_set_bit(ETHTOOL_LINK_MODE_100baseFX_Half_BIT,
 436                                 phydev->advertising);
 437
 438                /* Auto neg is not supported in fiber mode */
 439                bmcr = phy_read(phydev, MII_BMCR);
 440                if (bmcr < 0)
 441                        return bmcr;
 442
 443                if (bmcr & BMCR_ANENABLE) {
 444                        err =  phy_modify(phydev, MII_BMCR, BMCR_ANENABLE, 0);
 445                        if (err < 0)
 446                                return err;
 447                }
 448                phydev->autoneg = AUTONEG_DISABLE;
 449                linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
 450                                   phydev->supported);
 451                linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
 452                                   phydev->advertising);
 453
 454                /* Setup fiber advertisement */
 455                err = phy_modify_changed(phydev, MII_ADVERTISE,
 456                                         MII_DP83822_FIBER_ADVERTISE,
 457                                         MII_DP83822_FIBER_ADVERTISE);
 458
 459                if (err < 0)
 460                        return err;
 461
 462                if (dp83822->fx_signal_det_low) {
 463                        err = phy_set_bits_mmd(phydev, DP83822_DEVADDR,
 464                                               MII_DP83822_GENCFG,
 465                                               DP83822_SIG_DET_LOW);
 466                        if (err)
 467                                return err;
 468                }
 469        }
 470        return dp8382x_disable_wol(phydev);
 471}
 472
 473static int dp8382x_config_init(struct phy_device *phydev)
 474{
 475        return dp8382x_disable_wol(phydev);
 476}
 477
 478static int dp83822_phy_reset(struct phy_device *phydev)
 479{
 480        int err;
 481
 482        err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_SW_RESET);
 483        if (err < 0)
 484                return err;
 485
 486        return phydev->drv->config_init(phydev);
 487}
 488
 489#ifdef CONFIG_OF_MDIO
 490static int dp83822_of_init(struct phy_device *phydev)
 491{
 492        struct dp83822_private *dp83822 = phydev->priv;
 493        struct device *dev = &phydev->mdio.dev;
 494
 495        /* Signal detection for the PHY is only enabled if the FX_EN and the
 496         * SD_EN pins are strapped. Signal detection can only enabled if FX_EN
 497         * is strapped otherwise signal detection is disabled for the PHY.
 498         */
 499        if (dp83822->fx_enabled && dp83822->fx_sd_enable)
 500                dp83822->fx_signal_det_low = device_property_present(dev,
 501                                                                     "ti,link-loss-low");
 502        if (!dp83822->fx_enabled)
 503                dp83822->fx_enabled = device_property_present(dev,
 504                                                              "ti,fiber-mode");
 505
 506        return 0;
 507}
 508#else
 509static int dp83822_of_init(struct phy_device *phydev)
 510{
 511        return 0;
 512}
 513#endif /* CONFIG_OF_MDIO */
 514
 515static int dp83822_read_straps(struct phy_device *phydev)
 516{
 517        struct dp83822_private *dp83822 = phydev->priv;
 518        int fx_enabled, fx_sd_enable;
 519        int val;
 520
 521        val = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_SOR1);
 522        if (val < 0)
 523                return val;
 524
 525        fx_enabled = (val & DP83822_COL_STRAP_MASK) >> DP83822_COL_SHIFT;
 526        if (fx_enabled == DP83822_STRAP_MODE2 ||
 527            fx_enabled == DP83822_STRAP_MODE3)
 528                dp83822->fx_enabled = 1;
 529
 530        if (dp83822->fx_enabled) {
 531                fx_sd_enable = (val & DP83822_RX_ER_STR_MASK) >> DP83822_RX_ER_SHIFT;
 532                if (fx_sd_enable == DP83822_STRAP_MODE3 ||
 533                    fx_sd_enable == DP83822_STRAP_MODE4)
 534                        dp83822->fx_sd_enable = 1;
 535        }
 536
 537        return 0;
 538}
 539
 540static int dp83822_probe(struct phy_device *phydev)
 541{
 542        struct dp83822_private *dp83822;
 543        int ret;
 544
 545        dp83822 = devm_kzalloc(&phydev->mdio.dev, sizeof(*dp83822),
 546                               GFP_KERNEL);
 547        if (!dp83822)
 548                return -ENOMEM;
 549
 550        phydev->priv = dp83822;
 551
 552        ret = dp83822_read_straps(phydev);
 553        if (ret)
 554                return ret;
 555
 556        dp83822_of_init(phydev);
 557
 558        return 0;
 559}
 560
 561static int dp83822_suspend(struct phy_device *phydev)
 562{
 563        int value;
 564
 565        value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
 566
 567        if (!(value & DP83822_WOL_EN))
 568                genphy_suspend(phydev);
 569
 570        return 0;
 571}
 572
 573static int dp83822_resume(struct phy_device *phydev)
 574{
 575        int value;
 576
 577        genphy_resume(phydev);
 578
 579        value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG);
 580
 581        phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value |
 582                      DP83822_WOL_CLR_INDICATION);
 583
 584        return 0;
 585}
 586
 587#define DP83822_PHY_DRIVER(_id, _name)                          \
 588        {                                                       \
 589                PHY_ID_MATCH_MODEL(_id),                        \
 590                .name           = (_name),                      \
 591                /* PHY_BASIC_FEATURES */                        \
 592                .probe          = dp83822_probe,                \
 593                .soft_reset     = dp83822_phy_reset,            \
 594                .config_init    = dp83822_config_init,          \
 595                .read_status    = dp83822_read_status,          \
 596                .get_wol = dp83822_get_wol,                     \
 597                .set_wol = dp83822_set_wol,                     \
 598                .config_intr = dp83822_config_intr,             \
 599                .handle_interrupt = dp83822_handle_interrupt,   \
 600                .suspend = dp83822_suspend,                     \
 601                .resume = dp83822_resume,                       \
 602        }
 603
 604#define DP8382X_PHY_DRIVER(_id, _name)                          \
 605        {                                                       \
 606                PHY_ID_MATCH_MODEL(_id),                        \
 607                .name           = (_name),                      \
 608                /* PHY_BASIC_FEATURES */                        \
 609                .soft_reset     = dp83822_phy_reset,            \
 610                .config_init    = dp8382x_config_init,          \
 611                .get_wol = dp83822_get_wol,                     \
 612                .set_wol = dp83822_set_wol,                     \
 613                .config_intr = dp83822_config_intr,             \
 614                .handle_interrupt = dp83822_handle_interrupt,   \
 615                .suspend = dp83822_suspend,                     \
 616                .resume = dp83822_resume,                       \
 617        }
 618
 619static struct phy_driver dp83822_driver[] = {
 620        DP83822_PHY_DRIVER(DP83822_PHY_ID, "TI DP83822"),
 621        DP8382X_PHY_DRIVER(DP83825I_PHY_ID, "TI DP83825I"),
 622        DP8382X_PHY_DRIVER(DP83826C_PHY_ID, "TI DP83826C"),
 623        DP8382X_PHY_DRIVER(DP83826NC_PHY_ID, "TI DP83826NC"),
 624        DP8382X_PHY_DRIVER(DP83825S_PHY_ID, "TI DP83825S"),
 625        DP8382X_PHY_DRIVER(DP83825CM_PHY_ID, "TI DP83825M"),
 626        DP8382X_PHY_DRIVER(DP83825CS_PHY_ID, "TI DP83825CS"),
 627};
 628module_phy_driver(dp83822_driver);
 629
 630static struct mdio_device_id __maybe_unused dp83822_tbl[] = {
 631        { DP83822_PHY_ID, 0xfffffff0 },
 632        { DP83825I_PHY_ID, 0xfffffff0 },
 633        { DP83826C_PHY_ID, 0xfffffff0 },
 634        { DP83826NC_PHY_ID, 0xfffffff0 },
 635        { DP83825S_PHY_ID, 0xfffffff0 },
 636        { DP83825CM_PHY_ID, 0xfffffff0 },
 637        { DP83825CS_PHY_ID, 0xfffffff0 },
 638        { },
 639};
 640MODULE_DEVICE_TABLE(mdio, dp83822_tbl);
 641
 642MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver");
 643MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com");
 644MODULE_LICENSE("GPL v2");
 645