]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/plat-s3c24xx/clock.c
Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jgarzi...
[linux-2.6-omap-h63xx.git] / arch / arm / plat-s3c24xx / clock.c
index 99a44746f8f27f89fb4943197a1d6b55b1a259c8..3ac8d8d781b3837f4ec47653e2b1ce4b98d25dfe 100644 (file)
@@ -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)
 {
@@ -359,7 +411,7 @@ static int s3c24xx_clkout_setparent(struct clk *clk, struct clk *parent)
 
        clk->parent = parent;
 
-       if (clk == &s3c24xx_dclk0)
+       if (clk == &s3c24xx_clkout0)
                mask = S3C2410_MISCCR_CLK0_MASK;
        else {
                source <<= 4;
@@ -378,14 +430,18 @@ 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 = {
        .name           = "dclk1",
        .id             = -1,
-       .ctrlbit        = S3C2410_DCLKCON_DCLK0EN,
+       .ctrlbit        = S3C2410_DCLKCON_DCLK1EN,
        .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 = {