0001
0002
0003
0004
0005
0006
0007
0008
0009 #include <linux/module.h>
0010 #include <linux/bitfield.h>
0011 #include <linux/hwmon.h>
0012 #include <linux/phy.h>
0013 #include <linux/polynomial.h>
0014 #include <linux/netdevice.h>
0015
0016
0017 #define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
0018 #define PHY_ID_GPY21xB_MASK 0xFFFFFFF9
0019 #define PHY_ID_GPY2xx 0x67C9DC00
0020 #define PHY_ID_GPY115B 0x67C9DF00
0021 #define PHY_ID_GPY115C 0x67C9DF10
0022 #define PHY_ID_GPY211B 0x67C9DE08
0023 #define PHY_ID_GPY211C 0x67C9DE10
0024 #define PHY_ID_GPY212B 0x67C9DE09
0025 #define PHY_ID_GPY212C 0x67C9DE20
0026 #define PHY_ID_GPY215B 0x67C9DF04
0027 #define PHY_ID_GPY215C 0x67C9DF20
0028 #define PHY_ID_GPY241B 0x67C9DE40
0029 #define PHY_ID_GPY241BM 0x67C9DE80
0030 #define PHY_ID_GPY245B 0x67C9DEC0
0031
0032 #define PHY_MIISTAT 0x18
0033 #define PHY_IMASK 0x19
0034 #define PHY_ISTAT 0x1A
0035 #define PHY_FWV 0x1E
0036
0037 #define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
0038 #define PHY_MIISTAT_DPX BIT(3)
0039 #define PHY_MIISTAT_LS BIT(10)
0040
0041 #define PHY_MIISTAT_SPD_10 0
0042 #define PHY_MIISTAT_SPD_100 1
0043 #define PHY_MIISTAT_SPD_1000 2
0044 #define PHY_MIISTAT_SPD_2500 4
0045
0046 #define PHY_IMASK_WOL BIT(15)
0047 #define PHY_IMASK_ANC BIT(10)
0048 #define PHY_IMASK_ADSC BIT(5)
0049 #define PHY_IMASK_DXMC BIT(2)
0050 #define PHY_IMASK_LSPC BIT(1)
0051 #define PHY_IMASK_LSTC BIT(0)
0052 #define PHY_IMASK_MASK (PHY_IMASK_LSTC | \
0053 PHY_IMASK_LSPC | \
0054 PHY_IMASK_DXMC | \
0055 PHY_IMASK_ADSC | \
0056 PHY_IMASK_ANC)
0057
0058 #define PHY_FWV_REL_MASK BIT(15)
0059 #define PHY_FWV_MAJOR_MASK GENMASK(11, 8)
0060 #define PHY_FWV_MINOR_MASK GENMASK(7, 0)
0061
0062
0063 #define VSPEC1_SGMII_CTRL 0x08
0064 #define VSPEC1_SGMII_CTRL_ANEN BIT(12)
0065 #define VSPEC1_SGMII_CTRL_ANRS BIT(9)
0066 #define VSPEC1_SGMII_ANEN_ANRS (VSPEC1_SGMII_CTRL_ANEN | \
0067 VSPEC1_SGMII_CTRL_ANRS)
0068
0069
0070 #define VPSPEC1_TEMP_STA 0x0E
0071 #define VPSPEC1_TEMP_STA_DATA GENMASK(9, 0)
0072
0073
0074 #define VPSPEC2_WOL_CTL 0x0E06
0075 #define VPSPEC2_WOL_AD01 0x0E08
0076 #define VPSPEC2_WOL_AD23 0x0E09
0077 #define VPSPEC2_WOL_AD45 0x0E0A
0078 #define WOL_EN BIT(0)
0079
0080 struct gpy_priv {
0081 u8 fw_major;
0082 u8 fw_minor;
0083 };
0084
0085 static const struct {
0086 int major;
0087 int minor;
0088 } ver_need_sgmii_reaneg[] = {
0089 {7, 0x6D},
0090 {8, 0x6D},
0091 {9, 0x73},
0092 };
0093
0094 #if IS_ENABLED(CONFIG_HWMON)
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115 static const struct polynomial poly_N_to_temp = {
0116 .terms = {
0117 {4, -25761, 1000, 1},
0118 {3, 97332, 1000, 1},
0119 {2, -191650, 1000, 1},
0120 {1, 307620, 1000, 1},
0121 {0, -52156, 1, 1}
0122 }
0123 };
0124
0125 static int gpy_hwmon_read(struct device *dev,
0126 enum hwmon_sensor_types type,
0127 u32 attr, int channel, long *value)
0128 {
0129 struct phy_device *phydev = dev_get_drvdata(dev);
0130 int ret;
0131
0132 ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VPSPEC1_TEMP_STA);
0133 if (ret < 0)
0134 return ret;
0135 if (!ret)
0136 return -ENODATA;
0137
0138 *value = polynomial_calc(&poly_N_to_temp,
0139 FIELD_GET(VPSPEC1_TEMP_STA_DATA, ret));
0140
0141 return 0;
0142 }
0143
0144 static umode_t gpy_hwmon_is_visible(const void *data,
0145 enum hwmon_sensor_types type,
0146 u32 attr, int channel)
0147 {
0148 return 0444;
0149 }
0150
0151 static const struct hwmon_channel_info *gpy_hwmon_info[] = {
0152 HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
0153 NULL
0154 };
0155
0156 static const struct hwmon_ops gpy_hwmon_hwmon_ops = {
0157 .is_visible = gpy_hwmon_is_visible,
0158 .read = gpy_hwmon_read,
0159 };
0160
0161 static const struct hwmon_chip_info gpy_hwmon_chip_info = {
0162 .ops = &gpy_hwmon_hwmon_ops,
0163 .info = gpy_hwmon_info,
0164 };
0165
0166 static int gpy_hwmon_register(struct phy_device *phydev)
0167 {
0168 struct device *dev = &phydev->mdio.dev;
0169 struct device *hwmon_dev;
0170 char *hwmon_name;
0171
0172 hwmon_name = devm_hwmon_sanitize_name(dev, dev_name(dev));
0173 if (IS_ERR(hwmon_name))
0174 return PTR_ERR(hwmon_name);
0175
0176 hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_name,
0177 phydev,
0178 &gpy_hwmon_chip_info,
0179 NULL);
0180
0181 return PTR_ERR_OR_ZERO(hwmon_dev);
0182 }
0183 #else
0184 static int gpy_hwmon_register(struct phy_device *phydev)
0185 {
0186 return 0;
0187 }
0188 #endif
0189
0190 static int gpy_config_init(struct phy_device *phydev)
0191 {
0192 int ret;
0193
0194
0195 ret = phy_write(phydev, PHY_IMASK, 0);
0196 if (ret)
0197 return ret;
0198
0199
0200 ret = phy_read(phydev, PHY_ISTAT);
0201 return ret < 0 ? ret : 0;
0202 }
0203
0204 static int gpy_probe(struct phy_device *phydev)
0205 {
0206 struct device *dev = &phydev->mdio.dev;
0207 struct gpy_priv *priv;
0208 int fw_version;
0209 int ret;
0210
0211 if (!phydev->is_c45) {
0212 ret = phy_get_c45_ids(phydev);
0213 if (ret < 0)
0214 return ret;
0215 }
0216
0217 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
0218 if (!priv)
0219 return -ENOMEM;
0220 phydev->priv = priv;
0221
0222 fw_version = phy_read(phydev, PHY_FWV);
0223 if (fw_version < 0)
0224 return fw_version;
0225 priv->fw_major = FIELD_GET(PHY_FWV_MAJOR_MASK, fw_version);
0226 priv->fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_version);
0227
0228 ret = gpy_hwmon_register(phydev);
0229 if (ret)
0230 return ret;
0231
0232
0233 phydev_info(phydev, "Firmware Version: %d.%d (0x%04X%s)\n",
0234 priv->fw_major, priv->fw_minor, fw_version,
0235 fw_version & PHY_FWV_REL_MASK ? "" : " test version");
0236
0237 return 0;
0238 }
0239
0240 static bool gpy_sgmii_need_reaneg(struct phy_device *phydev)
0241 {
0242 struct gpy_priv *priv = phydev->priv;
0243 size_t i;
0244
0245 for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) {
0246 if (priv->fw_major != ver_need_sgmii_reaneg[i].major)
0247 continue;
0248 if (priv->fw_minor < ver_need_sgmii_reaneg[i].minor)
0249 return true;
0250 break;
0251 }
0252
0253 return false;
0254 }
0255
0256 static bool gpy_2500basex_chk(struct phy_device *phydev)
0257 {
0258 int ret;
0259
0260 ret = phy_read(phydev, PHY_MIISTAT);
0261 if (ret < 0) {
0262 phydev_err(phydev, "Error: MDIO register access failed: %d\n",
0263 ret);
0264 return false;
0265 }
0266
0267 if (!(ret & PHY_MIISTAT_LS) ||
0268 FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500)
0269 return false;
0270
0271 phydev->speed = SPEED_2500;
0272 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
0273 phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0274 VSPEC1_SGMII_CTRL_ANEN, 0);
0275 return true;
0276 }
0277
0278 static bool gpy_sgmii_aneg_en(struct phy_device *phydev)
0279 {
0280 int ret;
0281
0282 ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL);
0283 if (ret < 0) {
0284 phydev_err(phydev, "Error: MMD register access failed: %d\n",
0285 ret);
0286 return true;
0287 }
0288
0289 return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false;
0290 }
0291
0292 static int gpy_config_aneg(struct phy_device *phydev)
0293 {
0294 bool changed = false;
0295 u32 adv;
0296 int ret;
0297
0298 if (phydev->autoneg == AUTONEG_DISABLE) {
0299
0300
0301
0302 return phydev->duplex != DUPLEX_FULL
0303 ? genphy_setup_forced(phydev)
0304 : genphy_c45_pma_setup_forced(phydev);
0305 }
0306
0307 ret = genphy_c45_an_config_aneg(phydev);
0308 if (ret < 0)
0309 return ret;
0310 if (ret > 0)
0311 changed = true;
0312
0313 adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
0314 ret = phy_modify_changed(phydev, MII_CTRL1000,
0315 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
0316 adv);
0317 if (ret < 0)
0318 return ret;
0319 if (ret > 0)
0320 changed = true;
0321
0322 ret = genphy_c45_check_and_restart_aneg(phydev, changed);
0323 if (ret < 0)
0324 return ret;
0325
0326 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
0327 phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
0328 return 0;
0329
0330
0331
0332
0333 if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) ||
0334 !gpy_sgmii_aneg_en(phydev))
0335 return 0;
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350
0351
0352
0353
0354
0355
0356
0357
0358 if (phydev->state != PHY_UP)
0359 return 0;
0360
0361 ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS,
0362 20000, 4000000, false);
0363 if (ret == -ETIMEDOUT)
0364 return 0;
0365 else if (ret < 0)
0366 return ret;
0367
0368
0369 return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0370 VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS);
0371 }
0372
0373 static void gpy_update_interface(struct phy_device *phydev)
0374 {
0375 int ret;
0376
0377
0378 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
0379 phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
0380 return;
0381
0382
0383
0384
0385 switch (phydev->speed) {
0386 case SPEED_2500:
0387 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
0388 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0389 VSPEC1_SGMII_CTRL_ANEN, 0);
0390 if (ret < 0)
0391 phydev_err(phydev,
0392 "Error: Disable of SGMII ANEG failed: %d\n",
0393 ret);
0394 break;
0395 case SPEED_1000:
0396 case SPEED_100:
0397 case SPEED_10:
0398 phydev->interface = PHY_INTERFACE_MODE_SGMII;
0399 if (gpy_sgmii_aneg_en(phydev))
0400 break;
0401
0402
0403
0404 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
0405 VSPEC1_SGMII_ANEN_ANRS,
0406 VSPEC1_SGMII_ANEN_ANRS);
0407 if (ret < 0)
0408 phydev_err(phydev,
0409 "Error: Enable of SGMII ANEG failed: %d\n",
0410 ret);
0411 break;
0412 }
0413
0414 if (phydev->speed == SPEED_2500 || phydev->speed == SPEED_1000)
0415 genphy_read_master_slave(phydev);
0416 }
0417
0418 static int gpy_read_status(struct phy_device *phydev)
0419 {
0420 int ret;
0421
0422 ret = genphy_update_link(phydev);
0423 if (ret)
0424 return ret;
0425
0426 phydev->speed = SPEED_UNKNOWN;
0427 phydev->duplex = DUPLEX_UNKNOWN;
0428 phydev->pause = 0;
0429 phydev->asym_pause = 0;
0430
0431 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
0432 ret = genphy_c45_read_lpa(phydev);
0433 if (ret < 0)
0434 return ret;
0435
0436
0437 ret = phy_read(phydev, MII_STAT1000);
0438 if (ret < 0)
0439 return ret;
0440 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
0441 } else if (phydev->autoneg == AUTONEG_DISABLE) {
0442 linkmode_zero(phydev->lp_advertising);
0443 }
0444
0445 ret = phy_read(phydev, PHY_MIISTAT);
0446 if (ret < 0)
0447 return ret;
0448
0449 phydev->link = (ret & PHY_MIISTAT_LS) ? 1 : 0;
0450 phydev->duplex = (ret & PHY_MIISTAT_DPX) ? DUPLEX_FULL : DUPLEX_HALF;
0451 switch (FIELD_GET(PHY_MIISTAT_SPD_MASK, ret)) {
0452 case PHY_MIISTAT_SPD_10:
0453 phydev->speed = SPEED_10;
0454 break;
0455 case PHY_MIISTAT_SPD_100:
0456 phydev->speed = SPEED_100;
0457 break;
0458 case PHY_MIISTAT_SPD_1000:
0459 phydev->speed = SPEED_1000;
0460 break;
0461 case PHY_MIISTAT_SPD_2500:
0462 phydev->speed = SPEED_2500;
0463 break;
0464 }
0465
0466 if (phydev->link)
0467 gpy_update_interface(phydev);
0468
0469 return 0;
0470 }
0471
0472 static int gpy_config_intr(struct phy_device *phydev)
0473 {
0474 u16 mask = 0;
0475
0476 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
0477 mask = PHY_IMASK_MASK;
0478
0479 return phy_write(phydev, PHY_IMASK, mask);
0480 }
0481
0482 static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev)
0483 {
0484 int reg;
0485
0486 reg = phy_read(phydev, PHY_ISTAT);
0487 if (reg < 0) {
0488 phy_error(phydev);
0489 return IRQ_NONE;
0490 }
0491
0492 if (!(reg & PHY_IMASK_MASK))
0493 return IRQ_NONE;
0494
0495 phy_trigger_machine(phydev);
0496
0497 return IRQ_HANDLED;
0498 }
0499
0500 static int gpy_set_wol(struct phy_device *phydev,
0501 struct ethtool_wolinfo *wol)
0502 {
0503 struct net_device *attach_dev = phydev->attached_dev;
0504 int ret;
0505
0506 if (wol->wolopts & WAKE_MAGIC) {
0507
0508
0509
0510
0511
0512 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0513 VPSPEC2_WOL_AD45,
0514 ((attach_dev->dev_addr[0] << 8) |
0515 attach_dev->dev_addr[1]));
0516 if (ret < 0)
0517 return ret;
0518
0519 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0520 VPSPEC2_WOL_AD23,
0521 ((attach_dev->dev_addr[2] << 8) |
0522 attach_dev->dev_addr[3]));
0523 if (ret < 0)
0524 return ret;
0525
0526 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0527 VPSPEC2_WOL_AD01,
0528 ((attach_dev->dev_addr[4] << 8) |
0529 attach_dev->dev_addr[5]));
0530 if (ret < 0)
0531 return ret;
0532
0533
0534 ret = phy_write(phydev, PHY_IMASK, PHY_IMASK_WOL);
0535 if (ret < 0)
0536 return ret;
0537
0538
0539 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
0540 VPSPEC2_WOL_CTL,
0541 WOL_EN);
0542 if (ret < 0)
0543 return ret;
0544
0545
0546
0547
0548 ret = phy_read(phydev, PHY_ISTAT);
0549 if (ret < 0)
0550 return ret;
0551 } else {
0552
0553 ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
0554 VPSPEC2_WOL_CTL,
0555 WOL_EN);
0556 if (ret < 0)
0557 return ret;
0558 }
0559
0560 if (wol->wolopts & WAKE_PHY) {
0561
0562 ret = phy_set_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
0563 if (ret < 0)
0564 return ret;
0565
0566
0567 ret = phy_read(phydev, PHY_ISTAT);
0568 if (ret < 0)
0569 return ret;
0570
0571 if (ret & (PHY_IMASK_MASK & ~PHY_IMASK_LSTC))
0572 phy_trigger_machine(phydev);
0573
0574 return 0;
0575 }
0576
0577
0578 return phy_clear_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
0579 }
0580
0581 static void gpy_get_wol(struct phy_device *phydev,
0582 struct ethtool_wolinfo *wol)
0583 {
0584 int ret;
0585
0586 wol->supported = WAKE_MAGIC | WAKE_PHY;
0587 wol->wolopts = 0;
0588
0589 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, VPSPEC2_WOL_CTL);
0590 if (ret & WOL_EN)
0591 wol->wolopts |= WAKE_MAGIC;
0592
0593 ret = phy_read(phydev, PHY_IMASK);
0594 if (ret & PHY_IMASK_LSTC)
0595 wol->wolopts |= WAKE_PHY;
0596 }
0597
0598 static int gpy_loopback(struct phy_device *phydev, bool enable)
0599 {
0600 int ret;
0601
0602 ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
0603 enable ? BMCR_LOOPBACK : 0);
0604 if (!ret) {
0605
0606
0607
0608 msleep(100);
0609 }
0610
0611 return ret;
0612 }
0613
0614 static int gpy115_loopback(struct phy_device *phydev, bool enable)
0615 {
0616 struct gpy_priv *priv = phydev->priv;
0617
0618 if (enable)
0619 return gpy_loopback(phydev, enable);
0620
0621 if (priv->fw_minor > 0x76)
0622 return gpy_loopback(phydev, 0);
0623
0624 return genphy_soft_reset(phydev);
0625 }
0626
0627 static struct phy_driver gpy_drivers[] = {
0628 {
0629 PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
0630 .name = "Maxlinear Ethernet GPY2xx",
0631 .get_features = genphy_c45_pma_read_abilities,
0632 .config_init = gpy_config_init,
0633 .probe = gpy_probe,
0634 .suspend = genphy_suspend,
0635 .resume = genphy_resume,
0636 .config_aneg = gpy_config_aneg,
0637 .aneg_done = genphy_c45_aneg_done,
0638 .read_status = gpy_read_status,
0639 .config_intr = gpy_config_intr,
0640 .handle_interrupt = gpy_handle_interrupt,
0641 .set_wol = gpy_set_wol,
0642 .get_wol = gpy_get_wol,
0643 .set_loopback = gpy_loopback,
0644 },
0645 {
0646 .phy_id = PHY_ID_GPY115B,
0647 .phy_id_mask = PHY_ID_GPYx15B_MASK,
0648 .name = "Maxlinear Ethernet GPY115B",
0649 .get_features = genphy_c45_pma_read_abilities,
0650 .config_init = gpy_config_init,
0651 .probe = gpy_probe,
0652 .suspend = genphy_suspend,
0653 .resume = genphy_resume,
0654 .config_aneg = gpy_config_aneg,
0655 .aneg_done = genphy_c45_aneg_done,
0656 .read_status = gpy_read_status,
0657 .config_intr = gpy_config_intr,
0658 .handle_interrupt = gpy_handle_interrupt,
0659 .set_wol = gpy_set_wol,
0660 .get_wol = gpy_get_wol,
0661 .set_loopback = gpy115_loopback,
0662 },
0663 {
0664 PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
0665 .name = "Maxlinear Ethernet GPY115C",
0666 .get_features = genphy_c45_pma_read_abilities,
0667 .config_init = gpy_config_init,
0668 .probe = gpy_probe,
0669 .suspend = genphy_suspend,
0670 .resume = genphy_resume,
0671 .config_aneg = gpy_config_aneg,
0672 .aneg_done = genphy_c45_aneg_done,
0673 .read_status = gpy_read_status,
0674 .config_intr = gpy_config_intr,
0675 .handle_interrupt = gpy_handle_interrupt,
0676 .set_wol = gpy_set_wol,
0677 .get_wol = gpy_get_wol,
0678 .set_loopback = gpy115_loopback,
0679 },
0680 {
0681 .phy_id = PHY_ID_GPY211B,
0682 .phy_id_mask = PHY_ID_GPY21xB_MASK,
0683 .name = "Maxlinear Ethernet GPY211B",
0684 .get_features = genphy_c45_pma_read_abilities,
0685 .config_init = gpy_config_init,
0686 .probe = gpy_probe,
0687 .suspend = genphy_suspend,
0688 .resume = genphy_resume,
0689 .config_aneg = gpy_config_aneg,
0690 .aneg_done = genphy_c45_aneg_done,
0691 .read_status = gpy_read_status,
0692 .config_intr = gpy_config_intr,
0693 .handle_interrupt = gpy_handle_interrupt,
0694 .set_wol = gpy_set_wol,
0695 .get_wol = gpy_get_wol,
0696 .set_loopback = gpy_loopback,
0697 },
0698 {
0699 PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
0700 .name = "Maxlinear Ethernet GPY211C",
0701 .get_features = genphy_c45_pma_read_abilities,
0702 .config_init = gpy_config_init,
0703 .probe = gpy_probe,
0704 .suspend = genphy_suspend,
0705 .resume = genphy_resume,
0706 .config_aneg = gpy_config_aneg,
0707 .aneg_done = genphy_c45_aneg_done,
0708 .read_status = gpy_read_status,
0709 .config_intr = gpy_config_intr,
0710 .handle_interrupt = gpy_handle_interrupt,
0711 .set_wol = gpy_set_wol,
0712 .get_wol = gpy_get_wol,
0713 .set_loopback = gpy_loopback,
0714 },
0715 {
0716 .phy_id = PHY_ID_GPY212B,
0717 .phy_id_mask = PHY_ID_GPY21xB_MASK,
0718 .name = "Maxlinear Ethernet GPY212B",
0719 .get_features = genphy_c45_pma_read_abilities,
0720 .config_init = gpy_config_init,
0721 .probe = gpy_probe,
0722 .suspend = genphy_suspend,
0723 .resume = genphy_resume,
0724 .config_aneg = gpy_config_aneg,
0725 .aneg_done = genphy_c45_aneg_done,
0726 .read_status = gpy_read_status,
0727 .config_intr = gpy_config_intr,
0728 .handle_interrupt = gpy_handle_interrupt,
0729 .set_wol = gpy_set_wol,
0730 .get_wol = gpy_get_wol,
0731 .set_loopback = gpy_loopback,
0732 },
0733 {
0734 PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
0735 .name = "Maxlinear Ethernet GPY212C",
0736 .get_features = genphy_c45_pma_read_abilities,
0737 .config_init = gpy_config_init,
0738 .probe = gpy_probe,
0739 .suspend = genphy_suspend,
0740 .resume = genphy_resume,
0741 .config_aneg = gpy_config_aneg,
0742 .aneg_done = genphy_c45_aneg_done,
0743 .read_status = gpy_read_status,
0744 .config_intr = gpy_config_intr,
0745 .handle_interrupt = gpy_handle_interrupt,
0746 .set_wol = gpy_set_wol,
0747 .get_wol = gpy_get_wol,
0748 .set_loopback = gpy_loopback,
0749 },
0750 {
0751 .phy_id = PHY_ID_GPY215B,
0752 .phy_id_mask = PHY_ID_GPYx15B_MASK,
0753 .name = "Maxlinear Ethernet GPY215B",
0754 .get_features = genphy_c45_pma_read_abilities,
0755 .config_init = gpy_config_init,
0756 .probe = gpy_probe,
0757 .suspend = genphy_suspend,
0758 .resume = genphy_resume,
0759 .config_aneg = gpy_config_aneg,
0760 .aneg_done = genphy_c45_aneg_done,
0761 .read_status = gpy_read_status,
0762 .config_intr = gpy_config_intr,
0763 .handle_interrupt = gpy_handle_interrupt,
0764 .set_wol = gpy_set_wol,
0765 .get_wol = gpy_get_wol,
0766 .set_loopback = gpy_loopback,
0767 },
0768 {
0769 PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
0770 .name = "Maxlinear Ethernet GPY215C",
0771 .get_features = genphy_c45_pma_read_abilities,
0772 .config_init = gpy_config_init,
0773 .probe = gpy_probe,
0774 .suspend = genphy_suspend,
0775 .resume = genphy_resume,
0776 .config_aneg = gpy_config_aneg,
0777 .aneg_done = genphy_c45_aneg_done,
0778 .read_status = gpy_read_status,
0779 .config_intr = gpy_config_intr,
0780 .handle_interrupt = gpy_handle_interrupt,
0781 .set_wol = gpy_set_wol,
0782 .get_wol = gpy_get_wol,
0783 .set_loopback = gpy_loopback,
0784 },
0785 {
0786 PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
0787 .name = "Maxlinear Ethernet GPY241B",
0788 .get_features = genphy_c45_pma_read_abilities,
0789 .config_init = gpy_config_init,
0790 .probe = gpy_probe,
0791 .suspend = genphy_suspend,
0792 .resume = genphy_resume,
0793 .config_aneg = gpy_config_aneg,
0794 .aneg_done = genphy_c45_aneg_done,
0795 .read_status = gpy_read_status,
0796 .config_intr = gpy_config_intr,
0797 .handle_interrupt = gpy_handle_interrupt,
0798 .set_wol = gpy_set_wol,
0799 .get_wol = gpy_get_wol,
0800 .set_loopback = gpy_loopback,
0801 },
0802 {
0803 PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM),
0804 .name = "Maxlinear Ethernet GPY241BM",
0805 .get_features = genphy_c45_pma_read_abilities,
0806 .config_init = gpy_config_init,
0807 .probe = gpy_probe,
0808 .suspend = genphy_suspend,
0809 .resume = genphy_resume,
0810 .config_aneg = gpy_config_aneg,
0811 .aneg_done = genphy_c45_aneg_done,
0812 .read_status = gpy_read_status,
0813 .config_intr = gpy_config_intr,
0814 .handle_interrupt = gpy_handle_interrupt,
0815 .set_wol = gpy_set_wol,
0816 .get_wol = gpy_get_wol,
0817 .set_loopback = gpy_loopback,
0818 },
0819 {
0820 PHY_ID_MATCH_MODEL(PHY_ID_GPY245B),
0821 .name = "Maxlinear Ethernet GPY245B",
0822 .get_features = genphy_c45_pma_read_abilities,
0823 .config_init = gpy_config_init,
0824 .probe = gpy_probe,
0825 .suspend = genphy_suspend,
0826 .resume = genphy_resume,
0827 .config_aneg = gpy_config_aneg,
0828 .aneg_done = genphy_c45_aneg_done,
0829 .read_status = gpy_read_status,
0830 .config_intr = gpy_config_intr,
0831 .handle_interrupt = gpy_handle_interrupt,
0832 .set_wol = gpy_set_wol,
0833 .get_wol = gpy_get_wol,
0834 .set_loopback = gpy_loopback,
0835 },
0836 };
0837 module_phy_driver(gpy_drivers);
0838
0839 static struct mdio_device_id __maybe_unused gpy_tbl[] = {
0840 {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)},
0841 {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK},
0842 {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)},
0843 {PHY_ID_GPY211B, PHY_ID_GPY21xB_MASK},
0844 {PHY_ID_MATCH_MODEL(PHY_ID_GPY211C)},
0845 {PHY_ID_GPY212B, PHY_ID_GPY21xB_MASK},
0846 {PHY_ID_MATCH_MODEL(PHY_ID_GPY212C)},
0847 {PHY_ID_GPY215B, PHY_ID_GPYx15B_MASK},
0848 {PHY_ID_MATCH_MODEL(PHY_ID_GPY215C)},
0849 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)},
0850 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)},
0851 {PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)},
0852 { }
0853 };
0854 MODULE_DEVICE_TABLE(mdio, gpy_tbl);
0855
0856 MODULE_DESCRIPTION("Maxlinear Ethernet GPY Driver");
0857 MODULE_AUTHOR("Xu Liang");
0858 MODULE_LICENSE("GPL");