[PATCHv12 01/49] clk: add support for registering clocks from description
Tero Kristo
t-kristo at ti.com
Fri Dec 20 11:34:20 EST 2013
From: Mike Turquette <mturquette at 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 <mturquette at linaro.org>
Signed-off-by: Tero Kristo <t-kristo at 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
More information about the linux-arm-kernel
mailing list