[PATCH RFC 2/3] clk: allow assigning parent lazily

Yang Xiwen via B4 Relay devnull+forbidden405.outlook.com at kernel.org
Sat Jun 21 12:54:19 CEST 2025


From: Yang Xiwen <forbidden405 at outlook.com>

Don't mandate parent to exist when registering clocks.

Cache the parent name in core clk struct, and refresh the parent in
clk_get_parent(), which is called later.

Also modify clk_enable() and clk_disable() to use clk_get_parent()
rather than getting parent from dm directly, which bypassed the
reparent logic.

Signed-off-by: Yang Xiwen <forbidden405 at outlook.com>
---
 drivers/clk/clk-uclass.c | 47 ++++++++++++++++++++++++++++++++++-------------
 drivers/clk/clk.c        | 14 ++++++++++++--
 include/clk.h            |  2 ++
 3 files changed, 48 insertions(+), 15 deletions(-)

diff --git a/drivers/clk/clk-uclass.c b/drivers/clk/clk-uclass.c
index 2167cd5ad0fe..f619b963e66d 100644
--- a/drivers/clk/clk-uclass.c
+++ b/drivers/clk/clk-uclass.c
@@ -494,14 +494,31 @@ struct clk *clk_get_parent(struct clk *clk)
 {
 	struct udevice *pdev;
 	struct clk *pclk;
+	int ret;
 
 	debug("%s(clk=%p)\n", __func__, clk);
 	if (!clk_valid(clk))
 		return NULL;
 
 	pdev = dev_get_parent(clk->dev);
-	if (!pdev)
-		return ERR_PTR(-ENODEV);
+	if (!pdev) {
+		clk = dev_get_clk_ptr(clk->dev);
+		if (!clk->parent_name)
+			return ERR_PTR(-ENODEV);
+
+		debug("%s: Trying to reparent to %s\n", __func__, clk->parent_name);
+
+		ret = uclass_get_device_by_name(UCLASS_CLK, clk->parent_name, &pdev);
+		free(clk->parent_name);
+		clk->parent_name = NULL;
+		if (ret)
+			return ERR_PTR(ret);
+
+		ret = device_reparent(clk->dev, pdev);
+		if (ret)
+			return ERR_PTR(ret);
+	}
+
 	pclk = dev_get_clk_ptr(pdev);
 	if (!pclk)
 		return ERR_PTR(-ENODEV);
@@ -652,7 +669,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 int clk_enable(struct clk *clk)
 {
 	const struct clk_ops *ops;
-	struct clk *clkp = NULL;
+	struct clk *clkp = NULL, *clk_parent;
 	int ret;
 
 	debug("%s(clk=%p name=%s)\n", __func__, clk, clk->dev->name);
@@ -668,9 +685,10 @@ int clk_enable(struct clk *clk)
 				clkp->enable_count++;
 				return 0;
 			}
-			if (clkp->dev->parent &&
-			    device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) {
-				ret = clk_enable(dev_get_clk_ptr(clkp->dev->parent));
+
+			clk_parent = clk_get_parent(clkp);
+			if (!IS_ERR_OR_NULL(clk_parent)) {
+				ret = clk_enable(clk_parent);
 				if (ret) {
 					printf("Enable %s failed\n",
 					       clkp->dev->parent->name);
@@ -743,13 +761,16 @@ int clk_disable(struct clk *clk)
 				return ret;
 		}
 
-		if (clkp && clkp->dev->parent &&
-		    device_get_uclass_id(clkp->dev->parent) == UCLASS_CLK) {
-			ret = clk_disable(dev_get_clk_ptr(clkp->dev->parent));
-			if (ret) {
-				printf("Disable %s failed\n",
-				       clkp->dev->parent->name);
-				return ret;
+		if (clkp) {
+			struct clk *clk_parent = clk_get_parent(clkp);
+
+			if (!IS_ERR_OR_NULL(clk_parent)) {
+				ret = clk_disable(clk_parent);
+				if (ret) {
+					printf("Disable %s failed\n",
+					       clkp->dev->parent->name);
+					return ret;
+				}
 			}
 		}
 	} else {
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index b8c2e8d531b9..a0c7fad700f9 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -24,12 +24,22 @@ int clk_register(struct clk *clk, const char *drv_name,
 	if (parent_name) {
 		ret = uclass_get_device_by_name(UCLASS_CLK, parent_name, &parent);
 		if (ret) {
-			log_err("%s: failed to get %s device (parent of %s)\n",
-				__func__, parent_name, name);
+			/*
+			 * The parent is not registered yet right now.
+			 * Cache the parent name and reparent it when needed.
+			 */
+			log_debug("%s: failed to get %s device (parent of %s)\n",
+				  __func__, parent_name, name);
+
+			clk->parent_name = strdup(parent_name);
+			if (!clk->parent_name)
+				return -ENOMEM;
 		} else {
 			log_debug("%s: name: %s parent: %s [0x%p]\n", __func__, name,
 				  parent->name, parent);
 		}
+	} else {
+		clk->parent_name = NULL;
 	}
 
 	drv = lists_driver_lookup_name(drv_name);
diff --git a/include/clk.h b/include/clk.h
index a6ef4e026922..5f684dcbf9d2 100644
--- a/include/clk.h
+++ b/include/clk.h
@@ -37,6 +37,7 @@ struct udevice;
 /**
  * struct clk - A handle to (allowing control of) a single clock.
  * @dev: The device which implements the clock signal.
+ * @parent_name: The name of the parent.
  * @rate: The clock rate (in HZ).
  * @flags: Flags used across common clock structure (e.g. %CLK_)
  *         Clock IP blocks specific flags (i.e. mux, div, gate, etc) are defined
@@ -62,6 +63,7 @@ struct udevice;
  */
 struct clk {
 	struct udevice *dev;
+	char *parent_name;
 	long long rate;	/* in HZ */
 	u32 flags;
 	int enable_count;

-- 
2.43.0




More information about the U-Boot mailing list