1 /* 2 * Copyright (C) 2015 Microchip Technology 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 2 7 * of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, see <http://www.gnu.org/licenses/>. 16 */ 17 #include <linux/kernel.h> 18 #include <linux/module.h> 19 #include <linux/mii.h> 20 #include <linux/ethtool.h> 21 #include <linux/phy.h> 22 #include <linux/microchipphy.h> 23 24 #define DRIVER_AUTHOR "WOOJUNG HUH <woojung.huh@microchip.com>" 25 #define DRIVER_DESC "Microchip LAN88XX PHY driver" 26 27 struct lan88xx_priv { 28 int chip_id; 29 int chip_rev; 30 __u32 wolopts; 31 }; 32 33 static int lan88xx_phy_config_intr(struct phy_device *phydev) 34 { 35 int rc; 36 37 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 38 /* unmask all source and clear them before enable */ 39 rc = phy_write(phydev, LAN88XX_INT_MASK, 0x7FFF); 40 rc = phy_read(phydev, LAN88XX_INT_STS); 41 rc = phy_write(phydev, LAN88XX_INT_MASK, 42 LAN88XX_INT_MASK_MDINTPIN_EN_ | 43 LAN88XX_INT_MASK_LINK_CHANGE_); 44 } else { 45 rc = phy_write(phydev, LAN88XX_INT_MASK, 0); 46 } 47 48 return rc < 0 ? rc : 0; 49 } 50 51 static int lan88xx_phy_ack_interrupt(struct phy_device *phydev) 52 { 53 int rc = phy_read(phydev, LAN88XX_INT_STS); 54 55 return rc < 0 ? rc : 0; 56 } 57 58 static int lan88xx_suspend(struct phy_device *phydev) 59 { 60 struct lan88xx_priv *priv = phydev->priv; 61 62 /* do not power down PHY when WOL is enabled */ 63 if (!priv->wolopts) 64 genphy_suspend(phydev); 65 66 return 0; 67 } 68 69 static int lan88xx_probe(struct phy_device *phydev) 70 { 71 struct device *dev = &phydev->mdio.dev; 72 struct lan88xx_priv *priv; 73 74 priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); 75 if (!priv) 76 return -ENOMEM; 77 78 priv->wolopts = 0; 79 80 /* these values can be used to identify internal PHY */ 81 priv->chip_id = phy_read_mmd_indirect(phydev, LAN88XX_MMD3_CHIP_ID, 3); 82 priv->chip_rev = phy_read_mmd_indirect(phydev, LAN88XX_MMD3_CHIP_REV, 83 3); 84 85 phydev->priv = priv; 86 87 return 0; 88 } 89 90 static void lan88xx_remove(struct phy_device *phydev) 91 { 92 struct device *dev = &phydev->mdio.dev; 93 struct lan88xx_priv *priv = phydev->priv; 94 95 if (priv) 96 devm_kfree(dev, priv); 97 } 98 99 static int lan88xx_set_wol(struct phy_device *phydev, 100 struct ethtool_wolinfo *wol) 101 { 102 struct lan88xx_priv *priv = phydev->priv; 103 104 priv->wolopts = wol->wolopts; 105 106 return 0; 107 } 108 109 static void lan88xx_set_mdix(struct phy_device *phydev) 110 { 111 int buf; 112 int val; 113 114 switch (phydev->mdix_ctrl) { 115 case ETH_TP_MDI: 116 val = LAN88XX_EXT_MODE_CTRL_MDI_; 117 break; 118 case ETH_TP_MDI_X: 119 val = LAN88XX_EXT_MODE_CTRL_MDI_X_; 120 break; 121 case ETH_TP_MDI_AUTO: 122 val = LAN88XX_EXT_MODE_CTRL_AUTO_MDIX_; 123 break; 124 default: 125 return; 126 } 127 128 phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_1); 129 buf = phy_read(phydev, LAN88XX_EXT_MODE_CTRL); 130 buf &= ~LAN88XX_EXT_MODE_CTRL_MDIX_MASK_; 131 buf |= val; 132 phy_write(phydev, LAN88XX_EXT_MODE_CTRL, buf); 133 phy_write(phydev, LAN88XX_EXT_PAGE_ACCESS, LAN88XX_EXT_PAGE_SPACE_0); 134 } 135 136 static int lan88xx_config_aneg(struct phy_device *phydev) 137 { 138 lan88xx_set_mdix(phydev); 139 140 return genphy_config_aneg(phydev); 141 } 142 143 static struct phy_driver microchip_phy_driver[] = { 144 { 145 .phy_id = 0x0007c130, 146 .phy_id_mask = 0xfffffff0, 147 .name = "Microchip LAN88xx", 148 149 .features = PHY_GBIT_FEATURES, 150 .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, 151 152 .probe = lan88xx_probe, 153 .remove = lan88xx_remove, 154 155 .config_init = genphy_config_init, 156 .config_aneg = lan88xx_config_aneg, 157 .read_status = genphy_read_status, 158 159 .ack_interrupt = lan88xx_phy_ack_interrupt, 160 .config_intr = lan88xx_phy_config_intr, 161 162 .suspend = lan88xx_suspend, 163 .resume = genphy_resume, 164 .set_wol = lan88xx_set_wol, 165 } }; 166 167 module_phy_driver(microchip_phy_driver); 168 169 static struct mdio_device_id __maybe_unused microchip_tbl[] = { 170 { 0x0007c130, 0xfffffff0 }, 171 { } 172 }; 173 174 MODULE_DEVICE_TABLE(mdio, microchip_tbl); 175 176 MODULE_AUTHOR(DRIVER_AUTHOR); 177 MODULE_DESCRIPTION(DRIVER_DESC); 178 MODULE_LICENSE("GPL"); 179