]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/plat-s3c24xx/clock.c
Merge branch 'core/locking' into core/urgent
[linux-2.6-omap-h63xx.git] / arch / arm / plat-s3c24xx / clock.c
index 99a44746f8f27f89fb4943197a1d6b55b1a259c8..54d4b8e2263cb9ab3e35dc0c5b696f2ae925d97f 100644 (file)
 #include <linux/mutex.h>
 #include <linux/delay.h>
 
-#include <asm/hardware.h>
+#include <mach/hardware.h>
 #include <asm/irq.h>
 #include <asm/io.h>
 
-#include <asm/arch/regs-clock.h>
-#include <asm/arch/regs-gpio.h>
+#include <mach/regs-clock.h>
+#include <mach/regs-gpio.h>
 
 #include <asm/plat-s3c24xx/clock.h>
 #include <asm/plat-s3c24xx/cpu.h>
@@ -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 = {