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