clk: defer clk_gets on orphan clocks
authorElaine Zhang <zhangqing@rock-chips.com>
Fri, 31 Mar 2017 08:01:00 +0000 (16:01 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 11 Apr 2017 10:29:22 +0000 (18:29 +0800)
Orphan clocks or children of orphan clocks don't have rate information at
all and can produce strange results if they're allowed to be used and the
parent becomes available later on.

This change, based on one from Stephen Boyd, defers __clk_create_clk()
calls on orphan clocks in all regular cases.

One special case that gets handled, is accessing such orphan clocks when
handling assigned-clocks configurations. In the boot-defaults it may be
the case that a clock is connected to an orphan parent which then might
be needed to get reparented to an actually usable clock using
assigned-clock-parents. In this case even orphaned clocks should be
usable, but only for the set-parent case.

The added of_clk_get_from_provider_with_orphans() is only available
to ccf internal parts to prevent abuse.

(am from https://patchwork.kernel.org/patch/7690221/)

Change-Id: I2e603dab191fa8a431adebad1f9d482d52b7deeb
Signed-off-by: Heiko Stuebner <heiko.stuebner@collabora.com>
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
drivers/clk/clk-conf.c
drivers/clk/clk.c
drivers/clk/clk.h
drivers/clk/clkdev.c

index 43a218f35b190a21e62bc520cdac38f275f5da82..60ebfd9d020ff60f5d2bae39d88d69b60c75d12e 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/device.h>
 #include <linux/of.h>
 #include <linux/printk.h>
 #include <linux/device.h>
 #include <linux/of.h>
 #include <linux/printk.h>
+#include "clk.h"
 
 static int __set_clk_parents(struct device_node *node, bool clk_supplier)
 {
 
 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;
                }
                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)) {
                        pr_warn("clk: couldn't get parent clock %d for %s\n",
                                index, node->full_name);
                if (IS_ERR(pclk)) {
                        pr_warn("clk: couldn't get parent clock %d for %s\n",
                                index, node->full_name);
@@ -53,7 +54,7 @@ static int __set_clk_parents(struct device_node *node, bool clk_supplier)
                        rc = 0;
                        goto err;
                }
                        rc = 0;
                        goto err;
                }
-               clk = of_clk_get_from_provider(&clkspec);
+               clk = of_clk_get_from_provider_with_orphans(&clkspec);
                if (IS_ERR(clk)) {
                        pr_warn("clk: couldn't get parent clock %d for %s\n",
                                index, node->full_name);
                if (IS_ERR(clk)) {
                        pr_warn("clk: couldn't get parent clock %d for %s\n",
                                index, node->full_name);
index ba7d8e3e3db58035b2a199b189a94a6277fbf6df..f66b24e9e18e5c00b4854b4bfd861029d075cda4 100644 (file)
@@ -2515,15 +2515,11 @@ out:
        return ret;
 }
 
        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;
 
 {
        struct clk *clk;
 
-       /* This is to allow this function to be chained to others */
-       if (!hw || IS_ERR(hw))
-               return (struct clk *) hw;
-
        clk = kzalloc(sizeof(*clk), GFP_KERNEL);
        if (!clk)
                return ERR_PTR(-ENOMEM);
        clk = kzalloc(sizeof(*clk), GFP_KERNEL);
        if (!clk)
                return ERR_PTR(-ENOMEM);
@@ -2540,6 +2536,19 @@ struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
        return clk;
 }
 
        return clk;
 }
 
+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();
 void __clk_free_clk(struct clk *clk)
 {
        clk_prepare_lock();
@@ -2608,7 +2617,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
 
        INIT_HLIST_HEAD(&core->clks);
 
 
        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_parent_names_copy;
        if (IS_ERR(hw->clk)) {
                ret = PTR_ERR(hw->clk);
                goto fail_parent_names_copy;
@@ -3046,7 +3055,8 @@ void of_clk_del_provider(struct device_node *np)
 EXPORT_SYMBOL_GPL(of_clk_del_provider);
 
 struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
 EXPORT_SYMBOL_GPL(of_clk_del_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);
 {
        struct of_clk_provider *provider;
        struct clk *clk = ERR_PTR(-EPROBE_DEFER);
@@ -3061,7 +3071,7 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
                        clk = provider->get(clkspec, provider->data);
                if (!IS_ERR(clk)) {
                        clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
                        clk = provider->get(clkspec, provider->data);
                if (!IS_ERR(clk)) {
                        clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
-                                              con_id);
+                                              con_id, with_orphans);
 
                        if (!IS_ERR(clk) && !__clk_get(clk)) {
                                __clk_free_clk(clk);
 
                        if (!IS_ERR(clk) && !__clk_get(clk)) {
                                __clk_free_clk(clk);
@@ -3086,7 +3096,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)
 {
  */
 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);
 }
 
 int of_clk_get_parent_count(struct device_node *np)
 }
 
 int of_clk_get_parent_count(struct device_node *np)
index 00b35a13cdf389310afe65856fc23e3fee68d067..5a70f09f333b941296554385d15be121ad8f3682 100644 (file)
@@ -13,17 +13,21 @@ struct clk_hw;
 
 #if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
 struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
 
 #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,
 #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);
 #else
 /* All these casts to avoid ifdefs in clkdev... */
 static inline struct clk *
 void __clk_free_clk(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;
 }
 {
        return (struct clk *)hw;
 }
index 779b6ff0c7ad4040a680a2155964bd3016363767..a7e8bbe53868774765870496fb8f6fcd8a07d026 100644 (file)
@@ -43,7 +43,7 @@ static struct clk *__of_clk_get(struct device_node *np, int index,
        if (rc)
                return ERR_PTR(rc);
 
        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;
        of_node_put(clkspec.np);
 
        return clk;
@@ -177,7 +177,7 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id)
        if (!cl)
                goto out;
 
        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;
 
        if (IS_ERR(clk))
                goto out;