diff options
Diffstat (limited to 'drivers/net/phy')
-rw-r--r-- | drivers/net/phy/Kconfig | 23 | ||||
-rw-r--r-- | drivers/net/phy/Makefile | 5 | ||||
-rw-r--r-- | drivers/net/phy/broadcom.c | 216 | ||||
-rw-r--r-- | drivers/net/phy/et1011c.c | 113 | ||||
-rw-r--r-- | drivers/net/phy/mdio-gpio.c | 296 | ||||
-rw-r--r-- | drivers/net/phy/mdio-ofgpio.c | 204 | ||||
-rw-r--r-- | drivers/net/phy/mdio_bus.c | 18 | ||||
-rw-r--r-- | drivers/net/phy/national.c | 155 | ||||
-rw-r--r-- | drivers/net/phy/phy.c | 2 | ||||
-rw-r--r-- | drivers/net/phy/phy_device.c | 52 | ||||
-rw-r--r-- | drivers/net/phy/smsc.c | 28 | ||||
-rw-r--r-- | drivers/net/phy/ste10Xp.c | 137 |
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 | ||
69 | config NATIONAL_PHY | ||
70 | tristate "Drivers for National Semiconductor PHYs" | ||
71 | ---help--- | ||
72 | Currently supports the DP83865 PHY. | ||
73 | |||
74 | config 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 | |||
80 | config LSI_ET1011C_PHY | ||
81 | tristate "Driver for LSI ET1011C PHY" | ||
82 | ---help--- | ||
83 | Supports the LSI ET1011C PHY. | ||
84 | |||
69 | config FIXED_PHY | 85 | config 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 | ||
87 | config MDIO_OF_GPIO | 103 | config 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 | |||
93 | endif # PHYLIB | 112 | endif # 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 | |||
13 | obj-$(CONFIG_BROADCOM_PHY) += broadcom.o | 13 | obj-$(CONFIG_BROADCOM_PHY) += broadcom.o |
14 | obj-$(CONFIG_ICPLUS_PHY) += icplus.o | 14 | obj-$(CONFIG_ICPLUS_PHY) += icplus.o |
15 | obj-$(CONFIG_REALTEK_PHY) += realtek.o | 15 | obj-$(CONFIG_REALTEK_PHY) += realtek.o |
16 | obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o | ||
16 | obj-$(CONFIG_FIXED_PHY) += fixed.o | 17 | obj-$(CONFIG_FIXED_PHY) += fixed.o |
17 | obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o | 18 | obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o |
18 | obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o | 19 | obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o |
20 | obj-$(CONFIG_NATIONAL_PHY) += national.o | ||
21 | obj-$(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 | 167 | static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum) |
133 | * and Secondary SerDes registers (when sec_serdes=1). | ||
134 | */ | ||
135 | static 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 | ||
150 | static int bcm54xx_exp_write(struct phy_device *phydev, | 183 | static 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 | ||
199 | static 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 | |||
204 | static 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 | |||
245 | error: | ||
246 | bcm54xx_auxctl_write(phydev, | ||
247 | MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, | ||
248 | MII_BCM54XX_AUXCTL_ACTL_TX_6DB); | ||
249 | |||
250 | return err; | ||
251 | } | ||
252 | |||
165 | static int bcm54xx_config_init(struct phy_device *phydev) | 253 | static 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 | ||
528 | static 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 | |||
543 | static 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 | |||
418 | static int __init broadcom_init(void) | 558 | static 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 | ||
588 | out_57780: | ||
589 | phy_driver_unregister(&bcm50610_driver); | ||
590 | out_50610: | ||
591 | phy_driver_unregister(&bcm5482_driver); | ||
442 | out_5482: | 592 | out_5482: |
443 | phy_driver_unregister(&bcm5481_driver); | 593 | phy_driver_unregister(&bcm5481_driver); |
444 | out_5481: | 594 | out_5481: |
@@ -455,6 +605,8 @@ out_5411: | |||
455 | 605 | ||
456 | static void __exit broadcom_exit(void) | 606 | static 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 | |||
49 | MODULE_DESCRIPTION("LSI ET1011C PHY driver"); | ||
50 | MODULE_AUTHOR("Chaithrika U S"); | ||
51 | MODULE_LICENSE("GPL"); | ||
52 | |||
53 | static 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 | |||
67 | static 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 | |||
91 | static 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 | |||
102 | static int __init et1011c_init(void) | ||
103 | { | ||
104 | return phy_driver_register(&et1011c_driver); | ||
105 | } | ||
106 | |||
107 | static void __exit et1011c_exit(void) | ||
108 | { | ||
109 | phy_driver_unregister(&et1011c_driver); | ||
110 | } | ||
111 | |||
112 | module_init(et1011c_init); | ||
113 | module_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 | |||
36 | struct mdio_gpio_info { | ||
37 | struct mdiobb_ctrl ctrl; | ||
38 | int mdc, mdio; | ||
39 | }; | ||
40 | |||
41 | static 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 | |||
52 | static 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 | |||
60 | static 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 | |||
68 | static 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 | |||
76 | static 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 | |||
84 | static 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 | |||
136 | out_free_all: | ||
137 | dev_set_drvdata(dev, NULL); | ||
138 | gpio_free(bitbang->mdio); | ||
139 | out_free_mdc: | ||
140 | gpio_free(bitbang->mdc); | ||
141 | out_free_bus: | ||
142 | free_mdio_bitbang(new_bus); | ||
143 | out_free_bitbang: | ||
144 | kfree(bitbang); | ||
145 | out: | ||
146 | return ret; | ||
147 | } | ||
148 | |||
149 | static 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 | |||
162 | static 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 | |||
172 | static 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 | ||
180 | static 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 | |||
198 | static 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 | |||
220 | out_free: | ||
221 | kfree(pdata); | ||
222 | return -ENODEV; | ||
223 | } | ||
224 | |||
225 | static 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 | |||
233 | static struct of_device_id mdio_ofgpio_match[] = { | ||
234 | { | ||
235 | .compatible = "virtual,mdio-gpio", | ||
236 | }, | ||
237 | {}, | ||
238 | }; | ||
239 | |||
240 | static 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 | |||
247 | static inline int __init mdio_ofgpio_init(void) | ||
248 | { | ||
249 | return of_register_platform_driver(&mdio_ofgpio_driver); | ||
250 | } | ||
251 | |||
252 | static inline void __exit mdio_ofgpio_exit(void) | ||
253 | { | ||
254 | of_unregister_platform_driver(&mdio_ofgpio_driver); | ||
255 | } | ||
256 | #else | ||
257 | static inline int __init mdio_ofgpio_init(void) { return 0; } | ||
258 | static inline void __exit mdio_ofgpio_exit(void) { } | ||
259 | #endif /* CONFIG_OF_GPIO */ | ||
260 | |||
261 | static 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 | |||
270 | static 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 | } | ||
284 | module_init(mdio_gpio_init); | ||
285 | |||
286 | static void __exit mdio_gpio_exit(void) | ||
287 | { | ||
288 | platform_driver_unregister(&mdio_gpio_driver); | ||
289 | mdio_ofgpio_exit(); | ||
290 | } | ||
291 | module_exit(mdio_gpio_exit); | ||
292 | |||
293 | MODULE_ALIAS("platform:mdio-gpio"); | ||
294 | MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); | ||
295 | MODULE_LICENSE("GPL"); | ||
296 | MODULE_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 | |||
28 | struct mdio_gpio_info { | ||
29 | struct mdiobb_ctrl ctrl; | ||
30 | int mdc, mdio; | ||
31 | }; | ||
32 | |||
33 | static 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 | |||
44 | static 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 | |||
52 | static 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 | |||
60 | static 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 | |||
68 | static 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 | |||
76 | static 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 | |||
91 | static 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 | |||
108 | static 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 | |||
154 | out_free_irqs: | ||
155 | dev_set_drvdata(&ofdev->dev, NULL); | ||
156 | kfree(new_bus->irq); | ||
157 | out_free_bus: | ||
158 | free_mdio_bitbang(new_bus); | ||
159 | out_free_bitbang: | ||
160 | kfree(bitbang); | ||
161 | out: | ||
162 | return ret; | ||
163 | } | ||
164 | |||
165 | static 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 | |||
179 | static struct of_device_id mdio_ofgpio_match[] = { | ||
180 | { | ||
181 | .compatible = "virtual,mdio-gpio", | ||
182 | }, | ||
183 | {}, | ||
184 | }; | ||
185 | |||
186 | static 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 | |||
193 | static int mdio_ofgpio_init(void) | ||
194 | { | ||
195 | return of_register_platform_driver(&mdio_ofgpio_driver); | ||
196 | } | ||
197 | |||
198 | static void mdio_ofgpio_exit(void) | ||
199 | { | ||
200 | of_unregister_platform_driver(&mdio_ofgpio_driver); | ||
201 | } | ||
202 | |||
203 | module_init(mdio_ofgpio_init); | ||
204 | module_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 | |||
49 | enum hdx_loopback { | ||
50 | hdx_loopback_on = 0, | ||
51 | hdx_loopback_off = 1, | ||
52 | }; | ||
53 | |||
54 | static 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 | |||
60 | static 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 | |||
66 | static 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 | |||
79 | static 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 | |||
88 | static 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 | |||
103 | static 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 | |||
117 | static 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 | |||
126 | static 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 | |||
140 | static int __init ns_init(void) | ||
141 | { | ||
142 | return phy_driver_register(&dp83865_driver); | ||
143 | } | ||
144 | |||
145 | static void __exit ns_exit(void) | ||
146 | { | ||
147 | phy_driver_unregister(&dp83865_driver); | ||
148 | } | ||
149 | |||
150 | MODULE_DESCRIPTION("NatSemi PHY driver"); | ||
151 | MODULE_AUTHOR("Stuart Menefy"); | ||
152 | MODULE_LICENSE("GPL"); | ||
153 | |||
154 | module_init(ns_init); | ||
155 | module_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 | */ |
46 | void phy_print_status(struct phy_device *phydev) | 46 | void 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 | */ |
110 | static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) | 110 | static 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 | } |
765 | int 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 | } | ||
778 | EXPORT_SYMBOL(genphy_suspend); | ||
779 | |||
780 | int 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 | } | ||
793 | EXPORT_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 | ||
129 | static 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 | |||
129 | static int __init smsc_init(void) | 150 | static 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 | ||
172 | err4: | ||
173 | phy_driver_unregister (&lan8700_driver); | ||
147 | err3: | 174 | err3: |
148 | phy_driver_unregister (&lan8187_driver); | 175 | phy_driver_unregister (&lan8187_driver); |
149 | err2: | 176 | err2: |
@@ -154,6 +181,7 @@ err1: | |||
154 | 181 | ||
155 | static void __exit smsc_exit(void) | 182 | static 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 | |||
35 | static 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 | |||
56 | static 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 | |||
75 | static 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 | |||
84 | static 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 | |||
100 | static 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 | |||
116 | static 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 | |||
126 | static void __exit ste10Xp_exit(void) | ||
127 | { | ||
128 | phy_driver_unregister(&ste100p_pdriver); | ||
129 | phy_driver_unregister(&ste101p_pdriver); | ||
130 | } | ||
131 | |||
132 | module_init(ste10Xp_init); | ||
133 | module_exit(ste10Xp_exit); | ||
134 | |||
135 | MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver"); | ||
136 | MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>"); | ||
137 | MODULE_LICENSE("GPL"); | ||