852 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * drivers/net/phy/smsc.c4 *5 * Driver for SMSC PHYs6 *7 * Author: Herbert Valerio Riedel8 *9 * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org>10 *11 * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net12 *13 */14 15#include <linux/clk.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/mii.h>19#include <linux/ethtool.h>20#include <linux/of.h>21#include <linux/phy.h>22#include <linux/netdevice.h>23#include <linux/crc16.h>24#include <linux/etherdevice.h>25#include <linux/smscphy.h>26 27/* Vendor-specific PHY Definitions */28/* EDPD NLP / crossover time configuration */29#define PHY_EDPD_CONFIG 1630#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ 0x000131 32/* Control/Status Indication Register */33#define SPECIAL_CTRL_STS 2734#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ 0x800035#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ 0x400036#define SPECIAL_CTRL_STS_AMDIX_STATE_ 0x200037 38#define EDPD_MAX_WAIT_DFLT_MS 64039/* interval between phylib state machine runs in ms */40#define PHY_STATE_MACH_MS 100041 42struct smsc_hw_stat {43 const char *string;44 u8 reg;45 u8 bits;46};47 48static struct smsc_hw_stat smsc_hw_stats[] = {49 { "phy_symbol_errors", 26, 16},50};51 52struct smsc_phy_priv {53 unsigned int edpd_enable:1;54 unsigned int edpd_mode_set_by_user:1;55 unsigned int edpd_max_wait_ms;56 bool wol_arp;57};58 59static int smsc_phy_ack_interrupt(struct phy_device *phydev)60{61 int rc = phy_read(phydev, MII_LAN83C185_ISF);62 63 return rc < 0 ? rc : 0;64}65 66int smsc_phy_config_intr(struct phy_device *phydev)67{68 int rc;69 70 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {71 rc = smsc_phy_ack_interrupt(phydev);72 if (rc)73 return rc;74 75 rc = phy_write(phydev, MII_LAN83C185_IM,76 MII_LAN83C185_ISF_INT_PHYLIB_EVENTS);77 } else {78 rc = phy_write(phydev, MII_LAN83C185_IM, 0);79 if (rc)80 return rc;81 82 rc = smsc_phy_ack_interrupt(phydev);83 }84 85 return rc < 0 ? rc : 0;86}87EXPORT_SYMBOL_GPL(smsc_phy_config_intr);88 89static int smsc_phy_config_edpd(struct phy_device *phydev)90{91 struct smsc_phy_priv *priv = phydev->priv;92 93 if (priv->edpd_enable)94 return phy_set_bits(phydev, MII_LAN83C185_CTRL_STATUS,95 MII_LAN83C185_EDPWRDOWN);96 else97 return phy_clear_bits(phydev, MII_LAN83C185_CTRL_STATUS,98 MII_LAN83C185_EDPWRDOWN);99}100 101irqreturn_t smsc_phy_handle_interrupt(struct phy_device *phydev)102{103 int irq_status;104 105 irq_status = phy_read(phydev, MII_LAN83C185_ISF);106 if (irq_status < 0) {107 if (irq_status != -ENODEV)108 phy_error(phydev);109 110 return IRQ_NONE;111 }112 113 if (!(irq_status & MII_LAN83C185_ISF_INT_PHYLIB_EVENTS))114 return IRQ_NONE;115 116 phy_trigger_machine(phydev);117 118 return IRQ_HANDLED;119}120EXPORT_SYMBOL_GPL(smsc_phy_handle_interrupt);121 122int smsc_phy_config_init(struct phy_device *phydev)123{124 struct smsc_phy_priv *priv = phydev->priv;125 126 if (!priv)127 return 0;128 129 /* don't use EDPD in irq mode except overridden by user */130 if (!priv->edpd_mode_set_by_user && phydev->irq != PHY_POLL)131 priv->edpd_enable = false;132 133 return smsc_phy_config_edpd(phydev);134}135EXPORT_SYMBOL_GPL(smsc_phy_config_init);136 137static int smsc_phy_reset(struct phy_device *phydev)138{139 int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);140 if (rc < 0)141 return rc;142 143 /* If the SMSC PHY is in power down mode, then set it144 * in all capable mode before using it.145 */146 if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {147 /* set "all capable" mode */148 rc |= MII_LAN83C185_MODE_ALL;149 phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);150 }151 152 /* reset the phy */153 return genphy_soft_reset(phydev);154}155 156static int lan87xx_config_aneg(struct phy_device *phydev)157{158 int rc;159 int val;160 161 switch (phydev->mdix_ctrl) {162 case ETH_TP_MDI:163 val = SPECIAL_CTRL_STS_OVRRD_AMDIX_;164 break;165 case ETH_TP_MDI_X:166 val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ |167 SPECIAL_CTRL_STS_AMDIX_STATE_;168 break;169 case ETH_TP_MDI_AUTO:170 val = SPECIAL_CTRL_STS_AMDIX_ENABLE_;171 break;172 default:173 return genphy_config_aneg(phydev);174 }175 176 rc = phy_read(phydev, SPECIAL_CTRL_STS);177 if (rc < 0)178 return rc;179 180 rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ |181 SPECIAL_CTRL_STS_AMDIX_ENABLE_ |182 SPECIAL_CTRL_STS_AMDIX_STATE_);183 rc |= val;184 phy_write(phydev, SPECIAL_CTRL_STS, rc);185 186 phydev->mdix = phydev->mdix_ctrl;187 return genphy_config_aneg(phydev);188}189 190static int lan95xx_config_aneg_ext(struct phy_device *phydev)191{192 if (phydev->phy_id == 0x0007c0f0) { /* LAN9500A or LAN9505A */193 /* Extend Manual AutoMDIX timer */194 int rc = phy_set_bits(phydev, PHY_EDPD_CONFIG,195 PHY_EDPD_CONFIG_EXT_CROSSOVER_);196 197 if (rc < 0)198 return rc;199 }200 201 return lan87xx_config_aneg(phydev);202}203 204/*205 * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable206 * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to207 * unstable detection of plugging in Ethernet cable.208 * This workaround disables Energy Detect Power-Down mode and waiting for209 * response on link pulses to detect presence of plugged Ethernet cable.210 * The Energy Detect Power-Down mode is enabled again in the end of procedure to211 * save approximately 220 mW of power if cable is unplugged.212 * The workaround is only applicable to poll mode. Energy Detect Power-Down may213 * not be used in interrupt mode lest link change detection becomes unreliable.214 */215int lan87xx_read_status(struct phy_device *phydev)216{217 struct smsc_phy_priv *priv = phydev->priv;218 int err;219 220 err = genphy_read_status(phydev);221 if (err)222 return err;223 224 if (!phydev->link && priv && priv->edpd_enable &&225 priv->edpd_max_wait_ms) {226 unsigned int max_wait = priv->edpd_max_wait_ms * 1000;227 int rc;228 229 /* Disable EDPD to wake up PHY */230 rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);231 if (rc < 0)232 return rc;233 234 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,235 rc & ~MII_LAN83C185_EDPWRDOWN);236 if (rc < 0)237 return rc;238 239 /* Wait max 640 ms to detect energy and the timeout is not240 * an actual error.241 */242 read_poll_timeout(phy_read, rc,243 rc & MII_LAN83C185_ENERGYON || rc < 0,244 10000, max_wait, true, phydev,245 MII_LAN83C185_CTRL_STATUS);246 if (rc < 0)247 return rc;248 249 /* Re-enable EDPD */250 rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS);251 if (rc < 0)252 return rc;253 254 rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS,255 rc | MII_LAN83C185_EDPWRDOWN);256 if (rc < 0)257 return rc;258 }259 260 return err;261}262EXPORT_SYMBOL_GPL(lan87xx_read_status);263 264static int lan874x_phy_config_init(struct phy_device *phydev)265{266 u16 val;267 int rc;268 269 /* Setup LED2/nINT/nPME pin to function as nPME. May need user option270 * to use LED1/nINT/nPME.271 */272 val = MII_LAN874X_PHY_PME2_SET;273 274 /* The bits MII_LAN874X_PHY_WOL_PFDA_FR, MII_LAN874X_PHY_WOL_WUFR,275 * MII_LAN874X_PHY_WOL_MPR, and MII_LAN874X_PHY_WOL_BCAST_FR need to276 * be cleared to de-assert PME signal after a WoL event happens, but277 * using PME auto clear gets around that.278 */279 val |= MII_LAN874X_PHY_PME_SELF_CLEAR;280 rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR,281 val);282 if (rc < 0)283 return rc;284 285 /* set nPME self clear delay time */286 rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_MCFGR,287 MII_LAN874X_PHY_PME_SELF_CLEAR_DELAY);288 if (rc < 0)289 return rc;290 291 return smsc_phy_config_init(phydev);292}293 294static void lan874x_get_wol(struct phy_device *phydev,295 struct ethtool_wolinfo *wol)296{297 struct smsc_phy_priv *priv = phydev->priv;298 int rc;299 300 wol->supported = (WAKE_UCAST | WAKE_BCAST | WAKE_MAGIC |301 WAKE_ARP | WAKE_MCAST);302 wol->wolopts = 0;303 304 rc = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR);305 if (rc < 0)306 return;307 308 if (rc & MII_LAN874X_PHY_WOL_PFDAEN)309 wol->wolopts |= WAKE_UCAST;310 311 if (rc & MII_LAN874X_PHY_WOL_BCSTEN)312 wol->wolopts |= WAKE_BCAST;313 314 if (rc & MII_LAN874X_PHY_WOL_MPEN)315 wol->wolopts |= WAKE_MAGIC;316 317 if (rc & MII_LAN874X_PHY_WOL_WUEN) {318 if (priv->wol_arp)319 wol->wolopts |= WAKE_ARP;320 else321 wol->wolopts |= WAKE_MCAST;322 }323}324 325static u16 smsc_crc16(const u8 *buffer, size_t len)326{327 return bitrev16(crc16(0xFFFF, buffer, len));328}329 330static int lan874x_chk_wol_pattern(const u8 pattern[], const u16 *mask,331 u8 len, u8 *data, u8 *datalen)332{333 size_t i, j, k;334 int ret = 0;335 u16 bits;336 337 /* Pattern filtering can match up to 128 bytes of frame data. There338 * are 8 registers to program the 16-bit masks, where each bit means339 * the byte will be compared. The frame data will then go through a340 * CRC16 calculation for hardware comparison. This helper function341 * makes sure only relevant frame data are included in this342 * calculation. It provides a warning when the masks and expected343 * data size do not match.344 */345 i = 0;346 k = 0;347 while (len > 0) {348 bits = *mask;349 for (j = 0; j < 16; j++, i++, len--) {350 /* No more pattern. */351 if (!len) {352 /* The rest of bitmap is not empty. */353 if (bits)354 ret = i + 1;355 break;356 }357 if (bits & 1)358 data[k++] = pattern[i];359 bits >>= 1;360 }361 mask++;362 }363 *datalen = k;364 return ret;365}366 367static int lan874x_set_wol_pattern(struct phy_device *phydev, u16 val,368 const u8 data[], u8 datalen,369 const u16 *mask, u8 masklen)370{371 u16 crc, reg;372 int rc;373 374 /* Starting pattern offset is set before calling this function. */375 val |= MII_LAN874X_PHY_WOL_FILTER_EN;376 rc = phy_write_mmd(phydev, MDIO_MMD_PCS,377 MII_LAN874X_PHY_MMD_WOL_WUF_CFGA, val);378 if (rc < 0)379 return rc;380 381 crc = smsc_crc16(data, datalen);382 rc = phy_write_mmd(phydev, MDIO_MMD_PCS,383 MII_LAN874X_PHY_MMD_WOL_WUF_CFGB, crc);384 if (rc < 0)385 return rc;386 387 masklen = (masklen + 15) & ~0xf;388 reg = MII_LAN874X_PHY_MMD_WOL_WUF_MASK7;389 while (masklen >= 16) {390 rc = phy_write_mmd(phydev, MDIO_MMD_PCS, reg, *mask);391 if (rc < 0)392 return rc;393 reg--;394 mask++;395 masklen -= 16;396 }397 398 /* Clear out the rest of mask registers. */399 while (reg != MII_LAN874X_PHY_MMD_WOL_WUF_MASK0) {400 phy_write_mmd(phydev, MDIO_MMD_PCS, reg, 0);401 reg--;402 }403 return rc;404}405 406static int lan874x_set_wol(struct phy_device *phydev,407 struct ethtool_wolinfo *wol)408{409 struct net_device *ndev = phydev->attached_dev;410 struct smsc_phy_priv *priv = phydev->priv;411 u16 val, val_wucsr;412 u8 data[128];413 u8 datalen;414 int rc;415 416 /* lan874x has only one WoL filter pattern */417 if ((wol->wolopts & (WAKE_ARP | WAKE_MCAST)) ==418 (WAKE_ARP | WAKE_MCAST)) {419 phydev_info(phydev,420 "lan874x WoL supports one of ARP|MCAST at a time\n");421 return -EOPNOTSUPP;422 }423 424 rc = phy_read_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR);425 if (rc < 0)426 return rc;427 428 val_wucsr = rc;429 430 if (wol->wolopts & WAKE_UCAST)431 val_wucsr |= MII_LAN874X_PHY_WOL_PFDAEN;432 else433 val_wucsr &= ~MII_LAN874X_PHY_WOL_PFDAEN;434 435 if (wol->wolopts & WAKE_BCAST)436 val_wucsr |= MII_LAN874X_PHY_WOL_BCSTEN;437 else438 val_wucsr &= ~MII_LAN874X_PHY_WOL_BCSTEN;439 440 if (wol->wolopts & WAKE_MAGIC)441 val_wucsr |= MII_LAN874X_PHY_WOL_MPEN;442 else443 val_wucsr &= ~MII_LAN874X_PHY_WOL_MPEN;444 445 /* Need to use pattern matching */446 if (wol->wolopts & (WAKE_ARP | WAKE_MCAST))447 val_wucsr |= MII_LAN874X_PHY_WOL_WUEN;448 else449 val_wucsr &= ~MII_LAN874X_PHY_WOL_WUEN;450 451 if (wol->wolopts & WAKE_ARP) {452 const u8 pattern[2] = { 0x08, 0x06 };453 const u16 mask[1] = { 0x0003 };454 455 rc = lan874x_chk_wol_pattern(pattern, mask, 2, data,456 &datalen);457 if (rc)458 phydev_dbg(phydev, "pattern not valid at %d\n", rc);459 460 /* Need to match broadcast destination address and provided461 * data pattern at offset 12.462 */463 val = 12 | MII_LAN874X_PHY_WOL_FILTER_BCSTEN;464 rc = lan874x_set_wol_pattern(phydev, val, data, datalen, mask,465 2);466 if (rc < 0)467 return rc;468 priv->wol_arp = true;469 }470 471 if (wol->wolopts & WAKE_MCAST) {472 /* Need to match multicast destination address. */473 val = MII_LAN874X_PHY_WOL_FILTER_MCASTTEN;474 rc = lan874x_set_wol_pattern(phydev, val, data, 0, NULL, 0);475 if (rc < 0)476 return rc;477 priv->wol_arp = false;478 }479 480 if (wol->wolopts & (WAKE_MAGIC | WAKE_UCAST)) {481 const u8 *mac = (const u8 *)ndev->dev_addr;482 int i, reg;483 484 reg = MII_LAN874X_PHY_MMD_WOL_RX_ADDRC;485 for (i = 0; i < 6; i += 2, reg--) {486 rc = phy_write_mmd(phydev, MDIO_MMD_PCS, reg,487 ((mac[i + 1] << 8) | mac[i]));488 if (rc < 0)489 return rc;490 }491 }492 493 rc = phy_write_mmd(phydev, MDIO_MMD_PCS, MII_LAN874X_PHY_MMD_WOL_WUCSR,494 val_wucsr);495 if (rc < 0)496 return rc;497 498 return 0;499}500 501static int smsc_get_sset_count(struct phy_device *phydev)502{503 return ARRAY_SIZE(smsc_hw_stats);504}505 506static void smsc_get_strings(struct phy_device *phydev, u8 *data)507{508 int i;509 510 for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)511 ethtool_puts(&data, smsc_hw_stats[i].string);512}513 514static u64 smsc_get_stat(struct phy_device *phydev, int i)515{516 struct smsc_hw_stat stat = smsc_hw_stats[i];517 int val;518 u64 ret;519 520 val = phy_read(phydev, stat.reg);521 if (val < 0)522 ret = U64_MAX;523 else524 ret = val;525 526 return ret;527}528 529static void smsc_get_stats(struct phy_device *phydev,530 struct ethtool_stats *stats, u64 *data)531{532 int i;533 534 for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++)535 data[i] = smsc_get_stat(phydev, i);536}537 538static int smsc_phy_get_edpd(struct phy_device *phydev, u16 *edpd)539{540 struct smsc_phy_priv *priv = phydev->priv;541 542 if (!priv)543 return -EOPNOTSUPP;544 545 if (!priv->edpd_enable)546 *edpd = ETHTOOL_PHY_EDPD_DISABLE;547 else if (!priv->edpd_max_wait_ms)548 *edpd = ETHTOOL_PHY_EDPD_NO_TX;549 else550 *edpd = PHY_STATE_MACH_MS + priv->edpd_max_wait_ms;551 552 return 0;553}554 555static int smsc_phy_set_edpd(struct phy_device *phydev, u16 edpd)556{557 struct smsc_phy_priv *priv = phydev->priv;558 559 if (!priv)560 return -EOPNOTSUPP;561 562 switch (edpd) {563 case ETHTOOL_PHY_EDPD_DISABLE:564 priv->edpd_enable = false;565 break;566 case ETHTOOL_PHY_EDPD_NO_TX:567 priv->edpd_enable = true;568 priv->edpd_max_wait_ms = 0;569 break;570 case ETHTOOL_PHY_EDPD_DFLT_TX_MSECS:571 edpd = PHY_STATE_MACH_MS + EDPD_MAX_WAIT_DFLT_MS;572 fallthrough;573 default:574 if (phydev->irq != PHY_POLL)575 return -EOPNOTSUPP;576 if (edpd < PHY_STATE_MACH_MS || edpd > PHY_STATE_MACH_MS + 1000)577 return -EINVAL;578 priv->edpd_enable = true;579 priv->edpd_max_wait_ms = edpd - PHY_STATE_MACH_MS;580 }581 582 priv->edpd_mode_set_by_user = true;583 584 return smsc_phy_config_edpd(phydev);585}586 587int smsc_phy_get_tunable(struct phy_device *phydev,588 struct ethtool_tunable *tuna, void *data)589{590 switch (tuna->id) {591 case ETHTOOL_PHY_EDPD:592 return smsc_phy_get_edpd(phydev, data);593 default:594 return -EOPNOTSUPP;595 }596}597EXPORT_SYMBOL_GPL(smsc_phy_get_tunable);598 599int smsc_phy_set_tunable(struct phy_device *phydev,600 struct ethtool_tunable *tuna, const void *data)601{602 switch (tuna->id) {603 case ETHTOOL_PHY_EDPD:604 return smsc_phy_set_edpd(phydev, *(u16 *)data);605 default:606 return -EOPNOTSUPP;607 }608}609EXPORT_SYMBOL_GPL(smsc_phy_set_tunable);610 611int smsc_phy_probe(struct phy_device *phydev)612{613 struct device *dev = &phydev->mdio.dev;614 struct smsc_phy_priv *priv;615 struct clk *refclk;616 617 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);618 if (!priv)619 return -ENOMEM;620 621 priv->edpd_enable = true;622 priv->edpd_max_wait_ms = EDPD_MAX_WAIT_DFLT_MS;623 624 if (device_property_present(dev, "smsc,disable-energy-detect"))625 priv->edpd_enable = false;626 627 phydev->priv = priv;628 629 /* Make clk optional to keep DTB backward compatibility. */630 refclk = devm_clk_get_optional_enabled(dev, NULL);631 if (IS_ERR(refclk))632 return dev_err_probe(dev, PTR_ERR(refclk),633 "Failed to request clock\n");634 635 return clk_set_rate(refclk, 50 * 1000 * 1000);636}637EXPORT_SYMBOL_GPL(smsc_phy_probe);638 639static struct phy_driver smsc_phy_driver[] = {640{641 .phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */642 .phy_id_mask = 0xfffffff0,643 .name = "SMSC LAN83C185",644 645 /* PHY_BASIC_FEATURES */646 647 .probe = smsc_phy_probe,648 649 /* basic functions */650 .config_init = smsc_phy_config_init,651 .soft_reset = smsc_phy_reset,652 653 /* IRQ related */654 .config_intr = smsc_phy_config_intr,655 .handle_interrupt = smsc_phy_handle_interrupt,656 657 .suspend = genphy_suspend,658 .resume = genphy_resume,659}, {660 .phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */661 .phy_id_mask = 0xfffffff0,662 .name = "SMSC LAN8187",663 664 /* PHY_BASIC_FEATURES */665 666 .probe = smsc_phy_probe,667 668 /* basic functions */669 .config_init = smsc_phy_config_init,670 .soft_reset = smsc_phy_reset,671 672 /* IRQ related */673 .config_intr = smsc_phy_config_intr,674 .handle_interrupt = smsc_phy_handle_interrupt,675 676 /* Statistics */677 .get_sset_count = smsc_get_sset_count,678 .get_strings = smsc_get_strings,679 .get_stats = smsc_get_stats,680 681 .suspend = genphy_suspend,682 .resume = genphy_resume,683}, {684 /* This covers internal PHY (phy_id: 0x0007C0C3) for685 * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505)686 */687 .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */688 .phy_id_mask = 0xfffffff0,689 .name = "SMSC LAN8700",690 691 /* PHY_BASIC_FEATURES */692 693 .probe = smsc_phy_probe,694 695 /* basic functions */696 .read_status = lan87xx_read_status,697 .config_init = smsc_phy_config_init,698 .soft_reset = smsc_phy_reset,699 .config_aneg = lan87xx_config_aneg,700 701 /* IRQ related */702 .config_intr = smsc_phy_config_intr,703 .handle_interrupt = smsc_phy_handle_interrupt,704 705 /* Statistics */706 .get_sset_count = smsc_get_sset_count,707 .get_strings = smsc_get_strings,708 .get_stats = smsc_get_stats,709 710 .get_tunable = smsc_phy_get_tunable,711 .set_tunable = smsc_phy_set_tunable,712 713 .suspend = genphy_suspend,714 .resume = genphy_resume,715}, {716 .phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */717 .phy_id_mask = 0xfffffff0,718 .name = "SMSC LAN911x Internal PHY",719 720 /* PHY_BASIC_FEATURES */721 722 .probe = smsc_phy_probe,723 724 /* IRQ related */725 .config_intr = smsc_phy_config_intr,726 .handle_interrupt = smsc_phy_handle_interrupt,727 728 .suspend = genphy_suspend,729 .resume = genphy_resume,730}, {731 /* This covers internal PHY (phy_id: 0x0007C0F0) for732 * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01)733 */734 .phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */735 .phy_id_mask = 0xfffffff0,736 .name = "SMSC LAN8710/LAN8720",737 738 /* PHY_BASIC_FEATURES */739 740 .probe = smsc_phy_probe,741 742 /* basic functions */743 .read_status = lan87xx_read_status,744 .config_init = smsc_phy_config_init,745 .soft_reset = smsc_phy_reset,746 .config_aneg = lan95xx_config_aneg_ext,747 748 /* IRQ related */749 .config_intr = smsc_phy_config_intr,750 .handle_interrupt = smsc_phy_handle_interrupt,751 752 /* Statistics */753 .get_sset_count = smsc_get_sset_count,754 .get_strings = smsc_get_strings,755 .get_stats = smsc_get_stats,756 757 .get_tunable = smsc_phy_get_tunable,758 .set_tunable = smsc_phy_set_tunable,759 760 .suspend = genphy_suspend,761 .resume = genphy_resume,762}, {763 .phy_id = 0x0007c110,764 .phy_id_mask = 0xfffffff0,765 .name = "SMSC LAN8740",766 767 /* PHY_BASIC_FEATURES */768 .flags = PHY_RST_AFTER_CLK_EN,769 770 .probe = smsc_phy_probe,771 772 /* basic functions */773 .read_status = lan87xx_read_status,774 .config_init = lan874x_phy_config_init,775 .soft_reset = smsc_phy_reset,776 777 /* IRQ related */778 .config_intr = smsc_phy_config_intr,779 .handle_interrupt = smsc_phy_handle_interrupt,780 781 /* Statistics */782 .get_sset_count = smsc_get_sset_count,783 .get_strings = smsc_get_strings,784 .get_stats = smsc_get_stats,785 786 .get_tunable = smsc_phy_get_tunable,787 .set_tunable = smsc_phy_set_tunable,788 789 /* WoL */790 .set_wol = lan874x_set_wol,791 .get_wol = lan874x_get_wol,792 793 .suspend = genphy_suspend,794 .resume = genphy_resume,795}, {796 .phy_id = 0x0007c130, /* 0x0007c130 and 0x0007c131 */797 /* This mask (0xfffffff2) is to differentiate from798 * LAN88xx (phy_id 0x0007c132)799 * and allows future phy_id revisions.800 */801 .phy_id_mask = 0xfffffff2,802 .name = "Microchip LAN8742",803 804 /* PHY_BASIC_FEATURES */805 .flags = PHY_RST_AFTER_CLK_EN,806 807 .probe = smsc_phy_probe,808 809 /* basic functions */810 .read_status = lan87xx_read_status,811 .config_init = lan874x_phy_config_init,812 .soft_reset = smsc_phy_reset,813 814 /* IRQ related */815 .config_intr = smsc_phy_config_intr,816 .handle_interrupt = smsc_phy_handle_interrupt,817 818 /* Statistics */819 .get_sset_count = smsc_get_sset_count,820 .get_strings = smsc_get_strings,821 .get_stats = smsc_get_stats,822 823 .get_tunable = smsc_phy_get_tunable,824 .set_tunable = smsc_phy_set_tunable,825 826 /* WoL */827 .set_wol = lan874x_set_wol,828 .get_wol = lan874x_get_wol,829 830 .suspend = genphy_suspend,831 .resume = genphy_resume,832} };833 834module_phy_driver(smsc_phy_driver);835 836MODULE_DESCRIPTION("SMSC PHY driver");837MODULE_AUTHOR("Herbert Valerio Riedel");838MODULE_LICENSE("GPL");839 840static struct mdio_device_id __maybe_unused smsc_tbl[] = {841 { 0x0007c0a0, 0xfffffff0 },842 { 0x0007c0b0, 0xfffffff0 },843 { 0x0007c0c0, 0xfffffff0 },844 { 0x0007c0d0, 0xfffffff0 },845 { 0x0007c0f0, 0xfffffff0 },846 { 0x0007c110, 0xfffffff0 },847 { 0x0007c130, 0xfffffff2 },848 { }849};850 851MODULE_DEVICE_TABLE(mdio, smsc_tbl);852