GNU Linux-libre 4.14.290-gnu1
[releases.git] / drivers / net / phy / mscc.c
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
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
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
106 struct vsc8531_private {
107         int rate_magic;
108         u8 led_0_mode;
109         u8 led_1_mode;
110 };
111
112 #ifdef CONFIG_OF_MDIO
113 struct vsc8531_edge_rate_table {
114         u32 vddmac;
115         u32 slowdown[8];
116 };
117
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} },
123 };
124 #endif /* CONFIG_OF_MDIO */
125
126 static int vsc85xx_phy_page_set(struct phy_device *phydev, u8 page)
127 {
128         int rc;
129
130         rc = phy_write(phydev, MSCC_EXT_PAGE_ACCESS, page);
131         return rc;
132 }
133
134 static 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
157 static 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
170 static 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
210 static 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
227 out:
228         return rc;
229 }
230
231 static 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
260 out:
261         return rc;
262 }
263
264 static 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
335 out_unlock:
336         mutex_unlock(&phydev->lock);
337
338         return rc;
339 }
340
341 static 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
371 out_unlock:
372         mutex_unlock(&phydev->lock);
373 }
374
375 #ifdef CONFIG_OF_MDIO
376 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
377 {
378         u32 vdd, sd;
379         int rc, i, j;
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);
383
384         if (!of_node)
385                 return -ENODEV;
386
387         rc = of_property_read_u32(of_node, "vsc8531,vddmac", &vdd);
388         if (rc != 0)
389                 vdd = MSCC_VDDMAC_3300;
390
391         rc = of_property_read_u32(of_node, "vsc8531,edge-slowdown", &sd);
392         if (rc != 0)
393                 sd = 0;
394
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);
400
401         return -EINVAL;
402 }
403
404 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
405                                    char *led,
406                                    u8 default_mode)
407 {
408         struct device *dev = &phydev->mdio.dev;
409         struct device_node *of_node = dev->of_node;
410         u8 led_mode;
411         int err;
412
413         if (!of_node)
414                 return -ENODEV;
415
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);
420                 return -EINVAL;
421         }
422
423         return led_mode;
424 }
425
426 #else
427 static int vsc85xx_edge_rate_magic_get(struct phy_device *phydev)
428 {
429         return 0;
430 }
431
432 static int vsc85xx_dt_led_mode_get(struct phy_device *phydev,
433                                    char *led,
434                                    u8 default_mode)
435 {
436         return default_mode;
437 }
438 #endif /* CONFIG_OF_MDIO */
439
440 static int vsc85xx_edge_rate_cntl_set(struct phy_device *phydev, u8 edge_rate)
441 {
442         int rc;
443         u16 reg_val;
444
445         mutex_lock(&phydev->lock);
446         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_EXTENDED_2);
447         if (rc != 0)
448                 goto out_unlock;
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);
453         if (rc != 0)
454                 goto out_unlock;
455         rc = vsc85xx_phy_page_set(phydev, MSCC_PHY_PAGE_STANDARD);
456
457 out_unlock:
458         mutex_unlock(&phydev->lock);
459
460         return rc;
461 }
462
463 static int vsc85xx_mac_if_set(struct phy_device *phydev,
464                               phy_interface_t interface)
465 {
466         int rc;
467         u16 reg_val;
468
469         mutex_lock(&phydev->lock);
470         reg_val = phy_read(phydev, MSCC_PHY_EXT_PHY_CNTL_1);
471         reg_val &= ~(MAC_IF_SELECTION_MASK);
472         switch (interface) {
473         case PHY_INTERFACE_MODE_RGMII:
474                 reg_val |= (MAC_IF_SELECTION_RGMII << MAC_IF_SELECTION_POS);
475                 break;
476         case PHY_INTERFACE_MODE_RMII:
477                 reg_val |= (MAC_IF_SELECTION_RMII << MAC_IF_SELECTION_POS);
478                 break;
479         case PHY_INTERFACE_MODE_MII:
480         case PHY_INTERFACE_MODE_GMII:
481                 reg_val |= (MAC_IF_SELECTION_GMII << MAC_IF_SELECTION_POS);
482                 break;
483         default:
484                 rc = -EINVAL;
485                 goto out_unlock;
486         }
487         rc = phy_write(phydev, MSCC_PHY_EXT_PHY_CNTL_1, reg_val);
488         if (rc != 0)
489                 goto out_unlock;
490
491         rc = genphy_soft_reset(phydev);
492
493 out_unlock:
494         mutex_unlock(&phydev->lock);
495
496         return rc;
497 }
498
499 static int vsc85xx_default_config(struct phy_device *phydev)
500 {
501         int rc;
502         u16 reg_val;
503
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);
507         if (rc != 0)
508                 goto out_unlock;
509
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);
515
516 out_unlock:
517         mutex_unlock(&phydev->lock);
518
519         return rc;
520 }
521
522 static int vsc85xx_get_tunable(struct phy_device *phydev,
523                                struct ethtool_tunable *tuna, void *data)
524 {
525         switch (tuna->id) {
526         case ETHTOOL_PHY_DOWNSHIFT:
527                 return vsc85xx_downshift_get(phydev, (u8 *)data);
528         default:
529                 return -EINVAL;
530         }
531 }
532
533 static int vsc85xx_set_tunable(struct phy_device *phydev,
534                                struct ethtool_tunable *tuna,
535                                const void *data)
536 {
537         switch (tuna->id) {
538         case ETHTOOL_PHY_DOWNSHIFT:
539                 return vsc85xx_downshift_set(phydev, *(u8 *)data);
540         default:
541                 return -EINVAL;
542         }
543 }
544
545 static int vsc85xx_config_init(struct phy_device *phydev)
546 {
547         int rc;
548         struct vsc8531_private *vsc8531 = phydev->priv;
549
550         rc = vsc85xx_default_config(phydev);
551         if (rc)
552                 return rc;
553
554         rc = vsc85xx_mac_if_set(phydev, phydev->interface);
555         if (rc)
556                 return rc;
557
558         rc = vsc85xx_edge_rate_cntl_set(phydev, vsc8531->rate_magic);
559         if (rc)
560                 return rc;
561
562         rc = vsc85xx_led_cntl_set(phydev, 1, vsc8531->led_1_mode);
563         if (rc)
564                 return rc;
565
566         rc = vsc85xx_led_cntl_set(phydev, 0, vsc8531->led_0_mode);
567         if (rc)
568                 return rc;
569
570         rc = genphy_config_init(phydev);
571
572         return rc;
573 }
574
575 static int vsc85xx_ack_interrupt(struct phy_device *phydev)
576 {
577         int rc = 0;
578
579         if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
580                 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
581
582         return (rc < 0) ? rc : 0;
583 }
584
585 static int vsc85xx_config_intr(struct phy_device *phydev)
586 {
587         int rc;
588
589         if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
590                 rc = phy_write(phydev, MII_VSC85XX_INT_MASK,
591                                MII_VSC85XX_INT_MASK_MASK);
592         } else {
593                 rc = phy_write(phydev, MII_VSC85XX_INT_MASK, 0);
594                 if (rc < 0)
595                         return rc;
596                 rc = phy_read(phydev, MII_VSC85XX_INT_STATUS);
597         }
598
599         return rc;
600 }
601
602 static int vsc85xx_config_aneg(struct phy_device *phydev)
603 {
604         int rc;
605
606         rc = vsc85xx_mdix_set(phydev, phydev->mdix_ctrl);
607         if (rc < 0)
608                 return rc;
609
610         return genphy_config_aneg(phydev);
611 }
612
613 static int vsc85xx_read_status(struct phy_device *phydev)
614 {
615         int rc;
616
617         rc = vsc85xx_mdix_get(phydev, &phydev->mdix);
618         if (rc < 0)
619                 return rc;
620
621         return genphy_read_status(phydev);
622 }
623
624 static int vsc85xx_probe(struct phy_device *phydev)
625 {
626         struct vsc8531_private *vsc8531;
627         int rate_magic;
628         int led_mode;
629
630         rate_magic = vsc85xx_edge_rate_magic_get(phydev);
631         if (rate_magic < 0)
632                 return rate_magic;
633
634         vsc8531 = devm_kzalloc(&phydev->mdio.dev, sizeof(*vsc8531), GFP_KERNEL);
635         if (!vsc8531)
636                 return -ENOMEM;
637
638         phydev->priv = vsc8531;
639
640         vsc8531->rate_magic = rate_magic;
641
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);
645         if (led_mode < 0)
646                 return led_mode;
647         vsc8531->led_0_mode = led_mode;
648
649         led_mode = vsc85xx_dt_led_mode_get(phydev, "vsc8531,led-1-mode",
650                                            VSC8531_LINK_100_ACTIVITY);
651         if (led_mode < 0)
652                 return led_mode;
653         vsc8531->led_1_mode = led_mode;
654
655         return 0;
656 }
657
658 /* Microsemi VSC85xx PHYs */
659 static struct phy_driver vsc85xx_driver[] = {
660 {
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,
680 },
681 {
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,
701 },
702 {
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,
722 },
723 {
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,
743 }
744
745 };
746
747 module_phy_driver(vsc85xx_driver);
748
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, },
754         { }
755 };
756
757 MODULE_DEVICE_TABLE(mdio, vsc85xx_tbl);
758
759 MODULE_DESCRIPTION("Microsemi VSC85xx PHY driver");
760 MODULE_AUTHOR("Nagaraju Lakkaraju");
761 MODULE_LICENSE("Dual MIT/GPL");