mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 0/3] introduce clk framework
@ 2010-08-03 12:51 Jean-Christophe PLAGNIOL-VILLARD
  2010-08-03 12:53 ` [PATCH 1/3] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:51 UTC (permalink / raw)
  To: barebox

Hi,

The following changes since commit 139ec08127825f2fdc4d0386d26f1fad9f745c2c:

  Merge branch 'next' (2010-08-03 09:31:38 +0200)

Jean-Christophe PLAGNIOL-VILLARD (3):
      initcall: add postconsole_initcall
      clock: Introduce clock framework from Linux
      at91: implement clock framework

 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                  |  672 +++++++++++++++++++++++++++
 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       |  118 +++++
 arch/arm/mach-at91/include/mach/gpio.h      |    1 +
 drivers/net/macb.c                          |   11 +-
 drivers/serial/atmel.c                      |   32 ++-
 include/init.h                              |    1 +
 include/linux/clk.h                         |  158 +++++++
 24 files changed, 1545 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
 create mode 100644 include/linux/clk.h

Best Regards,
J.

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/3] initcall: add postconsole_initcall
  2010-08-03 12:51 [PATCH 0/3] introduce clk framework Jean-Christophe PLAGNIOL-VILLARD
@ 2010-08-03 12:53 ` Jean-Christophe PLAGNIOL-VILLARD
  2010-08-03 12:53   ` [PATCH 2/3] clock: Introduce clock framework from Linux Jean-Christophe PLAGNIOL-VILLARD
  2010-08-29 16:53   ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 2 replies; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 UTC (permalink / raw)
  To: barebox

this will allow us to print information as soon as the console will be enable

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 include/init.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

diff --git a/include/init.h b/include/init.h
index eb606f3..c5dea07 100644
--- a/include/init.h
+++ b/include/init.h
@@ -11,6 +11,7 @@ typedef int (*initcall_t)(void);
 #define core_initcall(fn)		__define_initcall("0",fn,0)
 #define postcore_initcall(fn)		__define_initcall("1",fn,1)
 #define console_initcall(fn)		__define_initcall("2",fn,2)
+#define postconsole_initcall(fn)	__define_initcall("3",fn,3)
 #define coredevice_initcall(fn)		__define_initcall("4",fn,4)
 #define fs_initcall(fn)			__define_initcall("5",fn,5)
 #define device_initcall(fn)		__define_initcall("6",fn,6)
-- 
1.7.1


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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/3] clock: Introduce clock framework from Linux
  2010-08-03 12:53 ` [PATCH 1/3] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD
@ 2010-08-03 12:53   ` Jean-Christophe PLAGNIOL-VILLARD
  2010-08-03 12:53     ` [PATCH 3/3] at91: implement clock framework Jean-Christophe PLAGNIOL-VILLARD
  2010-08-29 16:53   ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 1 reply; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
---
 include/linux/clk.h |  158 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 158 insertions(+), 0 deletions(-)
 create mode 100644 include/linux/clk.h

diff --git a/include/linux/clk.h b/include/linux/clk.h
new file mode 100644
index 0000000..0cf86d7
--- /dev/null
+++ b/include/linux/clk.h
@@ -0,0 +1,158 @@
+/*
+ *  linux/include/linux/clk.h
+ *
+ *  Copyright (C) 2004 ARM Limited.
+ *  Written by Deep Blue Solutions Limited.
+ *
+ * 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.
+ */
+#ifndef __LINUX_CLK_H
+#define __LINUX_CLK_H
+
+struct device_d;
+
+/*
+ * The base API.
+ */
+
+
+/*
+ * struct clk - an machine class defined object / cookie.
+ */
+struct clk;
+
+/**
+ * clk_get - lookup and obtain a reference to a clock producer.
+ * @dev: device for clock "consumer"
+ * @id: clock comsumer ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno.  The implementation
+ * uses @dev and @id to determine the clock consumer, and thereby
+ * the clock producer.  (IOW, @id may be identical strings, but
+ * clk_get may return different clock producers depending on @dev.)
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * clk_get should not be called from within interrupt context.
+ */
+struct clk *clk_get(struct device_d *dev, const char *id);
+
+/**
+ * clk_enable - inform the system when the clock source should be running.
+ * @clk: clock source
+ *
+ * If the clock can not be enabled/disabled, this should return success.
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_enable(struct clk *clk);
+
+/**
+ * clk_disable - inform the system when the clock source is no longer required.
+ * @clk: clock source
+ *
+ * Inform the system that a clock source is no longer required by
+ * a driver and may be shut down.
+ *
+ * Implementation detail: if the clock source is shared between
+ * multiple drivers, clk_enable() calls must be balanced by the
+ * same number of clk_disable() calls for the clock source to be
+ * disabled.
+ */
+void clk_disable(struct clk *clk);
+
+/**
+ * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
+ *		  This is only valid once the clock source has been enabled.
+ * @clk: clock source
+ */
+unsigned long clk_get_rate(struct clk *clk);
+
+/**
+ * clk_put	- "free" the clock source
+ * @clk: clock source
+ *
+ * Note: drivers must ensure that all clk_enable calls made on this
+ * clock source are balanced by clk_disable calls prior to calling
+ * this function.
+ *
+ * clk_put should not be called from within interrupt context.
+ */
+void clk_put(struct clk *clk);
+
+
+/*
+ * The remaining APIs are optional for machine class support.
+ */
+
+
+/**
+ * clk_round_rate - adjust a rate to the exact rate a clock can provide
+ * @clk: clock source
+ * @rate: desired clock rate in Hz
+ *
+ * Returns rounded clock rate in Hz, or negative errno.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate);
+ 
+/**
+ * clk_set_rate - set the clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired clock rate in Hz
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate);
+ 
+/**
+ * clk_set_parent - set the parent clock source for this clock
+ * @clk: clock source
+ * @parent: parent clock source
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent);
+
+/**
+ * clk_get_parent - get the parent clock source for this clock
+ * @clk: clock source
+ *
+ * Returns struct clk corresponding to parent clock source, or
+ * valid IS_ERR() condition containing errno.
+ */
+struct clk *clk_get_parent(struct clk *clk);
+
+/**
+ * clk_get_sys - get a clock based upon the device name
+ * @dev_id: device name
+ * @con_id: connection ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno.  The implementation
+ * uses @dev_id and @con_id to determine the clock consumer, and
+ * thereby the clock producer. In contrast to clk_get() this function
+ * takes the device name instead of the device itself for identification.
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * clk_get_sys should not be called from within interrupt context.
+ */
+struct clk *clk_get_sys(const char *dev_id, const char *con_id);
+
+/**
+ * clk_add_alias - add a new clock alias
+ * @alias: name for clock alias
+ * @alias_dev_name: device name
+ * @id: platform specific clock name
+ * @dev: device
+ *
+ * Allows using generic clock names for drivers by adding a new alias.
+ * Assumes clkdev, see clkdev.h for more info.
+ */
+int clk_add_alias(const char *alias, const char *alias_dev_name, char *id,
+			struct device_d *dev);
+
+#endif
-- 
1.7.1


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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/3] at91: implement clock framework
  2010-08-03 12:53   ` [PATCH 2/3] clock: Introduce clock framework from Linux Jean-Christophe PLAGNIOL-VILLARD
@ 2010-08-03 12:53     ` Jean-Christophe PLAGNIOL-VILLARD
  2010-08-03 20:23       ` Sascha Hauer
  2010-08-04  1:33       ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 2 replies; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-03 12:53 UTC (permalink / raw)
  To: barebox

this implementation is based on linux one
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>
---
 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                  |  672 +++++++++++++++++++++++++++
 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       |  118 +++++
 arch/arm/mach-at91/include/mach/gpio.h      |    1 +
 drivers/net/macb.c                          |   11 +-
 drivers/serial/atmel.c                      |   32 ++-
 22 files changed, 1386 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..422ac09 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_M1IN_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..1912e5a
--- /dev/null
+++ b/arch/arm/mach-at91/clock.c
@@ -0,0 +1,672 @@
+/*
+ * 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())
+
+#define cpu_has_800M_plla()	(cpu_is_at91sam9g20())
+
+#define cpu_has_pllb()		(!cpu_is_at91sam9rl())
+
+#define cpu_has_upll()		(0)
+
+/* USB host HS & FS */
+#define cpu_has_uhp()		(!cpu_is_at91sam9rl())
+
+/* USB device FS only */
+#define cpu_has_udpfs()		(!cpu_is_at91sam9rl())
+
+
+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 (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;
+
+	if (!clk_is_programmable(clk))
+		return -EINVAL;
+
+	actual = clk->parent->rate_hz;
+	for (prescale = 0; prescale < 7; prescale++) {
+		if (actual && actual <= rate)
+			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;
+
+	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()) {
+		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);
+}
+
+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_upll() && !cpu_has_pllb()) {
+		/* 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 {
+		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 ((!cpu_has_800M_plla() && plla.rate_hz > 209000000)
+	   || (cpu_has_800M_plla() && plla.rate_hz > 800000000))
+		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..6f05732
--- /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:2;		/* PCK0..3, 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..c554c3e
--- /dev/null
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -0,0 +1,118 @@
+/*
+ * 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_AT91SAM9G20	0x019905a0
+#define ARCH_ID_AT91SAM9RL64	0x019b03a0
+#define ARCH_ID_AT91CAP9	0x039A03A0
+
+#define ARCH_ID_AT91SAM9XE128	0x329973a0
+#define ARCH_ID_AT91SAM9XE256	0x329a93a0
+#define ARCH_ID_AT91SAM9XE512	0x329aa3a0
+
+#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);
+}
+
+
+#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_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_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
+
+/*
+ * 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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3] at91: implement clock framework
  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
  1 sibling, 0 replies; 11+ messages in thread
From: Sascha Hauer @ 2010-08-03 20:23 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

Hi Jean-Christophe,

That was fast ;)

On Tue, Aug 03, 2010 at 02:53:39PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> this implementation is based on linux one
> it will calculate all the clock dynamically instead of statictly
> this will use also the new clock framework

I think it's a good idea to leave a pointer to the Linux version this
code is from. This will help us find relevant changes for barebox in the
Linux history.

> 
> +
> +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);

Any special reason these are not registered in the array above other
that they are not peripheral clocks?
I just saw that it's the same in Linux, so probably this is the reason.

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/3 v2] at91: implement clock framework
  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       ` Jean-Christophe PLAGNIOL-VILLARD
  2010-08-04  5:20         ` Baruch Siach
  2010-08-04  6:12         ` [PATCH 3/3 v3] " Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 2 replies; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-04  1:33 UTC (permalink / raw)
  To: barebox

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>
---
v2:
upadate against mainline kernel
and add ref on which revision it's based on

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..422ac09 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_M1IN_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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3 v2] at91: implement clock framework
  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         ` [PATCH 3/3 v3] " Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 1 reply; 11+ messages in thread
From: Baruch Siach @ 2010-08-04  5:20 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

Hi Jean-Christophe,

On Wed, Aug 04, 2010 at 03:33:15AM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> 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>
> ---
> v2:
> upadate against mainline kernel
> and add ref on which revision it's based on

[snip]

> diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h
> index 1133b8f..422ac09 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_M1IN_CLOCK		18432000

s/M1IN/MAIN/ ?

baruch

-- 
                                                     ~. .~   Tk Open Systems
=}------------------------------------------------ooO--U--Ooo------------{=
   - baruch@tkos.co.il - tel: +972.2.679.5364, http://www.tkos.co.il -

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 3/3 v2] at91: implement clock framework
  2010-08-04  5:20         ` Baruch Siach
@ 2010-08-04  6:06           ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-04  6:06 UTC (permalink / raw)
  To: Baruch Siach; +Cc: barebox

On 08:20 Wed 04 Aug     , Baruch Siach wrote:
> Hi Jean-Christophe,
> 
> On Wed, Aug 04, 2010 at 03:33:15AM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > 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>
> > ---
> > v2:
> > upadate against mainline kernel
> > and add ref on which revision it's based on
> 
> [snip]
> 
> > diff --git a/arch/arm/boards/mmccpu/config.h b/arch/arm/boards/mmccpu/config.h
> > index 1133b8f..422ac09 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_M1IN_CLOCK		18432000
> 
> s/M1IN/MAIN/ ?
nice

Best Regards,
J.

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/3 v3] at91: implement clock framework
  2010-08-04  1:33       ` [PATCH 3/3 v2] " Jean-Christophe PLAGNIOL-VILLARD
  2010-08-04  5:20         ` Baruch Siach
@ 2010-08-04  6:12         ` Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 0 replies; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-04  6:12 UTC (permalink / raw)
  To: barebox

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH V2] initcall: add postconsole_initcall
  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-29 16:53   ` Jean-Christophe PLAGNIOL-VILLARD
  2010-08-30  1:21     ` [PATCH V3] " Jean-Christophe PLAGNIOL-VILLARD
  1 sibling, 1 reply; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-29 16:53 UTC (permalink / raw)
  To: barebox

this will allow us to print information as soon as the console will be enable

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

	this patch is a rebase version which is needed by at91 since the
	switch to linux clk framework

	which was forget

Best Regards,
J.
 include/init.h |    9 +++++----
 1 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/include/init.h b/include/init.h
index bc70874..9651f2a 100644
--- a/include/init.h
+++ b/include/init.h
@@ -25,10 +25,11 @@ typedef int (*initcall_t)(void);
 #define core_initcall(fn)		__define_initcall("1",fn,1)
 #define postcore_initcall(fn)		__define_initcall("2",fn,2)
 #define console_initcall(fn)		__define_initcall("3",fn,3)
-#define coredevice_initcall(fn)		__define_initcall("4",fn,4)
-#define fs_initcall(fn)			__define_initcall("5",fn,5)
-#define device_initcall(fn)		__define_initcall("6",fn,6)
-#define late_initcall(fn)		__define_initcall("7",fn,7)
+#define postconsole_initcall(fn)	__define_initcall("4",fn,4)
+#define coredevice_initcall(fn)		__define_initcall("5",fn,5)
+#define fs_initcall(fn)			__define_initcall("6",fn,6)
+#define device_initcall(fn)		__define_initcall("7",fn,7)
+#define late_initcall(fn)		__define_initcall("8",fn,8)
 
 /* section for code used very early when
  * - we're not running from where we linked at
-- 
1.7.1


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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH V3] initcall: add postconsole_initcall
  2010-08-29 16:53   ` [PATCH V2] initcall: add postconsole_initcall Jean-Christophe PLAGNIOL-VILLARD
@ 2010-08-30  1:21     ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 11+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2010-08-30  1:21 UTC (permalink / raw)
  To: barebox

this will allow us to print information as soon as the console will be enable

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

	this patch is a rebase version which is needed by at91 since the
	switch to linux clk framework

	which was forget

v3:

	add missing KEEP for linker script
Best Regards,
J.
 include/asm-generic/barebox.lds.h |    3 ++-
 include/init.h                    |    9 +++++----
 2 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/include/asm-generic/barebox.lds.h b/include/asm-generic/barebox.lds.h
index 99ccc5e..1d3f4f7 100644
--- a/include/asm-generic/barebox.lds.h
+++ b/include/asm-generic/barebox.lds.h
@@ -15,7 +15,8 @@
 	KEEP(*(.initcall.4))			\
 	KEEP(*(.initcall.5))			\
 	KEEP(*(.initcall.6))			\
-	KEEP(*(.initcall.7))
+	KEEP(*(.initcall.7))			\
+	KEEP(*(.initcall.8))
 
 #define BAREBOX_CMDS	KEEP(*(SORT_BY_NAME(.barebox_cmd*)))
 
diff --git a/include/init.h b/include/init.h
index bc70874..8692b68 100644
--- a/include/init.h
+++ b/include/init.h
@@ -25,10 +25,11 @@ typedef int (*initcall_t)(void);
 #define core_initcall(fn)		__define_initcall("1",fn,1)
 #define postcore_initcall(fn)		__define_initcall("2",fn,2)
 #define console_initcall(fn)		__define_initcall("3",fn,3)
-#define coredevice_initcall(fn)		__define_initcall("4",fn,4)
-#define fs_initcall(fn)			__define_initcall("5",fn,5)
-#define device_initcall(fn)		__define_initcall("6",fn,6)
-#define late_initcall(fn)		__define_initcall("7",fn,7)
+#define postconsole_initcall(fn)	__define_initcall("4",fn,4)
+#define coredevice_initcall(fn)		__define_initcall("5",fn,5)
+#define fs_initcall(fn)			__define_initcall("6",fn,6)
+#define device_initcall(fn)		__define_initcall("7",fn,7)
+#define late_initcall(fn)		__define_initcall("8",fn,8)
 
 /* section for code used very early when
  * - we're not running from where we linked at
-- 
1.7.1


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

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2010-08-30  1:22 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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         ` [PATCH 3/3 v3] " Jean-Christophe PLAGNIOL-VILLARD
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

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox