1 /* 2 * Driver for the Texas Instruments DP83822 PHY 3 * 4 * Copyright (C) 2017 Texas Instruments Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 */ 15 16 #include <linux/ethtool.h> 17 #include <linux/etherdevice.h> 18 #include <linux/kernel.h> 19 #include <linux/mii.h> 20 #include <linux/module.h> 21 #include <linux/of.h> 22 #include <linux/phy.h> 23 #include <linux/netdevice.h> 24 25 #define DP83822_PHY_ID 0x2000a240 26 #define DP83822_DEVADDR 0x1f 27 28 #define MII_DP83822_PHYSCR 0x11 29 #define MII_DP83822_MISR1 0x12 30 #define MII_DP83822_MISR2 0x13 31 #define MII_DP83822_RESET_CTRL 0x1f 32 33 #define DP83822_HW_RESET BIT(15) 34 #define DP83822_SW_RESET BIT(14) 35 36 /* PHYSCR Register Fields */ 37 #define DP83822_PHYSCR_INT_OE BIT(0) /* Interrupt Output Enable */ 38 #define DP83822_PHYSCR_INTEN BIT(1) /* Interrupt Enable */ 39 40 /* MISR1 bits */ 41 #define DP83822_RX_ERR_HF_INT_EN BIT(0) 42 #define DP83822_FALSE_CARRIER_HF_INT_EN BIT(1) 43 #define DP83822_ANEG_COMPLETE_INT_EN BIT(2) 44 #define DP83822_DUP_MODE_CHANGE_INT_EN BIT(3) 45 #define DP83822_SPEED_CHANGED_INT_EN BIT(4) 46 #define DP83822_LINK_STAT_INT_EN BIT(5) 47 #define DP83822_ENERGY_DET_INT_EN BIT(6) 48 #define DP83822_LINK_QUAL_INT_EN BIT(7) 49 50 /* MISR2 bits */ 51 #define DP83822_JABBER_DET_INT_EN BIT(0) 52 #define DP83822_WOL_PKT_INT_EN BIT(1) 53 #define DP83822_SLEEP_MODE_INT_EN BIT(2) 54 #define DP83822_MDI_XOVER_INT_EN BIT(3) 55 #define DP83822_LB_FIFO_INT_EN BIT(4) 56 #define DP83822_PAGE_RX_INT_EN BIT(5) 57 #define DP83822_ANEG_ERR_INT_EN BIT(6) 58 #define DP83822_EEE_ERROR_CHANGE_INT_EN BIT(7) 59 60 /* INT_STAT1 bits */ 61 #define DP83822_WOL_INT_EN BIT(4) 62 #define DP83822_WOL_INT_STAT BIT(12) 63 64 #define MII_DP83822_RXSOP1 0x04a5 65 #define MII_DP83822_RXSOP2 0x04a6 66 #define MII_DP83822_RXSOP3 0x04a7 67 68 /* WoL Registers */ 69 #define MII_DP83822_WOL_CFG 0x04a0 70 #define MII_DP83822_WOL_STAT 0x04a1 71 #define MII_DP83822_WOL_DA1 0x04a2 72 #define MII_DP83822_WOL_DA2 0x04a3 73 #define MII_DP83822_WOL_DA3 0x04a4 74 75 /* WoL bits */ 76 #define DP83822_WOL_MAGIC_EN BIT(0) 77 #define DP83822_WOL_SECURE_ON BIT(5) 78 #define DP83822_WOL_EN BIT(7) 79 #define DP83822_WOL_INDICATION_SEL BIT(8) 80 #define DP83822_WOL_CLR_INDICATION BIT(11) 81 82 static int dp83822_ack_interrupt(struct phy_device *phydev) 83 { 84 int err; 85 86 err = phy_read(phydev, MII_DP83822_MISR1); 87 if (err < 0) 88 return err; 89 90 err = phy_read(phydev, MII_DP83822_MISR2); 91 if (err < 0) 92 return err; 93 94 return 0; 95 } 96 97 static int dp83822_set_wol(struct phy_device *phydev, 98 struct ethtool_wolinfo *wol) 99 { 100 struct net_device *ndev = phydev->attached_dev; 101 u16 value; 102 const u8 *mac; 103 104 if (wol->wolopts & (WAKE_MAGIC | WAKE_MAGICSECURE)) { 105 mac = (const u8 *)ndev->dev_addr; 106 107 if (!is_valid_ether_addr(mac)) 108 return -EINVAL; 109 110 /* MAC addresses start with byte 5, but stored in mac[0]. 111 * 822 PHYs store bytes 4|5, 2|3, 0|1 112 */ 113 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA1, 114 (mac[1] << 8) | mac[0]); 115 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA2, 116 (mac[3] << 8) | mac[2]); 117 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_DA3, 118 (mac[5] << 8) | mac[4]); 119 120 value = phy_read_mmd(phydev, DP83822_DEVADDR, 121 MII_DP83822_WOL_CFG); 122 if (wol->wolopts & WAKE_MAGIC) 123 value |= DP83822_WOL_MAGIC_EN; 124 else 125 value &= ~DP83822_WOL_MAGIC_EN; 126 127 if (wol->wolopts & WAKE_MAGICSECURE) { 128 phy_write_mmd(phydev, DP83822_DEVADDR, 129 MII_DP83822_RXSOP1, 130 (wol->sopass[1] << 8) | wol->sopass[0]); 131 phy_write_mmd(phydev, DP83822_DEVADDR, 132 MII_DP83822_RXSOP2, 133 (wol->sopass[3] << 8) | wol->sopass[2]); 134 phy_write_mmd(phydev, DP83822_DEVADDR, 135 MII_DP83822_RXSOP3, 136 (wol->sopass[5] << 8) | wol->sopass[4]); 137 value |= DP83822_WOL_SECURE_ON; 138 } else { 139 value &= ~DP83822_WOL_SECURE_ON; 140 } 141 142 value |= (DP83822_WOL_EN | DP83822_WOL_INDICATION_SEL | 143 DP83822_WOL_CLR_INDICATION); 144 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, 145 value); 146 } else { 147 value = phy_read_mmd(phydev, DP83822_DEVADDR, 148 MII_DP83822_WOL_CFG); 149 value &= ~DP83822_WOL_EN; 150 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, 151 value); 152 } 153 154 return 0; 155 } 156 157 static void dp83822_get_wol(struct phy_device *phydev, 158 struct ethtool_wolinfo *wol) 159 { 160 int value; 161 u16 sopass_val; 162 163 wol->supported = (WAKE_MAGIC | WAKE_MAGICSECURE); 164 wol->wolopts = 0; 165 166 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); 167 168 if (value & DP83822_WOL_MAGIC_EN) 169 wol->wolopts |= WAKE_MAGIC; 170 171 if (value & DP83822_WOL_SECURE_ON) { 172 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, 173 MII_DP83822_RXSOP1); 174 wol->sopass[0] = (sopass_val & 0xff); 175 wol->sopass[1] = (sopass_val >> 8); 176 177 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, 178 MII_DP83822_RXSOP2); 179 wol->sopass[2] = (sopass_val & 0xff); 180 wol->sopass[3] = (sopass_val >> 8); 181 182 sopass_val = phy_read_mmd(phydev, DP83822_DEVADDR, 183 MII_DP83822_RXSOP3); 184 wol->sopass[4] = (sopass_val & 0xff); 185 wol->sopass[5] = (sopass_val >> 8); 186 187 wol->wolopts |= WAKE_MAGICSECURE; 188 } 189 190 /* WoL is not enabled so set wolopts to 0 */ 191 if (!(value & DP83822_WOL_EN)) 192 wol->wolopts = 0; 193 } 194 195 static int dp83822_config_intr(struct phy_device *phydev) 196 { 197 int misr_status; 198 int physcr_status; 199 int err; 200 201 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 202 misr_status = phy_read(phydev, MII_DP83822_MISR1); 203 if (misr_status < 0) 204 return misr_status; 205 206 misr_status |= (DP83822_RX_ERR_HF_INT_EN | 207 DP83822_FALSE_CARRIER_HF_INT_EN | 208 DP83822_ANEG_COMPLETE_INT_EN | 209 DP83822_DUP_MODE_CHANGE_INT_EN | 210 DP83822_SPEED_CHANGED_INT_EN | 211 DP83822_LINK_STAT_INT_EN | 212 DP83822_ENERGY_DET_INT_EN | 213 DP83822_LINK_QUAL_INT_EN); 214 215 err = phy_write(phydev, MII_DP83822_MISR1, misr_status); 216 if (err < 0) 217 return err; 218 219 misr_status = phy_read(phydev, MII_DP83822_MISR2); 220 if (misr_status < 0) 221 return misr_status; 222 223 misr_status |= (DP83822_JABBER_DET_INT_EN | 224 DP83822_WOL_PKT_INT_EN | 225 DP83822_SLEEP_MODE_INT_EN | 226 DP83822_MDI_XOVER_INT_EN | 227 DP83822_LB_FIFO_INT_EN | 228 DP83822_PAGE_RX_INT_EN | 229 DP83822_ANEG_ERR_INT_EN | 230 DP83822_EEE_ERROR_CHANGE_INT_EN); 231 232 err = phy_write(phydev, MII_DP83822_MISR2, misr_status); 233 if (err < 0) 234 return err; 235 236 physcr_status = phy_read(phydev, MII_DP83822_PHYSCR); 237 if (physcr_status < 0) 238 return physcr_status; 239 240 physcr_status |= DP83822_PHYSCR_INT_OE | DP83822_PHYSCR_INTEN; 241 242 } else { 243 err = phy_write(phydev, MII_DP83822_MISR1, 0); 244 if (err < 0) 245 return err; 246 247 err = phy_write(phydev, MII_DP83822_MISR1, 0); 248 if (err < 0) 249 return err; 250 251 physcr_status = phy_read(phydev, MII_DP83822_PHYSCR); 252 if (physcr_status < 0) 253 return physcr_status; 254 255 physcr_status &= ~DP83822_PHYSCR_INTEN; 256 } 257 258 return phy_write(phydev, MII_DP83822_PHYSCR, physcr_status); 259 } 260 261 static int dp83822_config_init(struct phy_device *phydev) 262 { 263 int err; 264 int value; 265 266 err = genphy_config_init(phydev); 267 if (err < 0) 268 return err; 269 270 value = DP83822_WOL_MAGIC_EN | DP83822_WOL_SECURE_ON | DP83822_WOL_EN; 271 272 return phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, 273 value); 274 } 275 276 static int dp83822_phy_reset(struct phy_device *phydev) 277 { 278 int err; 279 280 err = phy_write(phydev, MII_DP83822_RESET_CTRL, DP83822_HW_RESET); 281 if (err < 0) 282 return err; 283 284 dp83822_config_init(phydev); 285 286 return 0; 287 } 288 289 static int dp83822_suspend(struct phy_device *phydev) 290 { 291 int value; 292 293 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); 294 295 if (!(value & DP83822_WOL_EN)) 296 genphy_suspend(phydev); 297 298 return 0; 299 } 300 301 static int dp83822_resume(struct phy_device *phydev) 302 { 303 int value; 304 305 genphy_resume(phydev); 306 307 value = phy_read_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG); 308 309 phy_write_mmd(phydev, DP83822_DEVADDR, MII_DP83822_WOL_CFG, value | 310 DP83822_WOL_CLR_INDICATION); 311 312 return 0; 313 } 314 315 static struct phy_driver dp83822_driver[] = { 316 { 317 .phy_id = DP83822_PHY_ID, 318 .phy_id_mask = 0xfffffff0, 319 .name = "TI DP83822", 320 .features = PHY_BASIC_FEATURES, 321 .flags = PHY_HAS_INTERRUPT, 322 .config_init = dp83822_config_init, 323 .soft_reset = dp83822_phy_reset, 324 .get_wol = dp83822_get_wol, 325 .set_wol = dp83822_set_wol, 326 .ack_interrupt = dp83822_ack_interrupt, 327 .config_intr = dp83822_config_intr, 328 .suspend = dp83822_suspend, 329 .resume = dp83822_resume, 330 }, 331 }; 332 module_phy_driver(dp83822_driver); 333 334 static struct mdio_device_id __maybe_unused dp83822_tbl[] = { 335 { DP83822_PHY_ID, 0xfffffff0 }, 336 { }, 337 }; 338 MODULE_DEVICE_TABLE(mdio, dp83822_tbl); 339 340 MODULE_DESCRIPTION("Texas Instruments DP83822 PHY driver"); 341 MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com"); 342 MODULE_LICENSE("GPL"); 343