Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
[linux-2.6-block.git] / drivers / clk / clk.c
index 498cae518147d83a1aee9fb64f3f292911df933d..1c677d7f7f530739ef2dd91428697d308dee3349 100644 (file)
@@ -330,6 +330,25 @@ static struct clk_core *clk_core_lookup(const char *name)
        return NULL;
 }
 
+#ifdef CONFIG_OF
+static int of_parse_clkspec(const struct device_node *np, int index,
+                           const char *name, struct of_phandle_args *out_args);
+static struct clk_hw *
+of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec);
+#else
+static inline int of_parse_clkspec(const struct device_node *np, int index,
+                                  const char *name,
+                                  struct of_phandle_args *out_args)
+{
+       return -ENOENT;
+}
+static inline struct clk_hw *
+of_clk_get_hw_from_clkspec(struct of_phandle_args *clkspec)
+{
+       return ERR_PTR(-ENOENT);
+}
+#endif
+
 /**
  * clk_core_get - Find the clk_core parent of a clk
  * @core: clk to find parent of
@@ -361,8 +380,9 @@ static struct clk_core *clk_core_lookup(const char *name)
  *      };
  *
  * Returns: -ENOENT when the provider can't be found or the clk doesn't
- * exist in the provider. -EINVAL when the name can't be found. NULL when the
- * provider knows about the clk but it isn't provided on this system.
+ * exist in the provider or the name can't be found in the DT node or
+ * in a clkdev lookup. NULL when the provider knows about the clk but it
+ * isn't provided on this system.
  * A valid clk_core pointer when the clk can be found in the provider.
  */
 static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
@@ -373,17 +393,19 @@ static struct clk_core *clk_core_get(struct clk_core *core, u8 p_index)
        struct device *dev = core->dev;
        const char *dev_id = dev ? dev_name(dev) : NULL;
        struct device_node *np = core->of_node;
+       struct of_phandle_args clkspec;
 
-       if (np && (name || index >= 0))
-               hw = of_clk_get_hw(np, index, name);
-
-       /*
-        * If the DT search above couldn't find the provider or the provider
-        * didn't know about this clk, fallback to looking up via clkdev based
-        * clk_lookups
-        */
-       if (PTR_ERR(hw) == -ENOENT && name)
+       if (np && (name || index >= 0) &&
+           !of_parse_clkspec(np, index, name, &clkspec)) {
+               hw = of_clk_get_hw_from_clkspec(&clkspec);
+               of_node_put(clkspec.np);
+       } else if (name) {
+               /*
+                * If the DT search above couldn't find the provider fallback to
+                * looking up via clkdev based clk_lookups.
+                */
                hw = clk_find_hw(dev_id, name);
+       }
 
        if (IS_ERR(hw))
                return ERR_CAST(hw);
@@ -407,7 +429,7 @@ static void clk_core_fill_parent_index(struct clk_core *core, u8 index)
                        parent = ERR_PTR(-EPROBE_DEFER);
        } else {
                parent = clk_core_get(core, index);
-               if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT)
+               if (IS_ERR(parent) && PTR_ERR(parent) == -ENOENT && entry->name)
                        parent = clk_core_lookup(entry->name);
        }
 
@@ -1640,7 +1662,8 @@ static int clk_fetch_parent_index(struct clk_core *core,
                        break;
 
                /* Fallback to comparing globally unique names */
-               if (!strcmp(parent->name, core->parents[i].name))
+               if (core->parents[i].name &&
+                   !strcmp(parent->name, core->parents[i].name))
                        break;
        }