linux/drivers/net/phy/micrel.c
<<
>>
Prefs
   1/*
   2 * drivers/net/phy/micrel.c
   3 *
   4 * Driver for Micrel PHYs
   5 *
   6 * Author: David J. Choi
   7 *
   8 * Copyright (c) 2010-2013 Micrel, Inc.
   9 * Copyright (c) 2014 Johan Hovold <johan@kernel.org>
  10 *
  11 * This program is free software; you can redistribute  it and/or modify it
  12 * under  the terms of  the GNU General  Public License as published by the
  13 * Free Software Foundation;  either version 2 of the  License, or (at your
  14 * option) any later version.
  15 *
  16 * Support : Micrel Phys:
  17 *              Giga phys: ksz9021, ksz9031
  18 *              100/10 Phys : ksz8001, ksz8721, ksz8737, ksz8041
  19 *                         ksz8021, ksz8031, ksz8051,
  20 *                         ksz8081, ksz8091,
  21 *                         ksz8061,
  22 *              Switch : ksz8873, ksz886x
  23 */
  24
  25#include <linux/kernel.h>
  26#include <linux/module.h>
  27#include <linux/phy.h>
  28#include <linux/micrel_phy.h>
  29#include <linux/of.h>
  30#include <linux/clk.h>
  31
  32/* Operation Mode Strap Override */
  33#define MII_KSZPHY_OMSO                         0x16
  34#define KSZPHY_OMSO_B_CAST_OFF                  BIT(9)
  35#define KSZPHY_OMSO_RMII_OVERRIDE               BIT(1)
  36#define KSZPHY_OMSO_MII_OVERRIDE                BIT(0)
  37
  38/* general Interrupt control/status reg in vendor specific block. */
  39#define MII_KSZPHY_INTCS                        0x1B
  40#define KSZPHY_INTCS_JABBER                     BIT(15)
  41#define KSZPHY_INTCS_RECEIVE_ERR                BIT(14)
  42#define KSZPHY_INTCS_PAGE_RECEIVE               BIT(13)
  43#define KSZPHY_INTCS_PARELLEL                   BIT(12)
  44#define KSZPHY_INTCS_LINK_PARTNER_ACK           BIT(11)
  45#define KSZPHY_INTCS_LINK_DOWN                  BIT(10)
  46#define KSZPHY_INTCS_REMOTE_FAULT               BIT(9)
  47#define KSZPHY_INTCS_LINK_UP                    BIT(8)
  48#define KSZPHY_INTCS_ALL                        (KSZPHY_INTCS_LINK_UP |\
  49                                                KSZPHY_INTCS_LINK_DOWN)
  50
  51/* PHY Control 1 */
  52#define MII_KSZPHY_CTRL_1                       0x1e
  53
  54/* PHY Control 2 / PHY Control (if no PHY Control 1) */
  55#define MII_KSZPHY_CTRL_2                       0x1f
  56#define MII_KSZPHY_CTRL                         MII_KSZPHY_CTRL_2
  57/* bitmap of PHY register to set interrupt mode */
  58#define KSZPHY_CTRL_INT_ACTIVE_HIGH             BIT(9)
  59#define KSZPHY_RMII_REF_CLK_SEL                 BIT(7)
  60
  61/* Write/read to/from extended registers */
  62#define MII_KSZPHY_EXTREG                       0x0b
  63#define KSZPHY_EXTREG_WRITE                     0x8000
  64
  65#define MII_KSZPHY_EXTREG_WRITE                 0x0c
  66#define MII_KSZPHY_EXTREG_READ                  0x0d
  67
  68/* Extended registers */
  69#define MII_KSZPHY_CLK_CONTROL_PAD_SKEW         0x104
  70#define MII_KSZPHY_RX_DATA_PAD_SKEW             0x105
  71#define MII_KSZPHY_TX_DATA_PAD_SKEW             0x106
  72
  73#define PS_TO_REG                               200
  74
  75struct kszphy_type {
  76        u32 led_mode_reg;
  77        u16 interrupt_level_mask;
  78        bool has_broadcast_disable;
  79        bool has_rmii_ref_clk_sel;
  80};
  81
  82struct kszphy_priv {
  83        const struct kszphy_type *type;
  84        int led_mode;
  85        bool rmii_ref_clk_sel;
  86        bool rmii_ref_clk_sel_val;
  87};
  88
  89static const struct kszphy_type ksz8021_type = {
  90        .led_mode_reg           = MII_KSZPHY_CTRL_2,
  91        .has_broadcast_disable  = true,
  92        .has_rmii_ref_clk_sel   = true,
  93};
  94
  95static const struct kszphy_type ksz8041_type = {
  96        .led_mode_reg           = MII_KSZPHY_CTRL_1,
  97};
  98
  99static const struct kszphy_type ksz8051_type = {
 100        .led_mode_reg           = MII_KSZPHY_CTRL_2,
 101};
 102
 103static const struct kszphy_type ksz8081_type = {
 104        .led_mode_reg           = MII_KSZPHY_CTRL_2,
 105        .has_broadcast_disable  = true,
 106        .has_rmii_ref_clk_sel   = true,
 107};
 108
 109static const struct kszphy_type ks8737_type = {
 110        .interrupt_level_mask   = BIT(14),
 111};
 112
 113static const struct kszphy_type ksz9021_type = {
 114        .interrupt_level_mask   = BIT(14),
 115};
 116
 117static int kszphy_extended_write(struct phy_device *phydev,
 118                                u32 regnum, u16 val)
 119{
 120        phy_write(phydev, MII_KSZPHY_EXTREG, KSZPHY_EXTREG_WRITE | regnum);
 121        return phy_write(phydev, MII_KSZPHY_EXTREG_WRITE, val);
 122}
 123
 124static int kszphy_extended_read(struct phy_device *phydev,
 125                                u32 regnum)
 126{
 127        phy_write(phydev, MII_KSZPHY_EXTREG, regnum);
 128        return phy_read(phydev, MII_KSZPHY_EXTREG_READ);
 129}
 130
 131static int kszphy_ack_interrupt(struct phy_device *phydev)
 132{
 133        /* bit[7..0] int status, which is a read and clear register. */
 134        int rc;
 135
 136        rc = phy_read(phydev, MII_KSZPHY_INTCS);
 137
 138        return (rc < 0) ? rc : 0;
 139}
 140
 141static int kszphy_config_intr(struct phy_device *phydev)
 142{
 143        const struct kszphy_type *type = phydev->drv->driver_data;
 144        int temp;
 145        u16 mask;
 146
 147        if (type && type->interrupt_level_mask)
 148                mask = type->interrupt_level_mask;
 149        else
 150                mask = KSZPHY_CTRL_INT_ACTIVE_HIGH;
 151
 152        /* set the interrupt pin active low */
 153        temp = phy_read(phydev, MII_KSZPHY_CTRL);
 154        if (temp < 0)
 155                return temp;
 156        temp &= ~mask;
 157        phy_write(phydev, MII_KSZPHY_CTRL, temp);
 158
 159        /* enable / disable interrupts */
 160        if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
 161                temp = KSZPHY_INTCS_ALL;
 162        else
 163                temp = 0;
 164
 165        return phy_write(phydev, MII_KSZPHY_INTCS, temp);
 166}
 167
 168static int kszphy_rmii_clk_sel(struct phy_device *phydev, bool val)
 169{
 170        int ctrl;
 171
 172        ctrl = phy_read(phydev, MII_KSZPHY_CTRL);
 173        if (ctrl < 0)
 174                return ctrl;
 175
 176        if (val)
 177                ctrl |= KSZPHY_RMII_REF_CLK_SEL;
 178        else
 179                ctrl &= ~KSZPHY_RMII_REF_CLK_SEL;
 180
 181        return phy_write(phydev, MII_KSZPHY_CTRL, ctrl);
 182}
 183
 184static int kszphy_setup_led(struct phy_device *phydev, u32 reg, int val)
 185{
 186        int rc, temp, shift;
 187
 188        switch (reg) {
 189        case MII_KSZPHY_CTRL_1:
 190                shift = 14;
 191                break;
 192        case MII_KSZPHY_CTRL_2:
 193                shift = 4;
 194                break;
 195        default:
 196                return -EINVAL;
 197        }
 198
 199        temp = phy_read(phydev, reg);
 200        if (temp < 0) {
 201                rc = temp;
 202                goto out;
 203        }
 204
 205        temp &= ~(3 << shift);
 206        temp |= val << shift;
 207        rc = phy_write(phydev, reg, temp);
 208out:
 209        if (rc < 0)
 210                dev_err(&phydev->dev, "failed to set led mode\n");
 211
 212        return rc;
 213}
 214
 215/* Disable PHY address 0 as the broadcast address, so that it can be used as a
 216 * unique (non-broadcast) address on a shared bus.
 217 */
 218static int kszphy_broadcast_disable(struct phy_device *phydev)
 219{
 220        int ret;
 221
 222        ret = phy_read(phydev, MII_KSZPHY_OMSO);
 223        if (ret < 0)
 224                goto out;
 225
 226        ret = phy_write(phydev, MII_KSZPHY_OMSO, ret | KSZPHY_OMSO_B_CAST_OFF);
 227out:
 228        if (ret)
 229                dev_err(&phydev->dev, "failed to disable broadcast address\n");
 230
 231        return ret;
 232}
 233
 234static int kszphy_config_init(struct phy_device *phydev)
 235{
 236        struct kszphy_priv *priv = phydev->priv;
 237        const struct kszphy_type *type;
 238        int ret;
 239
 240        if (!priv)
 241                return 0;
 242
 243        type = priv->type;
 244
 245        if (type->has_broadcast_disable)
 246                kszphy_broadcast_disable(phydev);
 247
 248        if (priv->rmii_ref_clk_sel) {
 249                ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val);
 250                if (ret) {
 251                        dev_err(&phydev->dev, "failed to set rmii reference clock\n");
 252                        return ret;
 253                }
 254        }
 255
 256        if (priv->led_mode >= 0)
 257                kszphy_setup_led(phydev, type->led_mode_reg, priv->led_mode);
 258
 259        return 0;
 260}
 261
 262static int ksz9021_load_values_from_of(struct phy_device *phydev,
 263                                       struct device_node *of_node, u16 reg,
 264                                       char *field1, char *field2,
 265                                       char *field3, char *field4)
 266{
 267        int val1 = -1;
 268        int val2 = -2;
 269        int val3 = -3;
 270        int val4 = -4;
 271        int newval;
 272        int matches = 0;
 273
 274        if (!of_property_read_u32(of_node, field1, &val1))
 275                matches++;
 276
 277        if (!of_property_read_u32(of_node, field2, &val2))
 278                matches++;
 279
 280        if (!of_property_read_u32(of_node, field3, &val3))
 281                matches++;
 282
 283        if (!of_property_read_u32(of_node, field4, &val4))
 284                matches++;
 285
 286        if (!matches)
 287                return 0;
 288
 289        if (matches < 4)
 290                newval = kszphy_extended_read(phydev, reg);
 291        else
 292                newval = 0;
 293
 294        if (val1 != -1)
 295                newval = ((newval & 0xfff0) | ((val1 / PS_TO_REG) & 0xf) << 0);
 296
 297        if (val2 != -2)
 298                newval = ((newval & 0xff0f) | ((val2 / PS_TO_REG) & 0xf) << 4);
 299
 300        if (val3 != -3)
 301                newval = ((newval & 0xf0ff) | ((val3 / PS_TO_REG) & 0xf) << 8);
 302
 303        if (val4 != -4)
 304                newval = ((newval & 0x0fff) | ((val4 / PS_TO_REG) & 0xf) << 12);
 305
 306        return kszphy_extended_write(phydev, reg, newval);
 307}
 308
 309static int ksz9021_config_init(struct phy_device *phydev)
 310{
 311        struct device *dev = &phydev->dev;
 312        struct device_node *of_node = dev->of_node;
 313
 314        if (!of_node && dev->parent->of_node)
 315                of_node = dev->parent->of_node;
 316
 317        if (of_node) {
 318                ksz9021_load_values_from_of(phydev, of_node,
 319                                    MII_KSZPHY_CLK_CONTROL_PAD_SKEW,
 320                                    "txen-skew-ps", "txc-skew-ps",
 321                                    "rxdv-skew-ps", "rxc-skew-ps");
 322                ksz9021_load_values_from_of(phydev, of_node,
 323                                    MII_KSZPHY_RX_DATA_PAD_SKEW,
 324                                    "rxd0-skew-ps", "rxd1-skew-ps",
 325                                    "rxd2-skew-ps", "rxd3-skew-ps");
 326                ksz9021_load_values_from_of(phydev, of_node,
 327                                    MII_KSZPHY_TX_DATA_PAD_SKEW,
 328                                    "txd0-skew-ps", "txd1-skew-ps",
 329                                    "txd2-skew-ps", "txd3-skew-ps");
 330        }
 331        return 0;
 332}
 333
 334#define MII_KSZ9031RN_MMD_CTRL_REG      0x0d
 335#define MII_KSZ9031RN_MMD_REGDATA_REG   0x0e
 336#define OP_DATA                         1
 337#define KSZ9031_PS_TO_REG               60
 338
 339/* Extended registers */
 340#define MII_KSZ9031RN_CONTROL_PAD_SKEW  4
 341#define MII_KSZ9031RN_RX_DATA_PAD_SKEW  5
 342#define MII_KSZ9031RN_TX_DATA_PAD_SKEW  6
 343#define MII_KSZ9031RN_CLK_PAD_SKEW      8
 344
 345static int ksz9031_extended_write(struct phy_device *phydev,
 346                                  u8 mode, u32 dev_addr, u32 regnum, u16 val)
 347{
 348        phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr);
 349        phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum);
 350        phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr);
 351        return phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, val);
 352}
 353
 354static int ksz9031_extended_read(struct phy_device *phydev,
 355                                 u8 mode, u32 dev_addr, u32 regnum)
 356{
 357        phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, dev_addr);
 358        phy_write(phydev, MII_KSZ9031RN_MMD_REGDATA_REG, regnum);
 359        phy_write(phydev, MII_KSZ9031RN_MMD_CTRL_REG, (mode << 14) | dev_addr);
 360        return phy_read(phydev, MII_KSZ9031RN_MMD_REGDATA_REG);
 361}
 362
 363static int ksz9031_of_load_skew_values(struct phy_device *phydev,
 364                                       struct device_node *of_node,
 365                                       u16 reg, size_t field_sz,
 366                                       char *field[], u8 numfields)
 367{
 368        int val[4] = {-1, -2, -3, -4};
 369        int matches = 0;
 370        u16 mask;
 371        u16 maxval;
 372        u16 newval;
 373        int i;
 374
 375        for (i = 0; i < numfields; i++)
 376                if (!of_property_read_u32(of_node, field[i], val + i))
 377                        matches++;
 378
 379        if (!matches)
 380                return 0;
 381
 382        if (matches < numfields)
 383                newval = ksz9031_extended_read(phydev, OP_DATA, 2, reg);
 384        else
 385                newval = 0;
 386
 387        maxval = (field_sz == 4) ? 0xf : 0x1f;
 388        for (i = 0; i < numfields; i++)
 389                if (val[i] != -(i + 1)) {
 390                        mask = 0xffff;
 391                        mask ^= maxval << (field_sz * i);
 392                        newval = (newval & mask) |
 393                                (((val[i] / KSZ9031_PS_TO_REG) & maxval)
 394                                        << (field_sz * i));
 395                }
 396
 397        return ksz9031_extended_write(phydev, OP_DATA, 2, reg, newval);
 398}
 399
 400static int ksz9031_config_init(struct phy_device *phydev)
 401{
 402        struct device *dev = &phydev->dev;
 403        struct device_node *of_node = dev->of_node;
 404        char *clk_skews[2] = {"rxc-skew-ps", "txc-skew-ps"};
 405        char *rx_data_skews[4] = {
 406                "rxd0-skew-ps", "rxd1-skew-ps",
 407                "rxd2-skew-ps", "rxd3-skew-ps"
 408        };
 409        char *tx_data_skews[4] = {
 410                "txd0-skew-ps", "txd1-skew-ps",
 411                "txd2-skew-ps", "txd3-skew-ps"
 412        };
 413        char *control_skews[2] = {"txen-skew-ps", "rxdv-skew-ps"};
 414
 415        if (!of_node && dev->parent->of_node)
 416                of_node = dev->parent->of_node;
 417
 418        if (of_node) {
 419                ksz9031_of_load_skew_values(phydev, of_node,
 420                                MII_KSZ9031RN_CLK_PAD_SKEW, 5,
 421                                clk_skews, 2);
 422
 423                ksz9031_of_load_skew_values(phydev, of_node,
 424                                MII_KSZ9031RN_CONTROL_PAD_SKEW, 4,
 425                                control_skews, 2);
 426
 427                ksz9031_of_load_skew_values(phydev, of_node,
 428                                MII_KSZ9031RN_RX_DATA_PAD_SKEW, 4,
 429                                rx_data_skews, 4);
 430
 431                ksz9031_of_load_skew_values(phydev, of_node,
 432                                MII_KSZ9031RN_TX_DATA_PAD_SKEW, 4,
 433                                tx_data_skews, 4);
 434        }
 435        return 0;
 436}
 437
 438#define KSZ8873MLL_GLOBAL_CONTROL_4     0x06
 439#define KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX      BIT(6)
 440#define KSZ8873MLL_GLOBAL_CONTROL_4_SPEED       BIT(4)
 441static int ksz8873mll_read_status(struct phy_device *phydev)
 442{
 443        int regval;
 444
 445        /* dummy read */
 446        regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
 447
 448        regval = phy_read(phydev, KSZ8873MLL_GLOBAL_CONTROL_4);
 449
 450        if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_DUPLEX)
 451                phydev->duplex = DUPLEX_HALF;
 452        else
 453                phydev->duplex = DUPLEX_FULL;
 454
 455        if (regval & KSZ8873MLL_GLOBAL_CONTROL_4_SPEED)
 456                phydev->speed = SPEED_10;
 457        else
 458                phydev->speed = SPEED_100;
 459
 460        phydev->link = 1;
 461        phydev->pause = phydev->asym_pause = 0;
 462
 463        return 0;
 464}
 465
 466static int ksz8873mll_config_aneg(struct phy_device *phydev)
 467{
 468        return 0;
 469}
 470
 471/* This routine returns -1 as an indication to the caller that the
 472 * Micrel ksz9021 10/100/1000 PHY does not support standard IEEE
 473 * MMD extended PHY registers.
 474 */
 475static int
 476ksz9021_rd_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
 477                      int regnum)
 478{
 479        return -1;
 480}
 481
 482/* This routine does nothing since the Micrel ksz9021 does not support
 483 * standard IEEE MMD extended PHY registers.
 484 */
 485static void
 486ksz9021_wr_mmd_phyreg(struct phy_device *phydev, int ptrad, int devnum,
 487                      int regnum, u32 val)
 488{
 489}
 490
 491static int kszphy_probe(struct phy_device *phydev)
 492{
 493        const struct kszphy_type *type = phydev->drv->driver_data;
 494        struct device_node *np = phydev->dev.of_node;
 495        struct kszphy_priv *priv;
 496        struct clk *clk;
 497        int ret;
 498
 499        priv = devm_kzalloc(&phydev->dev, sizeof(*priv), GFP_KERNEL);
 500        if (!priv)
 501                return -ENOMEM;
 502
 503        phydev->priv = priv;
 504
 505        priv->type = type;
 506
 507        if (type->led_mode_reg) {
 508                ret = of_property_read_u32(np, "micrel,led-mode",
 509                                &priv->led_mode);
 510                if (ret)
 511                        priv->led_mode = -1;
 512
 513                if (priv->led_mode > 3) {
 514                        dev_err(&phydev->dev, "invalid led mode: 0x%02x\n",
 515                                        priv->led_mode);
 516                        priv->led_mode = -1;
 517                }
 518        } else {
 519                priv->led_mode = -1;
 520        }
 521
 522        clk = devm_clk_get(&phydev->dev, "rmii-ref");
 523        if (!IS_ERR(clk)) {
 524                unsigned long rate = clk_get_rate(clk);
 525                bool rmii_ref_clk_sel_25_mhz;
 526
 527                priv->rmii_ref_clk_sel = type->has_rmii_ref_clk_sel;
 528                rmii_ref_clk_sel_25_mhz = of_property_read_bool(np,
 529                                "micrel,rmii-reference-clock-select-25-mhz");
 530
 531                if (rate > 24500000 && rate < 25500000) {
 532                        priv->rmii_ref_clk_sel_val = rmii_ref_clk_sel_25_mhz;
 533                } else if (rate > 49500000 && rate < 50500000) {
 534                        priv->rmii_ref_clk_sel_val = !rmii_ref_clk_sel_25_mhz;
 535                } else {
 536                        dev_err(&phydev->dev, "Clock rate out of range: %ld\n", rate);
 537                        return -EINVAL;
 538                }
 539        }
 540
 541        /* Support legacy board-file configuration */
 542        if (phydev->dev_flags & MICREL_PHY_50MHZ_CLK) {
 543                priv->rmii_ref_clk_sel = true;
 544                priv->rmii_ref_clk_sel_val = true;
 545        }
 546
 547        return 0;
 548}
 549
 550static struct phy_driver ksphy_driver[] = {
 551{
 552        .phy_id         = PHY_ID_KS8737,
 553        .phy_id_mask    = 0x00fffff0,
 554        .name           = "Micrel KS8737",
 555        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 556        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 557        .driver_data    = &ks8737_type,
 558        .config_init    = kszphy_config_init,
 559        .config_aneg    = genphy_config_aneg,
 560        .read_status    = genphy_read_status,
 561        .ack_interrupt  = kszphy_ack_interrupt,
 562        .config_intr    = kszphy_config_intr,
 563        .suspend        = genphy_suspend,
 564        .resume         = genphy_resume,
 565        .driver         = { .owner = THIS_MODULE,},
 566}, {
 567        .phy_id         = PHY_ID_KSZ8021,
 568        .phy_id_mask    = 0x00ffffff,
 569        .name           = "Micrel KSZ8021 or KSZ8031",
 570        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
 571                           SUPPORTED_Asym_Pause),
 572        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 573        .driver_data    = &ksz8021_type,
 574        .probe          = kszphy_probe,
 575        .config_init    = kszphy_config_init,
 576        .config_aneg    = genphy_config_aneg,
 577        .read_status    = genphy_read_status,
 578        .ack_interrupt  = kszphy_ack_interrupt,
 579        .config_intr    = kszphy_config_intr,
 580        .suspend        = genphy_suspend,
 581        .resume         = genphy_resume,
 582        .driver         = { .owner = THIS_MODULE,},
 583}, {
 584        .phy_id         = PHY_ID_KSZ8031,
 585        .phy_id_mask    = 0x00ffffff,
 586        .name           = "Micrel KSZ8031",
 587        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause |
 588                           SUPPORTED_Asym_Pause),
 589        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 590        .driver_data    = &ksz8021_type,
 591        .probe          = kszphy_probe,
 592        .config_init    = kszphy_config_init,
 593        .config_aneg    = genphy_config_aneg,
 594        .read_status    = genphy_read_status,
 595        .ack_interrupt  = kszphy_ack_interrupt,
 596        .config_intr    = kszphy_config_intr,
 597        .suspend        = genphy_suspend,
 598        .resume         = genphy_resume,
 599        .driver         = { .owner = THIS_MODULE,},
 600}, {
 601        .phy_id         = PHY_ID_KSZ8041,
 602        .phy_id_mask    = 0x00fffff0,
 603        .name           = "Micrel KSZ8041",
 604        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
 605                                | SUPPORTED_Asym_Pause),
 606        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 607        .driver_data    = &ksz8041_type,
 608        .probe          = kszphy_probe,
 609        .config_init    = kszphy_config_init,
 610        .config_aneg    = genphy_config_aneg,
 611        .read_status    = genphy_read_status,
 612        .ack_interrupt  = kszphy_ack_interrupt,
 613        .config_intr    = kszphy_config_intr,
 614        .suspend        = genphy_suspend,
 615        .resume         = genphy_resume,
 616        .driver         = { .owner = THIS_MODULE,},
 617}, {
 618        .phy_id         = PHY_ID_KSZ8041RNLI,
 619        .phy_id_mask    = 0x00fffff0,
 620        .name           = "Micrel KSZ8041RNLI",
 621        .features       = PHY_BASIC_FEATURES |
 622                          SUPPORTED_Pause | SUPPORTED_Asym_Pause,
 623        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 624        .driver_data    = &ksz8041_type,
 625        .probe          = kszphy_probe,
 626        .config_init    = kszphy_config_init,
 627        .config_aneg    = genphy_config_aneg,
 628        .read_status    = genphy_read_status,
 629        .ack_interrupt  = kszphy_ack_interrupt,
 630        .config_intr    = kszphy_config_intr,
 631        .suspend        = genphy_suspend,
 632        .resume         = genphy_resume,
 633        .driver         = { .owner = THIS_MODULE,},
 634}, {
 635        .phy_id         = PHY_ID_KSZ8051,
 636        .phy_id_mask    = 0x00fffff0,
 637        .name           = "Micrel KSZ8051",
 638        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause
 639                                | SUPPORTED_Asym_Pause),
 640        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 641        .driver_data    = &ksz8051_type,
 642        .probe          = kszphy_probe,
 643        .config_init    = kszphy_config_init,
 644        .config_aneg    = genphy_config_aneg,
 645        .read_status    = genphy_read_status,
 646        .ack_interrupt  = kszphy_ack_interrupt,
 647        .config_intr    = kszphy_config_intr,
 648        .suspend        = genphy_suspend,
 649        .resume         = genphy_resume,
 650        .driver         = { .owner = THIS_MODULE,},
 651}, {
 652        .phy_id         = PHY_ID_KSZ8001,
 653        .name           = "Micrel KSZ8001 or KS8721",
 654        .phy_id_mask    = 0x00ffffff,
 655        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 656        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 657        .driver_data    = &ksz8041_type,
 658        .probe          = kszphy_probe,
 659        .config_init    = kszphy_config_init,
 660        .config_aneg    = genphy_config_aneg,
 661        .read_status    = genphy_read_status,
 662        .ack_interrupt  = kszphy_ack_interrupt,
 663        .config_intr    = kszphy_config_intr,
 664        .suspend        = genphy_suspend,
 665        .resume         = genphy_resume,
 666        .driver         = { .owner = THIS_MODULE,},
 667}, {
 668        .phy_id         = PHY_ID_KSZ8081,
 669        .name           = "Micrel KSZ8081 or KSZ8091",
 670        .phy_id_mask    = 0x00fffff0,
 671        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 672        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 673        .driver_data    = &ksz8081_type,
 674        .probe          = kszphy_probe,
 675        .config_init    = kszphy_config_init,
 676        .config_aneg    = genphy_config_aneg,
 677        .read_status    = genphy_read_status,
 678        .ack_interrupt  = kszphy_ack_interrupt,
 679        .config_intr    = kszphy_config_intr,
 680        .suspend        = genphy_suspend,
 681        .resume         = genphy_resume,
 682        .driver         = { .owner = THIS_MODULE,},
 683}, {
 684        .phy_id         = PHY_ID_KSZ8061,
 685        .name           = "Micrel KSZ8061",
 686        .phy_id_mask    = 0x00fffff0,
 687        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 688        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 689        .config_init    = kszphy_config_init,
 690        .config_aneg    = genphy_config_aneg,
 691        .read_status    = genphy_read_status,
 692        .ack_interrupt  = kszphy_ack_interrupt,
 693        .config_intr    = kszphy_config_intr,
 694        .suspend        = genphy_suspend,
 695        .resume         = genphy_resume,
 696        .driver         = { .owner = THIS_MODULE,},
 697}, {
 698        .phy_id         = PHY_ID_KSZ9021,
 699        .phy_id_mask    = 0x000ffffe,
 700        .name           = "Micrel KSZ9021 Gigabit PHY",
 701        .features       = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
 702        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 703        .driver_data    = &ksz9021_type,
 704        .config_init    = ksz9021_config_init,
 705        .config_aneg    = genphy_config_aneg,
 706        .read_status    = genphy_read_status,
 707        .ack_interrupt  = kszphy_ack_interrupt,
 708        .config_intr    = kszphy_config_intr,
 709        .suspend        = genphy_suspend,
 710        .resume         = genphy_resume,
 711        .read_mmd_indirect = ksz9021_rd_mmd_phyreg,
 712        .write_mmd_indirect = ksz9021_wr_mmd_phyreg,
 713        .driver         = { .owner = THIS_MODULE, },
 714}, {
 715        .phy_id         = PHY_ID_KSZ9031,
 716        .phy_id_mask    = 0x00fffff0,
 717        .name           = "Micrel KSZ9031 Gigabit PHY",
 718        .features       = (PHY_GBIT_FEATURES | SUPPORTED_Pause),
 719        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 720        .driver_data    = &ksz9021_type,
 721        .config_init    = ksz9031_config_init,
 722        .config_aneg    = genphy_config_aneg,
 723        .read_status    = genphy_read_status,
 724        .ack_interrupt  = kszphy_ack_interrupt,
 725        .config_intr    = kszphy_config_intr,
 726        .suspend        = genphy_suspend,
 727        .resume         = genphy_resume,
 728        .driver         = { .owner = THIS_MODULE, },
 729}, {
 730        .phy_id         = PHY_ID_KSZ8873MLL,
 731        .phy_id_mask    = 0x00fffff0,
 732        .name           = "Micrel KSZ8873MLL Switch",
 733        .features       = (SUPPORTED_Pause | SUPPORTED_Asym_Pause),
 734        .flags          = PHY_HAS_MAGICANEG,
 735        .config_init    = kszphy_config_init,
 736        .config_aneg    = ksz8873mll_config_aneg,
 737        .read_status    = ksz8873mll_read_status,
 738        .suspend        = genphy_suspend,
 739        .resume         = genphy_resume,
 740        .driver         = { .owner = THIS_MODULE, },
 741}, {
 742        .phy_id         = PHY_ID_KSZ886X,
 743        .phy_id_mask    = 0x00fffff0,
 744        .name           = "Micrel KSZ886X Switch",
 745        .features       = (PHY_BASIC_FEATURES | SUPPORTED_Pause),
 746        .flags          = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
 747        .config_init    = kszphy_config_init,
 748        .config_aneg    = genphy_config_aneg,
 749        .read_status    = genphy_read_status,
 750        .suspend        = genphy_suspend,
 751        .resume         = genphy_resume,
 752        .driver         = { .owner = THIS_MODULE, },
 753} };
 754
 755module_phy_driver(ksphy_driver);
 756
 757MODULE_DESCRIPTION("Micrel PHY driver");
 758MODULE_AUTHOR("David J. Choi");
 759MODULE_LICENSE("GPL");
 760
 761static struct mdio_device_id __maybe_unused micrel_tbl[] = {
 762        { PHY_ID_KSZ9021, 0x000ffffe },
 763        { PHY_ID_KSZ9031, 0x00fffff0 },
 764        { PHY_ID_KSZ8001, 0x00ffffff },
 765        { PHY_ID_KS8737, 0x00fffff0 },
 766        { PHY_ID_KSZ8021, 0x00ffffff },
 767        { PHY_ID_KSZ8031, 0x00ffffff },
 768        { PHY_ID_KSZ8041, 0x00fffff0 },
 769        { PHY_ID_KSZ8051, 0x00fffff0 },
 770        { PHY_ID_KSZ8061, 0x00fffff0 },
 771        { PHY_ID_KSZ8081, 0x00fffff0 },
 772        { PHY_ID_KSZ8873MLL, 0x00fffff0 },
 773        { PHY_ID_KSZ886X, 0x00fffff0 },
 774        { }
 775};
 776
 777MODULE_DEVICE_TABLE(mdio, micrel_tbl);
 778