aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-s3c2410/clock.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-s3c2410/clock.c')
-rw-r--r--arch/arm/mach-s3c2410/clock.c178
1 files changed, 174 insertions, 4 deletions
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index 08489efdaf06..fec02c92f95f 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -38,12 +38,14 @@
38#include <linux/ioport.h> 38#include <linux/ioport.h>
39#include <linux/clk.h> 39#include <linux/clk.h>
40#include <linux/mutex.h> 40#include <linux/mutex.h>
41#include <linux/delay.h>
41 42
42#include <asm/hardware.h> 43#include <asm/hardware.h>
43#include <asm/irq.h> 44#include <asm/irq.h>
44#include <asm/io.h> 45#include <asm/io.h>
45 46
46#include <asm/arch/regs-clock.h> 47#include <asm/arch/regs-clock.h>
48#include <asm/arch/regs-gpio.h>
47 49
48#include "clock.h" 50#include "clock.h"
49#include "cpu.h" 51#include "cpu.h"
@@ -51,7 +53,8 @@
51/* clock information */ 53/* clock information */
52 54
53static LIST_HEAD(clocks); 55static LIST_HEAD(clocks);
54static DEFINE_MUTEX(clocks_mutex); 56
57DEFINE_MUTEX(clocks_mutex);
55 58
56/* old functions */ 59/* old functions */
57 60
@@ -178,12 +181,24 @@ unsigned long clk_get_rate(struct clk *clk)
178 181
179long clk_round_rate(struct clk *clk, unsigned long rate) 182long clk_round_rate(struct clk *clk, unsigned long rate)
180{ 183{
184 if (!IS_ERR(clk) && clk->round_rate)
185 return (clk->round_rate)(clk, rate);
186
181 return rate; 187 return rate;
182} 188}
183 189
184int clk_set_rate(struct clk *clk, unsigned long rate) 190int clk_set_rate(struct clk *clk, unsigned long rate)
185{ 191{
186 return -EINVAL; 192 int ret;
193
194 if (IS_ERR(clk))
195 return -EINVAL;
196
197 mutex_lock(&clocks_mutex);
198 ret = (clk->set_rate)(clk, rate);
199 mutex_unlock(&clocks_mutex);
200
201 return ret;
187} 202}
188 203
189struct clk *clk_get_parent(struct clk *clk) 204struct clk *clk_get_parent(struct clk *clk)
@@ -191,6 +206,23 @@ struct clk *clk_get_parent(struct clk *clk)
191 return clk->parent; 206 return clk->parent;
192} 207}
193 208
209int clk_set_parent(struct clk *clk, struct clk *parent)
210{
211 int ret = 0;
212
213 if (IS_ERR(clk))
214 return -EINVAL;
215
216 mutex_lock(&clocks_mutex);
217
218 if (clk->set_parent)
219 ret = (clk->set_parent)(clk, parent);
220
221 mutex_unlock(&clocks_mutex);
222
223 return ret;
224}
225
194EXPORT_SYMBOL(clk_get); 226EXPORT_SYMBOL(clk_get);
195EXPORT_SYMBOL(clk_put); 227EXPORT_SYMBOL(clk_put);
196EXPORT_SYMBOL(clk_enable); 228EXPORT_SYMBOL(clk_enable);
@@ -199,6 +231,29 @@ EXPORT_SYMBOL(clk_get_rate);
199EXPORT_SYMBOL(clk_round_rate); 231EXPORT_SYMBOL(clk_round_rate);
200EXPORT_SYMBOL(clk_set_rate); 232EXPORT_SYMBOL(clk_set_rate);
201EXPORT_SYMBOL(clk_get_parent); 233EXPORT_SYMBOL(clk_get_parent);
234EXPORT_SYMBOL(clk_set_parent);
235
236/* base clock enable */
237
238static int s3c24xx_upll_enable(struct clk *clk, int enable)
239{
240 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
241 unsigned long orig = clkslow;
242
243 if (enable)
244 clkslow &= ~S3C2410_CLKSLOW_UCLK_OFF;
245 else
246 clkslow |= S3C2410_CLKSLOW_UCLK_OFF;
247
248 __raw_writel(clkslow, S3C2410_CLKSLOW);
249
250 /* if we started the UPLL, then allow to settle */
251
252 if (enable && !(orig & S3C2410_CLKSLOW_UCLK_OFF))
253 udelay(200);
254
255 return 0;
256}
202 257
203/* base clocks */ 258/* base clocks */
204 259
@@ -210,6 +265,14 @@ static struct clk clk_xtal = {
210 .ctrlbit = 0, 265 .ctrlbit = 0,
211}; 266};
212 267
268static struct clk clk_upll = {
269 .name = "upll",
270 .id = -1,
271 .parent = NULL,
272 .enable = s3c24xx_upll_enable,
273 .ctrlbit = 0,
274};
275
213static struct clk clk_f = { 276static struct clk clk_f = {
214 .name = "fclk", 277 .name = "fclk",
215 .id = -1, 278 .id = -1,
@@ -234,26 +297,124 @@ static struct clk clk_p = {
234 .ctrlbit = 0, 297 .ctrlbit = 0,
235}; 298};
236 299
300struct clk clk_usb_bus = {
301 .name = "usb-bus",
302 .id = -1,
303 .rate = 0,
304 .parent = &clk_upll,
305};
306
237/* clocks that could be registered by external code */ 307/* clocks that could be registered by external code */
238 308
309static int s3c24xx_dclk_enable(struct clk *clk, int enable)
310{
311 unsigned long dclkcon = __raw_readl(S3C2410_DCLKCON);
312
313 if (enable)
314 dclkcon |= clk->ctrlbit;
315 else
316 dclkcon &= ~clk->ctrlbit;
317
318 __raw_writel(dclkcon, S3C2410_DCLKCON);
319
320 return 0;
321}
322
323static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent)
324{
325 unsigned long dclkcon;
326 unsigned int uclk;
327
328 if (parent == &clk_upll)
329 uclk = 1;
330 else if (parent == &clk_p)
331 uclk = 0;
332 else
333 return -EINVAL;
334
335 clk->parent = parent;
336
337 dclkcon = __raw_readl(S3C2410_DCLKCON);
338
339 if (clk->ctrlbit == S3C2410_DCLKCON_DCLK0EN) {
340 if (uclk)
341 dclkcon |= S3C2410_DCLKCON_DCLK0_UCLK;
342 else
343 dclkcon &= ~S3C2410_DCLKCON_DCLK0_UCLK;
344 } else {
345 if (uclk)
346 dclkcon |= S3C2410_DCLKCON_DCLK1_UCLK;
347 else
348 dclkcon &= ~S3C2410_DCLKCON_DCLK1_UCLK;
349 }
350
351 __raw_writel(dclkcon, S3C2410_DCLKCON);
352
353 return 0;
354}
355
356
357static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
358{
359 unsigned long mask;
360 unsigned long source;
361
362 /* calculate the MISCCR setting for the clock */
363
364 if (parent == &clk_xtal)
365 source = S3C2410_MISCCR_CLK0_MPLL;
366 else if (parent == &clk_upll)
367 source = S3C2410_MISCCR_CLK0_UPLL;
368 else if (parent == &clk_f)
369 source = S3C2410_MISCCR_CLK0_FCLK;
370 else if (parent == &clk_p)
371 source = S3C2410_MISCCR_CLK0_PCLK;
372 else if (clk == &s3c24xx_clkout0 && parent == &s3c24xx_dclk0)
373 source = S3C2410_MISCCR_CLK0_DCLK0;
374 else if (clk == &s3c24xx_clkout1 && parent == &s3c24xx_dclk1)
375 source = S3C2410_MISCCR_CLK0_DCLK0;
376 else
377 return -EINVAL;
378
379 if (clk == &s3c24xx_dclk0)
380 mask = S3C2410_MISCCR_CLK0_MASK;
381 else {
382 source <<= 4;
383 mask = S3C2410_MISCCR_CLK1_MASK;
384 }
385
386 s3c2410_modify_misccr(mask, source);
387 return 0;
388}
389
390/* external clock definitions */
391
239struct clk s3c24xx_dclk0 = { 392struct clk s3c24xx_dclk0 = {
240 .name = "dclk0", 393 .name = "dclk0",
241 .id = -1, 394 .id = -1,
395 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
396 .enable = s3c24xx_dclk_enable,
397 .set_parent = s3c24xx_dclk_setparent,
242}; 398};
243 399
244struct clk s3c24xx_dclk1 = { 400struct clk s3c24xx_dclk1 = {
245 .name = "dclk1", 401 .name = "dclk1",
246 .id = -1, 402 .id = -1,
403 .ctrlbit = S3C2410_DCLKCON_DCLK0EN,
404 .enable = s3c24xx_dclk_enable,
405 .set_parent = s3c24xx_dclk_setparent,
247}; 406};
248 407
249struct clk s3c24xx_clkout0 = { 408struct clk s3c24xx_clkout0 = {
250 .name = "clkout0", 409 .name = "clkout0",
251 .id = -1, 410 .id = -1,
411 .set_parent = s3c24xx_clkout_setparent,
252}; 412};
253 413
254struct clk s3c24xx_clkout1 = { 414struct clk s3c24xx_clkout1 = {
255 .name = "clkout1", 415 .name = "clkout1",
256 .id = -1, 416 .id = -1,
417 .set_parent = s3c24xx_clkout_setparent,
257}; 418};
258 419
259struct clk s3c24xx_uclk = { 420struct clk s3c24xx_uclk = {
@@ -262,7 +423,7 @@ struct clk s3c24xx_uclk = {
262}; 423};
263 424
264 425
265/* clock definitions */ 426/* standard clock definitions */
266 427
267static struct clk init_clocks[] = { 428static struct clk init_clocks[] = {
268 { 429 {
@@ -374,7 +535,7 @@ int s3c24xx_register_clock(struct clk *clk)
374 535
375 /* if this is a standard clock, set the usage state */ 536 /* if this is a standard clock, set the usage state */
376 537
377 if (clk->ctrlbit) { 538 if (clk->ctrlbit && clk->enable == s3c24xx_clkcon_enable) {
378 unsigned long clkcon = __raw_readl(S3C2410_CLKCON); 539 unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
379 540
380 clk->usage = (clkcon & clk->ctrlbit) ? 1 : 0; 541 clk->usage = (clkcon & clk->ctrlbit) ? 1 : 0;
@@ -396,6 +557,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
396 unsigned long hclk, 557 unsigned long hclk,
397 unsigned long pclk) 558 unsigned long pclk)
398{ 559{
560 unsigned long upllcon = __raw_readl(S3C2410_UPLLCON);
399 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW); 561 unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
400 struct clk *clkp = init_clocks; 562 struct clk *clkp = init_clocks;
401 int ptr; 563 int ptr;
@@ -406,6 +568,7 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
406 /* initialise the main system clocks */ 568 /* initialise the main system clocks */
407 569
408 clk_xtal.rate = xtal; 570 clk_xtal.rate = xtal;
571 clk_upll.rate = s3c2410_get_pll(upllcon, xtal);
409 572
410 clk_h.rate = hclk; 573 clk_h.rate = hclk;
411 clk_p.rate = pclk; 574 clk_p.rate = pclk;
@@ -439,6 +602,9 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
439 if (s3c24xx_register_clock(&clk_xtal) < 0) 602 if (s3c24xx_register_clock(&clk_xtal) < 0)
440 printk(KERN_ERR "failed to register master xtal\n"); 603 printk(KERN_ERR "failed to register master xtal\n");
441 604
605 if (s3c24xx_register_clock(&clk_upll) < 0)
606 printk(KERN_ERR "failed to register upll clock\n");
607
442 if (s3c24xx_register_clock(&clk_f) < 0) 608 if (s3c24xx_register_clock(&clk_f) < 0)
443 printk(KERN_ERR "failed to register cpu fclk\n"); 609 printk(KERN_ERR "failed to register cpu fclk\n");
444 610
@@ -448,6 +614,10 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
448 if (s3c24xx_register_clock(&clk_p) < 0) 614 if (s3c24xx_register_clock(&clk_p) < 0)
449 printk(KERN_ERR "failed to register cpu pclk\n"); 615 printk(KERN_ERR "failed to register cpu pclk\n");
450 616
617
618 if (s3c24xx_register_clock(&clk_usb_bus) < 0)
619 printk(KERN_ERR "failed to register usb bus clock\n");
620
451 /* register clocks from clock array */ 621 /* register clocks from clock array */
452 622
453 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) { 623 for (ptr = 0; ptr < ARRAY_SIZE(init_clocks); ptr++, clkp++) {