clk: defer clk_gets on orphan clocks
[firefly-linux-kernel-4.4.55.git] / drivers / clk / clk.c
index ba7d8e3e3db58035b2a199b189a94a6277fbf6df..f66b24e9e18e5c00b4854b4bfd861029d075cda4 100644 (file)
@@ -2515,15 +2515,11 @@ out:
        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 (!hw || IS_ERR(hw))
-               return (struct clk *) hw;
-
        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;
 }
 
+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();
@@ -2608,7 +2617,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_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,
-                                      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);
@@ -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,
-                                              con_id);
+                                              con_id, with_orphans);
 
                        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)
 {
-       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)