aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBen Dooks <ben-linux@fluff.org>2006-02-08 16:09:05 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2006-02-08 16:09:05 -0500
commit2a513ce79958d47b72a11c76ec291c8c1169214c (patch)
tree2698cdc04f710d80da77ed36f6e3aad6d5e9fa57
parentf8e5b28413a8bf0b421dd116b30ab2d3befec629 (diff)
[ARM] 3303/1: S3C24XX - add clock enable usage counting
Patch from Ben Dooks Move to using an enable count for the shared clocks and protect the clock system using a mutex instead of just disabling IRQs during the clock update. Since there is little more code in the path for non-shared clocks, the enable and disable calls use the same code for each. Signed-off-by: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--arch/arm/mach-s3c2410/clock.c43
-rw-r--r--arch/arm/mach-s3c2410/clock.h1
2 files changed, 34 insertions, 10 deletions
diff --git a/arch/arm/mach-s3c2410/clock.c b/arch/arm/mach-s3c2410/clock.c
index af2f3d52b61b..08489efdaf06 100644
--- a/arch/arm/mach-s3c2410/clock.c
+++ b/arch/arm/mach-s3c2410/clock.c
@@ -40,7 +40,6 @@
40#include <linux/mutex.h> 40#include <linux/mutex.h>
41 41
42#include <asm/hardware.h> 42#include <asm/hardware.h>
43#include <asm/atomic.h>
44#include <asm/irq.h> 43#include <asm/irq.h>
45#include <asm/io.h> 44#include <asm/io.h>
46 45
@@ -59,22 +58,18 @@ static DEFINE_MUTEX(clocks_mutex);
59void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable) 58void inline s3c24xx_clk_enable(unsigned int clocks, unsigned int enable)
60{ 59{
61 unsigned long clkcon; 60 unsigned long clkcon;
62 unsigned long flags;
63
64 local_irq_save(flags);
65 61
66 clkcon = __raw_readl(S3C2410_CLKCON); 62 clkcon = __raw_readl(S3C2410_CLKCON);
67 clkcon &= ~clocks;
68 63
69 if (enable) 64 if (enable)
70 clkcon |= clocks; 65 clkcon |= clocks;
66 else
67 clkcon &= ~clocks;
71 68
72 /* ensure none of the special function bits set */ 69 /* ensure none of the special function bits set */
73 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER); 70 clkcon &= ~(S3C2410_CLKCON_IDLE|S3C2410_CLKCON_POWER);
74 71
75 __raw_writel(clkcon, S3C2410_CLKCON); 72 __raw_writel(clkcon, S3C2410_CLKCON);
76
77 local_irq_restore(flags);
78} 73}
79 74
80/* enable and disable calls for use with the clk struct */ 75/* enable and disable calls for use with the clk struct */
@@ -138,16 +133,32 @@ void clk_put(struct clk *clk)
138 133
139int clk_enable(struct clk *clk) 134int clk_enable(struct clk *clk)
140{ 135{
141 if (IS_ERR(clk)) 136 if (IS_ERR(clk) || clk == NULL)
142 return -EINVAL; 137 return -EINVAL;
143 138
144 return (clk->enable)(clk, 1); 139 clk_enable(clk->parent);
140
141 mutex_lock(&clocks_mutex);
142
143 if ((clk->usage++) == 0)
144 (clk->enable)(clk, 1);
145
146 mutex_unlock(&clocks_mutex);
147 return 0;
145} 148}
146 149
147void clk_disable(struct clk *clk) 150void clk_disable(struct clk *clk)
148{ 151{
149 if (!IS_ERR(clk)) 152 if (IS_ERR(clk) || clk == NULL)
153 return;
154
155 mutex_lock(&clocks_mutex);
156
157 if ((--clk->usage) == 0)
150 (clk->enable)(clk, 0); 158 (clk->enable)(clk, 0);
159
160 mutex_unlock(&clocks_mutex);
161 clk_disable(clk->parent);
151} 162}
152 163
153 164
@@ -361,6 +372,14 @@ int s3c24xx_register_clock(struct clk *clk)
361 if (clk->enable == NULL) 372 if (clk->enable == NULL)
362 clk->enable = clk_null_enable; 373 clk->enable = clk_null_enable;
363 374
375 /* if this is a standard clock, set the usage state */
376
377 if (clk->ctrlbit) {
378 unsigned long clkcon = __raw_readl(S3C2410_CLKCON);
379
380 clk->usage = (clkcon & clk->ctrlbit) ? 1 : 0;
381 }
382
364 /* add to the list of available clocks */ 383 /* add to the list of available clocks */
365 384
366 mutex_lock(&clocks_mutex); 385 mutex_lock(&clocks_mutex);
@@ -402,6 +421,8 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
402 * the LCD clock if it is not needed. 421 * the LCD clock if it is not needed.
403 */ 422 */
404 423
424 mutex_lock(&clocks_mutex);
425
405 s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0); 426 s3c24xx_clk_enable(S3C2410_CLKCON_NAND, 0);
406 s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0); 427 s3c24xx_clk_enable(S3C2410_CLKCON_USBH, 0);
407 s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0); 428 s3c24xx_clk_enable(S3C2410_CLKCON_USBD, 0);
@@ -409,6 +430,8 @@ int __init s3c24xx_setup_clocks(unsigned long xtal,
409 s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0); 430 s3c24xx_clk_enable(S3C2410_CLKCON_IIC, 0);
410 s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0); 431 s3c24xx_clk_enable(S3C2410_CLKCON_SPI, 0);
411 432
433 mutex_unlock(&clocks_mutex);
434
412 /* assume uart clocks are correctly setup */ 435 /* assume uart clocks are correctly setup */
413 436
414 /* register our clocks */ 437 /* register our clocks */
diff --git a/arch/arm/mach-s3c2410/clock.h b/arch/arm/mach-s3c2410/clock.h
index 177d5c8decf7..eb5c95d1e7f2 100644
--- a/arch/arm/mach-s3c2410/clock.h
+++ b/arch/arm/mach-s3c2410/clock.h
@@ -16,6 +16,7 @@ struct clk {
16 struct clk *parent; 16 struct clk *parent;
17 const char *name; 17 const char *name;
18 int id; 18 int id;
19 int usage;
19 unsigned long rate; 20 unsigned long rate;
20 unsigned long ctrlbit; 21 unsigned long ctrlbit;
21 int (*enable)(struct clk *, int enable); 22 int (*enable)(struct clk *, int enable);