18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * drivers/net/phy/smsc.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Driver for SMSC PHYs 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Author: Herbert Valerio Riedel 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright (c) 2006 Herbert Valerio Riedel <hvr@gnu.org> 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Support added for SMSC LAN8187 and LAN8700 by steve.glendinning@shawell.net 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/clk.h> 168c2ecf20Sopenharmony_ci#include <linux/kernel.h> 178c2ecf20Sopenharmony_ci#include <linux/module.h> 188c2ecf20Sopenharmony_ci#include <linux/mii.h> 198c2ecf20Sopenharmony_ci#include <linux/ethtool.h> 208c2ecf20Sopenharmony_ci#include <linux/of.h> 218c2ecf20Sopenharmony_ci#include <linux/phy.h> 228c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/smscphy.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* Vendor-specific PHY Definitions */ 268c2ecf20Sopenharmony_ci/* EDPD NLP / crossover time configuration */ 278c2ecf20Sopenharmony_ci#define PHY_EDPD_CONFIG 16 288c2ecf20Sopenharmony_ci#define PHY_EDPD_CONFIG_EXT_CROSSOVER_ 0x0001 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* Control/Status Indication Register */ 318c2ecf20Sopenharmony_ci#define SPECIAL_CTRL_STS 27 328c2ecf20Sopenharmony_ci#define SPECIAL_CTRL_STS_OVRRD_AMDIX_ 0x8000 338c2ecf20Sopenharmony_ci#define SPECIAL_CTRL_STS_AMDIX_ENABLE_ 0x4000 348c2ecf20Sopenharmony_ci#define SPECIAL_CTRL_STS_AMDIX_STATE_ 0x2000 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct smsc_hw_stat { 378c2ecf20Sopenharmony_ci const char *string; 388c2ecf20Sopenharmony_ci u8 reg; 398c2ecf20Sopenharmony_ci u8 bits; 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic struct smsc_hw_stat smsc_hw_stats[] = { 438c2ecf20Sopenharmony_ci { "phy_symbol_errors", 26, 16}, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistruct smsc_phy_priv { 478c2ecf20Sopenharmony_ci bool energy_enable; 488c2ecf20Sopenharmony_ci struct clk *refclk; 498c2ecf20Sopenharmony_ci}; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic int smsc_phy_config_intr(struct phy_device *phydev) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci struct smsc_phy_priv *priv = phydev->priv; 548c2ecf20Sopenharmony_ci u16 intmask = 0; 558c2ecf20Sopenharmony_ci int rc; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 588c2ecf20Sopenharmony_ci intmask = MII_LAN83C185_ISF_INT4 | MII_LAN83C185_ISF_INT6; 598c2ecf20Sopenharmony_ci if (priv->energy_enable) 608c2ecf20Sopenharmony_ci intmask |= MII_LAN83C185_ISF_INT7; 618c2ecf20Sopenharmony_ci } 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci rc = phy_write(phydev, MII_LAN83C185_IM, intmask); 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci return rc < 0 ? rc : 0; 668c2ecf20Sopenharmony_ci} 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic int smsc_phy_ack_interrupt(struct phy_device *phydev) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci int rc = phy_read (phydev, MII_LAN83C185_ISF); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci return rc < 0 ? rc : 0; 738c2ecf20Sopenharmony_ci} 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic int smsc_phy_config_init(struct phy_device *phydev) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci struct smsc_phy_priv *priv = phydev->priv; 788c2ecf20Sopenharmony_ci int rc; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci if (!priv->energy_enable) 818c2ecf20Sopenharmony_ci return 0; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci if (rc < 0) 868c2ecf20Sopenharmony_ci return rc; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* Enable energy detect mode for this SMSC Transceivers */ 898c2ecf20Sopenharmony_ci rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, 908c2ecf20Sopenharmony_ci rc | MII_LAN83C185_EDPWRDOWN); 918c2ecf20Sopenharmony_ci if (rc < 0) 928c2ecf20Sopenharmony_ci return rc; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return smsc_phy_ack_interrupt(phydev); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int smsc_phy_reset(struct phy_device *phydev) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES); 1008c2ecf20Sopenharmony_ci if (rc < 0) 1018c2ecf20Sopenharmony_ci return rc; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci /* If the SMSC PHY is in power down mode, then set it 1048c2ecf20Sopenharmony_ci * in all capable mode before using it. 1058c2ecf20Sopenharmony_ci */ 1068c2ecf20Sopenharmony_ci if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) { 1078c2ecf20Sopenharmony_ci /* set "all capable" mode */ 1088c2ecf20Sopenharmony_ci rc |= MII_LAN83C185_MODE_ALL; 1098c2ecf20Sopenharmony_ci phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc); 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci /* reset the phy */ 1138c2ecf20Sopenharmony_ci return genphy_soft_reset(phydev); 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cistatic int lan911x_config_init(struct phy_device *phydev) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci return smsc_phy_ack_interrupt(phydev); 1198c2ecf20Sopenharmony_ci} 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic int lan87xx_config_aneg(struct phy_device *phydev) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci int rc; 1248c2ecf20Sopenharmony_ci int val; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci switch (phydev->mdix_ctrl) { 1278c2ecf20Sopenharmony_ci case ETH_TP_MDI: 1288c2ecf20Sopenharmony_ci val = SPECIAL_CTRL_STS_OVRRD_AMDIX_; 1298c2ecf20Sopenharmony_ci break; 1308c2ecf20Sopenharmony_ci case ETH_TP_MDI_X: 1318c2ecf20Sopenharmony_ci val = SPECIAL_CTRL_STS_OVRRD_AMDIX_ | 1328c2ecf20Sopenharmony_ci SPECIAL_CTRL_STS_AMDIX_STATE_; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case ETH_TP_MDI_AUTO: 1358c2ecf20Sopenharmony_ci val = SPECIAL_CTRL_STS_AMDIX_ENABLE_; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci default: 1388c2ecf20Sopenharmony_ci return genphy_config_aneg(phydev); 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci rc = phy_read(phydev, SPECIAL_CTRL_STS); 1428c2ecf20Sopenharmony_ci if (rc < 0) 1438c2ecf20Sopenharmony_ci return rc; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci rc &= ~(SPECIAL_CTRL_STS_OVRRD_AMDIX_ | 1468c2ecf20Sopenharmony_ci SPECIAL_CTRL_STS_AMDIX_ENABLE_ | 1478c2ecf20Sopenharmony_ci SPECIAL_CTRL_STS_AMDIX_STATE_); 1488c2ecf20Sopenharmony_ci rc |= val; 1498c2ecf20Sopenharmony_ci phy_write(phydev, SPECIAL_CTRL_STS, rc); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci phydev->mdix = phydev->mdix_ctrl; 1528c2ecf20Sopenharmony_ci return genphy_config_aneg(phydev); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int lan95xx_config_aneg_ext(struct phy_device *phydev) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int rc; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci if (phydev->phy_id != 0x0007c0f0) /* not (LAN9500A or LAN9505A) */ 1608c2ecf20Sopenharmony_ci return lan87xx_config_aneg(phydev); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* Extend Manual AutoMDIX timer */ 1638c2ecf20Sopenharmony_ci rc = phy_read(phydev, PHY_EDPD_CONFIG); 1648c2ecf20Sopenharmony_ci if (rc < 0) 1658c2ecf20Sopenharmony_ci return rc; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci rc |= PHY_EDPD_CONFIG_EXT_CROSSOVER_; 1688c2ecf20Sopenharmony_ci phy_write(phydev, PHY_EDPD_CONFIG, rc); 1698c2ecf20Sopenharmony_ci return lan87xx_config_aneg(phydev); 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci/* 1738c2ecf20Sopenharmony_ci * The LAN87xx suffers from rare absence of the ENERGYON-bit when Ethernet cable 1748c2ecf20Sopenharmony_ci * plugs in while LAN87xx is in Energy Detect Power-Down mode. This leads to 1758c2ecf20Sopenharmony_ci * unstable detection of plugging in Ethernet cable. 1768c2ecf20Sopenharmony_ci * This workaround disables Energy Detect Power-Down mode and waiting for 1778c2ecf20Sopenharmony_ci * response on link pulses to detect presence of plugged Ethernet cable. 1788c2ecf20Sopenharmony_ci * The Energy Detect Power-Down mode is enabled again in the end of procedure to 1798c2ecf20Sopenharmony_ci * save approximately 220 mW of power if cable is unplugged. 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_cistatic int lan87xx_read_status(struct phy_device *phydev) 1828c2ecf20Sopenharmony_ci{ 1838c2ecf20Sopenharmony_ci struct smsc_phy_priv *priv = phydev->priv; 1848c2ecf20Sopenharmony_ci int err; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci err = genphy_read_status(phydev); 1878c2ecf20Sopenharmony_ci if (err) 1888c2ecf20Sopenharmony_ci return err; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci if (!phydev->link && priv->energy_enable) { 1918c2ecf20Sopenharmony_ci /* Disable EDPD to wake up PHY */ 1928c2ecf20Sopenharmony_ci int rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); 1938c2ecf20Sopenharmony_ci if (rc < 0) 1948c2ecf20Sopenharmony_ci return rc; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, 1978c2ecf20Sopenharmony_ci rc & ~MII_LAN83C185_EDPWRDOWN); 1988c2ecf20Sopenharmony_ci if (rc < 0) 1998c2ecf20Sopenharmony_ci return rc; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* Wait max 640 ms to detect energy and the timeout is not 2028c2ecf20Sopenharmony_ci * an actual error. 2038c2ecf20Sopenharmony_ci */ 2048c2ecf20Sopenharmony_ci read_poll_timeout(phy_read, rc, 2058c2ecf20Sopenharmony_ci rc & MII_LAN83C185_ENERGYON || rc < 0, 2068c2ecf20Sopenharmony_ci 10000, 640000, true, phydev, 2078c2ecf20Sopenharmony_ci MII_LAN83C185_CTRL_STATUS); 2088c2ecf20Sopenharmony_ci if (rc < 0) 2098c2ecf20Sopenharmony_ci return rc; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* Re-enable EDPD */ 2128c2ecf20Sopenharmony_ci rc = phy_read(phydev, MII_LAN83C185_CTRL_STATUS); 2138c2ecf20Sopenharmony_ci if (rc < 0) 2148c2ecf20Sopenharmony_ci return rc; 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci rc = phy_write(phydev, MII_LAN83C185_CTRL_STATUS, 2178c2ecf20Sopenharmony_ci rc | MII_LAN83C185_EDPWRDOWN); 2188c2ecf20Sopenharmony_ci if (rc < 0) 2198c2ecf20Sopenharmony_ci return rc; 2208c2ecf20Sopenharmony_ci } 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci return err; 2238c2ecf20Sopenharmony_ci} 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_cistatic int smsc_get_sset_count(struct phy_device *phydev) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci return ARRAY_SIZE(smsc_hw_stats); 2288c2ecf20Sopenharmony_ci} 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_cistatic void smsc_get_strings(struct phy_device *phydev, u8 *data) 2318c2ecf20Sopenharmony_ci{ 2328c2ecf20Sopenharmony_ci int i; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) { 2358c2ecf20Sopenharmony_ci strncpy(data + i * ETH_GSTRING_LEN, 2368c2ecf20Sopenharmony_ci smsc_hw_stats[i].string, ETH_GSTRING_LEN); 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic u64 smsc_get_stat(struct phy_device *phydev, int i) 2418c2ecf20Sopenharmony_ci{ 2428c2ecf20Sopenharmony_ci struct smsc_hw_stat stat = smsc_hw_stats[i]; 2438c2ecf20Sopenharmony_ci int val; 2448c2ecf20Sopenharmony_ci u64 ret; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci val = phy_read(phydev, stat.reg); 2478c2ecf20Sopenharmony_ci if (val < 0) 2488c2ecf20Sopenharmony_ci ret = U64_MAX; 2498c2ecf20Sopenharmony_ci else 2508c2ecf20Sopenharmony_ci ret = val; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci return ret; 2538c2ecf20Sopenharmony_ci} 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_cistatic void smsc_get_stats(struct phy_device *phydev, 2568c2ecf20Sopenharmony_ci struct ethtool_stats *stats, u64 *data) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci int i; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(smsc_hw_stats); i++) 2618c2ecf20Sopenharmony_ci data[i] = smsc_get_stat(phydev, i); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void smsc_phy_remove(struct phy_device *phydev) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct smsc_phy_priv *priv = phydev->priv; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->refclk); 2698c2ecf20Sopenharmony_ci clk_put(priv->refclk); 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_cistatic int smsc_phy_probe(struct phy_device *phydev) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci struct device *dev = &phydev->mdio.dev; 2758c2ecf20Sopenharmony_ci struct device_node *of_node = dev->of_node; 2768c2ecf20Sopenharmony_ci struct smsc_phy_priv *priv; 2778c2ecf20Sopenharmony_ci int ret; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 2808c2ecf20Sopenharmony_ci if (!priv) 2818c2ecf20Sopenharmony_ci return -ENOMEM; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci priv->energy_enable = true; 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci if (of_property_read_bool(of_node, "smsc,disable-energy-detect")) 2868c2ecf20Sopenharmony_ci priv->energy_enable = false; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci phydev->priv = priv; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* Make clk optional to keep DTB backward compatibility. */ 2918c2ecf20Sopenharmony_ci priv->refclk = clk_get_optional(dev, NULL); 2928c2ecf20Sopenharmony_ci if (IS_ERR(priv->refclk)) 2938c2ecf20Sopenharmony_ci return dev_err_probe(dev, PTR_ERR(priv->refclk), 2948c2ecf20Sopenharmony_ci "Failed to request clock\n"); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci ret = clk_prepare_enable(priv->refclk); 2978c2ecf20Sopenharmony_ci if (ret) 2988c2ecf20Sopenharmony_ci return ret; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci ret = clk_set_rate(priv->refclk, 50 * 1000 * 1000); 3018c2ecf20Sopenharmony_ci if (ret) { 3028c2ecf20Sopenharmony_ci clk_disable_unprepare(priv->refclk); 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci return 0; 3078c2ecf20Sopenharmony_ci} 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_cistatic struct phy_driver smsc_phy_driver[] = { 3108c2ecf20Sopenharmony_ci{ 3118c2ecf20Sopenharmony_ci .phy_id = 0x0007c0a0, /* OUI=0x00800f, Model#=0x0a */ 3128c2ecf20Sopenharmony_ci .phy_id_mask = 0xfffffff0, 3138c2ecf20Sopenharmony_ci .name = "SMSC LAN83C185", 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci /* PHY_BASIC_FEATURES */ 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci .probe = smsc_phy_probe, 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* basic functions */ 3208c2ecf20Sopenharmony_ci .config_init = smsc_phy_config_init, 3218c2ecf20Sopenharmony_ci .soft_reset = smsc_phy_reset, 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci /* IRQ related */ 3248c2ecf20Sopenharmony_ci .ack_interrupt = smsc_phy_ack_interrupt, 3258c2ecf20Sopenharmony_ci .config_intr = smsc_phy_config_intr, 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci .suspend = genphy_suspend, 3288c2ecf20Sopenharmony_ci .resume = genphy_resume, 3298c2ecf20Sopenharmony_ci}, { 3308c2ecf20Sopenharmony_ci .phy_id = 0x0007c0b0, /* OUI=0x00800f, Model#=0x0b */ 3318c2ecf20Sopenharmony_ci .phy_id_mask = 0xfffffff0, 3328c2ecf20Sopenharmony_ci .name = "SMSC LAN8187", 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci /* PHY_BASIC_FEATURES */ 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci .probe = smsc_phy_probe, 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci /* basic functions */ 3398c2ecf20Sopenharmony_ci .config_init = smsc_phy_config_init, 3408c2ecf20Sopenharmony_ci .soft_reset = smsc_phy_reset, 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci /* IRQ related */ 3438c2ecf20Sopenharmony_ci .ack_interrupt = smsc_phy_ack_interrupt, 3448c2ecf20Sopenharmony_ci .config_intr = smsc_phy_config_intr, 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci /* Statistics */ 3478c2ecf20Sopenharmony_ci .get_sset_count = smsc_get_sset_count, 3488c2ecf20Sopenharmony_ci .get_strings = smsc_get_strings, 3498c2ecf20Sopenharmony_ci .get_stats = smsc_get_stats, 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci .suspend = genphy_suspend, 3528c2ecf20Sopenharmony_ci .resume = genphy_resume, 3538c2ecf20Sopenharmony_ci}, { 3548c2ecf20Sopenharmony_ci /* This covers internal PHY (phy_id: 0x0007C0C3) for 3558c2ecf20Sopenharmony_ci * LAN9500 (PID: 0x9500), LAN9514 (PID: 0xec00), LAN9505 (PID: 0x9505) 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci .phy_id = 0x0007c0c0, /* OUI=0x00800f, Model#=0x0c */ 3588c2ecf20Sopenharmony_ci .phy_id_mask = 0xfffffff0, 3598c2ecf20Sopenharmony_ci .name = "SMSC LAN8700", 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci /* PHY_BASIC_FEATURES */ 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci .probe = smsc_phy_probe, 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci /* basic functions */ 3668c2ecf20Sopenharmony_ci .read_status = lan87xx_read_status, 3678c2ecf20Sopenharmony_ci .config_init = smsc_phy_config_init, 3688c2ecf20Sopenharmony_ci .soft_reset = smsc_phy_reset, 3698c2ecf20Sopenharmony_ci .config_aneg = lan87xx_config_aneg, 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci /* IRQ related */ 3728c2ecf20Sopenharmony_ci .ack_interrupt = smsc_phy_ack_interrupt, 3738c2ecf20Sopenharmony_ci .config_intr = smsc_phy_config_intr, 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_ci /* Statistics */ 3768c2ecf20Sopenharmony_ci .get_sset_count = smsc_get_sset_count, 3778c2ecf20Sopenharmony_ci .get_strings = smsc_get_strings, 3788c2ecf20Sopenharmony_ci .get_stats = smsc_get_stats, 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci .suspend = genphy_suspend, 3818c2ecf20Sopenharmony_ci .resume = genphy_resume, 3828c2ecf20Sopenharmony_ci}, { 3838c2ecf20Sopenharmony_ci .phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */ 3848c2ecf20Sopenharmony_ci .phy_id_mask = 0xfffffff0, 3858c2ecf20Sopenharmony_ci .name = "SMSC LAN911x Internal PHY", 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* PHY_BASIC_FEATURES */ 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci .probe = smsc_phy_probe, 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci /* basic functions */ 3928c2ecf20Sopenharmony_ci .config_init = lan911x_config_init, 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci /* IRQ related */ 3958c2ecf20Sopenharmony_ci .ack_interrupt = smsc_phy_ack_interrupt, 3968c2ecf20Sopenharmony_ci .config_intr = smsc_phy_config_intr, 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci .suspend = genphy_suspend, 3998c2ecf20Sopenharmony_ci .resume = genphy_resume, 4008c2ecf20Sopenharmony_ci}, { 4018c2ecf20Sopenharmony_ci /* This covers internal PHY (phy_id: 0x0007C0F0) for 4028c2ecf20Sopenharmony_ci * LAN9500A (PID: 0x9E00), LAN9505A (PID: 0x9E01) 4038c2ecf20Sopenharmony_ci */ 4048c2ecf20Sopenharmony_ci .phy_id = 0x0007c0f0, /* OUI=0x00800f, Model#=0x0f */ 4058c2ecf20Sopenharmony_ci .phy_id_mask = 0xfffffff0, 4068c2ecf20Sopenharmony_ci .name = "SMSC LAN8710/LAN8720", 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci /* PHY_BASIC_FEATURES */ 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci .probe = smsc_phy_probe, 4118c2ecf20Sopenharmony_ci .remove = smsc_phy_remove, 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ci /* basic functions */ 4148c2ecf20Sopenharmony_ci .read_status = lan87xx_read_status, 4158c2ecf20Sopenharmony_ci .config_init = smsc_phy_config_init, 4168c2ecf20Sopenharmony_ci .soft_reset = smsc_phy_reset, 4178c2ecf20Sopenharmony_ci .config_aneg = lan95xx_config_aneg_ext, 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci /* IRQ related */ 4208c2ecf20Sopenharmony_ci .ack_interrupt = smsc_phy_ack_interrupt, 4218c2ecf20Sopenharmony_ci .config_intr = smsc_phy_config_intr, 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci /* Statistics */ 4248c2ecf20Sopenharmony_ci .get_sset_count = smsc_get_sset_count, 4258c2ecf20Sopenharmony_ci .get_strings = smsc_get_strings, 4268c2ecf20Sopenharmony_ci .get_stats = smsc_get_stats, 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci .suspend = genphy_suspend, 4298c2ecf20Sopenharmony_ci .resume = genphy_resume, 4308c2ecf20Sopenharmony_ci}, { 4318c2ecf20Sopenharmony_ci .phy_id = 0x0007c110, 4328c2ecf20Sopenharmony_ci .phy_id_mask = 0xfffffff0, 4338c2ecf20Sopenharmony_ci .name = "SMSC LAN8740", 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci /* PHY_BASIC_FEATURES */ 4368c2ecf20Sopenharmony_ci .flags = PHY_RST_AFTER_CLK_EN, 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci .probe = smsc_phy_probe, 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci /* basic functions */ 4418c2ecf20Sopenharmony_ci .read_status = lan87xx_read_status, 4428c2ecf20Sopenharmony_ci .config_init = smsc_phy_config_init, 4438c2ecf20Sopenharmony_ci .soft_reset = smsc_phy_reset, 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* IRQ related */ 4468c2ecf20Sopenharmony_ci .ack_interrupt = smsc_phy_ack_interrupt, 4478c2ecf20Sopenharmony_ci .config_intr = smsc_phy_config_intr, 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* Statistics */ 4508c2ecf20Sopenharmony_ci .get_sset_count = smsc_get_sset_count, 4518c2ecf20Sopenharmony_ci .get_strings = smsc_get_strings, 4528c2ecf20Sopenharmony_ci .get_stats = smsc_get_stats, 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci .suspend = genphy_suspend, 4558c2ecf20Sopenharmony_ci .resume = genphy_resume, 4568c2ecf20Sopenharmony_ci} }; 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cimodule_phy_driver(smsc_phy_driver); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("SMSC PHY driver"); 4618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Herbert Valerio Riedel"); 4628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic struct mdio_device_id __maybe_unused smsc_tbl[] = { 4658c2ecf20Sopenharmony_ci { 0x0007c0a0, 0xfffffff0 }, 4668c2ecf20Sopenharmony_ci { 0x0007c0b0, 0xfffffff0 }, 4678c2ecf20Sopenharmony_ci { 0x0007c0c0, 0xfffffff0 }, 4688c2ecf20Sopenharmony_ci { 0x0007c0d0, 0xfffffff0 }, 4698c2ecf20Sopenharmony_ci { 0x0007c0f0, 0xfffffff0 }, 4708c2ecf20Sopenharmony_ci { 0x0007c110, 0xfffffff0 }, 4718c2ecf20Sopenharmony_ci { } 4728c2ecf20Sopenharmony_ci}; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(mdio, smsc_tbl); 475