diff options
Diffstat (limited to 'drivers/phy/phy-uclass.c')
-rw-r--r-- | drivers/phy/phy-uclass.c | 121 |
1 files changed, 74 insertions, 47 deletions
diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index 83e4b63..629ef3a 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -12,6 +12,7 @@ #include <dm/devres.h> #include <generic-phy.h> #include <linux/list.h> +#include <power/regulator.h> /** * struct phy_counts - Init and power-on counts of a single PHY port @@ -29,12 +30,14 @@ * without a matching generic_phy_exit() afterwards * @list: Handle for a linked list of these structures corresponding to * ports of the same PHY provider + * @supply: Handle to a phy-supply device */ struct phy_counts { unsigned long id; int power_on_count; int init_count; struct list_head list; + struct udevice *supply; }; static inline struct phy_ops *phy_dev_ops(struct udevice *dev) @@ -58,7 +61,7 @@ static struct phy_counts *phy_get_counts(struct phy *phy) return NULL; } -static int phy_alloc_counts(struct phy *phy) +static int phy_alloc_counts(struct phy *phy, struct udevice *supply) { struct list_head *uc_priv; struct phy_counts *counts; @@ -76,6 +79,7 @@ static int phy_alloc_counts(struct phy *phy) counts->id = phy->id; counts->power_on_count = 0; counts->init_count = 0; + counts->supply = supply; list_add(&counts->list, uc_priv); return 0; @@ -123,7 +127,7 @@ int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy) { struct ofnode_phandle_args args; struct phy_ops *ops; - struct udevice *phydev; + struct udevice *phydev, *supply = NULL; int i, ret; debug("%s(node=%s, index=%d, phy=%p)\n", @@ -172,7 +176,17 @@ int generic_phy_get_by_index_nodev(ofnode node, int index, struct phy *phy) goto err; } - ret = phy_alloc_counts(phy); + if (CONFIG_IS_ENABLED(DM_REGULATOR)) { + ret = device_get_supply_regulator(phydev, "phy-supply", + &supply); + if (ret && ret != -ENOENT) { + debug("%s: device_get_supply_regulator failed: %d\n", + __func__, ret); + goto err; + } + } + + ret = phy_alloc_counts(phy, supply); if (ret) { debug("phy_alloc_counts() failed: %d\n", ret); goto err; @@ -214,24 +228,24 @@ int generic_phy_init(struct phy *phy) if (!generic_phy_valid(phy)) return 0; - ops = phy_dev_ops(phy->dev); - if (!ops->init) - return 0; - counts = phy_get_counts(phy); if (counts->init_count > 0) { counts->init_count++; return 0; } - ret = ops->init(phy); - if (ret) - dev_err(phy->dev, "PHY: Failed to init %s: %d.\n", - phy->dev->name, ret); - else - counts->init_count = 1; + ops = phy_dev_ops(phy->dev); + if (ops->init) { + ret = ops->init(phy); + if (ret) { + dev_err(phy->dev, "PHY: Failed to init %s: %d.\n", + phy->dev->name, ret); + return ret; + } + } + counts->init_count = 1; - return ret; + return 0; } int generic_phy_reset(struct phy *phy) @@ -260,10 +274,6 @@ int generic_phy_exit(struct phy *phy) if (!generic_phy_valid(phy)) return 0; - ops = phy_dev_ops(phy->dev); - if (!ops->exit) - return 0; - counts = phy_get_counts(phy); if (counts->init_count == 0) return 0; @@ -272,14 +282,18 @@ int generic_phy_exit(struct phy *phy) return 0; } - ret = ops->exit(phy); - if (ret) - dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n", - phy->dev->name, ret); - else - counts->init_count = 0; + ops = phy_dev_ops(phy->dev); + if (ops->exit) { + ret = ops->exit(phy); + if (ret) { + dev_err(phy->dev, "PHY: Failed to exit %s: %d.\n", + phy->dev->name, ret); + return ret; + } + } + counts->init_count = 0; - return ret; + return 0; } int generic_phy_power_on(struct phy *phy) @@ -290,24 +304,32 @@ int generic_phy_power_on(struct phy *phy) if (!generic_phy_valid(phy)) return 0; - ops = phy_dev_ops(phy->dev); - if (!ops->power_on) - return 0; - counts = phy_get_counts(phy); if (counts->power_on_count > 0) { counts->power_on_count++; return 0; } - ret = ops->power_on(phy); - if (ret) - dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n", - phy->dev->name, ret); - else - counts->power_on_count = 1; + ret = regulator_set_enable_if_allowed(counts->supply, true); + if (ret && ret != -ENOSYS) { + dev_err(phy->dev, "PHY: Failed to enable regulator %s: %d.\n", + counts->supply->name, ret); + return ret; + } - return ret; + ops = phy_dev_ops(phy->dev); + if (ops->power_on) { + ret = ops->power_on(phy); + if (ret) { + dev_err(phy->dev, "PHY: Failed to power on %s: %d.\n", + phy->dev->name, ret); + regulator_set_enable_if_allowed(counts->supply, false); + return ret; + } + } + counts->power_on_count = 1; + + return 0; } int generic_phy_power_off(struct phy *phy) @@ -318,10 +340,6 @@ int generic_phy_power_off(struct phy *phy) if (!generic_phy_valid(phy)) return 0; - ops = phy_dev_ops(phy->dev); - if (!ops->power_off) - return 0; - counts = phy_get_counts(phy); if (counts->power_on_count == 0) return 0; @@ -330,14 +348,23 @@ int generic_phy_power_off(struct phy *phy) return 0; } - ret = ops->power_off(phy); - if (ret) - dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n", - phy->dev->name, ret); - else - counts->power_on_count = 0; + ops = phy_dev_ops(phy->dev); + if (ops->power_off) { + ret = ops->power_off(phy); + if (ret) { + dev_err(phy->dev, "PHY: Failed to power off %s: %d.\n", + phy->dev->name, ret); + return ret; + } + } + counts->power_on_count = 0; - return ret; + ret = regulator_set_enable_if_allowed(counts->supply, false); + if (ret && ret != -ENOSYS) + dev_err(phy->dev, "PHY: Failed to disable regulator %s: %d.\n", + counts->supply->name, ret); + + return 0; } int generic_phy_configure(struct phy *phy, void *params) |