Skip to content

Commit

Permalink
Merge branch 'of_mdio'
Browse files Browse the repository at this point in the history
Daniel Mack says:

====================
mdio: Parse DT nodes for auto-probed PHYs

Here's v2.

v1 -> v2:
	* Switch to of_property_read_u32() in patch #1
	* Check for mdio->dev_of_node in patch #2
	* Added Florian's Reviewed-by: tags
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
davem330 committed May 29, 2014
2 parents 6623b41 + 24f28dd commit c3aad35
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 14 deletions.
6 changes: 6 additions & 0 deletions drivers/net/phy/mdio_bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,12 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr)
if (IS_ERR(phydev) || phydev == NULL)
return phydev;

/*
* For DT, see if the auto-probed phy has a correspoding child
* in the bus node, and set the of_node pointer in this case.
*/
of_mdiobus_link_phydev(bus, phydev);

err = phy_device_register(phydev);
if (err) {
phy_device_free(phydev);
Expand Down
72 changes: 58 additions & 14 deletions drivers/of/of_mdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,27 @@ static int of_mdiobus_register_phy(struct mii_bus *mdio, struct device_node *chi
return 0;
}

static int of_mdio_parse_addr(struct device *dev, const struct device_node *np)
{
u32 addr;
int ret;

ret = of_property_read_u32(np, "reg", &addr);
if (ret < 0) {
dev_err(dev, "%s has invalid PHY address\n", np->full_name);
return ret;
}

/* A PHY must have a reg property in the range [0-31] */
if (addr >= PHY_MAX_ADDR) {
dev_err(dev, "%s PHY address %i is too large\n",
np->full_name, addr);
return -EINVAL;
}

return addr;
}

/**
* of_mdiobus_register - Register mii_bus and create PHYs from the device tree
* @mdio: pointer to mii_bus structure
Expand All @@ -102,7 +123,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
const __be32 *paddr;
u32 addr;
bool scanphys = false;
int rc, i, len;
int rc, i;

/* Mask out all PHYs from auto probing. Instead the PHYs listed in
* the device tree are populated after the bus has been registered */
Expand All @@ -122,19 +143,9 @@ 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) {
/* A PHY must have a reg property in the range [0-31] */
paddr = of_get_property(child, "reg", &len);
if (!paddr || len < sizeof(*paddr)) {
addr = of_mdio_parse_addr(&mdio->dev, child);
if (addr < 0) {
scanphys = true;
dev_err(&mdio->dev, "%s has invalid PHY address\n",
child->full_name);
continue;
}

addr = be32_to_cpup(paddr);
if (addr >= PHY_MAX_ADDR) {
dev_err(&mdio->dev, "%s PHY address %i is too large\n",
child->full_name, addr);
continue;
}

Expand All @@ -149,7 +160,7 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
/* auto scan for PHYs with empty reg property */
for_each_available_child_of_node(np, child) {
/* Skip PHYs with reg property set */
paddr = of_get_property(child, "reg", &len);
paddr = of_get_property(child, "reg", NULL);
if (paddr)
continue;

Expand All @@ -172,6 +183,39 @@ int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
}
EXPORT_SYMBOL(of_mdiobus_register);

/**
* of_mdiobus_link_phydev - Find a device node for a phy
* @mdio: pointer to mii_bus structure
* @phydev: phydev for which the of_node pointer should be set
*
* Walk the list of subnodes of a mdio bus and look for a node that matches the
* phy's address with its 'reg' property. If found, set the of_node pointer for
* the phy. This allows auto-probed pyh devices to be supplied with information
* passed in via DT.
*/
void of_mdiobus_link_phydev(struct mii_bus *mdio,
struct phy_device *phydev)
{
struct device *dev = &phydev->dev;
struct device_node *child;

if (dev->of_node || !mdio->dev.of_node)
return;

for_each_available_child_of_node(mdio->dev.of_node, child) {
int addr;

addr = of_mdio_parse_addr(&mdio->dev, child);
if (addr < 0)
continue;

if (addr == phydev->addr) {
dev->of_node = child;
return;
}
}
}

/* Helper function for of_phy_find_device */
static int of_phy_match(struct device *dev, void *phy_np)
{
Expand Down
8 changes: 8 additions & 0 deletions include/linux/of_mdio.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ struct phy_device *of_phy_attach(struct net_device *dev,

extern struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np);

extern void of_mdiobus_link_phydev(struct mii_bus *mdio,
struct phy_device *phydev);

#else /* CONFIG_OF */
static inline int of_mdiobus_register(struct mii_bus *mdio, struct device_node *np)
{
Expand Down Expand Up @@ -60,6 +63,11 @@ static inline struct mii_bus *of_mdio_find_bus(struct device_node *mdio_np)
{
return NULL;
}

static inline void of_mdiobus_link_phydev(struct mii_bus *mdio,
struct phy_device *phydev)
{
}
#endif /* CONFIG_OF */

#if defined(CONFIG_OF) && defined(CONFIG_FIXED_PHY)
Expand Down

0 comments on commit c3aad35

Please sign in to comment.