Add handling of optional regulators for PHY. Regulators need to be enabled before PHY scanning, so MDIO bus initiate this task. Signed-off-by: Corentin Labbe <clabbe@xxxxxxxxxxxx> --- drivers/net/mdio/fwnode_mdio.c | 32 ++++++++++++++++++++++++++++++++ drivers/net/phy/phy_device.c | 20 ++++++++++++++++++++ include/linux/phy.h | 3 +++ 3 files changed, 55 insertions(+) diff --git a/drivers/net/mdio/fwnode_mdio.c b/drivers/net/mdio/fwnode_mdio.c index 1c1584fca632..c377cadc14c3 100644 --- a/drivers/net/mdio/fwnode_mdio.c +++ b/drivers/net/mdio/fwnode_mdio.c @@ -10,6 +10,7 @@ #include <linux/fwnode_mdio.h> #include <linux/of.h> #include <linux/phy.h> +#include <linux/regulator/consumer.h> MODULE_AUTHOR("Calvin Johnson <calvin.johnson@xxxxxxxxxxx>"); MODULE_LICENSE("GPL"); @@ -95,6 +96,8 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus, bool is_c45 = false; u32 phy_id; int rc; + struct regulator *regulator_phy; + struct regulator *regulator_phy_io; mii_ts = fwnode_find_mii_timestamper(child); if (IS_ERR(mii_ts)) @@ -104,6 +107,32 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus, "ethernet-phy-ieee802.3-c45"); if (rc >= 0) is_c45 = true; + regulator_phy_io = devm_regulator_get_optional(&bus->dev, "phy-io"); + if (IS_ERR(regulator_phy_io)) { + rc = PTR_ERR(regulator_phy_io); + if (rc == -ENODEV) + regulator_phy_io = NULL; + else + return rc; + } + regulator_phy = devm_regulator_get_optional(&bus->dev, "phy"); + if (IS_ERR(regulator_phy)) { + rc = PTR_ERR(regulator_phy); + if (rc == -ENODEV) + regulator_phy = NULL; + else + return rc; + } + if (regulator_phy_io) { + rc = regulator_enable(regulator_phy_io); + if (rc) + return rc; + } + if (regulator_phy) { + rc = regulator_enable(regulator_phy); + if (rc) + return rc; + } if (is_c45 || fwnode_get_phy_id(child, &phy_id)) phy = get_phy_device(bus, addr, is_c45); @@ -114,6 +143,9 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus, return PTR_ERR(phy); } + phy->regulator_phy = regulator_phy; + phy->regulator_phy_io = regulator_phy_io; + if (is_acpi_node(child)) { phy->irq = bus->irq[addr]; diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 431a8719c635..ce64df596580 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -27,6 +27,7 @@ #include <linux/phy.h> #include <linux/phy_led_triggers.h> #include <linux/property.h> +#include <linux/regulator/consumer.h> #include <linux/sfp.h> #include <linux/skbuff.h> #include <linux/slab.h> @@ -1785,6 +1786,11 @@ int phy_suspend(struct phy_device *phydev) if (!ret) phydev->suspended = true; + if (phydev->regulator_phy) + regulator_disable(phydev->regulator_phy); + if (phydev->regulator_phy_io) + regulator_disable(phydev->regulator_phy_io); + return ret; } EXPORT_SYMBOL(phy_suspend); @@ -1811,6 +1817,20 @@ int phy_resume(struct phy_device *phydev) { int ret; + if (phydev->regulator_phy_io) { + ret = regulator_enable(phydev->regulator_phy_io); + if (ret) + return ret; + } + if (phydev->regulator_phy) { + ret = regulator_enable(phydev->regulator_phy); + if (ret) { + if (phydev->regulator_phy_io) + regulator_disable(phydev->regulator_phy_io); + return ret; + } + } + mutex_lock(&phydev->lock); ret = __phy_resume(phydev); mutex_unlock(&phydev->lock); diff --git a/include/linux/phy.h b/include/linux/phy.h index 2d12054932ba..c29f45668d94 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -704,6 +704,9 @@ struct phy_device { void (*phy_link_change)(struct phy_device *phydev, bool up); void (*adjust_link)(struct net_device *dev); + struct regulator *regulator_phy; + struct regulator *regulator_phy_io; + #if IS_ENABLED(CONFIG_MACSEC) /* MACsec management functions */ const struct macsec_ops *macsec_ops; -- 2.35.1