summaryrefslogtreecommitdiffstats
path: root/drivers/net/phy/mdio_bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/phy/mdio_bus.c')
-rw-r--r--drivers/net/phy/mdio_bus.c146
1 files changed, 108 insertions, 38 deletions
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 99d23ffedf..eed7c779e7 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -19,16 +19,68 @@
#include <clock.h>
#include <net.h>
#include <errno.h>
+#include <linux/mdio.h>
#include <linux/phy.h>
#include <linux/err.h>
#include <of_device.h>
+#include <pinctrl.h>
#define DEFAULT_GPIO_RESET_ASSERT 1000 /* us */
#define DEFAULT_GPIO_RESET_DEASSERT 1000 /* us */
LIST_HEAD(mii_bus_list);
-int mdiobus_detect(struct device_d *dev)
+static struct phy_device *mdio_device_create(struct mii_bus *bus, int addr)
+{
+ struct phy_device *phydev;
+
+ phydev = xzalloc(sizeof(*phydev));
+
+ phydev->addr = addr;
+ phydev->bus = bus;
+ phydev->dev.bus = &mdio_bus_type;
+
+ dev_set_name(&phydev->dev, "mdio%d-dev%02x", phydev->bus->dev.id,
+ phydev->addr);
+ phydev->dev.id = DEVICE_ID_SINGLE;
+
+ return phydev;
+}
+
+static int mdio_register_device(struct phy_device *phydev)
+{
+ int ret;
+
+ if (phydev->registered)
+ return -EBUSY;
+
+ if (!phydev->dev.parent)
+ phydev->dev.parent = &phydev->bus->dev;
+
+ ret = register_device(&phydev->dev);
+ if (ret)
+ return ret;
+
+ if (phydev->bus)
+ phydev->bus->phy_map[phydev->addr] = phydev;
+
+ phydev->registered = 1;
+
+ if (phydev->dev.driver)
+ return 0;
+
+ return ret;
+}
+
+int mdio_driver_register(struct phy_driver *phydrv)
+{
+ phydrv->drv.bus = &mdio_bus_type;
+ phydrv->is_phy = false;
+
+ return register_driver(&phydrv->drv);
+}
+
+int mdiobus_detect(struct device *dev)
{
struct mii_bus *mii = to_mii_bus(dev);
int i, ret;
@@ -67,7 +119,8 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
* Associate the OF node with the device structure so it
* can be looked up later
*/
- phy->dev.device_node = child;
+ child->dev = &phy->dev;
+ phy->dev.of_node = child;
/*
* All data is now stored in the phy struct;
@@ -83,6 +136,29 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
return 0;
}
+static int of_mdiobus_register_device(struct mii_bus *mdio,
+ struct device_node *child, u32 addr)
+{
+ struct phy_device *mdiodev;
+ int ret;
+
+ mdiodev = mdio_device_create(mdio, addr);
+ if (IS_ERR(mdiodev))
+ return PTR_ERR(mdiodev);
+
+ child->dev = &mdiodev->dev;
+ mdiodev->dev.of_node = child;
+
+ ret = mdio_register_device(mdiodev);
+ if (ret)
+ return ret;
+
+ dev_dbg(&mdio->dev, "registered mdio device %s at address %i\n",
+ child->name, addr);
+
+ return 0;
+}
+
/*
* Node is considered a PHY node if:
* o Compatible string of "ethernet-phy-idX.X"
@@ -175,35 +251,27 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
/* Loop over the child nodes and register a phy_device for each one */
for_each_available_child_of_node(np, child) {
- if (!of_mdiobus_child_is_phy(child)) {
- if (of_get_property(child, "compatible", NULL)) {
- if (!of_platform_device_create(child,
- &mdio->dev)) {
- dev_err(&mdio->dev,
- "Failed to create device "
- "for %s\n",
- child->full_name);
- }
- }
-
- continue;
- }
-
ret = of_property_read_u32(child, "reg", &addr);
if (ret) {
- dev_dbg(&mdio->dev, "%s has invalid PHY address\n",
- child->full_name);
+ dev_dbg(&mdio->dev, "%pOF has invalid PHY address\n",
+ child);
continue;
}
if (addr >= PHY_MAX_ADDR) {
- dev_err(&mdio->dev, "%s PHY address %i is too large\n",
- child->full_name, addr);
+ dev_err(&mdio->dev, "%pOF PHY address %i is too large\n",
+ child, addr);
continue;
}
- of_mdiobus_reset_phy(mdio, child);
- of_mdiobus_register_phy(mdio, child, addr);
+ of_pinctrl_select_state_default(child);
+
+ if (of_mdiobus_child_is_phy(child)) {
+ of_mdiobus_reset_phy(mdio, child);
+ of_mdiobus_register_phy(mdio, child, addr);
+ } else {
+ of_mdiobus_register_device(mdio, child, addr);
+ }
}
return 0;
@@ -248,16 +316,14 @@ int mdiobus_register(struct mii_bus *bus)
pr_info("%s: probed\n", dev_name(&bus->dev));
- if (bus->dev.device_node) {
+ if (!bus->dev.of_node)
+ bus->dev.of_node = bus->parent->of_node;
+
+ if (bus->dev.of_node) {
+ bus->dev.of_node->dev = &bus->dev;
+
/* Register PHY's as child node to mdio node */
- of_mdiobus_register(bus, bus->dev.device_node);
- }
- else if (bus->parent->device_node) {
- /*
- * Register PHY's as child node to the ethernet node,
- * if there was no mdio node
- */
- of_mdiobus_register(bus, bus->parent->device_node);
+ of_mdiobus_register(bus, bus->dev.of_node);
}
return 0;
@@ -333,7 +399,7 @@ struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np)
return NULL;
for_each_mii_bus(mii)
- if (mii->dev.device_node == mdio_bus_np)
+ if (mii->dev.of_node == mdio_bus_np)
return mii;
return NULL;
@@ -349,14 +415,18 @@ EXPORT_SYMBOL(of_mdio_find_bus);
* Description: Given a PHY device, and a PHY driver, return 0 if
* the driver supports the device. Otherwise, return 1.
*/
-static int mdio_bus_match(struct device_d *dev, struct driver_d *drv)
+static int mdio_bus_match(struct device *dev, struct driver *drv)
{
struct phy_device *phydev = to_phy_device(dev);
struct phy_driver *phydrv = to_phy_driver(drv);
- if ((phydrv->phy_id & phydrv->phy_id_mask) ==
- (phydev->phy_id & phydrv->phy_id_mask))
+ if (phydrv->is_phy) {
+ if ((phydrv->phy_id & phydrv->phy_id_mask) ==
+ (phydev->phy_id & phydrv->phy_id_mask))
return 0;
+ } else {
+ return device_match(dev, drv);
+ }
return 1;
}
@@ -439,7 +509,7 @@ static struct cdev_operations phydev_ops = {
static void of_set_phy_supported(struct phy_device *phydev)
{
- struct device_node *node = phydev->dev.device_node;
+ struct device_node *node = phydev->dev.of_node;
u32 max_speed;
if (!IS_ENABLED(CONFIG_OFDEVICE))
@@ -470,7 +540,7 @@ static void of_set_phy_supported(struct phy_device *phydev)
}
}
-static int mdio_bus_probe(struct device_d *_dev)
+static int mdio_bus_probe(struct device *_dev)
{
struct phy_device *dev = to_phy_device(_dev);
struct phy_driver *drv = to_phy_driver(_dev->driver);
@@ -524,7 +594,7 @@ err:
return ret;
}
-static void mdio_bus_remove(struct device_d *_dev)
+static void mdio_bus_remove(struct device *_dev)
{
struct phy_device *dev = to_phy_device(_dev);
struct phy_driver *drv = to_phy_driver(_dev->driver);