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>
17 enum rgmii_rx_clock_delay
{
18 RGMII_RX_CLK_DELAY_0_2_NS
= 0,
19 RGMII_RX_CLK_DELAY_0_8_NS
= 1,
20 RGMII_RX_CLK_DELAY_1_1_NS
= 2,
21 RGMII_RX_CLK_DELAY_1_7_NS
= 3,
22 RGMII_RX_CLK_DELAY_2_0_NS
= 4,
23 RGMII_RX_CLK_DELAY_2_3_NS
= 5,
24 RGMII_RX_CLK_DELAY_2_6_NS
= 6,
25 RGMII_RX_CLK_DELAY_3_4_NS
= 7
28 /* Microsemi VSC85xx PHY registers */
29 /* IEEE 802. Std Registers */
30 #define MSCC_PHY_BYPASS_CONTROL 18
31 #define DISABLE_HP_AUTO_MDIX_MASK 0x0080
32 #define DISABLE_PAIR_SWAP_CORR_MASK 0x0020
33 #define DISABLE_POLARITY_CORR_MASK 0x0010
35 #define MSCC_PHY_EXT_PHY_CNTL_1 23
36 #define MAC_IF_SELECTION_MASK 0x1800
37 #define MAC_IF_SELECTION_GMII 0
38 #define MAC_IF_SELECTION_RMII 1
39 #define MAC_IF_SELECTION_RGMII 2
40 #define MAC_IF_SELECTION_POS 11
41 #define FAR_END_LOOPBACK_MODE_MASK 0x0008
43 #define MII_VSC85XX_INT_MASK 25
44 #define MII_VSC85XX_INT_MASK_MASK 0xa000
45 #define MII_VSC85XX_INT_MASK_WOL 0x0040
46 #define MII_VSC85XX_INT_STATUS 26
48 #define MSCC_PHY_WOL_MAC_CONTROL 27
49 #define EDGE_RATE_CNTL_POS 5
50 #define EDGE_RATE_CNTL_MASK 0x00E0
52 #define MSCC_PHY_DEV_AUX_CNTL 28
53 #define HP_AUTO_MDIX_X_OVER_IND_MASK 0x2000
55 #define MSCC_EXT_PAGE_ACCESS 31
56 #define MSCC_PHY_PAGE_STANDARD 0x0000 /* Standard registers */
57 #define MSCC_PHY_PAGE_EXTENDED 0x0001 /* Extended registers */
58 #define MSCC_PHY_PAGE_EXTENDED_2 0x0002 /* Extended reg - page 2 */
60 /* Extended Page 1 Registers */
61 #define MSCC_PHY_EXT_MODE_CNTL 19
62 #define FORCE_MDI_CROSSOVER_MASK 0x000C
63 #define FORCE_MDI_CROSSOVER_MDIX 0x000C
64 #define FORCE_MDI_CROSSOVER_MDI 0x0008
66 #define MSCC_PHY_ACTIPHY_CNTL 20
67 #define DOWNSHIFT_CNTL_MASK 0x001C
68 #define DOWNSHIFT_EN 0x0010
69 #define DOWNSHIFT_CNTL_POS 2
71 /* Extended Page 2 Registers */
72 #define MSCC_PHY_RGMII_CNTL 20
73 #define RGMII_RX_CLK_DELAY_MASK 0x0070
74 #define RGMII_RX_CLK_DELAY_POS 4
76 #define MSCC_PHY_WOL_LOWER_MAC_ADDR 21
77 #define MSCC_PHY_WOL_MID_MAC_ADDR 22
78 #define MSCC_PHY_WOL_UPPER_MAC_ADDR 23
79 #define MSCC_PHY_WOL_LOWER_PASSWD 24
80 #define MSCC_PHY_WOL_MID_PASSWD 25
81 #define MSCC_PHY_WOL_UPPER_PASSWD 26
83 #define MSCC_PHY_WOL_MAC_CONTROL 27
84 #define SECURE_ON_ENABLE 0x8000
85 #define SECURE_ON_PASSWD_LEN_4 0x4000
87 /* Microsemi PHY ID's */
88 #define PHY_ID_VSC8530 0x00070560
89 #define PHY_ID_VSC8531 0x00070570
90 #define PHY_ID_VSC8540 0x00070760
91 #define PHY_ID_VSC8541 0x00070770
93 #define MSCC_VDDMAC_1500 1500
94 #define MSCC_VDDMAC_1800 1800
95 #define MSCC_VDDMAC_2500 2500
96 #define MSCC_VDDMAC_3300 3300
98 #define DOWNSHIFT_COUNT_MAX 5
100 struct vsc8531_private
{
104 #ifdef CONFIG_OF_MDIO
105 struct vsc8531_edge_rate_table
{
110 static const struct vsc8531_edge_rate_table edge_table
[] = {
111 {MSCC_VDDMAC_3300
, { 0, 2, 4, 7, 10, 17, 29, 53} },
112 {MSCC_VDDMAC_2500
, { 0, 3, 6, 10, 14, 23, 37, 63} },
113 {MSCC_VDDMAC_1800
, { 0, 5, 9, 16, 23, 35, 52, 76} },
114 {MSCC_VDDMAC_1500
, { 0, 6, 14, 21, 29, 42, 58, 77} },
116 #endif /* CONFIG_OF_MDIO */
118 static int vsc85xx_phy_page_set(struct phy_device
*phydev
, u8 page
)
122 rc
= phy_write(phydev
, MSCC_EXT_PAGE_ACCESS
, page
);
126 static int vsc85xx_mdix_get(struct phy_device
*phydev
, u8
*mdix
)
130 reg_val
= phy_read(phydev
, MSCC_PHY_DEV_AUX_CNTL
);
131 if (reg_val
& HP_AUTO_MDIX_X_OVER_IND_MASK
)
132 *mdix
= ETH_TP_MDI_X
;
139 static int vsc85xx_mdix_set(struct phy_device
*phydev
, u8 mdix
)
144 reg_val
= phy_read(phydev
, MSCC_PHY_BYPASS_CONTROL
);
145 if ((mdix
== ETH_TP_MDI
) || (mdix
== ETH_TP_MDI_X
)) {
146 reg_val
|= (DISABLE_PAIR_SWAP_CORR_MASK
|
147 DISABLE_POLARITY_CORR_MASK
|
148 DISABLE_HP_AUTO_MDIX_MASK
);
150 reg_val
&= ~(DISABLE_PAIR_SWAP_CORR_MASK
|
151 DISABLE_POLARITY_CORR_MASK
|
152 DISABLE_HP_AUTO_MDIX_MASK
);
154 rc
= phy_write(phydev
, MSCC_PHY_BYPASS_CONTROL
, reg_val
);
158 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED
);
162 reg_val
= phy_read(phydev
, MSCC_PHY_EXT_MODE_CNTL
);
163 reg_val
&= ~(FORCE_MDI_CROSSOVER_MASK
);
164 if (mdix
== ETH_TP_MDI
)
165 reg_val
|= FORCE_MDI_CROSSOVER_MDI
;
166 else if (mdix
== ETH_TP_MDI_X
)
167 reg_val
|= FORCE_MDI_CROSSOVER_MDIX
;
168 rc
= phy_write(phydev
, MSCC_PHY_EXT_MODE_CNTL
, reg_val
);
172 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
176 return genphy_restart_aneg(phydev
);
179 static int vsc85xx_downshift_get(struct phy_device
*phydev
, u8
*count
)
184 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED
);
188 reg_val
= phy_read(phydev
, MSCC_PHY_ACTIPHY_CNTL
);
189 reg_val
&= DOWNSHIFT_CNTL_MASK
;
190 if (!(reg_val
& DOWNSHIFT_EN
))
191 *count
= DOWNSHIFT_DEV_DISABLE
;
193 *count
= ((reg_val
& ~DOWNSHIFT_EN
) >> DOWNSHIFT_CNTL_POS
) + 2;
194 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
200 static int vsc85xx_downshift_set(struct phy_device
*phydev
, u8 count
)
205 if (count
== DOWNSHIFT_DEV_DEFAULT_COUNT
) {
206 /* Default downshift count 3 (i.e. Bit3:2 = 0b01) */
207 count
= ((1 << DOWNSHIFT_CNTL_POS
) | DOWNSHIFT_EN
);
208 } else if (count
> DOWNSHIFT_COUNT_MAX
|| count
== 1) {
209 phydev_err(phydev
, "Downshift count should be 2,3,4 or 5\n");
212 /* Downshift count is either 2,3,4 or 5 */
213 count
= (((count
- 2) << DOWNSHIFT_CNTL_POS
) | DOWNSHIFT_EN
);
216 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED
);
220 reg_val
= phy_read(phydev
, MSCC_PHY_ACTIPHY_CNTL
);
221 reg_val
&= ~(DOWNSHIFT_CNTL_MASK
);
223 rc
= phy_write(phydev
, MSCC_PHY_ACTIPHY_CNTL
, reg_val
);
227 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
233 static int vsc85xx_wol_set(struct phy_device
*phydev
,
234 struct ethtool_wolinfo
*wol
)
239 u16 pwd
[3] = {0, 0, 0};
240 struct ethtool_wolinfo
*wol_conf
= wol
;
241 u8
*mac_addr
= phydev
->attached_dev
->dev_addr
;
243 mutex_lock(&phydev
->lock
);
244 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
248 if (wol
->wolopts
& WAKE_MAGIC
) {
249 /* Store the device address for the magic packet */
250 for (i
= 0; i
< ARRAY_SIZE(pwd
); i
++)
251 pwd
[i
] = mac_addr
[5 - (i
* 2 + 1)] << 8 |
253 phy_write(phydev
, MSCC_PHY_WOL_LOWER_MAC_ADDR
, pwd
[0]);
254 phy_write(phydev
, MSCC_PHY_WOL_MID_MAC_ADDR
, pwd
[1]);
255 phy_write(phydev
, MSCC_PHY_WOL_UPPER_MAC_ADDR
, pwd
[2]);
257 phy_write(phydev
, MSCC_PHY_WOL_LOWER_MAC_ADDR
, 0);
258 phy_write(phydev
, MSCC_PHY_WOL_MID_MAC_ADDR
, 0);
259 phy_write(phydev
, MSCC_PHY_WOL_UPPER_MAC_ADDR
, 0);
262 if (wol_conf
->wolopts
& WAKE_MAGICSECURE
) {
263 for (i
= 0; i
< ARRAY_SIZE(pwd
); i
++)
264 pwd
[i
] = wol_conf
->sopass
[5 - (i
* 2 + 1)] << 8 |
265 wol_conf
->sopass
[5 - i
* 2];
266 phy_write(phydev
, MSCC_PHY_WOL_LOWER_PASSWD
, pwd
[0]);
267 phy_write(phydev
, MSCC_PHY_WOL_MID_PASSWD
, pwd
[1]);
268 phy_write(phydev
, MSCC_PHY_WOL_UPPER_PASSWD
, pwd
[2]);
270 phy_write(phydev
, MSCC_PHY_WOL_LOWER_PASSWD
, 0);
271 phy_write(phydev
, MSCC_PHY_WOL_MID_PASSWD
, 0);
272 phy_write(phydev
, MSCC_PHY_WOL_UPPER_PASSWD
, 0);
275 reg_val
= phy_read(phydev
, MSCC_PHY_WOL_MAC_CONTROL
);
276 if (wol_conf
->wolopts
& WAKE_MAGICSECURE
)
277 reg_val
|= SECURE_ON_ENABLE
;
279 reg_val
&= ~SECURE_ON_ENABLE
;
280 phy_write(phydev
, MSCC_PHY_WOL_MAC_CONTROL
, reg_val
);
282 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
286 if (wol
->wolopts
& WAKE_MAGIC
) {
287 /* Enable the WOL interrupt */
288 reg_val
= phy_read(phydev
, MII_VSC85XX_INT_MASK
);
289 reg_val
|= MII_VSC85XX_INT_MASK_WOL
;
290 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
, reg_val
);
294 /* Disable the WOL interrupt */
295 reg_val
= phy_read(phydev
, MII_VSC85XX_INT_MASK
);
296 reg_val
&= (~MII_VSC85XX_INT_MASK_WOL
);
297 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
, reg_val
);
301 /* Clear WOL iterrupt status */
302 reg_val
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
305 mutex_unlock(&phydev
->lock
);
310 static void vsc85xx_wol_get(struct phy_device
*phydev
,
311 struct ethtool_wolinfo
*wol
)
316 u16 pwd
[3] = {0, 0, 0};
317 struct ethtool_wolinfo
*wol_conf
= wol
;
319 mutex_lock(&phydev
->lock
);
320 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
324 reg_val
= phy_read(phydev
, MSCC_PHY_WOL_MAC_CONTROL
);
325 if (reg_val
& SECURE_ON_ENABLE
)
326 wol_conf
->wolopts
|= WAKE_MAGICSECURE
;
327 if (wol_conf
->wolopts
& WAKE_MAGICSECURE
) {
328 pwd
[0] = phy_read(phydev
, MSCC_PHY_WOL_LOWER_PASSWD
);
329 pwd
[1] = phy_read(phydev
, MSCC_PHY_WOL_MID_PASSWD
);
330 pwd
[2] = phy_read(phydev
, MSCC_PHY_WOL_UPPER_PASSWD
);
331 for (i
= 0; i
< ARRAY_SIZE(pwd
); i
++) {
332 wol_conf
->sopass
[5 - i
* 2] = pwd
[i
] & 0x00ff;
333 wol_conf
->sopass
[5 - (i
* 2 + 1)] = (pwd
[i
] & 0xff00)
338 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
341 mutex_unlock(&phydev
->lock
);
344 #ifdef CONFIG_OF_MDIO
345 static int vsc85xx_edge_rate_magic_get(struct phy_device
*phydev
)
350 struct device
*dev
= &phydev
->mdio
.dev
;
351 struct device_node
*of_node
= dev
->of_node
;
352 u8 sd_array_size
= ARRAY_SIZE(edge_table
[0].slowdown
);
357 rc
= of_property_read_u16(of_node
, "vsc8531,vddmac", &vdd
);
359 vdd
= MSCC_VDDMAC_3300
;
361 rc
= of_property_read_u8(of_node
, "vsc8531,edge-slowdown", &sd
);
365 for (i
= 0; i
< ARRAY_SIZE(edge_table
); i
++)
366 if (edge_table
[i
].vddmac
== vdd
)
367 for (j
= 0; j
< sd_array_size
; j
++)
368 if (edge_table
[i
].slowdown
[j
] == sd
)
369 return (sd_array_size
- j
- 1);
374 static int vsc85xx_edge_rate_magic_get(struct phy_device
*phydev
)
378 #endif /* CONFIG_OF_MDIO */
380 static int vsc85xx_edge_rate_cntl_set(struct phy_device
*phydev
, u8 edge_rate
)
385 mutex_lock(&phydev
->lock
);
386 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
389 reg_val
= phy_read(phydev
, MSCC_PHY_WOL_MAC_CONTROL
);
390 reg_val
&= ~(EDGE_RATE_CNTL_MASK
);
391 reg_val
|= (edge_rate
<< EDGE_RATE_CNTL_POS
);
392 rc
= phy_write(phydev
, MSCC_PHY_WOL_MAC_CONTROL
, reg_val
);
395 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
398 mutex_unlock(&phydev
->lock
);
403 static int vsc85xx_mac_if_set(struct phy_device
*phydev
,
404 phy_interface_t interface
)
409 mutex_lock(&phydev
->lock
);
410 reg_val
= phy_read(phydev
, MSCC_PHY_EXT_PHY_CNTL_1
);
411 reg_val
&= ~(MAC_IF_SELECTION_MASK
);
413 case PHY_INTERFACE_MODE_RGMII
:
414 reg_val
|= (MAC_IF_SELECTION_RGMII
<< MAC_IF_SELECTION_POS
);
416 case PHY_INTERFACE_MODE_RMII
:
417 reg_val
|= (MAC_IF_SELECTION_RMII
<< MAC_IF_SELECTION_POS
);
419 case PHY_INTERFACE_MODE_MII
:
420 case PHY_INTERFACE_MODE_GMII
:
421 reg_val
|= (MAC_IF_SELECTION_GMII
<< MAC_IF_SELECTION_POS
);
427 rc
= phy_write(phydev
, MSCC_PHY_EXT_PHY_CNTL_1
, reg_val
);
431 rc
= genphy_soft_reset(phydev
);
434 mutex_unlock(&phydev
->lock
);
439 static int vsc85xx_default_config(struct phy_device
*phydev
)
444 phydev
->mdix_ctrl
= ETH_TP_MDI_AUTO
;
445 mutex_lock(&phydev
->lock
);
446 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_EXTENDED_2
);
450 reg_val
= phy_read(phydev
, MSCC_PHY_RGMII_CNTL
);
451 reg_val
&= ~(RGMII_RX_CLK_DELAY_MASK
);
452 reg_val
|= (RGMII_RX_CLK_DELAY_1_1_NS
<< RGMII_RX_CLK_DELAY_POS
);
453 phy_write(phydev
, MSCC_PHY_RGMII_CNTL
, reg_val
);
454 rc
= vsc85xx_phy_page_set(phydev
, MSCC_PHY_PAGE_STANDARD
);
457 mutex_unlock(&phydev
->lock
);
462 static int vsc85xx_get_tunable(struct phy_device
*phydev
,
463 struct ethtool_tunable
*tuna
, void *data
)
466 case ETHTOOL_PHY_DOWNSHIFT
:
467 return vsc85xx_downshift_get(phydev
, (u8
*)data
);
473 static int vsc85xx_set_tunable(struct phy_device
*phydev
,
474 struct ethtool_tunable
*tuna
,
478 case ETHTOOL_PHY_DOWNSHIFT
:
479 return vsc85xx_downshift_set(phydev
, *(u8
*)data
);
485 static int vsc85xx_config_init(struct phy_device
*phydev
)
488 struct vsc8531_private
*vsc8531
= phydev
->priv
;
490 rc
= vsc85xx_default_config(phydev
);
494 rc
= vsc85xx_mac_if_set(phydev
, phydev
->interface
);
498 rc
= vsc85xx_edge_rate_cntl_set(phydev
, vsc8531
->rate_magic
);
502 rc
= genphy_config_init(phydev
);
507 static int vsc85xx_ack_interrupt(struct phy_device
*phydev
)
511 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
)
512 rc
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
514 return (rc
< 0) ? rc
: 0;
517 static int vsc85xx_config_intr(struct phy_device
*phydev
)
521 if (phydev
->interrupts
== PHY_INTERRUPT_ENABLED
) {
522 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
,
523 MII_VSC85XX_INT_MASK_MASK
);
525 rc
= phy_write(phydev
, MII_VSC85XX_INT_MASK
, 0);
528 rc
= phy_read(phydev
, MII_VSC85XX_INT_STATUS
);
534 static int vsc85xx_config_aneg(struct phy_device
*phydev
)
538 rc
= vsc85xx_mdix_set(phydev
, phydev
->mdix_ctrl
);
542 return genphy_config_aneg(phydev
);
545 static int vsc85xx_read_status(struct phy_device
*phydev
)
549 rc
= vsc85xx_mdix_get(phydev
, &phydev
->mdix
);
553 return genphy_read_status(phydev
);
556 static int vsc85xx_probe(struct phy_device
*phydev
)
559 struct vsc8531_private
*vsc8531
;
561 rate_magic
= vsc85xx_edge_rate_magic_get(phydev
);
565 vsc8531
= devm_kzalloc(&phydev
->mdio
.dev
, sizeof(*vsc8531
), GFP_KERNEL
);
569 phydev
->priv
= vsc8531
;
571 vsc8531
->rate_magic
= rate_magic
;
576 /* Microsemi VSC85xx PHYs */
577 static struct phy_driver vsc85xx_driver
[] = {
579 .phy_id
= PHY_ID_VSC8530
,
580 .name
= "Microsemi FE VSC8530",
581 .phy_id_mask
= 0xfffffff0,
582 .features
= PHY_BASIC_FEATURES
,
583 .flags
= PHY_HAS_INTERRUPT
,
584 .soft_reset
= &genphy_soft_reset
,
585 .config_init
= &vsc85xx_config_init
,
586 .config_aneg
= &vsc85xx_config_aneg
,
587 .aneg_done
= &genphy_aneg_done
,
588 .read_status
= &vsc85xx_read_status
,
589 .ack_interrupt
= &vsc85xx_ack_interrupt
,
590 .config_intr
= &vsc85xx_config_intr
,
591 .suspend
= &genphy_suspend
,
592 .resume
= &genphy_resume
,
593 .probe
= &vsc85xx_probe
,
594 .set_wol
= &vsc85xx_wol_set
,
595 .get_wol
= &vsc85xx_wol_get
,
596 .get_tunable
= &vsc85xx_get_tunable
,
597 .set_tunable
= &vsc85xx_set_tunable
,
600 .phy_id
= PHY_ID_VSC8531
,
601 .name
= "Microsemi VSC8531",
602 .phy_id_mask
= 0xfffffff0,
603 .features
= PHY_GBIT_FEATURES
,
604 .flags
= PHY_HAS_INTERRUPT
,
605 .soft_reset
= &genphy_soft_reset
,
606 .config_init
= &vsc85xx_config_init
,
607 .config_aneg
= &vsc85xx_config_aneg
,
608 .aneg_done
= &genphy_aneg_done
,
609 .read_status
= &vsc85xx_read_status
,
610 .ack_interrupt
= &vsc85xx_ack_interrupt
,
611 .config_intr
= &vsc85xx_config_intr
,
612 .suspend
= &genphy_suspend
,
613 .resume
= &genphy_resume
,
614 .probe
= &vsc85xx_probe
,
615 .set_wol
= &vsc85xx_wol_set
,
616 .get_wol
= &vsc85xx_wol_get
,
617 .get_tunable
= &vsc85xx_get_tunable
,
618 .set_tunable
= &vsc85xx_set_tunable
,
621 .phy_id
= PHY_ID_VSC8540
,
622 .name
= "Microsemi FE VSC8540 SyncE",
623 .phy_id_mask
= 0xfffffff0,
624 .features
= PHY_BASIC_FEATURES
,
625 .flags
= PHY_HAS_INTERRUPT
,
626 .soft_reset
= &genphy_soft_reset
,
627 .config_init
= &vsc85xx_config_init
,
628 .config_aneg
= &vsc85xx_config_aneg
,
629 .aneg_done
= &genphy_aneg_done
,
630 .read_status
= &vsc85xx_read_status
,
631 .ack_interrupt
= &vsc85xx_ack_interrupt
,
632 .config_intr
= &vsc85xx_config_intr
,
633 .suspend
= &genphy_suspend
,
634 .resume
= &genphy_resume
,
635 .probe
= &vsc85xx_probe
,
636 .set_wol
= &vsc85xx_wol_set
,
637 .get_wol
= &vsc85xx_wol_get
,
638 .get_tunable
= &vsc85xx_get_tunable
,
639 .set_tunable
= &vsc85xx_set_tunable
,
642 .phy_id
= PHY_ID_VSC8541
,
643 .name
= "Microsemi VSC8541 SyncE",
644 .phy_id_mask
= 0xfffffff0,
645 .features
= PHY_GBIT_FEATURES
,
646 .flags
= PHY_HAS_INTERRUPT
,
647 .soft_reset
= &genphy_soft_reset
,
648 .config_init
= &vsc85xx_config_init
,
649 .config_aneg
= &vsc85xx_config_aneg
,
650 .aneg_done
= &genphy_aneg_done
,
651 .read_status
= &vsc85xx_read_status
,
652 .ack_interrupt
= &vsc85xx_ack_interrupt
,
653 .config_intr
= &vsc85xx_config_intr
,
654 .suspend
= &genphy_suspend
,
655 .resume
= &genphy_resume
,
656 .probe
= &vsc85xx_probe
,
657 .set_wol
= &vsc85xx_wol_set
,
658 .get_wol
= &vsc85xx_wol_get
,
659 .get_tunable
= &vsc85xx_get_tunable
,
660 .set_tunable
= &vsc85xx_set_tunable
,
665 module_phy_driver(vsc85xx_driver
);
667 static struct mdio_device_id __maybe_unused vsc85xx_tbl
[] = {
668 { PHY_ID_VSC8530
, 0xfffffff0, },
669 { PHY_ID_VSC8531
, 0xfffffff0, },
670 { PHY_ID_VSC8540
, 0xfffffff0, },
671 { PHY_ID_VSC8541
, 0xfffffff0, },
675 MODULE_DEVICE_TABLE(mdio
, vsc85xx_tbl
);
677 MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
678 MODULE_AUTHOR("Nagaraju Lakkaraju");
679 MODULE_LICENSE("Dual MIT/GPL");