Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clock.c
Go to the documentation of this file.
1 /*
2  * linux/arch/arm/mach-omap2/clock.c
3  *
4  * Copyright (C) 2005-2008 Texas Instruments, Inc.
5  * Copyright (C) 2004-2010 Nokia Corporation
6  *
7  * Contacts:
8  * Richard Woodruff <[email protected]>
9  * Paul Walmsley
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  */
15 #undef DEBUG
16 
17 #include <linux/kernel.h>
18 #include <linux/list.h>
19 #include <linux/errno.h>
20 #include <linux/err.h>
21 #include <linux/delay.h>
22 #include <linux/clk.h>
23 #include <linux/io.h>
24 #include <linux/bitops.h>
25 
26 #include <asm/cpu.h>
27 
28 #include <plat/clock.h>
29 #include <plat/prcm.h>
30 
31 #include <trace/events/power.h>
32 
33 #include "soc.h"
34 #include "clockdomain.h"
35 #include "clock.h"
36 #include "cm2xxx_3xxx.h"
37 #include "cm-regbits-24xx.h"
38 #include "cm-regbits-34xx.h"
39 
41 
42 /*
43  * clkdm_control: if true, then when a clock is enabled in the
44  * hardware, its clockdomain will first be enabled; and when a clock
45  * is disabled in the hardware, its clockdomain will be disabled
46  * afterwards.
47  */
48 static bool clkdm_control = true;
49 
50 /*
51  * OMAP2+ specific clock functions
52  */
53 
54 /* Private functions */
55 
66 static void _omap2_module_wait_ready(struct clk *clk)
67 {
68  void __iomem *companion_reg, *idlest_reg;
69  u8 other_bit, idlest_bit, idlest_val;
70 
71  /* Not all modules have multiple clocks that their IDLEST depends on */
72  if (clk->ops->find_companion) {
73  clk->ops->find_companion(clk, &companion_reg, &other_bit);
74  if (!(__raw_readl(companion_reg) & (1 << other_bit)))
75  return;
76  }
77 
78  clk->ops->find_idlest(clk, &idlest_reg, &idlest_bit, &idlest_val);
79 
80  omap2_cm_wait_idlest(idlest_reg, (1 << idlest_bit), idlest_val,
81  __clk_get_name(clk));
82 }
83 
84 /* Public functions */
85 
95 {
96  struct clockdomain *clkdm;
97  const char *clk_name;
98 
99  if (!clk->clkdm_name)
100  return;
101 
102  clk_name = __clk_get_name(clk);
103 
104  clkdm = clkdm_lookup(clk->clkdm_name);
105  if (clkdm) {
106  pr_debug("clock: associated clk %s to clkdm %s\n",
107  clk_name, clk->clkdm_name);
108  clk->clkdm = clkdm;
109  } else {
110  pr_debug("clock: could not associate clk %s to clkdm %s\n",
111  clk_name, clk->clkdm_name);
112  }
113 }
114 
124 {
125  clkdm_control = false;
126 }
127 
149 void omap2_clk_dflt_find_companion(struct clk *clk, void __iomem **other_reg,
150  u8 *other_bit)
151 {
152  u32 r;
153 
154  /*
155  * Convert CM_ICLKEN* <-> CM_FCLKEN*. This conversion assumes
156  * it's just a matter of XORing the bits.
157  */
158  r = ((__force u32)clk->enable_reg ^ (CM_FCLKEN ^ CM_ICLKEN));
159 
160  *other_reg = (__force void __iomem *)r;
161  *other_bit = clk->enable_bit;
162 }
163 
178 void omap2_clk_dflt_find_idlest(struct clk *clk, void __iomem **idlest_reg,
179  u8 *idlest_bit, u8 *idlest_val)
180 {
181  u32 r;
182 
183  r = (((__force u32)clk->enable_reg & ~0xf0) | 0x20);
184  *idlest_reg = (__force void __iomem *)r;
185  *idlest_bit = clk->enable_bit;
186 
187  /*
188  * 24xx uses 0 to indicate not ready, and 1 to indicate ready.
189  * 34xx reverses this, just to keep us on our toes
190  * AM35xx uses both, depending on the module.
191  */
192  if (cpu_is_omap24xx())
193  *idlest_val = OMAP24XX_CM_IDLEST_VAL;
194  else if (cpu_is_omap34xx())
195  *idlest_val = OMAP34XX_CM_IDLEST_VAL;
196  else
197  BUG();
198 
199 }
200 
202 {
203  u32 v;
204 
205  if (unlikely(clk->enable_reg == NULL)) {
206  pr_err("clock.c: Enable for %s without enable code\n",
207  clk->name);
208  return 0; /* REVISIT: -EINVAL */
209  }
210 
211  v = __raw_readl(clk->enable_reg);
212  if (clk->flags & INVERT_ENABLE)
213  v &= ~(1 << clk->enable_bit);
214  else
215  v |= (1 << clk->enable_bit);
216  __raw_writel(v, clk->enable_reg);
217  v = __raw_readl(clk->enable_reg); /* OCP barrier */
218 
219  if (clk->ops->find_idlest)
220  _omap2_module_wait_ready(clk);
221 
222  return 0;
223 }
224 
226 {
227  u32 v;
228 
229  if (!clk->enable_reg) {
230  /*
231  * 'Independent' here refers to a clock which is not
232  * controlled by its parent.
233  */
234  pr_err("clock: clk_disable called on independent clock %s which has no enable_reg\n", clk->name);
235  return;
236  }
237 
238  v = __raw_readl(clk->enable_reg);
239  if (clk->flags & INVERT_ENABLE)
240  v |= (1 << clk->enable_bit);
241  else
242  v &= ~(1 << clk->enable_bit);
243  __raw_writel(v, clk->enable_reg);
244  /* No OCP barrier needed here since it is a disable operation */
245 }
246 
248  .enable = omap2_dflt_clk_enable,
249  .disable = omap2_dflt_clk_disable,
250  .find_companion = omap2_clk_dflt_find_companion,
251  .find_idlest = omap2_clk_dflt_find_idlest,
252 };
253 
254 const struct clkops clkops_omap2_dflt = {
255  .enable = omap2_dflt_clk_enable,
256  .disable = omap2_dflt_clk_disable,
257 };
258 
274 void omap2_clk_disable(struct clk *clk)
275 {
276  if (clk->usecount == 0) {
277  WARN(1, "clock: %s: omap2_clk_disable() called, but usecount already 0?", clk->name);
278  return;
279  }
280 
281  pr_debug("clock: %s: decrementing usecount\n", clk->name);
282 
283  clk->usecount--;
284 
285  if (clk->usecount > 0)
286  return;
287 
288  pr_debug("clock: %s: disabling in hardware\n", clk->name);
289 
290  if (clk->ops && clk->ops->disable) {
291  trace_clock_disable(clk->name, 0, smp_processor_id());
292  clk->ops->disable(clk);
293  }
294 
295  if (clkdm_control && clk->clkdm)
296  clkdm_clk_disable(clk->clkdm, clk);
297 
298  if (clk->parent)
300 }
301 
314 {
315  int ret;
316 
317  pr_debug("clock: %s: incrementing usecount\n", clk->name);
318 
319  clk->usecount++;
320 
321  if (clk->usecount > 1)
322  return 0;
323 
324  pr_debug("clock: %s: enabling in hardware\n", clk->name);
325 
326  if (clk->parent) {
327  ret = omap2_clk_enable(clk->parent);
328  if (ret) {
329  WARN(1, "clock: %s: could not enable parent %s: %d\n",
330  clk->name, clk->parent->name, ret);
331  goto oce_err1;
332  }
333  }
334 
335  if (clkdm_control && clk->clkdm) {
336  ret = clkdm_clk_enable(clk->clkdm, clk);
337  if (ret) {
338  WARN(1, "clock: %s: could not enable clockdomain %s: %d\n",
339  clk->name, clk->clkdm->name, ret);
340  goto oce_err2;
341  }
342  }
343 
344  if (clk->ops && clk->ops->enable) {
345  trace_clock_enable(clk->name, 1, smp_processor_id());
346  ret = clk->ops->enable(clk);
347  if (ret) {
348  WARN(1, "clock: %s: could not enable: %d\n",
349  clk->name, ret);
350  goto oce_err3;
351  }
352  }
353 
354  return 0;
355 
356 oce_err3:
357  if (clkdm_control && clk->clkdm)
358  clkdm_clk_disable(clk->clkdm, clk);
359 oce_err2:
360  if (clk->parent)
362 oce_err1:
363  clk->usecount--;
364 
365  return ret;
366 }
367 
368 /* Given a clock and a rate apply a clock specific rounding function */
369 long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
370 {
371  if (clk->round_rate)
372  return clk->round_rate(clk, rate);
373 
374  return clk->rate;
375 }
376 
377 /* Set the clock rate for a clock source */
378 int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
379 {
380  int ret = -EINVAL;
381 
382  pr_debug("clock: set_rate for clock %s to rate %ld\n", clk->name, rate);
383 
384  /* dpll_ck, core_ck, virt_prcm_set; plus all clksel clocks */
385  if (clk->set_rate) {
386  trace_clock_set_rate(clk->name, rate, smp_processor_id());
387  ret = clk->set_rate(clk, rate);
388  }
389 
390  return ret;
391 }
392 
393 int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
394 {
395  if (!clk->clksel)
396  return -EINVAL;
397 
398  if (clk->parent == new_parent)
399  return 0;
400 
401  return omap2_clksel_set_parent(clk, new_parent);
402 }
403 
404 /*
405  * OMAP2+ clock reset and init functions
406  */
407 
408 #ifdef CONFIG_OMAP_RESET_CLOCKS
409 void omap2_clk_disable_unused(struct clk *clk)
410 {
411  u32 regval32, v;
412 
413  v = (clk->flags & INVERT_ENABLE) ? (1 << clk->enable_bit) : 0;
414 
415  regval32 = __raw_readl(clk->enable_reg);
416  if ((regval32 & (1 << clk->enable_bit)) == v)
417  return;
418 
419  pr_debug("Disabling unused clock \"%s\"\n", clk->name);
420  if (cpu_is_omap34xx()) {
421  omap2_clk_enable(clk);
422  omap2_clk_disable(clk);
423  } else {
424  clk->ops->disable(clk);
425  }
426  if (clk->clkdm != NULL)
427  pwrdm_state_switch(clk->clkdm->pwrdm.ptr);
428 }
429 #endif
430 
446 int __init omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name)
447 {
448  struct clk *mpurate_ck;
449  int r;
450 
451  if (!mpurate)
452  return -EINVAL;
453 
454  mpurate_ck = clk_get(NULL, mpurate_ck_name);
455  if (WARN(IS_ERR(mpurate_ck), "Failed to get %s.\n", mpurate_ck_name))
456  return -ENOENT;
457 
458  r = clk_set_rate(mpurate_ck, mpurate);
459  if (IS_ERR_VALUE(r)) {
460  WARN(1, "clock: %s: unable to set MPU rate to %d: %d\n",
461  mpurate_ck->name, mpurate, r);
462  clk_put(mpurate_ck);
463  return -EINVAL;
464  }
465 
466  calibrate_delay();
468 
469  clk_put(mpurate_ck);
470 
471  return 0;
472 }
473 
486 void __init omap2_clk_print_new_rates(const char *hfclkin_ck_name,
487  const char *core_ck_name,
488  const char *mpu_ck_name)
489 {
490  struct clk *hfclkin_ck, *core_ck, *mpu_ck;
491  unsigned long hfclkin_rate;
492 
493  mpu_ck = clk_get(NULL, mpu_ck_name);
494  if (WARN(IS_ERR(mpu_ck), "clock: failed to get %s.\n", mpu_ck_name))
495  return;
496 
497  core_ck = clk_get(NULL, core_ck_name);
498  if (WARN(IS_ERR(core_ck), "clock: failed to get %s.\n", core_ck_name))
499  return;
500 
501  hfclkin_ck = clk_get(NULL, hfclkin_ck_name);
502  if (WARN(IS_ERR(hfclkin_ck), "Failed to get %s.\n", hfclkin_ck_name))
503  return;
504 
505  hfclkin_rate = clk_get_rate(hfclkin_ck);
506 
507  pr_info("Switched to new clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
508  (hfclkin_rate / 1000000), ((hfclkin_rate / 100000) % 10),
509  (clk_get_rate(core_ck) / 1000000),
510  (clk_get_rate(mpu_ck) / 1000000));
511 }
512 
513 /* Common data */
514 
516  .clk_enable = omap2_clk_enable,
517  .clk_disable = omap2_clk_disable,
518  .clk_round_rate = omap2_clk_round_rate,
519  .clk_set_rate = omap2_clk_set_rate,
520  .clk_set_parent = omap2_clk_set_parent,
521  .clk_disable_unused = omap2_clk_disable_unused,
522 };
523