1
2
3
4
5
6
7
8
9#include <linux/module.h>
10#include <linux/bitfield.h>
11#include <linux/phy.h>
12#include <linux/netdevice.h>
13
14
15#define PHY_ID_GPYx15B_MASK 0xFFFFFFFC
16#define PHY_ID_GPY21xB_MASK 0xFFFFFFF9
17#define PHY_ID_GPY2xx 0x67C9DC00
18#define PHY_ID_GPY115B 0x67C9DF00
19#define PHY_ID_GPY115C 0x67C9DF10
20#define PHY_ID_GPY211B 0x67C9DE08
21#define PHY_ID_GPY211C 0x67C9DE10
22#define PHY_ID_GPY212B 0x67C9DE09
23#define PHY_ID_GPY212C 0x67C9DE20
24#define PHY_ID_GPY215B 0x67C9DF04
25#define PHY_ID_GPY215C 0x67C9DF20
26#define PHY_ID_GPY241B 0x67C9DE40
27#define PHY_ID_GPY241BM 0x67C9DE80
28#define PHY_ID_GPY245B 0x67C9DEC0
29
30#define PHY_MIISTAT 0x18
31#define PHY_IMASK 0x19
32#define PHY_ISTAT 0x1A
33#define PHY_FWV 0x1E
34
35#define PHY_MIISTAT_SPD_MASK GENMASK(2, 0)
36#define PHY_MIISTAT_DPX BIT(3)
37#define PHY_MIISTAT_LS BIT(10)
38
39#define PHY_MIISTAT_SPD_10 0
40#define PHY_MIISTAT_SPD_100 1
41#define PHY_MIISTAT_SPD_1000 2
42#define PHY_MIISTAT_SPD_2500 4
43
44#define PHY_IMASK_WOL BIT(15)
45#define PHY_IMASK_ANC BIT(10)
46#define PHY_IMASK_ADSC BIT(5)
47#define PHY_IMASK_DXMC BIT(2)
48#define PHY_IMASK_LSPC BIT(1)
49#define PHY_IMASK_LSTC BIT(0)
50#define PHY_IMASK_MASK (PHY_IMASK_LSTC | \
51 PHY_IMASK_LSPC | \
52 PHY_IMASK_DXMC | \
53 PHY_IMASK_ADSC | \
54 PHY_IMASK_ANC)
55
56#define PHY_FWV_REL_MASK BIT(15)
57#define PHY_FWV_TYPE_MASK GENMASK(11, 8)
58#define PHY_FWV_MINOR_MASK GENMASK(7, 0)
59
60
61#define VSPEC1_SGMII_CTRL 0x08
62#define VSPEC1_SGMII_CTRL_ANEN BIT(12)
63#define VSPEC1_SGMII_CTRL_ANRS BIT(9)
64#define VSPEC1_SGMII_ANEN_ANRS (VSPEC1_SGMII_CTRL_ANEN | \
65 VSPEC1_SGMII_CTRL_ANRS)
66
67
68#define VPSPEC2_WOL_CTL 0x0E06
69#define VPSPEC2_WOL_AD01 0x0E08
70#define VPSPEC2_WOL_AD23 0x0E09
71#define VPSPEC2_WOL_AD45 0x0E0A
72#define WOL_EN BIT(0)
73
74static const struct {
75 int type;
76 int minor;
77} ver_need_sgmii_reaneg[] = {
78 {7, 0x6D},
79 {8, 0x6D},
80 {9, 0x73},
81};
82
83static int gpy_config_init(struct phy_device *phydev)
84{
85 int ret;
86
87
88 ret = phy_write(phydev, PHY_IMASK, 0);
89 if (ret)
90 return ret;
91
92
93 ret = phy_read(phydev, PHY_ISTAT);
94 return ret < 0 ? ret : 0;
95}
96
97static int gpy_probe(struct phy_device *phydev)
98{
99 int ret;
100
101 if (!phydev->is_c45) {
102 ret = phy_get_c45_ids(phydev);
103 if (ret < 0)
104 return ret;
105 }
106
107
108 ret = phy_read(phydev, PHY_FWV);
109 if (ret < 0)
110 return ret;
111
112 phydev_info(phydev, "Firmware Version: 0x%04X (%s)\n", ret,
113 (ret & PHY_FWV_REL_MASK) ? "release" : "test");
114
115 return 0;
116}
117
118static bool gpy_sgmii_need_reaneg(struct phy_device *phydev)
119{
120 int fw_ver, fw_type, fw_minor;
121 size_t i;
122
123 fw_ver = phy_read(phydev, PHY_FWV);
124 if (fw_ver < 0)
125 return true;
126
127 fw_type = FIELD_GET(PHY_FWV_TYPE_MASK, fw_ver);
128 fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, fw_ver);
129
130 for (i = 0; i < ARRAY_SIZE(ver_need_sgmii_reaneg); i++) {
131 if (fw_type != ver_need_sgmii_reaneg[i].type)
132 continue;
133 if (fw_minor < ver_need_sgmii_reaneg[i].minor)
134 return true;
135 break;
136 }
137
138 return false;
139}
140
141static bool gpy_2500basex_chk(struct phy_device *phydev)
142{
143 int ret;
144
145 ret = phy_read(phydev, PHY_MIISTAT);
146 if (ret < 0) {
147 phydev_err(phydev, "Error: MDIO register access failed: %d\n",
148 ret);
149 return false;
150 }
151
152 if (!(ret & PHY_MIISTAT_LS) ||
153 FIELD_GET(PHY_MIISTAT_SPD_MASK, ret) != PHY_MIISTAT_SPD_2500)
154 return false;
155
156 phydev->speed = SPEED_2500;
157 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
158 phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
159 VSPEC1_SGMII_CTRL_ANEN, 0);
160 return true;
161}
162
163static bool gpy_sgmii_aneg_en(struct phy_device *phydev)
164{
165 int ret;
166
167 ret = phy_read_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL);
168 if (ret < 0) {
169 phydev_err(phydev, "Error: MMD register access failed: %d\n",
170 ret);
171 return true;
172 }
173
174 return (ret & VSPEC1_SGMII_CTRL_ANEN) ? true : false;
175}
176
177static int gpy_config_aneg(struct phy_device *phydev)
178{
179 bool changed = false;
180 u32 adv;
181 int ret;
182
183 if (phydev->autoneg == AUTONEG_DISABLE) {
184
185
186
187 return phydev->duplex != DUPLEX_FULL
188 ? genphy_setup_forced(phydev)
189 : genphy_c45_pma_setup_forced(phydev);
190 }
191
192 ret = genphy_c45_an_config_aneg(phydev);
193 if (ret < 0)
194 return ret;
195 if (ret > 0)
196 changed = true;
197
198 adv = linkmode_adv_to_mii_ctrl1000_t(phydev->advertising);
199 ret = phy_modify_changed(phydev, MII_CTRL1000,
200 ADVERTISE_1000FULL | ADVERTISE_1000HALF,
201 adv);
202 if (ret < 0)
203 return ret;
204 if (ret > 0)
205 changed = true;
206
207 ret = genphy_c45_check_and_restart_aneg(phydev, changed);
208 if (ret < 0)
209 return ret;
210
211 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
212 phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
213 return 0;
214
215
216
217
218 if (!gpy_sgmii_need_reaneg(phydev) || gpy_2500basex_chk(phydev) ||
219 !gpy_sgmii_aneg_en(phydev))
220 return 0;
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243 if (phydev->state != PHY_UP)
244 return 0;
245
246 ret = phy_read_poll_timeout(phydev, MII_BMSR, ret, ret & BMSR_LSTATUS,
247 20000, 4000000, false);
248 if (ret == -ETIMEDOUT)
249 return 0;
250 else if (ret < 0)
251 return ret;
252
253
254 return phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
255 VSPEC1_SGMII_CTRL_ANRS, VSPEC1_SGMII_CTRL_ANRS);
256}
257
258static void gpy_update_interface(struct phy_device *phydev)
259{
260 int ret;
261
262
263 if (phydev->interface == PHY_INTERFACE_MODE_USXGMII ||
264 phydev->interface == PHY_INTERFACE_MODE_INTERNAL)
265 return;
266
267
268
269
270 switch (phydev->speed) {
271 case SPEED_2500:
272 phydev->interface = PHY_INTERFACE_MODE_2500BASEX;
273 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
274 VSPEC1_SGMII_CTRL_ANEN, 0);
275 if (ret < 0)
276 phydev_err(phydev,
277 "Error: Disable of SGMII ANEG failed: %d\n",
278 ret);
279 break;
280 case SPEED_1000:
281 case SPEED_100:
282 case SPEED_10:
283 phydev->interface = PHY_INTERFACE_MODE_SGMII;
284 if (gpy_sgmii_aneg_en(phydev))
285 break;
286
287
288
289 ret = phy_modify_mmd(phydev, MDIO_MMD_VEND1, VSPEC1_SGMII_CTRL,
290 VSPEC1_SGMII_ANEN_ANRS,
291 VSPEC1_SGMII_ANEN_ANRS);
292 if (ret < 0)
293 phydev_err(phydev,
294 "Error: Enable of SGMII ANEG failed: %d\n",
295 ret);
296 break;
297 }
298}
299
300static int gpy_read_status(struct phy_device *phydev)
301{
302 int ret;
303
304 ret = genphy_update_link(phydev);
305 if (ret)
306 return ret;
307
308 phydev->speed = SPEED_UNKNOWN;
309 phydev->duplex = DUPLEX_UNKNOWN;
310 phydev->pause = 0;
311 phydev->asym_pause = 0;
312
313 if (phydev->autoneg == AUTONEG_ENABLE && phydev->autoneg_complete) {
314 ret = genphy_c45_read_lpa(phydev);
315 if (ret < 0)
316 return ret;
317
318
319 ret = phy_read(phydev, MII_STAT1000);
320 if (ret < 0)
321 return ret;
322 mii_stat1000_mod_linkmode_lpa_t(phydev->lp_advertising, ret);
323 } else if (phydev->autoneg == AUTONEG_DISABLE) {
324 linkmode_zero(phydev->lp_advertising);
325 }
326
327 ret = phy_read(phydev, PHY_MIISTAT);
328 if (ret < 0)
329 return ret;
330
331 phydev->link = (ret & PHY_MIISTAT_LS) ? 1 : 0;
332 phydev->duplex = (ret & PHY_MIISTAT_DPX) ? DUPLEX_FULL : DUPLEX_HALF;
333 switch (FIELD_GET(PHY_MIISTAT_SPD_MASK, ret)) {
334 case PHY_MIISTAT_SPD_10:
335 phydev->speed = SPEED_10;
336 break;
337 case PHY_MIISTAT_SPD_100:
338 phydev->speed = SPEED_100;
339 break;
340 case PHY_MIISTAT_SPD_1000:
341 phydev->speed = SPEED_1000;
342 break;
343 case PHY_MIISTAT_SPD_2500:
344 phydev->speed = SPEED_2500;
345 break;
346 }
347
348 if (phydev->link)
349 gpy_update_interface(phydev);
350
351 return 0;
352}
353
354static int gpy_config_intr(struct phy_device *phydev)
355{
356 u16 mask = 0;
357
358 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
359 mask = PHY_IMASK_MASK;
360
361 return phy_write(phydev, PHY_IMASK, mask);
362}
363
364static irqreturn_t gpy_handle_interrupt(struct phy_device *phydev)
365{
366 int reg;
367
368 reg = phy_read(phydev, PHY_ISTAT);
369 if (reg < 0) {
370 phy_error(phydev);
371 return IRQ_NONE;
372 }
373
374 if (!(reg & PHY_IMASK_MASK))
375 return IRQ_NONE;
376
377 phy_trigger_machine(phydev);
378
379 return IRQ_HANDLED;
380}
381
382static int gpy_set_wol(struct phy_device *phydev,
383 struct ethtool_wolinfo *wol)
384{
385 struct net_device *attach_dev = phydev->attached_dev;
386 int ret;
387
388 if (wol->wolopts & WAKE_MAGIC) {
389
390
391
392
393
394 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
395 VPSPEC2_WOL_AD45,
396 ((attach_dev->dev_addr[0] << 8) |
397 attach_dev->dev_addr[1]));
398 if (ret < 0)
399 return ret;
400
401 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
402 VPSPEC2_WOL_AD23,
403 ((attach_dev->dev_addr[2] << 8) |
404 attach_dev->dev_addr[3]));
405 if (ret < 0)
406 return ret;
407
408 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
409 VPSPEC2_WOL_AD01,
410 ((attach_dev->dev_addr[4] << 8) |
411 attach_dev->dev_addr[5]));
412 if (ret < 0)
413 return ret;
414
415
416 ret = phy_write(phydev, PHY_IMASK, PHY_IMASK_WOL);
417 if (ret < 0)
418 return ret;
419
420
421 ret = phy_set_bits_mmd(phydev, MDIO_MMD_VEND2,
422 VPSPEC2_WOL_CTL,
423 WOL_EN);
424 if (ret < 0)
425 return ret;
426
427
428
429
430 ret = phy_read(phydev, PHY_ISTAT);
431 if (ret < 0)
432 return ret;
433 } else {
434
435 ret = phy_clear_bits_mmd(phydev, MDIO_MMD_VEND2,
436 VPSPEC2_WOL_CTL,
437 WOL_EN);
438 if (ret < 0)
439 return ret;
440 }
441
442 if (wol->wolopts & WAKE_PHY) {
443
444 ret = phy_set_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
445 if (ret < 0)
446 return ret;
447
448
449 ret = phy_read(phydev, PHY_ISTAT);
450 if (ret < 0)
451 return ret;
452
453 if (ret & (PHY_IMASK_MASK & ~PHY_IMASK_LSTC))
454 phy_trigger_machine(phydev);
455
456 return 0;
457 }
458
459
460 return phy_clear_bits(phydev, PHY_IMASK, PHY_IMASK_LSTC);
461}
462
463static void gpy_get_wol(struct phy_device *phydev,
464 struct ethtool_wolinfo *wol)
465{
466 int ret;
467
468 wol->supported = WAKE_MAGIC | WAKE_PHY;
469 wol->wolopts = 0;
470
471 ret = phy_read_mmd(phydev, MDIO_MMD_VEND2, VPSPEC2_WOL_CTL);
472 if (ret & WOL_EN)
473 wol->wolopts |= WAKE_MAGIC;
474
475 ret = phy_read(phydev, PHY_IMASK);
476 if (ret & PHY_IMASK_LSTC)
477 wol->wolopts |= WAKE_PHY;
478}
479
480static int gpy_loopback(struct phy_device *phydev, bool enable)
481{
482 int ret;
483
484 ret = phy_modify(phydev, MII_BMCR, BMCR_LOOPBACK,
485 enable ? BMCR_LOOPBACK : 0);
486 if (!ret) {
487
488
489
490 msleep(100);
491 }
492
493 return ret;
494}
495
496static int gpy115_loopback(struct phy_device *phydev, bool enable)
497{
498 int ret;
499 int fw_minor;
500
501 if (enable)
502 return gpy_loopback(phydev, enable);
503
504 ret = phy_read(phydev, PHY_FWV);
505 if (ret < 0)
506 return ret;
507
508 fw_minor = FIELD_GET(PHY_FWV_MINOR_MASK, ret);
509 if (fw_minor > 0x0076)
510 return gpy_loopback(phydev, 0);
511
512 return genphy_soft_reset(phydev);
513}
514
515static struct phy_driver gpy_drivers[] = {
516 {
517 PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx),
518 .name = "Maxlinear Ethernet GPY2xx",
519 .get_features = genphy_c45_pma_read_abilities,
520 .config_init = gpy_config_init,
521 .probe = gpy_probe,
522 .suspend = genphy_suspend,
523 .resume = genphy_resume,
524 .config_aneg = gpy_config_aneg,
525 .aneg_done = genphy_c45_aneg_done,
526 .read_status = gpy_read_status,
527 .config_intr = gpy_config_intr,
528 .handle_interrupt = gpy_handle_interrupt,
529 .set_wol = gpy_set_wol,
530 .get_wol = gpy_get_wol,
531 .set_loopback = gpy_loopback,
532 },
533 {
534 .phy_id = PHY_ID_GPY115B,
535 .phy_id_mask = PHY_ID_GPYx15B_MASK,
536 .name = "Maxlinear Ethernet GPY115B",
537 .get_features = genphy_c45_pma_read_abilities,
538 .config_init = gpy_config_init,
539 .probe = gpy_probe,
540 .suspend = genphy_suspend,
541 .resume = genphy_resume,
542 .config_aneg = gpy_config_aneg,
543 .aneg_done = genphy_c45_aneg_done,
544 .read_status = gpy_read_status,
545 .config_intr = gpy_config_intr,
546 .handle_interrupt = gpy_handle_interrupt,
547 .set_wol = gpy_set_wol,
548 .get_wol = gpy_get_wol,
549 .set_loopback = gpy115_loopback,
550 },
551 {
552 PHY_ID_MATCH_MODEL(PHY_ID_GPY115C),
553 .name = "Maxlinear Ethernet GPY115C",
554 .get_features = genphy_c45_pma_read_abilities,
555 .config_init = gpy_config_init,
556 .probe = gpy_probe,
557 .suspend = genphy_suspend,
558 .resume = genphy_resume,
559 .config_aneg = gpy_config_aneg,
560 .aneg_done = genphy_c45_aneg_done,
561 .read_status = gpy_read_status,
562 .config_intr = gpy_config_intr,
563 .handle_interrupt = gpy_handle_interrupt,
564 .set_wol = gpy_set_wol,
565 .get_wol = gpy_get_wol,
566 .set_loopback = gpy115_loopback,
567 },
568 {
569 .phy_id = PHY_ID_GPY211B,
570 .phy_id_mask = PHY_ID_GPY21xB_MASK,
571 .name = "Maxlinear Ethernet GPY211B",
572 .get_features = genphy_c45_pma_read_abilities,
573 .config_init = gpy_config_init,
574 .probe = gpy_probe,
575 .suspend = genphy_suspend,
576 .resume = genphy_resume,
577 .config_aneg = gpy_config_aneg,
578 .aneg_done = genphy_c45_aneg_done,
579 .read_status = gpy_read_status,
580 .config_intr = gpy_config_intr,
581 .handle_interrupt = gpy_handle_interrupt,
582 .set_wol = gpy_set_wol,
583 .get_wol = gpy_get_wol,
584 .set_loopback = gpy_loopback,
585 },
586 {
587 PHY_ID_MATCH_MODEL(PHY_ID_GPY211C),
588 .name = "Maxlinear Ethernet GPY211C",
589 .get_features = genphy_c45_pma_read_abilities,
590 .config_init = gpy_config_init,
591 .probe = gpy_probe,
592 .suspend = genphy_suspend,
593 .resume = genphy_resume,
594 .config_aneg = gpy_config_aneg,
595 .aneg_done = genphy_c45_aneg_done,
596 .read_status = gpy_read_status,
597 .config_intr = gpy_config_intr,
598 .handle_interrupt = gpy_handle_interrupt,
599 .set_wol = gpy_set_wol,
600 .get_wol = gpy_get_wol,
601 .set_loopback = gpy_loopback,
602 },
603 {
604 .phy_id = PHY_ID_GPY212B,
605 .phy_id_mask = PHY_ID_GPY21xB_MASK,
606 .name = "Maxlinear Ethernet GPY212B",
607 .get_features = genphy_c45_pma_read_abilities,
608 .config_init = gpy_config_init,
609 .probe = gpy_probe,
610 .suspend = genphy_suspend,
611 .resume = genphy_resume,
612 .config_aneg = gpy_config_aneg,
613 .aneg_done = genphy_c45_aneg_done,
614 .read_status = gpy_read_status,
615 .config_intr = gpy_config_intr,
616 .handle_interrupt = gpy_handle_interrupt,
617 .set_wol = gpy_set_wol,
618 .get_wol = gpy_get_wol,
619 .set_loopback = gpy_loopback,
620 },
621 {
622 PHY_ID_MATCH_MODEL(PHY_ID_GPY212C),
623 .name = "Maxlinear Ethernet GPY212C",
624 .get_features = genphy_c45_pma_read_abilities,
625 .config_init = gpy_config_init,
626 .probe = gpy_probe,
627 .suspend = genphy_suspend,
628 .resume = genphy_resume,
629 .config_aneg = gpy_config_aneg,
630 .aneg_done = genphy_c45_aneg_done,
631 .read_status = gpy_read_status,
632 .config_intr = gpy_config_intr,
633 .handle_interrupt = gpy_handle_interrupt,
634 .set_wol = gpy_set_wol,
635 .get_wol = gpy_get_wol,
636 .set_loopback = gpy_loopback,
637 },
638 {
639 .phy_id = PHY_ID_GPY215B,
640 .phy_id_mask = PHY_ID_GPYx15B_MASK,
641 .name = "Maxlinear Ethernet GPY215B",
642 .get_features = genphy_c45_pma_read_abilities,
643 .config_init = gpy_config_init,
644 .probe = gpy_probe,
645 .suspend = genphy_suspend,
646 .resume = genphy_resume,
647 .config_aneg = gpy_config_aneg,
648 .aneg_done = genphy_c45_aneg_done,
649 .read_status = gpy_read_status,
650 .config_intr = gpy_config_intr,
651 .handle_interrupt = gpy_handle_interrupt,
652 .set_wol = gpy_set_wol,
653 .get_wol = gpy_get_wol,
654 .set_loopback = gpy_loopback,
655 },
656 {
657 PHY_ID_MATCH_MODEL(PHY_ID_GPY215C),
658 .name = "Maxlinear Ethernet GPY215C",
659 .get_features = genphy_c45_pma_read_abilities,
660 .config_init = gpy_config_init,
661 .probe = gpy_probe,
662 .suspend = genphy_suspend,
663 .resume = genphy_resume,
664 .config_aneg = gpy_config_aneg,
665 .aneg_done = genphy_c45_aneg_done,
666 .read_status = gpy_read_status,
667 .config_intr = gpy_config_intr,
668 .handle_interrupt = gpy_handle_interrupt,
669 .set_wol = gpy_set_wol,
670 .get_wol = gpy_get_wol,
671 .set_loopback = gpy_loopback,
672 },
673 {
674 PHY_ID_MATCH_MODEL(PHY_ID_GPY241B),
675 .name = "Maxlinear Ethernet GPY241B",
676 .get_features = genphy_c45_pma_read_abilities,
677 .config_init = gpy_config_init,
678 .probe = gpy_probe,
679 .suspend = genphy_suspend,
680 .resume = genphy_resume,
681 .config_aneg = gpy_config_aneg,
682 .aneg_done = genphy_c45_aneg_done,
683 .read_status = gpy_read_status,
684 .config_intr = gpy_config_intr,
685 .handle_interrupt = gpy_handle_interrupt,
686 .set_wol = gpy_set_wol,
687 .get_wol = gpy_get_wol,
688 .set_loopback = gpy_loopback,
689 },
690 {
691 PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM),
692 .name = "Maxlinear Ethernet GPY241BM",
693 .get_features = genphy_c45_pma_read_abilities,
694 .config_init = gpy_config_init,
695 .probe = gpy_probe,
696 .suspend = genphy_suspend,
697 .resume = genphy_resume,
698 .config_aneg = gpy_config_aneg,
699 .aneg_done = genphy_c45_aneg_done,
700 .read_status = gpy_read_status,
701 .config_intr = gpy_config_intr,
702 .handle_interrupt = gpy_handle_interrupt,
703 .set_wol = gpy_set_wol,
704 .get_wol = gpy_get_wol,
705 .set_loopback = gpy_loopback,
706 },
707 {
708 PHY_ID_MATCH_MODEL(PHY_ID_GPY245B),
709 .name = "Maxlinear Ethernet GPY245B",
710 .get_features = genphy_c45_pma_read_abilities,
711 .config_init = gpy_config_init,
712 .probe = gpy_probe,
713 .suspend = genphy_suspend,
714 .resume = genphy_resume,
715 .config_aneg = gpy_config_aneg,
716 .aneg_done = genphy_c45_aneg_done,
717 .read_status = gpy_read_status,
718 .config_intr = gpy_config_intr,
719 .handle_interrupt = gpy_handle_interrupt,
720 .set_wol = gpy_set_wol,
721 .get_wol = gpy_get_wol,
722 .set_loopback = gpy_loopback,
723 },
724};
725module_phy_driver(gpy_drivers);
726
727static struct mdio_device_id __maybe_unused gpy_tbl[] = {
728 {PHY_ID_MATCH_MODEL(PHY_ID_GPY2xx)},
729 {PHY_ID_GPY115B, PHY_ID_GPYx15B_MASK},
730 {PHY_ID_MATCH_MODEL(PHY_ID_GPY115C)},
731 {PHY_ID_GPY211B, PHY_ID_GPY21xB_MASK},
732 {PHY_ID_MATCH_MODEL(PHY_ID_GPY211C)},
733 {PHY_ID_GPY212B, PHY_ID_GPY21xB_MASK},
734 {PHY_ID_MATCH_MODEL(PHY_ID_GPY212C)},
735 {PHY_ID_GPY215B, PHY_ID_GPYx15B_MASK},
736 {PHY_ID_MATCH_MODEL(PHY_ID_GPY215C)},
737 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241B)},
738 {PHY_ID_MATCH_MODEL(PHY_ID_GPY241BM)},
739 {PHY_ID_MATCH_MODEL(PHY_ID_GPY245B)},
740 { }
741};
742MODULE_DEVICE_TABLE(mdio, gpy_tbl);
743
744MODULE_DESCRIPTION("Maxlinear Ethernet GPY Driver");
745MODULE_AUTHOR("Xu Liang");
746MODULE_LICENSE("GPL");
747