aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy')
-rw-r--r--drivers/net/phy/Kconfig23
-rw-r--r--drivers/net/phy/Makefile5
-rw-r--r--drivers/net/phy/broadcom.c216
-rw-r--r--drivers/net/phy/et1011c.c113
-rw-r--r--drivers/net/phy/mdio-gpio.c296
-rw-r--r--drivers/net/phy/mdio-ofgpio.c204
-rw-r--r--drivers/net/phy/mdio_bus.c18
-rw-r--r--drivers/net/phy/national.c155
-rw-r--r--drivers/net/phy/phy.c2
-rw-r--r--drivers/net/phy/phy_device.c52
-rw-r--r--drivers/net/phy/smsc.c28
-rw-r--r--drivers/net/phy/ste10Xp.c137
12 files changed, 983 insertions, 266 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index d55932acd887..de9cf5136fdc 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -66,6 +66,22 @@ config REALTEK_PHY
66 ---help--- 66 ---help---
67 Supports the Realtek 821x PHY. 67 Supports the Realtek 821x PHY.
68 68
69config NATIONAL_PHY
70 tristate "Drivers for National Semiconductor PHYs"
71 ---help---
72 Currently supports the DP83865 PHY.
73
74config STE10XP
75 depends on PHYLIB
76 tristate "Driver for STMicroelectronics STe10Xp PHYs"
77 ---help---
78 This is the driver for the STe100p and STe101p PHYs.
79
80config LSI_ET1011C_PHY
81 tristate "Driver for LSI ET1011C PHY"
82 ---help---
83 Supports the LSI ET1011C PHY.
84
69config FIXED_PHY 85config FIXED_PHY
70 bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" 86 bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
71 depends on PHYLIB=y 87 depends on PHYLIB=y
@@ -84,10 +100,13 @@ config MDIO_BITBANG
84 100
85 If in doubt, say N. 101 If in doubt, say N.
86 102
87config MDIO_OF_GPIO 103config MDIO_GPIO
88 tristate "Support for GPIO lib-based bitbanged MDIO buses" 104 tristate "Support for GPIO lib-based bitbanged MDIO buses"
89 depends on MDIO_BITBANG && OF_GPIO 105 depends on MDIO_BITBANG && GENERIC_GPIO
90 ---help--- 106 ---help---
91 Supports GPIO lib-based MDIO busses. 107 Supports GPIO lib-based MDIO busses.
92 108
109 To compile this driver as a module, choose M here: the module
110 will be called mdio-gpio.
111
93endif # PHYLIB 112endif # PHYLIB
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index eee329fa6f53..3a1bfefefbc3 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,6 +13,9 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o
13obj-$(CONFIG_BROADCOM_PHY) += broadcom.o 13obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
14obj-$(CONFIG_ICPLUS_PHY) += icplus.o 14obj-$(CONFIG_ICPLUS_PHY) += icplus.o
15obj-$(CONFIG_REALTEK_PHY) += realtek.o 15obj-$(CONFIG_REALTEK_PHY) += realtek.o
16obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o
16obj-$(CONFIG_FIXED_PHY) += fixed.o 17obj-$(CONFIG_FIXED_PHY) += fixed.o
17obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o 18obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
18obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o 19obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
20obj-$(CONFIG_NATIONAL_PHY) += national.o
21obj-$(CONFIG_STE10XP) += ste10Xp.o
diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c
index 4b4dc98ad165..190efc3301c6 100644
--- a/drivers/net/phy/broadcom.c
+++ b/drivers/net/phy/broadcom.c
@@ -17,6 +17,8 @@
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/phy.h> 18#include <linux/phy.h>
19 19
20#define PHY_ID_BCM50610 0x0143bd60
21
20#define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ 22#define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */
21#define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ 23#define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */
22#define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ 24#define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */
@@ -54,6 +56,21 @@
54#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) 56#define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0)
55 57
56/* 58/*
59 * AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18)
60 */
61#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
62#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400
63#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800
64
65#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
66#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
67#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
68#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
69
70#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
71
72
73/*
57 * Broadcom LED source encodings. These are used in BCM5461, BCM5481, 74 * Broadcom LED source encodings. These are used in BCM5461, BCM5481,
58 * BCM5482, and possibly some others. 75 * BCM5482, and possibly some others.
59 */ 76 */
@@ -88,6 +105,24 @@
88#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ 105#define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */
89 106
90/* 107/*
108 * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17)
109 */
110#define MII_BCM54XX_EXP_AADJ1CH0 0x001f
111#define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200
112#define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100
113#define MII_BCM54XX_EXP_AADJ1CH3 0x601f
114#define MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ 0x0002
115#define MII_BCM54XX_EXP_EXP08 0x0F08
116#define MII_BCM54XX_EXP_EXP08_RJCT_2MHZ 0x0001
117#define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200
118#define MII_BCM54XX_EXP_EXP75 0x0f75
119#define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c
120#define MII_BCM54XX_EXP_EXP96 0x0f96
121#define MII_BCM54XX_EXP_EXP96_MYST 0x0010
122#define MII_BCM54XX_EXP_EXP97 0x0f97
123#define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c
124
125/*
91 * BCM5482: Secondary SerDes registers 126 * BCM5482: Secondary SerDes registers
92 */ 127 */
93#define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */ 128#define BCM5482_SSD_1000BX_CTL 0x00 /* 1000BASE-X Control */
@@ -128,40 +163,93 @@ static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val)
128 MII_BCM54XX_SHD_DATA(val)); 163 MII_BCM54XX_SHD_DATA(val));
129} 164}
130 165
131/* 166/* Indirect register access functions for the Expansion Registers */
132 * Indirect register access functions for the Expansion Registers 167static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum)
133 * and Secondary SerDes registers (when sec_serdes=1).
134 */
135static int bcm54xx_exp_read(struct phy_device *phydev,
136 int sec_serdes, u8 regnum)
137{ 168{
138 int val; 169 int val;
139 170
140 phy_write(phydev, MII_BCM54XX_EXP_SEL, 171 val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
141 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : 172 if (val < 0)
142 MII_BCM54XX_EXP_SEL_ER) | 173 return val;
143 regnum); 174
144 val = phy_read(phydev, MII_BCM54XX_EXP_DATA); 175 val = phy_read(phydev, MII_BCM54XX_EXP_DATA);
145 phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); 176
177 /* Restore default value. It's O.K. if this write fails. */
178 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
146 179
147 return val; 180 return val;
148} 181}
149 182
150static int bcm54xx_exp_write(struct phy_device *phydev, 183static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val)
151 int sec_serdes, u8 regnum, u16 val)
152{ 184{
153 int ret; 185 int ret;
154 186
155 phy_write(phydev, MII_BCM54XX_EXP_SEL, 187 ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum);
156 (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : 188 if (ret < 0)
157 MII_BCM54XX_EXP_SEL_ER) | 189 return ret;
158 regnum); 190
159 ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val); 191 ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val);
160 phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); 192
193 /* Restore default value. It's O.K. if this write fails. */
194 phy_write(phydev, MII_BCM54XX_EXP_SEL, 0);
161 195
162 return ret; 196 return ret;
163} 197}
164 198
199static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
200{
201 return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
202}
203
204static int bcm50610_a0_workaround(struct phy_device *phydev)
205{
206 int err;
207
208 err = bcm54xx_auxctl_write(phydev,
209 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
210 MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA |
211 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
212 if (err < 0)
213 return err;
214
215 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08,
216 MII_BCM54XX_EXP_EXP08_RJCT_2MHZ |
217 MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE);
218 if (err < 0)
219 goto error;
220
221 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0,
222 MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN |
223 MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF);
224 if (err < 0)
225 goto error;
226
227 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3,
228 MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ);
229 if (err < 0)
230 goto error;
231
232 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75,
233 MII_BCM54XX_EXP_EXP75_VDACCTRL);
234 if (err < 0)
235 goto error;
236
237 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96,
238 MII_BCM54XX_EXP_EXP96_MYST);
239 if (err < 0)
240 goto error;
241
242 err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97,
243 MII_BCM54XX_EXP_EXP97_MYST);
244
245error:
246 bcm54xx_auxctl_write(phydev,
247 MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL,
248 MII_BCM54XX_AUXCTL_ACTL_TX_6DB);
249
250 return err;
251}
252
165static int bcm54xx_config_init(struct phy_device *phydev) 253static int bcm54xx_config_init(struct phy_device *phydev)
166{ 254{
167 int reg, err; 255 int reg, err;
@@ -183,6 +271,13 @@ static int bcm54xx_config_init(struct phy_device *phydev)
183 err = phy_write(phydev, MII_BCM54XX_IMR, reg); 271 err = phy_write(phydev, MII_BCM54XX_IMR, reg);
184 if (err < 0) 272 if (err < 0)
185 return err; 273 return err;
274
275 if (phydev->drv->phy_id == PHY_ID_BCM50610) {
276 err = bcm50610_a0_workaround(phydev);
277 if (err < 0)
278 return err;
279 }
280
186 return 0; 281 return 0;
187} 282}
188 283
@@ -205,18 +300,27 @@ static int bcm5482_config_init(struct phy_device *phydev)
205 /* 300 /*
206 * Enable SGMII slave mode and auto-detection 301 * Enable SGMII slave mode and auto-detection
207 */ 302 */
208 reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE); 303 reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD;
209 bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE, 304 err = bcm54xx_exp_read(phydev, reg);
210 reg | 305 if (err < 0)
211 BCM5482_SSD_SGMII_SLAVE_EN | 306 return err;
212 BCM5482_SSD_SGMII_SLAVE_AD); 307 err = bcm54xx_exp_write(phydev, reg, err |
308 BCM5482_SSD_SGMII_SLAVE_EN |
309 BCM5482_SSD_SGMII_SLAVE_AD);
310 if (err < 0)
311 return err;
213 312
214 /* 313 /*
215 * Disable secondary SerDes powerdown 314 * Disable secondary SerDes powerdown
216 */ 315 */
217 reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL); 316 reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD;
218 bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL, 317 err = bcm54xx_exp_read(phydev, reg);
219 reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); 318 if (err < 0)
319 return err;
320 err = bcm54xx_exp_write(phydev, reg,
321 err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN);
322 if (err < 0)
323 return err;
220 324
221 /* 325 /*
222 * Select 1000BASE-X register set (primary SerDes) 326 * Select 1000BASE-X register set (primary SerDes)
@@ -335,7 +439,8 @@ static struct phy_driver bcm5411_driver = {
335 .phy_id = 0x00206070, 439 .phy_id = 0x00206070,
336 .phy_id_mask = 0xfffffff0, 440 .phy_id_mask = 0xfffffff0,
337 .name = "Broadcom BCM5411", 441 .name = "Broadcom BCM5411",
338 .features = PHY_GBIT_FEATURES, 442 .features = PHY_GBIT_FEATURES |
443 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
339 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 444 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
340 .config_init = bcm54xx_config_init, 445 .config_init = bcm54xx_config_init,
341 .config_aneg = genphy_config_aneg, 446 .config_aneg = genphy_config_aneg,
@@ -349,7 +454,8 @@ static struct phy_driver bcm5421_driver = {
349 .phy_id = 0x002060e0, 454 .phy_id = 0x002060e0,
350 .phy_id_mask = 0xfffffff0, 455 .phy_id_mask = 0xfffffff0,
351 .name = "Broadcom BCM5421", 456 .name = "Broadcom BCM5421",
352 .features = PHY_GBIT_FEATURES, 457 .features = PHY_GBIT_FEATURES |
458 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
353 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 459 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
354 .config_init = bcm54xx_config_init, 460 .config_init = bcm54xx_config_init,
355 .config_aneg = genphy_config_aneg, 461 .config_aneg = genphy_config_aneg,
@@ -363,7 +469,8 @@ static struct phy_driver bcm5461_driver = {
363 .phy_id = 0x002060c0, 469 .phy_id = 0x002060c0,
364 .phy_id_mask = 0xfffffff0, 470 .phy_id_mask = 0xfffffff0,
365 .name = "Broadcom BCM5461", 471 .name = "Broadcom BCM5461",
366 .features = PHY_GBIT_FEATURES, 472 .features = PHY_GBIT_FEATURES |
473 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
367 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 474 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
368 .config_init = bcm54xx_config_init, 475 .config_init = bcm54xx_config_init,
369 .config_aneg = genphy_config_aneg, 476 .config_aneg = genphy_config_aneg,
@@ -377,7 +484,8 @@ static struct phy_driver bcm5464_driver = {
377 .phy_id = 0x002060b0, 484 .phy_id = 0x002060b0,
378 .phy_id_mask = 0xfffffff0, 485 .phy_id_mask = 0xfffffff0,
379 .name = "Broadcom BCM5464", 486 .name = "Broadcom BCM5464",
380 .features = PHY_GBIT_FEATURES, 487 .features = PHY_GBIT_FEATURES |
488 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
381 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 489 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
382 .config_init = bcm54xx_config_init, 490 .config_init = bcm54xx_config_init,
383 .config_aneg = genphy_config_aneg, 491 .config_aneg = genphy_config_aneg,
@@ -391,7 +499,8 @@ static struct phy_driver bcm5481_driver = {
391 .phy_id = 0x0143bca0, 499 .phy_id = 0x0143bca0,
392 .phy_id_mask = 0xfffffff0, 500 .phy_id_mask = 0xfffffff0,
393 .name = "Broadcom BCM5481", 501 .name = "Broadcom BCM5481",
394 .features = PHY_GBIT_FEATURES, 502 .features = PHY_GBIT_FEATURES |
503 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
395 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 504 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
396 .config_init = bcm54xx_config_init, 505 .config_init = bcm54xx_config_init,
397 .config_aneg = bcm5481_config_aneg, 506 .config_aneg = bcm5481_config_aneg,
@@ -405,7 +514,8 @@ static struct phy_driver bcm5482_driver = {
405 .phy_id = 0x0143bcb0, 514 .phy_id = 0x0143bcb0,
406 .phy_id_mask = 0xfffffff0, 515 .phy_id_mask = 0xfffffff0,
407 .name = "Broadcom BCM5482", 516 .name = "Broadcom BCM5482",
408 .features = PHY_GBIT_FEATURES, 517 .features = PHY_GBIT_FEATURES |
518 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
409 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, 519 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
410 .config_init = bcm5482_config_init, 520 .config_init = bcm5482_config_init,
411 .config_aneg = genphy_config_aneg, 521 .config_aneg = genphy_config_aneg,
@@ -415,6 +525,36 @@ static struct phy_driver bcm5482_driver = {
415 .driver = { .owner = THIS_MODULE }, 525 .driver = { .owner = THIS_MODULE },
416}; 526};
417 527
528static struct phy_driver bcm50610_driver = {
529 .phy_id = PHY_ID_BCM50610,
530 .phy_id_mask = 0xfffffff0,
531 .name = "Broadcom BCM50610",
532 .features = PHY_GBIT_FEATURES |
533 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
534 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
535 .config_init = bcm54xx_config_init,
536 .config_aneg = genphy_config_aneg,
537 .read_status = genphy_read_status,
538 .ack_interrupt = bcm54xx_ack_interrupt,
539 .config_intr = bcm54xx_config_intr,
540 .driver = { .owner = THIS_MODULE },
541};
542
543static struct phy_driver bcm57780_driver = {
544 .phy_id = 0x03625d90,
545 .phy_id_mask = 0xfffffff0,
546 .name = "Broadcom BCM57780",
547 .features = PHY_GBIT_FEATURES |
548 SUPPORTED_Pause | SUPPORTED_Asym_Pause,
549 .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
550 .config_init = bcm54xx_config_init,
551 .config_aneg = genphy_config_aneg,
552 .read_status = genphy_read_status,
553 .ack_interrupt = bcm54xx_ack_interrupt,
554 .config_intr = bcm54xx_config_intr,
555 .driver = { .owner = THIS_MODULE },
556};
557
418static int __init broadcom_init(void) 558static int __init broadcom_init(void)
419{ 559{
420 int ret; 560 int ret;
@@ -437,8 +577,18 @@ static int __init broadcom_init(void)
437 ret = phy_driver_register(&bcm5482_driver); 577 ret = phy_driver_register(&bcm5482_driver);
438 if (ret) 578 if (ret)
439 goto out_5482; 579 goto out_5482;
580 ret = phy_driver_register(&bcm50610_driver);
581 if (ret)
582 goto out_50610;
583 ret = phy_driver_register(&bcm57780_driver);
584 if (ret)
585 goto out_57780;
440 return ret; 586 return ret;
441 587
588out_57780:
589 phy_driver_unregister(&bcm50610_driver);
590out_50610:
591 phy_driver_unregister(&bcm5482_driver);
442out_5482: 592out_5482:
443 phy_driver_unregister(&bcm5481_driver); 593 phy_driver_unregister(&bcm5481_driver);
444out_5481: 594out_5481:
@@ -455,6 +605,8 @@ out_5411:
455 605
456static void __exit broadcom_exit(void) 606static void __exit broadcom_exit(void)
457{ 607{
608 phy_driver_unregister(&bcm57780_driver);
609 phy_driver_unregister(&bcm50610_driver);
458 phy_driver_unregister(&bcm5482_driver); 610 phy_driver_unregister(&bcm5482_driver);
459 phy_driver_unregister(&bcm5481_driver); 611 phy_driver_unregister(&bcm5481_driver);
460 phy_driver_unregister(&bcm5464_driver); 612 phy_driver_unregister(&bcm5464_driver);
diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c
new file mode 100644
index 000000000000..b031fa21f1aa
--- /dev/null
+++ b/drivers/net/phy/et1011c.c
@@ -0,0 +1,113 @@
1/*
2 * drivers/net/phy/et1011c.c
3 *
4 * Driver for LSI ET1011C PHYs
5 *
6 * Author: Chaithrika U S
7 *
8 * Copyright (c) 2008 Texas Instruments
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/slab.h>
21#include <linux/interrupt.h>
22#include <linux/init.h>
23#include <linux/delay.h>
24#include <linux/netdevice.h>
25#include <linux/etherdevice.h>
26#include <linux/skbuff.h>
27#include <linux/spinlock.h>
28#include <linux/mm.h>
29#include <linux/module.h>
30#include <linux/mii.h>
31#include <linux/ethtool.h>
32#include <linux/phy.h>
33#include <linux/io.h>
34#include <linux/uaccess.h>
35#include <asm/irq.h>
36
37#define ET1011C_STATUS_REG (0x1A)
38#define ET1011C_CONFIG_REG (0x16)
39#define ET1011C_SPEED_MASK (0x0300)
40#define ET1011C_GIGABIT_SPEED (0x0200)
41#define ET1011C_TX_FIFO_MASK (0x3000)
42#define ET1011C_TX_FIFO_DEPTH_8 (0x0000)
43#define ET1011C_TX_FIFO_DEPTH_16 (0x1000)
44#define ET1011C_INTERFACE_MASK (0x0007)
45#define ET1011C_GMII_INTERFACE (0x0002)
46#define ET1011C_SYS_CLK_EN (0x01 << 4)
47
48
49MODULE_DESCRIPTION("LSI ET1011C PHY driver");
50MODULE_AUTHOR("Chaithrika U S");
51MODULE_LICENSE("GPL");
52
53static int et1011c_config_aneg(struct phy_device *phydev)
54{
55 int ctl = 0;
56 ctl = phy_read(phydev, MII_BMCR);
57 if (ctl < 0)
58 return ctl;
59 ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 |
60 BMCR_ANENABLE);
61 /* First clear the PHY */
62 phy_write(phydev, MII_BMCR, ctl | BMCR_RESET);
63
64 return genphy_config_aneg(phydev);
65}
66
67static int et1011c_read_status(struct phy_device *phydev)
68{
69 int ret;
70 u32 val;
71 static int speed;
72 ret = genphy_read_status(phydev);
73
74 if (speed != phydev->speed) {
75 speed = phydev->speed;
76 val = phy_read(phydev, ET1011C_STATUS_REG);
77 if ((val & ET1011C_SPEED_MASK) ==
78 ET1011C_GIGABIT_SPEED) {
79 val = phy_read(phydev, ET1011C_CONFIG_REG);
80 val &= ~ET1011C_TX_FIFO_MASK;
81 phy_write(phydev, ET1011C_CONFIG_REG, val\
82 | ET1011C_GMII_INTERFACE\
83 | ET1011C_SYS_CLK_EN\
84 | ET1011C_TX_FIFO_DEPTH_16);
85
86 }
87 }
88 return ret;
89}
90
91static struct phy_driver et1011c_driver = {
92 .phy_id = 0x0282f014,
93 .name = "ET1011C",
94 .phy_id_mask = 0xfffffff0,
95 .features = (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full),
96 .flags = PHY_POLL,
97 .config_aneg = et1011c_config_aneg,
98 .read_status = et1011c_read_status,
99 .driver = { .owner = THIS_MODULE,},
100};
101
102static int __init et1011c_init(void)
103{
104 return phy_driver_register(&et1011c_driver);
105}
106
107static void __exit et1011c_exit(void)
108{
109 phy_driver_unregister(&et1011c_driver);
110}
111
112module_init(et1011c_init);
113module_exit(et1011c_exit);
diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c
new file mode 100644
index 000000000000..a439ebeb4319
--- /dev/null
+++ b/drivers/net/phy/mdio-gpio.c
@@ -0,0 +1,296 @@
1/*
2 * GPIO based MDIO bitbang driver.
3 * Supports OpenFirmware.
4 *
5 * Copyright (c) 2008 CSE Semaphore Belgium.
6 * by Laurent Pinchart <laurentp@cse-semaphore.com>
7 *
8 * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
9 *
10 * Based on earlier work by
11 *
12 * Copyright (c) 2003 Intracom S.A.
13 * by Pantelis Antoniou <panto@intracom.gr>
14 *
15 * 2005 (c) MontaVista Software, Inc.
16 * Vitaly Bordug <vbordug@ru.mvista.com>
17 *
18 * This file is licensed under the terms of the GNU General Public License
19 * version 2. This program is licensed "as is" without any warranty of any
20 * kind, whether express or implied.
21 */
22
23#include <linux/module.h>
24#include <linux/slab.h>
25#include <linux/init.h>
26#include <linux/interrupt.h>
27#include <linux/platform_device.h>
28#include <linux/gpio.h>
29#include <linux/mdio-gpio.h>
30
31#ifdef CONFIG_OF_GPIO
32#include <linux/of_gpio.h>
33#include <linux/of_platform.h>
34#endif
35
36struct mdio_gpio_info {
37 struct mdiobb_ctrl ctrl;
38 int mdc, mdio;
39};
40
41static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
42{
43 struct mdio_gpio_info *bitbang =
44 container_of(ctrl, struct mdio_gpio_info, ctrl);
45
46 if (dir)
47 gpio_direction_output(bitbang->mdio, 1);
48 else
49 gpio_direction_input(bitbang->mdio);
50}
51
52static int mdio_get(struct mdiobb_ctrl *ctrl)
53{
54 struct mdio_gpio_info *bitbang =
55 container_of(ctrl, struct mdio_gpio_info, ctrl);
56
57 return gpio_get_value(bitbang->mdio);
58}
59
60static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
61{
62 struct mdio_gpio_info *bitbang =
63 container_of(ctrl, struct mdio_gpio_info, ctrl);
64
65 gpio_set_value(bitbang->mdio, what);
66}
67
68static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
69{
70 struct mdio_gpio_info *bitbang =
71 container_of(ctrl, struct mdio_gpio_info, ctrl);
72
73 gpio_set_value(bitbang->mdc, what);
74}
75
76static struct mdiobb_ops mdio_gpio_ops = {
77 .owner = THIS_MODULE,
78 .set_mdc = mdc_set,
79 .set_mdio_dir = mdio_dir,
80 .set_mdio_data = mdio_set,
81 .get_mdio_data = mdio_get,
82};
83
84static int __devinit mdio_gpio_bus_init(struct device *dev,
85 struct mdio_gpio_platform_data *pdata,
86 int bus_id)
87{
88 struct mii_bus *new_bus;
89 struct mdio_gpio_info *bitbang;
90 int ret = -ENOMEM;
91 int i;
92
93 bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL);
94 if (!bitbang)
95 goto out;
96
97 bitbang->ctrl.ops = &mdio_gpio_ops;
98 bitbang->mdc = pdata->mdc;
99 bitbang->mdio = pdata->mdio;
100
101 new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
102 if (!new_bus)
103 goto out_free_bitbang;
104
105 new_bus->name = "GPIO Bitbanged MDIO",
106
107 ret = -ENODEV;
108
109 new_bus->phy_mask = pdata->phy_mask;
110 new_bus->irq = pdata->irqs;
111 new_bus->parent = dev;
112
113 if (new_bus->phy_mask == ~0)
114 goto out_free_bus;
115
116 for (i = 0; i < PHY_MAX_ADDR; i++)
117 if (!new_bus->irq[i])
118 new_bus->irq[i] = PHY_POLL;
119
120 snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id);
121
122 if (gpio_request(bitbang->mdc, "mdc"))
123 goto out_free_bus;
124
125 if (gpio_request(bitbang->mdio, "mdio"))
126 goto out_free_mdc;
127
128 dev_set_drvdata(dev, new_bus);
129
130 ret = mdiobus_register(new_bus);
131 if (ret)
132 goto out_free_all;
133
134 return 0;
135
136out_free_all:
137 dev_set_drvdata(dev, NULL);
138 gpio_free(bitbang->mdio);
139out_free_mdc:
140 gpio_free(bitbang->mdc);
141out_free_bus:
142 free_mdio_bitbang(new_bus);
143out_free_bitbang:
144 kfree(bitbang);
145out:
146 return ret;
147}
148
149static void __devexit mdio_gpio_bus_destroy(struct device *dev)
150{
151 struct mii_bus *bus = dev_get_drvdata(dev);
152 struct mdio_gpio_info *bitbang = bus->priv;
153
154 mdiobus_unregister(bus);
155 free_mdio_bitbang(bus);
156 dev_set_drvdata(dev, NULL);
157 gpio_free(bitbang->mdc);
158 gpio_free(bitbang->mdio);
159 kfree(bitbang);
160}
161
162static int __devinit mdio_gpio_probe(struct platform_device *pdev)
163{
164 struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data;
165
166 if (!pdata)
167 return -ENODEV;
168
169 return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id);
170}
171
172static int __devexit mdio_gpio_remove(struct platform_device *pdev)
173{
174 mdio_gpio_bus_destroy(&pdev->dev);
175
176 return 0;
177}
178
179#ifdef CONFIG_OF_GPIO
180static void __devinit add_phy(struct mdio_gpio_platform_data *pdata,
181 struct device_node *np)
182{
183 const u32 *data;
184 int len, id, irq;
185
186 data = of_get_property(np, "reg", &len);
187 if (!data || len != 4)
188 return;
189
190 id = *data;
191 pdata->phy_mask &= ~(1 << id);
192
193 irq = of_irq_to_resource(np, 0, NULL);
194 if (irq)
195 pdata->irqs[id] = irq;
196}
197
198static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
199 const struct of_device_id *match)
200{
201 struct device_node *np = NULL;
202 struct mdio_gpio_platform_data *pdata;
203
204 pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
205 if (!pdata)
206 return -ENOMEM;
207
208 pdata->mdc = of_get_gpio(ofdev->node, 0);
209 pdata->mdio = of_get_gpio(ofdev->node, 1);
210
211 if (pdata->mdc < 0 || pdata->mdio < 0)
212 goto out_free;
213
214 while ((np = of_get_next_child(ofdev->node, np)))
215 if (!strcmp(np->type, "ethernet-phy"))
216 add_phy(pdata, np);
217
218 return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc);
219
220out_free:
221 kfree(pdata);
222 return -ENODEV;
223}
224
225static int __devexit mdio_ofgpio_remove(struct of_device *ofdev)
226{
227 mdio_gpio_bus_destroy(&ofdev->dev);
228 kfree(ofdev->dev.platform_data);
229
230 return 0;
231}
232
233static struct of_device_id mdio_ofgpio_match[] = {
234 {
235 .compatible = "virtual,mdio-gpio",
236 },
237 {},
238};
239
240static struct of_platform_driver mdio_ofgpio_driver = {
241 .name = "mdio-gpio",
242 .match_table = mdio_ofgpio_match,
243 .probe = mdio_ofgpio_probe,
244 .remove = __devexit_p(mdio_ofgpio_remove),
245};
246
247static inline int __init mdio_ofgpio_init(void)
248{
249 return of_register_platform_driver(&mdio_ofgpio_driver);
250}
251
252static inline void __exit mdio_ofgpio_exit(void)
253{
254 of_unregister_platform_driver(&mdio_ofgpio_driver);
255}
256#else
257static inline int __init mdio_ofgpio_init(void) { return 0; }
258static inline void __exit mdio_ofgpio_exit(void) { }
259#endif /* CONFIG_OF_GPIO */
260
261static struct platform_driver mdio_gpio_driver = {
262 .probe = mdio_gpio_probe,
263 .remove = __devexit_p(mdio_gpio_remove),
264 .driver = {
265 .name = "mdio-gpio",
266 .owner = THIS_MODULE,
267 },
268};
269
270static int __init mdio_gpio_init(void)
271{
272 int ret;
273
274 ret = mdio_ofgpio_init();
275 if (ret)
276 return ret;
277
278 ret = platform_driver_register(&mdio_gpio_driver);
279 if (ret)
280 mdio_ofgpio_exit();
281
282 return ret;
283}
284module_init(mdio_gpio_init);
285
286static void __exit mdio_gpio_exit(void)
287{
288 platform_driver_unregister(&mdio_gpio_driver);
289 mdio_ofgpio_exit();
290}
291module_exit(mdio_gpio_exit);
292
293MODULE_ALIAS("platform:mdio-gpio");
294MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas");
295MODULE_LICENSE("GPL");
296MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO");
diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c
deleted file mode 100644
index 2ff97754e574..000000000000
--- a/drivers/net/phy/mdio-ofgpio.c
+++ /dev/null
@@ -1,204 +0,0 @@
1/*
2 * OpenFirmware GPIO based MDIO bitbang driver.
3 *
4 * Copyright (c) 2008 CSE Semaphore Belgium.
5 * by Laurent Pinchart <laurentp@cse-semaphore.com>
6 *
7 * Based on earlier work by
8 *
9 * Copyright (c) 2003 Intracom S.A.
10 * by Pantelis Antoniou <panto@intracom.gr>
11 *
12 * 2005 (c) MontaVista Software, Inc.
13 * Vitaly Bordug <vbordug@ru.mvista.com>
14 *
15 * This file is licensed under the terms of the GNU General Public License
16 * version 2. This program is licensed "as is" without any warranty of any
17 * kind, whether express or implied.
18 */
19
20#include <linux/module.h>
21#include <linux/slab.h>
22#include <linux/init.h>
23#include <linux/interrupt.h>
24#include <linux/mdio-bitbang.h>
25#include <linux/of_gpio.h>
26#include <linux/of_platform.h>
27
28struct mdio_gpio_info {
29 struct mdiobb_ctrl ctrl;
30 int mdc, mdio;
31};
32
33static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
34{
35 struct mdio_gpio_info *bitbang =
36 container_of(ctrl, struct mdio_gpio_info, ctrl);
37
38 if (dir)
39 gpio_direction_output(bitbang->mdio, 1);
40 else
41 gpio_direction_input(bitbang->mdio);
42}
43
44static int mdio_read(struct mdiobb_ctrl *ctrl)
45{
46 struct mdio_gpio_info *bitbang =
47 container_of(ctrl, struct mdio_gpio_info, ctrl);
48
49 return gpio_get_value(bitbang->mdio);
50}
51
52static void mdio(struct mdiobb_ctrl *ctrl, int what)
53{
54 struct mdio_gpio_info *bitbang =
55 container_of(ctrl, struct mdio_gpio_info, ctrl);
56
57 gpio_set_value(bitbang->mdio, what);
58}
59
60static void mdc(struct mdiobb_ctrl *ctrl, int what)
61{
62 struct mdio_gpio_info *bitbang =
63 container_of(ctrl, struct mdio_gpio_info, ctrl);
64
65 gpio_set_value(bitbang->mdc, what);
66}
67
68static struct mdiobb_ops mdio_gpio_ops = {
69 .owner = THIS_MODULE,
70 .set_mdc = mdc,
71 .set_mdio_dir = mdio_dir,
72 .set_mdio_data = mdio,
73 .get_mdio_data = mdio_read,
74};
75
76static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus,
77 struct device_node *np)
78{
79 struct mdio_gpio_info *bitbang = bus->priv;
80
81 bitbang->mdc = of_get_gpio(np, 0);
82 bitbang->mdio = of_get_gpio(np, 1);
83
84 if (bitbang->mdc < 0 || bitbang->mdio < 0)
85 return -ENODEV;
86
87 snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc);
88 return 0;
89}
90
91static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
92{
93 const u32 *data;
94 int len, id, irq;
95
96 data = of_get_property(np, "reg", &len);
97 if (!data || len != 4)
98 return;
99
100 id = *data;
101 bus->phy_mask &= ~(1 << id);
102
103 irq = of_irq_to_resource(np, 0, NULL);
104 if (irq != NO_IRQ)
105 bus->irq[id] = irq;
106}
107
108static int __devinit mdio_ofgpio_probe(struct of_device *ofdev,
109 const struct of_device_id *match)
110{
111 struct device_node *np = NULL;
112 struct mii_bus *new_bus;
113 struct mdio_gpio_info *bitbang;
114 int ret = -ENOMEM;
115 int i;
116
117 bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL);
118 if (!bitbang)
119 goto out;
120
121 bitbang->ctrl.ops = &mdio_gpio_ops;
122
123 new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
124 if (!new_bus)
125 goto out_free_bitbang;
126
127 new_bus->name = "GPIO Bitbanged MII",
128
129 ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node);
130 if (ret)
131 goto out_free_bus;
132
133 new_bus->phy_mask = ~0;
134 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
135 if (!new_bus->irq)
136 goto out_free_bus;
137
138 for (i = 0; i < PHY_MAX_ADDR; i++)
139 new_bus->irq[i] = -1;
140
141 while ((np = of_get_next_child(ofdev->node, np)))
142 if (!strcmp(np->type, "ethernet-phy"))
143 add_phy(new_bus, np);
144
145 new_bus->parent = &ofdev->dev;
146 dev_set_drvdata(&ofdev->dev, new_bus);
147
148 ret = mdiobus_register(new_bus);
149 if (ret)
150 goto out_free_irqs;
151
152 return 0;
153
154out_free_irqs:
155 dev_set_drvdata(&ofdev->dev, NULL);
156 kfree(new_bus->irq);
157out_free_bus:
158 free_mdio_bitbang(new_bus);
159out_free_bitbang:
160 kfree(bitbang);
161out:
162 return ret;
163}
164
165static int mdio_ofgpio_remove(struct of_device *ofdev)
166{
167 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
168 struct mdio_gpio_info *bitbang = bus->priv;
169
170 mdiobus_unregister(bus);
171 kfree(bus->irq);
172 free_mdio_bitbang(bus);
173 dev_set_drvdata(&ofdev->dev, NULL);
174 kfree(bitbang);
175
176 return 0;
177}
178
179static struct of_device_id mdio_ofgpio_match[] = {
180 {
181 .compatible = "virtual,mdio-gpio",
182 },
183 {},
184};
185
186static struct of_platform_driver mdio_ofgpio_driver = {
187 .name = "mdio-gpio",
188 .match_table = mdio_ofgpio_match,
189 .probe = mdio_ofgpio_probe,
190 .remove = mdio_ofgpio_remove,
191};
192
193static int mdio_ofgpio_init(void)
194{
195 return of_register_platform_driver(&mdio_ofgpio_driver);
196}
197
198static void mdio_ofgpio_exit(void)
199{
200 of_unregister_platform_driver(&mdio_ofgpio_driver);
201}
202
203module_init(mdio_ofgpio_init);
204module_exit(mdio_ofgpio_exit);
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 289fc267edf3..7a333601fbe8 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -97,7 +97,7 @@ int mdiobus_register(struct mii_bus *bus)
97 bus->dev.parent = bus->parent; 97 bus->dev.parent = bus->parent;
98 bus->dev.class = &mdio_bus_class; 98 bus->dev.class = &mdio_bus_class;
99 bus->dev.groups = NULL; 99 bus->dev.groups = NULL;
100 memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE); 100 dev_set_name(&bus->dev, bus->id);
101 101
102 err = device_register(&bus->dev); 102 err = device_register(&bus->dev);
103 if (err) { 103 if (err) {
@@ -192,7 +192,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
192 192
193 phydev->dev.parent = bus->parent; 193 phydev->dev.parent = bus->parent;
194 phydev->dev.bus = &mdio_bus_type; 194 phydev->dev.bus = &mdio_bus_type;
195 snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr); 195 dev_set_name(&phydev->dev, PHY_ID_FMT, bus->id, addr);
196 196
197 phydev->bus = bus; 197 phydev->bus = bus;
198 198
@@ -285,9 +285,12 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state)
285{ 285{
286 int ret = 0; 286 int ret = 0;
287 struct device_driver *drv = dev->driver; 287 struct device_driver *drv = dev->driver;
288 struct phy_driver *phydrv = to_phy_driver(drv);
289 struct phy_device *phydev = to_phy_device(dev);
288 290
289 if (drv && drv->suspend) 291 if ((!device_may_wakeup(phydev->dev.parent)) &&
290 ret = drv->suspend(dev, state); 292 (phydrv && phydrv->suspend))
293 ret = phydrv->suspend(phydev);
291 294
292 return ret; 295 return ret;
293} 296}
@@ -296,9 +299,12 @@ static int mdio_bus_resume(struct device * dev)
296{ 299{
297 int ret = 0; 300 int ret = 0;
298 struct device_driver *drv = dev->driver; 301 struct device_driver *drv = dev->driver;
302 struct phy_driver *phydrv = to_phy_driver(drv);
303 struct phy_device *phydev = to_phy_device(dev);
299 304
300 if (drv && drv->resume) 305 if ((!device_may_wakeup(phydev->dev.parent)) &&
301 ret = drv->resume(dev); 306 (phydrv && phydrv->resume))
307 ret = phydrv->resume(phydev);
302 308
303 return ret; 309 return ret;
304} 310}
diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c
new file mode 100644
index 000000000000..6c636eb72089
--- /dev/null
+++ b/drivers/net/phy/national.c
@@ -0,0 +1,155 @@
1/*
2 * drivers/net/phy/national.c
3 *
4 * Driver for National Semiconductor PHYs
5 *
6 * Author: Stuart Menefy <stuart.menefy@st.com>
7 * Maintainer: Giuseppe Cavallaro <peppe.cavallaro@st.com>
8 *
9 * Copyright (c) 2008 STMicroelectronics Limited
10 *
11 * This program is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by the
13 * Free Software Foundation; either version 2 of the License, or (at your
14 * option) any later version.
15 *
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/mii.h>
21#include <linux/ethtool.h>
22#include <linux/phy.h>
23#include <linux/netdevice.h>
24
25/* DP83865 phy identifier values */
26#define DP83865_PHY_ID 0x20005c7a
27
28#define DP83865_INT_MASK_REG 0x15
29#define DP83865_INT_MASK_STATUS 0x14
30
31#define DP83865_INT_REMOTE_FAULT 0x0008
32#define DP83865_INT_ANE_COMPLETED 0x0010
33#define DP83865_INT_LINK_CHANGE 0xe000
34#define DP83865_INT_MASK_DEFAULT (DP83865_INT_REMOTE_FAULT | \
35 DP83865_INT_ANE_COMPLETED | \
36 DP83865_INT_LINK_CHANGE)
37
38/* Advanced proprietary configuration */
39#define NS_EXP_MEM_CTL 0x16
40#define NS_EXP_MEM_DATA 0x1d
41#define NS_EXP_MEM_ADD 0x1e
42
43#define LED_CTRL_REG 0x13
44#define AN_FALLBACK_AN 0x0001
45#define AN_FALLBACK_CRC 0x0002
46#define AN_FALLBACK_IE 0x0004
47#define ALL_FALLBACK_ON (AN_FALLBACK_AN | AN_FALLBACK_CRC | AN_FALLBACK_IE)
48
49enum hdx_loopback {
50 hdx_loopback_on = 0,
51 hdx_loopback_off = 1,
52};
53
54static u8 ns_exp_read(struct phy_device *phydev, u16 reg)
55{
56 phy_write(phydev, NS_EXP_MEM_ADD, reg);
57 return phy_read(phydev, NS_EXP_MEM_DATA);
58}
59
60static void ns_exp_write(struct phy_device *phydev, u16 reg, u8 data)
61{
62 phy_write(phydev, NS_EXP_MEM_ADD, reg);
63 phy_write(phydev, NS_EXP_MEM_DATA, data);
64}
65
66static int ns_config_intr(struct phy_device *phydev)
67{
68 int err;
69
70 if (phydev->interrupts == PHY_INTERRUPT_ENABLED)
71 err = phy_write(phydev, DP83865_INT_MASK_REG,
72 DP83865_INT_MASK_DEFAULT);
73 else
74 err = phy_write(phydev, DP83865_INT_MASK_REG, 0);
75
76 return err;
77}
78
79static int ns_ack_interrupt(struct phy_device *phydev)
80{
81 int ret = phy_read(phydev, DP83865_INT_MASK_STATUS);
82 if (ret < 0)
83 return ret;
84
85 return 0;
86}
87
88static void ns_giga_speed_fallback(struct phy_device *phydev, int mode)
89{
90 int bmcr = phy_read(phydev, MII_BMCR);
91
92 phy_write(phydev, MII_BMCR, (bmcr | BMCR_PDOWN));
93
94 /* Enable 8 bit expended memory read/write (no auto increment) */
95 phy_write(phydev, NS_EXP_MEM_CTL, 0);
96 phy_write(phydev, NS_EXP_MEM_ADD, 0x1C0);
97 phy_write(phydev, NS_EXP_MEM_DATA, 0x0008);
98 phy_write(phydev, MII_BMCR, (bmcr & ~BMCR_PDOWN));
99 phy_write(phydev, LED_CTRL_REG, mode);
100 return;
101}
102
103static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable)
104{
105 if (disable)
106 ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1);
107 else
108 ns_exp_write(phydev, 0x1c0,
109 ns_exp_read(phydev, 0x1c0) & 0xfffe);
110
111 printk(KERN_DEBUG "DP83865 PHY: 10BASE-T HDX loopback %s\n",
112 (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on");
113
114 return;
115}
116
117static int ns_config_init(struct phy_device *phydev)
118{
119 ns_giga_speed_fallback(phydev, ALL_FALLBACK_ON);
120 /* In the latest MAC or switches design, the 10 Mbps loopback
121 is desired to be turned off. */
122 ns_10_base_t_hdx_loopack(phydev, hdx_loopback_off);
123 return ns_ack_interrupt(phydev);
124}
125
126static struct phy_driver dp83865_driver = {
127 .phy_id = DP83865_PHY_ID,
128 .phy_id_mask = 0xfffffff0,
129 .name = "NatSemi DP83865",
130 .features = PHY_GBIT_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause,
131 .flags = PHY_HAS_INTERRUPT,
132 .config_init = ns_config_init,
133 .config_aneg = genphy_config_aneg,
134 .read_status = genphy_read_status,
135 .ack_interrupt = ns_ack_interrupt,
136 .config_intr = ns_config_intr,
137 .driver = {.owner = THIS_MODULE,}
138};
139
140static int __init ns_init(void)
141{
142 return phy_driver_register(&dp83865_driver);
143}
144
145static void __exit ns_exit(void)
146{
147 phy_driver_unregister(&dp83865_driver);
148}
149
150MODULE_DESCRIPTION("NatSemi PHY driver");
151MODULE_AUTHOR("Stuart Menefy");
152MODULE_LICENSE("GPL");
153
154module_init(ns_init);
155module_exit(ns_exit);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index df4e6257d4a7..e4ede6080c9d 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -45,7 +45,7 @@
45 */ 45 */
46void phy_print_status(struct phy_device *phydev) 46void phy_print_status(struct phy_device *phydev)
47{ 47{
48 pr_info("PHY: %s - Link is %s", phydev->dev.bus_id, 48 pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev),
49 phydev->link ? "Up" : "Down"); 49 phydev->link ? "Up" : "Down");
50 if (phydev->link) 50 if (phydev->link)
51 printk(" - %d/%s", phydev->speed, 51 printk(" - %d/%s", phydev->speed,
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 25acbbde4a60..f84f6a1b530c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -74,7 +74,7 @@ int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
74 if (!fixup) 74 if (!fixup)
75 return -ENOMEM; 75 return -ENOMEM;
76 76
77 strncpy(fixup->bus_id, bus_id, BUS_ID_SIZE); 77 strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id));
78 fixup->phy_uid = phy_uid; 78 fixup->phy_uid = phy_uid;
79 fixup->phy_uid_mask = phy_uid_mask; 79 fixup->phy_uid_mask = phy_uid_mask;
80 fixup->run = run; 80 fixup->run = run;
@@ -109,7 +109,7 @@ EXPORT_SYMBOL(phy_register_fixup_for_id);
109 */ 109 */
110static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) 110static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup)
111{ 111{
112 if (strcmp(fixup->bus_id, phydev->dev.bus_id) != 0) 112 if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0)
113 if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0) 113 if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0)
114 return 0; 114 return 0;
115 115
@@ -517,23 +517,6 @@ int genphy_setup_forced(struct phy_device *phydev)
517 517
518 err = phy_write(phydev, MII_BMCR, ctl); 518 err = phy_write(phydev, MII_BMCR, ctl);
519 519
520 if (err < 0)
521 return err;
522
523 /*
524 * Run the fixups on this PHY, just in case the
525 * board code needs to change something after a reset
526 */
527 err = phy_scan_fixups(phydev);
528
529 if (err < 0)
530 return err;
531
532 /* We just reset the device, so we'd better configure any
533 * settings the PHY requires to operate */
534 if (phydev->drv->config_init)
535 err = phydev->drv->config_init(phydev);
536
537 return err; 520 return err;
538} 521}
539 522
@@ -779,7 +762,35 @@ static int genphy_config_init(struct phy_device *phydev)
779 762
780 return 0; 763 return 0;
781} 764}
765int genphy_suspend(struct phy_device *phydev)
766{
767 int value;
782 768
769 mutex_lock(&phydev->lock);
770
771 value = phy_read(phydev, MII_BMCR);
772 phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN));
773
774 mutex_unlock(&phydev->lock);
775
776 return 0;
777}
778EXPORT_SYMBOL(genphy_suspend);
779
780int genphy_resume(struct phy_device *phydev)
781{
782 int value;
783
784 mutex_lock(&phydev->lock);
785
786 value = phy_read(phydev, MII_BMCR);
787 phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN));
788
789 mutex_unlock(&phydev->lock);
790
791 return 0;
792}
793EXPORT_SYMBOL(genphy_resume);
783 794
784/** 795/**
785 * phy_probe - probe and init a PHY device 796 * phy_probe - probe and init a PHY device
@@ -855,7 +866,6 @@ int phy_driver_register(struct phy_driver *new_driver)
855{ 866{
856 int retval; 867 int retval;
857 868
858 memset(&new_driver->driver, 0, sizeof(new_driver->driver));
859 new_driver->driver.name = new_driver->name; 869 new_driver->driver.name = new_driver->name;
860 new_driver->driver.bus = &mdio_bus_type; 870 new_driver->driver.bus = &mdio_bus_type;
861 new_driver->driver.probe = phy_probe; 871 new_driver->driver.probe = phy_probe;
@@ -890,6 +900,8 @@ static struct phy_driver genphy_driver = {
890 .features = 0, 900 .features = 0,
891 .config_aneg = genphy_config_aneg, 901 .config_aneg = genphy_config_aneg,
892 .read_status = genphy_read_status, 902 .read_status = genphy_read_status,
903 .suspend = genphy_suspend,
904 .resume = genphy_resume,
893 .driver = {.owner= THIS_MODULE, }, 905 .driver = {.owner= THIS_MODULE, },
894}; 906};
895 907
diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c
index 73baa7a3bb0e..c05d38d46350 100644
--- a/drivers/net/phy/smsc.c
+++ b/drivers/net/phy/smsc.c
@@ -126,6 +126,27 @@ static struct phy_driver lan8700_driver = {
126 .driver = { .owner = THIS_MODULE, } 126 .driver = { .owner = THIS_MODULE, }
127}; 127};
128 128
129static struct phy_driver lan911x_int_driver = {
130 .phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */
131 .phy_id_mask = 0xfffffff0,
132 .name = "SMSC LAN911x Internal PHY",
133
134 .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause
135 | SUPPORTED_Asym_Pause),
136 .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG,
137
138 /* basic functions */
139 .config_aneg = genphy_config_aneg,
140 .read_status = genphy_read_status,
141 .config_init = smsc_phy_config_init,
142
143 /* IRQ related */
144 .ack_interrupt = smsc_phy_ack_interrupt,
145 .config_intr = smsc_phy_config_intr,
146
147 .driver = { .owner = THIS_MODULE, }
148};
149
129static int __init smsc_init(void) 150static int __init smsc_init(void)
130{ 151{
131 int ret; 152 int ret;
@@ -142,8 +163,14 @@ static int __init smsc_init(void)
142 if (ret) 163 if (ret)
143 goto err3; 164 goto err3;
144 165
166 ret = phy_driver_register (&lan911x_int_driver);
167 if (ret)
168 goto err4;
169
145 return 0; 170 return 0;
146 171
172err4:
173 phy_driver_unregister (&lan8700_driver);
147err3: 174err3:
148 phy_driver_unregister (&lan8187_driver); 175 phy_driver_unregister (&lan8187_driver);
149err2: 176err2:
@@ -154,6 +181,7 @@ err1:
154 181
155static void __exit smsc_exit(void) 182static void __exit smsc_exit(void)
156{ 183{
184 phy_driver_unregister (&lan911x_int_driver);
157 phy_driver_unregister (&lan8700_driver); 185 phy_driver_unregister (&lan8700_driver);
158 phy_driver_unregister (&lan8187_driver); 186 phy_driver_unregister (&lan8187_driver);
159 phy_driver_unregister (&lan83c185_driver); 187 phy_driver_unregister (&lan83c185_driver);
diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c
new file mode 100644
index 000000000000..6bdb0d53aaf9
--- /dev/null
+++ b/drivers/net/phy/ste10Xp.c
@@ -0,0 +1,137 @@
1/*
2 * drivers/net/phy/ste10Xp.c
3 *
4 * Driver for STMicroelectronics STe10Xp PHYs
5 *
6 * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
7 *
8 * Copyright (c) 2008 STMicroelectronics Limited
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
17#include <linux/module.h>
18#include <linux/init.h>
19#include <linux/sched.h>
20#include <linux/kernel.h>
21#include <linux/moduleparam.h>
22#include <linux/interrupt.h>
23#include <linux/netdevice.h>
24#include <linux/ethtool.h>
25#include <linux/mii.h>
26#include <linux/phy.h>
27
28#define MII_XCIIS 0x11 /* Configuration Info IRQ & Status Reg */
29#define MII_XIE 0x12 /* Interrupt Enable Register */
30#define MII_XIE_DEFAULT_MASK 0x0070 /* ANE complete, Remote Fault, Link Down */
31
32#define STE101P_PHY_ID 0x00061c50
33#define STE100P_PHY_ID 0x1c040011
34
35static int ste10Xp_config_init(struct phy_device *phydev)
36{
37 int value, err;
38
39 /* Software Reset PHY */
40 value = phy_read(phydev, MII_BMCR);
41 if (value < 0)
42 return value;
43
44 value |= BMCR_RESET;
45 err = phy_write(phydev, MII_BMCR, value);
46 if (err < 0)
47 return err;
48
49 do {
50 value = phy_read(phydev, MII_BMCR);
51 } while (value & BMCR_RESET);
52
53 return 0;
54}
55
56static int ste10Xp_config_intr(struct phy_device *phydev)
57{
58 int err, value;
59
60 if (phydev->interrupts == PHY_INTERRUPT_ENABLED) {
61 /* Enable all STe101P interrupts (PR12) */
62 err = phy_write(phydev, MII_XIE, MII_XIE_DEFAULT_MASK);
63 /* clear any pending interrupts */
64 if (err == 0) {
65 value = phy_read(phydev, MII_XCIIS);
66 if (value < 0)
67 err = value;
68 }
69 } else
70 err = phy_write(phydev, MII_XIE, 0);
71
72 return err;
73}
74
75static int ste10Xp_ack_interrupt(struct phy_device *phydev)
76{
77 int err = phy_read(phydev, MII_XCIIS);
78 if (err < 0)
79 return err;
80
81 return 0;
82}
83
84static struct phy_driver ste101p_pdriver = {
85 .phy_id = STE101P_PHY_ID,
86 .phy_id_mask = 0xfffffff0,
87 .name = "STe101p",
88 .features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
89 .flags = PHY_HAS_INTERRUPT,
90 .config_init = ste10Xp_config_init,
91 .config_aneg = genphy_config_aneg,
92 .read_status = genphy_read_status,
93 .ack_interrupt = ste10Xp_ack_interrupt,
94 .config_intr = ste10Xp_config_intr,
95 .suspend = genphy_suspend,
96 .resume = genphy_resume,
97 .driver = {.owner = THIS_MODULE,}
98};
99
100static struct phy_driver ste100p_pdriver = {
101 .phy_id = STE100P_PHY_ID,
102 .phy_id_mask = 0xffffffff,
103 .name = "STe100p",
104 .features = PHY_BASIC_FEATURES | SUPPORTED_Pause,
105 .flags = PHY_HAS_INTERRUPT,
106 .config_init = ste10Xp_config_init,
107 .config_aneg = genphy_config_aneg,
108 .read_status = genphy_read_status,
109 .ack_interrupt = ste10Xp_ack_interrupt,
110 .config_intr = ste10Xp_config_intr,
111 .suspend = genphy_suspend,
112 .resume = genphy_resume,
113 .driver = {.owner = THIS_MODULE,}
114};
115
116static int __init ste10Xp_init(void)
117{
118 int retval;
119
120 retval = phy_driver_register(&ste100p_pdriver);
121 if (retval < 0)
122 return retval;
123 return phy_driver_register(&ste101p_pdriver);
124}
125
126static void __exit ste10Xp_exit(void)
127{
128 phy_driver_unregister(&ste100p_pdriver);
129 phy_driver_unregister(&ste101p_pdriver);
130}
131
132module_init(ste10Xp_init);
133module_exit(ste10Xp_exit);
134
135MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver");
136MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
137MODULE_LICENSE("GPL");