blob: 7cf132f0f952fa6032a984afb9a59d3d10a2b947 [file] [log] [blame]
Pantelis Antoniou48257c42005-10-28 16:25:58 -04001/*
2 * Combined Ethernet driver for Motorola MPC8xx and MPC82xx.
3 *
Vitaly Bordug9b8ee8e2007-09-18 20:05:35 +04004 * Copyright (c) 2003 Intracom S.A.
Pantelis Antoniou48257c42005-10-28 16:25:58 -04005 * by Pantelis Antoniou <panto@intracom.gr>
Vitaly Bordug9b8ee8e2007-09-18 20:05:35 +04006 *
7 * 2005 (c) MontaVista Software, Inc.
Pantelis Antoniou48257c42005-10-28 16:25:58 -04008 * Vitaly Bordug <vbordug@ru.mvista.com>
9 *
Vitaly Bordug9b8ee8e2007-09-18 20:05:35 +040010 * This file is licensed under the terms of the GNU General Public License
11 * version 2. This program is licensed "as is" without any warranty of any
Pantelis Antoniou48257c42005-10-28 16:25:58 -040012 * kind, whether express or implied.
13 */
14
Pantelis Antoniou48257c42005-10-28 16:25:58 -040015#include <linux/module.h>
Pantelis Antoniou48257c42005-10-28 16:25:58 -040016#include <linux/ioport.h>
17#include <linux/slab.h>
18#include <linux/interrupt.h>
Pantelis Antoniou48257c42005-10-28 16:25:58 -040019#include <linux/init.h>
20#include <linux/delay.h>
21#include <linux/netdevice.h>
22#include <linux/etherdevice.h>
Pantelis Antoniou48257c42005-10-28 16:25:58 -040023#include <linux/mii.h>
24#include <linux/ethtool.h>
25#include <linux/bitops.h>
Vitaly Bordug5b4b8452006-08-14 23:00:30 -070026#include <linux/platform_device.h>
Pantelis Antoniou48257c42005-10-28 16:25:58 -040027
Scott Wood976de6a2007-10-02 10:55:58 -050028#ifdef CONFIG_PPC_CPM_NEW_BINDING
29#include <linux/of_platform.h>
30#endif
Pantelis Antoniou48257c42005-10-28 16:25:58 -040031
32#include "fs_enet.h"
33
Scott Wood976de6a2007-10-02 10:55:58 -050034struct bb_info {
35 __be32 __iomem *dir;
36 __be32 __iomem *dat;
37 u32 mdio_msk;
38 u32 mdc_msk;
39 int delay;
40};
41
42/* FIXME: If any other users of GPIO crop up, then these will have to
43 * have some sort of global synchronization to avoid races with other
44 * pins on the same port. The ideal solution would probably be to
45 * bind the ports to a GPIO driver, and have this be a client of it.
46 */
47static inline void bb_set(u32 __iomem *p, u32 m)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040048{
Scott Wood976de6a2007-10-02 10:55:58 -050049 out_be32(p, in_be32(p) | m);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040050}
Pantelis Antoniou48257c42005-10-28 16:25:58 -040051
Scott Wood976de6a2007-10-02 10:55:58 -050052static inline void bb_clr(u32 __iomem *p, u32 m)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040053{
Scott Wood976de6a2007-10-02 10:55:58 -050054 out_be32(p, in_be32(p) & ~m);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040055}
56
Scott Wood976de6a2007-10-02 10:55:58 -050057static inline int bb_read(u32 __iomem *p, u32 m)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040058{
Scott Wood976de6a2007-10-02 10:55:58 -050059 return (in_be32(p) & m) != 0;
Pantelis Antoniou48257c42005-10-28 16:25:58 -040060}
61
Vitaly Bordug5b4b8452006-08-14 23:00:30 -070062static inline void mdio_active(struct bb_info *bitbang)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040063{
Scott Wood976de6a2007-10-02 10:55:58 -050064 bb_set(bitbang->dir, bitbang->mdio_msk);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040065}
66
Scott Wood976de6a2007-10-02 10:55:58 -050067static inline void mdio_tristate(struct bb_info *bitbang)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040068{
Scott Wood976de6a2007-10-02 10:55:58 -050069 bb_clr(bitbang->dir, bitbang->mdio_msk);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040070}
71
Scott Wood976de6a2007-10-02 10:55:58 -050072static inline int mdio_read(struct bb_info *bitbang)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040073{
Scott Wood976de6a2007-10-02 10:55:58 -050074 return bb_read(bitbang->dat, bitbang->mdio_msk);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040075}
76
Scott Wood976de6a2007-10-02 10:55:58 -050077static inline void mdio(struct bb_info *bitbang, int what)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040078{
79 if (what)
Scott Wood976de6a2007-10-02 10:55:58 -050080 bb_set(bitbang->dat, bitbang->mdio_msk);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040081 else
Scott Wood976de6a2007-10-02 10:55:58 -050082 bb_clr(bitbang->dat, bitbang->mdio_msk);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040083}
84
Scott Wood976de6a2007-10-02 10:55:58 -050085static inline void mdc(struct bb_info *bitbang, int what)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040086{
87 if (what)
Scott Wood976de6a2007-10-02 10:55:58 -050088 bb_set(bitbang->dat, bitbang->mdc_msk);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040089 else
Scott Wood976de6a2007-10-02 10:55:58 -050090 bb_clr(bitbang->dat, bitbang->mdc_msk);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040091}
92
Scott Wood976de6a2007-10-02 10:55:58 -050093static inline void mii_delay(struct bb_info *bitbang)
Pantelis Antoniou48257c42005-10-28 16:25:58 -040094{
Vitaly Bordug5b4b8452006-08-14 23:00:30 -070095 udelay(bitbang->delay);
Pantelis Antoniou48257c42005-10-28 16:25:58 -040096}
97
98/* Utility to send the preamble, address, and register (common to read and write). */
Vitaly Bordug5b4b8452006-08-14 23:00:30 -070099static void bitbang_pre(struct bb_info *bitbang , int read, u8 addr, u8 reg)
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400100{
101 int j;
102
103 /*
104 * Send a 32 bit preamble ('1's) with an extra '1' bit for good measure.
105 * The IEEE spec says this is a PHY optional requirement. The AMD
106 * 79C874 requires one after power up and one after a MII communications
107 * error. This means that we are doing more preambles than we need,
108 * but it is safer and will be much more robust.
109 */
110
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700111 mdio_active(bitbang);
112 mdio(bitbang, 1);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400113 for (j = 0; j < 32; j++) {
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700114 mdc(bitbang, 0);
115 mii_delay(bitbang);
116 mdc(bitbang, 1);
117 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400118 }
119
120 /* send the start bit (01) and the read opcode (10) or write (10) */
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700121 mdc(bitbang, 0);
122 mdio(bitbang, 0);
123 mii_delay(bitbang);
124 mdc(bitbang, 1);
125 mii_delay(bitbang);
126 mdc(bitbang, 0);
127 mdio(bitbang, 1);
128 mii_delay(bitbang);
129 mdc(bitbang, 1);
130 mii_delay(bitbang);
131 mdc(bitbang, 0);
132 mdio(bitbang, read);
133 mii_delay(bitbang);
134 mdc(bitbang, 1);
135 mii_delay(bitbang);
136 mdc(bitbang, 0);
137 mdio(bitbang, !read);
138 mii_delay(bitbang);
139 mdc(bitbang, 1);
140 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400141
142 /* send the PHY address */
143 for (j = 0; j < 5; j++) {
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700144 mdc(bitbang, 0);
145 mdio(bitbang, (addr & 0x10) != 0);
146 mii_delay(bitbang);
147 mdc(bitbang, 1);
148 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400149 addr <<= 1;
150 }
151
152 /* send the register address */
153 for (j = 0; j < 5; j++) {
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700154 mdc(bitbang, 0);
155 mdio(bitbang, (reg & 0x10) != 0);
156 mii_delay(bitbang);
157 mdc(bitbang, 1);
158 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400159 reg <<= 1;
160 }
161}
162
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700163static int fs_enet_mii_bb_read(struct mii_bus *bus , int phy_id, int location)
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400164{
165 u16 rdreg;
166 int ret, j;
167 u8 addr = phy_id & 0xff;
168 u8 reg = location & 0xff;
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700169 struct bb_info* bitbang = bus->priv;
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400170
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700171 bitbang_pre(bitbang, 1, addr, reg);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400172
173 /* tri-state our MDIO I/O pin so we can read */
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700174 mdc(bitbang, 0);
175 mdio_tristate(bitbang);
176 mii_delay(bitbang);
177 mdc(bitbang, 1);
178 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400179
180 /* check the turnaround bit: the PHY should be driving it to zero */
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700181 if (mdio_read(bitbang) != 0) {
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400182 /* PHY didn't drive TA low */
183 for (j = 0; j < 32; j++) {
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700184 mdc(bitbang, 0);
185 mii_delay(bitbang);
186 mdc(bitbang, 1);
187 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400188 }
189 ret = -1;
190 goto out;
191 }
192
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700193 mdc(bitbang, 0);
194 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400195
196 /* read 16 bits of register data, MSB first */
197 rdreg = 0;
198 for (j = 0; j < 16; j++) {
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700199 mdc(bitbang, 1);
200 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400201 rdreg <<= 1;
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700202 rdreg |= mdio_read(bitbang);
203 mdc(bitbang, 0);
204 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400205 }
206
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700207 mdc(bitbang, 1);
208 mii_delay(bitbang);
209 mdc(bitbang, 0);
210 mii_delay(bitbang);
211 mdc(bitbang, 1);
212 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400213
214 ret = rdreg;
215out:
216 return ret;
217}
218
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700219static int fs_enet_mii_bb_write(struct mii_bus *bus, int phy_id, int location, u16 val)
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400220{
221 int j;
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700222 struct bb_info* bitbang = bus->priv;
223
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400224 u8 addr = phy_id & 0xff;
225 u8 reg = location & 0xff;
226 u16 value = val & 0xffff;
227
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700228 bitbang_pre(bitbang, 0, addr, reg);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400229
230 /* send the turnaround (10) */
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700231 mdc(bitbang, 0);
232 mdio(bitbang, 1);
233 mii_delay(bitbang);
234 mdc(bitbang, 1);
235 mii_delay(bitbang);
236 mdc(bitbang, 0);
237 mdio(bitbang, 0);
238 mii_delay(bitbang);
239 mdc(bitbang, 1);
240 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400241
242 /* write 16 bits of register data, MSB first */
243 for (j = 0; j < 16; j++) {
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700244 mdc(bitbang, 0);
245 mdio(bitbang, (value & 0x8000) != 0);
246 mii_delay(bitbang);
247 mdc(bitbang, 1);
248 mii_delay(bitbang);
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400249 value <<= 1;
250 }
251
252 /*
253 * Tri-state the MDIO line.
254 */
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700255 mdio_tristate(bitbang);
256 mdc(bitbang, 0);
257 mii_delay(bitbang);
258 mdc(bitbang, 1);
259 mii_delay(bitbang);
260 return 0;
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400261}
262
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700263static int fs_enet_mii_bb_reset(struct mii_bus *bus)
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400264{
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700265 /*nothing here - dunno how to reset it*/
266 return 0;
267}
268
Scott Wood976de6a2007-10-02 10:55:58 -0500269#ifdef CONFIG_PPC_CPM_NEW_BINDING
270static int __devinit fs_mii_bitbang_init(struct mii_bus *bus,
271 struct device_node *np)
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700272{
Scott Wood976de6a2007-10-02 10:55:58 -0500273 struct resource res;
274 const u32 *data;
275 int mdio_pin, mdc_pin, len;
276 struct bb_info *bitbang = bus->priv;
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400277
Scott Wood976de6a2007-10-02 10:55:58 -0500278 int ret = of_address_to_resource(np, 0, &res);
279 if (ret)
280 return ret;
281
282 if (res.end - res.start < 13)
283 return -ENODEV;
284
285 /* This should really encode the pin number as well, but all
286 * we get is an int, and the odds of multiple bitbang mdio buses
287 * is low enough that it's not worth going too crazy.
288 */
289 bus->id = res.start;
290
291 data = of_get_property(np, "fsl,mdio-pin", &len);
292 if (!data || len != 4)
293 return -ENODEV;
294 mdio_pin = *data;
295
296 data = of_get_property(np, "fsl,mdc-pin", &len);
297 if (!data || len != 4)
298 return -ENODEV;
299 mdc_pin = *data;
300
301 bitbang->dir = ioremap(res.start, res.end - res.start + 1);
302 if (!bitbang->dir)
303 return -ENOMEM;
304
305 bitbang->dat = bitbang->dir + 4;
306 bitbang->mdio_msk = 1 << (31 - mdio_pin);
307 bitbang->mdc_msk = 1 << (31 - mdc_pin);
308 bitbang->delay = 1; /* 1 us between operations */
309
310 return 0;
311}
312
313static void __devinit add_phy(struct mii_bus *bus, struct device_node *np)
314{
315 const u32 *data;
316 int len, id, irq;
317
318 data = of_get_property(np, "reg", &len);
319 if (!data || len != 4)
320 return;
321
322 id = *data;
323 bus->phy_mask &= ~(1 << id);
324
325 irq = of_irq_to_resource(np, 0, NULL);
326 if (irq != NO_IRQ)
327 bus->irq[id] = irq;
328}
329
330static int __devinit fs_enet_mdio_probe(struct of_device *ofdev,
331 const struct of_device_id *match)
332{
333 struct device_node *np = NULL;
334 struct mii_bus *new_bus;
335 struct bb_info *bitbang;
336 int ret = -ENOMEM;
337 int i;
338
339 new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
340 if (!new_bus)
341 goto out;
342
343 bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
344 if (!bitbang)
345 goto out_free_bus;
346
347 new_bus->priv = bitbang;
348 new_bus->name = "CPM2 Bitbanged MII",
349 new_bus->read = &fs_enet_mii_bb_read,
350 new_bus->write = &fs_enet_mii_bb_write,
351 new_bus->reset = &fs_enet_mii_bb_reset,
352
353 ret = fs_mii_bitbang_init(new_bus, ofdev->node);
354 if (ret)
355 goto out_free_bitbang;
356
357 new_bus->phy_mask = ~0;
358 new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
359 if (!new_bus->irq)
360 goto out_unmap_regs;
361
362 for (i = 0; i < PHY_MAX_ADDR; i++)
363 new_bus->irq[i] = -1;
364
365 while ((np = of_get_next_child(ofdev->node, np)))
366 if (!strcmp(np->type, "ethernet-phy"))
367 add_phy(new_bus, np);
368
369 new_bus->dev = &ofdev->dev;
370 dev_set_drvdata(&ofdev->dev, new_bus);
371
372 ret = mdiobus_register(new_bus);
373 if (ret)
374 goto out_free_irqs;
375
376 return 0;
377
378out_free_irqs:
379 dev_set_drvdata(&ofdev->dev, NULL);
380 kfree(new_bus->irq);
381out_unmap_regs:
382 iounmap(bitbang->dir);
383out_free_bitbang:
384 kfree(bitbang);
385out_free_bus:
386 kfree(new_bus);
387out:
388 return ret;
389}
390
391static int fs_enet_mdio_remove(struct of_device *ofdev)
392{
393 struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
394 struct bb_info *bitbang = bus->priv;
395
396 mdiobus_unregister(bus);
397 dev_set_drvdata(&ofdev->dev, NULL);
398 kfree(bus->irq);
399 iounmap(bitbang->dir);
400 kfree(bitbang);
401 kfree(bus);
402
403 return 0;
404}
405
406static struct of_device_id fs_enet_mdio_bb_match[] = {
407 {
408 .compatible = "fsl,cpm2-mdio-bitbang",
409 },
410 {},
411};
412
413static struct of_platform_driver fs_enet_bb_mdio_driver = {
414 .name = "fsl-bb-mdio",
415 .match_table = fs_enet_mdio_bb_match,
416 .probe = fs_enet_mdio_probe,
417 .remove = fs_enet_mdio_remove,
418};
419
420int fs_enet_mdio_bb_init(void)
421{
422 return of_register_platform_driver(&fs_enet_bb_mdio_driver);
423}
424
425void fs_enet_mdio_bb_exit(void)
426{
427 of_unregister_platform_driver(&fs_enet_bb_mdio_driver);
428}
429
430module_init(fs_enet_mdio_bb_init);
431module_exit(fs_enet_mdio_bb_exit);
432#else
433static int __devinit fs_mii_bitbang_init(struct bb_info *bitbang,
434 struct fs_mii_bb_platform_info *fmpi)
435{
436 bitbang->dir = (u32 __iomem *)fmpi->mdio_dir.offset;
437 bitbang->dat = (u32 __iomem *)fmpi->mdio_dat.offset;
438 bitbang->mdio_msk = 1U << (31 - fmpi->mdio_dat.bit);
439 bitbang->mdc_msk = 1U << (31 - fmpi->mdc_dat.bit);
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700440 bitbang->delay = fmpi->delay;
441
Pantelis Antoniou48257c42005-10-28 16:25:58 -0400442 return 0;
443}
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700444
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700445static int __devinit fs_enet_mdio_probe(struct device *dev)
446{
447 struct platform_device *pdev = to_platform_device(dev);
448 struct fs_mii_bb_platform_info *pdata;
449 struct mii_bus *new_bus;
450 struct bb_info *bitbang;
451 int err = 0;
452
453 if (NULL == dev)
454 return -EINVAL;
455
456 new_bus = kzalloc(sizeof(struct mii_bus), GFP_KERNEL);
457
458 if (NULL == new_bus)
459 return -ENOMEM;
460
461 bitbang = kzalloc(sizeof(struct bb_info), GFP_KERNEL);
462
463 if (NULL == bitbang)
464 return -ENOMEM;
465
466 new_bus->name = "BB MII Bus",
467 new_bus->read = &fs_enet_mii_bb_read,
468 new_bus->write = &fs_enet_mii_bb_write,
469 new_bus->reset = &fs_enet_mii_bb_reset,
470 new_bus->id = pdev->id;
471
472 new_bus->phy_mask = ~0x9;
473 pdata = (struct fs_mii_bb_platform_info *)pdev->dev.platform_data;
474
475 if (NULL == pdata) {
476 printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id);
477 return -ENODEV;
478 }
479
480 /*set up workspace*/
481 fs_mii_bitbang_init(bitbang, pdata);
482
483 new_bus->priv = bitbang;
484
485 new_bus->irq = pdata->irq;
486
487 new_bus->dev = dev;
488 dev_set_drvdata(dev, new_bus);
489
490 err = mdiobus_register(new_bus);
491
492 if (0 != err) {
493 printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
494 new_bus->name);
495 goto bus_register_fail;
496 }
497
498 return 0;
499
500bus_register_fail:
501 kfree(bitbang);
502 kfree(new_bus);
503
504 return err;
505}
506
Vitaly Bordug5b4b8452006-08-14 23:00:30 -0700507static int fs_enet_mdio_remove(struct device *dev)
508{
509 struct mii_bus *bus = dev_get_drvdata(dev);
510
511 mdiobus_unregister(bus);
512
513 dev_set_drvdata(dev, NULL);
514
515 iounmap((void *) (&bus->priv));
516 bus->priv = NULL;
517 kfree(bus);
518
519 return 0;
520}
521
522static struct device_driver fs_enet_bb_mdio_driver = {
523 .name = "fsl-bb-mdio",
524 .bus = &platform_bus_type,
525 .probe = fs_enet_mdio_probe,
526 .remove = fs_enet_mdio_remove,
527};
528
529int fs_enet_mdio_bb_init(void)
530{
531 return driver_register(&fs_enet_bb_mdio_driver);
532}
533
534void fs_enet_mdio_bb_exit(void)
535{
536 driver_unregister(&fs_enet_bb_mdio_driver);
537}
538