sh: remove old sh_mobile mstpc clocks
[safe/jmp/linux-2.6] / arch / sh / kernel / cpu / sh4a / clock-sh7722.c
index a0fd8bb..83b6919 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * arch/sh/kernel/cpu/sh4a/clock-sh7722.c
  *
- * SH7722 support for the clock framework
+ * SH7343, SH7722, SH7723 & SH7366 support for the clock framework
  *
  * Copyright (c) 2006-2007 Nomad Global Solutions Inc
  * Based on code for sh7343 by Paul Mundt
@@ -14,6 +14,7 @@
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/errno.h>
+#include <linux/stringify.h>
 #include <asm/clock.h>
 #include <asm/freq.h>
 
@@ -228,7 +229,7 @@ struct frqcr_context sh7722_get_clk_context(const char *name)
 }
 
 /**
- * sh7722_find_divisors - find divisor for setting rate
+ * sh7722_find_div_index - find divisor for setting rate
  *
  * All sh7722 clocks use the same set of multipliers/divisors. This function
  * chooses correct divisor to set the rate of clock with parent clock that
@@ -237,7 +238,7 @@ struct frqcr_context sh7722_get_clk_context(const char *name)
  * @parent_rate: rate of parent clock
  * @rate: requested rate to be set
  */
-static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate)
+static int sh7722_find_div_index(unsigned long parent_rate, unsigned rate)
 {
        unsigned div2 = parent_rate * 2 / rate;
        int index;
@@ -246,12 +247,12 @@ static int sh7722_find_divisors(unsigned long parent_rate, unsigned rate)
                return -EINVAL;
 
        for (index = 1; index < ARRAY_SIZE(divisors2); index++) {
-               if (div2 > divisors2[index] && div2 <= divisors2[index])
+               if (div2 > divisors2[index - 1] && div2 <= divisors2[index])
                        break;
        }
        if (index >= ARRAY_SIZE(divisors2))
                index = ARRAY_SIZE(divisors2) - 1;
-       return divisors2[index];
+       return index;
 }
 
 static void sh7722_frqcr_recalc(struct clk *clk)
@@ -278,12 +279,12 @@ static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
                return -EINVAL;
 
        /* look for multiplier/divisor pair */
-       div = sh7722_find_divisors(parent_rate, rate);
+       div = sh7722_find_div_index(parent_rate, rate);
        if (div<0)
                return div;
 
        /* calculate new value of clock rate */
-       clk->rate = parent_rate * 2 / div;
+       clk->rate = parent_rate * 2 / divisors2[div];
        frqcr = ctrl_inl(FRQCR);
 
        /* FIXME: adjust as algo_id specifies */
@@ -352,7 +353,7 @@ static int sh7722_frqcr_set_rate(struct clk *clk, unsigned long rate,
                        int part_div;
 
                        if (likely(!err)) {
-                               part_div = sh7722_find_divisors(parent_rate,
+                               part_div = sh7722_find_div_index(parent_rate,
                                                                rate);
                                if (part_div > 0) {
                                        part_ctx = sh7722_get_clk_context(
@@ -393,12 +394,12 @@ static long sh7722_frqcr_round_rate(struct clk *clk, unsigned long rate)
        int div;
 
        /* look for multiplier/divisor pair */
-       div = sh7722_find_divisors(parent_rate, rate);
+       div = sh7722_find_div_index(parent_rate, rate);
        if (div < 0)
                return clk->rate;
 
        /* calculate new value of clock rate */
-       return parent_rate * 2 / div;
+       return parent_rate * 2 / divisors2[div];
 }
 
 static struct clk_ops sh7722_frqcr_clk_ops = {
@@ -411,36 +412,40 @@ static struct clk_ops sh7722_frqcr_clk_ops = {
  * clock ops methods for SIU A/B and IrDA clock
  *
  */
-static int sh7722_siu_which(struct clk *clk)
+
+#ifndef CONFIG_CPU_SUBTYPE_SH7343
+
+static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
 {
-       if (!strcmp(clk->name, "siu_a_clk"))
-               return 0;
-       if (!strcmp(clk->name, "siu_b_clk"))
-               return 1;
-       if (!strcmp(clk->name, "irda_clk"))
-               return 2;
-       return -EINVAL;
+       unsigned long r;
+       int div;
+
+       r = ctrl_inl(clk->arch_flags);
+       div = sh7722_find_div_index(clk->parent->rate, rate);
+       if (div < 0)
+               return div;
+       r = (r & ~0xF) | div;
+       ctrl_outl(r, clk->arch_flags);
+       return 0;
 }
 
-static unsigned long sh7722_siu_regs[] = {
-       [0] = SCLKACR,
-       [1] = SCLKBCR,
-       [2] = IrDACLKCR,
-};
+static void sh7722_siu_recalc(struct clk *clk)
+{
+       unsigned long r;
+
+       r = ctrl_inl(clk->arch_flags);
+       clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
+}
 
 static int sh7722_siu_start_stop(struct clk *clk, int enable)
 {
-       int siu = sh7722_siu_which(clk);
        unsigned long r;
 
-       if (siu < 0)
-               return siu;
-       BUG_ON(siu > 2);
-       r = ctrl_inl(sh7722_siu_regs[siu]);
+       r = ctrl_inl(clk->arch_flags);
        if (enable)
-               ctrl_outl(r & ~(1 << 8), sh7722_siu_regs[siu]);
+               ctrl_outl(r & ~(1 << 8), clk->arch_flags);
        else
-               ctrl_outl(r | (1 << 8), sh7722_siu_regs[siu]);
+               ctrl_outl(r | (1 << 8), clk->arch_flags);
        return 0;
 }
 
@@ -454,6 +459,15 @@ static void sh7722_siu_disable(struct clk *clk)
        sh7722_siu_start_stop(clk, 0);
 }
 
+static struct clk_ops sh7722_siu_clk_ops = {
+       .recalc = sh7722_siu_recalc,
+       .set_rate = sh7722_siu_set_rate,
+       .enable = sh7722_siu_enable,
+       .disable = sh7722_siu_disable,
+};
+
+#endif /* CONFIG_CPU_SUBTYPE_SH7343 */
+
 static void sh7722_video_enable(struct clk *clk)
 {
        unsigned long r;
@@ -490,43 +504,6 @@ static void sh7722_video_recalc(struct clk *clk)
        clk->rate = clk->parent->rate / ((r & 0x3F) + 1);
 }
 
-static int sh7722_siu_set_rate(struct clk *clk, unsigned long rate, int algo_id)
-{
-       int siu = sh7722_siu_which(clk);
-       unsigned long r;
-       int div;
-
-       if (siu < 0)
-               return siu;
-       BUG_ON(siu > 2);
-       r = ctrl_inl(sh7722_siu_regs[siu]);
-       div = sh7722_find_divisors(clk->parent->rate, rate);
-       if (div < 0)
-               return div;
-       r = (r & ~0xF) | div;
-       ctrl_outl(r, sh7722_siu_regs[siu]);
-       return 0;
-}
-
-static void sh7722_siu_recalc(struct clk *clk)
-{
-       int siu = sh7722_siu_which(clk);
-       unsigned long r;
-
-       if (siu < 0)
-               return /* siu */ ;
-       BUG_ON(siu > 2);
-       r = ctrl_inl(sh7722_siu_regs[siu]);
-       clk->rate = clk->parent->rate * 2 / divisors2[r & 0xF];
-}
-
-static struct clk_ops sh7722_siu_clk_ops = {
-       .recalc = sh7722_siu_recalc,
-       .set_rate = sh7722_siu_set_rate,
-       .enable = sh7722_siu_enable,
-       .disable = sh7722_siu_disable,
-};
-
 static struct clk_ops sh7722_video_clk_ops = {
        .recalc = sh7722_video_recalc,
        .set_rate = sh7722_video_set_rate,
@@ -539,16 +516,19 @@ static struct clk_ops sh7722_video_clk_ops = {
 static struct clk sh7722_umem_clock = {
        .name = "umem_clk",
        .ops = &sh7722_frqcr_clk_ops,
+       .flags = CLK_RATE_PROPAGATES,
 };
 
 static struct clk sh7722_sh_clock = {
        .name = "sh_clk",
        .ops = &sh7722_frqcr_clk_ops,
+       .flags = CLK_RATE_PROPAGATES,
 };
 
 static struct clk sh7722_peripheral_clock = {
        .name = "peripheral_clk",
        .ops = &sh7722_frqcr_clk_ops,
+       .flags = CLK_RATE_PROPAGATES,
 };
 
 static struct clk sh7722_sdram_clock = {
@@ -556,6 +536,14 @@ static struct clk sh7722_sdram_clock = {
        .ops = &sh7722_frqcr_clk_ops,
 };
 
+static struct clk sh7722_r_clock = {
+       .name = "r_clk",
+       .rate = 32768,
+       .flags = CLK_RATE_PROPAGATES,
+};
+
+#ifndef CONFIG_CPU_SUBTYPE_SH7343
+
 /*
  * these three clocks - SIU A, SIU B, IrDA - share the same clk_ops
  * methods of clk_ops determine which register they should access by
@@ -563,32 +551,248 @@ static struct clk sh7722_sdram_clock = {
  */
 static struct clk sh7722_siu_a_clock = {
        .name = "siu_a_clk",
+       .arch_flags = SCLKACR,
        .ops = &sh7722_siu_clk_ops,
 };
 
 static struct clk sh7722_siu_b_clock = {
        .name = "siu_b_clk",
+       .arch_flags = SCLKBCR,
        .ops = &sh7722_siu_clk_ops,
 };
 
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
 static struct clk sh7722_irda_clock = {
        .name = "irda_clk",
+       .arch_flags = IrDACLKCR,
        .ops = &sh7722_siu_clk_ops,
 };
+#endif
+#endif /* CONFIG_CPU_SUBTYPE_SH7343 */
 
 static struct clk sh7722_video_clock = {
        .name = "video_clk",
        .ops = &sh7722_video_clk_ops,
 };
 
+#define MSTPCR_ARCH_FLAGS(reg, bit) (((reg) << 8) | (bit))
+#define MSTPCR_ARCH_FLAGS_REG(value) ((value) >> 8)
+#define MSTPCR_ARCH_FLAGS_BIT(value) ((value) & 0xff)
+
+static int sh7722_mstpcr_start_stop(struct clk *clk, int enable)
+{
+       unsigned long bit = MSTPCR_ARCH_FLAGS_BIT(clk->arch_flags);
+       unsigned long reg;
+       unsigned long r;
+
+       switch(MSTPCR_ARCH_FLAGS_REG(clk->arch_flags)) {
+       case 0:
+               reg = MSTPCR0;
+               break;
+       case 1:
+               reg = MSTPCR1;
+               break;
+       case 2:
+               reg = MSTPCR2;
+               break;
+       default:
+               return -EINVAL;
+       }  
+
+       r = ctrl_inl(reg);
+
+       if (enable)
+               r &= ~(1 << bit);
+       else
+               r |= (1 << bit);
+
+       ctrl_outl(r, reg);
+       return 0;
+}
+
+static void sh7722_mstpcr_enable(struct clk *clk)
+{
+       sh7722_mstpcr_start_stop(clk, 1);
+}
+
+static void sh7722_mstpcr_disable(struct clk *clk)
+{
+       sh7722_mstpcr_start_stop(clk, 0);
+}
+
+static void sh7722_mstpcr_recalc(struct clk *clk)
+{
+       if (clk->parent)
+               clk->rate = clk->parent->rate;
+}
+
+static struct clk_ops sh7722_mstpcr_clk_ops = {
+       .enable = sh7722_mstpcr_enable,
+       .disable = sh7722_mstpcr_disable,
+       .recalc = sh7722_mstpcr_recalc,
+};
+
+#define MSTPCR(_name, _parent, regnr, bitnr) \
+{                                              \
+       .name = _name,                          \
+       .arch_flags = MSTPCR_ARCH_FLAGS(regnr, bitnr),  \
+       .ops = (void *)_parent,         \
+}
+
+static struct clk sh7722_mstpcr_clocks[] = {
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
+       MSTPCR("uram0", "umem_clk", 0, 28),
+       MSTPCR("xymem0", "bus_clk", 0, 26),
+       MSTPCR("tmu0", "peripheral_clk", 0, 15),
+       MSTPCR("cmt0", "r_clk", 0, 14),
+       MSTPCR("rwdt0", "r_clk", 0, 13),
+       MSTPCR("flctl0", "peripheral_clk", 0, 10),
+       MSTPCR("scif0", "peripheral_clk", 0, 7),
+       MSTPCR("scif1", "peripheral_clk", 0, 6),
+       MSTPCR("scif2", "peripheral_clk", 0, 5),
+       MSTPCR("i2c0", "peripheral_clk", 1, 9),
+       MSTPCR("rtc0", "r_clk", 1, 8),
+       MSTPCR("sdhi0", "peripheral_clk", 2, 18),
+       MSTPCR("keysc0", "r_clk", 2, 14),
+       MSTPCR("usbf0", "peripheral_clk", 2, 11),
+       MSTPCR("2dg0", "bus_clk", 2, 9),
+       MSTPCR("siu0", "bus_clk", 2, 8),
+       MSTPCR("vou0", "bus_clk", 2, 5),
+       MSTPCR("jpu0", "bus_clk", 2, 6),
+       MSTPCR("beu0", "bus_clk", 2, 4),
+       MSTPCR("ceu0", "bus_clk", 2, 3),
+       MSTPCR("veu0", "bus_clk", 2, 2),
+       MSTPCR("vpu0", "bus_clk", 2, 1),
+       MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7723)
+       /* See page 60 of Datasheet V1.0: Overview -> Block Diagram */
+       MSTPCR("tlb0", "cpu_clk", 0, 31),
+       MSTPCR("ic0", "cpu_clk", 0, 30),
+       MSTPCR("oc0", "cpu_clk", 0, 29),
+       MSTPCR("l2c0", "sh_clk", 0, 28),
+       MSTPCR("ilmem0", "cpu_clk", 0, 27),
+       MSTPCR("fpu0", "cpu_clk", 0, 24),
+       MSTPCR("intc0", "cpu_clk", 0, 22),
+       MSTPCR("dmac0", "bus_clk", 0, 21),
+       MSTPCR("sh0", "sh_clk", 0, 20),
+       MSTPCR("hudi0", "peripheral_clk", 0, 19),
+       MSTPCR("ubc0", "cpu_clk", 0, 17),
+       MSTPCR("tmu0", "peripheral_clk", 0, 15),
+       MSTPCR("cmt0", "r_clk", 0, 14),
+       MSTPCR("rwdt0", "r_clk", 0, 13),
+       MSTPCR("dmac1", "bus_clk", 0, 12),
+       MSTPCR("tmu1", "peripheral_clk", 0, 11),
+       MSTPCR("flctl0", "peripheral_clk", 0, 10),
+       MSTPCR("scif0", "peripheral_clk", 0, 9),
+       MSTPCR("scif1", "peripheral_clk", 0, 8),
+       MSTPCR("scif2", "peripheral_clk", 0, 7),
+       MSTPCR("scif3", "bus_clk", 0, 6),
+       MSTPCR("scif4", "bus_clk", 0, 5),
+       MSTPCR("scif5", "bus_clk", 0, 4),
+       MSTPCR("msiof0", "bus_clk", 0, 2),
+       MSTPCR("msiof1", "bus_clk", 0, 1),
+       MSTPCR("meram0", "sh_clk", 0, 0),
+       MSTPCR("i2c0", "peripheral_clk", 1, 9),
+       MSTPCR("rtc0", "r_clk", 1, 8),
+       MSTPCR("atapi0", "sh_clk", 2, 28),
+       MSTPCR("adc0", "peripheral_clk", 2, 28),
+       MSTPCR("tpu0", "bus_clk", 2, 25),
+       MSTPCR("irda0", "peripheral_clk", 2, 24),
+       MSTPCR("tsif0", "bus_clk", 2, 22),
+       MSTPCR("icb0", "bus_clk", 2, 21),
+       MSTPCR("sdhi0", "bus_clk", 2, 18),
+       MSTPCR("sdhi1", "bus_clk", 2, 17),
+       MSTPCR("keysc0", "r_clk", 2, 14),
+       MSTPCR("usb0", "bus_clk", 2, 11),
+       MSTPCR("2dg0", "bus_clk", 2, 10),
+       MSTPCR("siu0", "bus_clk", 2, 8),
+       MSTPCR("veu1", "bus_clk", 2, 6),
+       MSTPCR("vou0", "bus_clk", 2, 5),
+       MSTPCR("beu0", "bus_clk", 2, 4),
+       MSTPCR("ceu0", "bus_clk", 2, 3),
+       MSTPCR("veu0", "bus_clk", 2, 2),
+       MSTPCR("vpu0", "bus_clk", 2, 1),
+       MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7343)
+       MSTPCR("uram0", "umem_clk", 0, 28),
+       MSTPCR("xymem0", "bus_clk", 0, 26),
+       MSTPCR("tmu0", "peripheral_clk", 0, 15),
+       MSTPCR("cmt0", "r_clk", 0, 14),
+       MSTPCR("rwdt0", "r_clk", 0, 13),
+       MSTPCR("scif0", "peripheral_clk", 0, 7),
+       MSTPCR("scif1", "peripheral_clk", 0, 6),
+       MSTPCR("scif2", "peripheral_clk", 0, 5),
+       MSTPCR("scif3", "peripheral_clk", 0, 4),
+       MSTPCR("i2c0", "peripheral_clk", 1, 9),
+       MSTPCR("i2c1", "peripheral_clk", 1, 8),
+       MSTPCR("sdhi0", "peripheral_clk", 2, 18),
+       MSTPCR("keysc0", "r_clk", 2, 14),
+       MSTPCR("usbf0", "peripheral_clk", 2, 11),
+       MSTPCR("siu0", "bus_clk", 2, 8),
+       MSTPCR("jpu0", "bus_clk", 2, 6),
+       MSTPCR("vou0", "bus_clk", 2, 5),
+       MSTPCR("beu0", "bus_clk", 2, 4),
+       MSTPCR("ceu0", "bus_clk", 2, 3),
+       MSTPCR("veu0", "bus_clk", 2, 2),
+       MSTPCR("vpu0", "bus_clk", 2, 1),
+       MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
+#if defined(CONFIG_CPU_SUBTYPE_SH7366)
+       /* See page 52 of Datasheet V0.40: Overview -> Block Diagram */
+       MSTPCR("tlb0", "cpu_clk", 0, 31),
+       MSTPCR("ic0", "cpu_clk", 0, 30),
+       MSTPCR("oc0", "cpu_clk", 0, 29),
+       MSTPCR("rsmem0", "sh_clk", 0, 28),
+       MSTPCR("xymem0", "cpu_clk", 0, 26),
+       MSTPCR("intc30", "peripheral_clk", 0, 23),
+       MSTPCR("intc0", "peripheral_clk", 0, 22),
+       MSTPCR("dmac0", "bus_clk", 0, 21),
+       MSTPCR("sh0", "sh_clk", 0, 20),
+       MSTPCR("hudi0", "peripheral_clk", 0, 19),
+       MSTPCR("ubc0", "cpu_clk", 0, 17),
+       MSTPCR("tmu0", "peripheral_clk", 0, 15),
+       MSTPCR("cmt0", "r_clk", 0, 14),
+       MSTPCR("rwdt0", "r_clk", 0, 13),
+       MSTPCR("flctl0", "peripheral_clk", 0, 10),
+       MSTPCR("scif0", "peripheral_clk", 0, 7),
+       MSTPCR("scif1", "bus_clk", 0, 6),
+       MSTPCR("scif2", "bus_clk", 0, 5),
+       MSTPCR("msiof0", "peripheral_clk", 0, 2),
+       MSTPCR("sbr0", "peripheral_clk", 0, 1),
+       MSTPCR("i2c0", "peripheral_clk", 1, 9),
+       MSTPCR("icb0", "bus_clk", 2, 27),
+       MSTPCR("meram0", "sh_clk", 2, 26),
+       MSTPCR("dacc0", "peripheral_clk", 2, 24),
+       MSTPCR("dacy0", "peripheral_clk", 2, 23),
+       MSTPCR("tsif0", "bus_clk", 2, 22),
+       MSTPCR("sdhi0", "bus_clk", 2, 18),
+       MSTPCR("mmcif0", "bus_clk", 2, 17),
+       MSTPCR("usb0", "bus_clk", 2, 11),
+       MSTPCR("siu0", "bus_clk", 2, 8),
+       MSTPCR("veu1", "bus_clk", 2, 7),
+       MSTPCR("vou0", "bus_clk", 2, 5),
+       MSTPCR("beu0", "bus_clk", 2, 4),
+       MSTPCR("ceu0", "bus_clk", 2, 3),
+       MSTPCR("veu0", "bus_clk", 2, 2),
+       MSTPCR("vpu0", "bus_clk", 2, 1),
+       MSTPCR("lcdc0", "bus_clk", 2, 0),
+#endif
+};
+
 static struct clk *sh7722_clocks[] = {
        &sh7722_umem_clock,
        &sh7722_sh_clock,
        &sh7722_peripheral_clock,
        &sh7722_sdram_clock,
+#ifndef CONFIG_CPU_SUBTYPE_SH7343
        &sh7722_siu_a_clock,
        &sh7722_siu_b_clock,
+#if defined(CONFIG_CPU_SUBTYPE_SH7722)
        &sh7722_irda_clock,
+#endif
+#endif
        &sh7722_video_clock,
 };
 
@@ -611,15 +815,28 @@ arch_init_clk_ops(struct clk_ops **ops, int type)
 
 int __init arch_clk_init(void)
 {
-       struct clk *master;
+       struct clk *clk;
        int i;
 
-       master = clk_get(NULL, "master_clk");
+       clk = clk_get(NULL, "master_clk");
        for (i = 0; i < ARRAY_SIZE(sh7722_clocks); i++) {
                pr_debug( "Registering clock '%s'\n", sh7722_clocks[i]->name);
-               sh7722_clocks[i]->parent = master;
+               sh7722_clocks[i]->parent = clk;
                clk_register(sh7722_clocks[i]);
        }
-       clk_put(master);
+       clk_put(clk);
+
+       clk_register(&sh7722_r_clock);
+
+       for (i = 0; i < ARRAY_SIZE(sh7722_mstpcr_clocks); i++) {
+               pr_debug( "Registering mstpcr clock '%s'\n",
+                         sh7722_mstpcr_clocks[i].name);
+               clk = clk_get(NULL, (void *) sh7722_mstpcr_clocks[i].ops);
+               sh7722_mstpcr_clocks[i].parent = clk;
+               sh7722_mstpcr_clocks[i].ops = &sh7722_mstpcr_clk_ops;
+               clk_register(&sh7722_mstpcr_clocks[i]);
+               clk_put(clk);
+       }
+
        return 0;
 }