]> git.karo-electronics.de Git - mv-sheeva.git/blob - drivers/net/phy/marvell.c
phy/marvell: add 88ec048 support
[mv-sheeva.git] / drivers / net / phy / marvell.c
1 /*
2  * drivers/net/phy/marvell.c
3  *
4  * Driver for Marvell PHYs
5  *
6  * Author: Andy Fleming
7  *
8  * Copyright (c) 2004 Freescale Semiconductor, Inc.
9  *
10  * This program is free software; you can redistribute  it and/or modify it
11  * under  the terms of  the GNU General  Public License as published by the
12  * Free Software Foundation;  either version 2 of the  License, or (at your
13  * option) any later version.
14  *
15  */
16 #include <linux/kernel.h>
17 #include <linux/string.h>
18 #include <linux/errno.h>
19 #include <linux/unistd.h>
20 #include <linux/interrupt.h>
21 #include <linux/init.h>
22 #include <linux/delay.h>
23 #include <linux/netdevice.h>
24 #include <linux/etherdevice.h>
25 #include <linux/skbuff.h>
26 #include <linux/spinlock.h>
27 #include <linux/mm.h>
28 #include <linux/module.h>
29 #include <linux/mii.h>
30 #include <linux/ethtool.h>
31 #include <linux/phy.h>
32
33 #include <asm/io.h>
34 #include <asm/irq.h>
35 #include <asm/uaccess.h>
36
37 #define MII_M1011_IEVENT                0x13
38 #define MII_M1011_IEVENT_CLEAR          0x0000
39
40 #define MII_M1011_IMASK                 0x12
41 #define MII_M1011_IMASK_INIT            0x6400
42 #define MII_M1011_IMASK_CLEAR           0x0000
43
44 #define MII_M1011_PHY_SCR               0x10
45 #define MII_M1011_PHY_SCR_AUTO_CROSS    0x0060
46
47 #define MII_M1145_PHY_EXT_CR            0x14
48 #define MII_M1145_RGMII_RX_DELAY        0x0080
49 #define MII_M1145_RGMII_TX_DELAY        0x0002
50
51 #define M1145_DEV_FLAGS_RESISTANCE      0x00000001
52
53 #define MII_M1111_PHY_LED_CONTROL       0x18
54 #define MII_M1111_PHY_LED_DIRECT        0x4100
55 #define MII_M1111_PHY_LED_COMBINE       0x411c
56 #define MII_M1111_PHY_EXT_CR            0x14
57 #define MII_M1111_RX_DELAY              0x80
58 #define MII_M1111_TX_DELAY              0x2
59 #define MII_M1111_PHY_EXT_SR            0x1b
60
61 #define MII_M1111_HWCFG_MODE_MASK               0xf
62 #define MII_M1111_HWCFG_MODE_COPPER_RGMII       0xb
63 #define MII_M1111_HWCFG_MODE_FIBER_RGMII        0x3
64 #define MII_M1111_HWCFG_MODE_SGMII_NO_CLK       0x4
65 #define MII_M1111_HWCFG_MODE_COPPER_RTBI        0x9
66 #define MII_M1111_HWCFG_FIBER_COPPER_AUTO       0x8000
67 #define MII_M1111_HWCFG_FIBER_COPPER_RES        0x2000
68
69 #define MII_M1111_COPPER                0
70 #define MII_M1111_FIBER                 1
71
72 #define MII_88E1121_PHY_MSCR_PAGE       2
73 #define MII_88E1121_PHY_MSCR_REG        21
74 #define MII_88E1121_PHY_MSCR_RX_DELAY   BIT(5)
75 #define MII_88E1121_PHY_MSCR_TX_DELAY   BIT(4)
76 #define MII_88E1121_PHY_MSCR_DELAY_MASK (~(0x3 << 4))
77
78 #define MII_88EC048_PHY_MSCR1_REG       16
79 #define MII_88EC048_PHY_MSCR1_PAD_ODD   BIT(6)
80
81 #define MII_88E1121_PHY_LED_CTRL        16
82 #define MII_88E1121_PHY_LED_PAGE        3
83 #define MII_88E1121_PHY_LED_DEF         0x0030
84 #define MII_88E1121_PHY_PAGE            22
85
86 #define MII_M1011_PHY_STATUS            0x11
87 #define MII_M1011_PHY_STATUS_1000       0x8000
88 #define MII_M1011_PHY_STATUS_100        0x4000
89 #define MII_M1011_PHY_STATUS_SPD_MASK   0xc000
90 #define MII_M1011_PHY_STATUS_FULLDUPLEX 0x2000
91 #define MII_M1011_PHY_STATUS_RESOLVED   0x0800
92 #define MII_M1011_PHY_STATUS_LINK       0x0400
93
94
95 MODULE_DESCRIPTION("Marvell PHY driver");
96 MODULE_AUTHOR("Andy Fleming");
97 MODULE_LICENSE("GPL");
98
99 static int marvell_ack_interrupt(struct phy_device *phydev)
100 {
101         int err;
102
103         /* Clear the interrupts by reading the reg */
104         err = phy_read(phydev, MII_M1011_IEVENT);
105
106         if (err < 0)
107                 return err;
108
109         return 0;
110 }
111
112 static int marvell_config_intr(struct phy_device *phydev)
113 {
114         int err;
115
116         if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
117                 err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_INIT);
118         else
119                 err = phy_write(phydev, MII_M1011_IMASK, MII_M1011_IMASK_CLEAR);
120
121         return err;
122 }
123
124 static int marvell_config_aneg(struct phy_device *phydev)
125 {
126         int err;
127
128         /* The Marvell PHY has an errata which requires
129          * that certain registers get written in order
130          * to restart autonegotiation */
131         err = phy_write(phydev, MII_BMCR, BMCR_RESET);
132
133         if (err < 0)
134                 return err;
135
136         err = phy_write(phydev, 0x1d, 0x1f);
137         if (err < 0)
138                 return err;
139
140         err = phy_write(phydev, 0x1e, 0x200c);
141         if (err < 0)
142                 return err;
143
144         err = phy_write(phydev, 0x1d, 0x5);
145         if (err < 0)
146                 return err;
147
148         err = phy_write(phydev, 0x1e, 0);
149         if (err < 0)
150                 return err;
151
152         err = phy_write(phydev, 0x1e, 0x100);
153         if (err < 0)
154                 return err;
155
156         err = phy_write(phydev, MII_M1011_PHY_SCR,
157                         MII_M1011_PHY_SCR_AUTO_CROSS);
158         if (err < 0)
159                 return err;
160
161         err = phy_write(phydev, MII_M1111_PHY_LED_CONTROL,
162                         MII_M1111_PHY_LED_DIRECT);
163         if (err < 0)
164                 return err;
165
166         err = genphy_config_aneg(phydev);
167         if (err < 0)
168                 return err;
169
170         if (phydev->autoneg != AUTONEG_ENABLE) {
171                 int bmcr;
172
173                 /*
174                  * A write to speed/duplex bits (that is performed by
175                  * genphy_config_aneg() call above) must be followed by
176                  * a software reset. Otherwise, the write has no effect.
177                  */
178                 bmcr = phy_read(phydev, MII_BMCR);
179                 if (bmcr < 0)
180                         return bmcr;
181
182                 err = phy_write(phydev, MII_BMCR, bmcr | BMCR_RESET);
183                 if (err < 0)
184                         return err;
185         }
186
187         return 0;
188 }
189
190 static int m88e1121_config_aneg(struct phy_device *phydev)
191 {
192         int err, oldpage, mscr;
193
194         oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
195
196         err = phy_write(phydev, MII_88E1121_PHY_PAGE,
197                         MII_88E1121_PHY_MSCR_PAGE);
198         if (err < 0)
199                 return err;
200         mscr = phy_read(phydev, MII_88E1121_PHY_MSCR_REG) &
201                 MII_88E1121_PHY_MSCR_DELAY_MASK;
202
203         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID)
204                 mscr |= (MII_88E1121_PHY_MSCR_RX_DELAY |
205                          MII_88E1121_PHY_MSCR_TX_DELAY);
206         else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID)
207                 mscr |= MII_88E1121_PHY_MSCR_RX_DELAY;
208         else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)
209                 mscr |= MII_88E1121_PHY_MSCR_TX_DELAY;
210
211         err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
212         if (err < 0)
213                 return err;
214
215         phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
216
217         err = phy_write(phydev, MII_BMCR, BMCR_RESET);
218         if (err < 0)
219                 return err;
220
221         err = phy_write(phydev, MII_M1011_PHY_SCR,
222                         MII_M1011_PHY_SCR_AUTO_CROSS);
223         if (err < 0)
224                 return err;
225
226         oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
227
228         phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
229         phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
230         phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
231
232         err = genphy_config_aneg(phydev);
233
234         return err;
235 }
236
237 static int m88ec048_config_aneg(struct phy_device *phydev)
238 {
239         int err, oldpage, mscr;
240
241         oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
242
243         err = phy_write(phydev, MII_88E1121_PHY_PAGE,
244                         MII_88E1121_PHY_MSCR_PAGE);
245         if (err < 0)
246                 return err;
247
248         mscr = phy_read(phydev, MII_88EC048_PHY_MSCR1_REG);
249         mscr |= MII_88EC048_PHY_MSCR1_PAD_ODD;
250
251         err = phy_write(phydev, MII_88E1121_PHY_MSCR_REG, mscr);
252         if (err < 0)
253                 return err;
254
255         err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
256         if (err < 0)
257                 return err;
258
259         return m88e1121_config_aneg(phydev);
260 }
261
262 static int m88e1111_config_init(struct phy_device *phydev)
263 {
264         int err;
265         int temp;
266
267         /* Enable Fiber/Copper auto selection */
268         temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
269         temp &= ~MII_M1111_HWCFG_FIBER_COPPER_AUTO;
270         phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
271
272         temp = phy_read(phydev, MII_BMCR);
273         temp |= BMCR_RESET;
274         phy_write(phydev, MII_BMCR, temp);
275
276         if ((phydev->interface == PHY_INTERFACE_MODE_RGMII) ||
277             (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) ||
278             (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) ||
279             (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID)) {
280
281                 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
282                 if (temp < 0)
283                         return temp;
284
285                 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
286                         temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
287                 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
288                         temp &= ~MII_M1111_TX_DELAY;
289                         temp |= MII_M1111_RX_DELAY;
290                 } else if (phydev->interface == PHY_INTERFACE_MODE_RGMII_TXID) {
291                         temp &= ~MII_M1111_RX_DELAY;
292                         temp |= MII_M1111_TX_DELAY;
293                 }
294
295                 err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
296                 if (err < 0)
297                         return err;
298
299                 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
300                 if (temp < 0)
301                         return temp;
302
303                 temp &= ~(MII_M1111_HWCFG_MODE_MASK);
304
305                 if (temp & MII_M1111_HWCFG_FIBER_COPPER_RES)
306                         temp |= MII_M1111_HWCFG_MODE_FIBER_RGMII;
307                 else
308                         temp |= MII_M1111_HWCFG_MODE_COPPER_RGMII;
309
310                 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
311                 if (err < 0)
312                         return err;
313         }
314
315         if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
316                 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
317                 if (temp < 0)
318                         return temp;
319
320                 temp &= ~(MII_M1111_HWCFG_MODE_MASK);
321                 temp |= MII_M1111_HWCFG_MODE_SGMII_NO_CLK;
322                 temp |= MII_M1111_HWCFG_FIBER_COPPER_AUTO;
323
324                 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
325                 if (err < 0)
326                         return err;
327         }
328
329         if (phydev->interface == PHY_INTERFACE_MODE_RTBI) {
330                 temp = phy_read(phydev, MII_M1111_PHY_EXT_CR);
331                 if (temp < 0)
332                         return temp;
333                 temp |= (MII_M1111_RX_DELAY | MII_M1111_TX_DELAY);
334                 err = phy_write(phydev, MII_M1111_PHY_EXT_CR, temp);
335                 if (err < 0)
336                         return err;
337
338                 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
339                 if (temp < 0)
340                         return temp;
341                 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
342                 temp |= 0x7 | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
343                 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
344                 if (err < 0)
345                         return err;
346
347                 /* soft reset */
348                 err = phy_write(phydev, MII_BMCR, BMCR_RESET);
349                 if (err < 0)
350                         return err;
351                 do
352                         temp = phy_read(phydev, MII_BMCR);
353                 while (temp & BMCR_RESET);
354
355                 temp = phy_read(phydev, MII_M1111_PHY_EXT_SR);
356                 if (temp < 0)
357                         return temp;
358                 temp &= ~(MII_M1111_HWCFG_MODE_MASK | MII_M1111_HWCFG_FIBER_COPPER_RES);
359                 temp |= MII_M1111_HWCFG_MODE_COPPER_RTBI | MII_M1111_HWCFG_FIBER_COPPER_AUTO;
360                 err = phy_write(phydev, MII_M1111_PHY_EXT_SR, temp);
361                 if (err < 0)
362                         return err;
363         }
364
365
366         err = phy_write(phydev, MII_BMCR, BMCR_RESET);
367         if (err < 0)
368                 return err;
369
370         return 0;
371 }
372
373 static int m88e1118_config_aneg(struct phy_device *phydev)
374 {
375         int err;
376
377         err = phy_write(phydev, MII_BMCR, BMCR_RESET);
378         if (err < 0)
379                 return err;
380
381         err = phy_write(phydev, MII_M1011_PHY_SCR,
382                         MII_M1011_PHY_SCR_AUTO_CROSS);
383         if (err < 0)
384                 return err;
385
386         err = genphy_config_aneg(phydev);
387         return 0;
388 }
389
390 static int m88e1118_config_init(struct phy_device *phydev)
391 {
392         int err;
393
394         /* Change address */
395         err = phy_write(phydev, 0x16, 0x0002);
396         if (err < 0)
397                 return err;
398
399         /* Enable 1000 Mbit */
400         err = phy_write(phydev, 0x15, 0x1070);
401         if (err < 0)
402                 return err;
403
404         /* Change address */
405         err = phy_write(phydev, 0x16, 0x0003);
406         if (err < 0)
407                 return err;
408
409         /* Adjust LED Control */
410         err = phy_write(phydev, 0x10, 0x021e);
411         if (err < 0)
412                 return err;
413
414         /* Reset address */
415         err = phy_write(phydev, 0x16, 0x0);
416         if (err < 0)
417                 return err;
418
419         err = phy_write(phydev, MII_BMCR, BMCR_RESET);
420         if (err < 0)
421                 return err;
422
423         return 0;
424 }
425
426 static int m88e1145_config_init(struct phy_device *phydev)
427 {
428         int err;
429
430         /* Take care of errata E0 & E1 */
431         err = phy_write(phydev, 0x1d, 0x001b);
432         if (err < 0)
433                 return err;
434
435         err = phy_write(phydev, 0x1e, 0x418f);
436         if (err < 0)
437                 return err;
438
439         err = phy_write(phydev, 0x1d, 0x0016);
440         if (err < 0)
441                 return err;
442
443         err = phy_write(phydev, 0x1e, 0xa2da);
444         if (err < 0)
445                 return err;
446
447         if (phydev->interface == PHY_INTERFACE_MODE_RGMII_ID) {
448                 int temp = phy_read(phydev, MII_M1145_PHY_EXT_CR);
449                 if (temp < 0)
450                         return temp;
451
452                 temp |= (MII_M1145_RGMII_RX_DELAY | MII_M1145_RGMII_TX_DELAY);
453
454                 err = phy_write(phydev, MII_M1145_PHY_EXT_CR, temp);
455                 if (err < 0)
456                         return err;
457
458                 if (phydev->dev_flags & M1145_DEV_FLAGS_RESISTANCE) {
459                         err = phy_write(phydev, 0x1d, 0x0012);
460                         if (err < 0)
461                                 return err;
462
463                         temp = phy_read(phydev, 0x1e);
464                         if (temp < 0)
465                                 return temp;
466
467                         temp &= 0xf03f;
468                         temp |= 2 << 9; /* 36 ohm */
469                         temp |= 2 << 6; /* 39 ohm */
470
471                         err = phy_write(phydev, 0x1e, temp);
472                         if (err < 0)
473                                 return err;
474
475                         err = phy_write(phydev, 0x1d, 0x3);
476                         if (err < 0)
477                                 return err;
478
479                         err = phy_write(phydev, 0x1e, 0x8000);
480                         if (err < 0)
481                                 return err;
482                 }
483         }
484
485         return 0;
486 }
487
488 /* marvell_read_status
489  *
490  * Generic status code does not detect Fiber correctly!
491  * Description:
492  *   Check the link, then figure out the current state
493  *   by comparing what we advertise with what the link partner
494  *   advertises.  Start by checking the gigabit possibilities,
495  *   then move on to 10/100.
496  */
497 static int marvell_read_status(struct phy_device *phydev)
498 {
499         int adv;
500         int err;
501         int lpa;
502         int status = 0;
503
504         /* Update the link, but return if there
505          * was an error */
506         err = genphy_update_link(phydev);
507         if (err)
508                 return err;
509
510         if (AUTONEG_ENABLE == phydev->autoneg) {
511                 status = phy_read(phydev, MII_M1011_PHY_STATUS);
512                 if (status < 0)
513                         return status;
514
515                 lpa = phy_read(phydev, MII_LPA);
516                 if (lpa < 0)
517                         return lpa;
518
519                 adv = phy_read(phydev, MII_ADVERTISE);
520                 if (adv < 0)
521                         return adv;
522
523                 lpa &= adv;
524
525                 if (status & MII_M1011_PHY_STATUS_FULLDUPLEX)
526                         phydev->duplex = DUPLEX_FULL;
527                 else
528                         phydev->duplex = DUPLEX_HALF;
529
530                 status = status & MII_M1011_PHY_STATUS_SPD_MASK;
531                 phydev->pause = phydev->asym_pause = 0;
532
533                 switch (status) {
534                 case MII_M1011_PHY_STATUS_1000:
535                         phydev->speed = SPEED_1000;
536                         break;
537
538                 case MII_M1011_PHY_STATUS_100:
539                         phydev->speed = SPEED_100;
540                         break;
541
542                 default:
543                         phydev->speed = SPEED_10;
544                         break;
545                 }
546
547                 if (phydev->duplex == DUPLEX_FULL) {
548                         phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
549                         phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
550                 }
551         } else {
552                 int bmcr = phy_read(phydev, MII_BMCR);
553
554                 if (bmcr < 0)
555                         return bmcr;
556
557                 if (bmcr & BMCR_FULLDPLX)
558                         phydev->duplex = DUPLEX_FULL;
559                 else
560                         phydev->duplex = DUPLEX_HALF;
561
562                 if (bmcr & BMCR_SPEED1000)
563                         phydev->speed = SPEED_1000;
564                 else if (bmcr & BMCR_SPEED100)
565                         phydev->speed = SPEED_100;
566                 else
567                         phydev->speed = SPEED_10;
568
569                 phydev->pause = phydev->asym_pause = 0;
570         }
571
572         return 0;
573 }
574
575 static int m88e1121_did_interrupt(struct phy_device *phydev)
576 {
577         int imask;
578
579         imask = phy_read(phydev, MII_M1011_IEVENT);
580
581         if (imask & MII_M1011_IMASK_INIT)
582                 return 1;
583
584         return 0;
585 }
586
587 static struct phy_driver marvell_drivers[] = {
588         {
589                 .phy_id = 0x01410c60,
590                 .phy_id_mask = 0xfffffff0,
591                 .name = "Marvell 88E1101",
592                 .features = PHY_GBIT_FEATURES,
593                 .flags = PHY_HAS_INTERRUPT,
594                 .config_aneg = &marvell_config_aneg,
595                 .read_status = &genphy_read_status,
596                 .ack_interrupt = &marvell_ack_interrupt,
597                 .config_intr = &marvell_config_intr,
598                 .driver = { .owner = THIS_MODULE },
599         },
600         {
601                 .phy_id = 0x01410c90,
602                 .phy_id_mask = 0xfffffff0,
603                 .name = "Marvell 88E1112",
604                 .features = PHY_GBIT_FEATURES,
605                 .flags = PHY_HAS_INTERRUPT,
606                 .config_init = &m88e1111_config_init,
607                 .config_aneg = &marvell_config_aneg,
608                 .read_status = &genphy_read_status,
609                 .ack_interrupt = &marvell_ack_interrupt,
610                 .config_intr = &marvell_config_intr,
611                 .driver = { .owner = THIS_MODULE },
612         },
613         {
614                 .phy_id = 0x01410cc0,
615                 .phy_id_mask = 0xfffffff0,
616                 .name = "Marvell 88E1111",
617                 .features = PHY_GBIT_FEATURES,
618                 .flags = PHY_HAS_INTERRUPT,
619                 .config_init = &m88e1111_config_init,
620                 .config_aneg = &marvell_config_aneg,
621                 .read_status = &marvell_read_status,
622                 .ack_interrupt = &marvell_ack_interrupt,
623                 .config_intr = &marvell_config_intr,
624                 .driver = { .owner = THIS_MODULE },
625         },
626         {
627                 .phy_id = 0x01410e10,
628                 .phy_id_mask = 0xfffffff0,
629                 .name = "Marvell 88E1118",
630                 .features = PHY_GBIT_FEATURES,
631                 .flags = PHY_HAS_INTERRUPT,
632                 .config_init = &m88e1118_config_init,
633                 .config_aneg = &m88e1118_config_aneg,
634                 .read_status = &genphy_read_status,
635                 .ack_interrupt = &marvell_ack_interrupt,
636                 .config_intr = &marvell_config_intr,
637                 .driver = {.owner = THIS_MODULE,},
638         },
639         {
640                 .phy_id = 0x01410cb0,
641                 .phy_id_mask = 0xfffffff0,
642                 .name = "Marvell 88E1121R",
643                 .features = PHY_GBIT_FEATURES,
644                 .flags = PHY_HAS_INTERRUPT,
645                 .config_aneg = &m88e1121_config_aneg,
646                 .read_status = &marvell_read_status,
647                 .ack_interrupt = &marvell_ack_interrupt,
648                 .config_intr = &marvell_config_intr,
649                 .did_interrupt = &m88e1121_did_interrupt,
650                 .driver = { .owner = THIS_MODULE },
651         },
652         {
653                 .phy_id = 0x01410e90,
654                 .phy_id_mask = 0xfffffff0,
655                 .name = "Marvell 88EC048",
656                 .features = PHY_GBIT_FEATURES,
657                 .flags = PHY_HAS_INTERRUPT,
658                 .config_aneg = &m88ec048_config_aneg,
659                 .read_status = &marvell_read_status,
660                 .ack_interrupt = &marvell_ack_interrupt,
661                 .config_intr = &marvell_config_intr,
662                 .did_interrupt = &m88e1121_did_interrupt,
663                 .driver = { .owner = THIS_MODULE },
664         },
665         {
666                 .phy_id = 0x01410cd0,
667                 .phy_id_mask = 0xfffffff0,
668                 .name = "Marvell 88E1145",
669                 .features = PHY_GBIT_FEATURES,
670                 .flags = PHY_HAS_INTERRUPT,
671                 .config_init = &m88e1145_config_init,
672                 .config_aneg = &marvell_config_aneg,
673                 .read_status = &genphy_read_status,
674                 .ack_interrupt = &marvell_ack_interrupt,
675                 .config_intr = &marvell_config_intr,
676                 .driver = { .owner = THIS_MODULE },
677         },
678         {
679                 .phy_id = 0x01410e30,
680                 .phy_id_mask = 0xfffffff0,
681                 .name = "Marvell 88E1240",
682                 .features = PHY_GBIT_FEATURES,
683                 .flags = PHY_HAS_INTERRUPT,
684                 .config_init = &m88e1111_config_init,
685                 .config_aneg = &marvell_config_aneg,
686                 .read_status = &genphy_read_status,
687                 .ack_interrupt = &marvell_ack_interrupt,
688                 .config_intr = &marvell_config_intr,
689                 .driver = { .owner = THIS_MODULE },
690         },
691 };
692
693 static int __init marvell_init(void)
694 {
695         int ret;
696         int i;
697
698         for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++) {
699                 ret = phy_driver_register(&marvell_drivers[i]);
700
701                 if (ret) {
702                         while (i-- > 0)
703                                 phy_driver_unregister(&marvell_drivers[i]);
704                         return ret;
705                 }
706         }
707
708         return 0;
709 }
710
711 static void __exit marvell_exit(void)
712 {
713         int i;
714
715         for (i = 0; i < ARRAY_SIZE(marvell_drivers); i++)
716                 phy_driver_unregister(&marvell_drivers[i]);
717 }
718
719 module_init(marvell_init);
720 module_exit(marvell_exit);
721
722 static struct mdio_device_id marvell_tbl[] = {
723         { 0x01410c60, 0xfffffff0 },
724         { 0x01410c90, 0xfffffff0 },
725         { 0x01410cc0, 0xfffffff0 },
726         { 0x01410e10, 0xfffffff0 },
727         { 0x01410cb0, 0xfffffff0 },
728         { 0x01410cd0, 0xfffffff0 },
729         { 0x01410e30, 0xfffffff0 },
730         { 0x01410e90, 0xfffffff0 },
731         { }
732 };
733
734 MODULE_DEVICE_TABLE(mdio, marvell_tbl);