linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / arch / arm / mach-at91rm9200 / clock.c
index edc2cc8..ec8195a 100644 (file)
 #include <asm/io.h>
 #include <asm/mach-types.h>
 
-#include <asm/hardware.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/board.h>            /* for master clock global */
 
 #include "generic.h"
 
+#undef DEBUG
 
 /*
  * There's a lot more which can be done with clocks, including cpufreq
@@ -39,9 +41,7 @@
  */
 
 struct clk {
-       const char      *name;          /* unique clock name */
-       const char      *function;      /* function of the clock */
-       struct device   *dev;           /* device associated with function */
+       const char      *name;
        unsigned long   rate_hz;
        struct clk      *parent;
        u32             pmc_mask;
@@ -71,14 +71,15 @@ static struct clk clk32k = {
 };
 static struct clk main_clk = {
        .name           = "main",
-       .pmc_mask       = AT91_PMC_MOSCS,       /* in PMC_SR */
+       .pmc_mask       = 1 << 0,       /* in PMC_SR */
+       .users          = 1,
        .id             = 1,
        .primary        = 1,
 };
 static struct clk plla = {
        .name           = "plla",
        .parent         = &main_clk,
-       .pmc_mask       = AT91_PMC_LOCKA,       /* in PMC_SR */
+       .pmc_mask       = 1 << 1,       /* in PMC_SR */
        .id             = 2,
        .primary        = 1,
        .pll            = 1,
@@ -104,7 +105,7 @@ static void pllb_mode(struct clk *clk, int is_on)
 static struct clk pllb = {
        .name           = "pllb",
        .parent         = &main_clk,
-       .pmc_mask       = AT91_PMC_LOCKB,       /* in PMC_SR */
+       .pmc_mask       = 1 << 2,       /* in PMC_SR */
        .mode           = pllb_mode,
        .id             = 3,
        .primary        = 1,
@@ -176,7 +177,8 @@ static struct clk pck3 = {
  */
 static struct clk mck = {
        .name           = "mck",
-       .pmc_mask       = AT91_PMC_MCKRDY,      /* in PMC_SR */
+       .pmc_mask       = 1 << 3,       /* in PMC_SR */
+       .users          = 1,            /* (must be) always on */
 };
 
 static void pmc_periph_mode(struct clk *clk, int is_on)
@@ -199,78 +201,6 @@ static struct clk ohci_clk = {
        .pmc_mask       = 1 << AT91_ID_UHP,
        .mode           = pmc_periph_mode,
 };
-static struct clk ether_clk = {
-       .name           = "ether_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_EMAC,
-       .mode           = pmc_periph_mode,
-};
-static struct clk mmc_clk = {
-       .name           = "mci_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_MCI,
-       .mode           = pmc_periph_mode,
-};
-static struct clk twi_clk = {
-       .name           = "twi_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_TWI,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart0_clk = {
-       .name           = "usart0_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_US0,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart1_clk = {
-       .name           = "usart1_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_US1,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart2_clk = {
-       .name           = "usart2_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_US2,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart3_clk = {
-       .name           = "usart3_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_US3,
-       .mode           = pmc_periph_mode,
-};
-static struct clk spi_clk = {
-       .name           = "spi0_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_SPI,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioA_clk = {
-       .name           = "pioA_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_PIOA,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioB_clk = {
-       .name           = "pioB_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_PIOB,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioC_clk = {
-       .name           = "pioC_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_PIOC,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioD_clk = {
-       .name           = "pioD_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91_ID_PIOD,
-       .mode           = pmc_periph_mode,
-};
 
 static struct clk *const clock_list[] = {
        /* four primary clocks -- MUST BE FIRST! */
@@ -293,54 +223,26 @@ static struct clk *const clock_list[] = {
 
        /* MCK and peripherals */
        &mck,
-       &usart0_clk,
-       &usart1_clk,
-       &usart2_clk,
-       &usart3_clk,
-       &mmc_clk,
+       // usart0..usart3
+       // mmc
        &udc_clk,
-       &twi_clk,
-       &spi_clk,
-       &pioA_clk,
-       &pioB_clk,
-       &pioC_clk,
-       &pioD_clk,
+       // i2c
+       // spi
        // ssc0..ssc2
        // tc0..tc5
-       // irq0..irq6
        &ohci_clk,
-       &ether_clk,
+       // ether
 };
 
 
-/*
- * Associate a particular clock with a function (eg, "uart") and device.
- * The drivers can then request the same 'function' with several different
- * devices and not care about which clock name to use.
- */
-void __init at91_clock_associate(const char *id, struct device *dev, const char *func)
-{
-       struct clk *clk = clk_get(NULL, id);
-
-       if (!dev || !clk || !IS_ERR(clk_get(dev, func)))
-               return;
-
-       clk->function = func;
-       clk->dev = dev;
-}
-
 /* clocks are all static for now; no refcounting necessary */
 struct clk *clk_get(struct device *dev, const char *id)
 {
        int i;
 
        for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
-               struct clk *clk = clock_list[i];
-
-               if (strcmp(id, clk->name) == 0)
-                       return clk;
-               if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0)
-                       return clk;
+               if (strcmp(id, clock_list[i]->name) == 0)
+                       return clock_list[i];
        }
 
        return ERR_PTR(-ENOENT);
@@ -458,7 +360,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
                        u32     pckr;
 
                        pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-                       pckr &= AT91_PMC_CSS_PLLB;      /* clock selection */
+                       pckr &= 0x03;
                        pckr |= prescale << 2;
                        at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
                        clk->rate_hz = actual;
@@ -538,7 +440,7 @@ static int at91_clk_show(struct seq_file *s, void *unused)
                else
                        state = "";
 
-               seq_printf(s, "%-10s users=%2d %-3s %9ld Hz %s\n",
+               seq_printf(s, "%-10s users=%d %-3s %9ld Hz %s\n",
                        clk->name, clk->users, state, clk_get_rate(clk),
                        clk->parent ? clk->parent->name : "");
        }
@@ -581,18 +483,11 @@ static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
                freq *= mul + 1;
        } else
                freq = 0;
-
+       if (pll == &pllb && (reg & (1 << 28)))
+               freq /= 2;
        return freq;
 }
 
-static u32 __init at91_usb_rate(struct clk *pll, u32 freq, u32 reg)
-{
-       if (pll == &pllb && (reg & AT91_PMC_USB96M))
-               return freq / 2;
-       else
-               return freq;
-}
-
 static unsigned __init at91_pll_calc(unsigned main_freq, unsigned out_freq)
 {
        unsigned i, div = 0, mul = 0, diff = 1 << 30;
@@ -640,30 +535,6 @@ fail:
        return 0;
 }
 
-
-/*
- * Several unused clocks may be active.  Turn them off.
- */
-static void at91_periphclk_reset(void)
-{
-       unsigned long reg;
-       int i;
-
-       reg = at91_sys_read(AT91_PMC_PCSR);
-
-       for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
-               struct clk      *clk = clock_list[i];
-
-               if (clk->mode != pmc_periph_mode)
-                       continue;
-
-               if (clk->users > 0)
-                       reg &= ~clk->pmc_mask;
-       }
-
-       at91_sys_write(AT91_PMC_PCDR, reg);
-}
-
 int __init at91_clock_init(unsigned long main_clock)
 {
        unsigned tmp, freq, mckr;
@@ -679,8 +550,8 @@ int __init at91_clock_init(unsigned long main_clock)
        if (!main_clock) {
                do {
                        tmp = at91_sys_read(AT91_CKGR_MCFR);
-               } while (!(tmp & AT91_PMC_MAINRDY));
-               main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16);
+               } while (!(tmp & 0x10000));
+               main_clock = (tmp & 0xffff) * (AT91_SLOW_CLOCK / 16);
        }
        main_clk.rate_hz = main_clock;
 
@@ -695,33 +566,32 @@ int __init at91_clock_init(unsigned long main_clock)
         *
         * REVISIT:  assumes MCK doesn't derive from PLLB!
         */
-       at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
+       at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | 0x10000000;
        pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
+       at91_sys_write(AT91_PMC_PCDR, (1 << AT91_ID_UHP) | (1 << AT91_ID_UDP));
        at91_sys_write(AT91_PMC_SCDR, AT91_PMC_UHP | AT91_PMC_UDP);
        at91_sys_write(AT91_CKGR_PLLBR, 0);
        at91_sys_write(AT91_PMC_SCER, AT91_PMC_MCKUDP);
 
-       udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
-       uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, at91_pllb_usb_init);
-
        /*
         * MCK and CPU derive from one of those primary clocks.
         * For now, assume this parentage won't change.
         */
        mckr = at91_sys_read(AT91_PMC_MCKR);
        mck.parent = clock_list[mckr & AT91_PMC_CSS];
+       mck.parent->users++;
        freq = mck.parent->rate_hz;
        freq /= (1 << ((mckr >> 2) & 3));               /* prescale */
        mck.rate_hz = freq / (1 + ((mckr >> 8) & 3));   /* mdiv */
 
-       /* MCK and CPU clock are "always on" */
-       clk_enable(&mck);
-
        printk("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n",
                freq / 1000000, (unsigned) mck.rate_hz / 1000000,
                (unsigned) main_clock / 1000000,
                ((unsigned) main_clock % 1000000) / 1000);
 
+       /* FIXME get rid of master_clock global */
+       at91_master_clock = mck.rate_hz;
+
 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
        /* establish PCK0..PCK3 parentage */
        for (tmp = 0; tmp < ARRAY_SIZE(clock_list); tmp++) {
@@ -732,28 +602,19 @@ int __init at91_clock_init(unsigned long main_clock)
                        continue;
 
                pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-               parent = clock_list[pckr & AT91_PMC_CSS];
+               parent = clock_list[pckr & 3];
                clk->parent = parent;
                clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));
-
-               if (clk->users == 0) {
-                       /* not being used, so switch it off */
-                       at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask);
-               }
        }
 #else
-       /* disable all programmable clocks */
+       /* disable unused clocks */
        at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK0 | AT91_PMC_PCK1 | AT91_PMC_PCK2 | AT91_PMC_PCK3);
-#endif
-
-       /* enable the PIO clocks */
-       clk_enable(&pioA_clk);
-       clk_enable(&pioB_clk);
-       clk_enable(&pioC_clk);
-       clk_enable(&pioD_clk);
+#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
 
-       /* disable all other unused peripheral clocks */
-       at91_periphclk_reset();
+       /* FIXME several unused clocks may still be active...  provide
+        * a CONFIG option to turn off all unused clocks at some point
+        * before driver init starts.
+        */
 
        return 0;
 }