diff options
author | Tero Kristo <t-kristo@ti.com> | 2015-03-03 08:28:53 -0500 |
---|---|---|
committer | Tero Kristo <t-kristo@ti.com> | 2015-06-02 05:31:22 -0400 |
commit | 9f37e90efaf0772b8f98bc347b9db77a3f0c27eb (patch) | |
tree | 7a3b08e65e085952b5dd45442a22635718501c19 | |
parent | 046b7c31668311942a2e431e7983d8ab9874d845 (diff) |
clk: ti: dflt: move support for default gate clock to clock driver
With the legacy support gone, OMAP2+ default gate clock can be moved
under clock driver. Create a new file for the purpose, and clean-up
the header exports a bit as some clock APIs are no longer needed
outside clock driver itself.
Signed-off-by: Tero Kristo <t-kristo@ti.com>
-rw-r--r-- | arch/arm/mach-omap2/clock.c | 273 | ||||
-rw-r--r-- | drivers/clk/ti/Makefile | 2 | ||||
-rw-r--r-- | drivers/clk/ti/clkt_dflt.c | 316 | ||||
-rw-r--r-- | drivers/clk/ti/clock.h | 5 | ||||
-rw-r--r-- | include/linux/clk/ti.h | 4 |
5 files changed, 322 insertions, 278 deletions
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c index 6c17adf40e6f..38a336b4c42b 100644 --- a/arch/arm/mach-omap2/clock.c +++ b/arch/arm/mach-omap2/clock.c | |||
@@ -40,12 +40,6 @@ | |||
40 | #include "cm-regbits-34xx.h" | 40 | #include "cm-regbits-34xx.h" |
41 | #include "common.h" | 41 | #include "common.h" |
42 | 42 | ||
43 | /* | ||
44 | * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait | ||
45 | * for a module to indicate that it is no longer in idle | ||
46 | */ | ||
47 | #define MAX_MODULE_ENABLE_WAIT 100000 | ||
48 | |||
49 | u16 cpu_mask; | 43 | u16 cpu_mask; |
50 | 44 | ||
51 | /* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ | 45 | /* DPLL valid Fint frequency band limits - from 34xx TRM Section 4.7.6.2 */ |
@@ -176,77 +170,6 @@ void __init omap2_clk_legacy_provider_init(int index, void __iomem *mem) | |||
176 | 170 | ||
177 | /* Private functions */ | 171 | /* Private functions */ |
178 | 172 | ||
179 | |||
180 | /** | ||
181 | * _wait_idlest_generic - wait for a module to leave the idle state | ||
182 | * @clk: module clock to wait for (needed for register offsets) | ||
183 | * @reg: virtual address of module IDLEST register | ||
184 | * @mask: value to mask against to determine if the module is active | ||
185 | * @idlest: idle state indicator (0 or 1) for the clock | ||
186 | * @name: name of the clock (for printk) | ||
187 | * | ||
188 | * Wait for a module to leave idle, where its idle-status register is | ||
189 | * not inside the CM module. Returns 1 if the module left idle | ||
190 | * promptly, or 0 if the module did not leave idle before the timeout | ||
191 | * elapsed. XXX Deprecated - should be moved into drivers for the | ||
192 | * individual IP block that the IDLEST register exists in. | ||
193 | */ | ||
194 | static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, | ||
195 | u32 mask, u8 idlest, const char *name) | ||
196 | { | ||
197 | int i = 0, ena = 0; | ||
198 | |||
199 | ena = (idlest) ? 0 : mask; | ||
200 | |||
201 | omap_test_timeout(((omap2_clk_readl(clk, reg) & mask) == ena), | ||
202 | MAX_MODULE_ENABLE_WAIT, i); | ||
203 | |||
204 | if (i < MAX_MODULE_ENABLE_WAIT) | ||
205 | pr_debug("omap clock: module associated with clock %s ready after %d loops\n", | ||
206 | name, i); | ||
207 | else | ||
208 | pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n", | ||
209 | name, MAX_MODULE_ENABLE_WAIT); | ||
210 | |||
211 | return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; | ||
212 | }; | ||
213 | |||
214 | /** | ||
215 | * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE | ||
216 | * @clk: struct clk * belonging to the module | ||
217 | * | ||
218 | * If the necessary clocks for the OMAP hardware IP block that | ||
219 | * corresponds to clock @clk are enabled, then wait for the module to | ||
220 | * indicate readiness (i.e., to leave IDLE). This code does not | ||
221 | * belong in the clock code and will be moved in the medium term to | ||
222 | * module-dependent code. No return value. | ||
223 | */ | ||
224 | static void _omap2_module_wait_ready(struct clk_hw_omap *clk) | ||
225 | { | ||
226 | void __iomem *companion_reg, *idlest_reg; | ||
227 | u8 other_bit, idlest_bit, idlest_val, idlest_reg_id; | ||
228 | s16 prcm_mod; | ||
229 | int r; | ||
230 | |||
231 | /* Not all modules have multiple clocks that their IDLEST depends on */ | ||
232 | if (clk->ops->find_companion) { | ||
233 | clk->ops->find_companion(clk, &companion_reg, &other_bit); | ||
234 | if (!(omap2_clk_readl(clk, companion_reg) & (1 << other_bit))) | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); | ||
239 | r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id); | ||
240 | if (r) { | ||
241 | /* IDLEST register not in the CM module */ | ||
242 | _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), | ||
243 | idlest_val, __clk_get_name(clk->hw.clk)); | ||
244 | } else { | ||
245 | omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id, | ||
246 | idlest_bit); | ||
247 | }; | ||
248 | } | ||
249 | |||
250 | /* Public functions */ | 173 | /* Public functions */ |
251 | 174 | ||
252 | /** | 175 | /** |
@@ -280,174 +203,6 @@ void omap2_init_clk_clkdm(struct clk_hw *hw) | |||
280 | } | 203 | } |
281 | 204 | ||
282 | /** | 205 | /** |
283 | * omap2_clk_dflt_find_companion - find companion clock to @clk | ||
284 | * @clk: struct clk * to find the companion clock of | ||
285 | * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in | ||
286 | * @other_bit: u8 ** to return the companion clock bit shift in | ||
287 | * | ||
288 | * Note: We don't need special code here for INVERT_ENABLE for the | ||
289 | * time being since INVERT_ENABLE only applies to clocks enabled by | ||
290 | * CM_CLKEN_PLL | ||
291 | * | ||
292 | * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's | ||
293 | * just a matter of XORing the bits. | ||
294 | * | ||
295 | * Some clocks don't have companion clocks. For example, modules with | ||
296 | * only an interface clock (such as MAILBOXES) don't have a companion | ||
297 | * clock. Right now, this code relies on the hardware exporting a bit | ||
298 | * in the correct companion register that indicates that the | ||
299 | * nonexistent 'companion clock' is active. Future patches will | ||
300 | * associate this type of code with per-module data structures to | ||
301 | * avoid this issue, and remove the casts. No return value. | ||
302 | */ | ||
303 | void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, | ||
304 | void __iomem **other_reg, u8 *other_bit) | ||
305 | { | ||
306 | u32 r; | ||
307 | |||
308 | /* | ||
309 | * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes | ||
310 | * it's just a matter of XORing the bits. | ||
311 | */ | ||
312 | r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); | ||
313 | |||
314 | *other_reg = (__force void __iomem *)r; | ||
315 | *other_bit = clk->enable_bit; | ||
316 | } | ||
317 | |||
318 | /** | ||
319 | * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk | ||
320 | * @clk: struct clk * to find IDLEST info for | ||
321 | * @idlest_reg: void __iomem ** to return the CM_IDLEST va in | ||
322 | * @idlest_bit: u8 * to return the CM_IDLEST bit shift in | ||
323 | * @idlest_val: u8 * to return the idle status indicator | ||
324 | * | ||
325 | * Return the CM_IDLEST register address and bit shift corresponding | ||
326 | * to the module that "owns" this clock. This default code assumes | ||
327 | * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that | ||
328 | * the IDLEST register address ID corresponds to the CM_*CLKEN | ||
329 | * register address ID (e.g., that CM_FCLKEN2 corresponds to | ||
330 | * CM_IDLEST2). This is not true for all modules. No return value. | ||
331 | */ | ||
332 | void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, | ||
333 | void __iomem **idlest_reg, u8 *idlest_bit, u8 *idlest_val) | ||
334 | { | ||
335 | u32 r; | ||
336 | |||
337 | r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); | ||
338 | *idlest_reg = (__force void __iomem *)r; | ||
339 | *idlest_bit = clk->enable_bit; | ||
340 | |||
341 | /* | ||
342 | * 24xx uses 0 to indicate not ready, and 1 to indicate ready. | ||
343 | * 34xx reverses this, just to keep us on our toes | ||
344 | * AM35xx uses both, depending on the module. | ||
345 | */ | ||
346 | *idlest_val = ti_clk_get_features()->cm_idlest_val; | ||
347 | } | ||
348 | |||
349 | /** | ||
350 | * omap2_dflt_clk_enable - enable a clock in the hardware | ||
351 | * @hw: struct clk_hw * of the clock to enable | ||
352 | * | ||
353 | * Enable the clock @hw in the hardware. We first call into the OMAP | ||
354 | * clockdomain code to "enable" the corresponding clockdomain if this | ||
355 | * is the first enabled user of the clockdomain. Then program the | ||
356 | * hardware to enable the clock. Then wait for the IP block that uses | ||
357 | * this clock to leave idle (if applicable). Returns the error value | ||
358 | * from clkdm_clk_enable() if it terminated with an error, or -EINVAL | ||
359 | * if @hw has a null clock enable_reg, or zero upon success. | ||
360 | */ | ||
361 | int omap2_dflt_clk_enable(struct clk_hw *hw) | ||
362 | { | ||
363 | struct clk_hw_omap *clk; | ||
364 | u32 v; | ||
365 | int ret = 0; | ||
366 | bool clkdm_control; | ||
367 | |||
368 | if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) | ||
369 | clkdm_control = false; | ||
370 | else | ||
371 | clkdm_control = true; | ||
372 | |||
373 | clk = to_clk_hw_omap(hw); | ||
374 | |||
375 | if (clkdm_control && clk->clkdm) { | ||
376 | ret = clkdm_clk_enable(clk->clkdm, hw->clk); | ||
377 | if (ret) { | ||
378 | WARN(1, "%s: could not enable %s's clockdomain %s: %d\n", | ||
379 | __func__, __clk_get_name(hw->clk), | ||
380 | clk->clkdm->name, ret); | ||
381 | return ret; | ||
382 | } | ||
383 | } | ||
384 | |||
385 | if (unlikely(clk->enable_reg == NULL)) { | ||
386 | pr_err("%s: %s missing enable_reg\n", __func__, | ||
387 | __clk_get_name(hw->clk)); | ||
388 | ret = -EINVAL; | ||
389 | goto err; | ||
390 | } | ||
391 | |||
392 | /* FIXME should not have INVERT_ENABLE bit here */ | ||
393 | v = omap2_clk_readl(clk, clk->enable_reg); | ||
394 | if (clk->flags & INVERT_ENABLE) | ||
395 | v &= ~(1 << clk->enable_bit); | ||
396 | else | ||
397 | v |= (1 << clk->enable_bit); | ||
398 | omap2_clk_writel(v, clk, clk->enable_reg); | ||
399 | v = omap2_clk_readl(clk, clk->enable_reg); /* OCP barrier */ | ||
400 | |||
401 | if (clk->ops && clk->ops->find_idlest) | ||
402 | _omap2_module_wait_ready(clk); | ||
403 | |||
404 | return 0; | ||
405 | |||
406 | err: | ||
407 | if (clkdm_control && clk->clkdm) | ||
408 | clkdm_clk_disable(clk->clkdm, hw->clk); | ||
409 | return ret; | ||
410 | } | ||
411 | |||
412 | /** | ||
413 | * omap2_dflt_clk_disable - disable a clock in the hardware | ||
414 | * @hw: struct clk_hw * of the clock to disable | ||
415 | * | ||
416 | * Disable the clock @hw in the hardware, and call into the OMAP | ||
417 | * clockdomain code to "disable" the corresponding clockdomain if all | ||
418 | * clocks/hwmods in that clockdomain are now disabled. No return | ||
419 | * value. | ||
420 | */ | ||
421 | void omap2_dflt_clk_disable(struct clk_hw *hw) | ||
422 | { | ||
423 | struct clk_hw_omap *clk; | ||
424 | u32 v; | ||
425 | |||
426 | clk = to_clk_hw_omap(hw); | ||
427 | if (!clk->enable_reg) { | ||
428 | /* | ||
429 | * 'independent' here refers to a clock which is not | ||
430 | * controlled by its parent. | ||
431 | */ | ||
432 | pr_err("%s: independent clock %s has no enable_reg\n", | ||
433 | __func__, __clk_get_name(hw->clk)); | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | v = omap2_clk_readl(clk, clk->enable_reg); | ||
438 | if (clk->flags & INVERT_ENABLE) | ||
439 | v |= (1 << clk->enable_bit); | ||
440 | else | ||
441 | v &= ~(1 << clk->enable_bit); | ||
442 | omap2_clk_writel(v, clk, clk->enable_reg); | ||
443 | /* No OCP barrier needed here since it is a disable operation */ | ||
444 | |||
445 | if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) && | ||
446 | clk->clkdm) | ||
447 | clkdm_clk_disable(clk->clkdm, hw->clk); | ||
448 | } | ||
449 | |||
450 | /** | ||
451 | * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw | 206 | * omap2_clkops_enable_clkdm - increment usecount on clkdm of @hw |
452 | * @hw: struct clk_hw * of the clock being enabled | 207 | * @hw: struct clk_hw * of the clock being enabled |
453 | * | 208 | * |
@@ -523,29 +278,6 @@ void omap2_clkops_disable_clkdm(struct clk_hw *hw) | |||
523 | clkdm_clk_disable(clk->clkdm, hw->clk); | 278 | clkdm_clk_disable(clk->clkdm, hw->clk); |
524 | } | 279 | } |
525 | 280 | ||
526 | /** | ||
527 | * omap2_dflt_clk_is_enabled - is clock enabled in the hardware? | ||
528 | * @hw: struct clk_hw * to check | ||
529 | * | ||
530 | * Return 1 if the clock represented by @hw is enabled in the | ||
531 | * hardware, or 0 otherwise. Intended for use in the struct | ||
532 | * clk_ops.is_enabled function pointer. | ||
533 | */ | ||
534 | int omap2_dflt_clk_is_enabled(struct clk_hw *hw) | ||
535 | { | ||
536 | struct clk_hw_omap *clk = to_clk_hw_omap(hw); | ||
537 | u32 v; | ||
538 | |||
539 | v = omap2_clk_readl(clk, clk->enable_reg); | ||
540 | |||
541 | if (clk->flags & INVERT_ENABLE) | ||
542 | v ^= BIT(clk->enable_bit); | ||
543 | |||
544 | v &= BIT(clk->enable_bit); | ||
545 | |||
546 | return v ? 1 : 0; | ||
547 | } | ||
548 | |||
549 | static int __initdata mpurate; | 281 | static int __initdata mpurate; |
550 | 282 | ||
551 | /* | 283 | /* |
@@ -566,11 +298,6 @@ static int __init omap_clk_setup(char *str) | |||
566 | } | 298 | } |
567 | __setup("mpurate=", omap_clk_setup); | 299 | __setup("mpurate=", omap_clk_setup); |
568 | 300 | ||
569 | const struct clk_hw_omap_ops clkhwops_wait = { | ||
570 | .find_idlest = omap2_clk_dflt_find_idlest, | ||
571 | .find_companion = omap2_clk_dflt_find_companion, | ||
572 | }; | ||
573 | |||
574 | /** | 301 | /** |
575 | * omap2_clk_print_new_rates - print summary of current clock tree rates | 302 | * omap2_clk_print_new_rates - print summary of current clock tree rates |
576 | * @hfclkin_ck_name: clk name for the off-chip HF oscillator | 303 | * @hfclkin_ck_name: clk name for the off-chip HF oscillator |
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile index 05a0294aba10..9b93e6904359 100644 --- a/drivers/clk/ti/Makefile +++ b/drivers/clk/ti/Makefile | |||
@@ -1,7 +1,7 @@ | |||
1 | obj-y += clk.o autoidle.o clockdomain.o | 1 | obj-y += clk.o autoidle.o clockdomain.o |
2 | clk-common = dpll.o composite.o divider.o gate.o \ | 2 | clk-common = dpll.o composite.o divider.o gate.o \ |
3 | fixed-factor.o mux.o apll.o \ | 3 | fixed-factor.o mux.o apll.o \ |
4 | clkt_dpll.o clkt_iclk.o | 4 | clkt_dpll.o clkt_iclk.o clkt_dflt.o |
5 | obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o | 5 | obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o dpll3xxx.o |
6 | obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o | 6 | obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o |
7 | obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o | 7 | obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o |
diff --git a/drivers/clk/ti/clkt_dflt.c b/drivers/clk/ti/clkt_dflt.c new file mode 100644 index 000000000000..a176b8ac8dd0 --- /dev/null +++ b/drivers/clk/ti/clkt_dflt.c | |||
@@ -0,0 +1,316 @@ | |||
1 | /* | ||
2 | * Default clock type | ||
3 | * | ||
4 | * Copyright (C) 2005-2008, 2015 Texas Instruments, Inc. | ||
5 | * Copyright (C) 2004-2010 Nokia Corporation | ||
6 | * | ||
7 | * Contacts: | ||
8 | * Richard Woodruff <r-woodruff2@ti.com> | ||
9 | * Paul Walmsley | ||
10 | * Tero Kristo <t-kristo@ti.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any | ||
17 | * kind, whether express or implied; without even the implied warranty | ||
18 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | */ | ||
21 | |||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/clk-provider.h> | ||
25 | #include <linux/io.h> | ||
26 | #include <linux/clk/ti.h> | ||
27 | #include <linux/delay.h> | ||
28 | |||
29 | #include "clock.h" | ||
30 | |||
31 | /* | ||
32 | * MAX_MODULE_ENABLE_WAIT: maximum of number of microseconds to wait | ||
33 | * for a module to indicate that it is no longer in idle | ||
34 | */ | ||
35 | #define MAX_MODULE_ENABLE_WAIT 100000 | ||
36 | |||
37 | /* | ||
38 | * CM module register offsets, used for calculating the companion | ||
39 | * register addresses. | ||
40 | */ | ||
41 | #define CM_FCLKEN 0x0000 | ||
42 | #define CM_ICLKEN 0x0010 | ||
43 | |||
44 | /** | ||
45 | * _wait_idlest_generic - wait for a module to leave the idle state | ||
46 | * @clk: module clock to wait for (needed for register offsets) | ||
47 | * @reg: virtual address of module IDLEST register | ||
48 | * @mask: value to mask against to determine if the module is active | ||
49 | * @idlest: idle state indicator (0 or 1) for the clock | ||
50 | * @name: name of the clock (for printk) | ||
51 | * | ||
52 | * Wait for a module to leave idle, where its idle-status register is | ||
53 | * not inside the CM module. Returns 1 if the module left idle | ||
54 | * promptly, or 0 if the module did not leave idle before the timeout | ||
55 | * elapsed. XXX Deprecated - should be moved into drivers for the | ||
56 | * individual IP block that the IDLEST register exists in. | ||
57 | */ | ||
58 | static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg, | ||
59 | u32 mask, u8 idlest, const char *name) | ||
60 | { | ||
61 | int i = 0, ena = 0; | ||
62 | |||
63 | ena = (idlest) ? 0 : mask; | ||
64 | |||
65 | /* Wait until module enters enabled state */ | ||
66 | for (i = 0; i < MAX_MODULE_ENABLE_WAIT; i++) { | ||
67 | if ((ti_clk_ll_ops->clk_readl(reg) & mask) == ena) | ||
68 | break; | ||
69 | udelay(1); | ||
70 | } | ||
71 | |||
72 | if (i < MAX_MODULE_ENABLE_WAIT) | ||
73 | pr_debug("omap clock: module associated with clock %s ready after %d loops\n", | ||
74 | name, i); | ||
75 | else | ||
76 | pr_err("omap clock: module associated with clock %s didn't enable in %d tries\n", | ||
77 | name, MAX_MODULE_ENABLE_WAIT); | ||
78 | |||
79 | return (i < MAX_MODULE_ENABLE_WAIT) ? 1 : 0; | ||
80 | } | ||
81 | |||
82 | /** | ||
83 | * _omap2_module_wait_ready - wait for an OMAP module to leave IDLE | ||
84 | * @clk: struct clk * belonging to the module | ||
85 | * | ||
86 | * If the necessary clocks for the OMAP hardware IP block that | ||
87 | * corresponds to clock @clk are enabled, then wait for the module to | ||
88 | * indicate readiness (i.e., to leave IDLE). This code does not | ||
89 | * belong in the clock code and will be moved in the medium term to | ||
90 | * module-dependent code. No return value. | ||
91 | */ | ||
92 | static void _omap2_module_wait_ready(struct clk_hw_omap *clk) | ||
93 | { | ||
94 | void __iomem *companion_reg, *idlest_reg; | ||
95 | u8 other_bit, idlest_bit, idlest_val, idlest_reg_id; | ||
96 | s16 prcm_mod; | ||
97 | int r; | ||
98 | |||
99 | /* Not all modules have multiple clocks that their IDLEST depends on */ | ||
100 | if (clk->ops->find_companion) { | ||
101 | clk->ops->find_companion(clk, &companion_reg, &other_bit); | ||
102 | if (!(ti_clk_ll_ops->clk_readl(companion_reg) & | ||
103 | (1 << other_bit))) | ||
104 | return; | ||
105 | } | ||
106 | |||
107 | clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val); | ||
108 | r = ti_clk_ll_ops->cm_split_idlest_reg(idlest_reg, &prcm_mod, | ||
109 | &idlest_reg_id); | ||
110 | if (r) { | ||
111 | /* IDLEST register not in the CM module */ | ||
112 | _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit), | ||
113 | idlest_val, __clk_get_name(clk->hw.clk)); | ||
114 | } else { | ||
115 | ti_clk_ll_ops->cm_wait_module_ready(0, prcm_mod, idlest_reg_id, | ||
116 | idlest_bit); | ||
117 | } | ||
118 | } | ||
119 | |||
120 | /** | ||
121 | * omap2_clk_dflt_find_companion - find companion clock to @clk | ||
122 | * @clk: struct clk * to find the companion clock of | ||
123 | * @other_reg: void __iomem ** to return the companion clock CM_*CLKEN va in | ||
124 | * @other_bit: u8 ** to return the companion clock bit shift in | ||
125 | * | ||
126 | * Note: We don't need special code here for INVERT_ENABLE for the | ||
127 | * time being since INVERT_ENABLE only applies to clocks enabled by | ||
128 | * CM_CLKEN_PLL | ||
129 | * | ||
130 | * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes it's | ||
131 | * just a matter of XORing the bits. | ||
132 | * | ||
133 | * Some clocks don't have companion clocks. For example, modules with | ||
134 | * only an interface clock (such as MAILBOXES) don't have a companion | ||
135 | * clock. Right now, this code relies on the hardware exporting a bit | ||
136 | * in the correct companion register that indicates that the | ||
137 | * nonexistent 'companion clock' is active. Future patches will | ||
138 | * associate this type of code with per-module data structures to | ||
139 | * avoid this issue, and remove the casts. No return value. | ||
140 | */ | ||
141 | void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, | ||
142 | void __iomem **other_reg, u8 *other_bit) | ||
143 | { | ||
144 | u32 r; | ||
145 | |||
146 | /* | ||
147 | * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes | ||
148 | * it's just a matter of XORing the bits. | ||
149 | */ | ||
150 | r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN)); | ||
151 | |||
152 | *other_reg = (__force void __iomem *)r; | ||
153 | *other_bit = clk->enable_bit; | ||
154 | } | ||
155 | |||
156 | /** | ||
157 | * omap2_clk_dflt_find_idlest - find CM_IDLEST reg va, bit shift for @clk | ||
158 | * @clk: struct clk * to find IDLEST info for | ||
159 | * @idlest_reg: void __iomem ** to return the CM_IDLEST va in | ||
160 | * @idlest_bit: u8 * to return the CM_IDLEST bit shift in | ||
161 | * @idlest_val: u8 * to return the idle status indicator | ||
162 | * | ||
163 | * Return the CM_IDLEST register address and bit shift corresponding | ||
164 | * to the module that "owns" this clock. This default code assumes | ||
165 | * that the CM_IDLEST bit shift is the CM_*CLKEN bit shift, and that | ||
166 | * the IDLEST register address ID corresponds to the CM_*CLKEN | ||
167 | * register address ID (e.g., that CM_FCLKEN2 corresponds to | ||
168 | * CM_IDLEST2). This is not true for all modules. No return value. | ||
169 | */ | ||
170 | void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk, | ||
171 | void __iomem **idlest_reg, u8 *idlest_bit, | ||
172 | u8 *idlest_val) | ||
173 | { | ||
174 | u32 r; | ||
175 | |||
176 | r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20); | ||
177 | *idlest_reg = (__force void __iomem *)r; | ||
178 | *idlest_bit = clk->enable_bit; | ||
179 | |||
180 | /* | ||
181 | * 24xx uses 0 to indicate not ready, and 1 to indicate ready. | ||
182 | * 34xx reverses this, just to keep us on our toes | ||
183 | * AM35xx uses both, depending on the module. | ||
184 | */ | ||
185 | *idlest_val = ti_clk_get_features()->cm_idlest_val; | ||
186 | } | ||
187 | |||
188 | /** | ||
189 | * omap2_dflt_clk_enable - enable a clock in the hardware | ||
190 | * @hw: struct clk_hw * of the clock to enable | ||
191 | * | ||
192 | * Enable the clock @hw in the hardware. We first call into the OMAP | ||
193 | * clockdomain code to "enable" the corresponding clockdomain if this | ||
194 | * is the first enabled user of the clockdomain. Then program the | ||
195 | * hardware to enable the clock. Then wait for the IP block that uses | ||
196 | * this clock to leave idle (if applicable). Returns the error value | ||
197 | * from clkdm_clk_enable() if it terminated with an error, or -EINVAL | ||
198 | * if @hw has a null clock enable_reg, or zero upon success. | ||
199 | */ | ||
200 | int omap2_dflt_clk_enable(struct clk_hw *hw) | ||
201 | { | ||
202 | struct clk_hw_omap *clk; | ||
203 | u32 v; | ||
204 | int ret = 0; | ||
205 | bool clkdm_control; | ||
206 | |||
207 | if (ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) | ||
208 | clkdm_control = false; | ||
209 | else | ||
210 | clkdm_control = true; | ||
211 | |||
212 | clk = to_clk_hw_omap(hw); | ||
213 | |||
214 | if (clkdm_control && clk->clkdm) { | ||
215 | ret = ti_clk_ll_ops->clkdm_clk_enable(clk->clkdm, hw->clk); | ||
216 | if (ret) { | ||
217 | WARN(1, | ||
218 | "%s: could not enable %s's clockdomain %s: %d\n", | ||
219 | __func__, __clk_get_name(hw->clk), | ||
220 | clk->clkdm_name, ret); | ||
221 | return ret; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | if (unlikely(!clk->enable_reg)) { | ||
226 | pr_err("%s: %s missing enable_reg\n", __func__, | ||
227 | __clk_get_name(hw->clk)); | ||
228 | ret = -EINVAL; | ||
229 | goto err; | ||
230 | } | ||
231 | |||
232 | /* FIXME should not have INVERT_ENABLE bit here */ | ||
233 | v = ti_clk_ll_ops->clk_readl(clk->enable_reg); | ||
234 | if (clk->flags & INVERT_ENABLE) | ||
235 | v &= ~(1 << clk->enable_bit); | ||
236 | else | ||
237 | v |= (1 << clk->enable_bit); | ||
238 | ti_clk_ll_ops->clk_writel(v, clk->enable_reg); | ||
239 | v = ti_clk_ll_ops->clk_readl(clk->enable_reg); /* OCP barrier */ | ||
240 | |||
241 | if (clk->ops && clk->ops->find_idlest) | ||
242 | _omap2_module_wait_ready(clk); | ||
243 | |||
244 | return 0; | ||
245 | |||
246 | err: | ||
247 | if (clkdm_control && clk->clkdm) | ||
248 | ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); | ||
249 | return ret; | ||
250 | } | ||
251 | |||
252 | /** | ||
253 | * omap2_dflt_clk_disable - disable a clock in the hardware | ||
254 | * @hw: struct clk_hw * of the clock to disable | ||
255 | * | ||
256 | * Disable the clock @hw in the hardware, and call into the OMAP | ||
257 | * clockdomain code to "disable" the corresponding clockdomain if all | ||
258 | * clocks/hwmods in that clockdomain are now disabled. No return | ||
259 | * value. | ||
260 | */ | ||
261 | void omap2_dflt_clk_disable(struct clk_hw *hw) | ||
262 | { | ||
263 | struct clk_hw_omap *clk; | ||
264 | u32 v; | ||
265 | |||
266 | clk = to_clk_hw_omap(hw); | ||
267 | if (!clk->enable_reg) { | ||
268 | /* | ||
269 | * 'independent' here refers to a clock which is not | ||
270 | * controlled by its parent. | ||
271 | */ | ||
272 | pr_err("%s: independent clock %s has no enable_reg\n", | ||
273 | __func__, __clk_get_name(hw->clk)); | ||
274 | return; | ||
275 | } | ||
276 | |||
277 | v = ti_clk_ll_ops->clk_readl(clk->enable_reg); | ||
278 | if (clk->flags & INVERT_ENABLE) | ||
279 | v |= (1 << clk->enable_bit); | ||
280 | else | ||
281 | v &= ~(1 << clk->enable_bit); | ||
282 | ti_clk_ll_ops->clk_writel(v, clk->enable_reg); | ||
283 | /* No OCP barrier needed here since it is a disable operation */ | ||
284 | |||
285 | if (!(ti_clk_get_features()->flags & TI_CLK_DISABLE_CLKDM_CONTROL) && | ||
286 | clk->clkdm) | ||
287 | ti_clk_ll_ops->clkdm_clk_disable(clk->clkdm, hw->clk); | ||
288 | } | ||
289 | |||
290 | /** | ||
291 | * omap2_dflt_clk_is_enabled - is clock enabled in the hardware? | ||
292 | * @hw: struct clk_hw * to check | ||
293 | * | ||
294 | * Return 1 if the clock represented by @hw is enabled in the | ||
295 | * hardware, or 0 otherwise. Intended for use in the struct | ||
296 | * clk_ops.is_enabled function pointer. | ||
297 | */ | ||
298 | int omap2_dflt_clk_is_enabled(struct clk_hw *hw) | ||
299 | { | ||
300 | struct clk_hw_omap *clk = to_clk_hw_omap(hw); | ||
301 | u32 v; | ||
302 | |||
303 | v = ti_clk_ll_ops->clk_readl(clk->enable_reg); | ||
304 | |||
305 | if (clk->flags & INVERT_ENABLE) | ||
306 | v ^= BIT(clk->enable_bit); | ||
307 | |||
308 | v &= BIT(clk->enable_bit); | ||
309 | |||
310 | return v ? 1 : 0; | ||
311 | } | ||
312 | |||
313 | const struct clk_hw_omap_ops clkhwops_wait = { | ||
314 | .find_idlest = omap2_clk_dflt_find_idlest, | ||
315 | .find_companion = omap2_clk_dflt_find_companion, | ||
316 | }; | ||
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h index 688d9e47b2c8..f21538364588 100644 --- a/drivers/clk/ti/clock.h +++ b/drivers/clk/ti/clock.h | |||
@@ -175,9 +175,14 @@ void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks); | |||
175 | 175 | ||
176 | extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; | 176 | extern const struct clk_hw_omap_ops clkhwops_omap3_dpll; |
177 | extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; | 177 | extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx; |
178 | extern const struct clk_hw_omap_ops clkhwops_wait; | ||
178 | extern const struct clk_hw_omap_ops clkhwops_iclk; | 179 | extern const struct clk_hw_omap_ops clkhwops_iclk; |
179 | extern const struct clk_hw_omap_ops clkhwops_iclk_wait; | 180 | extern const struct clk_hw_omap_ops clkhwops_iclk_wait; |
180 | 181 | ||
182 | int omap2_dflt_clk_enable(struct clk_hw *hw); | ||
183 | void omap2_dflt_clk_disable(struct clk_hw *hw); | ||
184 | int omap2_dflt_clk_is_enabled(struct clk_hw *hw); | ||
185 | |||
181 | u8 omap2_init_dpll_parent(struct clk_hw *hw); | 186 | u8 omap2_init_dpll_parent(struct clk_hw *hw); |
182 | int omap3_noncore_dpll_enable(struct clk_hw *hw); | 187 | int omap3_noncore_dpll_enable(struct clk_hw *hw); |
183 | void omap3_noncore_dpll_disable(struct clk_hw *hw); | 188 | void omap3_noncore_dpll_disable(struct clk_hw *hw); |
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h index fbb65e401d13..81a913edffa7 100644 --- a/include/linux/clk/ti.h +++ b/include/linux/clk/ti.h | |||
@@ -278,9 +278,6 @@ int omap2_clk_disable_autoidle_all(void); | |||
278 | int omap2_clk_enable_autoidle_all(void); | 278 | int omap2_clk_enable_autoidle_all(void); |
279 | int omap2_clk_allow_idle(struct clk *clk); | 279 | int omap2_clk_allow_idle(struct clk *clk); |
280 | int omap2_clk_deny_idle(struct clk *clk); | 280 | int omap2_clk_deny_idle(struct clk *clk); |
281 | int omap2_dflt_clk_enable(struct clk_hw *hw); | ||
282 | void omap2_dflt_clk_disable(struct clk_hw *hw); | ||
283 | int omap2_dflt_clk_is_enabled(struct clk_hw *hw); | ||
284 | void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); | 281 | void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk); |
285 | void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); | 282 | void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk); |
286 | void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, | 283 | void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk, |
@@ -337,7 +334,6 @@ const struct ti_clk_features *ti_clk_get_features(void); | |||
337 | 334 | ||
338 | extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; | 335 | extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll; |
339 | extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; | 336 | extern const struct clk_hw_omap_ops clkhwops_omap2430_i2chs_wait; |
340 | extern const struct clk_hw_omap_ops clkhwops_wait; | ||
341 | extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; | 337 | extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait; |
342 | extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; | 338 | extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait; |
343 | extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; | 339 | extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait; |