mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
To: barebox@lists.infradead.org
Subject: [PATCH 3/3 v3] at91: implement clock framework
Date: Wed,  4 Aug 2010 08:12:56 +0200	[thread overview]
Message-ID: <1280902376-11891-1-git-send-email-plagnioj@jcrosoft.com> (raw)
In-Reply-To: <1280885595-18026-1-git-send-email-plagnioj@jcrosoft.com>

this implementation is based on linux one (v2.6.35-rc5-76-gd0c6f62)
it will calculate all the clock dynamically instead of statictly
this will use also the new clock framework

it will also print the clock status after the console init

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
v3:

fix typo

Best Regards,
J.
 arch/arm/boards/at91sam9260ek/config.h      |    2 +-
 arch/arm/boards/at91sam9263ek/config.h      |    2 +-
 arch/arm/boards/at91sam9263ek/init.c        |    3 -
 arch/arm/boards/mmccpu/config.h             |    2 +-
 arch/arm/boards/mmccpu/init.c               |    3 -
 arch/arm/boards/pm9263/config.h             |    2 +-
 arch/arm/boards/pm9263/init.c               |    3 -
 arch/arm/mach-at91/Makefile                 |    2 +-
 arch/arm/mach-at91/at91sam9260.c            |  207 ++++++++
 arch/arm/mach-at91/at91sam9260_devices.c    |   18 +-
 arch/arm/mach-at91/at91sam9263.c            |  217 ++++++++
 arch/arm/mach-at91/at91sam9263_devices.c    |   13 +-
 arch/arm/mach-at91/clock.c                  |  718 +++++++++++++++++++++++++++
 arch/arm/mach-at91/clock.h                  |   31 ++
 arch/arm/mach-at91/generic.h                |   14 +
 arch/arm/mach-at91/gpio.c                   |    3 +
 arch/arm/mach-at91/include/mach/at91_dbgu.h |   66 +++
 arch/arm/mach-at91/include/mach/clk.h       |   39 --
 arch/arm/mach-at91/include/mach/cpu.h       |  158 ++++++
 arch/arm/mach-at91/include/mach/gpio.h      |    1 +
 drivers/net/macb.c                          |   11 +-
 drivers/serial/atmel.c                      |   32 +-
 22 files changed, 1472 insertions(+), 75 deletions(-)
 create mode 100644 arch/arm/mach-at91/clock.c
 create mode 100644 arch/arm/mach-at91/clock.h
 create mode 100644 arch/arm/mach-at91/generic.h
 create mode 100644 arch/arm/mach-at91/include/mach/at91_dbgu.h
 delete mode 100644 arch/arm/mach-at91/include/mach/clk.h
 create mode 100644 arch/arm/mach-at91/include/mach/cpu.h

diff --git a/arch/arm/boards/at91sam9260ek/config.h b/arch/arm/boards/at91sam9260ek/config.h
index afd8563..006820c 100644
--- a/arch/arm/boards/at91sam9260ek/config.h
+++ b/arch/arm/boards/at91sam9260ek/config.h
@@ -1,6 +1,6 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define AT91_MASTER_CLOCK  99328000        /* peripheral = main / 2 */
+#define AT91_MAIN_CLOCK		18432000	/* 18.432 MHz crystal */
 
 #endif	/* __CONFIG_H */
diff --git a/arch/arm/boards/at91sam9263ek/config.h b/arch/arm/boards/at91sam9263ek/config.h
index 9cc8af2..bc33227 100644
--- a/arch/arm/boards/at91sam9263ek/config.h
+++ b/arch/arm/boards/at91sam9263ek/config.h
@@ -1,7 +1,7 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define AT91_MASTER_CLOCK 100000000        /* peripheral = main / 2 */
+#define AT91_MAIN_CLOCK		16367660	/* 16.367 MHz crystal */
 
 #define MASTER_PLL_MUL		171
 #define MASTER_PLL_DIV		14
diff --git a/arch/arm/boards/at91sam9263ek/init.c b/arch/arm/boards/at91sam9263ek/init.c
index 21803ca..61cd295 100644
--- a/arch/arm/boards/at91sam9263ek/init.c
+++ b/arch/arm/boards/at91sam9263ek/init.c
@@ -108,9 +108,6 @@ static int at91sam9263ek_devices_init(void)
 	at91_set_gpio_output(AT91_PIN_PB27, 1);
 	at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */
 
-	/* Enable clock */
-	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC);
-
 	at91_add_device_sdram(64 * 1024 * 1024);
 	ek_add_device_nand();
 	at91_add_device_eth(&macb_pdata);
diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h
index 1133b8f..c37d5eb 100644
--- a/arch/arm/boards/mmccpu/config.h
+++ b/arch/arm/boards/mmccpu/config.h
@@ -1,7 +1,7 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define AT91_MASTER_CLOCK	99532800		/* peripheral = main / 2 */
+#define AT91_MAIN_CLOCK		18432000
 
 /* values */
 #define MASTER_PLL_MUL		54
diff --git a/arch/arm/boards/mmccpu/init.c b/arch/arm/boards/mmccpu/init.c
index e010a83..9a7d930 100644
--- a/arch/arm/boards/mmccpu/init.c
+++ b/arch/arm/boards/mmccpu/init.c
@@ -58,9 +58,6 @@ static int mmccpu_devices_init(void)
 	at91_set_gpio_output(AT91_PIN_PB27, 1);
 	at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */
 
-	/* Enable clock */
-	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC);
-
 	at91_add_device_sdram(128 * 1024 * 1024);
 	at91_add_device_eth(&macb_pdata);
 	register_device(&cfi_dev);
diff --git a/arch/arm/boards/pm9263/config.h b/arch/arm/boards/pm9263/config.h
index 9a9c5cd..5252df2 100644
--- a/arch/arm/boards/pm9263/config.h
+++ b/arch/arm/boards/pm9263/config.h
@@ -1,7 +1,7 @@
 #ifndef __CONFIG_H
 #define __CONFIG_H
 
-#define AT91_MASTER_CLOCK  99328000        /* peripheral = main / 2 */
+#define AT91_MAIN_CLOCK	18432000
 
 #define MASTER_PLL_DIV		6
 #define MASTER_PLL_MUL		65
diff --git a/arch/arm/boards/pm9263/init.c b/arch/arm/boards/pm9263/init.c
index 88b91ea..d5ed921 100644
--- a/arch/arm/boards/pm9263/init.c
+++ b/arch/arm/boards/pm9263/init.c
@@ -107,9 +107,6 @@ static int pm9263_devices_init(void)
 	at91_set_gpio_output(AT91_PIN_PB27, 1);
 	at91_set_gpio_value(AT91_PIN_PB27, 1); /* 1- enable, 0 - disable */
 
-	/* Enable clock */
-	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_EMAC);
-
 	at91_add_device_sdram(64 * 1024 * 1024);
 	pm_add_device_nand();
 	at91_add_device_eth(&macb_pdata);
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c848919..0f55883 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -1,4 +1,4 @@
-obj-y += clocksource.o gpio.o
+obj-y += clock.o clocksource.o gpio.o
 
 obj-$(CONFIG_MACH_DO_LOWLEVEL_INIT) += lowlevel_init.o
 
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index 1a6e356..30d1a6a 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -2,22 +2,229 @@
 #include <gpio.h>
 #include <init.h>
 #include <asm/hardware.h>
+#include <mach/at91_pmc.h>
+
+#include "generic.h"
+#include "clock.h"
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioA_clk = {
+	.name		= "pioA_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_PIOA,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+	.name		= "pioB_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_PIOB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioC_clk = {
+	.name		= "pioC_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_PIOC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk adc_clk = {
+	.name		= "adc_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_ADC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+	.name		= "usart0_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_US0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+	.name		= "usart1_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_US1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+	.name		= "usart2_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_US2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc_clk = {
+	.name		= "mci_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_MCI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk udc_clk = {
+	.name		= "udc_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_UDP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi_clk = {
+	.name		= "twi_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TWI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+	.name		= "spi0_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_SPI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+	.name		= "spi1_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_SPI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc_clk = {
+	.name		= "ssc_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_SSC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc0_clk = {
+	.name		= "tc0_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc1_clk = {
+	.name		= "tc1_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc2_clk = {
+	.name		= "tc2_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ohci_clk = {
+	.name		= "ohci_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_UHP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk macb_clk = {
+	.name		= "macb_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_EMAC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk isi_clk = {
+	.name		= "isi_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_ISI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart3_clk = {
+	.name		= "usart3_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_US3,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart4_clk = {
+	.name		= "usart4_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_US4,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart5_clk = {
+	.name		= "usart5_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_US5,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc3_clk = {
+	.name		= "tc3_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC3,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc4_clk = {
+	.name		= "tc4_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC4,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc5_clk = {
+	.name		= "tc5_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC5,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] = {
+	&pioA_clk,
+	&pioB_clk,
+	&pioC_clk,
+	&adc_clk,
+	&usart0_clk,
+	&usart1_clk,
+	&usart2_clk,
+	&mmc_clk,
+	&udc_clk,
+	&twi_clk,
+	&spi0_clk,
+	&spi1_clk,
+	&ssc_clk,
+	&tc0_clk,
+	&tc1_clk,
+	&tc2_clk,
+	&ohci_clk,
+	&macb_clk,
+	&isi_clk,
+	&usart3_clk,
+	&usart4_clk,
+	&usart5_clk,
+	&tc3_clk,
+	&tc4_clk,
+	&tc5_clk,
+	// irq0 .. irq2
+};
+
+/*
+ * The two 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 void __init at91sam9260_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);
+}
+
+/* --------------------------------------------------------------------
+ *  GPIO
+ * -------------------------------------------------------------------- */
 
 static struct at91_gpio_bank at91sam9260_gpio[] = {
 	{
 		.id		= AT91SAM9260_ID_PIOA,
 		.offset		= AT91_PIOA,
+		.clock		= &pioA_clk,
 	}, {
 		.id		= AT91SAM9260_ID_PIOB,
 		.offset		= AT91_PIOB,
+		.clock		= &pioB_clk,
 	}, {
 		.id		= AT91SAM9260_ID_PIOC,
 		.offset		= AT91_PIOC,
+		.clock		= &pioC_clk,
 	}
 };
 
 static int at91sam9260_initialize(void)
 {
+	/* Init clock subsystem */
+	at91_clock_init(AT91_MAIN_CLOCK);
+
+	/* Register the processor-specific clocks */
+	at91sam9260_register_clocks();
+
 	/* Register GPIO subsystem */
 	at91_gpio_init(at91sam9260_gpio, 3);
 	return 0;
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
index 0cfe913..398a721 100644
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ b/arch/arm/mach-at91/at91sam9260_devices.c
@@ -18,6 +18,8 @@
 #include <mach/gpio.h>
 #include <mach/io.h>
 
+#include "generic.h"
+
 static struct memory_platform_data sram_pdata = {
 	.name = "sram0",
 	.flags = DEVFS_RDWR,
@@ -107,8 +109,6 @@ void at91_add_device_nand(struct atmel_nand_data *data)
 	if (data->det_pin)
 		at91_set_gpio_input(data->det_pin, 1);
 
-	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_PIOC);
-
 	nand_dev.platform_data = data;
 	register_device(&nand_dev);
 }
@@ -233,37 +233,37 @@ void at91_register_uart(unsigned id, unsigned pins)
 	switch (id) {
 		case 0:		/* DBGU */
 			configure_dbgu_pins();
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS);
+			at91_clock_associate("mck", &dbgu_serial_device, "usart");
 			register_device(&dbgu_serial_device);
 			break;
 		case AT91SAM9260_ID_US0:
 			configure_usart0_pins(pins);
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US0);
+			at91_clock_associate("usart0_clk", &uart0_serial_device, "usart");
 			register_device(&uart0_serial_device);
 			break;
 		case AT91SAM9260_ID_US1:
 			configure_usart1_pins(pins);
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US1);
+			at91_clock_associate("usart1_clk", &uart1_serial_device, "usart");
 			register_device(&uart1_serial_device);
 			break;
 		case AT91SAM9260_ID_US2:
 			configure_usart2_pins(pins);
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US2);
+			at91_clock_associate("usart2_clk", &uart2_serial_device, "usart");
 			register_device(&uart2_serial_device);
 			break;
 		case AT91SAM9260_ID_US3:
 			configure_usart3_pins(pins);
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US3);
+			at91_clock_associate("usart3_clk", &uart3_serial_device, "usart");
 			register_device(&uart3_serial_device);
 			break;
 		case AT91SAM9260_ID_US4:
 			configure_usart4_pins();
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US4);
+			at91_clock_associate("usart4_clk", &uart4_serial_device, "usart");
 			register_device(&uart4_serial_device);
 			break;
 		case AT91SAM9260_ID_US5:
 			configure_usart5_pins();
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9260_ID_US5);
+			at91_clock_associate("usart5_clk", &uart5_serial_device, "usart");
 			register_device(&uart5_serial_device);
 			break;
 		default:
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index 472b619..b0e3193 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -2,28 +2,245 @@
 #include <gpio.h>
 #include <init.h>
 #include <asm/hardware.h>
+#include <mach/at91_pmc.h>
+
+#include "clock.h"
+#include "generic.h"
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioA_clk = {
+	.name		= "pioA_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PIOA,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+	.name		= "pioB_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PIOB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioCDE_clk = {
+	.name		= "pioCDE_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PIOCDE,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+	.name		= "usart0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_US0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+	.name		= "usart1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_US1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+	.name		= "usart2_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_US2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc0_clk = {
+	.name		= "mci0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_MCI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+	.name		= "mci1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_MCI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk can_clk = {
+	.name		= "can_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_CAN,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi_clk = {
+	.name		= "twi_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_TWI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+	.name		= "spi0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SPI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+	.name		= "spi1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SPI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc0_clk = {
+	.name		= "ssc0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SSC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ssc1_clk = {
+	.name		= "ssc1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SSC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ac97_clk = {
+	.name		= "ac97_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_AC97C,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb_clk = {
+	.name		= "tcb_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_TCB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pwm_clk = {
+	.name		= "pwm_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PWMC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk macb_clk = {
+	.name		= "macb_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_EMAC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk dma_clk = {
+	.name		= "dma_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_DMA,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twodge_clk = {
+	.name		= "2dge_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_2DGE,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk udc_clk = {
+	.name		= "udc_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_UDP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk isi_clk = {
+	.name		= "isi_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_ISI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk lcdc_clk = {
+	.name		= "lcdc_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_LCDC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ohci_clk = {
+	.name		= "ohci_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_UHP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] = {
+	&pioA_clk,
+	&pioB_clk,
+	&pioCDE_clk,
+	&usart0_clk,
+	&usart1_clk,
+	&usart2_clk,
+	&mmc0_clk,
+	&mmc1_clk,
+	&can_clk,
+	&twi_clk,
+	&spi0_clk,
+	&spi1_clk,
+	&ssc0_clk,
+	&ssc1_clk,
+	&ac97_clk,
+	&tcb_clk,
+	&pwm_clk,
+	&macb_clk,
+	&twodge_clk,
+	&udc_clk,
+	&isi_clk,
+	&lcdc_clk,
+	&dma_clk,
+	&ohci_clk,
+	// irq0 .. irq1
+};
+
+/*
+ * 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 at91sam9263_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);
+}
+
+/* --------------------------------------------------------------------
+ *  GPIO
+ * -------------------------------------------------------------------- */
 
 static struct at91_gpio_bank at91sam9263_gpio[] = {
 	{
 		.id		= AT91SAM9263_ID_PIOA,
 		.offset		= AT91_PIOA,
+		.clock		= &pioA_clk,
 	}, {
 		.id		= AT91SAM9263_ID_PIOB,
 		.offset		= AT91_PIOB,
+		.clock		= &pioB_clk,
 	}, {
 		.id		= AT91SAM9263_ID_PIOCDE,
 		.offset		= AT91_PIOC,
+		.clock		= &pioCDE_clk,
 	}, {
 		.id		= AT91SAM9263_ID_PIOCDE,
 		.offset		= AT91_PIOD,
+		.clock		= &pioCDE_clk,
 	}, {
 		.id		= AT91SAM9263_ID_PIOCDE,
 		.offset		= AT91_PIOE,
+		.clock		= &pioCDE_clk,
 	}
 };
 
 static int at91sam9263_initialize(void)
 {
+	/* Init clock subsystem */
+	at91_clock_init(AT91_MAIN_CLOCK);
+
+	/* Register the processor-specific clocks */
+	at91sam9263_register_clocks();
+
 	/* Register GPIO subsystem */
 	at91_gpio_init(at91sam9263_gpio, 5);
 	return 0;
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
index 50a6348..7ebc32c 100644
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ b/arch/arm/mach-at91/at91sam9263_devices.c
@@ -18,6 +18,8 @@
 #include <mach/gpio.h>
 #include <mach/io.h>
 
+#include "generic.h"
+
 static struct memory_platform_data ram_pdata = {
 	.name = "ram0",
 	.flags = DEVFS_RDWR,
@@ -106,9 +108,6 @@ void at91_add_device_nand(struct atmel_nand_data *data)
 	if (data->det_pin)
 		at91_set_gpio_input(data->det_pin, 1);
 
-	at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_PIOA |
-				      1 << AT91SAM9263_ID_PIOCDE);
-
 	nand_dev.platform_data = data;
 	register_device(&nand_dev);
 }
@@ -184,22 +183,22 @@ void at91_register_uart(unsigned id, unsigned pins)
 	switch (id) {
 		case 0:		/* DBGU */
 			configure_dbgu_pins();
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91_ID_SYS);
+			at91_clock_associate("mck", &dbgu_serial_device, "usart");
 			register_device(&dbgu_serial_device);
 			break;
 		case AT91SAM9263_ID_US0:
 			configure_usart0_pins(pins);
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US0);
+			at91_clock_associate("usart0_clk", &uart0_serial_device, "usart");
 			register_device(&uart0_serial_device);
 			break;
 		case AT91SAM9263_ID_US1:
 			configure_usart1_pins(pins);
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US1);
+			at91_clock_associate("usart1_clk", &uart1_serial_device, "usart");
 			register_device(&uart1_serial_device);
 			break;
 		case AT91SAM9263_ID_US2:
 			configure_usart2_pins(pins);
-			at91_sys_write(AT91_PMC_PCER, 1 << AT91SAM9263_ID_US2);
+			at91_clock_associate("usart2_clk", &uart2_serial_device, "usart");
 			register_device(&uart2_serial_device);
 			break;
 		default:
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
new file mode 100644
index 0000000..6fd09d5
--- /dev/null
+++ b/arch/arm/mach-at91/clock.c
@@ -0,0 +1,718 @@
+/*
+ * linux/arch/arm/mach-at91/clock.c
+ *
+ * Copyright (C) 2005 David Brownell
+ * Copyright (C) 2005 Ivan Kokshaysky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <common.h>
+#include <linux/list.h>
+#include <errno.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <init.h>
+
+#include <mach/hardware.h>
+#include <mach/io.h>
+#include <mach/at91_pmc.h>
+#include <mach/cpu.h>
+
+#include "clock.h"
+#include "generic.h"
+
+/*
+ * There's a lot more which can be done with clocks, including cpufreq
+ * integration, slow clock mode support (for system suspend), letting
+ * PLLB be used at other rates (on boards that don't need USB), etc.
+ */
+
+#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)
+#define clk_is_sys(x)		((x)->type & CLK_TYPE_SYSTEM)
+
+
+/*
+ * Chips have some kind of clocks : group them by functionality
+ */
+#define cpu_has_utmi()		(  cpu_is_at91cap9() \
+				|| cpu_is_at91sam9rl() \
+				|| cpu_is_at91sam9g45())
+
+#define cpu_has_800M_plla()	(  cpu_is_at91sam9g20() \
+				|| cpu_is_at91sam9g45())
+
+#define cpu_has_300M_plla()	(cpu_is_at91sam9g10())
+
+#define cpu_has_pllb()		(!(cpu_is_at91sam9rl() \
+				|| cpu_is_at91sam9g45()))
+
+#define cpu_has_upll()		(cpu_is_at91sam9g45())
+
+/* USB host HS & FS */
+#define cpu_has_uhp()		(!cpu_is_at91sam9rl())
+
+/* USB device FS only */
+#define cpu_has_udpfs()		(!(cpu_is_at91sam9rl() \
+				|| cpu_is_at91sam9g45()))
+
+static LIST_HEAD(clocks);
+
+static u32 at91_pllb_usb_init;
+
+/*
+ * Four primary clock sources:  two crystal oscillators (32K, main), and
+ * two PLLs.  PLLA usually runs the master clock; and PLLB must run at
+ * 48 MHz (unless no USB function clocks are needed).  The main clock and
+ * both PLLs are turned off to run in "slow clock mode" (system suspend).
+ */
+static struct clk clk32k = {
+	.name		= "clk32k",
+	.rate_hz	= AT91_SLOW_CLOCK,
+	.users		= 1,		/* always on */
+	.id		= 0,
+	.type		= CLK_TYPE_PRIMARY,
+};
+static struct clk main_clk = {
+	.name		= "main",
+	.pmc_mask	= AT91_PMC_MOSCS,	/* in PMC_SR */
+	.id		= 1,
+	.type		= CLK_TYPE_PRIMARY,
+};
+static struct clk plla = {
+	.name		= "plla",
+	.parent		= &main_clk,
+	.pmc_mask	= AT91_PMC_LOCKA,	/* in PMC_SR */
+	.id		= 2,
+	.type		= CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
+};
+
+static void pllb_mode(struct clk *clk, int is_on)
+{
+	u32	value;
+
+	if (is_on) {
+		is_on = AT91_PMC_LOCKB;
+		value = at91_pllb_usb_init;
+	} else
+		value = 0;
+
+	// REVISIT: Add work-around for AT91RM9200 Errata #26 ?
+	at91_sys_write(AT91_CKGR_PLLBR, value);
+
+	do {
+		barrier();
+	} while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on);
+}
+
+static struct clk pllb = {
+	.name		= "pllb",
+	.parent		= &main_clk,
+	.pmc_mask	= AT91_PMC_LOCKB,	/* in PMC_SR */
+	.mode		= pllb_mode,
+	.id		= 3,
+	.type		= CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
+};
+
+static void pmc_sys_mode(struct clk *clk, int is_on)
+{
+	if (is_on)
+		at91_sys_write(AT91_PMC_SCER, clk->pmc_mask);
+	else
+		at91_sys_write(AT91_PMC_SCDR, clk->pmc_mask);
+}
+
+static void pmc_uckr_mode(struct clk *clk, int is_on)
+{
+	unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
+
+	if (cpu_is_at91sam9g45()) {
+		if (is_on)
+			uckr |= AT91_PMC_BIASEN;
+		else
+			uckr &= ~AT91_PMC_BIASEN;
+	}
+
+	if (is_on) {
+		is_on = AT91_PMC_LOCKU;
+		at91_sys_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
+	} else
+		at91_sys_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask));
+
+	do {
+		barrier();
+	} while ((at91_sys_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on);
+}
+
+/* USB function clocks (PLLB must be 48 MHz) */
+static struct clk udpck = {
+	.name		= "udpck",
+	.parent		= &pllb,
+	.mode		= pmc_sys_mode,
+};
+static struct clk utmi_clk = {
+	.name		= "utmi_clk",
+	.parent		= &main_clk,
+	.pmc_mask	= AT91_PMC_UPLLEN,	/* in CKGR_UCKR */
+	.mode		= pmc_uckr_mode,
+	.type		= CLK_TYPE_PLL,
+};
+static struct clk uhpck = {
+	.name		= "uhpck",
+	/*.parent		= ... we choose parent at runtime */
+	.mode		= pmc_sys_mode,
+};
+
+
+/*
+ * The master clock is divided from the CPU clock (by 1-4).  It's used for
+ * memory, interfaces to on-chip peripherals, the AIC, and sometimes more
+ * (e.g baud rate generation).  It's sourced from one of the primary clocks.
+ */
+static struct clk mck = {
+	.name		= "mck",
+	.pmc_mask	= AT91_PMC_MCKRDY,	/* in PMC_SR */
+};
+
+static void pmc_periph_mode(struct clk *clk, int is_on)
+{
+	if (is_on)
+		at91_sys_write(AT91_PMC_PCER, clk->pmc_mask);
+	else
+		at91_sys_write(AT91_PMC_PCDR, clk->pmc_mask);
+}
+
+static struct clk *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:
+			if (cpu_has_upll())
+				/* CSS_PLLB == CSS_UPLL */
+				return &utmi_clk;
+			else if (cpu_has_pllb())
+				return &pllb;
+	}
+
+	return NULL;
+}
+
+/*
+ * 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 at91_clock_associate(const char *id, struct device_d *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 cannot be de-registered no refcounting necessary */
+struct clk *clk_get(struct device_d *dev, const char *id)
+{
+	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)
+			return clk;
+	}
+
+	return ERR_PTR(-ENOENT);
+}
+EXPORT_SYMBOL(clk_get);
+
+void clk_put(struct clk *clk)
+{
+}
+EXPORT_SYMBOL(clk_put);
+
+static void __clk_enable(struct clk *clk)
+{
+	if (clk->parent)
+		__clk_enable(clk->parent);
+	if (clk->users++ == 0 && clk->mode)
+		clk->mode(clk, 1);
+}
+
+int clk_enable(struct clk *clk)
+{
+	__clk_enable(clk);
+	return 0;
+}
+EXPORT_SYMBOL(clk_enable);
+
+static void __clk_disable(struct clk *clk)
+{
+	BUG_ON(clk->users == 0);
+	if (--clk->users == 0 && clk->mode)
+		clk->mode(clk, 0);
+	if (clk->parent)
+		__clk_disable(clk->parent);
+}
+
+void clk_disable(struct clk *clk)
+{
+	__clk_disable(clk);
+}
+EXPORT_SYMBOL(clk_disable);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long	rate;
+
+	for (;;) {
+		rate = clk->rate_hz;
+		if (rate || !clk->parent)
+			break;
+		clk = clk->parent;
+	}
+	return rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/*------------------------------------------------------------------------*/
+
+#ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
+
+/*
+ * For now, only the programmable clocks support reparenting (MCK could
+ * do this too, with care) or rate changing (the PLLs could do this too,
+ * ditto MCK but that's more for cpufreq).  Drivers may reparent to get
+ * a better rate match; we don't.
+ */
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long	flags;
+	unsigned	prescale;
+	unsigned long	actual;
+	unsigned long	prev = ULONG_MAX;
+
+	if (!clk_is_programmable(clk))
+		return -EINVAL;
+
+	actual = clk->parent->rate_hz;
+	for (prescale = 0; prescale < 7; prescale++) {
+		if (actual > rate)
+			prev = actual;
+
+		if (actual && actual <= rate) {
+			if ((prev - rate) < (rate - actual)) {
+				actual = prev;
+				prescale--;
+			}
+			break;
+		}
+		actual >>= 1;
+	}
+
+	return (prescale < 7) ? actual : -ENOENT;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long	flags;
+	unsigned	prescale;
+	unsigned long	actual;
+
+	if (!clk_is_programmable(clk))
+		return -EINVAL;
+	if (clk->users)
+		return -EBUSY;
+
+	actual = clk->parent->rate_hz;
+	for (prescale = 0; prescale < 7; prescale++) {
+		if (actual && actual <= rate) {
+			u32	pckr;
+
+			pckr = at91_sys_read(AT91_PMC_PCKR(clk->id));
+			pckr &= AT91_PMC_CSS;	/* clock selection */
+			pckr |= prescale << 2;
+			at91_sys_write(AT91_PMC_PCKR(clk->id), pckr);
+			clk->rate_hz = actual;
+			break;
+		}
+		actual >>= 1;
+	}
+
+	return (prescale < 7) ? actual : -ENOENT;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	unsigned long	flags;
+
+	if (clk->users)
+		return -EBUSY;
+	if (!clk_is_primary(parent) || !clk_is_programmable(clk))
+		return -EINVAL;
+
+	if (cpu_is_at91sam9rl() && parent->id == AT91_PMC_CSS_PLLB)
+		return -EINVAL;
+
+	clk->rate_hz = parent->rate_hz;
+	clk->parent = parent;
+	at91_sys_write(AT91_PMC_PCKR(clk->id), parent->id);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+/* establish PCK0..PCKN 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 & AT91_PMC_PRES) >> 2));
+}
+
+#endif	/* CONFIG_AT91_PROGRAMMABLE_CLOCKS */
+
+/*------------------------------------------------------------------------*/
+
+/* Register a new clock */
+int clk_register(struct clk *clk)
+{
+	if (clk_is_peripheral(clk)) {
+		clk->parent = &mck;
+		clk->mode = pmc_periph_mode;
+		list_add_tail(&clk->node, &clocks);
+	}
+	else if (clk_is_sys(clk)) {
+		clk->parent = &mck;
+		clk->mode = pmc_sys_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 at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
+{
+	unsigned mul, div;
+
+	div = reg & 0xff;
+	mul = (reg >> 16) & 0x7ff;
+	if (div && mul) {
+		freq /= div;
+		freq *= mul + 1;
+	} else
+		freq = 0;
+
+	return freq;
+}
+
+static u32 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 at91_pll_calc(unsigned main_freq, unsigned out_freq)
+{
+	unsigned i, div = 0, mul = 0, diff = 1 << 30;
+	unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00;
+
+	/* PLL output max 240 MHz (or 180 MHz per errata) */
+	if (out_freq > 240000000)
+		goto fail;
+
+	for (i = 1; i < 256; i++) {
+		int diff1;
+		unsigned input, mul1;
+
+		/*
+		 * PLL input between 1MHz and 32MHz per spec, but lower
+		 * frequences seem necessary in some cases so allow 100K.
+		 * Warning: some newer products need 2MHz min.
+		 */
+		input = main_freq / i;
+		if (cpu_is_at91sam9g20() && input < 2000000)
+			continue;
+		if (input < 100000)
+			continue;
+		if (input > 32000000)
+			continue;
+
+		mul1 = out_freq / input;
+		if (cpu_is_at91sam9g20() && mul > 63)
+			continue;
+		if (mul1 > 2048)
+			continue;
+		if (mul1 < 2)
+			goto fail;
+
+		diff1 = out_freq - input * mul1;
+		if (diff1 < 0)
+			diff1 = -diff1;
+		if (diff > diff1) {
+			diff = diff1;
+			div = i;
+			mul = mul1;
+			if (diff == 0)
+				break;
+		}
+	}
+	if (i == 256 && diff > (out_freq >> 5))
+		goto fail;
+	return ret | ((mul - 1) << 16) | div;
+fail:
+	return 0;
+}
+
+static struct clk *const standard_pmc_clocks[] = {
+	/* four primary clocks */
+	&clk32k,
+	&main_clk,
+	&plla,
+
+	/* MCK */
+	&mck
+};
+
+/* PLLB generated USB full speed clock init */
+static void at91_pllb_usbfs_clock_init(unsigned long main_clock)
+{
+	/*
+	 * USB clock init:  choose 48 MHz PLLB value,
+	 * disable 48MHz clock during usb peripheral suspend.
+	 *
+	 * REVISIT:  assumes MCK doesn't derive from PLLB!
+	 */
+	uhpck.parent = &pllb;
+
+	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);
+	if (cpu_is_at91rm9200()) {
+		uhpck.pmc_mask = AT91RM9200_PMC_UHP;
+		udpck.pmc_mask = AT91RM9200_PMC_UDP;
+		at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
+	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
+		   cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
+		   cpu_is_at91sam9g10() || cpu_is_at572d940hf()) {
+		uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
+		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
+	} else if (cpu_is_at91cap9()) {
+		uhpck.pmc_mask = AT91CAP9_PMC_UHP;
+	}
+	at91_sys_write(AT91_CKGR_PLLBR, 0);
+
+	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);
+}
+
+/* UPLL generated USB full speed clock init */
+static void at91_upll_usbfs_clock_init(unsigned long main_clock)
+{
+	/*
+	 * USB clock init: choose 480 MHz from UPLL,
+	 */
+	unsigned int usbr = AT91_PMC_USBS_UPLL;
+
+	/* Setup divider by 10 to reach 48 MHz */
+	usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV;
+
+	at91_sys_write(AT91_PMC_USB, usbr);
+
+	/* Now set uhpck values */
+	uhpck.parent = &utmi_clk;
+	uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
+	uhpck.rate_hz = utmi_clk.parent->rate_hz;
+	uhpck.rate_hz /= 1 + ((at91_sys_read(AT91_PMC_USB) & AT91_PMC_OHCIUSBDIV) >> 8);
+}
+
+static int pll_overclock = 0;
+
+int at91_clock_init(unsigned long main_clock)
+{
+	unsigned tmp, freq, mckr;
+	int i;
+
+	/*
+	 * When the bootloader initialized the main oscillator correctly,
+	 * there's no problem using the cycle counter.  But if it didn't,
+	 * or when using oscillator bypass mode, we must be told the speed
+	 * of the 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);
+	}
+	main_clk.rate_hz = main_clock;
+
+	/* report if PLLA is more than mildly overclocked */
+	plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_sys_read(AT91_CKGR_PLLAR));
+	if (cpu_has_300M_plla()) {
+		if (plla.rate_hz > 300000000)
+			pll_overclock = 1;
+	} else if (cpu_has_800M_plla()) {
+		if (plla.rate_hz > 800000000)
+			pll_overclock = 1;
+	} else {
+		if (plla.rate_hz > 209000000)
+			pll_overclock = 1;
+	}
+
+	if (cpu_is_at91sam9g45()) {
+		mckr = at91_sys_read(AT91_PMC_MCKR);
+		plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12));	/* plla divisor by 2 */
+	}
+
+	if (!cpu_has_pllb() && cpu_has_upll()) {
+		/* setup UTMI clock as the fourth primary clock
+		 * (instead of pllb) */
+		utmi_clk.type |= CLK_TYPE_PRIMARY;
+		utmi_clk.id = 3;
+	}
+
+	/*
+	 * USB HS clock init
+	 */
+	if (cpu_has_utmi()) {
+		/*
+		 * multiplier is hard-wired to 40
+		 * (obtain the USB High Speed 480 MHz when input is 12 MHz)
+		 */
+		utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
+	}
+
+	/*
+	 * USB FS clock init
+	 */
+	if (cpu_has_pllb())
+		at91_pllb_usbfs_clock_init(main_clock);
+	if (cpu_has_upll())
+		/* assumes that we choose UPLL for USB and not PLLA */
+		at91_upll_usbfs_clock_init(main_clock);
+
+	/*
+	 * 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 = at91_css_to_clk(mckr & AT91_PMC_CSS);
+	freq = mck.parent->rate_hz;
+	freq /= (1 << ((mckr & AT91_PMC_PRES) >> 2));				/* prescale */
+	if (cpu_is_at91rm9200()) {
+		mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8));	/* mdiv */
+	} else if (cpu_is_at91sam9g20()) {
+		mck.rate_hz = (mckr & AT91_PMC_MDIV) ?
+			freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq;	/* mdiv ; (x >> 7) = ((x >> 8) * 2) */
+		if (mckr & AT91_PMC_PDIV)
+			freq /= 2;		/* processor clock division */
+	} else if (cpu_is_at91sam9g45()) {
+		mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
+			freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));	/* mdiv */
+	} else {
+		mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8));      /* 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);
+
+	if (cpu_has_pllb())
+		list_add_tail(&pllb.node, &clocks);
+
+	if (cpu_has_uhp())
+		list_add_tail(&uhpck.node, &clocks);
+
+	if (cpu_has_udpfs())
+		list_add_tail(&udpck.node, &clocks);
+
+	if (cpu_has_utmi())
+		list_add_tail(&utmi_clk.node, &clocks);
+
+	/* MCK and CPU clock are "always on" */
+	clk_enable(&mck);
+
+	return 0;
+}
+
+static int at91_clock_display(void)
+{
+	if (pll_overclock)
+		pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
+
+	printf("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n",
+		mck.parent->rate_hz / 1000000, (unsigned) mck.rate_hz / 1000000,
+		(unsigned) main_clk.rate_hz / 1000000,
+		((unsigned) main_clk.rate_hz % 1000000) / 1000);
+
+	return 0;
+}
+postconsole_initcall(at91_clock_display);
+
+/*
+ * Several unused clocks may be active.  Turn them off.
+ */
+static int at91_clock_reset(void)
+{
+	unsigned long pcdr = 0;
+	unsigned long scdr = 0;
+	struct clk *clk;
+
+	list_for_each_entry(clk, &clocks, node) {
+		if (clk->users > 0)
+			continue;
+
+		if (clk->mode == pmc_periph_mode)
+			pcdr |= clk->pmc_mask;
+
+		if (clk->mode == pmc_sys_mode)
+			scdr |= clk->pmc_mask;
+
+		pr_debug("Clocks: disable unused %s\n", clk->name);
+	}
+
+	at91_sys_write(AT91_PMC_PCDR, pcdr);
+	at91_sys_write(AT91_PMC_SCDR, scdr);
+
+	return 0;
+}
+late_initcall(at91_clock_reset);
diff --git a/arch/arm/mach-at91/clock.h b/arch/arm/mach-at91/clock.h
new file mode 100644
index 0000000..c8ecd0c
--- /dev/null
+++ b/arch/arm/mach-at91/clock.h
@@ -0,0 +1,31 @@
+/*
+ * linux/arch/arm/mach-at91/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
+#define CLK_TYPE_SYSTEM		0x10
+
+
+struct clk {
+	struct list_head node;
+	const char	*name;		/* unique clock name */
+	const char	*function;	/* function of the clock */
+	struct device_d	*dev;		/* device associated with function */
+	unsigned long	rate_hz;
+	struct clk	*parent;
+	u32		pmc_mask;
+	void		(*mode)(struct clk *, int);
+	unsigned	id:3;		/* PCK0..4, or 32k/main/a/b */
+	unsigned	type;		/* clock type */
+	u16		users;
+};
+
+
+extern int __init clk_register(struct clk *clk);
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
new file mode 100644
index 0000000..b3a029d
--- /dev/null
+++ b/arch/arm/mach-at91/generic.h
@@ -0,0 +1,14 @@
+/*
+ * linux/arch/arm/mach-at91/generic.h
+ *
+ *  Copyright (C) 2005 David Brownell
+ *
+ * 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.
+ */
+
+ /* Clocks */
+extern int __init at91_clock_init(unsigned long main_clock);
+struct device_d;
+extern void __init at91_clock_associate(const char *id, struct device_d *dev, const char *func);
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
index 1cafaf7..b257128 100644
--- a/arch/arm/mach-at91/gpio.c
+++ b/arch/arm/mach-at91/gpio.c
@@ -22,6 +22,7 @@
  */
 
 #include <common.h>
+#include <linux/clk.h>
 #include <errno.h>
 #include <asm/io.h>
 #include <mach/gpio.h>
@@ -245,6 +246,8 @@ int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
 		data->regbase = data->offset +
 			(void __iomem *)AT91_BASE_SYS;
 
+		/* enable PIO controller's clock */
+		clk_enable(data->clock);
 
 		/* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
 		if (last && last->id == data->id)
diff --git a/arch/arm/mach-at91/include/mach/at91_dbgu.h b/arch/arm/mach-at91/include/mach/at91_dbgu.h
new file mode 100644
index 0000000..6dcaa77
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/at91_dbgu.h
@@ -0,0 +1,66 @@
+/*
+ * arch/arm/mach-at91/include/mach/at91_dbgu.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Debug Unit (DBGU) - System peripherals registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91_DBGU_H
+#define AT91_DBGU_H
+
+#ifdef AT91_DBGU
+#define AT91_DBGU_CR		(AT91_DBGU + 0x00)	/* Control Register */
+#define AT91_DBGU_MR		(AT91_DBGU + 0x04)	/* Mode Register */
+#define AT91_DBGU_IER		(AT91_DBGU + 0x08)	/* Interrupt Enable Register */
+#define		AT91_DBGU_TXRDY		(1 << 1)		/* Transmitter Ready */
+#define		AT91_DBGU_TXEMPTY	(1 << 9)		/* Transmitter Empty */
+#define AT91_DBGU_IDR		(AT91_DBGU + 0x0c)	/* Interrupt Disable Register */
+#define AT91_DBGU_IMR		(AT91_DBGU + 0x10)	/* Interrupt Mask Register */
+#define AT91_DBGU_SR		(AT91_DBGU + 0x14)	/* Status Register */
+#define AT91_DBGU_RHR		(AT91_DBGU + 0x18)	/* Receiver Holding Register */
+#define AT91_DBGU_THR		(AT91_DBGU + 0x1c)	/* Transmitter Holding Register */
+#define AT91_DBGU_BRGR		(AT91_DBGU + 0x20)	/* Baud Rate Generator Register */
+
+#define AT91_DBGU_CIDR		(AT91_DBGU + 0x40)	/* Chip ID Register */
+#define AT91_DBGU_EXID		(AT91_DBGU + 0x44)	/* Chip ID Extension Register */
+#define AT91_DBGU_FNR		(AT91_DBGU + 0x48)	/* Force NTRST Register [SAM9 only] */
+#define		AT91_DBGU_FNTRST	(1 << 0)		/* Force NTRST */
+
+#endif /* AT91_DBGU */
+
+/*
+ * Some AT91 parts that don't have full DEBUG units still support the ID
+ * and extensions register.
+ */
+#define		AT91_CIDR_VERSION	(0x1f << 0)		/* Version of the Device */
+#define		AT91_CIDR_EPROC		(7    << 5)		/* Embedded Processor */
+#define		AT91_CIDR_NVPSIZ	(0xf  << 8)		/* Nonvolatile Program Memory Size */
+#define		AT91_CIDR_NVPSIZ2	(0xf  << 12)		/* Second Nonvolatile Program Memory Size */
+#define		AT91_CIDR_SRAMSIZ	(0xf  << 16)		/* Internal SRAM Size */
+#define			AT91_CIDR_SRAMSIZ_1K	(1 << 16)
+#define			AT91_CIDR_SRAMSIZ_2K	(2 << 16)
+#define			AT91_CIDR_SRAMSIZ_112K	(4 << 16)
+#define			AT91_CIDR_SRAMSIZ_4K	(5 << 16)
+#define			AT91_CIDR_SRAMSIZ_80K	(6 << 16)
+#define			AT91_CIDR_SRAMSIZ_160K	(7 << 16)
+#define			AT91_CIDR_SRAMSIZ_8K	(8 << 16)
+#define			AT91_CIDR_SRAMSIZ_16K	(9 << 16)
+#define			AT91_CIDR_SRAMSIZ_32K	(10 << 16)
+#define			AT91_CIDR_SRAMSIZ_64K	(11 << 16)
+#define			AT91_CIDR_SRAMSIZ_128K	(12 << 16)
+#define			AT91_CIDR_SRAMSIZ_256K	(13 << 16)
+#define			AT91_CIDR_SRAMSIZ_96K	(14 << 16)
+#define			AT91_CIDR_SRAMSIZ_512K	(15 << 16)
+#define		AT91_CIDR_ARCH		(0xff << 20)		/* Architecture Identifier */
+#define		AT91_CIDR_NVPTYP	(7    << 28)		/* Nonvolatile Program Memory Type */
+#define		AT91_CIDR_EXT		(1    << 31)		/* Extension Flag */
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/clk.h b/arch/arm/mach-at91/include/mach/clk.h
deleted file mode 100644
index a9c0683..0000000
--- a/arch/arm/mach-at91/include/mach/clk.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * (C) Copyright 2007
- * Stelian Pop <stelian.pop@leadtechdesign.com>
- * Lead Tech Design <www.leadtechdesign.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
- */
-#ifndef __ASM_ARM_ARCH_CLK_H__
-#define __ASM_ARM_ARCH_CLK_H__
-
-#include <mach/hardware.h>
-
-static inline unsigned long get_macb_pclk_rate(unsigned int dev_id)
-{
-	return AT91_MASTER_CLOCK;
-}
-
-static inline unsigned long get_usart_clk_rate(unsigned int dev_id)
-{
-	return AT91_MASTER_CLOCK;
-}
-
-#endif /* __ASM_ARM_ARCH_CLK_H__ */
diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
new file mode 100644
index 0000000..833659d
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -0,0 +1,158 @@
+/*
+ * arch/arm/mach-at91/include/mach/cpu.h
+ *
+ *  Copyright (C) 2006 SAN People
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#ifndef __ASM_ARCH_CPU_H
+#define __ASM_ARCH_CPU_H
+
+#include <mach/hardware.h>
+#include <mach/at91_dbgu.h>
+
+
+#define ARCH_ID_AT91RM9200	0x09290780
+#define ARCH_ID_AT91SAM9260	0x019803a0
+#define ARCH_ID_AT91SAM9261	0x019703a0
+#define ARCH_ID_AT91SAM9263	0x019607a0
+#define ARCH_ID_AT91SAM9G10	0x019903a0
+#define ARCH_ID_AT91SAM9G20	0x019905a0
+#define ARCH_ID_AT91SAM9RL64	0x019b03a0
+#define ARCH_ID_AT91SAM9G45	0x819b05a0
+#define ARCH_ID_AT91SAM9G45MRL	0x819b05a2	/* aka 9G45-ES2 & non ES lots */
+#define ARCH_ID_AT91SAM9G45ES	0x819b05a1	/* 9G45-ES (Engineering Sample) */
+#define ARCH_ID_AT91CAP9	0x039A03A0
+
+#define ARCH_ID_AT91SAM9XE128	0x329973a0
+#define ARCH_ID_AT91SAM9XE256	0x329a93a0
+#define ARCH_ID_AT91SAM9XE512	0x329aa3a0
+
+#define ARCH_ID_AT572D940HF	0x0e0303e0
+
+#define ARCH_ID_AT91M40800	0x14080044
+#define ARCH_ID_AT91R40807	0x44080746
+#define ARCH_ID_AT91M40807	0x14080745
+#define ARCH_ID_AT91R40008	0x44000840
+
+static inline unsigned long at91_cpu_identify(void)
+{
+	return (at91_sys_read(AT91_DBGU_CIDR) & ~AT91_CIDR_VERSION);
+}
+
+static inline unsigned long at91_cpu_fully_identify(void)
+{
+	return at91_sys_read(AT91_DBGU_CIDR);
+}
+
+#define ARCH_EXID_AT91SAM9M11	0x00000001
+#define ARCH_EXID_AT91SAM9M10	0x00000002
+#define ARCH_EXID_AT91SAM9G45	0x00000004
+
+static inline unsigned long at91_exid_identify(void)
+{
+	return at91_sys_read(AT91_DBGU_EXID);
+}
+
+
+#define ARCH_FAMILY_AT91X92	0x09200000
+#define ARCH_FAMILY_AT91SAM9	0x01900000
+#define ARCH_FAMILY_AT91SAM9XE	0x02900000
+
+static inline unsigned long at91_arch_identify(void)
+{
+	return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH);
+}
+
+#ifdef CONFIG_ARCH_AT91CAP9
+#include <mach/at91_pmc.h>
+
+#define ARCH_REVISION_CAP9_B	0x399
+#define ARCH_REVISION_CAP9_C	0x601
+
+static inline unsigned long at91cap9_rev_identify(void)
+{
+	return (at91_sys_read(AT91_PMC_VER));
+}
+#endif
+
+#ifdef CONFIG_ARCH_AT91RM9200
+#define cpu_is_at91rm9200()	(at91_cpu_identify() == ARCH_ID_AT91RM9200)
+#else
+#define cpu_is_at91rm9200()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91SAM9260
+#define cpu_is_at91sam9xe()	(at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE)
+#define cpu_is_at91sam9260()	((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe())
+#else
+#define cpu_is_at91sam9xe()	(0)
+#define cpu_is_at91sam9260()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91SAM9G20
+#define cpu_is_at91sam9g20()	(at91_cpu_identify() == ARCH_ID_AT91SAM9G20)
+#else
+#define cpu_is_at91sam9g20()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91SAM9261
+#define cpu_is_at91sam9261()	(at91_cpu_identify() == ARCH_ID_AT91SAM9261)
+#else
+#define cpu_is_at91sam9261()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91SAM9G10
+#define cpu_is_at91sam9g10()	((at91_cpu_identify() & ~AT91_CIDR_EXT)	== ARCH_ID_AT91SAM9G10)
+#else
+#define cpu_is_at91sam9g10()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91SAM9263
+#define cpu_is_at91sam9263()	(at91_cpu_identify() == ARCH_ID_AT91SAM9263)
+#else
+#define cpu_is_at91sam9263()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91SAM9RL
+#define cpu_is_at91sam9rl()	(at91_cpu_identify() == ARCH_ID_AT91SAM9RL64)
+#else
+#define cpu_is_at91sam9rl()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91SAM9G45
+#define cpu_is_at91sam9g45()	(at91_cpu_identify() == ARCH_ID_AT91SAM9G45)
+#define cpu_is_at91sam9g45es()	(at91_cpu_fully_identify() == ARCH_ID_AT91SAM9G45ES)
+#else
+#define cpu_is_at91sam9g45()	(0)
+#define cpu_is_at91sam9g45es()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT91CAP9
+#define cpu_is_at91cap9()	(at91_cpu_identify() == ARCH_ID_AT91CAP9)
+#define cpu_is_at91cap9_revB()	(at91cap9_rev_identify() == ARCH_REVISION_CAP9_B)
+#define cpu_is_at91cap9_revC()	(at91cap9_rev_identify() == ARCH_REVISION_CAP9_C)
+#else
+#define cpu_is_at91cap9()	(0)
+#define cpu_is_at91cap9_revB()	(0)
+#define cpu_is_at91cap9_revC()	(0)
+#endif
+
+#ifdef CONFIG_ARCH_AT572D940HF
+#define cpu_is_at572d940hf() (at91_cpu_identify() == ARCH_ID_AT572D940HF)
+#else
+#define cpu_is_at572d940hf() (0)
+#endif
+
+/*
+ * Since this is ARM, we will never run on any AVR32 CPU. But these
+ * definitions may reduce clutter in common drivers.
+ */
+#define cpu_is_at32ap7000()	(0)
+
+#endif
diff --git a/arch/arm/mach-at91/include/mach/gpio.h b/arch/arm/mach-at91/include/mach/gpio.h
index 76d53ba..7e1a9a8 100644
--- a/arch/arm/mach-at91/include/mach/gpio.h
+++ b/arch/arm/mach-at91/include/mach/gpio.h
@@ -241,6 +241,7 @@ struct at91_gpio_bank {
 	struct at91_gpio_bank *next;	/* bank sharing same IRQ/clock/... */
 	unsigned short id;		/* peripheral ID */
 	unsigned long offset;		/* offset from system peripheral base */
+	struct clk *clock;
 };
 
 extern int at91_gpio_init(struct at91_gpio_bank *data, int nr_banks);
diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 4feeed0..6864119 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -48,7 +48,7 @@
 #include <errno.h>
 #include <asm/io.h>
 #include <mach/board.h>
-#include <mach/clk.h>
+#include <linux/clk.h>
 
 #include "macb.h"
 
@@ -412,6 +412,9 @@ static int macb_probe(struct device_d *dev)
 	unsigned long macb_hz;
 	u32 ncfgr;
 	struct at91_ether_platform_data *pdata;
+#if defined(CONFIG_ARCH_AT91)
+	struct clk *pclk;
+#endif
 
 	if (!dev->platform_data) {
 		printf("macb: no platform_data\n");
@@ -450,7 +453,13 @@ static int macb_probe(struct device_d *dev)
 	 * Do some basic initialization so that we at least can talk
 	 * to the PHY
 	 */
+#if defined(CONFIG_ARCH_AT91)
+	pclk = clk_get(dev, "macb_clk");
+	clk_enable(pclk);
+	macb_hz = clk_get_rate(pclk);
+#else
 	macb_hz = get_macb_pclk_rate(0);
+#endif
 	if (macb_hz < 20000000)
 		ncfgr = MACB_BF(CLK, MACB_CLK_DIV8);
 	else if (macb_hz < 40000000)
diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
index e9e8116..b99ec4d 100644
--- a/drivers/serial/atmel.c
+++ b/drivers/serial/atmel.c
@@ -22,7 +22,7 @@
 #include <init.h>
 #include <malloc.h>
 #include <asm/io.h>
-#include <mach/clk.h>
+#include <linux/clk.h>
 
 /* USART3 register offsets */
 #define USART3_CR				0x0000
@@ -309,6 +309,21 @@
 		    << USART3_##name##_OFFSET))		\
 	 | USART3_BF(name,value))
 
+/*
+ * We wrap our port structure around the generic console_device.
+ */
+struct atmel_uart_port {
+	struct console_device	uart;		/* uart */
+	struct clk		*clk;		/* uart clock */
+	u32			uartclk;
+};
+
+static inline struct atmel_uart_port *
+to_atmel_uart_port(struct console_device *uart)
+{
+	return container_of(uart, struct atmel_uart_port, uart);
+}
+
 static void atmel_serial_putc(struct console_device *cdev, char c)
 {
 	struct device_d *dev = cdev->dev;
@@ -336,16 +351,15 @@ static int atmel_serial_getc(struct console_device *cdev)
 static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate)
 {
 	struct device_d *dev = cdev->dev;
+	struct atmel_uart_port *uart = to_atmel_uart_port(cdev);
 	unsigned long divisor;
-	unsigned long usart_hz;
 
 	/*
 	 *              Master Clock
 	 * Baud Rate = --------------
 	 *                16 * CD
 	 */
-	usart_hz = get_usart_clk_rate(0);
-	divisor = (usart_hz / 16 + baudrate / 2) / baudrate;
+	divisor = (uart->uartclk / 16 + baudrate / 2) / baudrate;
 	writel(USART3_BF(CD, divisor), dev->map_base + USART3_BRGR);
 
 	return 0;
@@ -359,6 +373,11 @@ static int atmel_serial_setbaudrate(struct console_device *cdev, int baudrate)
 static int atmel_serial_init_port(struct console_device *cdev)
 {
 	struct device_d *dev = cdev->dev;
+	struct atmel_uart_port *uart = to_atmel_uart_port(cdev);
+
+	uart->clk = clk_get(dev, "usart");
+	clk_enable(uart->clk);
+	uart->uartclk = clk_get_rate(uart->clk);
 
 	writel(USART3_BIT(RSTRX) | USART3_BIT(RSTTX), dev->map_base + USART3_CR);
 
@@ -376,9 +395,12 @@ static int atmel_serial_init_port(struct console_device *cdev)
 
 static int atmel_serial_probe(struct device_d *dev)
 {
+	struct atmel_uart_port *uart;
 	struct console_device *cdev;
 
-	cdev = malloc(sizeof(struct console_device));
+	uart = malloc(sizeof(struct atmel_uart_port));
+
+	cdev = &uart->uart;
 	dev->type_data = cdev;
 	cdev->dev = dev;
 	cdev->f_caps = CONSOLE_STDIN | CONSOLE_STDOUT | CONSOLE_STDERR;
-- 
1.7.1


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

  parent reply	other threads:[~2010-08-04  6:17 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-03 12:51 [PATCH 0/3] introduce clk framework Jean-Christophe PLAGNIOL-VILLARD
2010-08-03 12:53 ` [PATCH 1/3] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD
2010-08-03 12:53   ` [PATCH 2/3] clock: Introduce clock framework from Linux Jean-Christophe PLAGNIOL-VILLARD
2010-08-03 12:53     ` [PATCH 3/3] at91: implement clock framework Jean-Christophe PLAGNIOL-VILLARD
2010-08-03 20:23       ` Sascha Hauer
2010-08-04  1:33       ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD
2010-08-04  5:20         ` Baruch Siach
2010-08-04  6:06           ` Jean-Christophe PLAGNIOL-VILLARD
2010-08-04  6:12         ` Jean-Christophe PLAGNIOL-VILLARD [this message]
2010-08-29 16:53   ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD
2010-08-30  1:21     ` [PATCH V3] " Jean-Christophe PLAGNIOL-VILLARD

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1280902376-11891-1-git-send-email-plagnioj@jcrosoft.com \
    --to=plagnioj@jcrosoft.com \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox