[ARM] 3386/1: AT91RM9200 Clock update
Andrew Victor [Wed, 22 Mar 2006 20:14:14 +0000 (20:14 +0000)]
Patch from Andrew Victor

This patch includes a few changes to the clock support on the
AT91RM9200.

1. Added definitions for Ethernet, MMC, TWI, USARTs, and SPI peripheral
clocks.

2. Replaced some hard-coded hex values with the text definitions in
at91rm9200_sys.h.

3. If the USB96M bit is set for PLLB, then the rate of PLLB is not
affected but only the USB Host/Device clocks which are derived from it.
Issue reported by Sergei Sharonov.

Signed-off-by: Andrew Victor <andrew@sanpeople.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

arch/arm/mach-at91rm9200/clock.c

index ec8195a..8b95467 100644 (file)
@@ -201,6 +201,54 @@ 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 *const clock_list[] = {
        /* four primary clocks -- MUST BE FIRST! */
@@ -223,15 +271,18 @@ static struct clk *const clock_list[] = {
 
        /* MCK and peripherals */
        &mck,
-       // usart0..usart3
-       // mmc
+       &usart0_clk,
+       &usart1_clk,
+       &usart2_clk,
+       &usart3_clk,
+       &mmc_clk,
        &udc_clk,
-       // i2c
-       // spi
+       &twi_clk,
+       &spi_clk,
        // ssc0..ssc2
        // tc0..tc5
        &ohci_clk,
-       // ether
+       &ether_clk,
 };
 
 
@@ -360,7 +411,7 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
                        u32     pckr;
 
                        pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
-                       pckr &= 0x03;
+                       pckr &= AT91_PMC_CSS_PLLB;      /* clock selection */
                        pckr |= prescale << 2;
                        at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
                        clk->rate_hz = actual;
@@ -440,7 +491,7 @@ static int at91_clk_show(struct seq_file *s, void *unused)
                else
                        state = "";
 
-               seq_printf(s, "%-10s users=%d %-3s %9ld Hz %s\n",
+               seq_printf(s, "%-10s users=%2d %-3s %9ld Hz %s\n",
                        clk->name, clk->users, state, clk_get_rate(clk),
                        clk->parent ? clk->parent->name : "");
        }
@@ -483,11 +534,18 @@ 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;
@@ -550,8 +608,8 @@ int __init at91_clock_init(unsigned long main_clock)
        if (!main_clock) {
                do {
                        tmp = at91_sys_read(AT91_CKGR_MCFR);
-               } while (!(tmp & 0x10000));
-               main_clock = (tmp & 0xffff) * (AT91_SLOW_CLOCK / 16);
+               } while (!(tmp & AT91_PMC_MAINRDY));
+               main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16);
        }
        main_clk.rate_hz = main_clock;
 
@@ -566,13 +624,16 @@ 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) | 0x10000000;
+       at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2) | AT91_PMC_USB96M;
        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.