diff options
author | Davide Rizzo <davide@elpa.it> | 2008-04-12 15:08:15 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-04-19 14:04:30 +0100 |
commit | eb1f7d10d6b6728c87f79f30d1ae844d01d3486a (patch) | |
tree | 4a3dbdceea736fee36a869f554acd1e16039b6f5 | |
parent | 79b34afa68de4088081bcb7b4aed0fc4d8bf3618 (diff) |
[ARM] 4967/1: Adds functions to set clkout rate for Samsung S3C2410
This patch adds functions to set clkout rate for Samsung S3C2410
This patch supersedes 4884/1, that contained an error
Comments from Ben Dooks:
Note, looks like this needs to be applied before 4882/1
Signed-off-by: Davide Rizzo <davide@elpa.it>
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/plat-s3c24xx/clock.c | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/arch/arm/plat-s3c24xx/clock.c b/arch/arm/plat-s3c24xx/clock.c index 99a44746f8f..d84167fb33b 100644 --- a/arch/arm/plat-s3c24xx/clock.c +++ b/arch/arm/plat-s3c24xx/clock.c @@ -332,6 +332,58 @@ static int s3c24xx_dclk_setparent(struct clk *clk, struct clk *parent) return 0; } +static unsigned long s3c24xx_calc_div(struct clk *clk, unsigned long rate) +{ + unsigned long div; + + if ((rate == 0) || !clk->parent) + return 0; + + div = clk_get_rate(clk->parent) / rate; + if (div < 2) + div = 2; + else if (div > 16) + div = 16; + + return div; +} + +static unsigned long s3c24xx_round_dclk_rate(struct clk *clk, + unsigned long rate) +{ + unsigned long div = s3c24xx_calc_div(clk, rate); + + if (div == 0) + return 0; + + return clk_get_rate(clk->parent) / div; +} + +static int s3c24xx_set_dclk_rate(struct clk *clk, unsigned long rate) +{ + unsigned long mask, data, div = s3c24xx_calc_div(clk, rate); + + if (div == 0) + return -EINVAL; + + if (clk == &s3c24xx_dclk0) { + mask = S3C2410_DCLKCON_DCLK0_DIV_MASK | + S3C2410_DCLKCON_DCLK0_CMP_MASK; + data = S3C2410_DCLKCON_DCLK0_DIV(div) | + S3C2410_DCLKCON_DCLK0_CMP((div + 1) / 2); + } else if (clk == &s3c24xx_dclk1) { + mask = S3C2410_DCLKCON_DCLK1_DIV_MASK | + S3C2410_DCLKCON_DCLK1_CMP_MASK; + data = S3C2410_DCLKCON_DCLK1_DIV(div) | + S3C2410_DCLKCON_DCLK1_CMP((div + 1) / 2); + } else + return -EINVAL; + + clk->rate = clk_get_rate(clk->parent) / div; + __raw_writel(((__raw_readl(S3C24XX_DCLKCON) & ~mask) | data), + S3C24XX_DCLKCON); + return clk->rate; +} static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent) { @@ -378,6 +430,8 @@ struct clk s3c24xx_dclk0 = { .ctrlbit = S3C2410_DCLKCON_DCLK0EN, .enable = s3c24xx_dclk_enable, .set_parent = s3c24xx_dclk_setparent, + .set_rate = s3c24xx_set_dclk_rate, + .round_rate = s3c24xx_round_dclk_rate, }; struct clk s3c24xx_dclk1 = { @@ -386,6 +440,8 @@ struct clk s3c24xx_dclk1 = { .ctrlbit = S3C2410_DCLKCON_DCLK0EN, .enable = s3c24xx_dclk_enable, .set_parent = s3c24xx_dclk_setparent, + .set_rate = s3c24xx_set_dclk_rate, + .round_rate = s3c24xx_round_dclk_rate, }; struct clk s3c24xx_clkout0 = { |