blob: 854f2c9a7b2b5224f1dab808d16d8f514cdd486a [file] [log] [blame]
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +01001/*
2 * drivers/net/phy/broadcom.c
3 *
4 * Broadcom BCM5411, BCM5421 and BCM5461 Gigabit Ethernet
5 * transceivers.
6 *
7 * Copyright (c) 2006 Maciej W. Rozycki
8 *
9 * Inspired by code written by Amy Fong.
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version
14 * 2 of the License, or (at your option) any later version.
15 */
16
17#include <linux/module.h>
18#include <linux/phy.h>
Matt Carlson8649f132009-11-02 14:30:00 +000019#include <linux/brcmphy.h>
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +010020
Matt Carlsond9221e62009-08-25 10:11:26 +000021
22#define BRCM_PHY_MODEL(phydev) \
23 ((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
24
Matt Carlson32e5a8d2009-11-02 14:31:39 +000025#define BRCM_PHY_REV(phydev) \
26 ((phydev)->drv->phy_id & ~((phydev)->drv->phy_id_mask))
27
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +010028MODULE_DESCRIPTION("Broadcom PHY driver");
29MODULE_AUTHOR("Maciej W. Rozycki");
30MODULE_LICENSE("GPL");
31
Matt Carlson042a75b2008-11-03 16:56:29 -080032/* Indirect register access functions for the Expansion Registers */
Matt Carlsond9221e62009-08-25 10:11:26 +000033static int bcm54xx_exp_read(struct phy_device *phydev, u16 regnum)
Nate Casecd9af3d2008-05-17 06:40:39 +010034{
35 int val;
36
Matt Carlson042a75b2008-11-03 16:56:29 -080037 val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
38 if (val < 0)
39 return val;
40
Nate Casecd9af3d2008-05-17 06:40:39 +010041 val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
Matt Carlson042a75b2008-11-03 16:56:29 -080042
43 /* Restore default value. It's O.K. if this write fails. */
44 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
Nate Casecd9af3d2008-05-17 06:40:39 +010045
46 return val;
47}
48
Matt Carlson772638b2008-11-03 16:56:51 -080049static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
Nate Casecd9af3d2008-05-17 06:40:39 +010050{
51 int ret;
52
Matt Carlson042a75b2008-11-03 16:56:29 -080053 ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
54 if (ret < 0)
55 return ret;
56
Nate Casecd9af3d2008-05-17 06:40:39 +010057 ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
Matt Carlson042a75b2008-11-03 16:56:29 -080058
59 /* Restore default value. It's O.K. if this write fails. */
60 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
Nate Casecd9af3d2008-05-17 06:40:39 +010061
62 return ret;
63}
64
Matt Carlson772638b2008-11-03 16:56:51 -080065static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
66{
67 return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
68}
69
Matt Carlson47b1b532009-11-02 14:28:04 +000070/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
Matt Carlson772638b2008-11-03 16:56:51 -080071static int bcm50610_a0_workaround(struct phy_device *phydev)
72{
73 int err;
74
Matt Carlson47b1b532009-11-02 14:28:04 +000075 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
76 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
77 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
78 if (err < 0)
79 return err;
80
81 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
82 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
83 if (err < 0)
84 return err;
85
86 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
87 MII_BCM54XX_EXP_EXP75_VDACCTRL);
88 if (err < 0)
89 return err;
90
91 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
92 MII_BCM54XX_EXP_EXP96_MYST);
93 if (err < 0)
94 return err;
95
96 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
97 MII_BCM54XX_EXP_EXP97_MYST);
98
99 return err;
100}
101
102static int bcm54xx_phydsp_config(struct phy_device *phydev)
103{
104 int err, err2;
105
106 /* Enable the SMDSP clock */
Matt Carlson772638b2008-11-03 16:56:51 -0800107 err = bcm54xx_auxctl_write(phydev,
108 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
109 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
110 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
111 if (err < 0)
112 return err;
113
Matt Carlson219c6ef2009-11-02 14:28:33 +0000114 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
115 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) {
116 /* Clear bit 9 to fix a phy interop issue. */
117 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
118 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ);
119 if (err < 0)
120 goto error;
121
122 if (phydev->drv->phy_id == PHY_ID_BCM50610) {
123 err = bcm50610_a0_workaround(phydev);
124 if (err < 0)
125 goto error;
126 }
127 }
Matt Carlson772638b2008-11-03 16:56:51 -0800128
Matt Carlson47b1b532009-11-02 14:28:04 +0000129 if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM57780) {
130 int val;
Matt Carlson772638b2008-11-03 16:56:51 -0800131
Matt Carlson47b1b532009-11-02 14:28:04 +0000132 val = bcm54xx_exp_read(phydev, MII_BCM54XX_EXP_EXP75);
133 if (val < 0)
134 goto error;
Matt Carlson772638b2008-11-03 16:56:51 -0800135
Matt Carlson47b1b532009-11-02 14:28:04 +0000136 val |= MII_BCM54XX_EXP_EXP75_CM_OSC;
137 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, val);
138 }
Matt Carlson772638b2008-11-03 16:56:51 -0800139
140error:
Matt Carlson47b1b532009-11-02 14:28:04 +0000141 /* Disable the SMDSP clock */
142 err2 = bcm54xx_auxctl_write(phydev,
143 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
144 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
Matt Carlson772638b2008-11-03 16:56:51 -0800145
Matt Carlson47b1b532009-11-02 14:28:04 +0000146 /* Return the first error reported. */
147 return err ? err : err2;
Matt Carlson772638b2008-11-03 16:56:51 -0800148}
149
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000150static void bcm54xx_adjust_rxrefclk(struct phy_device *phydev)
151{
Roel Kluin5ee6f6a2009-12-18 20:16:10 -0800152 u32 orig;
153 int val;
Matt Carlsonc704dc22009-11-02 14:32:12 +0000154 bool clk125en = true;
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000155
156 /* Abort if we are using an untested phy. */
roel kluin7ec4e7d2009-12-30 06:43:06 +0000157 if (BRCM_PHY_MODEL(phydev) != PHY_ID_BCM57780 &&
158 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610 &&
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000159 BRCM_PHY_MODEL(phydev) != PHY_ID_BCM50610M)
160 return;
161
162 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_SCR3);
163 if (val < 0)
164 return;
165
166 orig = val;
167
Matt Carlsonc704dc22009-11-02 14:32:12 +0000168 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
169 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
170 BRCM_PHY_REV(phydev) >= 0x3) {
171 /*
172 * Here, bit 0 _disables_ CLK125 when set.
173 * This bit is set by default.
174 */
175 clk125en = false;
176 } else {
177 if (phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) {
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000178 /* Here, bit 0 _enables_ CLK125 when set */
179 val &= ~BCM54XX_SHD_SCR3_DEF_CLK125;
Matt Carlsonc704dc22009-11-02 14:32:12 +0000180 clk125en = false;
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000181 }
182 }
183
Joe Perches23677ce2012-02-09 11:17:23 +0000184 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
Matt Carlsonc704dc22009-11-02 14:32:12 +0000185 val &= ~BCM54XX_SHD_SCR3_DLLAPD_DIS;
186 else
187 val |= BCM54XX_SHD_SCR3_DLLAPD_DIS;
188
Matt Carlson52fae082009-11-02 14:32:38 +0000189 if (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY)
190 val |= BCM54XX_SHD_SCR3_TRDDAPD;
191
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000192 if (orig != val)
193 bcm54xx_shadow_write(phydev, BCM54XX_SHD_SCR3, val);
Matt Carlsonc704dc22009-11-02 14:32:12 +0000194
195 val = bcm54xx_shadow_read(phydev, BCM54XX_SHD_APD);
196 if (val < 0)
197 return;
198
199 orig = val;
200
Joe Perches23677ce2012-02-09 11:17:23 +0000201 if (!clk125en || (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
Matt Carlsonc704dc22009-11-02 14:32:12 +0000202 val |= BCM54XX_SHD_APD_EN;
203 else
204 val &= ~BCM54XX_SHD_APD_EN;
205
206 if (orig != val)
207 bcm54xx_shadow_write(phydev, BCM54XX_SHD_APD, val);
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000208}
209
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100210static int bcm54xx_config_init(struct phy_device *phydev)
211{
212 int reg, err;
213
214 reg = phy_read(phydev, MII_BCM54XX_ECR);
215 if (reg < 0)
216 return reg;
217
218 /* Mask interrupts globally. */
219 reg |= MII_BCM54XX_ECR_IM;
220 err = phy_write(phydev, MII_BCM54XX_ECR, reg);
221 if (err < 0)
222 return err;
223
224 /* Unmask events we are interested in. */
225 reg = ~(MII_BCM54XX_INT_DUPLEX |
226 MII_BCM54XX_INT_SPEED |
227 MII_BCM54XX_INT_LINK);
228 err = phy_write(phydev, MII_BCM54XX_IMR, reg);
229 if (err < 0)
230 return err;
Matt Carlson772638b2008-11-03 16:56:51 -0800231
Matt Carlson63a14ce2009-11-02 14:30:40 +0000232 if ((BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610 ||
233 BRCM_PHY_MODEL(phydev) == PHY_ID_BCM50610M) &&
234 (phydev->dev_flags & PHY_BRCM_CLEAR_RGMII_MODE))
235 bcm54xx_shadow_write(phydev, BCM54XX_SHD_RGMII_MODE, 0);
236
Matt Carlsonc704dc22009-11-02 14:32:12 +0000237 if ((phydev->dev_flags & PHY_BRCM_RX_REFCLK_UNUSED) ||
Matt Carlson52fae082009-11-02 14:32:38 +0000238 (phydev->dev_flags & PHY_BRCM_DIS_TXCRXC_NOENRGY) ||
Matt Carlsonc704dc22009-11-02 14:32:12 +0000239 (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
Matt Carlson32e5a8d2009-11-02 14:31:39 +0000240 bcm54xx_adjust_rxrefclk(phydev);
241
Matt Carlson47b1b532009-11-02 14:28:04 +0000242 bcm54xx_phydsp_config(phydev);
Matt Carlsond9221e62009-08-25 10:11:26 +0000243
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100244 return 0;
245}
246
Nate Casecd9af3d2008-05-17 06:40:39 +0100247static int bcm5482_config_init(struct phy_device *phydev)
248{
249 int err, reg;
250
251 err = bcm54xx_config_init(phydev);
252
253 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
254 /*
255 * Enable secondary SerDes and its use as an LED source
256 */
257 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_SSD);
258 bcm54xx_shadow_write(phydev, BCM5482_SHD_SSD,
259 reg |
260 BCM5482_SHD_SSD_LEDM |
261 BCM5482_SHD_SSD_EN);
262
263 /*
264 * Enable SGMII slave mode and auto-detection
265 */
Matt Carlson042a75b2008-11-03 16:56:29 -0800266 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
267 err = bcm54xx_exp_read(phydev, reg);
268 if (err < 0)
269 return err;
270 err = bcm54xx_exp_write(phydev, reg, err |
271 BCM5482_SSD_SGMII_SLAVE_EN |
272 BCM5482_SSD_SGMII_SLAVE_AD);
273 if (err < 0)
274 return err;
Nate Casecd9af3d2008-05-17 06:40:39 +0100275
276 /*
277 * Disable secondary SerDes powerdown
278 */
Matt Carlson042a75b2008-11-03 16:56:29 -0800279 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
280 err = bcm54xx_exp_read(phydev, reg);
281 if (err < 0)
282 return err;
283 err = bcm54xx_exp_write(phydev, reg,
284 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
285 if (err < 0)
286 return err;
Nate Casecd9af3d2008-05-17 06:40:39 +0100287
288 /*
289 * Select 1000BASE-X register set (primary SerDes)
290 */
291 reg = bcm54xx_shadow_read(phydev, BCM5482_SHD_MODE);
292 bcm54xx_shadow_write(phydev, BCM5482_SHD_MODE,
293 reg | BCM5482_SHD_MODE_1000BX);
294
295 /*
296 * LED1=ACTIVITYLED, LED3=LINKSPD[2]
297 * (Use LED1 as secondary SerDes ACTIVITY LED)
298 */
299 bcm54xx_shadow_write(phydev, BCM5482_SHD_LEDS1,
300 BCM5482_SHD_LEDS1_LED1(BCM_LED_SRC_ACTIVITYLED) |
301 BCM5482_SHD_LEDS1_LED3(BCM_LED_SRC_LINKSPD2));
302
303 /*
304 * Auto-negotiation doesn't seem to work quite right
305 * in this mode, so we disable it and force it to the
306 * right speed/duplex setting. Only 'link status'
307 * is important.
308 */
309 phydev->autoneg = AUTONEG_DISABLE;
310 phydev->speed = SPEED_1000;
311 phydev->duplex = DUPLEX_FULL;
312 }
313
314 return err;
315}
316
317static int bcm5482_read_status(struct phy_device *phydev)
318{
319 int err;
320
321 err = genphy_read_status(phydev);
322
323 if (phydev->dev_flags & PHY_BCM_FLAGS_MODE_1000BX) {
324 /*
325 * Only link status matters for 1000Base-X mode, so force
326 * 1000 Mbit/s full-duplex status
327 */
328 if (phydev->link) {
329 phydev->speed = SPEED_1000;
330 phydev->duplex = DUPLEX_FULL;
331 }
332 }
333
334 return err;
335}
336
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100337static int bcm54xx_ack_interrupt(struct phy_device *phydev)
338{
339 int reg;
340
341 /* Clear pending interrupts. */
342 reg = phy_read(phydev, MII_BCM54XX_ISR);
343 if (reg < 0)
344 return reg;
345
346 return 0;
347}
348
349static int bcm54xx_config_intr(struct phy_device *phydev)
350{
351 int reg, err;
352
353 reg = phy_read(phydev, MII_BCM54XX_ECR);
354 if (reg < 0)
355 return reg;
356
357 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
358 reg &= ~MII_BCM54XX_ECR_IM;
359 else
360 reg |= MII_BCM54XX_ECR_IM;
361
362 err = phy_write(phydev, MII_BCM54XX_ECR, reg);
363 return err;
364}
365
Anton Vorontsov57bb7e22008-03-04 19:41:32 +0300366static int bcm5481_config_aneg(struct phy_device *phydev)
367{
368 int ret;
369
370 /* Aneg firsly. */
371 ret = genphy_config_aneg(phydev);
372
373 /* Then we can set up the delay. */
374 if (phydev->interface == PHY_INTERFACE_MODE_RGMII_RXID) {
375 u16 reg;
376
377 /*
378 * There is no BCM5481 specification available, so down
379 * here is everything we know about "register 0x18". This
Joe Perchesbfb90352011-08-17 06:58:04 -0700380 * at least helps BCM5481 to successfully receive packets
Anton Vorontsov57bb7e22008-03-04 19:41:32 +0300381 * on MPC8360E-RDK board. Peter Barada <peterb@logicpd.com>
382 * says: "This sets delay between the RXD and RXC signals
383 * instead of using trace lengths to achieve timing".
384 */
385
386 /* Set RDX clk delay. */
387 reg = 0x7 | (0x7 << 12);
388 phy_write(phydev, 0x18, reg);
389
390 reg = phy_read(phydev, 0x18);
391 /* Set RDX-RXC skew. */
392 reg |= (1 << 8);
393 /* Write bits 14:0. */
394 reg |= (1 << 15);
395 phy_write(phydev, 0x18, reg);
396 }
397
398 return ret;
399}
400
Matt Carlsond7a2ed92009-08-25 10:10:58 +0000401static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
402{
403 int val;
404
405 val = phy_read(phydev, reg);
406 if (val < 0)
407 return val;
408
409 return phy_write(phydev, reg, val | set);
410}
411
412static int brcm_fet_config_init(struct phy_device *phydev)
413{
414 int reg, err, err2, brcmtest;
415
416 /* Reset the PHY to bring it to a known state. */
417 err = phy_write(phydev, MII_BMCR, BMCR_RESET);
418 if (err < 0)
419 return err;
420
421 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
422 if (reg < 0)
423 return reg;
424
425 /* Unmask events we are interested in and mask interrupts globally. */
426 reg = MII_BRCM_FET_IR_DUPLEX_EN |
427 MII_BRCM_FET_IR_SPEED_EN |
428 MII_BRCM_FET_IR_LINK_EN |
429 MII_BRCM_FET_IR_ENABLE |
430 MII_BRCM_FET_IR_MASK;
431
432 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
433 if (err < 0)
434 return err;
435
436 /* Enable shadow register access */
437 brcmtest = phy_read(phydev, MII_BRCM_FET_BRCMTEST);
438 if (brcmtest < 0)
439 return brcmtest;
440
441 reg = brcmtest | MII_BRCM_FET_BT_SRE;
442
443 err = phy_write(phydev, MII_BRCM_FET_BRCMTEST, reg);
444 if (err < 0)
445 return err;
446
447 /* Set the LED mode */
448 reg = phy_read(phydev, MII_BRCM_FET_SHDW_AUXMODE4);
449 if (reg < 0) {
450 err = reg;
451 goto done;
452 }
453
454 reg &= ~MII_BRCM_FET_SHDW_AM4_LED_MASK;
455 reg |= MII_BRCM_FET_SHDW_AM4_LED_MODE1;
456
457 err = phy_write(phydev, MII_BRCM_FET_SHDW_AUXMODE4, reg);
458 if (err < 0)
459 goto done;
460
461 /* Enable auto MDIX */
462 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_MISCCTRL,
463 MII_BRCM_FET_SHDW_MC_FAME);
464 if (err < 0)
465 goto done;
466
Matt Carlsoncdd4e09d2009-11-02 14:31:11 +0000467 if (phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE) {
468 /* Enable auto power down */
469 err = brcm_phy_setbits(phydev, MII_BRCM_FET_SHDW_AUXSTAT2,
470 MII_BRCM_FET_SHDW_AS2_APDE);
471 }
Matt Carlsond7a2ed92009-08-25 10:10:58 +0000472
473done:
474 /* Disable shadow register access */
475 err2 = phy_write(phydev, MII_BRCM_FET_BRCMTEST, brcmtest);
476 if (!err)
477 err = err2;
478
479 return err;
480}
481
482static int brcm_fet_ack_interrupt(struct phy_device *phydev)
483{
484 int reg;
485
486 /* Clear pending interrupts. */
487 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
488 if (reg < 0)
489 return reg;
490
491 return 0;
492}
493
494static int brcm_fet_config_intr(struct phy_device *phydev)
495{
496 int reg, err;
497
498 reg = phy_read(phydev, MII_BRCM_FET_INTREG);
499 if (reg < 0)
500 return reg;
501
502 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
503 reg &= ~MII_BRCM_FET_IR_MASK;
504 else
505 reg |= MII_BRCM_FET_IR_MASK;
506
507 err = phy_write(phydev, MII_BRCM_FET_INTREG, reg);
508 return err;
509}
510
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000511static struct phy_driver broadcom_drivers[] = {
512{
Dmitry Baryshkovfcb26ec2010-06-16 23:02:23 +0000513 .phy_id = PHY_ID_BCM5411,
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100514 .phy_id_mask = 0xfffffff0,
515 .name = "Broadcom BCM5411",
Matt Carlson5e0c6762008-11-03 16:56:07 -0800516 .features = PHY_GBIT_FEATURES |
517 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100518 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
519 .config_init = bcm54xx_config_init,
520 .config_aneg = genphy_config_aneg,
521 .read_status = genphy_read_status,
522 .ack_interrupt = bcm54xx_ack_interrupt,
523 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000524 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000525}, {
Dmitry Baryshkovfcb26ec2010-06-16 23:02:23 +0000526 .phy_id = PHY_ID_BCM5421,
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100527 .phy_id_mask = 0xfffffff0,
528 .name = "Broadcom BCM5421",
Matt Carlson5e0c6762008-11-03 16:56:07 -0800529 .features = PHY_GBIT_FEATURES |
530 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100531 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
532 .config_init = bcm54xx_config_init,
533 .config_aneg = genphy_config_aneg,
534 .read_status = genphy_read_status,
535 .ack_interrupt = bcm54xx_ack_interrupt,
536 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000537 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000538}, {
Dmitry Baryshkovfcb26ec2010-06-16 23:02:23 +0000539 .phy_id = PHY_ID_BCM5461,
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100540 .phy_id_mask = 0xfffffff0,
541 .name = "Broadcom BCM5461",
Matt Carlson5e0c6762008-11-03 16:56:07 -0800542 .features = PHY_GBIT_FEATURES |
543 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100544 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
545 .config_init = bcm54xx_config_init,
546 .config_aneg = genphy_config_aneg,
547 .read_status = genphy_read_status,
548 .ack_interrupt = bcm54xx_ack_interrupt,
549 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000550 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000551}, {
Dmitry Baryshkovfcb26ec2010-06-16 23:02:23 +0000552 .phy_id = PHY_ID_BCM5464,
Paul Gortmakerb1394f92008-04-14 23:35:41 -0400553 .phy_id_mask = 0xfffffff0,
554 .name = "Broadcom BCM5464",
Matt Carlson5e0c6762008-11-03 16:56:07 -0800555 .features = PHY_GBIT_FEATURES |
556 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
Paul Gortmakerb1394f92008-04-14 23:35:41 -0400557 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
558 .config_init = bcm54xx_config_init,
559 .config_aneg = genphy_config_aneg,
560 .read_status = genphy_read_status,
561 .ack_interrupt = bcm54xx_ack_interrupt,
562 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000563 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000564}, {
Dmitry Baryshkovfcb26ec2010-06-16 23:02:23 +0000565 .phy_id = PHY_ID_BCM5481,
Anton Vorontsov57bb7e22008-03-04 19:41:32 +0300566 .phy_id_mask = 0xfffffff0,
567 .name = "Broadcom BCM5481",
Matt Carlson5e0c6762008-11-03 16:56:07 -0800568 .features = PHY_GBIT_FEATURES |
569 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
Anton Vorontsov57bb7e22008-03-04 19:41:32 +0300570 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
571 .config_init = bcm54xx_config_init,
572 .config_aneg = bcm5481_config_aneg,
573 .read_status = genphy_read_status,
574 .ack_interrupt = bcm54xx_ack_interrupt,
575 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000576 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000577}, {
Dmitry Baryshkovfcb26ec2010-06-16 23:02:23 +0000578 .phy_id = PHY_ID_BCM5482,
Nate Case03157ac2008-01-29 10:19:00 -0600579 .phy_id_mask = 0xfffffff0,
580 .name = "Broadcom BCM5482",
Matt Carlson5e0c6762008-11-03 16:56:07 -0800581 .features = PHY_GBIT_FEATURES |
582 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
Nate Case03157ac2008-01-29 10:19:00 -0600583 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
Nate Casecd9af3d2008-05-17 06:40:39 +0100584 .config_init = bcm5482_config_init,
Nate Case03157ac2008-01-29 10:19:00 -0600585 .config_aneg = genphy_config_aneg,
Nate Casecd9af3d2008-05-17 06:40:39 +0100586 .read_status = bcm5482_read_status,
Nate Case03157ac2008-01-29 10:19:00 -0600587 .ack_interrupt = bcm54xx_ack_interrupt,
588 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000589 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000590}, {
Matt Carlson772638b2008-11-03 16:56:51 -0800591 .phy_id = PHY_ID_BCM50610,
592 .phy_id_mask = 0xfffffff0,
593 .name = "Broadcom BCM50610",
594 .features = PHY_GBIT_FEATURES |
595 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
596 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
597 .config_init = bcm54xx_config_init,
598 .config_aneg = genphy_config_aneg,
599 .read_status = genphy_read_status,
600 .ack_interrupt = bcm54xx_ack_interrupt,
601 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000602 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000603}, {
Matt Carlson4f4598f2009-08-25 10:10:30 +0000604 .phy_id = PHY_ID_BCM50610M,
605 .phy_id_mask = 0xfffffff0,
606 .name = "Broadcom BCM50610M",
607 .features = PHY_GBIT_FEATURES |
608 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
609 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
610 .config_init = bcm54xx_config_init,
611 .config_aneg = genphy_config_aneg,
612 .read_status = genphy_read_status,
613 .ack_interrupt = bcm54xx_ack_interrupt,
614 .config_intr = bcm54xx_config_intr,
615 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000616}, {
Matt Carlsond9221e62009-08-25 10:11:26 +0000617 .phy_id = PHY_ID_BCM57780,
Matt Carlson2fbb69a2008-11-21 17:22:53 -0800618 .phy_id_mask = 0xfffffff0,
619 .name = "Broadcom BCM57780",
620 .features = PHY_GBIT_FEATURES |
621 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
622 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
623 .config_init = bcm54xx_config_init,
624 .config_aneg = genphy_config_aneg,
625 .read_status = genphy_read_status,
626 .ack_interrupt = bcm54xx_ack_interrupt,
627 .config_intr = bcm54xx_config_intr,
Matt Carlson4f4598f2009-08-25 10:10:30 +0000628 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000629}, {
Matt Carlson6a443a02010-02-17 15:17:04 +0000630 .phy_id = PHY_ID_BCMAC131,
Matt Carlsond7a2ed92009-08-25 10:10:58 +0000631 .phy_id_mask = 0xfffffff0,
632 .name = "Broadcom BCMAC131",
633 .features = PHY_BASIC_FEATURES |
634 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
635 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
636 .config_init = brcm_fet_config_init,
637 .config_aneg = genphy_config_aneg,
638 .read_status = genphy_read_status,
639 .ack_interrupt = brcm_fet_ack_interrupt,
640 .config_intr = brcm_fet_config_intr,
641 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000642}, {
Dmitry Baryshkov7a938f82010-06-16 23:02:24 +0000643 .phy_id = PHY_ID_BCM5241,
644 .phy_id_mask = 0xfffffff0,
645 .name = "Broadcom BCM5241",
646 .features = PHY_BASIC_FEATURES |
647 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
648 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
649 .config_init = brcm_fet_config_init,
650 .config_aneg = genphy_config_aneg,
651 .read_status = genphy_read_status,
652 .ack_interrupt = brcm_fet_ack_interrupt,
653 .config_intr = brcm_fet_config_intr,
654 .driver = { .owner = THIS_MODULE },
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000655} };
Dmitry Baryshkov7a938f82010-06-16 23:02:24 +0000656
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100657static int __init broadcom_init(void)
658{
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000659 return phy_drivers_register(broadcom_drivers,
660 ARRAY_SIZE(broadcom_drivers));
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100661}
662
663static void __exit broadcom_exit(void)
664{
Christian Hohnstaedtd5bf9072012-07-04 05:44:34 +0000665 phy_drivers_unregister(broadcom_drivers,
666 ARRAY_SIZE(broadcom_drivers));
Maciej W. Rozyckic4b41c92006-10-03 16:18:13 +0100667}
668
669module_init(broadcom_init);
670module_exit(broadcom_exit);
David Woodhouse4e4f10f2010-04-02 01:05:56 +0000671
Uwe Kleine-Königcf93c942010-10-03 23:43:32 +0000672static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
Dmitry Baryshkovfcb26ec2010-06-16 23:02:23 +0000673 { PHY_ID_BCM5411, 0xfffffff0 },
674 { PHY_ID_BCM5421, 0xfffffff0 },
675 { PHY_ID_BCM5461, 0xfffffff0 },
676 { PHY_ID_BCM5464, 0xfffffff0 },
677 { PHY_ID_BCM5482, 0xfffffff0 },
678 { PHY_ID_BCM5482, 0xfffffff0 },
David Woodhouse4e4f10f2010-04-02 01:05:56 +0000679 { PHY_ID_BCM50610, 0xfffffff0 },
680 { PHY_ID_BCM50610M, 0xfffffff0 },
681 { PHY_ID_BCM57780, 0xfffffff0 },
682 { PHY_ID_BCMAC131, 0xfffffff0 },
Dmitry Baryshkov7a938f82010-06-16 23:02:24 +0000683 { PHY_ID_BCM5241, 0xfffffff0 },
David Woodhouse4e4f10f2010-04-02 01:05:56 +0000684 { }
685};
686
687MODULE_DEVICE_TABLE(mdio, broadcom_tbl);