diff --git a/drivers/clk/clk-conf.c b/drivers/clk/clk-conf.c index 49819b546134..c7405a2e68de 100644 --- a/drivers/clk/clk-conf.c +++ b/drivers/clk/clk-conf.c @@ -13,6 +13,7 @@ #include #include #include +#include "clk.h" static int __set_clk_parents(struct device_node *node, bool clk_supplier) { @@ -38,7 +39,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) } if (clkspec.np == node && !clk_supplier) return 0; - pclk = of_clk_get_from_provider(&clkspec); + pclk = of_clk_get_from_provider_with_orphans(&clkspec); if (IS_ERR(pclk)) { if (PTR_ERR(pclk) != -EPROBE_DEFER) pr_warn("clk: couldn't get parent clock %d for %pOF\n", @@ -54,7 +55,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier) rc = 0; goto err; } - clk = of_clk_get_from_provider(&clkspec); + clk = of_clk_get_from_provider_with_orphans(&clkspec); if (IS_ERR(clk)) { if (PTR_ERR(clk) != -EPROBE_DEFER) pr_warn("clk: couldn't get assigned clock %d for %pOF\n", diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index edbb389e93aa..d7a2c9c7467a 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -3332,15 +3332,11 @@ static int __clk_core_init(struct clk_core *core) return ret; } -struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, - const char *con_id) +static struct clk *clk_hw_create_clk(struct clk_hw *hw, const char *dev_id, + const char *con_id) { struct clk *clk; - /* This is to allow this function to be chained to others */ - if (IS_ERR_OR_NULL(hw)) - return ERR_CAST(hw); - clk = kzalloc(sizeof(*clk), GFP_KERNEL); if (!clk) return ERR_PTR(-ENOMEM); @@ -3357,7 +3353,19 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, return clk; } -/* keep in sync with __clk_put */ +struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, + const char *con_id, bool with_orphans) +{ + /* This is to allow this function to be chained to others */ + if (!hw || IS_ERR(hw)) + return (struct clk *) hw; + + if (hw->core->orphan && !with_orphans) + return ERR_PTR(-EPROBE_DEFER); + + return clk_hw_create_clk(hw, dev_id, con_id); +} + void __clk_free_clk(struct clk *clk) { clk_prepare_lock(); @@ -3443,7 +3451,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw) INIT_HLIST_HEAD(&core->clks); - hw->clk = __clk_create_clk(hw, NULL, NULL); + hw->clk = clk_hw_create_clk(hw, NULL, NULL); if (IS_ERR(hw->clk)) { ret = PTR_ERR(hw->clk); goto fail_parents; @@ -4107,7 +4115,8 @@ __of_clk_get_hw_from_provider(struct of_clk_provider *provider, } struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, - const char *dev_id, const char *con_id) + const char *dev_id, const char *con_id, + bool with_orphans) { struct of_clk_provider *provider; struct clk *clk = ERR_PTR(-EPROBE_DEFER); @@ -4121,7 +4130,8 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, list_for_each_entry(provider, &of_clk_providers, link) { if (provider->node == clkspec->np) { hw = __of_clk_get_hw_from_provider(provider, clkspec); - clk = __clk_create_clk(hw, dev_id, con_id); + clk = __clk_create_clk(hw, dev_id, con_id, + with_orphans); } if (!IS_ERR(clk)) { @@ -4148,7 +4158,25 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, */ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec) { - return __of_clk_get_from_provider(clkspec, NULL, __func__); + return __of_clk_get_from_provider(clkspec, NULL, __func__, false); +} + +/** + * of_clk_get_from_provider_with_orphans() - Lookup clock from a clock provider + * @clkspec: pointer to a clock specifier data structure + * + * This function looks up a struct clk from the registered list of clock + * providers, an input is a clock specifier data structure as returned + * from the of_parse_phandle_with_args() function call. + * + * The difference to of_clk_get_from_provider() is that this function will + * also successfully lookup orphan-clocks, as it in some cases may be + * necessary to access such orphan-clocks as well. + */ +struct clk * +of_clk_get_from_provider_with_orphans(struct of_phandle_args *clkspec) +{ + return __of_clk_get_from_provider(clkspec, NULL, __func__, true); } EXPORT_SYMBOL_GPL(of_clk_get_from_provider); diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 70c0ba6336c1..6aea188e3657 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -13,19 +13,23 @@ struct clk_hw; #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec, - const char *dev_id, const char *con_id); + const char *dev_id, const char *con_id, + bool with_orphans); +struct clk * +of_clk_get_from_provider_with_orphans(struct of_phandle_args *clkspec); #endif #ifdef CONFIG_COMMON_CLK struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id, - const char *con_id); + const char *con_id, bool with_orphans); void __clk_free_clk(struct clk *clk); int __clk_get(struct clk *clk); void __clk_put(struct clk *clk); #else /* All these casts to avoid ifdefs in clkdev... */ static inline struct clk * -__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id) +__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id, + bool with_orphans) { return (struct clk *)hw; } diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 9ab3db8b3988..063ffc6375b1 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -40,7 +40,7 @@ static struct clk *__of_clk_get(struct device_node *np, int index, if (rc) return ERR_PTR(rc); - clk = __of_clk_get_from_provider(&clkspec, dev_id, con_id); + clk = __of_clk_get_from_provider(&clkspec, dev_id, con_id, true); of_node_put(clkspec.np); return clk; @@ -174,7 +174,7 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id) if (!cl) goto out; - clk = __clk_create_clk(cl->clk_hw, dev_id, con_id); + clk = __clk_create_clk(cl->clk_hw, dev_id, con_id, false); if (IS_ERR(clk)) goto out;