From: Mike Turquette <mturque...@linaro.org>

clk_register_desc is the primary interface for populating the clock tree
with new clock nodes. In time, this will replace the various hardware-specific
registration functions (e.g. clk_register_gate).

Signed-off-by: Mike Turquette <mturque...@linaro.org>
Signed-off-by: Tero Kristo <t-kri...@ti.com>
---
 drivers/clk/clk.c            |   71 ++++++++++++++++++++++++++++++++++++++++++
 include/linux/clk-provider.h |   22 +++++++++++++
 2 files changed, 93 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 2cf2ea6..29281f6 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1905,6 +1905,77 @@ fail_out:
 EXPORT_SYMBOL_GPL(clk_register);
 
 /**
+ * clk_register_desc - register a new clock from its description
+ * @dev: device that is registering this clock
+ * @desc: description of the clock, may be __initdata or otherwise discarded
+ *
+ * clk_register_desc is the primary interface for populating the clock tree
+ * with new clock nodes. In time it will replace the various hardware-specific
+ * registration functions (e.g. clk_register_gate). clk_register_desc returns a
+ * pointer to the newly allocated struct clk which is an opaque cookie. Drivers
+ * must not dereference it except to check with IS_ERR.
+ */
+struct clk *clk_register_desc(struct device *dev, struct clk_desc *desc)
+{
+       int ret, i;
+       struct clk *clk;
+
+       clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+
+       if (!clk)
+               return ERR_PTR(-ENOMEM);
+
+       clk->hw = desc->register_func(dev, desc);
+       clk->hw->clk = clk;
+
+       /* _clk_register */
+       clk->name = kstrdup(desc->name, GFP_KERNEL);
+       if (!clk->name) {
+               ret = -ENOMEM;
+               goto fail_name;
+       }
+
+       clk->ops = desc->ops;
+       clk->flags = desc->flags;
+       clk->num_parents = desc->num_parents;
+
+       /* allocate local copy in case parent_names is __initdata */
+       clk->parent_names = kcalloc(clk->num_parents, sizeof(char *),
+                                   GFP_KERNEL);
+
+       if (!clk->parent_names) {
+               ret = -ENOMEM;
+               goto fail_parent_names;
+       }
+
+       /* copy each string name in case parent_names is __initdata */
+       for (i = 0; i < clk->num_parents; i++) {
+               clk->parent_names[i] = kstrdup(desc->parent_names[i],
+                                              GFP_KERNEL);
+
+               if (!clk->parent_names[i]) {
+                       ret = -ENOMEM;
+                       goto fail_parent_names_copy;
+               }
+       }
+
+       ret = __clk_init(dev, clk);
+
+       if (!ret)
+               return clk;
+
+fail_parent_names_copy:
+       while (--i >= 0)
+               kfree(clk->parent_names[i]);
+       kfree(clk->parent_names);
+fail_parent_names:
+       kfree(clk->name);
+fail_name:
+       kfree(clk);
+       return ERR_PTR(ret);
+}
+
+/**
  * clk_unregister - unregister a currently registered clock
  * @clk: clock to unregister
  *
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 7e59253..08a0da0 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -161,6 +161,27 @@ struct clk_init_data {
 };
 
 /**
+ * struct clk_desc - clock init descriptor for providing init time parameters
+ * for a clock.
+ * @name: clock name
+ * @ops: clock ops
+ * @parent_names: array of string names for all possible parents
+ * @num_parents: number of possible parents
+ * @flags: framework-level hints and quirks
+ * @register_func: function for parsing the clock descriptor and providing
+ *                ready-to-register clk_hw
+ */
+struct clk_desc {
+       const char              *name;
+       const struct clk_ops    *ops;
+       const char              **parent_names;
+       u8                      num_parents;
+       unsigned long           flags;
+       struct clk_hw *(*register_func)(struct device *dev,
+                                       struct clk_desc *desc);
+};
+
+/**
  * struct clk_hw - handle for traversing from a struct clk to its corresponding
  * hardware-specific structure.  struct clk_hw should be declared within struct
  * clk_foo and then referenced by the struct clk instance that uses struct
@@ -419,6 +440,7 @@ struct clk *clk_register_composite(struct device *dev, 
const char *name,
  * error code; drivers must test for an error code after calling clk_register.
  */
 struct clk *clk_register(struct device *dev, struct clk_hw *hw);
+struct clk *clk_register_desc(struct device *dev, struct clk_desc *desc);
 struct clk *devm_clk_register(struct device *dev, struct clk_hw *hw);
 
 void clk_unregister(struct clk *clk);
-- 
1.7.9.5

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to