From 00db8189d984d6c51226dafbbe4a667ce9b7d5da Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Sat, 30 Jul 2005 19:31:23 -0400 Subject: This patch adds a PHY Abstraction Layer to the Linux Kernel, enabling ethernet drivers to remain as ignorant as is reasonable of the connected PHY's design and operation details. Signed-off-by: Andy Fleming Signed-off-by: Jeff Garzik --- drivers/net/phy/mdio_bus.c | 173 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 173 insertions(+) create mode 100644 drivers/net/phy/mdio_bus.c (limited to 'drivers/net/phy/mdio_bus.c') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c new file mode 100644 index 000000000000..e75103ba6f86 --- /dev/null +++ b/drivers/net/phy/mdio_bus.c @@ -0,0 +1,173 @@ +/* + * drivers/net/phy/mdio_bus.c + * + * MDIO Bus interface + * + * Author: Andy Fleming + * + * Copyright (c) 2004 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* mdiobus_register + * + * description: Called by a bus driver to bring up all the PHYs + * on a given bus, and attach them to the bus + */ +int mdiobus_register(struct mii_bus *bus) +{ + int i; + int err = 0; + + spin_lock_init(&bus->mdio_lock); + + if (NULL == bus || NULL == bus->name || + NULL == bus->read || + NULL == bus->write) + return -EINVAL; + + if (bus->reset) + bus->reset(bus); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev; + + phydev = get_phy_device(bus, i); + + if (IS_ERR(phydev)) + return PTR_ERR(phydev); + + /* There's a PHY at this address + * We need to set: + * 1) IRQ + * 2) bus_id + * 3) parent + * 4) bus + * 5) mii_bus + * And, we need to register it */ + if (phydev) { + phydev->irq = bus->irq[i]; + + phydev->dev.parent = bus->dev; + phydev->dev.bus = &mdio_bus_type; + sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i); + + phydev->bus = bus; + + err = device_register(&phydev->dev); + + if (err) + printk(KERN_ERR "phy %d failed to register\n", + i); + } + + bus->phy_map[i] = phydev; + } + + pr_info("%s: probed\n", bus->name); + + return err; +} +EXPORT_SYMBOL(mdiobus_register); + +void mdiobus_unregister(struct mii_bus *bus) +{ + int i; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (bus->phy_map[i]) { + device_unregister(&bus->phy_map[i]->dev); + kfree(bus->phy_map[i]); + } + } +} +EXPORT_SYMBOL(mdiobus_unregister); + +/* mdio_bus_match + * + * description: Given a PHY device, and a PHY driver, return 1 if + * the driver supports the device. Otherwise, return 0 + */ +static int mdio_bus_match(struct device *dev, struct device_driver *drv) +{ + struct phy_device *phydev = to_phy_device(dev); + struct phy_driver *phydrv = to_phy_driver(drv); + + return (phydrv->phy_id == (phydev->phy_id & phydrv->phy_id_mask)); +} + +/* Suspend and resume. Copied from platform_suspend and + * platform_resume + */ +static int mdio_bus_suspend(struct device * dev, u32 state) +{ + int ret = 0; + struct device_driver *drv = dev->driver; + + if (drv && drv->suspend) { + ret = drv->suspend(dev, state, SUSPEND_DISABLE); + if (ret == 0) + ret = drv->suspend(dev, state, SUSPEND_SAVE_STATE); + if (ret == 0) + ret = drv->suspend(dev, state, SUSPEND_POWER_DOWN); + } + return ret; +} + +static int mdio_bus_resume(struct device * dev) +{ + int ret = 0; + struct device_driver *drv = dev->driver; + + if (drv && drv->resume) { + ret = drv->resume(dev, RESUME_POWER_ON); + if (ret == 0) + ret = drv->resume(dev, RESUME_RESTORE_STATE); + if (ret == 0) + ret = drv->resume(dev, RESUME_ENABLE); + } + return ret; +} + +struct bus_type mdio_bus_type = { + .name = "mdio_bus", + .match = mdio_bus_match, + .suspend = mdio_bus_suspend, + .resume = mdio_bus_resume, +}; + +static int __init mdio_bus_init(void) +{ + return bus_register(&mdio_bus_type); +} + +subsys_initcall(mdio_bus_init); -- cgit v1.2.2 From 67c4f3fa25502ce7ed82fb0307e09cf36f1f81da Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 11 Aug 2005 02:07:25 -0400 Subject: Fix numerous minor problems with new phy subsystem. Includes fixes for problems noted by Adrian Bunk, Andrew Morton, and one other person lost in the annals of history (and email folders). --- drivers/net/phy/mdio_bus.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/net/phy/mdio_bus.c') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index e75103ba6f86..5fbea6acfe80 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -165,9 +165,9 @@ struct bus_type mdio_bus_type = { .resume = mdio_bus_resume, }; -static int __init mdio_bus_init(void) +int __init mdio_bus_init(void) { return bus_register(&mdio_bus_type); } -subsys_initcall(mdio_bus_init); + -- cgit v1.2.2 From 2bf69b5fe90b3246ab50064c5a690a363e8c53e2 Mon Sep 17 00:00:00 2001 From: Jeff Garzik Date: Thu, 11 Aug 2005 02:47:54 -0400 Subject: phy subsystem: more cleanups - unexport symbols never used outside of home module - remove dead code - remove CONFIG_PHYCONTROL, make it unconditionally enabled --- drivers/net/phy/mdio_bus.c | 74 ---------------------------------------------- 1 file changed, 74 deletions(-) (limited to 'drivers/net/phy/mdio_bus.c') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 5fbea6acfe80..d5a05be28818 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -38,80 +38,6 @@ #include #include -/* mdiobus_register - * - * description: Called by a bus driver to bring up all the PHYs - * on a given bus, and attach them to the bus - */ -int mdiobus_register(struct mii_bus *bus) -{ - int i; - int err = 0; - - spin_lock_init(&bus->mdio_lock); - - if (NULL == bus || NULL == bus->name || - NULL == bus->read || - NULL == bus->write) - return -EINVAL; - - if (bus->reset) - bus->reset(bus); - - for (i = 0; i < PHY_MAX_ADDR; i++) { - struct phy_device *phydev; - - phydev = get_phy_device(bus, i); - - if (IS_ERR(phydev)) - return PTR_ERR(phydev); - - /* There's a PHY at this address - * We need to set: - * 1) IRQ - * 2) bus_id - * 3) parent - * 4) bus - * 5) mii_bus - * And, we need to register it */ - if (phydev) { - phydev->irq = bus->irq[i]; - - phydev->dev.parent = bus->dev; - phydev->dev.bus = &mdio_bus_type; - sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i); - - phydev->bus = bus; - - err = device_register(&phydev->dev); - - if (err) - printk(KERN_ERR "phy %d failed to register\n", - i); - } - - bus->phy_map[i] = phydev; - } - - pr_info("%s: probed\n", bus->name); - - return err; -} -EXPORT_SYMBOL(mdiobus_register); - -void mdiobus_unregister(struct mii_bus *bus) -{ - int i; - - for (i = 0; i < PHY_MAX_ADDR; i++) { - if (bus->phy_map[i]) { - device_unregister(&bus->phy_map[i]->dev); - kfree(bus->phy_map[i]); - } - } -} -EXPORT_SYMBOL(mdiobus_unregister); - /* mdio_bus_match * * description: Given a PHY device, and a PHY driver, return 1 if -- cgit v1.2.2 From e13934563db047043ccead26412f552375cea90c Mon Sep 17 00:00:00 2001 From: Andy Fleming Date: Wed, 24 Aug 2005 18:46:21 -0500 Subject: [PATCH] PHY Layer fixup This patch adds back the code that was taken out, thus re-enabling: * The PHY Layer to initialize without crashing * Drivers to actually connect to PHYs * The entire PHY Control Layer This patch is used by the gianfar driver, and other drivers which are in development. Signed-off-by: Andy Fleming Signed-off-by: Jeff Garzik --- drivers/net/phy/mdio_bus.c | 79 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) (limited to 'drivers/net/phy/mdio_bus.c') diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index d5a05be28818..41f62c0c5fcb 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -38,6 +38,80 @@ #include #include +/* mdiobus_register + * + * description: Called by a bus driver to bring up all the PHYs + * on a given bus, and attach them to the bus + */ +int mdiobus_register(struct mii_bus *bus) +{ + int i; + int err = 0; + + spin_lock_init(&bus->mdio_lock); + + if (NULL == bus || NULL == bus->name || + NULL == bus->read || + NULL == bus->write) + return -EINVAL; + + if (bus->reset) + bus->reset(bus); + + for (i = 0; i < PHY_MAX_ADDR; i++) { + struct phy_device *phydev; + + phydev = get_phy_device(bus, i); + + if (IS_ERR(phydev)) + return PTR_ERR(phydev); + + /* There's a PHY at this address + * We need to set: + * 1) IRQ + * 2) bus_id + * 3) parent + * 4) bus + * 5) mii_bus + * And, we need to register it */ + if (phydev) { + phydev->irq = bus->irq[i]; + + phydev->dev.parent = bus->dev; + phydev->dev.bus = &mdio_bus_type; + sprintf(phydev->dev.bus_id, "phy%d:%d", bus->id, i); + + phydev->bus = bus; + + err = device_register(&phydev->dev); + + if (err) + printk(KERN_ERR "phy %d failed to register\n", + i); + } + + bus->phy_map[i] = phydev; + } + + pr_info("%s: probed\n", bus->name); + + return err; +} +EXPORT_SYMBOL(mdiobus_register); + +void mdiobus_unregister(struct mii_bus *bus) +{ + int i; + + for (i = 0; i < PHY_MAX_ADDR; i++) { + if (bus->phy_map[i]) { + device_unregister(&bus->phy_map[i]->dev); + kfree(bus->phy_map[i]); + } + } +} +EXPORT_SYMBOL(mdiobus_unregister); + /* mdio_bus_match * * description: Given a PHY device, and a PHY driver, return 1 if @@ -96,4 +170,7 @@ int __init mdio_bus_init(void) return bus_register(&mdio_bus_type); } - +void __exit mdio_bus_exit(void) +{ + bus_unregister(&mdio_bus_type); +} -- cgit v1.2.2