From: Yang Xiwen <[email protected]> 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 <[email protected]> --- 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

