[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