From e2c977dca2901012ddabdc2a7b3c47a80c94d431 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Thu, 5 Mar 2009 11:43:14 +0800 Subject: [ARM] S3C6410: Add CAMIF clock Add camera interface clock to S3C6410. Signed-off-by: Werner Almesberger Signed-off-by: Ben Dooks --- arch/arm/plat-s3c64xx/s3c6400-clock.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) (limited to 'arch/arm/plat-s3c64xx/s3c6400-clock.c') diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 05b17528041..6dd187d0474 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c @@ -520,6 +520,33 @@ static struct clksrc_clk clk_irda = { .reg_divider = S3C_CLK_DIV2, }; +static struct clk *clkset_camif_list[] = { + &clk_h2, +}; + +static struct clk_sources clkset_camif = { + .sources = clkset_camif_list, + .nr_sources = ARRAY_SIZE(clkset_camif_list), +}; + +static struct clksrc_clk clk_camif = { + .clk = { + .name = "camera", + .id = -1, + .ctrlbit = S3C_CLKCON_SCLK_CAM, + .enable = s3c64xx_sclk_ctrl, + .set_parent = s3c64xx_setparent_clksrc, + .get_rate = s3c64xx_getrate_clksrc, + .set_rate = s3c64xx_setrate_clksrc, + .round_rate = s3c64xx_roundrate_clksrc, + }, + .shift = 0, + .mask = 0, + .sources = &clkset_camif, + .divider_shift = S3C6400_CLKDIV0_CAM_SHIFT, + .reg_divider = S3C_CLK_DIV0, +}; + /* Clock initialisation code */ static struct clksrc_clk *init_parents[] = { @@ -536,6 +563,7 @@ static struct clksrc_clk *init_parents[] = { &clk_audio0, &clk_audio1, &clk_irda, + &clk_camif, }; static void __init_or_cpufreq s3c6400_set_clksrc(struct clksrc_clk *clk) @@ -635,6 +663,7 @@ static struct clk *clks[] __initdata = { &clk_audio0.clk, &clk_audio1.clk, &clk_irda.clk, + &clk_camif.clk, }; void __init s3c6400_register_clocks(void) -- cgit v1.2.3-70-g09d2 From a03f7daf6df31b4d849031c51a3c10b8ba78ce67 Mon Sep 17 00:00:00 2001 From: Werner Almesberger Date: Thu, 5 Mar 2009 11:43:13 +0800 Subject: [ARM] S3C64XX: Add HCLKx2 Add doubled HCLK to S3C64xx. Signed-off-by: Werner Almesberger Signed-off-by: Ben Dooks --- arch/arm/plat-s3c/include/plat/clock.h | 1 + arch/arm/plat-s3c64xx/clock.c | 7 +++++++ arch/arm/plat-s3c64xx/s3c6400-clock.c | 1 + 3 files changed, 9 insertions(+) (limited to 'arch/arm/plat-s3c64xx/s3c6400-clock.c') diff --git a/arch/arm/plat-s3c/include/plat/clock.h b/arch/arm/plat-s3c/include/plat/clock.h index a10622eed43..d86af84b5b8 100644 --- a/arch/arm/plat-s3c/include/plat/clock.h +++ b/arch/arm/plat-s3c/include/plat/clock.h @@ -50,6 +50,7 @@ extern struct clk clk_xtal; extern struct clk clk_ext; /* S3C64XX specific clocks */ +extern struct clk clk_h2; extern struct clk clk_27m; extern struct clk clk_48m; diff --git a/arch/arm/plat-s3c64xx/clock.c b/arch/arm/plat-s3c64xx/clock.c index ad1b9682c9c..679076f5071 100644 --- a/arch/arm/plat-s3c64xx/clock.c +++ b/arch/arm/plat-s3c64xx/clock.c @@ -27,6 +27,12 @@ #include #include +struct clk clk_h2 = { + .name = "hclk2", + .id = -1, + .rate = 0, +}; + struct clk clk_27m = { .name = "clk_27m", .id = -1, @@ -246,6 +252,7 @@ static struct clk *clks[] __initdata = { &clk_epll, &clk_27m, &clk_48m, + &clk_h2, }; void __init s3c64xx_register_clocks(void) diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 6dd187d0474..96fa9ea4d5b 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c @@ -636,6 +636,7 @@ void __init_or_cpufreq s3c6400_setup_clocks(void) clk_fout_epll.rate = epll; clk_fout_apll.rate = apll; + clk_h2.rate = hclk2; clk_h.rate = hclk; clk_p.rate = pclk; clk_f.rate = fclk; -- cgit v1.2.3-70-g09d2 From 496a3f0927197ca155a604478bf6e7db3eca3bbd Mon Sep 17 00:00:00 2001 From: Ben Dooks Date: Sat, 2 May 2009 13:48:53 +0100 Subject: [ARM] S3C64XX: Add ARM clock Add ARM clock to provide 'arm' from the APLL to the ARM core. Signed-off-by: Ben Dooks --- arch/arm/mach-s3c6400/s3c6400.c | 3 +- arch/arm/mach-s3c6410/cpu.c | 3 +- arch/arm/plat-s3c64xx/include/plat/s3c6400.h | 2 +- arch/arm/plat-s3c64xx/s3c6400-clock.c | 76 +++++++++++++++++++++++++++- 4 files changed, 80 insertions(+), 4 deletions(-) (limited to 'arch/arm/plat-s3c64xx/s3c6400-clock.c') diff --git a/arch/arm/mach-s3c6400/s3c6400.c b/arch/arm/mach-s3c6400/s3c6400.c index bd17f3db2c2..1ece887d90b 100644 --- a/arch/arm/mach-s3c6400/s3c6400.c +++ b/arch/arm/mach-s3c6400/s3c6400.c @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -54,7 +55,7 @@ void __init s3c6400_init_clocks(int xtal) printk(KERN_DEBUG "%s: initialising clocks\n", __func__); s3c24xx_register_baseclocks(xtal); s3c64xx_register_clocks(); - s3c6400_register_clocks(); + s3c6400_register_clocks(S3C6400_CLKDIV0_ARM_MASK); s3c6400_setup_clocks(); } diff --git a/arch/arm/mach-s3c6410/cpu.c b/arch/arm/mach-s3c6410/cpu.c index 6a73ca6b7a3..ade904de889 100644 --- a/arch/arm/mach-s3c6410/cpu.c +++ b/arch/arm/mach-s3c6410/cpu.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -68,7 +69,7 @@ void __init s3c6410_init_clocks(int xtal) printk(KERN_DEBUG "%s: initialising clocks\n", __func__); s3c24xx_register_baseclocks(xtal); s3c64xx_register_clocks(); - s3c6400_register_clocks(); + s3c6400_register_clocks(S3C6410_CLKDIV0_ARM_MASK); s3c6400_setup_clocks(); } diff --git a/arch/arm/plat-s3c64xx/include/plat/s3c6400.h b/arch/arm/plat-s3c64xx/include/plat/s3c6400.h index e12296666d4..11f2e1e119b 100644 --- a/arch/arm/plat-s3c64xx/include/plat/s3c6400.h +++ b/arch/arm/plat-s3c64xx/include/plat/s3c6400.h @@ -15,7 +15,7 @@ /* Common init code for S3C6400 related SoCs */ extern void s3c6400_common_init_uarts(struct s3c2410_uartcfg *cfg, int no); -extern void s3c6400_register_clocks(void); +extern void s3c6400_register_clocks(unsigned armclk_divlimit); extern void s3c6400_setup_clocks(void); #ifdef CONFIG_CPU_S3C6400 diff --git a/arch/arm/plat-s3c64xx/s3c6400-clock.c b/arch/arm/plat-s3c64xx/s3c6400-clock.c index 96fa9ea4d5b..1debc1f9f98 100644 --- a/arch/arm/plat-s3c64xx/s3c6400-clock.c +++ b/arch/arm/plat-s3c64xx/s3c6400-clock.c @@ -133,6 +133,65 @@ static struct clksrc_clk clk_mout_mpll = { .sources = &clk_src_mpll, }; +static unsigned int armclk_mask; + +static unsigned long s3c64xx_clk_arm_get_rate(struct clk *clk) +{ + unsigned long rate = clk_get_rate(clk->parent); + u32 clkdiv; + + /* divisor mask starts at bit0, so no need to shift */ + clkdiv = __raw_readl(S3C_CLK_DIV0) & armclk_mask; + + return rate / (clkdiv + 1); +} + +static unsigned long s3c64xx_clk_arm_round_rate(struct clk *clk, + unsigned long rate) +{ + unsigned long parent = clk_get_rate(clk->parent); + u32 div; + + if (parent < rate) + return rate; + + div = (parent / rate) - 1; + if (div > armclk_mask) + div = armclk_mask; + + return parent / (div + 1); +} + +static int s3c64xx_clk_arm_set_rate(struct clk *clk, unsigned long rate) +{ + unsigned long parent = clk_get_rate(clk->parent); + u32 div; + u32 val; + + if (rate < parent / (armclk_mask + 1)) + return -EINVAL; + + rate = clk_round_rate(clk, rate); + div = clk_get_rate(clk->parent) / rate; + + val = __raw_readl(S3C_CLK_DIV0); + val &= armclk_mask; + val |= (div - 1); + __raw_writel(val, S3C_CLK_DIV0); + + return 0; + +} + +static struct clk clk_arm = { + .name = "armclk", + .id = -1, + .parent = &clk_mout_apll.clk, + .get_rate = s3c64xx_clk_arm_get_rate, + .set_rate = s3c64xx_clk_arm_set_rate, + .round_rate = s3c64xx_clk_arm_round_rate, +}; + static unsigned long s3c64xx_clk_doutmpll_get_rate(struct clk *clk) { unsigned long rate = clk_get_rate(clk->parent); @@ -665,14 +724,29 @@ static struct clk *clks[] __initdata = { &clk_audio1.clk, &clk_irda.clk, &clk_camif.clk, + &clk_arm, }; -void __init s3c6400_register_clocks(void) +/** + * s3c6400_register_clocks - register clocks for s3c6400 and above + * @armclk_divlimit: Divisor mask for ARMCLK + * + * Register the clocks for the S3C6400 and above SoC range, such + * as ARMCLK and the clocks which have divider chains attached. + * + * This call does not setup the clocks, which is left to the + * s3c6400_setup_clocks() call which may be needed by the cpufreq + * or resume code to re-set the clocks if the bootloader has changed + * them. + */ +void __init s3c6400_register_clocks(unsigned armclk_divlimit) { struct clk *clkp; int ret; int ptr; + armclk_mask = armclk_divlimit; + for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) { clkp = clks[ptr]; ret = s3c24xx_register_clock(clkp); -- cgit v1.2.3-70-g09d2