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
)
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
);
388 rc
= of_property_read_u16(of_node
, "vsc8531,vddmac", &vdd
);
390 vdd
= MSCC_VDDMAC_3300
;
392 rc
= of_property_read_u8(of_node
, "vsc8531,edge-slowdown", &sd
);
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);
405 static int vsc85xx_dt_led_mode_get(struct phy_device
*phydev
,
409 struct device
*dev
= &phydev
->mdio
.dev
;
410 struct device_node
*of_node
= dev
->of_node
;
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
);
428 static int vsc85xx_edge_rate_magic_get(struct phy_device
*phydev
)
433 static int vsc85xx_dt_led_mode_get(struct phy_device
*phydev
,
439 #endif /* CONFIG_OF_MDIO */
441 static int vsc85xx_edge_rate_cntl_set(struct phy_device
*phydev
, u8 edge_rate
)
446 mutex_lock(&phydev
->lock
);
447 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
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
);
456 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
459 mutex_unlock(&phydev
->lock
);
464 static int vsc85xx_mac_if_set(struct phy_device
*phydev
,
465 phy_interface_t interface
)
470 mutex_lock(&phydev
->lock
);
471 reg_val
= phy_read(phydev
, MSCC_PHY_EXT_PHY_CNTL_1
);
472 reg_val
&= ~(MAC_IF_SELECTION_MASK
);
474 case PHY_INTERFACE_MODE_RGMII
:
475 reg_val
|= (MAC_IF_SELECTION_RGMII
<< MAC_IF_SELECTION_POS
);
477 case PHY_INTERFACE_MODE_RMII
:
478 reg_val
|= (MAC_IF_SELECTION_RMII
<< MAC_IF_SELECTION_POS
);
480 case PHY_INTERFACE_MODE_MII
:
481 case PHY_INTERFACE_MODE_GMII
:
482 reg_val
|= (MAC_IF_SELECTION_GMII
<< MAC_IF_SELECTION_POS
);
488 rc
= phy_write(phydev
, MSCC_PHY_EXT_PHY_CNTL_1
, reg_val
);
492 rc
= genphy_soft_reset(phydev
);
495 mutex_unlock(&phydev
->lock
);
500 static int vsc85xx_default_config(struct phy_device
*phydev
)
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
);
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
);
518 mutex_unlock(&phydev
->lock
);
523 static int vsc85xx_get_tunable(struct phy_device
*phydev
,
524 struct ethtool_tunable
*tuna
, void *data
)
527 case ETHTOOL_PHY_DOWNSHIFT
:
528 return vsc85xx_downshift_get(phydev
, (u8
*)data
);
534 static int vsc85xx_set_tunable(struct phy_device
*phydev
,
535 struct ethtool_tunable
*tuna
,
539 case ETHTOOL_PHY_DOWNSHIFT
:
540 return vsc85xx_downshift_set(phydev
, *(u8
*)data
);
546 static int vsc85xx_config_init(struct phy_device
*phydev
)
549 struct vsc8531_private
*vsc8531
= phydev
->priv
;
551 rc
= vsc85xx_default_config(phydev
);
555 rc
= vsc85xx_mac_if_set(phydev
, phydev
->interface
);
559 rc
= vsc85xx_edge_rate_cntl_set(phydev
, vsc8531
->rate_magic
);
563 rc
= vsc85xx_led_cntl_set(phydev
, 1, vsc8531
->led_1_mode
);
567 rc
= vsc85xx_led_cntl_set(phydev
, 0, vsc8531
->led_0_mode
);
571 rc
= genphy_config_init(phydev
);
576 static int vsc85xx_ack_interrupt(struct phy_device
*phydev
)
580 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
)
581 rc
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
583 return (rc
< 0) ? rc
: 0;
586 static int vsc85xx_config_intr(struct phy_device
*phydev
)
590 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
) {
591 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
,
592 MII_VSC85XX_INT_MASK_MASK
);
594 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
, 0);
597 rc
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
603 static int vsc85xx_config_aneg(struct phy_device
*phydev
)
607 rc
= vsc85xx_mdix_set(phydev
, phydev
->mdix_ctrl
);
611 return genphy_config_aneg(phydev
);
614 static int vsc85xx_read_status(struct phy_device
*phydev
)
618 rc
= vsc85xx_mdix_get(phydev
, &phydev
->mdix
);
622 return genphy_read_status(phydev
);
625 static int vsc85xx_probe(struct phy_device
*phydev
)
627 struct vsc8531_private
*vsc8531
;
631 rate_magic
= vsc85xx_edge_rate_magic_get(phydev
);
635 vsc8531
= devm_kzalloc(&phydev
->mdio
.dev
, sizeof(*vsc8531
), GFP_KERNEL
);
639 phydev
->priv
= vsc8531
;
641 vsc8531
->rate_magic
= rate_magic
;
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
);
648 vsc8531
->led_0_mode
= led_mode
;
650 led_mode
= vsc85xx_dt_led_mode_get(phydev
, "vsc8531,led-1-mode",
651 VSC8531_LINK_100_ACTIVITY
);
654 vsc8531
->led_1_mode
= led_mode
;
659 /* Microsemi VSC85xx PHYs */
660 static struct phy_driver vsc85xx_driver
[] = {
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
,
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
,
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
,
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
,
748 module_phy_driver(vsc85xx_driver
);
750 static 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, },
758 MODULE_DEVICE_TABLE(mdio
, vsc85xx_tbl
);
760 MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
761 MODULE_AUTHOR("Nagaraju Lakkaraju");
762 MODULE_LICENSE("Dual MIT/GPL");