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