aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2009-03-04 07:38:05 +0000
committerAndy Green <agreen@octopus.localdomain>2009-03-04 07:38:05 +0000
commit7bd2f3cb193aefee782eb5faf5c4dcb0a782ef14 (patch)
tree575de98ed2269fbbed9b90c18e52793265e8c311 /arch
parent830ed8523da5f82235e4bead282f0d4cd595e449 (diff)
S3C64XX: Add initial support for ARMCLK
Add support for reconfiguring the clock for the ARM core, enabling CPUfreq support. Currently only the divider for ARMCLK may be changed, ARMPLL is left static. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/plat-s3c64xx/s3c6400-clock.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c
index a6f6b91b732..2dc67331c89 100644
--- a/arch/arm/plat-s3c64xx/s3c6400-clock.c
+++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c
@@ -24,6 +24,7 @@
#include <mach/hardware.h>
#include <mach/map.h>
+#include <mach/cpu.h>
#include <plat/cpu-freq.h>
@@ -88,6 +89,80 @@ struct clksrc_clk clk_mout_apll = {
.sources = &clk_src_apll,
};
+static u32 clk_arm_div_mask(void)
+{
+ if (cpu_is_s3c6400())
+ return S3C6400_CLKDIV0_ARM_MASK;
+
+ if (cpu_is_s3c6410())
+ return S3C6410_CLKDIV0_ARM_MASK;
+
+ return 0;
+}
+
+static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk)
+{
+ unsigned long rate = clk_get_rate(clk->parent);
+ u32 val;
+
+ val = __raw_readl(S3C_CLK_DIV0);
+ val &= clk_arm_div_mask();
+
+ return rate / (val + 1);
+}
+
+static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk,
+ unsigned long rate)
+{
+ unsigned long parent = clk_get_rate(clk->parent);
+ int div;
+ int max = clk_arm_div_mask() + 1;
+
+ if (parent < rate)
+ return parent;
+
+ div = parent / rate;
+
+ if (div < 1)
+ div = 1;
+ if (div > max)
+ div = max;
+
+ return parent / div;
+}
+
+static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned int div;
+ u32 val;
+ unsigned long flags;
+
+ rate = clk_round_rate(clk, rate);
+ div = (clk_get_rate(clk->parent) / rate) - 1;
+
+ if (div > clk_arm_div_mask())
+ return -EINVAL;
+
+ val = __raw_readl(S3C_CLK_DIV0);
+ val &= ~clk_arm_div_mask();
+ val |= div;
+
+ local_irq_save(flags);
+ __raw_writel(val, S3C_CLK_DIV0);
+ local_irq_restore(flags);
+
+ return 0;
+}
+
+static struct clk clk_arm = {
+ .name = "armclk",
+ .id = -1,
+ .parent = &clk_mout_apll.clk,
+ .round_rate = &s3c64xx_clk_arm_round_rate,
+ .get_rate = s3c64xx_clk_arm_get_rate,
+ .set_rate = s3c64xx_clk_arm_set_rate,
+};
+
struct clk clk_fout_epll = {
.name = "fout_epll",
.id = -1,
@@ -633,6 +708,7 @@ static struct clk *clks[] __initdata = {
&clk_audio0.clk,
&clk_audio1.clk,
&clk_irda.clk,
+ &clk_arm,
};
void __init s3c6400_register_clocks(void)