diff options
Diffstat (limited to 'drivers/net/phy/phy_device.c')
-rw-r--r-- | drivers/net/phy/phy_device.c | 163 |
1 files changed, 126 insertions, 37 deletions
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 0a06e4fd37d9..a2ece89622d6 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c | |||
@@ -39,20 +39,21 @@ MODULE_DESCRIPTION("PHY library"); | |||
39 | MODULE_AUTHOR("Andy Fleming"); | 39 | MODULE_AUTHOR("Andy Fleming"); |
40 | MODULE_LICENSE("GPL"); | 40 | MODULE_LICENSE("GPL"); |
41 | 41 | ||
42 | static struct phy_driver genphy_driver; | ||
43 | extern int mdio_bus_init(void); | ||
44 | extern void mdio_bus_exit(void); | ||
45 | |||
46 | void phy_device_free(struct phy_device *phydev) | 42 | void phy_device_free(struct phy_device *phydev) |
47 | { | 43 | { |
48 | kfree(phydev); | 44 | kfree(phydev); |
49 | } | 45 | } |
46 | EXPORT_SYMBOL(phy_device_free); | ||
50 | 47 | ||
51 | static void phy_device_release(struct device *dev) | 48 | static void phy_device_release(struct device *dev) |
52 | { | 49 | { |
53 | phy_device_free(to_phy_device(dev)); | 50 | phy_device_free(to_phy_device(dev)); |
54 | } | 51 | } |
55 | 52 | ||
53 | static struct phy_driver genphy_driver; | ||
54 | extern int mdio_bus_init(void); | ||
55 | extern void mdio_bus_exit(void); | ||
56 | |||
56 | static LIST_HEAD(phy_fixup_list); | 57 | static LIST_HEAD(phy_fixup_list); |
57 | static DEFINE_MUTEX(phy_fixup_lock); | 58 | static DEFINE_MUTEX(phy_fixup_lock); |
58 | 59 | ||
@@ -166,6 +167,10 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id) | |||
166 | dev->addr = addr; | 167 | dev->addr = addr; |
167 | dev->phy_id = phy_id; | 168 | dev->phy_id = phy_id; |
168 | dev->bus = bus; | 169 | dev->bus = bus; |
170 | dev->dev.parent = bus->parent; | ||
171 | dev->dev.bus = &mdio_bus_type; | ||
172 | dev->irq = bus->irq != NULL ? bus->irq[addr] : PHY_POLL; | ||
173 | dev_set_name(&dev->dev, PHY_ID_FMT, bus->id, addr); | ||
169 | 174 | ||
170 | dev->state = PHY_DOWN; | 175 | dev->state = PHY_DOWN; |
171 | 176 | ||
@@ -235,6 +240,38 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) | |||
235 | 240 | ||
236 | return dev; | 241 | return dev; |
237 | } | 242 | } |
243 | EXPORT_SYMBOL(get_phy_device); | ||
244 | |||
245 | /** | ||
246 | * phy_device_register - Register the phy device on the MDIO bus | ||
247 | * @phy_device: phy_device structure to be added to the MDIO bus | ||
248 | */ | ||
249 | int phy_device_register(struct phy_device *phydev) | ||
250 | { | ||
251 | int err; | ||
252 | |||
253 | /* Don't register a phy if one is already registered at this | ||
254 | * address */ | ||
255 | if (phydev->bus->phy_map[phydev->addr]) | ||
256 | return -EINVAL; | ||
257 | phydev->bus->phy_map[phydev->addr] = phydev; | ||
258 | |||
259 | /* Run all of the fixups for this PHY */ | ||
260 | phy_scan_fixups(phydev); | ||
261 | |||
262 | err = device_register(&phydev->dev); | ||
263 | if (err) { | ||
264 | pr_err("phy %d failed to register\n", phydev->addr); | ||
265 | goto out; | ||
266 | } | ||
267 | |||
268 | return 0; | ||
269 | |||
270 | out: | ||
271 | phydev->bus->phy_map[phydev->addr] = NULL; | ||
272 | return err; | ||
273 | } | ||
274 | EXPORT_SYMBOL(phy_device_register); | ||
238 | 275 | ||
239 | /** | 276 | /** |
240 | * phy_prepare_link - prepares the PHY layer to monitor link status | 277 | * phy_prepare_link - prepares the PHY layer to monitor link status |
@@ -255,6 +292,33 @@ void phy_prepare_link(struct phy_device *phydev, | |||
255 | } | 292 | } |
256 | 293 | ||
257 | /** | 294 | /** |
295 | * phy_connect_direct - connect an ethernet device to a specific phy_device | ||
296 | * @dev: the network device to connect | ||
297 | * @phydev: the pointer to the phy device | ||
298 | * @handler: callback function for state change notifications | ||
299 | * @flags: PHY device's dev_flags | ||
300 | * @interface: PHY device's interface | ||
301 | */ | ||
302 | int phy_connect_direct(struct net_device *dev, struct phy_device *phydev, | ||
303 | void (*handler)(struct net_device *), u32 flags, | ||
304 | phy_interface_t interface) | ||
305 | { | ||
306 | int rc; | ||
307 | |||
308 | rc = phy_attach_direct(dev, phydev, flags, interface); | ||
309 | if (rc) | ||
310 | return rc; | ||
311 | |||
312 | phy_prepare_link(phydev, handler); | ||
313 | phy_start_machine(phydev, NULL); | ||
314 | if (phydev->irq > 0) | ||
315 | phy_start_interrupts(phydev); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | EXPORT_SYMBOL(phy_connect_direct); | ||
320 | |||
321 | /** | ||
258 | * phy_connect - connect an ethernet device to a PHY device | 322 | * phy_connect - connect an ethernet device to a PHY device |
259 | * @dev: the network device to connect | 323 | * @dev: the network device to connect |
260 | * @bus_id: the id string of the PHY device to connect | 324 | * @bus_id: the id string of the PHY device to connect |
@@ -275,18 +339,21 @@ struct phy_device * phy_connect(struct net_device *dev, const char *bus_id, | |||
275 | phy_interface_t interface) | 339 | phy_interface_t interface) |
276 | { | 340 | { |
277 | struct phy_device *phydev; | 341 | struct phy_device *phydev; |
342 | struct device *d; | ||
343 | int rc; | ||
278 | 344 | ||
279 | phydev = phy_attach(dev, bus_id, flags, interface); | 345 | /* Search the list of PHY devices on the mdio bus for the |
280 | 346 | * PHY with the requested name */ | |
281 | if (IS_ERR(phydev)) | 347 | d = bus_find_device_by_name(&mdio_bus_type, NULL, bus_id); |
282 | return phydev; | 348 | if (!d) { |
283 | 349 | pr_err("PHY %s not found\n", bus_id); | |
284 | phy_prepare_link(phydev, handler); | 350 | return ERR_PTR(-ENODEV); |
285 | 351 | } | |
286 | phy_start_machine(phydev, NULL); | 352 | phydev = to_phy_device(d); |
287 | 353 | ||
288 | if (phydev->irq > 0) | 354 | rc = phy_connect_direct(dev, phydev, handler, flags, interface); |
289 | phy_start_interrupts(phydev); | 355 | if (rc) |
356 | return ERR_PTR(rc); | ||
290 | 357 | ||
291 | return phydev; | 358 | return phydev; |
292 | } | 359 | } |
@@ -310,9 +377,9 @@ void phy_disconnect(struct phy_device *phydev) | |||
310 | EXPORT_SYMBOL(phy_disconnect); | 377 | EXPORT_SYMBOL(phy_disconnect); |
311 | 378 | ||
312 | /** | 379 | /** |
313 | * phy_attach - attach a network device to a particular PHY device | 380 | * phy_attach_direct - attach a network device to a given PHY device pointer |
314 | * @dev: network device to attach | 381 | * @dev: network device to attach |
315 | * @bus_id: PHY device to attach | 382 | * @phydev: Pointer to phy_device to attach |
316 | * @flags: PHY device's dev_flags | 383 | * @flags: PHY device's dev_flags |
317 | * @interface: PHY device's interface | 384 | * @interface: PHY device's interface |
318 | * | 385 | * |
@@ -323,22 +390,10 @@ EXPORT_SYMBOL(phy_disconnect); | |||
323 | * the attaching device, and given a callback for link status | 390 | * the attaching device, and given a callback for link status |
324 | * change. The phy_device is returned to the attaching driver. | 391 | * change. The phy_device is returned to the attaching driver. |
325 | */ | 392 | */ |
326 | struct phy_device *phy_attach(struct net_device *dev, | 393 | int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, |
327 | const char *bus_id, u32 flags, phy_interface_t interface) | 394 | u32 flags, phy_interface_t interface) |
328 | { | 395 | { |
329 | struct bus_type *bus = &mdio_bus_type; | 396 | struct device *d = &phydev->dev; |
330 | struct phy_device *phydev; | ||
331 | struct device *d; | ||
332 | |||
333 | /* Search the list of PHY devices on the mdio bus for the | ||
334 | * PHY with the requested name */ | ||
335 | d = bus_find_device_by_name(bus, NULL, bus_id); | ||
336 | if (d) { | ||
337 | phydev = to_phy_device(d); | ||
338 | } else { | ||
339 | printk(KERN_ERR "%s not found\n", bus_id); | ||
340 | return ERR_PTR(-ENODEV); | ||
341 | } | ||
342 | 397 | ||
343 | /* Assume that if there is no driver, that it doesn't | 398 | /* Assume that if there is no driver, that it doesn't |
344 | * exist, and we should use the genphy driver. */ | 399 | * exist, and we should use the genphy driver. */ |
@@ -351,13 +406,12 @@ struct phy_device *phy_attach(struct net_device *dev, | |||
351 | err = device_bind_driver(d); | 406 | err = device_bind_driver(d); |
352 | 407 | ||
353 | if (err) | 408 | if (err) |
354 | return ERR_PTR(err); | 409 | return err; |
355 | } | 410 | } |
356 | 411 | ||
357 | if (phydev->attached_dev) { | 412 | if (phydev->attached_dev) { |
358 | printk(KERN_ERR "%s: %s already attached\n", | 413 | dev_err(&dev->dev, "PHY already attached\n"); |
359 | dev->name, bus_id); | 414 | return -EBUSY; |
360 | return ERR_PTR(-EBUSY); | ||
361 | } | 415 | } |
362 | 416 | ||
363 | phydev->attached_dev = dev; | 417 | phydev->attached_dev = dev; |
@@ -375,14 +429,49 @@ struct phy_device *phy_attach(struct net_device *dev, | |||
375 | err = phy_scan_fixups(phydev); | 429 | err = phy_scan_fixups(phydev); |
376 | 430 | ||
377 | if (err < 0) | 431 | if (err < 0) |
378 | return ERR_PTR(err); | 432 | return err; |
379 | 433 | ||
380 | err = phydev->drv->config_init(phydev); | 434 | err = phydev->drv->config_init(phydev); |
381 | 435 | ||
382 | if (err < 0) | 436 | if (err < 0) |
383 | return ERR_PTR(err); | 437 | return err; |
384 | } | 438 | } |
385 | 439 | ||
440 | return 0; | ||
441 | } | ||
442 | EXPORT_SYMBOL(phy_attach_direct); | ||
443 | |||
444 | /** | ||
445 | * phy_attach - attach a network device to a particular PHY device | ||
446 | * @dev: network device to attach | ||
447 | * @bus_id: Bus ID of PHY device to attach | ||
448 | * @flags: PHY device's dev_flags | ||
449 | * @interface: PHY device's interface | ||
450 | * | ||
451 | * Description: Same as phy_attach_direct() except that a PHY bus_id | ||
452 | * string is passed instead of a pointer to a struct phy_device. | ||
453 | */ | ||
454 | struct phy_device *phy_attach(struct net_device *dev, | ||
455 | const char *bus_id, u32 flags, phy_interface_t interface) | ||
456 | { | ||
457 | struct bus_type *bus = &mdio_bus_type; | ||
458 | struct phy_device *phydev; | ||
459 | struct device *d; | ||
460 | int rc; | ||
461 | |||
462 | /* Search the list of PHY devices on the mdio bus for the | ||
463 | * PHY with the requested name */ | ||
464 | d = bus_find_device_by_name(bus, NULL, bus_id); | ||
465 | if (!d) { | ||
466 | pr_err("PHY %s not found\n", bus_id); | ||
467 | return ERR_PTR(-ENODEV); | ||
468 | } | ||
469 | phydev = to_phy_device(d); | ||
470 | |||
471 | rc = phy_attach_direct(dev, phydev, flags, interface); | ||
472 | if (rc) | ||
473 | return ERR_PTR(rc); | ||
474 | |||
386 | return phydev; | 475 | return phydev; |
387 | } | 476 | } |
388 | EXPORT_SYMBOL(phy_attach); | 477 | EXPORT_SYMBOL(phy_attach); |