* [PATCH v4 1/5] phy: core: Add common helper to add phy phandle device link
2026-09-29 8:52 [PATCH v4 0/5] phy: core: Add phy bulk helpers support Inochi Amaoto
@ 2026-09-29 8:52 ` Inochi Amaoto
2026-09-29 8:52 ` [PATCH v4 2/5] phy: core: Add common helper for get phy phandle by index Inochi Amaoto
` (3 subsequent siblings)
4 siblings, 0 replies; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-29 8:52 UTC (permalink / raw)
To: Andy Shevchenko, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty,
Inochi Amaoto
Cc: linux-doc, linux-kernel, linux-phy, Yixun Lan, Longbin Li
It is very common for adding a device link for phy phandle
for device managed phy helper functions. So add a common
helper for future reuse.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/phy/phy-core.c | 39 ++++++++++++++++++++++++---------------
1 file changed, 24 insertions(+), 15 deletions(-)
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 21aaf2f76e53..7be649f14797 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -606,6 +606,27 @@ int phy_validate(struct phy *phy, enum phy_mode mode, int submode,
}
EXPORT_SYMBOL_GPL(phy_validate);
+/**
+ * phy_add_device_link() - Associate the phy with the device
+ * @dev: the device consuming the PHY
+ * @phy: the PHY supplied to @dev
+ *
+ * Add a device link with @dev as the consumer and @phy as the
+ * PHY supplier.
+ */
+static void phy_add_device_link(struct device *dev, struct phy *phy)
+{
+ struct device_link *link;
+
+ if (!phy)
+ return;
+
+ link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
+ if (!link)
+ dev_dbg(dev, "failed to create device link to %s\n",
+ dev_name(phy->dev.parent));
+}
+
/**
* _of_phy_get() - lookup and obtain a reference to a phy by phandle
* @np: device_node for which to get the phy
@@ -784,7 +805,6 @@ struct phy *phy_get(struct device *dev, const char *string)
{
int index = 0;
struct phy *phy;
- struct device_link *link;
if (dev->of_node) {
if (string)
@@ -808,10 +828,7 @@ struct phy *phy_get(struct device *dev, const char *string)
get_device(&phy->dev);
- link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
- if (!link)
- dev_dbg(dev, "failed to create device link to %s\n",
- dev_name(phy->dev.parent));
+ phy_add_device_link(dev, phy);
return phy;
}
@@ -885,7 +902,6 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
const char *con_id)
{
struct phy **ptr, *phy;
- struct device_link *link;
ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
@@ -900,10 +916,7 @@ struct phy *devm_of_phy_get(struct device *dev, struct device_node *np,
return phy;
}
- link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
- if (!link)
- dev_dbg(dev, "failed to create device link to %s\n",
- dev_name(phy->dev.parent));
+ phy_add_device_link(dev, phy);
return phy;
}
@@ -955,7 +968,6 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
int index)
{
struct phy **ptr, *phy;
- struct device_link *link;
ptr = devres_alloc(devm_phy_release, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
@@ -977,10 +989,7 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
*ptr = phy;
devres_add(dev, ptr);
- link = device_link_add(dev, &phy->dev, DL_FLAG_STATELESS);
- if (!link)
- dev_dbg(dev, "failed to create device link to %s\n",
- dev_name(phy->dev.parent));
+ phy_add_device_link(dev, phy);
return phy;
}
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v4 2/5] phy: core: Add common helper for get phy phandle by index
2026-09-29 8:52 [PATCH v4 0/5] phy: core: Add phy bulk helpers support Inochi Amaoto
2026-09-29 8:52 ` [PATCH v4 1/5] phy: core: Add common helper to add phy phandle device link Inochi Amaoto
@ 2026-09-29 8:52 ` Inochi Amaoto
2026-09-29 8:52 ` [PATCH v4 3/5] phy: core: Add phy bulk data helper functions Inochi Amaoto
` (2 subsequent siblings)
4 siblings, 0 replies; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-29 8:52 UTC (permalink / raw)
To: Andy Shevchenko, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty,
Inochi Amaoto
Cc: linux-doc, linux-kernel, linux-phy, Yixun Lan, Longbin Li
Two phy helpers use index to get phy phandle of a device node,
add a common function for the future reuse.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
---
drivers/phy/phy-core.c | 51 +++++++++++++++++++++++++-----------------
1 file changed, 30 insertions(+), 21 deletions(-)
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 7be649f14797..8fbaea003b90 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -682,33 +682,49 @@ static struct phy *_of_phy_get(struct device_node *np, int index)
return phy;
}
+/**
+ * of_phy_get_by_index() - lookup and obtain a reference to a phy using a
+ * device_node by index.
+ * @np: device_node for which to get the phy
+ * @index: index of the phy from device's point of view
+ *
+ * Returns: the phy device, after getting a refcount to it; or
+ * -ENODEV if there is no such phy. The caller is responsible for
+ * calling of_phy_put() to release that count.
+ */
+static struct phy *of_phy_get_by_index(struct device_node *np, int index)
+{
+ struct phy *phy;
+
+ phy = _of_phy_get(np, index);
+ if (IS_ERR(phy))
+ return phy;
+
+ if (!try_module_get(phy->ops->owner))
+ return ERR_PTR(-EPROBE_DEFER);
+
+ get_device(&phy->dev);
+
+ return phy;
+}
+
/**
* of_phy_get() - lookup and obtain a reference to a phy using a device_node.
* @np: device_node for which to get the phy
* @con_id: name of the phy from device's point of view
*
- * Returns the phy driver, after getting a refcount to it; or
+ * Returns: the phy device, after getting a refcount to it; or
* -ENODEV if there is no such phy. The caller is responsible for
* calling of_phy_put() to release that count.
*/
struct phy *of_phy_get(struct device_node *np, const char *con_id)
{
- struct phy *phy = NULL;
int index = 0;
if (con_id)
index = of_property_match_string(np, "phy-names", con_id);
- phy = _of_phy_get(np, index);
- if (IS_ERR(phy))
- return phy;
-
- if (!try_module_get(phy->ops->owner))
- return ERR_PTR(-EPROBE_DEFER);
-
- get_device(&phy->dev);
-
- return phy;
+ return of_phy_get_by_index(np, index);
}
EXPORT_SYMBOL_GPL(of_phy_get);
@@ -958,7 +974,7 @@ EXPORT_SYMBOL_GPL(devm_of_phy_optional_get);
* @np: node containing the phy
* @index: index of the phy
*
- * Gets the phy using _of_phy_get(), then gets a refcount to it,
+ * Gets the phy using of_phy_get_by_index(), then gets a refcount to it,
* and associates a device with it using devres. On driver detach,
* release function is invoked on the devres data,
* then, devres data is freed.
@@ -973,19 +989,12 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
if (!ptr)
return ERR_PTR(-ENOMEM);
- phy = _of_phy_get(np, index);
+ phy = of_phy_get_by_index(np, index);
if (IS_ERR(phy)) {
devres_free(ptr);
return phy;
}
- if (!try_module_get(phy->ops->owner)) {
- devres_free(ptr);
- return ERR_PTR(-EPROBE_DEFER);
- }
-
- get_device(&phy->dev);
-
*ptr = phy;
devres_add(dev, ptr);
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread* [PATCH v4 3/5] phy: core: Add phy bulk data helper functions
2026-09-29 8:52 [PATCH v4 0/5] phy: core: Add phy bulk helpers support Inochi Amaoto
2026-09-29 8:52 ` [PATCH v4 1/5] phy: core: Add common helper to add phy phandle device link Inochi Amaoto
2026-09-29 8:52 ` [PATCH v4 2/5] phy: core: Add common helper for get phy phandle by index Inochi Amaoto
@ 2026-09-29 8:52 ` Inochi Amaoto
2026-09-30 8:22 ` Andy Shevchenko
2026-09-29 8:52 ` [PATCH v4 4/5] phy: core: Add managed " Inochi Amaoto
2026-09-29 8:52 ` [PATCH v4 5/5] doc: phy: Document some bulk " Inochi Amaoto
4 siblings, 1 reply; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-29 8:52 UTC (permalink / raw)
To: Andy Shevchenko, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty,
Inochi Amaoto
Cc: linux-doc, linux-kernel, linux-phy, Yixun Lan, Longbin Li
Add several helper functions that allow drivers to get several phy
consumers in one operation. If any of the phy cannot be acquired then
any phys that were got will be put before returning to the caller.
This can relieve the driver owners' life who needs to handle many phys,
as well as each phy error reporting.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
drivers/phy/phy-core.c | 253 ++++++++++++++++++++++++++++++++++++++++
include/linux/phy/phy.h | 55 +++++++++
2 files changed, 308 insertions(+)
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 8fbaea003b90..5b76c006575b 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -1004,6 +1004,259 @@ struct phy *devm_of_phy_get_by_index(struct device *dev, struct device_node *np,
}
EXPORT_SYMBOL_GPL(devm_of_phy_get_by_index);
+/**
+ * of_phy_get_count() - Get the number of phys of a device node
+ * @np: device_node for which to get the phy
+ *
+ * Return: the phy count if successful, %0 if no phy handle is found,
+ * negative error value if error occurs.
+ */
+static int of_phy_get_count(const struct device_node *np)
+{
+ int count;
+
+ count = of_count_phandle_with_args(np, "phys", "#phy-cells");
+
+ if (count == -ENOENT)
+ return 0;
+
+ return count;
+}
+
+/**
+ * phy_bulk_put() - release a set of PHYs
+ * @dev: device that acquired the PHYs
+ * @num_phys: number of entries in the phys array
+ * @phys: array of struct phy_bulk_data with PHYs set
+ *
+ * Releases the PHY references in reverse order and clears the PHY pointer in
+ * each entry. The caller owns the phys array and is responsible for freeing it
+ * if necessary.
+ */
+static void phy_bulk_put(struct device *dev, unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ while (num_phys--) {
+ if (!IS_ERR_OR_NULL(phys[num_phys].phy))
+ phy_put(dev, phys[num_phys].phy);
+ phys[num_phys].phy = NULL;
+ }
+}
+
+/**
+ * of_phy_bulk_put() - release a set of PHYs
+ * @num_phys: number of entries in the phys array
+ * @phys: array of struct phy_bulk_data with PHYs set
+ *
+ * Releases the PHY references in reverse order and clears the PHY pointer in
+ * each entry. The caller owns the phys array and is responsible for freeing it
+ * if necessary.
+ */
+static void of_phy_bulk_put(unsigned int num_phys, struct phy_bulk_data *phys)
+{
+ while (num_phys--) {
+ of_phy_put(phys[num_phys].phy);
+ phys[num_phys].phy = NULL;
+ }
+}
+
+static int of_phy_bulk_get_by_index(struct device_node *np,
+ unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num_phys; i++) {
+ phys[i].id = NULL;
+ phys[i].phy = NULL;
+ }
+
+ for (i = 0; i < num_phys; i++) {
+ of_property_read_string_index(np, "phy-names", i, &phys[i].id);
+
+ phys[i].phy = of_phy_get_by_index(np, i);
+
+ ret = PTR_ERR_OR_ZERO(phys[i].phy);
+ if (ret) {
+ phys[i].phy = NULL;
+ goto err;
+ }
+ }
+
+ return 0;
+
+err:
+ of_phy_bulk_put(i, phys);
+
+ return ret;
+}
+
+/**
+ * of_phy_bulk_get_all() - obtain all PHYs from a device node
+ * @np: device node containing the PHY references
+ * @phys: pointer to store the allocated array of struct phy_bulk_data
+ *
+ * Gets every PHY referenced by the phys property in index order. PHY names are
+ * read from phy-names when present.
+ *
+ * Return: the number of PHYs on success, %0 if no PHYs are found, or a
+ * negative error code otherwise
+ */
+static int of_phy_bulk_get_all(struct device_node *np,
+ struct phy_bulk_data **phys)
+{
+ struct phy_bulk_data *phy_bulk;
+ int num_phys;
+ int ret;
+
+ num_phys = of_phy_get_count(np);
+ if (num_phys <= 0)
+ return num_phys;
+
+ phy_bulk = kmalloc_objs(*phy_bulk, num_phys);
+ if (!phy_bulk)
+ return -ENOMEM;
+
+ ret = of_phy_bulk_get_by_index(np, num_phys, phy_bulk);
+ if (ret) {
+ kfree(phy_bulk);
+ return ret;
+ }
+
+ *phys = phy_bulk;
+
+ return num_phys;
+}
+
+/**
+ * phy_bulk_put_all() - release and free PHYs
+ * @dev: device that acquired the PHYs
+ * @num_phys: number of entries in the phys array
+ * @phys: array of struct phy_bulk_data to release and free
+ */
+static void phy_bulk_put_all(struct device *dev, unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ if (IS_ERR_OR_NULL(phys))
+ return;
+
+ phy_bulk_put(dev, num_phys, phys);
+ kfree(phys);
+}
+
+/**
+ * phy_bulk_init() - initialize multiple PHYs
+ * @num_phys: number of entries in the phys array
+ * @phys: array of struct phy_bulk_data to initialize
+ *
+ * Initializes the PHYs in array order. If an initialization fails, all PHYs
+ * initialized by this call are exited in reverse order.
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int phy_bulk_init(unsigned int num_phys, struct phy_bulk_data *phys)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num_phys; i++) {
+ ret = phy_init(phys[i].phy);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ while (i--)
+ phy_exit(phys[i].phy);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_bulk_init);
+
+/**
+ * phy_bulk_exit() - exit multiple PHYs
+ * @num_phys: number of entries in the phys array
+ * @phys: array of struct phy_bulk_data to exit
+ *
+ * Exits the PHYs in reverse array order. All PHYs are processed even if an
+ * error occurs.
+ *
+ * Return: %0 if successful, the first negative error code otherwise
+ */
+int phy_bulk_exit(unsigned int num_phys, struct phy_bulk_data *phys)
+{
+ int ret = 0;
+ int err;
+
+ while (num_phys--) {
+ err = phy_exit(phys[num_phys].phy);
+ if (err && !ret)
+ ret = err;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_bulk_exit);
+
+/**
+ * phy_bulk_power_on() - power on multiple PHYs
+ * @num_phys: number of entries in the phys array
+ * @phys: array of struct phy_bulk_data to power on
+ *
+ * Powers on the PHYs in array order. If a power-on operation fails, all PHYs
+ * powered on by this call are powered off in reverse order.
+ *
+ * Return: %0 if successful, a negative error code otherwise
+ */
+int phy_bulk_power_on(unsigned int num_phys, struct phy_bulk_data *phys)
+{
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < num_phys; i++) {
+ ret = phy_power_on(phys[i].phy);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+
+err:
+ while (i--)
+ phy_power_off(phys[i].phy);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_bulk_power_on);
+
+/**
+ * phy_bulk_power_off() - power off multiple PHYs
+ * @num_phys: number of entries in the phys array
+ * @phys: array of struct phy_bulk_data to power off
+ *
+ * Powers off the PHYs in reverse array order. All PHYs are processed even if
+ * an error occurs.
+ *
+ * Return: %0 if successful, the first negative error code otherwise
+ */
+int phy_bulk_power_off(unsigned int num_phys, struct phy_bulk_data *phys)
+{
+ int ret = 0;
+ int err;
+
+ while (num_phys--) {
+ err = phy_power_off(phys[num_phys].phy);
+ if (err && !ret)
+ ret = err;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(phy_bulk_power_off);
+
/**
* phy_create() - create a new phy
* @dev: device that is creating the new phy
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index ea47975e288a..77d9d74682b7 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -81,6 +81,18 @@ union phy_configure_opts {
struct phy_configure_opts_hdmi hdmi;
};
+/**
+ * struct phy_bulk_data - Data used for bulk phy operations.
+ *
+ * @id: phy consumer ID
+ */
+struct phy_bulk_data {
+ const char *id;
+
+ /* private: Internal use */
+ struct phy *phy;
+};
+
/**
* struct phy_ops - set of function pointers for performing phy operations
* @init: operation to be performed for initializing phy
@@ -309,6 +321,12 @@ void devm_of_phy_provider_unregister(struct device *dev,
struct phy_provider *phy_provider);
int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+
+int phy_bulk_init(unsigned int num_phys, struct phy_bulk_data *phys);
+int phy_bulk_exit(unsigned int num_phys, struct phy_bulk_data *phys);
+int phy_bulk_power_on(unsigned int num_phys, struct phy_bulk_data *phys);
+int phy_bulk_power_off(unsigned int num_phys, struct phy_bulk_data *phys);
+
#else
static inline int phy_pm_runtime_get(struct phy *phy)
{
@@ -493,6 +511,43 @@ static inline struct phy *devm_of_phy_get_by_index(struct device *dev,
return ERR_PTR(-ENOSYS);
}
+static inline int phy_bulk_check_disabled(unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ if (!phys)
+ return 0;
+
+ for (unsigned int i = 0; i < num_phys; i++)
+ if (phys[i].phy)
+ return -EOPNOTSUPP;
+
+ return 0;
+}
+
+static inline int phy_bulk_init(unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ return phy_bulk_check_disabled(num_phys, phys);
+}
+
+static inline int phy_bulk_exit(unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ return phy_bulk_check_disabled(num_phys, phys);
+}
+
+static inline int phy_bulk_power_on(unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ return phy_bulk_check_disabled(num_phys, phys);
+}
+
+static inline int phy_bulk_power_off(unsigned int num_phys,
+ struct phy_bulk_data *phys)
+{
+ return phy_bulk_check_disabled(num_phys, phys);
+}
+
static inline void of_phy_put(struct phy *phy)
{
}
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v4 3/5] phy: core: Add phy bulk data helper functions
2026-09-29 8:52 ` [PATCH v4 3/5] phy: core: Add phy bulk data helper functions Inochi Amaoto
@ 2026-09-30 8:22 ` Andy Shevchenko
2026-09-30 8:59 ` Inochi Amaoto
0 siblings, 1 reply; 13+ messages in thread
From: Andy Shevchenko @ 2026-09-30 8:22 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty, linux-doc,
linux-kernel, linux-phy, Yixun Lan, Longbin Li
On Tue, Sep 29, 2026 at 04:52:33PM +0800, Inochi Amaoto wrote:
> Add several helper functions that allow drivers to get several phy
> consumers in one operation. If any of the phy cannot be acquired then
> any phys that were got will be put before returning to the caller.
>
> This can relieve the driver owners' life who needs to handle many phys,
> as well as each phy error reporting.
...
> +/**
> + * of_phy_get_count() - Get the number of phys of a device node
> + * @np: device_node for which to get the phy
> + *
> + * Return: the phy count if successful, %0 if no phy handle is found,
> + * negative error value if error occurs.
> + */
> +static int of_phy_get_count(const struct device_node *np)
> +{
> + int count;
> +
> + count = of_count_phandle_with_args(np, "phys", "#phy-cells");
> +
I would drop this blank line.
> + if (count == -ENOENT)
> + return 0;
I'm not sure about usefulness of this kind of trick in the _count API.
> + return count;
> +}
...
> +static void phy_bulk_put(struct device *dev, unsigned int num_phys,
> + struct phy_bulk_data *phys)
> +{
> + while (num_phys--) {
> + if (!IS_ERR_OR_NULL(phys[num_phys].phy))
This should be part of phy_put(). In general many kernel resource release APIs
are NULL and/or error pointer aware. This is a slow path and it makes user's life
easier
> + phy_put(dev, phys[num_phys].phy);
> + phys[num_phys].phy = NULL;
> + }
> +}
...
> +static void of_phy_bulk_put(unsigned int num_phys, struct phy_bulk_data *phys)
> +{
> + while (num_phys--) {
> + of_phy_put(phys[num_phys].phy);
> + phys[num_phys].phy = NULL;
Is NULLification mandatory?
> + }
> +}
...
> +static int of_phy_bulk_get_by_index(struct device_node *np,
> + unsigned int num_phys,
> + struct phy_bulk_data *phys)
> +{
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < num_phys; i++) {
> + phys[i].id = NULL;
> + phys[i].phy = NULL;
> + }
But why? The below does the assognments.
> + for (i = 0; i < num_phys; i++) {
> + of_property_read_string_index(np, "phy-names", i, &phys[i].id);
> + phys[i].phy = of_phy_get_by_index(np, i);
> +
> + ret = PTR_ERR_OR_ZERO(phys[i].phy);
> + if (ret) {
> + phys[i].phy = NULL;
Same Q: do we need a NULLification in this case? Perhaps the respective APIs
should be error pointer aware?
> + goto err;
> + }
> + }
> +
> + return 0;
> +
> +err:
> + of_phy_bulk_put(i, phys);
> +
> + return ret;
> +}
...
> +/**
> + * phy_bulk_exit() - exit multiple PHYs
> + * @num_phys: number of entries in the phys array
> + * @phys: array of struct phy_bulk_data to exit
> + *
> + * Exits the PHYs in reverse array order. All PHYs are processed even if an
> + * error occurs.
> + *
> + * Return: %0 if successful, the first negative error code otherwise
> + */
> +int phy_bulk_exit(unsigned int num_phys, struct phy_bulk_data *phys)
> +{
> + int ret = 0;
> + int err;
> +
> + while (num_phys--) {
> + err = phy_exit(phys[num_phys].phy);
> + if (err && !ret)
> + ret = err;
> + }
> +
> + return ret;
So, we return an arbitrary error and inconsistent state of the phys[] array.
What can caller do about all this? Any type of recovery? TL;DR:
I put in doubt the function prototype and the implementation (error handling).
> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v4 3/5] phy: core: Add phy bulk data helper functions
2026-09-30 8:22 ` Andy Shevchenko
@ 2026-09-30 8:59 ` Inochi Amaoto
0 siblings, 0 replies; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-30 8:59 UTC (permalink / raw)
To: Andy Shevchenko, Inochi Amaoto
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty, linux-doc,
linux-kernel, linux-phy, Yixun Lan, Longbin Li
On Wed, Sep 30, 2026 at 11:22:32AM +0300, Andy Shevchenko wrote:
> On Tue, Sep 29, 2026 at 04:52:33PM +0800, Inochi Amaoto wrote:
> > Add several helper functions that allow drivers to get several phy
> > consumers in one operation. If any of the phy cannot be acquired then
> > any phys that were got will be put before returning to the caller.
> >
> > This can relieve the driver owners' life who needs to handle many phys,
> > as well as each phy error reporting.
>
> ...
>
> > +/**
> > + * of_phy_get_count() - Get the number of phys of a device node
> > + * @np: device_node for which to get the phy
> > + *
> > + * Return: the phy count if successful, %0 if no phy handle is found,
> > + * negative error value if error occurs.
> > + */
> > +static int of_phy_get_count(const struct device_node *np)
> > +{
> > + int count;
> > +
> > + count = of_count_phandle_with_args(np, "phys", "#phy-cells");
>
> > +
>
> I would drop this blank line.
>
> > + if (count == -ENOENT)
> > + return 0;
>
> I'm not sure about usefulness of this kind of trick in the _count API.
>
> > + return count;
> > +}
>
> ...
>
> > +static void phy_bulk_put(struct device *dev, unsigned int num_phys,
> > + struct phy_bulk_data *phys)
> > +{
> > + while (num_phys--) {
>
> > + if (!IS_ERR_OR_NULL(phys[num_phys].phy))
>
> This should be part of phy_put(). In general many kernel resource release APIs
> are NULL and/or error pointer aware. This is a slow path and it makes user's life
> easier
>
Something reasonable, As of_phy_put does have a check, but phy_put
does not and it use phy->dev directly. I think this is acceptable
QoL change.
> > + phy_put(dev, phys[num_phys].phy);
> > + phys[num_phys].phy = NULL;
> > + }
> > +}
>
> ...
>
> > +static void of_phy_bulk_put(unsigned int num_phys, struct phy_bulk_data *phys)
> > +{
> > + while (num_phys--) {
> > + of_phy_put(phys[num_phys].phy);
>
> > + phys[num_phys].phy = NULL;
>
> Is NULLification mandatory?
>
I think it may not be as the phy is managed internally.
But I think it could be keeped to avoid misuse.
> > + }
> > +}
>
> ...
>
> > +static int of_phy_bulk_get_by_index(struct device_node *np,
> > + unsigned int num_phys,
> > + struct phy_bulk_data *phys)
> > +{
> > + unsigned int i;
> > + int ret;
> > +
> > + for (i = 0; i < num_phys; i++) {
> > + phys[i].id = NULL;
> > + phys[i].phy = NULL;
> > + }
>
> But why? The below does the assognments.
>
I refered of_clk_bulk_get(). And at least I think the init for
phy field should be kept for an initial state. For id, I think
it is possible to be removed.
> > + for (i = 0; i < num_phys; i++) {
> > + of_property_read_string_index(np, "phy-names", i, &phys[i].id);
>
> > + phys[i].phy = of_phy_get_by_index(np, i);
> > +
> > + ret = PTR_ERR_OR_ZERO(phys[i].phy);
> > + if (ret) {
> > + phys[i].phy = NULL;
>
> Same Q: do we need a NULLification in this case? Perhaps the respective APIs
> should be error pointer aware?
>
I think this should be removed to keep the error info. This is the
thing I have missed. Thanks.
> > + goto err;
> > + }
> > + }
> > +
> > + return 0;
> > +
> > +err:
> > + of_phy_bulk_put(i, phys);
> > +
> > + return ret;
> > +}
>
> ...
>
> > +/**
> > + * phy_bulk_exit() - exit multiple PHYs
> > + * @num_phys: number of entries in the phys array
> > + * @phys: array of struct phy_bulk_data to exit
> > + *
> > + * Exits the PHYs in reverse array order. All PHYs are processed even if an
> > + * error occurs.
> > + *
> > + * Return: %0 if successful, the first negative error code otherwise
> > + */
> > +int phy_bulk_exit(unsigned int num_phys, struct phy_bulk_data *phys)
> > +{
> > + int ret = 0;
> > + int err;
> > +
> > + while (num_phys--) {
> > + err = phy_exit(phys[num_phys].phy);
> > + if (err && !ret)
> > + ret = err;
> > + }
> > +
> > + return ret;
>
> So, we return an arbitrary error and inconsistent state of the phys[] array.
> What can caller do about all this? Any type of recovery? TL;DR:
> I put in doubt the function prototype and the implementation (error handling).
>
This is something I have done wrongly. It should return when the first
error occurs. So the caller can continue to exit the left phys.
As the phy_exit() does not check whether the init_count is 0, I think
an additional check is needed fpr phy_exit() to avoid a negative
init_count.
> > +}
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v4 4/5] phy: core: Add managed phy bulk data helper functions
2026-09-29 8:52 [PATCH v4 0/5] phy: core: Add phy bulk helpers support Inochi Amaoto
` (2 preceding siblings ...)
2026-09-29 8:52 ` [PATCH v4 3/5] phy: core: Add phy bulk data helper functions Inochi Amaoto
@ 2026-09-29 8:52 ` Inochi Amaoto
2026-09-30 8:29 ` Andy Shevchenko
2026-09-29 8:52 ` [PATCH v4 5/5] doc: phy: Document some bulk " Inochi Amaoto
4 siblings, 1 reply; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-29 8:52 UTC (permalink / raw)
To: Andy Shevchenko, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty,
Inochi Amaoto
Cc: linux-doc, linux-kernel, linux-phy, Yixun Lan, Longbin Li
Add device managed variants of the phy bulk helper functions. So
the driver can benefit from automatically managed phy handles.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
drivers/phy/phy-core.c | 73 +++++++++++++++++++++++++++++++++++++++++
include/linux/phy/phy.h | 19 +++++++++++
2 files changed, 92 insertions(+)
diff --git a/drivers/phy/phy-core.c b/drivers/phy/phy-core.c
index 5b76c006575b..a588fba33313 100644
--- a/drivers/phy/phy-core.c
+++ b/drivers/phy/phy-core.c
@@ -1145,6 +1145,79 @@ static void phy_bulk_put_all(struct device *dev, unsigned int num_phys,
kfree(phys);
}
+struct phy_bulk_devres {
+ struct phy_bulk_data *phys;
+ unsigned int num_phys;
+};
+
+static void devm_phy_bulk_release_all(struct device *dev, void *res)
+{
+ struct phy_bulk_devres *devres = res;
+
+ phy_bulk_put_all(dev, devres->num_phys, devres->phys);
+}
+
+/**
+ * devm_phy_bulk_get_all() - managed lookup of all PHYs requested by a device
+ * @dev: device that requests the PHYs
+ * @phys: pointer to store the allocated array of struct phy_bulk_data
+ *
+ * The function calls devm_of_phy_bulk_get_all() directly, but sets the
+ * @np parameter to dev_of_node(dev).
+ *
+ * Return: the number of PHYs on success, %0 if no PHYs are found, or a
+ * negative error code otherwise
+ */
+int devm_phy_bulk_get_all(struct device *dev, struct phy_bulk_data **phys)
+{
+ return devm_of_phy_bulk_get_all(dev, dev_of_node(dev), phys);
+}
+EXPORT_SYMBOL_GPL(devm_phy_bulk_get_all);
+
+/**
+ * devm_of_phy_bulk_get_all() - managed lookup of all PHYs from a device node
+ * @dev: device that requests the PHYs
+ * @np: device node containing the PHY references
+ * @phys: pointer to store the allocated array of struct phy_bulk_data
+ *
+ * Gets all PHYs from the specified device node, associates the allocated array
+ * and PHY references with @dev, and creates a device link for each PHY. They
+ * are automatically released on driver detach.
+ *
+ * Return: the number of PHYs on success, %0 if no PHYs are found, or a
+ * negative error code otherwise
+ */
+int devm_of_phy_bulk_get_all(struct device *dev, struct device_node *np,
+ struct phy_bulk_data **phys)
+{
+ struct phy_bulk_devres *devres;
+ int ret;
+
+ *phys = NULL;
+
+ if (!np)
+ return 0;
+
+ devres = devres_alloc(devm_phy_bulk_release_all, sizeof(*devres),
+ GFP_KERNEL);
+ if (!devres)
+ return -ENOMEM;
+
+ ret = of_phy_bulk_get_all(np, &devres->phys);
+ if (ret > 0) {
+ for (int i = 0; i < ret; i++)
+ phy_add_device_link(dev, devres->phys[i].phy);
+ *phys = devres->phys;
+ devres->num_phys = ret;
+ devres_add(dev, devres);
+ } else {
+ devres_free(devres);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devm_of_phy_bulk_get_all);
+
/**
* phy_bulk_init() - initialize multiple PHYs
* @num_phys: number of entries in the phys array
diff --git a/include/linux/phy/phy.h b/include/linux/phy/phy.h
index 77d9d74682b7..e60e42eb7e0b 100644
--- a/include/linux/phy/phy.h
+++ b/include/linux/phy/phy.h
@@ -322,6 +322,9 @@ void devm_of_phy_provider_unregister(struct device *dev,
int phy_create_lookup(struct phy *phy, const char *con_id, const char *dev_id);
void phy_remove_lookup(struct phy *phy, const char *con_id, const char *dev_id);
+int devm_phy_bulk_get_all(struct device *dev, struct phy_bulk_data **phys);
+int devm_of_phy_bulk_get_all(struct device *dev, struct device_node *np,
+ struct phy_bulk_data **phys);
int phy_bulk_init(unsigned int num_phys, struct phy_bulk_data *phys);
int phy_bulk_exit(unsigned int num_phys, struct phy_bulk_data *phys);
int phy_bulk_power_on(unsigned int num_phys, struct phy_bulk_data *phys);
@@ -511,6 +514,22 @@ static inline struct phy *devm_of_phy_get_by_index(struct device *dev,
return ERR_PTR(-ENOSYS);
}
+static inline int devm_of_phy_bulk_get_all(struct device *dev,
+ struct device_node *np,
+ struct phy_bulk_data **phys)
+{
+ if (phys)
+ *phys = NULL;
+
+ return 0;
+}
+
+static inline int devm_phy_bulk_get_all(struct device *dev,
+ struct phy_bulk_data **phys)
+{
+ return devm_of_phy_bulk_get_all(dev, dev_of_node(dev), phys);
+}
+
static inline int phy_bulk_check_disabled(unsigned int num_phys,
struct phy_bulk_data *phys)
{
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v4 4/5] phy: core: Add managed phy bulk data helper functions
2026-09-29 8:52 ` [PATCH v4 4/5] phy: core: Add managed " Inochi Amaoto
@ 2026-09-30 8:29 ` Andy Shevchenko
2026-09-30 9:21 ` Inochi Amaoto
0 siblings, 1 reply; 13+ messages in thread
From: Andy Shevchenko @ 2026-09-30 8:29 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty, linux-doc,
linux-kernel, linux-phy, Yixun Lan, Longbin Li
On Tue, Sep 29, 2026 at 04:52:34PM +0800, Inochi Amaoto wrote:
> Add device managed variants of the phy bulk helper functions. So
> the driver can benefit from automatically managed phy handles.
...
> +int devm_of_phy_bulk_get_all(struct device *dev, struct device_node *np,
> + struct phy_bulk_data **phys)
> +{
> + struct phy_bulk_devres *devres;
> + int ret;
> + *phys = NULL;
Why?! In case of error we modify the output, this is usually not the best
approach as in most of the cases the expectation is that whatever user
provide (including a garbage) should be left untouched in case of an error.
> + if (!np)
> + return 0;
Same here. On top why do we even care about np like this? Interestingly that
some other APIs consider this as np == dev_of_node(dev) case, and automatically
propagate that.
> + devres = devres_alloc(devm_phy_bulk_release_all, sizeof(*devres),
> + GFP_KERNEL);
> + if (!devres)
> + return -ENOMEM;
> +
> + ret = of_phy_bulk_get_all(np, &devres->phys);
> + if (ret > 0) {
> + for (int i = 0; i < ret; i++)
> + phy_add_device_link(dev, devres->phys[i].phy);
> + *phys = devres->phys;
> + devres->num_phys = ret;
> + devres_add(dev, devres);
> + } else {
> + devres_free(devres);
> + }
> +
> + return ret;
> +}
...
> +static inline int devm_of_phy_bulk_get_all(struct device *dev,
> + struct device_node *np,
> + struct phy_bulk_data **phys)
> +{
> + if (phys)
> + *phys = NULL;
Same as per above.
> + return 0;
Why not an error? I do not see the _optional word in the function name.
> +}
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v4 4/5] phy: core: Add managed phy bulk data helper functions
2026-09-30 8:29 ` Andy Shevchenko
@ 2026-09-30 9:21 ` Inochi Amaoto
2026-09-30 9:23 ` Inochi Amaoto
2026-09-30 9:44 ` Andy Shevchenko
0 siblings, 2 replies; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-30 9:21 UTC (permalink / raw)
To: Andy Shevchenko, Inochi Amaoto
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty, linux-doc,
linux-kernel, linux-phy, Yixun Lan, Longbin Li
On Wed, Sep 30, 2026 at 11:29:01AM +0300, Andy Shevchenko wrote:
> On Tue, Sep 29, 2026 at 04:52:34PM +0800, Inochi Amaoto wrote:
> > Add device managed variants of the phy bulk helper functions. So
> > the driver can benefit from automatically managed phy handles.
>
> ...
>
> > +int devm_of_phy_bulk_get_all(struct device *dev, struct device_node *np,
> > + struct phy_bulk_data **phys)
> > +{
> > + struct phy_bulk_devres *devres;
> > + int ret;
>
> > + *phys = NULL;
>
> Why?! In case of error we modify the output, this is usually not the best
> approach as in most of the cases the expectation is that whatever user
> provide (including a garbage) should be left untouched in case of an error.
>
This is something I think this is wrong and I need to removed.
> > + if (!np)
> > + return 0;
>
> Same here. On top why do we even care about np like this? Interestingly that
> some other APIs consider this as np == dev_of_node(dev) case, and automatically
> propagate that.
>
After a deep recheck. I think you are true. We do not need to care
about that, just let the internal api decide whether it should be
an error is better. I misunderstand that it should check it at early
stage to avoid some bad use in the following logic. Now I found it
is meaningless.
> > + devres = devres_alloc(devm_phy_bulk_release_all, sizeof(*devres),
> > + GFP_KERNEL);
> > + if (!devres)
> > + return -ENOMEM;
> > +
> > + ret = of_phy_bulk_get_all(np, &devres->phys);
> > + if (ret > 0) {
> > + for (int i = 0; i < ret; i++)
> > + phy_add_device_link(dev, devres->phys[i].phy);
> > + *phys = devres->phys;
> > + devres->num_phys = ret;
> > + devres_add(dev, devres);
> > + } else {
> > + devres_free(devres);
> > + }
> > +
> > + return ret;
> > +}
>
> ...
>
> > +static inline int devm_of_phy_bulk_get_all(struct device *dev,
> > + struct device_node *np,
> > + struct phy_bulk_data **phys)
> > +{
> > + if (phys)
> > + *phys = NULL;
>
> Same as per above.
>
> > + return 0;
>
> Why not an error? I do not see the _optional word in the function name.
>
IIRC get_all it a special optional meaning: treat not existing device as
0, this follows the same meaning like clk. Vladimir has a good explaination
on this in the previous version:
https://lore.kernel.org/linux-phy/20260907124318.6q4rr2huxyehm3zs@skbuf/
> > +}
>
> --
> With Best Regards,
> Andy Shevchenko
>
>
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v4 4/5] phy: core: Add managed phy bulk data helper functions
2026-09-30 9:21 ` Inochi Amaoto
@ 2026-09-30 9:23 ` Inochi Amaoto
2026-09-30 9:44 ` Andy Shevchenko
1 sibling, 0 replies; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-30 9:23 UTC (permalink / raw)
To: Andy Shevchenko, Inochi Amaoto
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty, linux-doc,
linux-kernel, linux-phy, Yixun Lan, Longbin Li
On Wed, Sep 30, 2026 at 05:21:08PM +0800, Inochi Amaoto wrote:
> On Wed, Sep 30, 2026 at 11:29:01AM +0300, Andy Shevchenko wrote:
> > On Tue, Sep 29, 2026 at 04:52:34PM +0800, Inochi Amaoto wrote:
> > > Add device managed variants of the phy bulk helper functions. So
> > > the driver can benefit from automatically managed phy handles.
> >
> > ...
> >
> > > +int devm_of_phy_bulk_get_all(struct device *dev, struct device_node *np,
> > > + struct phy_bulk_data **phys)
> > > +{
> > > + struct phy_bulk_devres *devres;
> > > + int ret;
> >
> > > + *phys = NULL;
> >
> > Why?! In case of error we modify the output, this is usually not the best
> > approach as in most of the cases the expectation is that whatever user
> > provide (including a garbage) should be left untouched in case of an error.
> >
>
> This is something I think this is wrong and I need to removed.
>
> > > + if (!np)
> > > + return 0;
> >
> > Same here. On top why do we even care about np like this? Interestingly that
> > some other APIs consider this as np == dev_of_node(dev) case, and automatically
> > propagate that.
> >
>
> After a deep recheck. I think you are true. We do not need to care
> about that, just let the internal api decide whether it should be
> an error is better. I misunderstand that it should check it at early
> stage to avoid some bad use in the following logic. Now I found it
> is meaningless.
>
> > > + devres = devres_alloc(devm_phy_bulk_release_all, sizeof(*devres),
> > > + GFP_KERNEL);
> > > + if (!devres)
> > > + return -ENOMEM;
> > > +
> > > + ret = of_phy_bulk_get_all(np, &devres->phys);
> > > + if (ret > 0) {
> > > + for (int i = 0; i < ret; i++)
> > > + phy_add_device_link(dev, devres->phys[i].phy);
> > > + *phys = devres->phys;
> > > + devres->num_phys = ret;
> > > + devres_add(dev, devres);
> > > + } else {
> > > + devres_free(devres);
> > > + }
> > > +
> > > + return ret;
> > > +}
> >
> > ...
> >
> > > +static inline int devm_of_phy_bulk_get_all(struct device *dev,
> > > + struct device_node *np,
> > > + struct phy_bulk_data **phys)
> > > +{
> > > + if (phys)
> > > + *phys = NULL;
> >
> > Same as per above.
> >
> > > + return 0;
> >
> > Why not an error? I do not see the _optional word in the function name.
> >
>
> IIRC get_all it a special optional meaning: treat not existing device as
> 0, this follows the same meaning like clk. Vladimir has a good explaination
> on this in the previous version:
> https://lore.kernel.org/linux-phy/20260907124318.6q4rr2huxyehm3zs@skbuf/
>
s/device/property/.
> > > +}
> >
> > --
> > With Best Regards,
> > Andy Shevchenko
> >
> >
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v4 4/5] phy: core: Add managed phy bulk data helper functions
2026-09-30 9:21 ` Inochi Amaoto
2026-09-30 9:23 ` Inochi Amaoto
@ 2026-09-30 9:44 ` Andy Shevchenko
1 sibling, 0 replies; 13+ messages in thread
From: Andy Shevchenko @ 2026-09-30 9:44 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty, linux-doc,
linux-kernel, linux-phy, Yixun Lan, Longbin Li
On Wed, Sep 30, 2026 at 05:21:08PM +0800, Inochi Amaoto wrote:
> On Wed, Sep 30, 2026 at 11:29:01AM +0300, Andy Shevchenko wrote:
> > On Tue, Sep 29, 2026 at 04:52:34PM +0800, Inochi Amaoto wrote:
...
> > Why not an error? I do not see the _optional word in the function name.
>
> IIRC get_all it a special optional meaning: treat not existing device as
> 0, this follows the same meaning like clk. Vladimir has a good explaination
> on this in the previous version:
> https://lore.kernel.org/linux-phy/20260907124318.6q4rr2huxyehm3zs@skbuf/
Thank you for the pointer. Perhaps add a short comment or a sentence into
kernel-doc to summarize that reasoning?
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH v4 5/5] doc: phy: Document some bulk helper functions
2026-09-29 8:52 [PATCH v4 0/5] phy: core: Add phy bulk helpers support Inochi Amaoto
` (3 preceding siblings ...)
2026-09-29 8:52 ` [PATCH v4 4/5] phy: core: Add managed " Inochi Amaoto
@ 2026-09-29 8:52 ` Inochi Amaoto
2026-09-30 8:30 ` Andy Shevchenko
4 siblings, 1 reply; 13+ messages in thread
From: Inochi Amaoto @ 2026-09-29 8:52 UTC (permalink / raw)
To: Andy Shevchenko, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Vinod Koul, Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty,
Inochi Amaoto
Cc: linux-doc, linux-kernel, linux-phy, Yixun Lan, Longbin Li
Document all newly added bulk helper function, it can be used to manage
a set of PHYs automatically. This is useful when the driver want to
simplify the management of multiple PHYs.
Signed-off-by: Inochi Amaoto <inochiama@gmail.com>
---
Documentation/driver-api/phy/phy.rst | 29 ++++++++++++++++++++++++++++
1 file changed, 29 insertions(+)
diff --git a/Documentation/driver-api/phy/phy.rst b/Documentation/driver-api/phy/phy.rst
index 0865c2e94eec..9d238ba0296d 100644
--- a/Documentation/driver-api/phy/phy.rst
+++ b/Documentation/driver-api/phy/phy.rst
@@ -114,6 +114,10 @@ it. This framework provides the following APIs to get a reference to the PHY.
struct phy *devm_of_phy_get_by_index(struct device *dev,
struct device_node *np,
int index);
+ int devm_phy_bulk_get_all(struct device *dev,
+ struct phy_bulk_data **phys);
+ int devm_of_phy_bulk_get_all(struct device *dev, struct device_node *np,
+ struct phy_bulk_data **phys);
phy_get, devm_phy_get and devm_phy_optional_get can be used to get the PHY.
In the case of dt boot, the string arguments
@@ -129,6 +133,13 @@ Some generic drivers, such as ehci, may use multiple phys. In this case,
devm_of_phy_get or devm_of_phy_get_by_index can be used to get a phy
reference based on name or index.
+When a controller needs every PHY listed in a device node's ``phys`` property,
+devm_phy_bulk_get_all() obtains them from the controller's device node.
+devm_of_phy_bulk_get_all() does the same for an explicitly supplied device
+node. On success, these functions return the number of PHYs and store an array
+of ``struct phy_bulk_data`` in ``*phys``. The PHY references and array are
+managed by devres and are released when the device is detached.
+
It should be noted that NULL is a valid phy reference. All phy
consumer calls on the NULL phy become NOPs. That is the release calls,
the phy_init() and phy_exit() calls, and phy_power_on() and
@@ -149,6 +160,19 @@ The general order of calls should be::
phy_exit()
[[of_]phy_put()]
+For a set of PHYs acquired with devm_phy_bulk_get_all() or
+devm_of_phy_bulk_get_all(), the corresponding order is::
+
+ devm_[of_]phy_bulk_get_all()
+ phy_bulk_init()
+ phy_bulk_power_on()
+ ...
+ phy_bulk_power_off()
+ phy_bulk_exit()
+
+The bulk get-all APIs release the PHY references and the array automatically
+when the device is detached.
+
Some PHY drivers may not implement :c:func:`phy_init` or :c:func:`phy_power_on`,
but controllers should always call these functions to be compatible with other
PHYs. Some PHYs may require :c:func:`phy_set_mode <phy_set_mode_ext>`, while
@@ -221,3 +245,8 @@ DeviceTree Binding
The documentation for PHY dt binding can be found @
Documentation/devicetree/bindings/phy/phy-bindings.txt
+
+Missing Bulk Helpers
+====================
+Currently, only a few bulk helper functions are added as they have users.
+Function not upstreamed can be found at https://lore.kernel.org/linux-phy/20260904083709.425893-1-inochiama@gmail.com/
--
2.55.0
^ permalink raw reply [flat|nested] 13+ messages in thread* Re: [PATCH v4 5/5] doc: phy: Document some bulk helper functions
2026-09-29 8:52 ` [PATCH v4 5/5] doc: phy: Document some bulk " Inochi Amaoto
@ 2026-09-30 8:30 ` Andy Shevchenko
0 siblings, 0 replies; 13+ messages in thread
From: Andy Shevchenko @ 2026-09-30 8:30 UTC (permalink / raw)
To: Inochi Amaoto
Cc: Jonathan Corbet, Shuah Khan, Randy Dunlap, Vinod Koul,
Neil Armstrong, Manivannan Sadhasivam, Rhys Tumelty, linux-doc,
linux-kernel, linux-phy, Yixun Lan, Longbin Li
On Tue, Sep 29, 2026 at 04:52:35PM +0800, Inochi Amaoto wrote:
> Document all newly added bulk helper function, it can be used to manage
> a set of PHYs automatically. This is useful when the driver want to
> simplify the management of multiple PHYs.
It misses to document unusual behaviour on an error and np==NULL cases.
But before updating let's discuss first if that kind of behaviour
is even desired.
--
With Best Regards,
Andy Shevchenko
^ permalink raw reply [flat|nested] 13+ messages in thread