diff options
author | Tero Kristo <t-kristo@ti.com> | 2013-10-22 12:39:36 +0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-01-18 00:34:52 +0400 |
commit | 819b4861c18d602463cfe815041d11fd81002654 (patch) | |
tree | b9b83374a962896f3d3903dc16345a9dfa53ecca /drivers | |
parent | a8aceccb4d5db0acb476b74051525fb26f57f8ae (diff) | |
download | linux-819b4861c18d602463cfe815041d11fd81002654.tar.xz |
CLK: ti: add init support for clock IP blocks
ti_dt_clk_init_provider() can now be used to initialize the contents of
a single clock IP block. This parses all the clocks under the IP block
and calls the corresponding init function for them.
This patch also introduces a helper function for the TI clock drivers
to get register info from DT and append the master IP info to this.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Mike Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/clk/clk.c | 4 | ||||
-rw-r--r-- | drivers/clk/ti/clk.c | 112 |
2 files changed, 113 insertions, 3 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 2b38dc99063f..077106732550 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -2373,8 +2373,6 @@ struct of_clk_provider { void *data; }; -extern struct of_device_id __clk_of_table[]; - static const struct of_device_id __clk_of_table_sentinel __used __section(__clk_of_table_end); @@ -2534,7 +2532,7 @@ void __init of_clk_init(const struct of_device_id *matches) struct device_node *np; if (!matches) - matches = __clk_of_table; + matches = &__clk_of_table; for_each_matching_node_and_match(np, matches, &match) { of_clk_init_cb_t clk_init_cb = match->data; diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c index ef1a7cdecfd9..b1a6f7144f3f 100644 --- a/drivers/clk/ti/clk.c +++ b/drivers/clk/ti/clk.c @@ -19,10 +19,15 @@ #include <linux/clkdev.h> #include <linux/clk/ti.h> #include <linux/of.h> +#include <linux/of_address.h> +#include <linux/list.h> #undef pr_fmt #define pr_fmt(fmt) "%s: " fmt, __func__ +static int ti_dt_clk_memmap_index; +struct ti_clk_ll_ops *ti_clk_ll_ops; + /** * ti_dt_clocks_register - register DT alias clocks during boot * @oclks: list of clocks to register @@ -53,3 +58,110 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) } } } + +struct clk_init_item { + struct device_node *node; + struct clk_hw *hw; + ti_of_clk_init_cb_t func; + struct list_head link; +}; + +static LIST_HEAD(retry_list); + +/** + * ti_clk_retry_init - retries a failed clock init at later phase + * @node: device not for the clock + * @hw: partially initialized clk_hw struct for the clock + * @func: init function to be called for the clock + * + * Adds a failed clock init to the retry list. The retry list is parsed + * once all the other clocks have been initialized. + */ +int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, + ti_of_clk_init_cb_t func) +{ + struct clk_init_item *retry; + + pr_debug("%s: adding to retry list...\n", node->name); + retry = kzalloc(sizeof(*retry), GFP_KERNEL); + if (!retry) + return -ENOMEM; + + retry->node = node; + retry->func = func; + retry->hw = hw; + list_add(&retry->link, &retry_list); + + return 0; +} + +/** + * ti_clk_get_reg_addr - get register address for a clock register + * @node: device node for the clock + * @index: register index from the clock node + * + * Builds clock register address from device tree information. This + * is a struct of type clk_omap_reg. + */ +void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) +{ + struct clk_omap_reg *reg; + u32 val; + u32 tmp; + + reg = (struct clk_omap_reg *)&tmp; + reg->index = ti_dt_clk_memmap_index; + + if (of_property_read_u32_index(node, "reg", index, &val)) { + pr_err("%s must have reg[%d]!\n", node->name, index); + return NULL; + } + + reg->offset = val; + + return (void __iomem *)tmp; +} + +/** + * ti_dt_clk_init_provider - init master clock provider + * @parent: master node + * @index: internal index for clk_reg_ops + * + * Initializes a master clock IP block and its child clock nodes. + * Regmap is provided for accessing the register space for the + * IP block and all the clocks under it. + */ +void ti_dt_clk_init_provider(struct device_node *parent, int index) +{ + const struct of_device_id *match; + struct device_node *np; + struct device_node *clocks; + of_clk_init_cb_t clk_init_cb; + struct clk_init_item *retry; + struct clk_init_item *tmp; + + ti_dt_clk_memmap_index = index; + + /* get clocks for this parent */ + clocks = of_get_child_by_name(parent, "clocks"); + if (!clocks) { + pr_err("%s missing 'clocks' child node.\n", parent->name); + return; + } + + for_each_child_of_node(clocks, np) { + match = of_match_node(&__clk_of_table, np); + if (!match) + continue; + clk_init_cb = (of_clk_init_cb_t)match->data; + pr_debug("%s: initializing: %s\n", __func__, np->name); + clk_init_cb(np); + } + + list_for_each_entry_safe(retry, tmp, &retry_list, link) { + pr_debug("retry-init: %s\n", retry->node->name); + retry->func(retry->hw, retry->node); + list_del(&retry->link); + kfree(retry); + } +} |