2 * Driver for Microsemi VSC85xx PHYs
4 * Author: Nagaraju Lakkaraju
5 * License: Dual MIT/GPL
6 * Copyright (c) 2016 Microsemi Corporation
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>
15 #include <linux/netdevice.h>
16 #include <dt-bindings/net/mscc-phy-vsc8531.h>
18 enum 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
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
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
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
49 #define MSCC_PHY_WOL_MAC_CONTROL 27
50 #define EDGE_RATE_CNTL_POS 5
51 #define EDGE_RATE_CNTL_MASK 0x00E0
53 #define MSCC_PHY_DEV_AUX_CNTL 28
54 #define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
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
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 */
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
72 #define MSCC_PHY_ACTIPHY_CNTL 20
73 #define DOWNSHIFT_CNTL_MASK 0x001C
74 #define DOWNSHIFT_EN 0x0010
75 #define DOWNSHIFT_CNTL_POS 2
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
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
89 #define MSCC_PHY_WOL_MAC_CONTROL 27
90 #define SECURE_ON_ENABLE 0x8000
91 #define SECURE_ON_PASSWD_LEN_4 0x4000
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
99 #define MSCC_VDDMAC_1500 1500
100 #define MSCC_VDDMAC_1800 1800
101 #define MSCC_VDDMAC_2500 2500
102 #define MSCC_VDDMAC_3300 3300
104 #define DOWNSHIFT_COUNT_MAX 5
106 struct vsc8531_private {
112 #ifdef CONFIG_OF_MDIO
113 struct vsc8531_edge_rate_table {
118 static 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} },
124 #endif /* CONFIG_OF_MDIO */
126 static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
130 rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
134 static int vsc85xx_led_cntl_set(struct phy_device *phydev,
141 mutex_lock(&phydev->lock);
142 reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
144 reg_val &= ~LED_1_MODE_SEL_MASK;
145 reg_val |= (((u16)mode << LED_1_MODE_SEL_POS) &
146 LED_1_MODE_SEL_MASK);
148 reg_val &= ~LED_0_MODE_SEL_MASK;
149 reg_val |= ((u16)mode & LED_0_MODE_SEL_MASK);
151 rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
152 mutex_unlock(&phydev->lock);
157 static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
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;
170 static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
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);
181 reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
182 DISABLE_POLARITY_CORR_MASK |
183 DISABLE_HP_AUTO_MDIX_MASK);
185 rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
189 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
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);
203 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
207 return genphy_restart_aneg(phydev);
210 static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
215 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
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;
224 *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
225 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
231 static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
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");
243 /* Downshift count is either 2,3,4 or 5 */
244 count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
247 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED);
251 reg_val = phy_read(phydev, MSCC_PHY_ACTIPHY_CNTL);
252 reg_val &= ~(DOWNSHIFT_CNTL_MASK);
254 rc = phy_write(phydev, MSCC_PHY_ACTIPHY_CNTL, reg_val);
258 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
264 static int vsc85xx_wol_set(struct phy_device *phydev,
265 struct ethtool_wolinfo *wol)
270 u16 pwd[3] = {0, 0, 0};
271 struct ethtool_wolinfo *wol_conf = wol;
272 u8 *mac_addr = phydev->attached_dev->dev_addr;
274 mutex_lock(&phydev->lock);
275 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
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 |
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]);
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);
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]);
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);
306 reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
307 if (wol_conf->wolopts & WAKE_MAGICSECURE)
308 reg_val |= SECURE_ON_ENABLE;
310 reg_val &= ~SECURE_ON_ENABLE;
311 phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
313 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
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);
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);
332 /* Clear WOL iterrupt status */
333 reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
336 mutex_unlock(&phydev->lock);
341 static void vsc85xx_wol_get(struct phy_device *phydev,
342 struct ethtool_wolinfo *wol)
347 u16 pwd[3] = {0, 0, 0};
348 struct ethtool_wolinfo *wol_conf = wol;
350 mutex_lock(&phydev->lock);
351 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
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)
369 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
372 mutex_unlock(&phydev->lock);
375 #ifdef CONFIG_OF_MDIO
376 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
380 struct device *dev = &phydev->mdio.dev;
381 struct device_node *of_node = dev->of_node;
382 u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
387 rc = of_property_read_u32(of_node, "vsc8531,vddmac", &vdd);
389 vdd = MSCC_VDDMAC_3300;
391 rc = of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd);
395 for (i = 0; i < ARRAY_SIZE(edge_table); i++)
396 if (edge_table[i].vddmac == vdd)
397 for (j = 0; j < sd_array_size; j++)
398 if (edge_table[i].slowdown[j] == sd)
399 return (sd_array_size - j - 1);
404 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
408 struct device *dev = &phydev->mdio.dev;
409 struct device_node *of_node = dev->of_node;
416 led_mode = default_mode;
417 err = of_property_read_u8(of_node, led, &led_mode);
418 if (!err && (led_mode > 15 || led_mode == 7 || led_mode == 11)) {
419 phydev_err(phydev, "DT %s invalid\n", led);
427 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
432 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
438 #endif /* CONFIG_OF_MDIO */
440 static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
445 mutex_lock(&phydev->lock);
446 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
449 reg_val = phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
450 reg_val &= ~(EDGE_RATE_CNTL_MASK);
451 reg_val |= (edge_rate << EDGE_RATE_CNTL_POS);
452 rc = phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
455 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
458 mutex_unlock(&phydev->lock);
463 static int vsc85xx_mac_if_set(struct phy_device *phydev,
464 phy_interface_t interface)
469 mutex_lock(&phydev->lock);
470 reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
471 reg_val &= ~(MAC_IF_SELECTION_MASK);
473 case PHY_INTERFACE_MODE_RGMII:
474 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
476 case PHY_INTERFACE_MODE_RMII:
477 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
479 case PHY_INTERFACE_MODE_MII:
480 case PHY_INTERFACE_MODE_GMII:
481 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
487 rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
491 rc = genphy_soft_reset(phydev);
494 mutex_unlock(&phydev->lock);
499 static int vsc85xx_default_config(struct phy_device *phydev)
504 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
505 mutex_lock(&phydev->lock);
506 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
510 reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
511 reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
512 reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
513 phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
514 rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
517 mutex_unlock(&phydev->lock);
522 static int vsc85xx_get_tunable(struct phy_device *phydev,
523 struct ethtool_tunable *tuna, void *data)
526 case ETHTOOL_PHY_DOWNSHIFT:
527 return vsc85xx_downshift_get(phydev, (u8 *)data);
533 static int vsc85xx_set_tunable(struct phy_device *phydev,
534 struct ethtool_tunable *tuna,
538 case ETHTOOL_PHY_DOWNSHIFT:
539 return vsc85xx_downshift_set(phydev, *(u8 *)data);
545 static int vsc85xx_config_init(struct phy_device *phydev)
548 struct vsc8531_private *vsc8531 = phydev->priv;
550 rc = vsc85xx_default_config(phydev);
554 rc = vsc85xx_mac_if_set(phydev, phydev->interface);
558 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
562 rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode);
566 rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode);
570 rc = genphy_config_init(phydev);
575 static int vsc85xx_ack_interrupt(struct phy_device *phydev)
579 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
580 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
582 return (rc < 0) ? rc : 0;
585 static int vsc85xx_config_intr(struct phy_device *phydev)
589 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
590 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
591 MII_VSC85XX_INT_MASK_MASK);
593 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
596 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
602 static int vsc85xx_config_aneg(struct phy_device *phydev)
606 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
610 return genphy_config_aneg(phydev);
613 static int vsc85xx_read_status(struct phy_device *phydev)
617 rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
621 return genphy_read_status(phydev);
624 static int vsc85xx_probe(struct phy_device *phydev)
626 struct vsc8531_private *vsc8531;
630 rate_magic = vsc85xx_edge_rate_magic_get(phydev);
634 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
638 phydev->priv = vsc8531;
640 vsc8531->rate_magic = rate_magic;
642 /* LED[0] and LED[1] mode */
643 led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-0-mode",
644 VSC8531_LINK_1000_ACTIVITY);
647 vsc8531->led_0_mode = led_mode;
649 led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode",
650 VSC8531_LINK_100_ACTIVITY);
653 vsc8531->led_1_mode = led_mode;
658 /* Microsemi VSC85xx PHYs */
659 static struct phy_driver vsc85xx_driver[] = {
661 .phy_id = PHY_ID_VSC8530,
662 .name = "Microsemi FE VSC8530",
663 .phy_id_mask = 0xfffffff0,
664 .features = PHY_BASIC_FEATURES,
665 .flags = PHY_HAS_INTERRUPT,
666 .soft_reset = &genphy_soft_reset,
667 .config_init = &vsc85xx_config_init,
668 .config_aneg = &vsc85xx_config_aneg,
669 .aneg_done = &genphy_aneg_done,
670 .read_status = &vsc85xx_read_status,
671 .ack_interrupt = &vsc85xx_ack_interrupt,
672 .config_intr = &vsc85xx_config_intr,
673 .suspend = &genphy_suspend,
674 .resume = &genphy_resume,
675 .probe = &vsc85xx_probe,
676 .set_wol = &vsc85xx_wol_set,
677 .get_wol = &vsc85xx_wol_get,
678 .get_tunable = &vsc85xx_get_tunable,
679 .set_tunable = &vsc85xx_set_tunable,
682 .phy_id = PHY_ID_VSC8531,
683 .name = "Microsemi VSC8531",
684 .phy_id_mask = 0xfffffff0,
685 .features = PHY_GBIT_FEATURES,
686 .flags = PHY_HAS_INTERRUPT,
687 .soft_reset = &genphy_soft_reset,
688 .config_init = &vsc85xx_config_init,
689 .config_aneg = &vsc85xx_config_aneg,
690 .aneg_done = &genphy_aneg_done,
691 .read_status = &vsc85xx_read_status,
692 .ack_interrupt = &vsc85xx_ack_interrupt,
693 .config_intr = &vsc85xx_config_intr,
694 .suspend = &genphy_suspend,
695 .resume = &genphy_resume,
696 .probe = &vsc85xx_probe,
697 .set_wol = &vsc85xx_wol_set,
698 .get_wol = &vsc85xx_wol_get,
699 .get_tunable = &vsc85xx_get_tunable,
700 .set_tunable = &vsc85xx_set_tunable,
703 .phy_id = PHY_ID_VSC8540,
704 .name = "Microsemi FE VSC8540 SyncE",
705 .phy_id_mask = 0xfffffff0,
706 .features = PHY_BASIC_FEATURES,
707 .flags = PHY_HAS_INTERRUPT,
708 .soft_reset = &genphy_soft_reset,
709 .config_init = &vsc85xx_config_init,
710 .config_aneg = &vsc85xx_config_aneg,
711 .aneg_done = &genphy_aneg_done,
712 .read_status = &vsc85xx_read_status,
713 .ack_interrupt = &vsc85xx_ack_interrupt,
714 .config_intr = &vsc85xx_config_intr,
715 .suspend = &genphy_suspend,
716 .resume = &genphy_resume,
717 .probe = &vsc85xx_probe,
718 .set_wol = &vsc85xx_wol_set,
719 .get_wol = &vsc85xx_wol_get,
720 .get_tunable = &vsc85xx_get_tunable,
721 .set_tunable = &vsc85xx_set_tunable,
724 .phy_id = PHY_ID_VSC8541,
725 .name = "Microsemi VSC8541 SyncE",
726 .phy_id_mask = 0xfffffff0,
727 .features = PHY_GBIT_FEATURES,
728 .flags = PHY_HAS_INTERRUPT,
729 .soft_reset = &genphy_soft_reset,
730 .config_init = &vsc85xx_config_init,
731 .config_aneg = &vsc85xx_config_aneg,
732 .aneg_done = &genphy_aneg_done,
733 .read_status = &vsc85xx_read_status,
734 .ack_interrupt = &vsc85xx_ack_interrupt,
735 .config_intr = &vsc85xx_config_intr,
736 .suspend = &genphy_suspend,
737 .resume = &genphy_resume,
738 .probe = &vsc85xx_probe,
739 .set_wol = &vsc85xx_wol_set,
740 .get_wol = &vsc85xx_wol_get,
741 .get_tunable = &vsc85xx_get_tunable,
742 .set_tunable = &vsc85xx_set_tunable,
747 module_phy_driver(vsc85xx_driver);
749 static struct mdio_device_id __maybe_unused vsc85xx_tbl[] = {
750 { PHY_ID_VSC8530, 0xfffffff0, },
751 { PHY_ID_VSC8531, 0xfffffff0, },
752 { PHY_ID_VSC8540, 0xfffffff0, },
753 { PHY_ID_VSC8541, 0xfffffff0, },
757 MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
759 MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
760 MODULE_AUTHOR("Nagaraju Lakkaraju");
761 MODULE_LICENSE("Dual MIT/GPL");