- Update to 2.6.25-rc3.
[linux-flexiantxendom0-3.2.10.git] / arch / arm / mach-s3c2412 / clock.c
index 4589936..2697a65 100644 (file)
@@ -217,7 +217,7 @@ static int s3c2412_setparent_msysclk(struct clk *clk, struct clk *parent)
 
        if (parent == &clk_mdivclk)
                clksrc &= ~S3C2412_CLKSRC_MSYSCLK_MPLL;
-       else if (parent == &clk_upll)
+       else if (parent == &clk_mpll)
                clksrc |= S3C2412_CLKSRC_MSYSCLK_MPLL;
        else
                return -EINVAL;
@@ -234,6 +234,45 @@ static struct clk clk_msysclk = {
        .set_parent     = s3c2412_setparent_msysclk,
 };
 
+static int s3c2412_setparent_armclk(struct clk *clk, struct clk *parent)
+{
+       unsigned long flags;
+       unsigned long clkdiv;
+       unsigned long dvs;
+
+       /* Note, we current equate fclk andf msysclk for S3C2412 */
+
+       if (parent == &clk_msysclk || parent == &clk_f)
+               dvs = 0;
+       else if (parent == &clk_h)
+               dvs = S3C2412_CLKDIVN_DVSEN;
+       else
+               return -EINVAL;
+
+       clk->parent = parent;
+
+       /* update this under irq lockdown, clkdivn is not protected
+        * by the clock system. */
+
+       local_irq_save(flags);
+
+       clkdiv  = __raw_readl(S3C2410_CLKDIVN);
+       clkdiv &= ~S3C2412_CLKDIVN_DVSEN;
+       clkdiv |= dvs;
+       __raw_writel(clkdiv, S3C2410_CLKDIVN);
+
+       local_irq_restore(flags);
+
+       return 0;
+}
+
+static struct clk clk_armclk = {
+       .name           = "armclk",
+       .id             = -1,
+       .parent         = &clk_msysclk,
+       .set_parent     = s3c2412_setparent_armclk,
+};
+
 /* these next clocks have an divider immediately after them,
  * so we can register them with their divider and leave out the
  * intermediate clock stage
@@ -630,11 +669,13 @@ static struct clk *clks[] __initdata = {
        &clk_erefclk,
        &clk_urefclk,
        &clk_mrefclk,
+       &clk_armclk,
 };
 
 int __init s3c2412_baseclk_add(void)
 {
        unsigned long clkcon  = __raw_readl(S3C2410_CLKCON);
+       unsigned int dvs;
        struct clk *clkp;
        int ret;
        int ptr;
@@ -643,6 +684,8 @@ int __init s3c2412_baseclk_add(void)
        clk_usb_bus.parent = &clk_usbsrc;
        clk_usb_bus.rate = 0x0;
 
+       clk_f.parent = &clk_msysclk;
+
        s3c2412_clk_initparents();
 
        for (ptr = 0; ptr < ARRAY_SIZE(clks); ptr++) {
@@ -655,6 +698,15 @@ int __init s3c2412_baseclk_add(void)
                }
        }
 
+       /* set the dvs state according to what we got at boot time */
+
+       dvs = __raw_readl(S3C2410_CLKDIVN) & S3C2412_CLKDIVN_DVSEN;
+
+       if (dvs)
+               clk_armclk.parent = &clk_h;
+
+       printk(KERN_INFO "S3C2412: DVS is %s\n", dvs ? "on" : "off");
+
        /* ensure usb bus clock is within correct rate of 48MHz */
 
        if (clk_get_rate(&clk_usb_bus) != (48 * 1000 * 1000)) {