[PATCH v1 2/3] net: add support for MDIO devices
Oleksij Rempel
o.rempel at pengutronix.de
Tue Sep 20 05:55:32 PDT 2022
On the MDIO bus we can have PHYs and some other type of devices.
Typical not_PHY MDIO devices do not have easy detectable ID and can't be
used as-is by the PHY framework. So, add additional handler to register
MDIO devices and drivers alongside with the PHY devices/drivers.
Signed-off-by: Oleksij Rempel <o.rempel at pengutronix.de>
---
drivers/net/phy/mdio_bus.c | 101 ++++++++++++++++++++++++++++++-------
drivers/net/phy/phy.c | 2 +
include/linux/mdio.h | 14 +++++
include/linux/phy.h | 1 +
4 files changed, 101 insertions(+), 17 deletions(-)
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index e37ab79f3e..f06ab68f50 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -19,6 +19,7 @@
#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>
@@ -29,6 +30,56 @@
LIST_HEAD(mii_bus_list);
+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_d *dev)
{
struct mii_bus *mii = to_mii_bus(dev);
@@ -84,6 +135,28 @@ 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);
+
+ mdiodev->dev.device_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"
@@ -176,20 +249,6 @@ 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",
@@ -205,7 +264,11 @@ static int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
of_pinctrl_select_state_default(child);
of_mdiobus_reset_phy(mdio, child);
- of_mdiobus_register_phy(mdio, child, addr);
+
+ if (of_mdiobus_child_is_phy(child))
+ of_mdiobus_register_phy(mdio, child, addr);
+ else
+ of_mdiobus_register_device(mdio, child, addr);
}
return 0;
@@ -356,9 +419,13 @@ static int mdio_bus_match(struct device_d *dev, struct driver_d *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;
}
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 60b5839b40..56ec8a28df 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -933,6 +933,8 @@ int phy_driver_register(struct phy_driver *phydrv)
{
phydrv->drv.bus = &mdio_bus_type;
+ phydrv->is_phy = true;
+
if (!phydrv->config_init)
phydrv->config_init = genphy_config_init;
diff --git a/include/linux/mdio.h b/include/linux/mdio.h
index b910b05cec..a4aee49d8d 100644
--- a/include/linux/mdio.h
+++ b/include/linux/mdio.h
@@ -326,4 +326,18 @@ static inline __u16 mdio_phy_id_c45(int prtad, int devad)
#define MDIO_DEVAD_NONE (-1)
+struct phy_driver;
+
+int mdio_driver_register(struct phy_driver *drv);
+
+#define mdio_register_driver_macro(level, drv) \
+ static int __init drv##_register(void) \
+ { \
+ return mdio_driver_register(&drv); \
+ } \
+ level##_initcall(drv##_register)
+
+#define device_mdio_driver(drv) \
+ mdio_register_driver_macro(device, drv)
+
#endif /* _UAPI__LINUX_MDIO_H__ */
diff --git a/include/linux/phy.h b/include/linux/phy.h
index a4c3f43c06..ba1740ff55 100644
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -223,6 +223,7 @@ struct phy_driver {
unsigned int phy_id_mask;
u32 features;
const void *driver_data;
+ bool is_phy;
/*
* Called to initialize the PHY,
--
2.30.2
More information about the barebox
mailing list