Commit | Line | Data |
---|---|---|
8c0236fc VK |
1 | /* |
2 | * arch/arm/plat-spear/clock.c | |
3 | * | |
4 | * Clock framework for SPEAr platform | |
5 | * | |
6 | * Copyright (C) 2009 ST Microelectronics | |
7 | * Viresh Kumar<viresh.kumar@st.com> | |
8 | * | |
9 | * This file is licensed under the terms of the GNU General Public | |
10 | * License version 2. This program is licensed "as is" without any | |
11 | * warranty of any kind, whether express or implied. | |
12 | */ | |
13 | ||
14 | #include <linux/bug.h> | |
15 | #include <linux/err.h> | |
16 | #include <linux/io.h> | |
17 | #include <linux/list.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/spinlock.h> | |
20 | #include <mach/misc_regs.h> | |
21 | #include <plat/clock.h> | |
22 | ||
23 | static DEFINE_SPINLOCK(clocks_lock); | |
24 | static LIST_HEAD(root_clks); | |
25 | ||
26 | static void propagate_rate(struct list_head *); | |
27 | ||
28 | static int generic_clk_enable(struct clk *clk) | |
29 | { | |
30 | unsigned int val; | |
31 | ||
32 | if (!clk->en_reg) | |
33 | return -EFAULT; | |
34 | ||
35 | val = readl(clk->en_reg); | |
36 | if (unlikely(clk->flags & RESET_TO_ENABLE)) | |
37 | val &= ~(1 << clk->en_reg_bit); | |
38 | else | |
39 | val |= 1 << clk->en_reg_bit; | |
40 | ||
41 | writel(val, clk->en_reg); | |
42 | ||
43 | return 0; | |
44 | } | |
45 | ||
46 | static void generic_clk_disable(struct clk *clk) | |
47 | { | |
48 | unsigned int val; | |
49 | ||
50 | if (!clk->en_reg) | |
51 | return; | |
52 | ||
53 | val = readl(clk->en_reg); | |
54 | if (unlikely(clk->flags & RESET_TO_ENABLE)) | |
55 | val |= 1 << clk->en_reg_bit; | |
56 | else | |
57 | val &= ~(1 << clk->en_reg_bit); | |
58 | ||
59 | writel(val, clk->en_reg); | |
60 | } | |
61 | ||
62 | /* generic clk ops */ | |
63 | static struct clkops generic_clkops = { | |
64 | .enable = generic_clk_enable, | |
65 | .disable = generic_clk_disable, | |
66 | }; | |
67 | ||
68 | /* | |
69 | * clk_enable - inform the system when the clock source should be running. | |
70 | * @clk: clock source | |
71 | * | |
72 | * If the clock can not be enabled/disabled, this should return success. | |
73 | * | |
74 | * Returns success (0) or negative errno. | |
75 | */ | |
76 | int clk_enable(struct clk *clk) | |
77 | { | |
78 | unsigned long flags; | |
79 | int ret = 0; | |
80 | ||
81 | if (!clk || IS_ERR(clk)) | |
82 | return -EFAULT; | |
83 | ||
84 | spin_lock_irqsave(&clocks_lock, flags); | |
85 | if (clk->usage_count == 0) { | |
86 | if (clk->ops && clk->ops->enable) | |
87 | ret = clk->ops->enable(clk); | |
88 | } | |
89 | clk->usage_count++; | |
90 | spin_unlock_irqrestore(&clocks_lock, flags); | |
91 | ||
92 | return ret; | |
93 | } | |
94 | EXPORT_SYMBOL(clk_enable); | |
95 | ||
96 | /* | |
97 | * clk_disable - inform the system when the clock source is no longer required. | |
98 | * @clk: clock source | |
99 | * | |
100 | * Inform the system that a clock source is no longer required by | |
101 | * a driver and may be shut down. | |
102 | * | |
103 | * Implementation detail: if the clock source is shared between | |
104 | * multiple drivers, clk_enable() calls must be balanced by the | |
105 | * same number of clk_disable() calls for the clock source to be | |
106 | * disabled. | |
107 | */ | |
108 | void clk_disable(struct clk *clk) | |
109 | { | |
110 | unsigned long flags; | |
111 | ||
112 | if (!clk || IS_ERR(clk)) | |
113 | return; | |
114 | ||
115 | WARN_ON(clk->usage_count == 0); | |
116 | ||
117 | spin_lock_irqsave(&clocks_lock, flags); | |
118 | clk->usage_count--; | |
119 | if (clk->usage_count == 0) { | |
120 | if (clk->ops && clk->ops->disable) | |
121 | clk->ops->disable(clk); | |
122 | } | |
123 | spin_unlock_irqrestore(&clocks_lock, flags); | |
124 | } | |
125 | EXPORT_SYMBOL(clk_disable); | |
126 | ||
127 | /** | |
128 | * clk_get_rate - obtain the current clock rate (in Hz) for a clock source. | |
129 | * This is only valid once the clock source has been enabled. | |
130 | * @clk: clock source | |
131 | */ | |
132 | unsigned long clk_get_rate(struct clk *clk) | |
133 | { | |
134 | unsigned long flags, rate; | |
135 | ||
136 | spin_lock_irqsave(&clocks_lock, flags); | |
137 | rate = clk->rate; | |
138 | spin_unlock_irqrestore(&clocks_lock, flags); | |
139 | ||
140 | return rate; | |
141 | } | |
142 | EXPORT_SYMBOL(clk_get_rate); | |
143 | ||
144 | /** | |
145 | * clk_set_parent - set the parent clock source for this clock | |
146 | * @clk: clock source | |
147 | * @parent: parent clock source | |
148 | * | |
149 | * Returns success (0) or negative errno. | |
150 | */ | |
151 | int clk_set_parent(struct clk *clk, struct clk *parent) | |
152 | { | |
153 | int i, found = 0, val = 0; | |
154 | unsigned long flags; | |
155 | ||
156 | if (!clk || IS_ERR(clk) || !parent || IS_ERR(parent)) | |
157 | return -EFAULT; | |
158 | if (clk->usage_count) | |
159 | return -EBUSY; | |
160 | if (!clk->pclk_sel) | |
161 | return -EPERM; | |
162 | if (clk->pclk == parent) | |
163 | return 0; | |
164 | ||
165 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | |
166 | if (clk->pclk_sel->pclk_info[i].pclk == parent) { | |
167 | found = 1; | |
168 | break; | |
169 | } | |
170 | } | |
171 | ||
172 | if (!found) | |
173 | return -EINVAL; | |
174 | ||
175 | spin_lock_irqsave(&clocks_lock, flags); | |
176 | /* reflect parent change in hardware */ | |
177 | val = readl(clk->pclk_sel->pclk_sel_reg); | |
178 | val &= ~(clk->pclk_sel->pclk_sel_mask << clk->pclk_sel_shift); | |
179 | val |= clk->pclk_sel->pclk_info[i].pclk_mask << clk->pclk_sel_shift; | |
180 | writel(val, clk->pclk_sel->pclk_sel_reg); | |
181 | spin_unlock_irqrestore(&clocks_lock, flags); | |
182 | ||
183 | /* reflect parent change in software */ | |
184 | clk->recalc(clk); | |
185 | propagate_rate(&clk->children); | |
186 | return 0; | |
187 | } | |
188 | EXPORT_SYMBOL(clk_set_parent); | |
189 | ||
190 | /* registers clock in platform clock framework */ | |
191 | void clk_register(struct clk_lookup *cl) | |
192 | { | |
193 | struct clk *clk = cl->clk; | |
194 | unsigned long flags; | |
195 | ||
196 | if (!clk || IS_ERR(clk)) | |
197 | return; | |
198 | ||
199 | spin_lock_irqsave(&clocks_lock, flags); | |
200 | ||
201 | INIT_LIST_HEAD(&clk->children); | |
202 | if (clk->flags & ALWAYS_ENABLED) | |
203 | clk->ops = NULL; | |
204 | else if (!clk->ops) | |
205 | clk->ops = &generic_clkops; | |
206 | ||
207 | /* root clock don't have any parents */ | |
208 | if (!clk->pclk && !clk->pclk_sel) { | |
209 | list_add(&clk->sibling, &root_clks); | |
210 | /* add clocks with only one parent to parent's children list */ | |
211 | } else if (clk->pclk && !clk->pclk_sel) { | |
212 | list_add(&clk->sibling, &clk->pclk->children); | |
213 | } else { | |
214 | /* add clocks with > 1 parent to 1st parent's children list */ | |
215 | list_add(&clk->sibling, | |
216 | &clk->pclk_sel->pclk_info[0].pclk->children); | |
217 | } | |
218 | spin_unlock_irqrestore(&clocks_lock, flags); | |
219 | ||
220 | /* add clock to arm clockdev framework */ | |
221 | clkdev_add(cl); | |
222 | } | |
223 | ||
224 | /** | |
225 | * propagate_rate - recalculate and propagate all clocks in list head | |
226 | * | |
227 | * Recalculates all root clocks in list head, which if the clock's .recalc is | |
228 | * set correctly, should also propagate their rates. | |
229 | */ | |
230 | static void propagate_rate(struct list_head *lhead) | |
231 | { | |
232 | struct clk *clkp, *_temp; | |
233 | ||
234 | list_for_each_entry_safe(clkp, _temp, lhead, sibling) { | |
235 | if (clkp->recalc) | |
236 | clkp->recalc(clkp); | |
237 | propagate_rate(&clkp->children); | |
238 | } | |
239 | } | |
240 | ||
241 | /* returns current programmed clocks clock info structure */ | |
242 | static struct pclk_info *pclk_info_get(struct clk *clk) | |
243 | { | |
244 | unsigned int mask, i; | |
245 | unsigned long flags; | |
246 | struct pclk_info *info = NULL; | |
247 | ||
248 | spin_lock_irqsave(&clocks_lock, flags); | |
249 | mask = (readl(clk->pclk_sel->pclk_sel_reg) >> clk->pclk_sel_shift) | |
250 | & clk->pclk_sel->pclk_sel_mask; | |
251 | ||
252 | for (i = 0; i < clk->pclk_sel->pclk_count; i++) { | |
253 | if (clk->pclk_sel->pclk_info[i].pclk_mask == mask) | |
254 | info = &clk->pclk_sel->pclk_info[i]; | |
255 | } | |
256 | spin_unlock_irqrestore(&clocks_lock, flags); | |
257 | ||
258 | return info; | |
259 | } | |
260 | ||
261 | /* | |
262 | * Set pclk as cclk's parent and add clock sibling node to current parents | |
263 | * children list | |
264 | */ | |
265 | static void change_parent(struct clk *cclk, struct clk *pclk) | |
266 | { | |
267 | unsigned long flags; | |
268 | ||
269 | spin_lock_irqsave(&clocks_lock, flags); | |
270 | list_del(&cclk->sibling); | |
271 | list_add(&cclk->sibling, &pclk->children); | |
272 | ||
273 | cclk->pclk = pclk; | |
274 | spin_unlock_irqrestore(&clocks_lock, flags); | |
275 | } | |
276 | ||
277 | /* | |
278 | * calculates current programmed rate of pll1 | |
279 | * | |
280 | * In normal mode | |
281 | * rate = (2 * M[15:8] * Fin)/(N * 2^P) | |
282 | * | |
283 | * In Dithered mode | |
284 | * rate = (2 * M[15:0] * Fin)/(256 * N * 2^P) | |
285 | */ | |
286 | void pll1_clk_recalc(struct clk *clk) | |
287 | { | |
288 | struct pll_clk_config *config = clk->private_data; | |
289 | unsigned int num = 2, den = 0, val, mode = 0; | |
290 | unsigned long flags; | |
291 | ||
292 | spin_lock_irqsave(&clocks_lock, flags); | |
293 | mode = (readl(config->mode_reg) >> PLL_MODE_SHIFT) & | |
294 | PLL_MODE_MASK; | |
295 | ||
296 | val = readl(config->cfg_reg); | |
297 | /* calculate denominator */ | |
298 | den = (val >> PLL_DIV_P_SHIFT) & PLL_DIV_P_MASK; | |
299 | den = 1 << den; | |
300 | den *= (val >> PLL_DIV_N_SHIFT) & PLL_DIV_N_MASK; | |
301 | ||
302 | /* calculate numerator & denominator */ | |
303 | if (!mode) { | |
304 | /* Normal mode */ | |
305 | num *= (val >> PLL_NORM_FDBK_M_SHIFT) & PLL_NORM_FDBK_M_MASK; | |
306 | } else { | |
307 | /* Dithered mode */ | |
308 | num *= (val >> PLL_DITH_FDBK_M_SHIFT) & PLL_DITH_FDBK_M_MASK; | |
309 | den *= 256; | |
310 | } | |
311 | ||
312 | clk->rate = (((clk->pclk->rate/10000) * num) / den) * 10000; | |
313 | spin_unlock_irqrestore(&clocks_lock, flags); | |
314 | } | |
315 | ||
316 | /* calculates current programmed rate of ahb or apb bus */ | |
317 | void bus_clk_recalc(struct clk *clk) | |
318 | { | |
319 | struct bus_clk_config *config = clk->private_data; | |
320 | unsigned int div; | |
321 | unsigned long flags; | |
322 | ||
323 | spin_lock_irqsave(&clocks_lock, flags); | |
324 | div = ((readl(config->reg) >> config->shift) & config->mask) + 1; | |
325 | clk->rate = (unsigned long)clk->pclk->rate / div; | |
326 | spin_unlock_irqrestore(&clocks_lock, flags); | |
327 | } | |
328 | ||
329 | /* | |
330 | * calculates current programmed rate of auxiliary synthesizers | |
331 | * used by: UART, FIRDA | |
332 | * | |
333 | * Fout from synthesizer can be given from two equations: | |
334 | * Fout1 = (Fin * X/Y)/2 | |
335 | * Fout2 = Fin * X/Y | |
336 | * | |
337 | * Selection of eqn 1 or 2 is programmed in register | |
338 | */ | |
339 | void aux_clk_recalc(struct clk *clk) | |
340 | { | |
341 | struct aux_clk_config *config = clk->private_data; | |
342 | struct pclk_info *pclk_info = NULL; | |
343 | unsigned int num = 1, den = 1, val, eqn; | |
344 | unsigned long flags; | |
345 | ||
346 | /* get current programmed parent */ | |
347 | pclk_info = pclk_info_get(clk); | |
348 | if (!pclk_info) { | |
349 | spin_lock_irqsave(&clocks_lock, flags); | |
350 | clk->pclk = NULL; | |
351 | clk->rate = 0; | |
352 | spin_unlock_irqrestore(&clocks_lock, flags); | |
353 | return; | |
354 | } | |
355 | ||
356 | change_parent(clk, pclk_info->pclk); | |
357 | ||
358 | spin_lock_irqsave(&clocks_lock, flags); | |
359 | if (pclk_info->scalable) { | |
360 | val = readl(config->synth_reg); | |
361 | ||
362 | eqn = (val >> AUX_EQ_SEL_SHIFT) & AUX_EQ_SEL_MASK; | |
363 | if (eqn == AUX_EQ1_SEL) | |
364 | den *= 2; | |
365 | ||
366 | /* calculate numerator */ | |
367 | num = (val >> AUX_XSCALE_SHIFT) & AUX_XSCALE_MASK; | |
368 | ||
369 | /* calculate denominator */ | |
370 | den *= (val >> AUX_YSCALE_SHIFT) & AUX_YSCALE_MASK; | |
371 | val = (((clk->pclk->rate/10000) * num) / den) * 10000; | |
372 | } else | |
373 | val = clk->pclk->rate; | |
374 | ||
375 | clk->rate = val; | |
376 | spin_unlock_irqrestore(&clocks_lock, flags); | |
377 | } | |
378 | ||
379 | /* | |
380 | * calculates current programmed rate of gpt synthesizers | |
381 | * Fout from synthesizer can be given from below equations: | |
382 | * Fout= Fin/((2 ^ (N+1)) * (M+1)) | |
383 | */ | |
384 | void gpt_clk_recalc(struct clk *clk) | |
385 | { | |
386 | struct aux_clk_config *config = clk->private_data; | |
387 | struct pclk_info *pclk_info = NULL; | |
388 | unsigned int div = 1, val; | |
389 | unsigned long flags; | |
390 | ||
391 | pclk_info = pclk_info_get(clk); | |
392 | if (!pclk_info) { | |
393 | spin_lock_irqsave(&clocks_lock, flags); | |
394 | clk->pclk = NULL; | |
395 | clk->rate = 0; | |
396 | spin_unlock_irqrestore(&clocks_lock, flags); | |
397 | return; | |
398 | } | |
399 | ||
400 | change_parent(clk, pclk_info->pclk); | |
401 | ||
402 | spin_lock_irqsave(&clocks_lock, flags); | |
403 | if (pclk_info->scalable) { | |
404 | val = readl(config->synth_reg); | |
405 | div += (val >> GPT_MSCALE_SHIFT) & GPT_MSCALE_MASK; | |
406 | div *= 1 << (((val >> GPT_NSCALE_SHIFT) & GPT_NSCALE_MASK) + 1); | |
407 | } | |
408 | ||
409 | clk->rate = (unsigned long)clk->pclk->rate / div; | |
410 | spin_unlock_irqrestore(&clocks_lock, flags); | |
411 | } | |
412 | ||
413 | /* | |
414 | * Used for clocks that always have same value as the parent clock divided by a | |
415 | * fixed divisor | |
416 | */ | |
417 | void follow_parent(struct clk *clk) | |
418 | { | |
419 | unsigned long flags; | |
420 | ||
421 | spin_lock_irqsave(&clocks_lock, flags); | |
422 | clk->rate = clk->pclk->rate; | |
423 | spin_unlock_irqrestore(&clocks_lock, flags); | |
424 | } | |
425 | ||
426 | /** | |
427 | * recalc_root_clocks - recalculate and propagate all root clocks | |
428 | * | |
429 | * Recalculates all root clocks (clocks with no parent), which if the | |
430 | * clock's .recalc is set correctly, should also propagate their rates. | |
431 | */ | |
432 | void recalc_root_clocks(void) | |
433 | { | |
434 | propagate_rate(&root_clks); | |
435 | } |