aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/phy_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/phy_device.c')
-rw-r--r--drivers/net/phy/phy_device.c172
1 files changed, 148 insertions, 24 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index c44d54f6310a..33f7bdb5857c 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -39,18 +39,9 @@
39#include <asm/irq.h> 39#include <asm/irq.h>
40#include <asm/uaccess.h> 40#include <asm/uaccess.h>
41 41
42static int genphy_config_init(struct phy_device *phydev); 42static struct phy_driver genphy_driver;
43 43extern int mdio_bus_init(void);
44static struct phy_driver genphy_driver = { 44extern void mdio_bus_exit(void);
45 .phy_id = 0xffffffff,
46 .phy_id_mask = 0xffffffff,
47 .name = "Generic PHY",
48 .config_init = genphy_config_init,
49 .features = 0,
50 .config_aneg = genphy_config_aneg,
51 .read_status = genphy_read_status,
52 .driver = {.owner = THIS_MODULE, },
53};
54 45
55/* get_phy_device 46/* get_phy_device
56 * 47 *
@@ -110,6 +101,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr)
110 return dev; 101 return dev;
111} 102}
112 103
104#ifdef CONFIG_PHYCONTROL
113/* phy_prepare_link: 105/* phy_prepare_link:
114 * 106 *
115 * description: Tells the PHY infrastructure to handle the 107 * description: Tells the PHY infrastructure to handle the
@@ -124,6 +116,132 @@ void phy_prepare_link(struct phy_device *phydev,
124 phydev->adjust_link = handler; 116 phydev->adjust_link = handler;
125} 117}
126 118
119/* phy_connect:
120 *
121 * description: Convenience function for connecting ethernet
122 * devices to PHY devices. The default behavior is for
123 * the PHY infrastructure to handle everything, and only notify
124 * the connected driver when the link status changes. If you
125 * don't want, or can't use the provided functionality, you may
126 * choose to call only the subset of functions which provide
127 * the desired functionality.
128 */
129struct phy_device * phy_connect(struct net_device *dev, const char *phy_id,
130 void (*handler)(struct net_device *), u32 flags)
131{
132 struct phy_device *phydev;
133
134 phydev = phy_attach(dev, phy_id, flags);
135
136 if (IS_ERR(phydev))
137 return phydev;
138
139 phy_prepare_link(phydev, handler);
140
141 phy_start_machine(phydev, NULL);
142
143 if (phydev->irq > 0)
144 phy_start_interrupts(phydev);
145
146 return phydev;
147}
148EXPORT_SYMBOL(phy_connect);
149
150void phy_disconnect(struct phy_device *phydev)
151{
152 if (phydev->irq > 0)
153 phy_stop_interrupts(phydev);
154
155 phy_stop_machine(phydev);
156
157 phydev->adjust_link = NULL;
158
159 phy_detach(phydev);
160}
161EXPORT_SYMBOL(phy_disconnect);
162
163#endif /* CONFIG_PHYCONTROL */
164
165/* phy_attach:
166 *
167 * description: Called by drivers to attach to a particular PHY
168 * device. The phy_device is found, and properly hooked up
169 * to the phy_driver. If no driver is attached, then the
170 * genphy_driver is used. The phy_device is given a ptr to
171 * the attaching device, and given a callback for link status
172 * change. The phy_device is returned to the attaching
173 * driver.
174 */
175static int phy_compare_id(struct device *dev, void *data)
176{
177 return strcmp((char *)data, dev->bus_id) ? 0 : 1;
178}
179
180struct phy_device *phy_attach(struct net_device *dev,
181 const char *phy_id, u32 flags)
182{
183 struct bus_type *bus = &mdio_bus_type;
184 struct phy_device *phydev;
185 struct device *d;
186
187 /* Search the list of PHY devices on the mdio bus for the
188 * PHY with the requested name */
189 d = bus_find_device(bus, NULL, (void *)phy_id, phy_compare_id);
190
191 if (d) {
192 phydev = to_phy_device(d);
193 } else {
194 printk(KERN_ERR "%s not found\n", phy_id);
195 return ERR_PTR(-ENODEV);
196 }
197
198 /* Assume that if there is no driver, that it doesn't
199 * exist, and we should use the genphy driver. */
200 if (NULL == d->driver) {
201 int err;
202 down_write(&d->bus->subsys.rwsem);
203 d->driver = &genphy_driver.driver;
204
205 err = d->driver->probe(d);
206
207 if (err < 0)
208 return ERR_PTR(err);
209
210 device_bind_driver(d);
211 up_write(&d->bus->subsys.rwsem);
212 }
213
214 if (phydev->attached_dev) {
215 printk(KERN_ERR "%s: %s already attached\n",
216 dev->name, phy_id);
217 return ERR_PTR(-EBUSY);
218 }
219
220 phydev->attached_dev = dev;
221
222 phydev->dev_flags = flags;
223
224 return phydev;
225}
226EXPORT_SYMBOL(phy_attach);
227
228void phy_detach(struct phy_device *phydev)
229{
230 phydev->attached_dev = NULL;
231
232 /* If the device had no specific driver before (i.e. - it
233 * was using the generic driver), we unbind the device
234 * from the generic driver so that there's a chance a
235 * real driver could be loaded */
236 if (phydev->dev.driver == &genphy_driver.driver) {
237 down_write(&phydev->dev.bus->subsys.rwsem);
238 device_release_driver(&phydev->dev);
239 up_write(&phydev->dev.bus->subsys.rwsem);
240 }
241}
242EXPORT_SYMBOL(phy_detach);
243
244
127/* Generic PHY support and helper functions */ 245/* Generic PHY support and helper functions */
128 246
129/* genphy_config_advert 247/* genphy_config_advert
@@ -132,7 +250,7 @@ void phy_prepare_link(struct phy_device *phydev,
132 * after sanitizing the values to make sure we only advertise 250 * after sanitizing the values to make sure we only advertise
133 * what is supported 251 * what is supported
134 */ 252 */
135static int genphy_config_advert(struct phy_device *phydev) 253int genphy_config_advert(struct phy_device *phydev)
136{ 254{
137 u32 advertise; 255 u32 advertise;
138 int adv; 256 int adv;
@@ -190,6 +308,7 @@ static int genphy_config_advert(struct phy_device *phydev)
190 308
191 return adv; 309 return adv;
192} 310}
311EXPORT_SYMBOL(genphy_config_advert);
193 312
194/* genphy_setup_forced 313/* genphy_setup_forced
195 * 314 *
@@ -541,32 +660,37 @@ void phy_driver_unregister(struct phy_driver *drv)
541} 660}
542EXPORT_SYMBOL(phy_driver_unregister); 661EXPORT_SYMBOL(phy_driver_unregister);
543 662
663static struct phy_driver genphy_driver = {
664 .phy_id = 0xffffffff,
665 .phy_id_mask = 0xffffffff,
666 .name = "Generic PHY",
667 .config_init = genphy_config_init,
668 .features = 0,
669 .config_aneg = genphy_config_aneg,
670 .read_status = genphy_read_status,
671 .driver = {.owner= THIS_MODULE, },
672};
544 673
545static int __init phy_init(void) 674static int __init phy_init(void)
546{ 675{
547 int rc; 676 int rc;
548 extern int mdio_bus_init(void);
549
550 rc = phy_driver_register(&genphy_driver);
551 if (rc)
552 goto out;
553 677
554 rc = mdio_bus_init(); 678 rc = mdio_bus_init();
555 if (rc) 679 if (rc)
556 goto out_unreg; 680 return rc;
557 681
558 return 0; 682 rc = phy_driver_register(&genphy_driver);
683 if (rc)
684 mdio_bus_exit();
559 685
560out_unreg:
561 phy_driver_unregister(&genphy_driver);
562out:
563 return rc; 686 return rc;
564} 687}
565 688
566static void __exit phy_exit(void) 689static void __exit phy_exit(void)
567{ 690{
568 phy_driver_unregister(&genphy_driver); 691 phy_driver_unregister(&genphy_driver);
692 mdio_bus_exit();
569} 693}
570 694
571module_init(phy_init); 695subsys_initcall(phy_init);
572module_exit(phy_exit); 696module_exit(phy_exit);