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_MODE_SEL_POS(x) ((x) * 4)
58 #define LED_MODE_SEL_MASK(x) (GENMASK(3, 0) << LED_MODE_SEL_POS(x))
59 #define LED_MODE_SEL(x, mode) (((mode) << LED_MODE_SEL_POS(x)) & LED_MODE_SEL_MASK(x))
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
107 #define VSC85XX_SUPP_LED_MODES (BIT(VSC8531_LINK_ACTIVITY) | \
108 BIT(VSC8531_LINK_1000_ACTIVITY) | \
109 BIT(VSC8531_LINK_100_ACTIVITY) | \
110 BIT(VSC8531_LINK_10_ACTIVITY) | \
111 BIT(VSC8531_LINK_100_1000_ACTIVITY) | \
112 BIT(VSC8531_LINK_10_1000_ACTIVITY) | \
113 BIT(VSC8531_LINK_10_100_ACTIVITY) | \
114 BIT(VSC8531_DUPLEX_COLLISION) | \
115 BIT(VSC8531_COLLISION) | \
116 BIT(VSC8531_ACTIVITY) | \
117 BIT(VSC8531_AUTONEG_FAULT) | \
118 BIT(VSC8531_SERIAL_MODE) | \
119 BIT(VSC8531_FORCE_LED_OFF) | \
120 BIT(VSC8531_FORCE_LED_ON))
122 struct vsc8531_private {
125 u32 leds_mode[MAX_LEDS];
129 #ifdef CONFIG_OF_MDIO
130 struct vsc8531_edge_rate_table {
135 static const struct vsc8531_edge_rate_table edge_table[] = {
136 {MSCC_VDDMAC_3300, { 0, 2, 4, 7, 10, 17, 29, 53} },
137 {MSCC_VDDMAC_2500, { 0, 3, 6, 10, 14, 23, 37, 63} },
138 {MSCC_VDDMAC_1800, { 0, 5, 9, 16, 23, 35, 52, 76} },
139 {MSCC_VDDMAC_1500, { 0, 6, 14, 21, 29, 42, 58, 77} },
141 #endif /* CONFIG_OF_MDIO */
143 static int vsc85xx_phy_read_page(struct phy_device *phydev)
145 return __phy_read(phydev, MSCC_EXT_PAGE_ACCESS);
148 static int vsc85xx_phy_write_page(struct phy_device *phydev, int page)
150 return __phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
153 static int vsc85xx_led_cntl_set(struct phy_device *phydev,
160 mutex_lock(&phydev->lock);
161 reg_val = phy_read(phydev, MSCC_PHY_LED_MODE_SEL);
162 reg_val &= ~LED_MODE_SEL_MASK(led_num);
163 reg_val |= LED_MODE_SEL(led_num, (u16)mode);
164 rc = phy_write(phydev, MSCC_PHY_LED_MODE_SEL, reg_val);
165 mutex_unlock(&phydev->lock);
170 static int vsc85xx_mdix_get(struct phy_device *phydev, u8 *mdix)
174 reg_val = phy_read(phydev, MSCC_PHY_DEV_AUX_CNTL);
175 if (reg_val & HP_AUTO_MDIX_X_OVER_IND_MASK)
176 *mdix = ETH_TP_MDI_X;
183 static int vsc85xx_mdix_set(struct phy_device *phydev, u8 mdix)
188 reg_val = phy_read(phydev, MSCC_PHY_BYPASS_CONTROL);
189 if ((mdix == ETH_TP_MDI) || (mdix == ETH_TP_MDI_X)) {
190 reg_val |= (DISABLE_PAIR_SWAP_CORR_MASK |
191 DISABLE_POLARITY_CORR_MASK |
192 DISABLE_HP_AUTO_MDIX_MASK);
194 reg_val &= ~(DISABLE_PAIR_SWAP_CORR_MASK |
195 DISABLE_POLARITY_CORR_MASK |
196 DISABLE_HP_AUTO_MDIX_MASK);
198 rc = phy_write(phydev, MSCC_PHY_BYPASS_CONTROL, reg_val);
204 if (mdix == ETH_TP_MDI)
205 reg_val = FORCE_MDI_CROSSOVER_MDI;
206 else if (mdix == ETH_TP_MDI_X)
207 reg_val = FORCE_MDI_CROSSOVER_MDIX;
209 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
210 MSCC_PHY_EXT_MODE_CNTL, FORCE_MDI_CROSSOVER_MASK,
215 return genphy_restart_aneg(phydev);
218 static int vsc85xx_downshift_get(struct phy_device *phydev, u8 *count)
222 reg_val = phy_read_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
223 MSCC_PHY_ACTIPHY_CNTL);
227 reg_val &= DOWNSHIFT_CNTL_MASK;
228 if (!(reg_val & DOWNSHIFT_EN))
229 *count = DOWNSHIFT_DEV_DISABLE;
231 *count = ((reg_val & ~DOWNSHIFT_EN) >> DOWNSHIFT_CNTL_POS) + 2;
236 static int vsc85xx_downshift_set(struct phy_device *phydev, u8 count)
238 if (count == DOWNSHIFT_DEV_DEFAULT_COUNT) {
239 /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
240 count = ((1 << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
241 } else if (count > DOWNSHIFT_COUNT_MAX || count == 1) {
242 phydev_err(phydev, "Downshift count should be 2,3,4 or 5\n");
245 /* Downshift count is either 2,3,4 or 5 */
246 count = (((count - 2) << DOWNSHIFT_CNTL_POS) | DOWNSHIFT_EN);
249 return phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED,
250 MSCC_PHY_ACTIPHY_CNTL, DOWNSHIFT_CNTL_MASK,
254 static int vsc85xx_wol_set(struct phy_device *phydev,
255 struct ethtool_wolinfo *wol)
260 u16 pwd[3] = {0, 0, 0};
261 struct ethtool_wolinfo *wol_conf = wol;
262 u8 *mac_addr = phydev->attached_dev->dev_addr;
264 mutex_lock(&phydev->lock);
265 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
267 rc = phy_restore_page(phydev, rc, rc);
271 if (wol->wolopts & WAKE_MAGIC) {
272 /* Store the device address for the magic packet */
273 for (i = 0; i < ARRAY_SIZE(pwd); i++)
274 pwd[i] = mac_addr[5 - (i * 2 + 1)] << 8 |
276 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, pwd[0]);
277 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, pwd[1]);
278 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, pwd[2]);
280 __phy_write(phydev, MSCC_PHY_WOL_LOWER_MAC_ADDR, 0);
281 __phy_write(phydev, MSCC_PHY_WOL_MID_MAC_ADDR, 0);
282 __phy_write(phydev, MSCC_PHY_WOL_UPPER_MAC_ADDR, 0);
285 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
286 for (i = 0; i < ARRAY_SIZE(pwd); i++)
287 pwd[i] = wol_conf->sopass[5 - (i * 2 + 1)] << 8 |
288 wol_conf->sopass[5 - i * 2];
289 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, pwd[0]);
290 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, pwd[1]);
291 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, pwd[2]);
293 __phy_write(phydev, MSCC_PHY_WOL_LOWER_PASSWD, 0);
294 __phy_write(phydev, MSCC_PHY_WOL_MID_PASSWD, 0);
295 __phy_write(phydev, MSCC_PHY_WOL_UPPER_PASSWD, 0);
298 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
299 if (wol_conf->wolopts & WAKE_MAGICSECURE)
300 reg_val |= SECURE_ON_ENABLE;
302 reg_val &= ~SECURE_ON_ENABLE;
303 __phy_write(phydev, MSCC_PHY_WOL_MAC_CONTROL, reg_val);
305 rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
309 if (wol->wolopts & WAKE_MAGIC) {
310 /* Enable the WOL interrupt */
311 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
312 reg_val |= MII_VSC85XX_INT_MASK_WOL;
313 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
317 /* Disable the WOL interrupt */
318 reg_val = phy_read(phydev, MII_VSC85XX_INT_MASK);
319 reg_val &= (~MII_VSC85XX_INT_MASK_WOL);
320 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, reg_val);
324 /* Clear WOL iterrupt status */
325 reg_val = phy_read(phydev, MII_VSC85XX_INT_STATUS);
328 mutex_unlock(&phydev->lock);
333 static void vsc85xx_wol_get(struct phy_device *phydev,
334 struct ethtool_wolinfo *wol)
339 u16 pwd[3] = {0, 0, 0};
340 struct ethtool_wolinfo *wol_conf = wol;
342 mutex_lock(&phydev->lock);
343 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
347 reg_val = __phy_read(phydev, MSCC_PHY_WOL_MAC_CONTROL);
348 if (reg_val & SECURE_ON_ENABLE)
349 wol_conf->wolopts |= WAKE_MAGICSECURE;
350 if (wol_conf->wolopts & WAKE_MAGICSECURE) {
351 pwd[0] = __phy_read(phydev, MSCC_PHY_WOL_LOWER_PASSWD);
352 pwd[1] = __phy_read(phydev, MSCC_PHY_WOL_MID_PASSWD);
353 pwd[2] = __phy_read(phydev, MSCC_PHY_WOL_UPPER_PASSWD);
354 for (i = 0; i < ARRAY_SIZE(pwd); i++) {
355 wol_conf->sopass[5 - i * 2] = pwd[i] & 0x00ff;
356 wol_conf->sopass[5 - (i * 2 + 1)] = (pwd[i] & 0xff00)
362 phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
363 mutex_unlock(&phydev->lock);
366 #ifdef CONFIG_OF_MDIO
367 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
371 struct device *dev = &phydev->mdio.dev;
372 struct device_node *of_node = dev->of_node;
373 u8 sd_array_size = ARRAY_SIZE(edge_table[0].slowdown);
378 rc = of_property_read_u32(of_node, "vsc8531,vddmac", &vdd);
380 vdd = MSCC_VDDMAC_3300;
382 rc = of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd);
386 for (i = 0; i < ARRAY_SIZE(edge_table); i++)
387 if (edge_table[i].vddmac == vdd)
388 for (j = 0; j < sd_array_size; j++)
389 if (edge_table[i].slowdown[j] == sd)
390 return (sd_array_size - j - 1);
395 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
399 struct vsc8531_private *priv = phydev->priv;
400 struct device *dev = &phydev->mdio.dev;
401 struct device_node *of_node = dev->of_node;
408 led_mode = default_mode;
409 err = of_property_read_u32(of_node, led, &led_mode);
410 if (!err && !(BIT(led_mode) & priv->supp_led_modes)) {
411 phydev_err(phydev, "DT %s invalid\n", led);
419 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
424 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
430 #endif /* CONFIG_OF_MDIO */
432 static int vsc85xx_dt_led_modes_get(struct phy_device *phydev,
435 struct vsc8531_private *priv = phydev->priv;
436 char led_dt_prop[28];
439 for (i = 0; i < priv->nleds; i++) {
440 ret = sprintf(led_dt_prop, "vsc8531,led-%d-mode", i);
444 ret = vsc85xx_dt_led_mode_get(phydev, led_dt_prop,
448 priv->leds_mode[i] = ret;
454 static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
458 mutex_lock(&phydev->lock);
459 rc = phy_modify_paged(phydev, MSCC_PHY_PAGE_EXTENDED_2,
460 MSCC_PHY_WOL_MAC_CONTROL, EDGE_RATE_CNTL_MASK,
461 edge_rate << EDGE_RATE_CNTL_POS);
462 mutex_unlock(&phydev->lock);
467 static int vsc85xx_mac_if_set(struct phy_device *phydev,
468 phy_interface_t interface)
473 mutex_lock(&phydev->lock);
474 reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
475 reg_val &= ~(MAC_IF_SELECTION_MASK);
477 case PHY_INTERFACE_MODE_RGMII:
478 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
480 case PHY_INTERFACE_MODE_RMII:
481 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
483 case PHY_INTERFACE_MODE_MII:
484 case PHY_INTERFACE_MODE_GMII:
485 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
491 rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
495 rc = genphy_soft_reset(phydev);
498 mutex_unlock(&phydev->lock);
503 static int vsc85xx_default_config(struct phy_device *phydev)
508 phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
509 mutex_lock(&phydev->lock);
510 rc = phy_select_page(phydev, MSCC_PHY_PAGE_EXTENDED_2);
514 reg_val = phy_read(phydev, MSCC_PHY_RGMII_CNTL);
515 reg_val &= ~(RGMII_RX_CLK_DELAY_MASK);
516 reg_val |= (RGMII_RX_CLK_DELAY_1_1_NS << RGMII_RX_CLK_DELAY_POS);
517 phy_write(phydev, MSCC_PHY_RGMII_CNTL, reg_val);
520 rc = phy_restore_page(phydev, rc, rc > 0 ? 0 : rc);
521 mutex_unlock(&phydev->lock);
526 static int vsc85xx_get_tunable(struct phy_device *phydev,
527 struct ethtool_tunable *tuna, void *data)
530 case ETHTOOL_PHY_DOWNSHIFT:
531 return vsc85xx_downshift_get(phydev, (u8 *)data);
537 static int vsc85xx_set_tunable(struct phy_device *phydev,
538 struct ethtool_tunable *tuna,
542 case ETHTOOL_PHY_DOWNSHIFT:
543 return vsc85xx_downshift_set(phydev, *(u8 *)data);
549 static int vsc85xx_config_init(struct phy_device *phydev)
552 struct vsc8531_private *vsc8531 = phydev->priv;
554 rc = vsc85xx_default_config(phydev);
558 rc = vsc85xx_mac_if_set(phydev, phydev->interface);
562 rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
566 for (i = 0; i < vsc8531->nleds; i++) {
567 rc = vsc85xx_led_cntl_set(phydev, i, vsc8531->leds_mode[i]);
572 rc = genphy_config_init(phydev);
577 static int vsc85xx_ack_interrupt(struct phy_device *phydev)
581 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
582 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
584 return (rc < 0) ? rc : 0;
587 static int vsc85xx_config_intr(struct phy_device *phydev)
591 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
592 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
593 MII_VSC85XX_INT_MASK_MASK);
595 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
598 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
604 static int vsc85xx_config_aneg(struct phy_device *phydev)
608 rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
612 return genphy_config_aneg(phydev);
615 static int vsc85xx_read_status(struct phy_device *phydev)
619 rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
623 return genphy_read_status(phydev);
626 static int vsc85xx_probe(struct phy_device *phydev)
628 struct vsc8531_private *vsc8531;
630 u32 default_mode[2] = {VSC8531_LINK_1000_ACTIVITY,
631 VSC8531_LINK_100_ACTIVITY};
633 rate_magic = vsc85xx_edge_rate_magic_get(phydev);
637 vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
641 phydev->priv = vsc8531;
643 vsc8531->rate_magic = rate_magic;
645 vsc8531->supp_led_modes = VSC85XX_SUPP_LED_MODES;
647 return vsc85xx_dt_led_modes_get(phydev, default_mode);
650 /* Microsemi VSC85xx PHYs */
651 static struct phy_driver vsc85xx_driver[] = {
653 .phy_id = PHY_ID_VSC8530,
654 .name = "Microsemi FE VSC8530",
655 .phy_id_mask = 0xfffffff0,
656 .features = PHY_BASIC_FEATURES,
657 .flags = PHY_HAS_INTERRUPT,
658 .soft_reset = &genphy_soft_reset,
659 .config_init = &vsc85xx_config_init,
660 .config_aneg = &vsc85xx_config_aneg,
661 .aneg_done = &genphy_aneg_done,
662 .read_status = &vsc85xx_read_status,
663 .ack_interrupt = &vsc85xx_ack_interrupt,
664 .config_intr = &vsc85xx_config_intr,
665 .suspend = &genphy_suspend,
666 .resume = &genphy_resume,
667 .probe = &vsc85xx_probe,
668 .set_wol = &vsc85xx_wol_set,
669 .get_wol = &vsc85xx_wol_get,
670 .get_tunable = &vsc85xx_get_tunable,
671 .set_tunable = &vsc85xx_set_tunable,
672 .read_page = &vsc85xx_phy_read_page,
673 .write_page = &vsc85xx_phy_write_page,
676 .phy_id = PHY_ID_VSC8531,
677 .name = "Microsemi VSC8531",
678 .phy_id_mask = 0xfffffff0,
679 .features = PHY_GBIT_FEATURES,
680 .flags = PHY_HAS_INTERRUPT,
681 .soft_reset = &genphy_soft_reset,
682 .config_init = &vsc85xx_config_init,
683 .config_aneg = &vsc85xx_config_aneg,
684 .aneg_done = &genphy_aneg_done,
685 .read_status = &vsc85xx_read_status,
686 .ack_interrupt = &vsc85xx_ack_interrupt,
687 .config_intr = &vsc85xx_config_intr,
688 .suspend = &genphy_suspend,
689 .resume = &genphy_resume,
690 .probe = &vsc85xx_probe,
691 .set_wol = &vsc85xx_wol_set,
692 .get_wol = &vsc85xx_wol_get,
693 .get_tunable = &vsc85xx_get_tunable,
694 .set_tunable = &vsc85xx_set_tunable,
695 .read_page = &vsc85xx_phy_read_page,
696 .write_page = &vsc85xx_phy_write_page,
699 .phy_id = PHY_ID_VSC8540,
700 .name = "Microsemi FE VSC8540 SyncE",
701 .phy_id_mask = 0xfffffff0,
702 .features = PHY_BASIC_FEATURES,
703 .flags = PHY_HAS_INTERRUPT,
704 .soft_reset = &genphy_soft_reset,
705 .config_init = &vsc85xx_config_init,
706 .config_aneg = &vsc85xx_config_aneg,
707 .aneg_done = &genphy_aneg_done,
708 .read_status = &vsc85xx_read_status,
709 .ack_interrupt = &vsc85xx_ack_interrupt,
710 .config_intr = &vsc85xx_config_intr,
711 .suspend = &genphy_suspend,
712 .resume = &genphy_resume,
713 .probe = &vsc85xx_probe,
714 .set_wol = &vsc85xx_wol_set,
715 .get_wol = &vsc85xx_wol_get,
716 .get_tunable = &vsc85xx_get_tunable,
717 .set_tunable = &vsc85xx_set_tunable,
718 .read_page = &vsc85xx_phy_read_page,
719 .write_page = &vsc85xx_phy_write_page,
722 .phy_id = PHY_ID_VSC8541,
723 .name = "Microsemi VSC8541 SyncE",
724 .phy_id_mask = 0xfffffff0,
725 .features = PHY_GBIT_FEATURES,
726 .flags = PHY_HAS_INTERRUPT,
727 .soft_reset = &genphy_soft_reset,
728 .config_init = &vsc85xx_config_init,
729 .config_aneg = &vsc85xx_config_aneg,
730 .aneg_done = &genphy_aneg_done,
731 .read_status = &vsc85xx_read_status,
732 .ack_interrupt = &vsc85xx_ack_interrupt,
733 .config_intr = &vsc85xx_config_intr,
734 .suspend = &genphy_suspend,
735 .resume = &genphy_resume,
736 .probe = &vsc85xx_probe,
737 .set_wol = &vsc85xx_wol_set,
738 .get_wol = &vsc85xx_wol_get,
739 .get_tunable = &vsc85xx_get_tunable,
740 .set_tunable = &vsc85xx_set_tunable,
741 .read_page = &vsc85xx_phy_read_page,
742 .write_page = &vsc85xx_phy_write_page,
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");