Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clkt_clksel.c
Go to the documentation of this file.
1 /*
2  * clkt_clksel.c - OMAP2/3/4 clksel clock functions
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  *
16  * clksel clocks are clocks that do not have a fixed parent, or that
17  * can divide their parent's rate, or possibly both at the same time, based
18  * on the contents of a hardware register bitfield.
19  *
20  * All of the various mux and divider settings can be encoded into
21  * struct clksel* data structures, and then these can be autogenerated
22  * from some hardware database for each new chip generation. This
23  * should avoid the need to write, review, and validate a lot of new
24  * clock code for each new chip, since it can be exported from the SoC
25  * design flow. This is now done on OMAP4.
26  *
27  * The fusion of mux and divider clocks is a software creation. In
28  * hardware reality, the multiplexer (parent selection) and the
29  * divider exist separately. XXX At some point these clksel clocks
30  * should be split into "divider" clocks and "mux" clocks to better
31  * match the hardware.
32  *
33  * (The name "clksel" comes from the name of the corresponding
34  * register field in the OMAP2/3 family of SoCs.)
35  *
36  * XXX Currently these clocks are only used in the OMAP2/3/4 code, but
37  * many of the OMAP1 clocks should be convertible to use this
38  * mechanism.
39  */
40 #undef DEBUG
41 
42 #include <linux/kernel.h>
43 #include <linux/errno.h>
44 #include <linux/clk.h>
45 #include <linux/io.h>
46 #include <linux/bug.h>
47 
48 #include <plat/clock.h>
49 
50 #include "clock.h"
51 
52 /* Private functions */
53 
63 static const struct clksel *_get_clksel_by_parent(struct clk *clk,
64  struct clk *src_clk)
65 {
66  const struct clksel *clks;
67 
68  for (clks = clk->clksel; clks->parent; clks++)
69  if (clks->parent == src_clk)
70  break; /* Found the requested parent */
71 
72  if (!clks->parent) {
73  /* This indicates a data problem */
74  WARN(1, "clock: %s: could not find parent clock %s in clksel array\n",
75  __clk_get_name(clk), __clk_get_name(src_clk));
76  return NULL;
77  }
78 
79  return clks;
80 }
81 
97 static u8 _get_div_and_fieldval(struct clk *src_clk, struct clk *clk,
98  u32 *field_val)
99 {
100  const struct clksel *clks;
101  const struct clksel_rate *clkr, *max_clkr = NULL;
102  u8 max_div = 0;
103 
104  clks = _get_clksel_by_parent(clk, src_clk);
105  if (!clks)
106  return 0;
107 
108  /*
109  * Find the highest divisor (e.g., the one resulting in the
110  * lowest rate) to use as the default. This should avoid
111  * clock rates that are too high for the device. XXX A better
112  * solution here would be to try to determine if there is a
113  * divisor matching the original clock rate before the parent
114  * switch, and if it cannot be found, to fall back to the
115  * highest divisor.
116  */
117  for (clkr = clks->rates; clkr->div; clkr++) {
118  if (!(clkr->flags & cpu_mask))
119  continue;
120 
121  if (clkr->div > max_div) {
122  max_div = clkr->div;
123  max_clkr = clkr;
124  }
125  }
126 
127  if (max_div == 0) {
128  /* This indicates an error in the clksel data */
129  WARN(1, "clock: %s: could not find divisor for parent %s\n",
130  __clk_get_name(clk),
131  __clk_get_name(__clk_get_parent(src_clk)));
132  return 0;
133  }
134 
135  *field_val = max_clkr->val;
136 
137  return max_div;
138 }
139 
153 static void _write_clksel_reg(struct clk *clk, u32 field_val)
154 {
155  u32 v;
156 
157  v = __raw_readl(clk->clksel_reg);
158  v &= ~clk->clksel_mask;
159  v |= field_val << __ffs(clk->clksel_mask);
160  __raw_writel(v, clk->clksel_reg);
161 
162  v = __raw_readl(clk->clksel_reg); /* OCP barrier */
163 }
164 
176 static u32 _clksel_to_divisor(struct clk *clk, u32 field_val)
177 {
178  const struct clksel *clks;
179  const struct clksel_rate *clkr;
180  struct clk *parent;
181 
182  parent = __clk_get_parent(clk);
183  clks = _get_clksel_by_parent(clk, parent);
184  if (!clks)
185  return 0;
186 
187  for (clkr = clks->rates; clkr->div; clkr++) {
188  if (!(clkr->flags & cpu_mask))
189  continue;
190 
191  if (clkr->val == field_val)
192  break;
193  }
194 
195  if (!clkr->div) {
196  /* This indicates a data error */
197  WARN(1, "clock: %s: could not find fieldval %d for parent %s\n",
198  __clk_get_name(clk), field_val, __clk_get_name(parent));
199  return 0;
200  }
201 
202  return clkr->div;
203 }
204 
215 static u32 _divisor_to_clksel(struct clk *clk, u32 div)
216 {
217  const struct clksel *clks;
218  const struct clksel_rate *clkr;
219  struct clk *parent;
220 
221  /* should never happen */
222  WARN_ON(div == 0);
223 
224  parent = __clk_get_parent(clk);
225  clks = _get_clksel_by_parent(clk, parent);
226  if (!clks)
227  return ~0;
228 
229  for (clkr = clks->rates; clkr->div; clkr++) {
230  if (!(clkr->flags & cpu_mask))
231  continue;
232 
233  if (clkr->div == div)
234  break;
235  }
236 
237  if (!clkr->div) {
238  pr_err("clock: %s: could not find divisor %d for parent %s\n",
239  __clk_get_name(clk), div, __clk_get_name(parent));
240  return ~0;
241  }
242 
243  return clkr->val;
244 }
245 
254 static u32 _read_divisor(struct clk *clk)
255 {
256  u32 v;
257 
258  if (!clk->clksel || !clk->clksel_mask)
259  return 0;
260 
261  v = __raw_readl(clk->clksel_reg);
262  v &= clk->clksel_mask;
263  v >>= __ffs(clk->clksel_mask);
264 
265  return _clksel_to_divisor(clk, v);
266 }
267 
268 /* Public functions */
269 
282 u32 omap2_clksel_round_rate_div(struct clk *clk, unsigned long target_rate,
283  u32 *new_div)
284 {
285  unsigned long test_rate;
286  const struct clksel *clks;
287  const struct clksel_rate *clkr;
288  u32 last_div = 0;
289  struct clk *parent;
290  unsigned long parent_rate;
291  const char *clk_name;
292 
293  parent = __clk_get_parent(clk);
294  parent_rate = __clk_get_rate(parent);
295  clk_name = __clk_get_name(clk);
296 
297  if (!clk->clksel || !clk->clksel_mask)
298  return ~0;
299 
300  pr_debug("clock: clksel_round_rate_div: %s target_rate %ld\n",
301  clk_name, target_rate);
302 
303  *new_div = 1;
304 
305  clks = _get_clksel_by_parent(clk, parent);
306  if (!clks)
307  return ~0;
308 
309  for (clkr = clks->rates; clkr->div; clkr++) {
310  if (!(clkr->flags & cpu_mask))
311  continue;
312 
313  /* Sanity check */
314  if (clkr->div <= last_div)
315  pr_err("clock: %s: clksel_rate table not sorted\n",
316  clk_name);
317 
318  last_div = clkr->div;
319 
320  test_rate = parent_rate / clkr->div;
321 
322  if (test_rate <= target_rate)
323  break; /* found it */
324  }
325 
326  if (!clkr->div) {
327  pr_err("clock: %s: could not find divisor for target rate %ld for parent %s\n",
328  clk_name, target_rate, __clk_get_name(parent));
329  return ~0;
330  }
331 
332  *new_div = clkr->div;
333 
334  pr_debug("clock: new_div = %d, new_rate = %ld\n", *new_div,
335  (parent_rate / clkr->div));
336 
337  return parent_rate / clkr->div;
338 }
339 
340 /*
341  * Clocktype interface functions to the OMAP clock code
342  * (i.e., those used in struct clk field function pointers, etc.)
343  */
344 
354 void omap2_init_clksel_parent(struct clk *clk)
355 {
356  const struct clksel *clks;
357  const struct clksel_rate *clkr;
358  u32 r, found = 0;
359  struct clk *parent;
360  const char *clk_name;
361 
362  if (!clk->clksel || !clk->clksel_mask)
363  return;
364 
365  parent = __clk_get_parent(clk);
366  clk_name = __clk_get_name(clk);
367 
368  r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
369  r >>= __ffs(clk->clksel_mask);
370 
371  for (clks = clk->clksel; clks->parent && !found; clks++) {
372  for (clkr = clks->rates; clkr->div && !found; clkr++) {
373  if (!(clkr->flags & cpu_mask))
374  continue;
375 
376  if (clkr->val == r) {
377  if (parent != clks->parent) {
378  pr_debug("clock: %s: inited parent to %s (was %s)\n",
379  clk_name,
380  __clk_get_name(clks->parent),
381  ((parent) ?
382  __clk_get_name(parent) :
383  "NULL"));
384  clk_reparent(clk, clks->parent);
385  }
386  found = 1;
387  }
388  }
389  }
390 
391  /* This indicates a data error */
392  WARN(!found, "clock: %s: init parent: could not find regval %0x\n",
393  clk_name, r);
394 
395  return;
396 }
397 
407 unsigned long omap2_clksel_recalc(struct clk *clk)
408 {
409  unsigned long rate;
410  u32 div = 0;
411  struct clk *parent;
412 
413  div = _read_divisor(clk);
414  if (div == 0)
415  return __clk_get_rate(clk);
416 
417  parent = __clk_get_parent(clk);
418  rate = __clk_get_rate(parent) / div;
419 
420  pr_debug("clock: %s: recalc'd rate is %ld (div %d)\n",
421  __clk_get_name(clk), rate, div);
422 
423  return rate;
424 }
425 
437 long omap2_clksel_round_rate(struct clk *clk, unsigned long target_rate)
438 {
439  u32 new_div;
440 
441  return omap2_clksel_round_rate_div(clk, target_rate, &new_div);
442 }
443 
459 int omap2_clksel_set_rate(struct clk *clk, unsigned long rate)
460 {
461  u32 field_val, validrate, new_div = 0;
462 
463  if (!clk->clksel || !clk->clksel_mask)
464  return -EINVAL;
465 
466  validrate = omap2_clksel_round_rate_div(clk, rate, &new_div);
467  if (validrate != rate)
468  return -EINVAL;
469 
470  field_val = _divisor_to_clksel(clk, new_div);
471  if (field_val == ~0)
472  return -EINVAL;
473 
474  _write_clksel_reg(clk, field_val);
475 
476  clk->rate = __clk_get_rate(__clk_get_parent(clk)) / new_div;
477 
478  pr_debug("clock: %s: set rate to %ld\n", __clk_get_name(clk),
479  __clk_get_rate(clk));
480 
481  return 0;
482 }
483 
484 /*
485  * Clksel parent setting function - not passed in struct clk function
486  * pointer - instead, the OMAP clock code currently assumes that any
487  * parent-setting clock is a clksel clock, and calls
488  * omap2_clksel_set_parent() by default
489  */
490 
504 int omap2_clksel_set_parent(struct clk *clk, struct clk *new_parent)
505 {
506  u32 field_val = 0;
507  u32 parent_div;
508 
509  if (!clk->clksel || !clk->clksel_mask)
510  return -EINVAL;
511 
512  parent_div = _get_div_and_fieldval(new_parent, clk, &field_val);
513  if (!parent_div)
514  return -EINVAL;
515 
516  _write_clksel_reg(clk, field_val);
517 
518  clk_reparent(clk, new_parent);
519 
520  /* CLKSEL clocks follow their parents' rates, divided by a divisor */
521  clk->rate = __clk_get_rate(new_parent);
522 
523  if (parent_div > 0)
524  __clk_get_rate(clk) /= parent_div;
525 
526  pr_debug("clock: %s: set parent to %s (new rate %ld)\n",
527  __clk_get_name(clk),
529  __clk_get_rate(clk));
530 
531  return 0;
532 }