at v4.13-rc2 762 lines 20 kB view raw
1/* 2 * Driver for Microsemi VSC85xx PHYs 3 * 4 * Author: Nagaraju Lakkaraju 5 * License: Dual MIT/GPL 6 * Copyright (c) 2016 Microsemi Corporation 7 */ 8 9#include <linux/kernel.h> 10#include <linux/module.h> 11#include <linux/mdio.h> 12#include <linux/mii.h> 13#include <linux/phy.h> 14#include <linux/of.h> 15#include <linux/netdevice.h> 16#include <dt-bindings/net/mscc-phy-vsc8531.h> 17 18enum rgmii_rx_clock_delay { 19 RGMII_RX_CLK_DELAY_0_2_NS = 0, 20 RGMII_RX_CLK_DELAY_0_8_NS = 1, 21 RGMII_RX_CLK_DELAY_1_1_NS = 2, 22 RGMII_RX_CLK_DELAY_1_7_NS = 3, 23 RGMII_RX_CLK_DELAY_2_0_NS = 4, 24 RGMII_RX_CLK_DELAY_2_3_NS = 5, 25 RGMII_RX_CLK_DELAY_2_6_NS = 6, 26 RGMII_RX_CLK_DELAY_3_4_NS = 7 27}; 28 29/* Microsemi VSC85xx PHY registers */ 30/* IEEE 802. Std Registers */ 31#define MSCC_PHY_BYPASS_CONTROL 18 32#define DISABLE_HP_AUTO_MDIX_MASK 0x0080 33#define DISABLE_PAIR_SWAP_CORR_MASK 0x0020 34#define DISABLE_POLARITY_CORR_MASK 0x0010 35 36#define MSCC_PHY_EXT_PHY_CNTL_1 23 37#define MAC_IF_SELECTION_MASK 0x1800 38#define MAC_IF_SELECTION_GMII 0 39#define MAC_IF_SELECTION_RMII 1 40#define MAC_IF_SELECTION_RGMII 2 41#define MAC_IF_SELECTION_POS 11 42#define FAR_END_LOOPBACK_MODE_MASK 0x0008 43 44#define MII_VSC85XX_INT_MASK 25 45#define MII_VSC85XX_INT_MASK_MASK 0xa000 46#define MII_VSC85XX_INT_MASK_WOL 0x0040 47#define MII_VSC85XX_INT_STATUS 26 48 49#define MSCC_PHY_WOL_MAC_CONTROL 27 50#define EDGE_RATE_CNTL_POS 5 51#define EDGE_RATE_CNTL_MASK 0x00E0 52 53#define MSCC_PHY_DEV_AUX_CNTL 28 54#define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000 55 56#define MSCC_PHY_LED_MODE_SEL 29 57#define LED_1_MODE_SEL_MASK 0x00F0 58#define LED_0_MODE_SEL_MASK 0x000F 59#define LED_1_MODE_SEL_POS 4 60 61#define MSCC_EXT_PAGE_ACCESS 31 62#define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */ 63#define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */ 64#define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */ 65 66/* Extended Page 1 Registers */ 67#define MSCC_PHY_EXT_MODE_CNTL 19 68#define FORCE_MDI_CROSSOVER_MASK 0x000C 69#define FORCE_MDI_CROSSOVER_MDIX 0x000C 70#define FORCE_MDI_CROSSOVER_MDI 0x0008 71 72#define MSCC_PHY_ACTIPHY_CNTL 20 73#define DOWNSHIFT_CNTL_MASK 0x001C 74#define DOWNSHIFT_EN 0x0010 75#define DOWNSHIFT_CNTL_POS 2 76 77/* Extended Page 2 Registers */ 78#define MSCC_PHY_RGMII_CNTL 20 79#define RGMII_RX_CLK_DELAY_MASK 0x0070 80#define RGMII_RX_CLK_DELAY_POS 4 81 82#define MSCC_PHY_WOL_LOWER_MAC_ADDR 21 83#define MSCC_PHY_WOL_MID_MAC_ADDR 22 84#define MSCC_PHY_WOL_UPPER_MAC_ADDR 23 85#define MSCC_PHY_WOL_LOWER_PASSWD 24 86#define MSCC_PHY_WOL_MID_PASSWD 25 87#define MSCC_PHY_WOL_UPPER_PASSWD 26 88 89#define MSCC_PHY_WOL_MAC_CONTROL 27 90#define SECURE_ON_ENABLE 0x8000 91#define SECURE_ON_PASSWD_LEN_4 0x4000 92 93/* Microsemi PHY ID's */ 94#define PHY_ID_VSC8530 0x00070560 95#define PHY_ID_VSC8531 0x00070570 96#define PHY_ID_VSC8540 0x00070760 97#define PHY_ID_VSC8541 0x00070770 98 99#define MSCC_VDDMAC_1500 1500 100#define MSCC_VDDMAC_1800 1800 101#define MSCC_VDDMAC_2500 2500 102#define MSCC_VDDMAC_3300 3300 103 104#define DOWNSHIFT_COUNT_MAX 5 105 106struct vsc8531_private { 107 int rate_magic; 108 u8 led_0_mode; 109 u8 led_1_mode; 110}; 111 112#ifdef CONFIG_OF_MDIO 113struct vsc8531_edge_rate_table { 114 u16 vddmac; 115 u8 slowdown[8]; 116}; 117 118static const struct vsc8531_edge_rate_table edge_table[] = { 119 {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} }, 120 {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} }, 121 {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} }, 122 {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} }, 123}; 124#endif /* CONFIG_OF_MDIO */ 125 126static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page) 127{ 128 int rc; 129 130 rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page); 131 return rc; 132} 133 134static int vsc85xx_led_cntl_set(struct phy_device *phydev, 135 u8 led_num, 136 u8 mode) 137{ 138 int rc; 139 u16 reg_val; 140 141 mutex_lock(&phydev->lock); 142 reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL); 143 if (led_num) { 144 reg_val &= ~LED_1_MODE_SEL_MASK; 145 reg_val |= (((u16)mode << LED_1_MODE_SEL_POS) & 146 LED_1_MODE_SEL_MASK); 147 } else { 148 reg_val &= ~LED_0_MODE_SEL_MASK; 149 reg_val |= ((u16)mode & LED_0_MODE_SEL_MASK); 150 } 151 rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val); 152 mutex_unlock(&phydev->lock); 153 154 return rc; 155} 156 157static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix) 158{ 159 u16 reg_val; 160 161 reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL); 162 if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK) 163 *mdix = ETH_TP_MDI_X; 164 else 165 *mdix = ETH_TP_MDI; 166 167 return 0; 168} 169 170static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix) 171{ 172 int rc; 173 u16 reg_val; 174 175 reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL); 176 if ((mdix == ETH_TP_MDI) || (mdix == ETH_TP_MDI_X)) { 177 reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK | 178 DISABLE_POLARITY_CORR_MASK | 179 DISABLE_HP_AUTO_MDIX_MASK); 180 } else { 181 reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK | 182 DISABLE_POLARITY_CORR_MASK | 183 DISABLE_HP_AUTO_MDIX_MASK); 184 } 185 rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val); 186 if (rc != 0) 187 return rc; 188 189 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); 190 if (rc != 0) 191 return rc; 192 193 reg_val = phy_read(phydev, MSCC_PHY_EXT_MODE_CNTL); 194 reg_val &= ~(FORCE_MDI_CROSSOVER_MASK); 195 if (mdix == ETH_TP_MDI) 196 reg_val |= FORCE_MDI_CROSSOVER_MDI; 197 else if (mdix == ETH_TP_MDI_X) 198 reg_val |= FORCE_MDI_CROSSOVER_MDIX; 199 rc = phy_write(phydev, MSCC_PHY_EXT_MODE_CNTL, reg_val); 200 if (rc != 0) 201 return rc; 202 203 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 204 if (rc != 0) 205 return rc; 206 207 return genphy_restart_aneg(phydev); 208} 209 210static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count) 211{ 212 int rc; 213 u16 reg_val; 214 215 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); 216 if (rc != 0) 217 goto out; 218 219 reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); 220 reg_val &= DOWNSHIFT_CNTL_MASK; 221 if (!(reg_val & DOWNSHIFT_EN)) 222 *count = DOWNSHIFT_DEV_DISABLE; 223 else 224 *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2; 225 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 226 227out: 228 return rc; 229} 230 231static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count) 232{ 233 int rc; 234 u16 reg_val; 235 236 if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) { 237 /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */ 238 count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN); 239 } else if (count > DOWNSHIFT_COUNT_MAX || count == 1) { 240 phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n"); 241 return -ERANGE; 242 } else if (count) { 243 /* Downshift count is either 2,3,4 or 5 */ 244 count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN); 245 } 246 247 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED); 248 if (rc != 0) 249 goto out; 250 251 reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL); 252 reg_val &= ~(DOWNSHIFT_CNTL_MASK); 253 reg_val |= count; 254 rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val); 255 if (rc != 0) 256 goto out; 257 258 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 259 260out: 261 return rc; 262} 263 264static int vsc85xx_wol_set(struct phy_device *phydev, 265 struct ethtool_wolinfo *wol) 266{ 267 int rc; 268 u16 reg_val; 269 u8 i; 270 u16 pwd[3] = {0, 0, 0}; 271 struct ethtool_wolinfo *wol_conf = wol; 272 u8 *mac_addr = phydev->attached_dev->dev_addr; 273 274 mutex_lock(&phydev->lock); 275 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); 276 if (rc != 0) 277 goto out_unlock; 278 279 if (wol->wolopts & WAKE_MAGIC) { 280 /* Store the device address for the magic packet */ 281 for (i = 0; i < ARRAY_SIZE(pwd); i++) 282 pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 | 283 mac_addr[5 - i * 2]; 284 phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]); 285 phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]); 286 phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]); 287 } else { 288 phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0); 289 phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0); 290 phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0); 291 } 292 293 if (wol_conf->wolopts & WAKE_MAGICSECURE) { 294 for (i = 0; i < ARRAY_SIZE(pwd); i++) 295 pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 | 296 wol_conf->sopass[5 - i * 2]; 297 phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]); 298 phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]); 299 phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]); 300 } else { 301 phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0); 302 phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0); 303 phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0); 304 } 305 306 reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); 307 if (wol_conf->wolopts & WAKE_MAGICSECURE) 308 reg_val |= SECURE_ON_ENABLE; 309 else 310 reg_val &= ~SECURE_ON_ENABLE; 311 phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); 312 313 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 314 if (rc != 0) 315 goto out_unlock; 316 317 if (wol->wolopts & WAKE_MAGIC) { 318 /* Enable the WOL interrupt */ 319 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK); 320 reg_val |= MII_VSC85XX_INT_MASK_WOL; 321 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val); 322 if (rc != 0) 323 goto out_unlock; 324 } else { 325 /* Disable the WOL interrupt */ 326 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK); 327 reg_val &= (~MII_VSC85XX_INT_MASK_WOL); 328 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val); 329 if (rc != 0) 330 goto out_unlock; 331 } 332 /* Clear WOL iterrupt status */ 333 reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS); 334 335out_unlock: 336 mutex_unlock(&phydev->lock); 337 338 return rc; 339} 340 341static void vsc85xx_wol_get(struct phy_device *phydev, 342 struct ethtool_wolinfo *wol) 343{ 344 int rc; 345 u16 reg_val; 346 u8 i; 347 u16 pwd[3] = {0, 0, 0}; 348 struct ethtool_wolinfo *wol_conf = wol; 349 350 mutex_lock(&phydev->lock); 351 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); 352 if (rc != 0) 353 goto out_unlock; 354 355 reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); 356 if (reg_val & SECURE_ON_ENABLE) 357 wol_conf->wolopts |= WAKE_MAGICSECURE; 358 if (wol_conf->wolopts & WAKE_MAGICSECURE) { 359 pwd[0] = phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD); 360 pwd[1] = phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD); 361 pwd[2] = phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD); 362 for (i = 0; i < ARRAY_SIZE(pwd); i++) { 363 wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff; 364 wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00) 365 >> 8; 366 } 367 } 368 369 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 370 371out_unlock: 372 mutex_unlock(&phydev->lock); 373} 374 375#ifdef CONFIG_OF_MDIO 376static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) 377{ 378 u8 sd; 379 u16 vdd; 380 int rc, i, j; 381 struct device *dev = &phydev->mdio.dev; 382 struct device_node *of_node = dev->of_node; 383 u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown); 384 385 if (!of_node) 386 return -ENODEV; 387 388 rc = of_property_read_u16(of_node, "vsc8531,vddmac", &vdd); 389 if (rc != 0) 390 vdd = MSCC_VDDMAC_3300; 391 392 rc = of_property_read_u8(of_node, "vsc8531,edge-slowdown", &sd); 393 if (rc != 0) 394 sd = 0; 395 396 for (i = 0; i < ARRAY_SIZE(edge_table); i++) 397 if (edge_table[i].vddmac == vdd) 398 for (j = 0; j < sd_array_size; j++) 399 if (edge_table[i].slowdown[j] == sd) 400 return (sd_array_size - j - 1); 401 402 return -EINVAL; 403} 404 405static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, 406 char *led, 407 u8 default_mode) 408{ 409 struct device *dev = &phydev->mdio.dev; 410 struct device_node *of_node = dev->of_node; 411 u8 led_mode; 412 int err; 413 414 if (!of_node) 415 return -ENODEV; 416 417 led_mode = default_mode; 418 err = of_property_read_u8(of_node, led, &led_mode); 419 if (!err && (led_mode > 15 || led_mode == 7 || led_mode == 11)) { 420 phydev_err(phydev, "DT %s invalid\n", led); 421 return -EINVAL; 422 } 423 424 return led_mode; 425} 426 427#else 428static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev) 429{ 430 return 0; 431} 432 433static int vsc85xx_dt_led_mode_get(struct phy_device *phydev, 434 char *led, 435 u8 default_mode) 436{ 437 return default_mode; 438} 439#endif /* CONFIG_OF_MDIO */ 440 441static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate) 442{ 443 int rc; 444 u16 reg_val; 445 446 mutex_lock(&phydev->lock); 447 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); 448 if (rc != 0) 449 goto out_unlock; 450 reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL); 451 reg_val &= ~(EDGE_RATE_CNTL_MASK); 452 reg_val |= (edge_rate << EDGE_RATE_CNTL_POS); 453 rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val); 454 if (rc != 0) 455 goto out_unlock; 456 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 457 458out_unlock: 459 mutex_unlock(&phydev->lock); 460 461 return rc; 462} 463 464static int vsc85xx_mac_if_set(struct phy_device *phydev, 465 phy_interface_t interface) 466{ 467 int rc; 468 u16 reg_val; 469 470 mutex_lock(&phydev->lock); 471 reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1); 472 reg_val &= ~(MAC_IF_SELECTION_MASK); 473 switch (interface) { 474 case PHY_INTERFACE_MODE_RGMII: 475 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS); 476 break; 477 case PHY_INTERFACE_MODE_RMII: 478 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS); 479 break; 480 case PHY_INTERFACE_MODE_MII: 481 case PHY_INTERFACE_MODE_GMII: 482 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS); 483 break; 484 default: 485 rc = -EINVAL; 486 goto out_unlock; 487 } 488 rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val); 489 if (rc != 0) 490 goto out_unlock; 491 492 rc = genphy_soft_reset(phydev); 493 494out_unlock: 495 mutex_unlock(&phydev->lock); 496 497 return rc; 498} 499 500static int vsc85xx_default_config(struct phy_device *phydev) 501{ 502 int rc; 503 u16 reg_val; 504 505 phydev->mdix_ctrl = ETH_TP_MDI_AUTO; 506 mutex_lock(&phydev->lock); 507 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2); 508 if (rc != 0) 509 goto out_unlock; 510 511 reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL); 512 reg_val &= ~(RGMII_RX_CLK_DELAY_MASK); 513 reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS); 514 phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val); 515 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD); 516 517out_unlock: 518 mutex_unlock(&phydev->lock); 519 520 return rc; 521} 522 523static int vsc85xx_get_tunable(struct phy_device *phydev, 524 struct ethtool_tunable *tuna, void *data) 525{ 526 switch (tuna->id) { 527 case ETHTOOL_PHY_DOWNSHIFT: 528 return vsc85xx_downshift_get(phydev, (u8 *)data); 529 default: 530 return -EINVAL; 531 } 532} 533 534static int vsc85xx_set_tunable(struct phy_device *phydev, 535 struct ethtool_tunable *tuna, 536 const void *data) 537{ 538 switch (tuna->id) { 539 case ETHTOOL_PHY_DOWNSHIFT: 540 return vsc85xx_downshift_set(phydev, *(u8 *)data); 541 default: 542 return -EINVAL; 543 } 544} 545 546static int vsc85xx_config_init(struct phy_device *phydev) 547{ 548 int rc; 549 struct vsc8531_private *vsc8531 = phydev->priv; 550 551 rc = vsc85xx_default_config(phydev); 552 if (rc) 553 return rc; 554 555 rc = vsc85xx_mac_if_set(phydev, phydev->interface); 556 if (rc) 557 return rc; 558 559 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic); 560 if (rc) 561 return rc; 562 563 rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode); 564 if (rc) 565 return rc; 566 567 rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode); 568 if (rc) 569 return rc; 570 571 rc = genphy_config_init(phydev); 572 573 return rc; 574} 575 576static int vsc85xx_ack_interrupt(struct phy_device *phydev) 577{ 578 int rc = 0; 579 580 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) 581 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS); 582 583 return (rc < 0) ? rc : 0; 584} 585 586static int vsc85xx_config_intr(struct phy_device *phydev) 587{ 588 int rc; 589 590 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { 591 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 592 MII_VSC85XX_INT_MASK_MASK); 593 } else { 594 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0); 595 if (rc < 0) 596 return rc; 597 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS); 598 } 599 600 return rc; 601} 602 603static int vsc85xx_config_aneg(struct phy_device *phydev) 604{ 605 int rc; 606 607 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl); 608 if (rc < 0) 609 return rc; 610 611 return genphy_config_aneg(phydev); 612} 613 614static int vsc85xx_read_status(struct phy_device *phydev) 615{ 616 int rc; 617 618 rc = vsc85xx_mdix_get(phydev, &phydev->mdix); 619 if (rc < 0) 620 return rc; 621 622 return genphy_read_status(phydev); 623} 624 625static int vsc85xx_probe(struct phy_device *phydev) 626{ 627 struct vsc8531_private *vsc8531; 628 int rate_magic; 629 int led_mode; 630 631 rate_magic = vsc85xx_edge_rate_magic_get(phydev); 632 if (rate_magic < 0) 633 return rate_magic; 634 635 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL); 636 if (!vsc8531) 637 return -ENOMEM; 638 639 phydev->priv = vsc8531; 640 641 vsc8531->rate_magic = rate_magic; 642 643 /* LED[0] and LED[1] mode */ 644 led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-0-mode", 645 VSC8531_LINK_1000_ACTIVITY); 646 if (led_mode < 0) 647 return led_mode; 648 vsc8531->led_0_mode = led_mode; 649 650 led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode", 651 VSC8531_LINK_100_ACTIVITY); 652 if (led_mode < 0) 653 return led_mode; 654 vsc8531->led_1_mode = led_mode; 655 656 return 0; 657} 658 659/* Microsemi VSC85xx PHYs */ 660static struct phy_driver vsc85xx_driver[] = { 661{ 662 .phy_id = PHY_ID_VSC8530, 663 .name = "Microsemi FE VSC8530", 664 .phy_id_mask = 0xfffffff0, 665 .features = PHY_BASIC_FEATURES, 666 .flags = PHY_HAS_INTERRUPT, 667 .soft_reset = &genphy_soft_reset, 668 .config_init = &vsc85xx_config_init, 669 .config_aneg = &vsc85xx_config_aneg, 670 .aneg_done = &genphy_aneg_done, 671 .read_status = &vsc85xx_read_status, 672 .ack_interrupt = &vsc85xx_ack_interrupt, 673 .config_intr = &vsc85xx_config_intr, 674 .suspend = &genphy_suspend, 675 .resume = &genphy_resume, 676 .probe = &vsc85xx_probe, 677 .set_wol = &vsc85xx_wol_set, 678 .get_wol = &vsc85xx_wol_get, 679 .get_tunable = &vsc85xx_get_tunable, 680 .set_tunable = &vsc85xx_set_tunable, 681}, 682{ 683 .phy_id = PHY_ID_VSC8531, 684 .name = "Microsemi VSC8531", 685 .phy_id_mask = 0xfffffff0, 686 .features = PHY_GBIT_FEATURES, 687 .flags = PHY_HAS_INTERRUPT, 688 .soft_reset = &genphy_soft_reset, 689 .config_init = &vsc85xx_config_init, 690 .config_aneg = &vsc85xx_config_aneg, 691 .aneg_done = &genphy_aneg_done, 692 .read_status = &vsc85xx_read_status, 693 .ack_interrupt = &vsc85xx_ack_interrupt, 694 .config_intr = &vsc85xx_config_intr, 695 .suspend = &genphy_suspend, 696 .resume = &genphy_resume, 697 .probe = &vsc85xx_probe, 698 .set_wol = &vsc85xx_wol_set, 699 .get_wol = &vsc85xx_wol_get, 700 .get_tunable = &vsc85xx_get_tunable, 701 .set_tunable = &vsc85xx_set_tunable, 702}, 703{ 704 .phy_id = PHY_ID_VSC8540, 705 .name = "Microsemi FE VSC8540 SyncE", 706 .phy_id_mask = 0xfffffff0, 707 .features = PHY_BASIC_FEATURES, 708 .flags = PHY_HAS_INTERRUPT, 709 .soft_reset = &genphy_soft_reset, 710 .config_init = &vsc85xx_config_init, 711 .config_aneg = &vsc85xx_config_aneg, 712 .aneg_done = &genphy_aneg_done, 713 .read_status = &vsc85xx_read_status, 714 .ack_interrupt = &vsc85xx_ack_interrupt, 715 .config_intr = &vsc85xx_config_intr, 716 .suspend = &genphy_suspend, 717 .resume = &genphy_resume, 718 .probe = &vsc85xx_probe, 719 .set_wol = &vsc85xx_wol_set, 720 .get_wol = &vsc85xx_wol_get, 721 .get_tunable = &vsc85xx_get_tunable, 722 .set_tunable = &vsc85xx_set_tunable, 723}, 724{ 725 .phy_id = PHY_ID_VSC8541, 726 .name = "Microsemi VSC8541 SyncE", 727 .phy_id_mask = 0xfffffff0, 728 .features = PHY_GBIT_FEATURES, 729 .flags = PHY_HAS_INTERRUPT, 730 .soft_reset = &genphy_soft_reset, 731 .config_init = &vsc85xx_config_init, 732 .config_aneg = &vsc85xx_config_aneg, 733 .aneg_done = &genphy_aneg_done, 734 .read_status = &vsc85xx_read_status, 735 .ack_interrupt = &vsc85xx_ack_interrupt, 736 .config_intr = &vsc85xx_config_intr, 737 .suspend = &genphy_suspend, 738 .resume = &genphy_resume, 739 .probe = &vsc85xx_probe, 740 .set_wol = &vsc85xx_wol_set, 741 .get_wol = &vsc85xx_wol_get, 742 .get_tunable = &vsc85xx_get_tunable, 743 .set_tunable = &vsc85xx_set_tunable, 744} 745 746}; 747 748module_phy_driver(vsc85xx_driver); 749 750static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = { 751 { PHY_ID_VSC8530, 0xfffffff0, }, 752 { PHY_ID_VSC8531, 0xfffffff0, }, 753 { PHY_ID_VSC8540, 0xfffffff0, }, 754 { PHY_ID_VSC8541, 0xfffffff0, }, 755 { } 756}; 757 758MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl); 759 760MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver"); 761MODULE_AUTHOR("Nagaraju Lakkaraju"); 762MODULE_LICENSE("Dual MIT/GPL");