diff options
Diffstat (limited to 'drivers/net/mdio/fwnode_mdio.c')
| -rw-r--r-- | drivers/net/mdio/fwnode_mdio.c | 58 | 
1 files changed, 47 insertions, 11 deletions
diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c index 1c1584fca632..689e728345ce 100644 --- a/drivers/net/mdio/fwnode_mdio.c +++ b/drivers/net/mdio/fwnode_mdio.c @@ -10,10 +10,31 @@  #include <linux/fwnode_mdio.h>  #include <linux/of.h>  #include <linux/phy.h> +#include <linux/pse-pd/pse.h>  MODULE_AUTHOR("Calvin Johnson <calvin.johnson@oss.nxp.com>");  MODULE_LICENSE("GPL"); +static struct pse_control * +fwnode_find_pse_control(struct fwnode_handle *fwnode) +{ +	struct pse_control *psec; +	struct device_node *np; + +	if (!IS_ENABLED(CONFIG_PSE_CONTROLLER)) +		return NULL; + +	np = to_of_node(fwnode); +	if (!np) +		return NULL; + +	psec = of_pse_control_get(np); +	if (PTR_ERR(psec) == -ENOENT) +		return NULL; + +	return psec; +} +  static struct mii_timestamper *  fwnode_find_mii_timestamper(struct fwnode_handle *fwnode)  { @@ -91,14 +112,21 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,  				struct fwnode_handle *child, u32 addr)  {  	struct mii_timestamper *mii_ts = NULL; +	struct pse_control *psec = NULL;  	struct phy_device *phy;  	bool is_c45 = false;  	u32 phy_id;  	int rc; +	psec = fwnode_find_pse_control(child); +	if (IS_ERR(psec)) +		return PTR_ERR(psec); +  	mii_ts = fwnode_find_mii_timestamper(child); -	if (IS_ERR(mii_ts)) -		return PTR_ERR(mii_ts); +	if (IS_ERR(mii_ts)) { +		rc = PTR_ERR(mii_ts); +		goto clean_pse; +	}  	rc = fwnode_property_match_string(child, "compatible",  					  "ethernet-phy-ieee802.3-c45"); @@ -110,8 +138,8 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,  	else  		phy = phy_device_create(bus, addr, phy_id, 0, NULL);  	if (IS_ERR(phy)) { -		unregister_mii_timestamper(mii_ts); -		return PTR_ERR(phy); +		rc = PTR_ERR(phy); +		goto clean_mii_ts;  	}  	if (is_acpi_node(child)) { @@ -125,25 +153,33 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,  		/* All data is now stored in the phy struct, so register it */  		rc = phy_device_register(phy);  		if (rc) { -			phy_device_free(phy);  			fwnode_handle_put(phy->mdio.dev.fwnode); -			return rc; +			goto clean_phy;  		}  	} else if (is_of_node(child)) {  		rc = fwnode_mdiobus_phy_device_register(bus, phy, child, addr); -		if (rc) { -			unregister_mii_timestamper(mii_ts); -			phy_device_free(phy); -			return rc; -		} +		if (rc) +			goto clean_phy;  	} +	phy->psec = psec; +  	/* phy->mii_ts may already be defined by the PHY driver. A  	 * mii_timestamper probed via the device tree will still have  	 * precedence.  	 */  	if (mii_ts)  		phy->mii_ts = mii_ts; +  	return 0; + +clean_phy: +	phy_device_free(phy); +clean_mii_ts: +	unregister_mii_timestamper(mii_ts); +clean_pse: +	pse_control_put(psec); + +	return rc;  }  EXPORT_SYMBOL(fwnode_mdiobus_register_phy);  | 
