Skip to content

Commit

Permalink
phy: handle optional regulator for PHY
Browse files Browse the repository at this point in the history
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.montjoie@gmail.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@gmail.com>
  • Loading branch information
montjoie authored and jernejsk committed Dec 17, 2023
1 parent b85ea95 commit 25b4414
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 2 deletions.
53 changes: 51 additions & 2 deletions drivers/net/mdio/fwnode_mdio.c
Expand Up @@ -11,6 +11,7 @@
#include <linux/of.h>
#include <linux/phy.h>
#include <linux/pse-pd/pse.h>
#include <linux/regulator/consumer.h>

MODULE_AUTHOR("Calvin Johnson <calvin.johnson@oss.nxp.com>");
MODULE_LICENSE("GPL");
Expand Down Expand Up @@ -58,6 +59,40 @@ fwnode_find_mii_timestamper(struct fwnode_handle *fwnode)
return register_mii_timestamper(arg.np, arg.args[0]);
}

static int
fwnode_regulator_get_bulk_enabled(struct device *dev,
struct fwnode_handle *fwnode,
struct regulator_bulk_data **consumers)
{
struct device_node *np;
int ret, reg_cnt;

np = to_of_node(fwnode);
if (!np)
return 0;

reg_cnt = of_regulator_bulk_get_all(dev, np, consumers);
if (reg_cnt < 0) {
ret = reg_cnt;
goto clean_consumers;
}

if (reg_cnt == 0)
return 0;

ret = regulator_bulk_enable(reg_cnt, *consumers);
if (ret)
goto clean_consumers;

return reg_cnt;

clean_consumers:
kfree(*consumers);
*consumers = NULL;

return ret;
}

int fwnode_mdiobus_phy_device_register(struct mii_bus *mdio,
struct phy_device *phy,
struct fwnode_handle *child, u32 addr)
Expand Down Expand Up @@ -113,12 +148,13 @@ EXPORT_SYMBOL(fwnode_mdiobus_phy_device_register);
int fwnode_mdiobus_register_phy(struct mii_bus *bus,
struct fwnode_handle *child, u32 addr)
{
struct regulator_bulk_data *consumers = NULL;
struct mii_timestamper *mii_ts = NULL;
struct pse_control *psec = NULL;
struct phy_device *phy;
int rc, reg_cnt;
bool is_c45;
u32 phy_id;
int rc;

psec = fwnode_find_pse_control(child);
if (IS_ERR(psec))
Expand All @@ -130,16 +166,25 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,
goto clean_pse;
}

reg_cnt = fwnode_regulator_get_bulk_enabled(&bus->dev, child, &consumers);
if (reg_cnt < 0) {
rc = reg_cnt;
goto clean_mii_ts;
}

is_c45 = fwnode_device_is_compatible(child, "ethernet-phy-ieee802.3-c45");
if (is_c45 || fwnode_get_phy_id(child, &phy_id))
phy = get_phy_device(bus, addr, is_c45);
else
phy = phy_device_create(bus, addr, phy_id, 0, NULL);
if (IS_ERR(phy)) {
rc = PTR_ERR(phy);
goto clean_mii_ts;
goto clean_regulators;
}

phy->regulator_cnt = reg_cnt;
phy->consumers = consumers;

if (is_acpi_node(child)) {
phy->irq = bus->irq[addr];

Expand Down Expand Up @@ -174,6 +219,10 @@ int fwnode_mdiobus_register_phy(struct mii_bus *bus,

clean_phy:
phy_device_free(phy);
clean_regulators:
if (reg_cnt > 0)
regulator_bulk_disable(reg_cnt, consumers);
kfree(consumers);
clean_mii_ts:
unregister_mii_timestamper(mii_ts);
clean_pse:
Expand Down
6 changes: 6 additions & 0 deletions drivers/net/phy/phy_device.c
Expand Up @@ -31,6 +31,7 @@
#include <linux/phy_led_triggers.h>
#include <linux/pse-pd/pse.h>
#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/rtnetlink.h>
#include <linux/sfp.h>
#include <linux/skbuff.h>
Expand Down Expand Up @@ -3400,6 +3401,11 @@ static int phy_remove(struct device *dev)

phydev->drv = NULL;

if (phydev->regulator_cnt > 0)
regulator_bulk_disable(phydev->regulator_cnt, phydev->consumers);

kfree(phydev->consumers);

return 0;
}

Expand Down
3 changes: 3 additions & 0 deletions include/linux/phy.h
Expand Up @@ -757,6 +757,9 @@ struct phy_device {
void (*phy_link_change)(struct phy_device *phydev, bool up);
void (*adjust_link)(struct net_device *dev);

int regulator_cnt;
struct regulator_bulk_data *consumers;

#if IS_ENABLED(CONFIG_MACSEC)
/* MACsec management functions */
const struct macsec_ops *macsec_ops;
Expand Down

0 comments on commit 25b4414

Please sign in to comment.