diff options
author | Tero Kristo <t-kristo@ti.com> | 2015-01-29 15:24:28 -0500 |
---|---|---|
committer | Michael Turquette <mturquette@linaro.org> | 2015-01-30 13:55:09 -0500 |
commit | ed405a2350646a940966f471ae705fa2d81eee65 (patch) | |
tree | e35f9ce7fa7d0bb91f90580093a2b0e488d6c4a7 /drivers/clk/ti/dpll.c | |
parent | d96f774b25386a7a71c799bbf55b69c27129e454 (diff) |
clk: ti: dpll: add support for legacy DPLL init
Legacy clock data is initialized slightly differently compared to
DT clocks, thus add support for this.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
Acked-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Michael Turquette <mturquette@linaro.org>
Diffstat (limited to 'drivers/clk/ti/dpll.c')
-rw-r--r-- | drivers/clk/ti/dpll.c | 119 |
1 files changed, 108 insertions, 11 deletions
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c index 85ac0dd501de..47ebff772b13 100644 --- a/drivers/clk/ti/dpll.c +++ b/drivers/clk/ti/dpll.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/of.h> | 21 | #include <linux/of.h> |
22 | #include <linux/of_address.h> | 22 | #include <linux/of_address.h> |
23 | #include <linux/clk/ti.h> | 23 | #include <linux/clk/ti.h> |
24 | #include "clock.h" | ||
24 | 25 | ||
25 | #undef pr_fmt | 26 | #undef pr_fmt |
26 | #define pr_fmt(fmt) "%s: " fmt, __func__ | 27 | #define pr_fmt(fmt) "%s: " fmt, __func__ |
@@ -130,7 +131,7 @@ static const struct clk_ops dpll_x2_ck_ops = { | |||
130 | }; | 131 | }; |
131 | 132 | ||
132 | /** | 133 | /** |
133 | * ti_clk_register_dpll - low level registration of a DPLL clock | 134 | * _register_dpll - low level registration of a DPLL clock |
134 | * @hw: hardware clock definition for the clock | 135 | * @hw: hardware clock definition for the clock |
135 | * @node: device node for the clock | 136 | * @node: device node for the clock |
136 | * | 137 | * |
@@ -138,8 +139,8 @@ static const struct clk_ops dpll_x2_ck_ops = { | |||
138 | * clk-bypass is missing), the clock is added to retry list and | 139 | * clk-bypass is missing), the clock is added to retry list and |
139 | * the initialization is retried on later stage. | 140 | * the initialization is retried on later stage. |
140 | */ | 141 | */ |
141 | static void __init ti_clk_register_dpll(struct clk_hw *hw, | 142 | static void __init _register_dpll(struct clk_hw *hw, |
142 | struct device_node *node) | 143 | struct device_node *node) |
143 | { | 144 | { |
144 | struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); | 145 | struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw); |
145 | struct dpll_data *dd = clk_hw->dpll_data; | 146 | struct dpll_data *dd = clk_hw->dpll_data; |
@@ -151,7 +152,7 @@ static void __init ti_clk_register_dpll(struct clk_hw *hw, | |||
151 | if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) { | 152 | if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) { |
152 | pr_debug("clk-ref or clk-bypass missing for %s, retry later\n", | 153 | pr_debug("clk-ref or clk-bypass missing for %s, retry later\n", |
153 | node->name); | 154 | node->name); |
154 | if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll)) | 155 | if (!ti_clk_retry_init(node, hw, _register_dpll)) |
155 | return; | 156 | return; |
156 | 157 | ||
157 | goto cleanup; | 158 | goto cleanup; |
@@ -175,20 +176,116 @@ cleanup: | |||
175 | kfree(clk_hw); | 176 | kfree(clk_hw); |
176 | } | 177 | } |
177 | 178 | ||
179 | void __iomem *_get_reg(u8 module, u16 offset) | ||
180 | { | ||
181 | u32 reg; | ||
182 | struct clk_omap_reg *reg_setup; | ||
183 | |||
184 | reg_setup = (struct clk_omap_reg *)® | ||
185 | |||
186 | reg_setup->index = module; | ||
187 | reg_setup->offset = offset; | ||
188 | |||
189 | return (void __iomem *)reg; | ||
190 | } | ||
191 | |||
192 | struct clk *ti_clk_register_dpll(struct ti_clk *setup) | ||
193 | { | ||
194 | struct clk_hw_omap *clk_hw; | ||
195 | struct clk_init_data init = { NULL }; | ||
196 | struct dpll_data *dd; | ||
197 | struct clk *clk; | ||
198 | struct ti_clk_dpll *dpll; | ||
199 | const struct clk_ops *ops = &omap3_dpll_ck_ops; | ||
200 | struct clk *clk_ref; | ||
201 | struct clk *clk_bypass; | ||
202 | |||
203 | dpll = setup->data; | ||
204 | |||
205 | if (dpll->num_parents < 2) | ||
206 | return ERR_PTR(-EINVAL); | ||
207 | |||
208 | clk_ref = clk_get_sys(NULL, dpll->parents[0]); | ||
209 | clk_bypass = clk_get_sys(NULL, dpll->parents[1]); | ||
210 | |||
211 | if (IS_ERR_OR_NULL(clk_ref) || IS_ERR_OR_NULL(clk_bypass)) | ||
212 | return ERR_PTR(-EAGAIN); | ||
213 | |||
214 | dd = kzalloc(sizeof(*dd), GFP_KERNEL); | ||
215 | clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL); | ||
216 | if (!dd || !clk_hw) { | ||
217 | clk = ERR_PTR(-ENOMEM); | ||
218 | goto cleanup; | ||
219 | } | ||
220 | |||
221 | clk_hw->dpll_data = dd; | ||
222 | clk_hw->ops = &clkhwops_omap3_dpll; | ||
223 | clk_hw->hw.init = &init; | ||
224 | clk_hw->flags = MEMMAP_ADDRESSING; | ||
225 | |||
226 | init.name = setup->name; | ||
227 | init.ops = ops; | ||
228 | |||
229 | init.num_parents = dpll->num_parents; | ||
230 | init.parent_names = dpll->parents; | ||
231 | |||
232 | dd->control_reg = _get_reg(dpll->module, dpll->control_reg); | ||
233 | dd->idlest_reg = _get_reg(dpll->module, dpll->idlest_reg); | ||
234 | dd->mult_div1_reg = _get_reg(dpll->module, dpll->mult_div1_reg); | ||
235 | dd->autoidle_reg = _get_reg(dpll->module, dpll->autoidle_reg); | ||
236 | |||
237 | dd->modes = dpll->modes; | ||
238 | dd->div1_mask = dpll->div1_mask; | ||
239 | dd->idlest_mask = dpll->idlest_mask; | ||
240 | dd->mult_mask = dpll->mult_mask; | ||
241 | dd->autoidle_mask = dpll->autoidle_mask; | ||
242 | dd->enable_mask = dpll->enable_mask; | ||
243 | dd->sddiv_mask = dpll->sddiv_mask; | ||
244 | dd->dco_mask = dpll->dco_mask; | ||
245 | dd->max_divider = dpll->max_divider; | ||
246 | dd->min_divider = dpll->min_divider; | ||
247 | dd->max_multiplier = dpll->max_multiplier; | ||
248 | dd->auto_recal_bit = dpll->auto_recal_bit; | ||
249 | dd->recal_en_bit = dpll->recal_en_bit; | ||
250 | dd->recal_st_bit = dpll->recal_st_bit; | ||
251 | |||
252 | dd->clk_ref = clk_ref; | ||
253 | dd->clk_bypass = clk_bypass; | ||
254 | |||
255 | if (dpll->flags & CLKF_CORE) | ||
256 | ops = &omap3_dpll_core_ck_ops; | ||
257 | |||
258 | if (dpll->flags & CLKF_PER) | ||
259 | ops = &omap3_dpll_per_ck_ops; | ||
260 | |||
261 | if (dpll->flags & CLKF_J_TYPE) | ||
262 | dd->flags |= DPLL_J_TYPE; | ||
263 | |||
264 | clk = clk_register(NULL, &clk_hw->hw); | ||
265 | |||
266 | if (!IS_ERR(clk)) | ||
267 | return clk; | ||
268 | |||
269 | cleanup: | ||
270 | kfree(dd); | ||
271 | kfree(clk_hw); | ||
272 | return clk; | ||
273 | } | ||
274 | |||
178 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ | 275 | #if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \ |
179 | defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \ | 276 | defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \ |
180 | defined(CONFIG_SOC_AM43XX) | 277 | defined(CONFIG_SOC_AM43XX) |
181 | /** | 278 | /** |
182 | * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock | 279 | * _register_dpll_x2 - Registers a DPLLx2 clock |
183 | * @node: device node for this clock | 280 | * @node: device node for this clock |
184 | * @ops: clk_ops for this clock | 281 | * @ops: clk_ops for this clock |
185 | * @hw_ops: clk_hw_ops for this clock | 282 | * @hw_ops: clk_hw_ops for this clock |
186 | * | 283 | * |
187 | * Initializes a DPLL x 2 clock from device tree data. | 284 | * Initializes a DPLL x 2 clock from device tree data. |
188 | */ | 285 | */ |
189 | static void ti_clk_register_dpll_x2(struct device_node *node, | 286 | static void _register_dpll_x2(struct device_node *node, |
190 | const struct clk_ops *ops, | 287 | const struct clk_ops *ops, |
191 | const struct clk_hw_omap_ops *hw_ops) | 288 | const struct clk_hw_omap_ops *hw_ops) |
192 | { | 289 | { |
193 | struct clk *clk; | 290 | struct clk *clk; |
194 | struct clk_init_data init = { NULL }; | 291 | struct clk_init_data init = { NULL }; |
@@ -318,7 +415,7 @@ static void __init of_ti_dpll_setup(struct device_node *node, | |||
318 | if (dpll_mode) | 415 | if (dpll_mode) |
319 | dd->modes = dpll_mode; | 416 | dd->modes = dpll_mode; |
320 | 417 | ||
321 | ti_clk_register_dpll(&clk_hw->hw, node); | 418 | _register_dpll(&clk_hw->hw, node); |
322 | return; | 419 | return; |
323 | 420 | ||
324 | cleanup: | 421 | cleanup: |
@@ -332,7 +429,7 @@ cleanup: | |||
332 | defined(CONFIG_SOC_DRA7XX) | 429 | defined(CONFIG_SOC_DRA7XX) |
333 | static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node) | 430 | static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node) |
334 | { | 431 | { |
335 | ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx); | 432 | _register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx); |
336 | } | 433 | } |
337 | CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", | 434 | CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", |
338 | of_ti_omap4_dpll_x2_setup); | 435 | of_ti_omap4_dpll_x2_setup); |
@@ -341,7 +438,7 @@ CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock", | |||
341 | #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) | 438 | #if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX) |
342 | static void __init of_ti_am3_dpll_x2_setup(struct device_node *node) | 439 | static void __init of_ti_am3_dpll_x2_setup(struct device_node *node) |
343 | { | 440 | { |
344 | ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL); | 441 | _register_dpll_x2(node, &dpll_x2_ck_ops, NULL); |
345 | } | 442 | } |
346 | CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock", | 443 | CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock", |
347 | of_ti_am3_dpll_x2_setup); | 444 | of_ti_am3_dpll_x2_setup); |