diff options
author | Tero Kristo <t-kristo@ti.com> | 2013-10-22 04:39:36 -0400 |
---|---|---|
committer | Mike Turquette <mturquette@linaro.org> | 2014-01-17 15:34:52 -0500 |
commit | 819b4861c18d602463cfe815041d11fd81002654 (patch) | |
tree | b9b83374a962896f3d3903dc16345a9dfa53ecca /drivers/clk/ti | |
parent | a8aceccb4d5db0acb476b74051525fb26f57f8ae (diff) |
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/clk/ti')
-rw-r--r-- | drivers/clk/ti/clk.c | 112 |
1 files changed, 112 insertions, 0 deletions
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 @@ | |||
19 | #include <linux/clkdev.h> | 19 | #include <linux/clkdev.h> |
20 | #include <linux/clk/ti.h> | 20 | #include <linux/clk/ti.h> |
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_address.h> | ||
23 | #include <linux/list.h> | ||
22 | 24 | ||
23 | #undef pr_fmt | 25 | #undef pr_fmt |
24 | #define pr_fmt(fmt) "%s: " fmt, __func__ | 26 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
25 | 27 | ||
28 | static int ti_dt_clk_memmap_index; | ||
29 | struct ti_clk_ll_ops *ti_clk_ll_ops; | ||
30 | |||
26 | /** | 31 | /** |
27 | * ti_dt_clocks_register - register DT alias clocks during boot | 32 | * ti_dt_clocks_register - register DT alias clocks during boot |
28 | * @oclks: list of clocks to register | 33 | * @oclks: list of clocks to register |
@@ -53,3 +58,110 @@ void __init ti_dt_clocks_register(struct ti_dt_clk oclks[]) | |||
53 | } | 58 | } |
54 | } | 59 | } |
55 | } | 60 | } |
61 | |||
62 | struct clk_init_item { | ||
63 | struct device_node *node; | ||
64 | struct clk_hw *hw; | ||
65 | ti_of_clk_init_cb_t func; | ||
66 | struct list_head link; | ||
67 | }; | ||
68 | |||
69 | static LIST_HEAD(retry_list); | ||
70 | |||
71 | /** | ||
72 | * ti_clk_retry_init - retries a failed clock init at later phase | ||
73 | * @node: device not for the clock | ||
74 | * @hw: partially initialized clk_hw struct for the clock | ||
75 | * @func: init function to be called for the clock | ||
76 | * | ||
77 | * Adds a failed clock init to the retry list. The retry list is parsed | ||
78 | * once all the other clocks have been initialized. | ||
79 | */ | ||
80 | int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw, | ||
81 | ti_of_clk_init_cb_t func) | ||
82 | { | ||
83 | struct clk_init_item *retry; | ||
84 | |||
85 | pr_debug("%s: adding to retry list...\n", node->name); | ||
86 | retry = kzalloc(sizeof(*retry), GFP_KERNEL); | ||
87 | if (!retry) | ||
88 | return -ENOMEM; | ||
89 | |||
90 | retry->node = node; | ||
91 | retry->func = func; | ||
92 | retry->hw = hw; | ||
93 | list_add(&retry->link, &retry_list); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | /** | ||
99 | * ti_clk_get_reg_addr - get register address for a clock register | ||
100 | * @node: device node for the clock | ||
101 | * @index: register index from the clock node | ||
102 | * | ||
103 | * Builds clock register address from device tree information. This | ||
104 | * is a struct of type clk_omap_reg. | ||
105 | */ | ||
106 | void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index) | ||
107 | { | ||
108 | struct clk_omap_reg *reg; | ||
109 | u32 val; | ||
110 | u32 tmp; | ||
111 | |||
112 | reg = (struct clk_omap_reg *)&tmp; | ||
113 | reg->index = ti_dt_clk_memmap_index; | ||
114 | |||
115 | if (of_property_read_u32_index(node, "reg", index, &val)) { | ||
116 | pr_err("%s must have reg[%d]!\n", node->name, index); | ||
117 | return NULL; | ||
118 | } | ||
119 | |||
120 | reg->offset = val; | ||
121 | |||
122 | return (void __iomem *)tmp; | ||
123 | } | ||
124 | |||
125 | /** | ||
126 | * ti_dt_clk_init_provider - init master clock provider | ||
127 | * @parent: master node | ||
128 | * @index: internal index for clk_reg_ops | ||
129 | * | ||
130 | * Initializes a master clock IP block and its child clock nodes. | ||
131 | * Regmap is provided for accessing the register space for the | ||
132 | * IP block and all the clocks under it. | ||
133 | */ | ||
134 | void ti_dt_clk_init_provider(struct device_node *parent, int index) | ||
135 | { | ||
136 | const struct of_device_id *match; | ||
137 | struct device_node *np; | ||
138 | struct device_node *clocks; | ||
139 | of_clk_init_cb_t clk_init_cb; | ||
140 | struct clk_init_item *retry; | ||
141 | struct clk_init_item *tmp; | ||
142 | |||
143 | ti_dt_clk_memmap_index = index; | ||
144 | |||
145 | /* get clocks for this parent */ | ||
146 | clocks = of_get_child_by_name(parent, "clocks"); | ||
147 | if (!clocks) { | ||
148 | pr_err("%s missing 'clocks' child node.\n", parent->name); | ||
149 | return; | ||
150 | } | ||
151 | |||
152 | for_each_child_of_node(clocks, np) { | ||
153 | match = of_match_node(&__clk_of_table, np); | ||
154 | if (!match) | ||
155 | continue; | ||
156 | clk_init_cb = (of_clk_init_cb_t)match->data; | ||
157 | pr_debug("%s: initializing: %s\n", __func__, np->name); | ||
158 | clk_init_cb(np); | ||
159 | } | ||
160 | |||
161 | list_for_each_entry_safe(retry, tmp, &retry_list, link) { | ||
162 | pr_debug("retry-init: %s\n", retry->node->name); | ||
163 | retry->func(retry->hw, retry->node); | ||
164 | list_del(&retry->link); | ||
165 | kfree(retry); | ||
166 | } | ||
167 | } | ||