From patchwork Fri Apr 3 03:33:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?b?Q2h1bmZlbmcgWXVuICjkupHmmKXls7Ap?= X-Patchwork-Id: 237118 List-Id: U-Boot discussion From: chunfeng.yun at mediatek.com (Chunfeng Yun) Date: Fri, 3 Apr 2020 11:33:27 +0800 Subject: [PATCH v4 03/13] phy: Add get/enable/disable for a bulk of phys In-Reply-To: <1585884817-5333-1-git-send-email-chunfeng.yun@mediatek.com> References: <1585884817-5333-1-git-send-email-chunfeng.yun@mediatek.com> Message-ID: <1585884817-5333-4-git-send-email-chunfeng.yun@mediatek.com> This patch adds a "bulk" API to the phy API in order to get/enable/disable a group of phys associated with a device. The bulk API will avoid adding a copy of the same code to manage a group of phys in drivers. Signed-off-by: Chunfeng Yun --- v4: new patch --- drivers/phy/phy-uclass.c | 80 ++++++++++++++++++++++++++++++++++++++++ include/generic-phy.h | 66 +++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) diff --git a/drivers/phy/phy-uclass.c b/drivers/phy/phy-uclass.c index e201a90c8c..62580520ad 100644 --- a/drivers/phy/phy-uclass.c +++ b/drivers/phy/phy-uclass.c @@ -6,6 +6,7 @@ #include #include +#include #include static inline struct phy_ops *phy_dev_ops(struct udevice *dev) @@ -161,6 +162,85 @@ int generic_phy_power_off(struct phy *phy) return ops->power_off ? ops->power_off(phy) : 0; } +int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + int i, ret, count; + + bulk->count = 0; + + /* Return if no phy declared */ + if (!dev_read_prop(dev, "phys", NULL)) + return 0; + + count = dev_count_phandle_with_args(dev, "phys", "#phy-cells"); + if (count < 1) + return count; + + bulk->phys = devm_kcalloc(dev, count, sizeof(struct phy), GFP_KERNEL); + if (!bulk->phys) + return -ENOMEM; + + for (i = 0; i < count; i++) { + ret = generic_phy_get_by_index(dev, i, &bulk->phys[i]); + if (ret) { + pr_err("Failed to get PHY%d for %s\n", i, dev->name); + return ret; + } + bulk->count++; + } + + return 0; +} + +int generic_phy_enable_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int count = bulk->count; + int i, ret; + + for (i = 0; i < count; i++) { + ret = generic_phy_init(&phys[i]); + if (ret) { + pr_err("Can't init PHY%d\n", i); + goto phys_init_err; + } + } + + for (i = 0; i < count; i++) { + ret = generic_phy_power_on(&phys[i]); + if (ret) { + pr_err("Can't power PHY%d\n", i); + goto phys_poweron_err; + } + } + + return 0; + +phys_poweron_err: + for (; i > 0; i--) + generic_phy_power_off(&phys[i - 1]); + + i = count; +phys_init_err: + for (; i > 0; i--) + generic_phy_exit(&phys[i - 1]); + + return ret; +} + +int generic_phy_disable_bulk(struct phy_bulk *bulk) +{ + struct phy *phys = bulk->phys; + int i, ret = 0; + + for (i = 0; i < bulk->count; i++) { + ret |= generic_phy_power_off(&phys[i]); + ret |= generic_phy_exit(&phys[i]); + } + + return ret; +} + UCLASS_DRIVER(phy) = { .id = UCLASS_PHY, .name = "phy", diff --git a/include/generic-phy.h b/include/generic-phy.h index 95caf58341..55395a50eb 100644 --- a/include/generic-phy.h +++ b/include/generic-phy.h @@ -122,6 +122,23 @@ struct phy_ops { int (*power_off)(struct phy *phy); }; +/** + * struct phy_bulk - A handle to (allowing control of) a bulk of phys. + * + * Consumers provide storage for the phy bulk. The content of the structure is + * managed solely by the phy API. A phy bulk struct is initialized + * by "get"ing the phy bulk struct. + * The phy bulk struct is passed to all other bulk phy APIs to apply + * the API to all the phy in the bulk struct. + * + * @phys: An array of phy handles. + * @count: The number of phy handles in the phys array. + */ +struct phy_bulk { + struct phy *phys; + unsigned int count; +}; + #ifdef CONFIG_PHY /** @@ -221,6 +238,39 @@ int generic_phy_get_by_index(struct udevice *user, int index, int generic_phy_get_by_name(struct udevice *user, const char *phy_name, struct phy *phy); +/** + * generic_phy_get_bulk - Get all phys of a device. + * + * This looks up and gets all phys of the consumer device; each device is + * assumed to have n phys associated with it somehow, and this function finds + * and gets all of them in a separate structure. + * + * @dev: The consumer device. + * @bulk A pointer to a phy bulk struct to initialize. + * @return 0 if OK, or a negative error code. + */ +int generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk); + +/** + * generic_phy_enable_bulk() - Enable (init and power on) all phys in a phy + * bulk struct. + * + * @bulk: A phy bulk struct that was previously successfully requested + * by generic_phy_get_bulk(). + * @return 0 if OK, or negative error code. + */ +int generic_phy_enable_bulk(struct phy_bulk *bulk); + +/** + * generic_phy_disable_bulk() - Enable (power off and exit) all phys in a phy + * bulk struct. + * + * @bulk: A phy bulk struct that was previously successfully requested + * by generic_phy_get_bulk(). + * @return 0 if OK, or negative error code. + */ +int generic_phy_disable_bulk(struct phy_bulk *bulk); + #else /* CONFIG_PHY */ static inline int generic_phy_init(struct phy *phy) @@ -260,6 +310,22 @@ static inline int generic_phy_get_by_name(struct udevice *user, const char *phy_ return 0; } +static inline int +generic_phy_get_bulk(struct udevice *dev, struct phy_bulk *bulk) +{ + return 0; +} + +static inline int generic_phy_enable_bulk(struct phy_bulk *bulk) +{ + return 0; +} + +static inline int generic_phy_disable_bulk(struct phy_bulk *bulk) +{ + return 0; +} + #endif /* CONFIG_PHY */ /**