[ARM] 3866/1: AT91 clock update
authorAndrew Victor <andrew@sanpeople.com>
Wed, 27 Sep 2006 09:50:59 +0000 (10:50 +0100)
committerRussell King <rmk+kernel@arm.linux.org.uk>
Thu, 28 Sep 2006 10:52:06 +0000 (11:52 +0100)
This patch makes the AT91 clock.c support processor-generic (AT91RM9200
and AT91SAM9xxx).  The clocks supported by a particular AT91 processor
are defined in the processor-specific file and are registered with
clock.c at startup.

Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
13 files changed:
arch/arm/mach-at91rm9200/at91rm9200.c
arch/arm/mach-at91rm9200/board-1arm.c
arch/arm/mach-at91rm9200/board-carmeva.c
arch/arm/mach-at91rm9200/board-csb337.c
arch/arm/mach-at91rm9200/board-csb637.c
arch/arm/mach-at91rm9200/board-dk.c
arch/arm/mach-at91rm9200/board-eb9200.c
arch/arm/mach-at91rm9200/board-ek.c
arch/arm/mach-at91rm9200/board-kafa.c
arch/arm/mach-at91rm9200/board-kb9202.c
arch/arm/mach-at91rm9200/clock.c
arch/arm/mach-at91rm9200/clock.h [new file with mode: 0644]
arch/arm/mach-at91rm9200/generic.h

index e21cb84..ae04cbd 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <asm/hardware.h>
 #include "generic.h"
+#include "clock.h"
 
 static struct map_desc at91rm9200_io_desc[] __initdata = {
        {
@@ -102,9 +103,160 @@ static struct map_desc at91rm9200_io_desc[] __initdata = {
        },
 };
 
-void __init at91rm9200_map_io(void)
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk udc_clk = {
+       .name           = "udc_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_UDP,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ohci_clk = {
+       .name           = "ohci_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_UHP,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk ether_clk = {
+       .name           = "ether_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_EMAC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc_clk = {
+       .name           = "mci_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_MCI,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi_clk = {
+       .name           = "twi_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_TWI,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+       .name           = "usart0_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_US0,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+       .name           = "usart1_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_US1,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+       .name           = "usart2_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_US2,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart3_clk = {
+       .name           = "usart3_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_US3,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi_clk = {
+       .name           = "spi_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_SPI,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioA_clk = {
+       .name           = "pioA_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_PIOA,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+       .name           = "pioB_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_PIOB,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioC_clk = {
+       .name           = "pioC_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_PIOC,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioD_clk = {
+       .name           = "pioD_clk",
+       .pmc_mask       = 1 << AT91RM9200_ID_PIOD,
+       .type           = CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+       &pioA_clk,
+       &pioB_clk,
+       &pioC_clk,
+       &pioD_clk,
+       &usart0_clk,
+       &usart1_clk,
+       &usart2_clk,
+       &usart3_clk,
+       &mmc_clk,
+       &udc_clk,
+       &twi_clk,
+       &spi_clk,
+       // ssc 0 .. ssc2
+       // tc0 .. tc5
+       &ohci_clk,
+       &ether_clk,
+       // irq0 .. irq6
+};
+
+/*
+ * The four programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+       .name           = "pck0",
+       .pmc_mask       = AT91_PMC_PCK0,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 0,
+};
+static struct clk pck1 = {
+       .name           = "pck1",
+       .pmc_mask       = AT91_PMC_PCK1,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 1,
+};
+static struct clk pck2 = {
+       .name           = "pck2",
+       .pmc_mask       = AT91_PMC_PCK2,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 2,
+};
+static struct clk pck3 = {
+       .name           = "pck3",
+       .pmc_mask       = AT91_PMC_PCK3,
+       .type           = CLK_TYPE_PROGRAMMABLE,
+       .id             = 3,
+};
+
+static void __init at91rm9200_register_clocks(void)
 {
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+               clk_register(periph_clocks[i]);
+
+       clk_register(&pck0);
+       clk_register(&pck1);
+       clk_register(&pck2);
+       clk_register(&pck3);
+}
+
+
+/* --------------------------------------------------------------------
+ *  AT91RM9200 processor initialization
+ * -------------------------------------------------------------------- */
+void __init at91rm9200_initialize(unsigned long main_clock)
+{
+       /* Map peripherals */
        iotable_init(at91rm9200_io_desc, ARRAY_SIZE(at91rm9200_io_desc));
+
+       /* Init clock subsystem */
+       at91_clock_init(main_clock);
+
+       /* Register the processor-specific clocks */
+       at91rm9200_register_clocks();
 }
 
 /*
index dc79e09..d2aa9c4 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -62,10 +61,8 @@ static struct at91_uart_config __initdata onearm_uart_config = {
 
 static void __init onearm_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 18.432 MHz crystal */
-       at91_clock_init(18432000);
+       /* Initialize processor: 18.432 MHz crystal */
+       at91rm9200_initialize(18432000);
 
        /* Setup the serial ports and console */
        at91_init_serial(&onearm_uart_config);
index 2c138b5..6af252b 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -63,10 +62,8 @@ static struct at91_uart_config __initdata carmeva_uart_config = {
 
 static void __init carmeva_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 20.000 MHz crystal */
-       at91_clock_init(20000000);
+       /* Initialize processor: 20.000 MHz crystal */
+       at91rm9200_initialize(20000000);
 
        /* Setup the serial ports and console */
        at91_init_serial(&carmeva_uart_config);
index 794d3fb..f74b483 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -62,10 +61,8 @@ static struct at91_uart_config __initdata csb337_uart_config = {
 
 static void __init csb337_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 3.6864 MHz crystal */
-       at91_clock_init(3686400);
+       /* Initialize processor: 3.6864 MHz crystal */
+       at91rm9200_initialize(3686400);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
index c8b6f33..8803509 100644 (file)
@@ -33,7 +33,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -61,10 +60,8 @@ static struct at91_uart_config __initdata csb637_uart_config = {
 
 static void __init csb637_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 3.6864 MHz crystal */
-       at91_clock_init(3686400);
+       /* Initialize processor: 3.6864 MHz crystal */
+       at91rm9200_initialize(3686400);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
index 6587303..23ea9d6 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -65,10 +64,8 @@ static struct at91_uart_config __initdata dk_uart_config = {
 
 static void __init dk_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 18.432 MHz crystal */
-       at91_clock_init(18432000);
+       /* Initialize processor: 18.432 MHz crystal */
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB2, AT91_PIN_PB2);
index a3e2df9..2ceb267 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -63,10 +62,8 @@ static struct at91_uart_config __initdata eb9200_uart_config = {
 
 static void __init eb9200_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 18.432 MHz crystal */
-       at91_clock_init(18432000);
+       /* Initialize processor: 18.432 MHz crystal */
+       at91rm9200_initialize(18432000);
 
        /* Setup the serial ports and console */
        at91_init_serial(&eb9200_uart_config);
index 8681923..8cd8336 100644 (file)
@@ -37,7 +37,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -65,10 +64,8 @@ static struct at91_uart_config __initdata ek_uart_config = {
 
 static void __init ek_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 18.432 MHz crystal */
-       at91_clock_init(18432000);
+       /* Initialize processor: 18.432 MHz crystal */
+       at91rm9200_initialize(18432000);
 
        /* Setup the LEDs */
        at91_init_leds(AT91_PIN_PB1, AT91_PIN_PB2);
index bf760c5..d9a6b7e 100644 (file)
@@ -34,7 +34,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -62,10 +61,8 @@ static struct at91_uart_config __initdata kafa_uart_config = {
 
 static void __init kafa_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 18.432 MHz crystal */
-       at91_clock_init(18432000);
+       /* Initialize processor: 18.432 MHz crystal */
+       at91rm9200_initialize(18432000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PB4, AT91_PIN_PB4);
index f06d2b5..935238f 100644 (file)
@@ -35,7 +35,6 @@
 #include <asm/mach/map.h>
 #include <asm/mach/irq.h>
 
-#include <asm/hardware.h>
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
 
@@ -63,10 +62,8 @@ static struct at91_uart_config __initdata kb9202_uart_config = {
 
 static void __init kb9202_map_io(void)
 {
-       at91rm9200_map_io();
-
-       /* Initialize clocks: 10 MHz crystal */
-       at91_clock_init(10000000);
+       /* Initialize processor: 10 MHz crystal */
+       at91rm9200_initialize(10000000);
 
        /* Set up the LEDs */
        at91_init_leds(AT91_PIN_PC19, AT91_PIN_PC18);
index 5b78922..a43b061 100644 (file)
@@ -29,7 +29,7 @@
 
 #include <asm/hardware.h>
 
-#include "generic.h"
+#include "clock.h"
 
 
 /*
  * PLLB be used at other rates (on boards that don't need USB), etc.
  */
 
-struct clk {
-       const char      *name;          /* unique clock name */
-       const char      *function;      /* function of the clock */
-       struct device   *dev;           /* device associated with function */
-       unsigned long   rate_hz;
-       struct clk      *parent;
-       u32             pmc_mask;
-       void            (*mode)(struct clk *, int);
-       unsigned        id:2;           /* PCK0..3, or 32k/main/a/b */
-       unsigned        primary:1;
-       unsigned        pll:1;
-       unsigned        programmable:1;
-       u16             users;
-};
+#define clk_is_primary(x)      ((x)->type & CLK_TYPE_PRIMARY)
+#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE)
+#define clk_is_peripheral(x)   ((x)->type & CLK_TYPE_PERIPHERAL)
+
+
+static LIST_HEAD(clocks);
+static DEFINE_SPINLOCK(clk_lock);
 
-static spinlock_t      clk_lock;
-static u32             at91_pllb_usb_init;
+static u32 at91_pllb_usb_init;
 
 /*
  * Four primary clock sources:  two crystal oscillators (32K, main), and
@@ -67,21 +59,20 @@ static struct clk clk32k = {
        .rate_hz        = AT91_SLOW_CLOCK,
        .users          = 1,            /* always on */
        .id             = 0,
-       .primary        = 1,
+       .type           = CLK_TYPE_PRIMARY,
 };
 static struct clk main_clk = {
        .name           = "main",
        .pmc_mask       = AT91_PMC_MOSCS,       /* in PMC_SR */
        .id             = 1,
-       .primary        = 1,
+       .type           = CLK_TYPE_PRIMARY,
 };
 static struct clk plla = {
        .name           = "plla",
        .parent         = &main_clk,
        .pmc_mask       = AT91_PMC_LOCKA,       /* in PMC_SR */
        .id             = 2,
-       .primary        = 1,
-       .pll            = 1,
+       .type           = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
 };
 
 static void pllb_mode(struct clk *clk, int is_on)
@@ -94,6 +85,7 @@ static void pllb_mode(struct clk *clk, int is_on)
        } else
                value = 0;
 
+       // REVISIT: Add work-around for AT91RM9200 Errata #26 ?
        at91_sys_write(AT91_CKGR_PLLBR, value);
 
        do {
@@ -107,8 +99,7 @@ static struct clk pllb = {
        .pmc_mask       = AT91_PMC_LOCKB,       /* in PMC_SR */
        .mode           = pllb_mode,
        .id             = 3,
-       .primary        = 1,
-       .pll            = 1,
+       .type           = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
 };
 
 static void pmc_sys_mode(struct clk *clk, int is_on)
@@ -133,41 +124,6 @@ static struct clk uhpck = {
        .mode           = pmc_sys_mode,
 };
 
-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
-/*
- * The four programmable clocks can be parented by any primary clock.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
-       .name           = "pck0",
-       .pmc_mask       = AT91_PMC_PCK0,
-       .mode           = pmc_sys_mode,
-       .programmable   = 1,
-       .id             = 0,
-};
-static struct clk pck1 = {
-       .name           = "pck1",
-       .pmc_mask       = AT91_PMC_PCK1,
-       .mode           = pmc_sys_mode,
-       .programmable   = 1,
-       .id             = 1,
-};
-static struct clk pck2 = {
-       .name           = "pck2",
-       .pmc_mask       = AT91_PMC_PCK2,
-       .mode           = pmc_sys_mode,
-       .programmable   = 1,
-       .id             = 2,
-};
-static struct clk pck3 = {
-       .name           = "pck3",
-       .pmc_mask       = AT91_PMC_PCK3,
-       .mode           = pmc_sys_mode,
-       .programmable   = 1,
-       .id             = 3,
-};
-#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
-
 
 /*
  * The master clock is divided from the CPU clock (by 1-4).  It's used for
@@ -187,131 +143,21 @@ static void pmc_periph_mode(struct clk *clk, int is_on)
                at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);
 }
 
-static struct clk udc_clk = {
-       .name           = "udc_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_UDP,
-       .mode           = pmc_periph_mode,
-};
-static struct clk ohci_clk = {
-       .name           = "ohci_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_UHP,
-       .mode           = pmc_periph_mode,
-};
-static struct clk ether_clk = {
-       .name           = "ether_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_EMAC,
-       .mode           = pmc_periph_mode,
-};
-static struct clk mmc_clk = {
-       .name           = "mci_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_MCI,
-       .mode           = pmc_periph_mode,
-};
-static struct clk twi_clk = {
-       .name           = "twi_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_TWI,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart0_clk = {
-       .name           = "usart0_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_US0,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart1_clk = {
-       .name           = "usart1_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_US1,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart2_clk = {
-       .name           = "usart2_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_US2,
-       .mode           = pmc_periph_mode,
-};
-static struct clk usart3_clk = {
-       .name           = "usart3_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_US3,
-       .mode           = pmc_periph_mode,
-};
-static struct clk spi_clk = {
-       .name           = "spi0_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_SPI,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioA_clk = {
-       .name           = "pioA_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_PIOA,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioB_clk = {
-       .name           = "pioB_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_PIOB,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioC_clk = {
-       .name           = "pioC_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_PIOC,
-       .mode           = pmc_periph_mode,
-};
-static struct clk pioD_clk = {
-       .name           = "pioD_clk",
-       .parent         = &mck,
-       .pmc_mask       = 1 << AT91RM9200_ID_PIOD,
-       .mode           = pmc_periph_mode,
-};
-
-static struct clk *const clock_list[] = {
-       /* four primary clocks -- MUST BE FIRST! */
-       &clk32k,
-       &main_clk,
-       &plla,
-       &pllb,
-
-       /* PLLB children (USB) */
-       &udpck,
-       &uhpck,
-
-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
-       /* programmable clocks */
-       &pck0,
-       &pck1,
-       &pck2,
-       &pck3,
-#endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
-
-       /* MCK and peripherals */
-       &mck,
-       &usart0_clk,
-       &usart1_clk,
-       &usart2_clk,
-       &usart3_clk,
-       &mmc_clk,
-       &udc_clk,
-       &twi_clk,
-       &spi_clk,
-       &pioA_clk,
-       &pioB_clk,
-       &pioC_clk,
-       &pioD_clk,
-       // ssc0..ssc2
-       // tc0..tc5
-       // irq0..irq6
-       &ohci_clk,
-       &ether_clk,
-};
+static struct clk __init *at91_css_to_clk(unsigned long css)
+{
+       switch (css) {
+               case AT91_PMC_CSS_SLOW:
+                       return &clk32k;
+               case AT91_PMC_CSS_MAIN:
+                       return &main_clk;
+               case AT91_PMC_CSS_PLLA:
+                       return &plla;
+               case AT91_PMC_CSS_PLLB:
+                       return &pllb;
+       }
 
+       return NULL;
+}
 
 /*
  * Associate a particular clock with a function (eg, "uart") and device.
@@ -329,14 +175,12 @@ void __init at91_clock_associate(const char *id, struct device *dev, const char
        clk->dev = dev;
 }
 
-/* clocks are all static for now; no refcounting necessary */
+/* clocks cannot be de-registered 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];
+       struct clk *clk;
 
+       list_for_each_entry(clk, &clocks, node) {
                if (strcmp(id, clk->name) == 0)
                        return clk;
                if (clk->function && (dev == clk->dev) && strcmp(id, clk->function) == 0)
@@ -424,7 +268,7 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
        unsigned        prescale;
        unsigned long   actual;
 
-       if (!clk->programmable)
+       if (!clk_is_programmable(clk))
                return -EINVAL;
        spin_lock_irqsave(&clk_lock, flags);
 
@@ -446,7 +290,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
        unsigned        prescale;
        unsigned long   actual;
 
-       if (!clk->programmable)
+       if (!clk_is_programmable(clk))
                return -EINVAL;
        if (clk->users)
                return -EBUSY;
@@ -484,7 +328,7 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 
        if (clk->users)
                return -EBUSY;
-       if (!parent->primary || !clk->programmable)
+       if (!clk_is_primary(parent) || !clk_is_programmable(clk))
                return -EINVAL;
        spin_lock_irqsave(&clk_lock, flags);
 
@@ -497,6 +341,18 @@ int clk_set_parent(struct clk *clk, struct clk *parent)
 }
 EXPORT_SYMBOL(clk_set_parent);
 
+/* establish PCK0..PCK3 parentage and rate */
+static void init_programmable_clock(struct clk *clk)
+{
+       struct clk      *parent;
+       u32             pckr;
+
+       pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
+       parent = at91_css_to_clk(pckr & AT91_PMC_CSS);
+       clk->parent = parent;
+       clk->rate_hz = parent->rate_hz / (1 << ((pckr >> 2) & 3));
+}
+
 #endif /* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
 
 /*------------------------------------------------------------------------*/
@@ -506,6 +362,7 @@ EXPORT_SYMBOL(clk_set_parent);
 static int at91_clk_show(struct seq_file *s, void *unused)
 {
        u32             scsr, pcsr, sr;
+       struct clk      *clk;
        unsigned        i;
 
        seq_printf(s, "SCSR = %8x\n", scsr = at91_sys_read(AT91_PMC_SCSR));
@@ -523,9 +380,8 @@ static int at91_clk_show(struct seq_file *s, void *unused)
 
        seq_printf(s, "\n");
 
-       for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
-               char            *state;
-               struct clk      *clk = clock_list[i];
+       list_for_each_entry(clk, &clocks, node) {
+               char    *state;
 
                if (clk->mode == pmc_sys_mode)
                        state = (scsr & clk->pmc_mask) ? "on" : "off";
@@ -568,6 +424,28 @@ postcore_initcall(at91_clk_debugfs_init);
 
 #endif
 
+/*------------------------------------------------------------------------*/
+
+/* Register a new clock */
+int __init clk_register(struct clk *clk)
+{
+       if (clk_is_peripheral(clk)) {
+               clk->parent = &mck;
+               clk->mode = pmc_periph_mode;
+               list_add_tail(&clk->node, &clocks);
+       }
+#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+       else if (clk_is_programmable(clk)) {
+               clk->mode = pmc_sys_mode;
+               init_programmable_clock(clk);
+               list_add_tail(&clk->node, &clocks);
+       }
+#endif
+
+       return 0;
+}
+
+
 /*------------------------------------------------------------------------*/
 
 static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
@@ -640,20 +518,17 @@ fail:
        return 0;
 }
 
-
 /*
  * Several unused clocks may be active.  Turn them off.
  */
-static void at91_periphclk_reset(void)
+static void __init at91_periphclk_reset(void)
 {
        unsigned long reg;
-       int i;
+       struct clk *clk;
 
        reg = at91_sys_read(AT91_PMC_PCSR);
 
-       for (i = 0; i < ARRAY_SIZE(clock_list); i++) {
-               struct clk      *clk = clock_list[i];
-
+       list_for_each_entry(clk, &clocks, node) {
                if (clk->mode != pmc_periph_mode)
                        continue;
 
@@ -664,11 +539,25 @@ static void at91_periphclk_reset(void)
        at91_sys_write(AT91_PMC_PCDR, reg);
 }
 
+static struct clk *const standard_pmc_clocks[] __initdata = {
+       /* four primary clocks */
+       &clk32k,
+       &main_clk,
+       &plla,
+       &pllb,
+
+       /* PLLB children (USB) */
+       &udpck,
+       &uhpck,
+
+       /* MCK */
+       &mck
+};
+
 int __init at91_clock_init(unsigned long main_clock)
 {
        unsigned tmp, freq, mckr;
-
-       spin_lock_init(&clk_lock);
+       int i;
 
        /*
         * When the bootloader initialized the main oscillator correctly,
@@ -709,11 +598,15 @@ int __init at91_clock_init(unsigned long main_clock)
         * 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 = at91_css_to_clk(mckr & AT91_PMC_CSS);
        freq = mck.parent->rate_hz;
        freq /= (1 << ((mckr >> 2) & 3));               /* prescale */
        mck.rate_hz = freq / (1 + ((mckr >> 8) & 3));   /* mdiv */
 
+       /* Register the PMC's standard clocks */
+       for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
+               list_add_tail(&standard_pmc_clocks[i]->node, &clocks);
+
        /* MCK and CPU clock are "always on" */
        clk_enable(&mck);
 
@@ -722,35 +615,8 @@ int __init at91_clock_init(unsigned long main_clock)
                (unsigned) main_clock / 1000000,
                ((unsigned) main_clock % 1000000) / 1000);
 
-#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
-       /* establish PCK0..PCK3 parentage */
-       for (tmp = 0; tmp < ARRAY_SIZE(clock_list); tmp++) {
-               struct clk      *clk = clock_list[tmp], *parent;
-               u32             pckr;
-
-               if (!clk->programmable)
-                       continue;
-
-               pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-               parent = clock_list[pckr & AT91_PMC_CSS];
-               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 */
        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);
 
        /* disable all other unused peripheral clocks */
        at91_periphclk_reset();
diff --git a/arch/arm/mach-at91rm9200/clock.h b/arch/arm/mach-at91rm9200/clock.h
new file mode 100644 (file)
index 0000000..0592e66
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * linux/arch/arm/mach-at91rm9200/clock.h
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define CLK_TYPE_PRIMARY       0x1
+#define CLK_TYPE_PLL           0x2
+#define CLK_TYPE_PROGRAMMABLE  0x4
+#define CLK_TYPE_PERIPHERAL    0x8
+
+
+struct clk {
+       struct list_head node;
+       const char      *name;          /* unique clock name */
+       const char      *function;      /* function of the clock */
+       struct device   *dev;           /* device associated with function */
+       unsigned long   rate_hz;
+       struct clk      *parent;
+       u32             pmc_mask;
+       void            (*mode)(struct clk *, int);
+       unsigned        id:2;           /* PCK0..3, or 32k/main/a/b */
+       unsigned        type;           /* clock type */
+       u16             users;
+};
+
+
+extern int __init clk_register(struct clk *clk);
index 7979d8a..c44e0e0 100644 (file)
@@ -8,6 +8,9 @@
  * published by the Free Software Foundation.
  */
 
+ /* Processors */
+extern void __init at91rm9200_initialize(unsigned long main_clock);
+
  /* Interrupts */
 extern void __init at91rm9200_init_irq(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
@@ -17,9 +20,6 @@ extern void __init at91_gpio_irq_setup(unsigned banks);
 struct sys_timer;
 extern struct sys_timer at91rm9200_timer;
 
- /* Memory Map */
-extern void __init at91rm9200_map_io(void);
-
  /* Clocks */
 extern int __init at91_clock_init(unsigned long main_clock);
 struct device;