linux/drivers/net/phy/mscc.c
<<
>>
Prefs
   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, u16 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");
 763