Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
clock-clksrc.c
Go to the documentation of this file.
1 /* linux/arch/arm/plat-samsung/clock-clksrc.c
2  *
3  * Copyright 2008 Simtec Electronics
4  * Ben Dooks <[email protected]>
5  * http://armlinux.simtec.co.uk/
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10 */
11 
12 #include <linux/init.h>
13 #include <linux/module.h>
14 #include <linux/kernel.h>
15 #include <linux/list.h>
16 #include <linux/errno.h>
17 #include <linux/err.h>
18 #include <linux/clk.h>
19 #include <linux/device.h>
20 #include <linux/io.h>
21 
22 #include <plat/clock.h>
23 #include <plat/clock-clksrc.h>
24 #include <plat/cpu-freq.h>
25 
26 static inline struct clksrc_clk *to_clksrc(struct clk *clk)
27 {
28  return container_of(clk, struct clksrc_clk, clk);
29 }
30 
31 static inline u32 bit_mask(u32 shift, u32 nr_bits)
32 {
33  u32 mask = 0xffffffff >> (32 - nr_bits);
34 
35  return mask << shift;
36 }
37 
38 static unsigned long s3c_getrate_clksrc(struct clk *clk)
39 {
40  struct clksrc_clk *sclk = to_clksrc(clk);
41  unsigned long rate = clk_get_rate(clk->parent);
42  u32 clkdiv = __raw_readl(sclk->reg_div.reg);
43  u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
44 
45  clkdiv &= mask;
46  clkdiv >>= sclk->reg_div.shift;
47  clkdiv++;
48 
49  rate /= clkdiv;
50  return rate;
51 }
52 
53 static int s3c_setrate_clksrc(struct clk *clk, unsigned long rate)
54 {
55  struct clksrc_clk *sclk = to_clksrc(clk);
56  void __iomem *reg = sclk->reg_div.reg;
57  unsigned int div;
58  u32 mask = bit_mask(sclk->reg_div.shift, sclk->reg_div.size);
59  u32 val;
60 
61  rate = clk_round_rate(clk, rate);
62  div = clk_get_rate(clk->parent) / rate;
63  if (div > (1 << sclk->reg_div.size))
64  return -EINVAL;
65 
66  val = __raw_readl(reg);
67  val &= ~mask;
68  val |= (div - 1) << sclk->reg_div.shift;
69  __raw_writel(val, reg);
70 
71  return 0;
72 }
73 
74 static int s3c_setparent_clksrc(struct clk *clk, struct clk *parent)
75 {
76  struct clksrc_clk *sclk = to_clksrc(clk);
77  struct clksrc_sources *srcs = sclk->sources;
78  u32 clksrc = __raw_readl(sclk->reg_src.reg);
79  u32 mask = bit_mask(sclk->reg_src.shift, sclk->reg_src.size);
80  int src_nr = -1;
81  int ptr;
82 
83  for (ptr = 0; ptr < srcs->nr_sources; ptr++)
84  if (srcs->sources[ptr] == parent) {
85  src_nr = ptr;
86  break;
87  }
88 
89  if (src_nr >= 0) {
90  clk->parent = parent;
91 
92  clksrc &= ~mask;
93  clksrc |= src_nr << sclk->reg_src.shift;
94 
95  __raw_writel(clksrc, sclk->reg_src.reg);
96  return 0;
97  }
98 
99  return -EINVAL;
100 }
101 
102 static unsigned long s3c_roundrate_clksrc(struct clk *clk,
103  unsigned long rate)
104 {
105  struct clksrc_clk *sclk = to_clksrc(clk);
106  unsigned long parent_rate = clk_get_rate(clk->parent);
107  int max_div = 1 << sclk->reg_div.size;
108  int div;
109 
110  if (rate >= parent_rate)
111  rate = parent_rate;
112  else {
113  div = parent_rate / rate;
114  if (parent_rate % rate)
115  div++;
116 
117  if (div == 0)
118  div = 1;
119  if (div > max_div)
120  div = max_div;
121 
122  rate = parent_rate / div;
123  }
124 
125  return rate;
126 }
127 
128 /* Clock initialisation code */
129 
130 void __init_or_cpufreq s3c_set_clksrc(struct clksrc_clk *clk, bool announce)
131 {
132  struct clksrc_sources *srcs = clk->sources;
133  u32 mask = bit_mask(clk->reg_src.shift, clk->reg_src.size);
134  u32 clksrc;
135 
136  if (!clk->reg_src.reg) {
137  if (!clk->clk.parent)
138  printk(KERN_ERR "%s: no parent clock specified\n",
139  clk->clk.name);
140  return;
141  }
142 
143  clksrc = __raw_readl(clk->reg_src.reg);
144  clksrc &= mask;
145  clksrc >>= clk->reg_src.shift;
146 
147  if (clksrc > srcs->nr_sources || !srcs->sources[clksrc]) {
148  printk(KERN_ERR "%s: bad source %d\n",
149  clk->clk.name, clksrc);
150  return;
151  }
152 
153  clk->clk.parent = srcs->sources[clksrc];
154 
155  if (announce)
156  printk(KERN_INFO "%s: source is %s (%d), rate is %ld\n",
157  clk->clk.name, clk->clk.parent->name, clksrc,
158  clk_get_rate(&clk->clk));
159 }
160 
161 static struct clk_ops clksrc_ops = {
162  .set_parent = s3c_setparent_clksrc,
163  .get_rate = s3c_getrate_clksrc,
164  .set_rate = s3c_setrate_clksrc,
165  .round_rate = s3c_roundrate_clksrc,
166 };
167 
168 static struct clk_ops clksrc_ops_nodiv = {
169  .set_parent = s3c_setparent_clksrc,
170 };
171 
172 static struct clk_ops clksrc_ops_nosrc = {
173  .get_rate = s3c_getrate_clksrc,
174  .set_rate = s3c_setrate_clksrc,
175  .round_rate = s3c_roundrate_clksrc,
176 };
177 
178 void __init s3c_register_clksrc(struct clksrc_clk *clksrc, int size)
179 {
180  int ret;
181 
182  for (; size > 0; size--, clksrc++) {
183  if (!clksrc->reg_div.reg && !clksrc->reg_src.reg)
184  printk(KERN_ERR "%s: clock %s has no registers set\n",
185  __func__, clksrc->clk.name);
186 
187  /* fill in the default functions */
188 
189  if (!clksrc->clk.ops) {
190  if (!clksrc->reg_div.reg)
191  clksrc->clk.ops = &clksrc_ops_nodiv;
192  else if (!clksrc->reg_src.reg)
193  clksrc->clk.ops = &clksrc_ops_nosrc;
194  else
195  clksrc->clk.ops = &clksrc_ops;
196  }
197 
198  /* setup the clocksource, but do not announce it
199  * as it may be re-set by the setup routines
200  * called after the rest of the clocks have been
201  * registered
202  */
203  s3c_set_clksrc(clksrc, false);
204 
205  ret = s3c24xx_register_clock(&clksrc->clk);
206 
207  if (ret < 0) {
208  printk(KERN_ERR "%s: failed to register %s (%d)\n",
209  __func__, clksrc->clk.name, ret);
210  }
211  }
212 }