mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/45] AT91, at91sam9x5ek updates
@ 2017-03-06 22:53 Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 01/45] at91: Fix bug/typo in debug_ll.h Andrey Smirnov
                   ` (46 more replies)
  0 siblings, 47 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Hi everyone,

I recently had a chance to work with at91sam9x5ek board and as a part
of that effort I converted the code to support features found in
Barebox for i.MX based SoCs. Most notably this patchset converts
at91sam9x5ek to use multi-image PBL build process as well as adds
support for board initialization from attached devicetree blob.

Sascha, at least for now, all of the patches, in chronological order,
are included in this submission. However if this proves to be too
burdensome to review, I'd be more than happy to split it into several
individual submissions. One such division could be:

	   - Generic bug fixes/infrastructure enhancements
	   - Peripheral drivers updates
	   - at91sam9x5ek specific changes

Please let me know if that is preferrable.

Thank you,
Andrey Smirnov


Andrey Smirnov (45):
  at91: Fix bug/typo in debug_ll.h
  at91sam9x5ek: Convert to mult-image build
  at91sam9x5ek: Add CONFIG_KALLSYMS to defconfig
  at91sam9x5ek: Add preliminary device tree support
  clocksource: at91: Move to 'drivers/clocksource'
  clocksource: at91: Add DT compatibility table
  serial: atmel: Check result of clk_get()
  serial: atmel: Add DT compatibility table
  regmap: Implement syscon_node_to_regmap()
  clk: Port two helper functions from Linux
  clk: Make COMMON_CLK_OF_PROVIDER depend on OFTREE
  clk: No-op CLK_OF_DECLARE if not enabled
  clk: at91: Port at91 DT clock code
  at91sam9x5ek: Convert to use DT clock tree
  at91sam9x5ek: Remove at91sam9x5ek_mem_init()
  at91sam9x5ek: Configure LEDs in DT
  pinctrl-at91: Fix a bug in at91_pinctrl_set_conf()
  at91: Enable PINCTRL for SOC_AT91SAM9
  at91sam9x5ek: Configure I2C via DT
  mci: Allow parsing for explicit DT node
  mci: atmel_mci: Add DT support
  at91sam9x5ek: Configure MMC in DT
  of: base: Use scoring in DT device matching
  pinctrl: at91: Fix a bug in at91_pinctrl_set_state
  pinctrl: at91: Implement .get_direction hook
  spi: atmel_spi: Add DT support
  spi: atmel_spi: Configure CS GPIO as output
  spi: atmel_spi: Use VERSION register instead of CPU type
  at91sam9x5ek: Configure SPI in DT
  w1-gpio: Add DT support
  at91sam9x5ek: Configure 1-wire in DT
  usb: ohci-at91: Check result of clk_get()
  usb: ohci-at91: Convert global variables to private data
  usb: ohci-at91: Check result of clk_enable()
  usb: ohci-at91: Add DT support
  usb/host: Allow USB_OHCI_AT91 even if USB_OHCI is disabled
  usb: ehci-atmel: Check result of clk_enable()
  usb: echi-atmel: Convert global variables to private data
  usb: ehci-atmel: Zero ehci_data before using it
  usb: echi-atmel: Check result of ehci_register()
  usb: echi-atmel: Add DT support
  at91sam9x5ek: Configure USB in DT
  net: macb: Add DT support
  at91sam9x5ek: Configure Ethernet in DT
  at91sam9x5ek: Configure NAND in DT

 arch/arm/Kconfig                                   |   2 +-
 arch/arm/boards/at91sam9x5ek/Makefile              |   1 +
 arch/arm/boards/at91sam9x5ek/hw_version.c          |   6 +-
 arch/arm/boards/at91sam9x5ek/hw_version.h          |   1 -
 arch/arm/boards/at91sam9x5ek/init.c                | 226 ++------
 arch/arm/boards/at91sam9x5ek/lowlevel.c            |  21 +
 arch/arm/configs/at91sam9x5ek_defconfig            |   8 +-
 arch/arm/dts/Makefile                              |   2 +
 arch/arm/dts/at91sam9x5ek.dts                      |  72 +++
 arch/arm/mach-at91/Kconfig                         |  73 ++-
 arch/arm/mach-at91/Makefile                        |  10 +-
 arch/arm/mach-at91/at91sam9x5.c                    | 311 -----------
 arch/arm/mach-at91/include/mach/board.h            |   6 +-
 arch/arm/mach-at91/include/mach/debug_ll.h         |   2 +-
 arch/arm/mach-at91/setup.c                         |   4 +-
 drivers/clk/Kconfig                                |   1 +
 drivers/clk/Makefile                               |   1 +
 drivers/clk/at91/Makefile                          |  15 +
 drivers/clk/at91/clk-generated.c                   | 323 ++++++++++++
 drivers/clk/at91/clk-h32mx.c                       | 125 +++++
 drivers/clk/at91/clk-main.c                        | 576 +++++++++++++++++++++
 drivers/clk/at91/clk-master.c                      | 245 +++++++++
 drivers/clk/at91/clk-peripheral.c                  | 430 +++++++++++++++
 drivers/clk/at91/clk-pll.c                         | 516 ++++++++++++++++++
 drivers/clk/at91/clk-plldiv.c                      | 135 +++++
 drivers/clk/at91/clk-programmable.c                | 254 +++++++++
 drivers/clk/at91/clk-slow.c                        | 108 ++++
 drivers/clk/at91/clk-smd.c                         | 172 ++++++
 drivers/clk/at91/clk-system.c                      | 160 ++++++
 drivers/clk/at91/clk-usb.c                         | 397 ++++++++++++++
 drivers/clk/at91/clk-utmi.c                        | 138 +++++
 drivers/clk/at91/pmc.c                             |  41 ++
 drivers/clk/at91/pmc.h                             |  27 +
 drivers/clk/at91/sckc.c                            | 485 +++++++++++++++++
 drivers/clk/clk-fixed-factor.c                     |   2 -
 drivers/clk/clk-fixed.c                            |   3 +-
 drivers/clk/clk.c                                  |  41 +-
 drivers/clk/clkdev.c                               |   2 +-
 drivers/clocksource/Kconfig                        |   4 +
 drivers/clocksource/Makefile                       |   1 +
 .../clocksource/timer-atmel-pit.c                  |   9 +
 drivers/mci/atmel_mci.c                            | 101 ++--
 drivers/mci/mci-core.c                             |  13 +-
 drivers/mfd/syscon.c                               |  54 +-
 drivers/net/macb.c                                 |  56 +-
 drivers/of/base.c                                  |  37 +-
 drivers/pinctrl/pinctrl-at91.c                     |  22 +-
 drivers/serial/atmel.c                             |  12 +
 drivers/spi/atmel_spi.c                            |  70 ++-
 drivers/spi/atmel_spi.h                            |   1 +
 drivers/usb/host/Kconfig                           |   5 +-
 drivers/usb/host/ehci-atmel.c                      |  66 ++-
 drivers/usb/host/ohci-at91.c                       | 156 +++++-
 drivers/w1/masters/w1-gpio.c                       |  53 ++
 images/Makefile                                    |   1 +
 images/Makefile.at91                               |   7 +
 include/linux/clk.h                                |   9 +-
 include/linux/clk/at91_pmc.h                       | 188 +++++++
 include/mci.h                                      |   1 +
 include/mfd/syscon.h                               |   8 +
 60 files changed, 5150 insertions(+), 666 deletions(-)
 create mode 100644 arch/arm/boards/at91sam9x5ek/lowlevel.c
 create mode 100644 arch/arm/dts/at91sam9x5ek.dts
 delete mode 100644 arch/arm/mach-at91/at91sam9x5.c
 create mode 100644 drivers/clk/at91/Makefile
 create mode 100644 drivers/clk/at91/clk-generated.c
 create mode 100644 drivers/clk/at91/clk-h32mx.c
 create mode 100644 drivers/clk/at91/clk-main.c
 create mode 100644 drivers/clk/at91/clk-master.c
 create mode 100644 drivers/clk/at91/clk-peripheral.c
 create mode 100644 drivers/clk/at91/clk-pll.c
 create mode 100644 drivers/clk/at91/clk-plldiv.c
 create mode 100644 drivers/clk/at91/clk-programmable.c
 create mode 100644 drivers/clk/at91/clk-slow.c
 create mode 100644 drivers/clk/at91/clk-smd.c
 create mode 100644 drivers/clk/at91/clk-system.c
 create mode 100644 drivers/clk/at91/clk-usb.c
 create mode 100644 drivers/clk/at91/clk-utmi.c
 create mode 100644 drivers/clk/at91/pmc.c
 create mode 100644 drivers/clk/at91/pmc.h
 create mode 100644 drivers/clk/at91/sckc.c
 rename arch/arm/mach-at91/at91sam926x_time.c => drivers/clocksource/timer-atmel-pit.c (93%)
 create mode 100644 images/Makefile.at91
 create mode 100644 include/linux/clk/at91_pmc.h

-- 
2.9.3


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

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

* [PATCH 01/45] at91: Fix bug/typo in debug_ll.h
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 02/45] at91sam9x5ek: Convert to mult-image build Andrey Smirnov
                   ` (45 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Correct "COFNIG" to "CONFIG".

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-at91/include/mach/debug_ll.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-at91/include/mach/debug_ll.h b/arch/arm/mach-at91/include/mach/debug_ll.h
index 1a85ae4..42728a4 100644
--- a/arch/arm/mach-at91/include/mach/debug_ll.h
+++ b/arch/arm/mach-at91/include/mach/debug_ll.h
@@ -11,7 +11,7 @@
 #include <asm/io.h>
 #include <mach/hardware.h>
 
-#ifdef COFNIG_HAVE_AT91_DBGU0
+#ifdef CONFIG_HAVE_AT91_DBGU0
 #define UART_BASE	AT91_BASE_DBGU0
 #else
 #define UART_BASE	AT91_BASE_DBGU1
-- 
2.9.3


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

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

* [PATCH 02/45] at91sam9x5ek: Convert to mult-image build
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 01/45] at91: Fix bug/typo in debug_ll.h Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 03/45] at91sam9x5ek: Add CONFIG_KALLSYMS to defconfig Andrey Smirnov
                   ` (44 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Convert AT91SAM9X5-EK board code to multi-image build process, similar
to how majority of i.MX board code is built.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/Kconfig                        |  1 -
 arch/arm/boards/at91sam9x5ek/Makefile   |  1 +
 arch/arm/boards/at91sam9x5ek/lowlevel.c | 16 +++++++++++++
 arch/arm/configs/at91sam9x5ek_defconfig |  4 +++-
 arch/arm/mach-at91/Kconfig              | 40 +++++++++++++++++++--------------
 images/Makefile                         |  1 +
 images/Makefile.at91                    |  7 ++++++
 7 files changed, 51 insertions(+), 19 deletions(-)
 create mode 100644 arch/arm/boards/at91sam9x5ek/lowlevel.c
 create mode 100644 images/Makefile.at91

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e4663ea..cfa9214 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -52,7 +52,6 @@ config ARCH_AT91
 	select GPIOLIB
 	select CLKDEV_LOOKUP
 	select HAS_DEBUG_LL
-	select HAVE_MACH_ARM_HEAD
 	select HAVE_CLK
 	select PINCTRL_AT91
 
diff --git a/arch/arm/boards/at91sam9x5ek/Makefile b/arch/arm/boards/at91sam9x5ek/Makefile
index 559df8f..4939b7e 100644
--- a/arch/arm/boards/at91sam9x5ek/Makefile
+++ b/arch/arm/boards/at91sam9x5ek/Makefile
@@ -1,3 +1,4 @@
 obj-y += init.o
 obj-y += hw_version.o
 bbenv-$(CONFIG_DEFAULT_ENVIRONMENT_GENERIC) += defaultenv-at91sam9x5ek
+lwl-y += lowlevel.o
diff --git a/arch/arm/boards/at91sam9x5ek/lowlevel.c b/arch/arm/boards/at91sam9x5ek/lowlevel.c
new file mode 100644
index 0000000..9b5c926
--- /dev/null
+++ b/arch/arm/boards/at91sam9x5ek/lowlevel.c
@@ -0,0 +1,16 @@
+#include <common.h>
+#include <linux/sizes.h>
+#include <mach/at91sam9_ddrsdr.h>
+#include <asm/barebox-arm-head.h>
+#include <asm/barebox-arm.h>
+#include <io.h>
+#include <debug_ll.h>
+
+
+ENTRY_FUNCTION(start_at91sam9x5ek, r0, r1, r2)
+{
+	arm_cpu_lowlevel_init();
+	arm_setup_stack(AT91SAM9X5_SRAM_BASE + AT91SAM9X5_SRAM_SIZE - 16);
+
+	barebox_arm_entry(AT91_CHIPSELECT_1, at91sam9x5_get_ddram_size(), NULL);
+}
diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig
index 6ee0052..76ee3d9 100644
--- a/arch/arm/configs/at91sam9x5ek_defconfig
+++ b/arch/arm/configs/at91sam9x5ek_defconfig
@@ -1,12 +1,14 @@
 CONFIG_ARCH_AT91SAM9X5=y
+CONFIG_AT91_MULTI_BOARDS=y
+CONFIG_MACH_AT91SAM9X5EK=y
 CONFIG_BAREBOX_MAX_IMAGE_SIZE=0x40000
 CONFIG_AEABI=y
 CONFIG_ARM_OPTIMZED_STRING_FUNCTIONS=y
-CONFIG_PBL_IMAGE=y
 CONFIG_MMU=y
 CONFIG_MALLOC_SIZE=0xa00000
 CONFIG_EXPERIMENTAL=y
 CONFIG_MALLOC_TLSF=y
+CONFIG_RELOCATABLE=y
 CONFIG_PROMPT="9G20-EK:"
 CONFIG_GLOB=y
 CONFIG_PROMPT_HUSH_PS2="y"
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index c45fc4d..969182c 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -143,18 +143,22 @@ config ARCH_AT91SAM9261
 config ARCH_AT91SAM9263
 	bool "AT91SAM9263"
 	select SOC_AT91SAM9263
+	select HAVE_MACH_ARM_HEAD
 
 config ARCH_AT91SAM9G10
 	bool "AT91SAM9G10"
 	select SOC_AT91SAM9261
+	select HAVE_MACH_ARM_HEAD
 
 config ARCH_AT91SAM9G20
 	bool "AT91SAM9G20"
 	select SOC_AT91SAM9260
+	select HAVE_MACH_ARM_HEAD
 
 config ARCH_AT91SAM9G45
 	bool "AT91SAM9G45 or AT91SAM9M10"
 	select SOC_AT91SAM9G45
+	select HAVE_MACH_ARM_HEAD
 
 config ARCH_AT91SAM9X5
 	bool "AT91SAM9X5"
@@ -163,6 +167,7 @@ config ARCH_AT91SAM9X5
 config ARCH_AT91SAM9N12
 	bool "AT91SAM9N12"
 	select SOC_AT91SAM9N12
+	select HAVE_MACH_ARM_HEAD
 
 config ARCH_SAMA5D3
 	bool "SAMA5D3x"
@@ -170,6 +175,7 @@ config ARCH_SAMA5D3
 	select HAVE_AT91_DBGU1
 	select HAS_MACB
 	select AT91SAM9G45_RESET
+	select HAVE_MACH_ARM_HEAD
 
 config ARCH_SAMA5D4
 	bool "SAMA5D4"
@@ -177,6 +183,7 @@ config ARCH_SAMA5D4
 	select HAVE_AT91_DBGU2
 	select HAS_MACB
 	select AT91SAM9G45_RESET
+	select HAVE_MACH_ARM_HEAD
 
 endchoice
 
@@ -432,23 +439,6 @@ endif
 
 # ----------------------------------------------------------
 
-if ARCH_AT91SAM9X5
-
-choice
-	prompt "AT91SAM9x5 Series Board Type"
-
-config MACH_AT91SAM9X5EK
-	bool "Atmel AT91SAM9x5 Series Evaluation Kit"
-	help
-	  Select this if you re using Atmel's AT91SAM9x5-EK Evaluation Kit.
-	  Supported chips are sam9g15, sam9g25, sam9x25, sam9g35 and sam9x35.
-
-endchoice
-
-endif
-
-# ----------------------------------------------------------
-
 if ARCH_AT91SAM9N12
 
 choice
@@ -507,6 +497,22 @@ endif
 
 # ----------------------------------------------------------
 
+
+config AT91_MULTI_BOARDS
+	bool "Allow multiple boards to be selected"
+	select HAVE_PBL_MULTI_IMAGES
+
+if AT91_MULTI_BOARDS
+
+config MACH_AT91SAM9X5EK
+	bool "Atmel AT91SAM9x5 Series Evaluation Kit"
+	depends on ARCH_AT91SAM9X5
+	help
+	  Select this if you re using Atmel's AT91SAM9x5-EK Evaluation Kit.
+	  Supported chips are sam9g15, sam9g25, sam9x25, sam9g35 and sam9x35.
+
+endif
+
 comment "AT91 Board Options"
 
 config MTD_AT91_DATAFLASH_CARD
diff --git a/images/Makefile b/images/Makefile
index 0537af1..2e84ba7 100644
--- a/images/Makefile
+++ b/images/Makefile
@@ -110,6 +110,7 @@ include $(srctree)/images/Makefile.omap3
 include $(srctree)/images/Makefile.rockchip
 include $(srctree)/images/Makefile.socfpga
 include $(srctree)/images/Makefile.tegra
+include $(srctree)/images/Makefile.at91
 
 targets += $(image-y) pbl.lds barebox.x barebox.z
 targets += $(patsubst %,%.pblx,$(pblx-y))
diff --git a/images/Makefile.at91 b/images/Makefile.at91
new file mode 100644
index 0000000..0f40a05
--- /dev/null
+++ b/images/Makefile.at91
@@ -0,0 +1,7 @@
+#
+# barebox image generation Makefile for AT91 images
+#
+
+pblx-y += start_at91sam9x5ek
+FILE_barebox-at91sam9x5ek.img = start_at91sam9x5ek.pblx
+image-y += barebox-at91sam9x5ek.img
-- 
2.9.3


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

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

* [PATCH 03/45] at91sam9x5ek: Add CONFIG_KALLSYMS to defconfig
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 01/45] at91: Fix bug/typo in debug_ll.h Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 02/45] at91sam9x5ek: Convert to mult-image build Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 04/45] at91sam9x5ek: Add preliminary device tree support Andrey Smirnov
                   ` (43 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/configs/at91sam9x5ek_defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig
index 76ee3d9..d6f18b2 100644
--- a/arch/arm/configs/at91sam9x5ek_defconfig
+++ b/arch/arm/configs/at91sam9x5ek_defconfig
@@ -8,6 +8,7 @@ CONFIG_MMU=y
 CONFIG_MALLOC_SIZE=0xa00000
 CONFIG_EXPERIMENTAL=y
 CONFIG_MALLOC_TLSF=y
+CONFIG_KALLSYMS=y
 CONFIG_RELOCATABLE=y
 CONFIG_PROMPT="9G20-EK:"
 CONFIG_GLOB=y
-- 
2.9.3


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

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

* [PATCH 04/45] at91sam9x5ek: Add preliminary device tree support
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (2 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 03/45] at91sam9x5ek: Add CONFIG_KALLSYMS to defconfig Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 05/45] clocksource: at91: Move to 'drivers/clocksource' Andrey Smirnov
                   ` (42 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Add basic code to build and pass board device tree blob to Barebox
initialization code.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/lowlevel.c | 7 ++++++-
 arch/arm/configs/at91sam9x5ek_defconfig | 2 ++
 arch/arm/dts/Makefile                   | 2 ++
 arch/arm/dts/at91sam9x5ek.dts           | 9 +++++++++
 arch/arm/mach-at91/Kconfig              | 1 +
 5 files changed, 20 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/dts/at91sam9x5ek.dts

diff --git a/arch/arm/boards/at91sam9x5ek/lowlevel.c b/arch/arm/boards/at91sam9x5ek/lowlevel.c
index 9b5c926..acf80d7 100644
--- a/arch/arm/boards/at91sam9x5ek/lowlevel.c
+++ b/arch/arm/boards/at91sam9x5ek/lowlevel.c
@@ -6,11 +6,16 @@
 #include <io.h>
 #include <debug_ll.h>
 
+extern char __dtb_at91sam9x5ek_start[];
 
 ENTRY_FUNCTION(start_at91sam9x5ek, r0, r1, r2)
 {
+	void *fdt;
+
 	arm_cpu_lowlevel_init();
 	arm_setup_stack(AT91SAM9X5_SRAM_BASE + AT91SAM9X5_SRAM_SIZE - 16);
 
-	barebox_arm_entry(AT91_CHIPSELECT_1, at91sam9x5_get_ddram_size(), NULL);
+	fdt = __dtb_at91sam9x5ek_start - get_runtime_offset();
+
+	barebox_arm_entry(AT91_CHIPSELECT_1, at91sam9x5_get_ddram_size(), fdt);
 }
diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig
index d6f18b2..0691145 100644
--- a/arch/arm/configs/at91sam9x5ek_defconfig
+++ b/arch/arm/configs/at91sam9x5ek_defconfig
@@ -51,6 +51,7 @@ CONFIG_CMD_OFTREE=y
 CONFIG_NET=y
 CONFIG_NET_NFS=y
 CONFIG_NET_NETCONSOLE=y
+CONFIG_OF_BAREBOX_DRIVERS=y
 CONFIG_DRIVER_NET_MACB=y
 CONFIG_NET_USB=y
 CONFIG_NET_USB_ASIX=y
@@ -74,6 +75,7 @@ CONFIG_USB_STORAGE=y
 CONFIG_MCI=y
 CONFIG_MCI_STARTUP=y
 CONFIG_MCI_ATMEL=y
+CONFIG_MFD_SYSCON=y
 CONFIG_LED=y
 CONFIG_LED_GPIO=y
 CONFIG_LED_TRIGGERS=y
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index 70359d8..c9a0946 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -89,5 +89,7 @@ pbl-dtb-$(CONFIG_MACH_ZII_VF610_DEV) += \
 	vf610-zii-spu3-rev-a.dtb.o	\
 	vf610-zii-scu4-aib-rev-c.dtb.o
 
+pbl-dtb-$(CONFIG_MACH_AT91SAM9X5EK) += at91sam9x5ek.dtb.o
+
 
 clean-files := *.dtb *.dtb.S .*.dtc .*.pre .*.dts *.dtb.lzo
diff --git a/arch/arm/dts/at91sam9x5ek.dts b/arch/arm/dts/at91sam9x5ek.dts
new file mode 100644
index 0000000..db1bd67
--- /dev/null
+++ b/arch/arm/dts/at91sam9x5ek.dts
@@ -0,0 +1,9 @@
+/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/pinctrl/at91.h>
+
+#include <arm/at91sam9x5.dtsi>
+#include <arm/at91sam9x5_lcd.dtsi>
+#include <arm/at91sam9x5dm.dtsi>
+#include <arm/at91sam9x5ek.dtsi>
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 969182c..be88bfa 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -163,6 +163,7 @@ config ARCH_AT91SAM9G45
 config ARCH_AT91SAM9X5
 	bool "AT91SAM9X5"
 	select SOC_AT91SAM9X5
+	select OFDEVICE
 
 config ARCH_AT91SAM9N12
 	bool "AT91SAM9N12"
-- 
2.9.3


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

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

* [PATCH 05/45] clocksource: at91: Move to 'drivers/clocksource'
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (3 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 04/45] at91sam9x5ek: Add preliminary device tree support Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 06/45] clocksource: at91: Add DT compatibility table Andrey Smirnov
                   ` (41 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Move PIT driver code to 'drivers/clocsource' and accomodate it by
adjusting Kconfig variables. Rename the file to 'timer-atmel-pit.c' to
re-align the driver with code in Linux kernel.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-at91/Kconfig                                         | 7 ++-----
 arch/arm/mach-at91/Makefile                                        | 1 -
 drivers/clocksource/Kconfig                                        | 4 ++++
 drivers/clocksource/Makefile                                       | 1 +
 .../at91sam926x_time.c => drivers/clocksource/timer-atmel-pit.c    | 0
 5 files changed, 7 insertions(+), 6 deletions(-)
 rename arch/arm/mach-at91/at91sam926x_time.c => drivers/clocksource/timer-atmel-pit.c (100%)

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index be88bfa..fe0269d 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -15,20 +15,17 @@ config HAVE_AT91_LOWLEVEL_INIT
 config AT91SAM9_SMC
 	bool
 
-config AT91SAM9_TIMER
-	bool
-
 config SOC_AT91SAM9
 	bool
 	select CPU_ARM926T
 	select AT91SAM9_SMC
-	select AT91SAM9_TIMER
+	select CLOCKSOURCE_ATMEL_PIT
 
 config SOC_SAMA5
 	bool
 	select CPU_V7
 	select AT91SAM9_SMC
-	select AT91SAM9_TIMER
+	select CLOCKSOURCE_ATMEL_PIT
 
 config ARCH_TEXT_BASE
 	hex
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index c2991b0..1f63b09 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -19,7 +19,6 @@ obj-$(CONFIG_AT91SAM9_RESET) += at91sam9_reset.o
 obj-$(CONFIG_AT91SAM9G45_RESET) += at91sam9g45_reset.o
 
 obj-$(CONFIG_AT91SAM9_SMC) += sam9_smc.o
-obj-$(CONFIG_AT91SAM9_TIMER) += at91sam926x_time.o
 
 # CPU-specific support
 obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index f1ab554..f3c3255 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -53,3 +53,7 @@ config CLOCKSOURCE_UEMD
 config CLOCKSOURCE_ROCKCHIP
 	bool
 	depends on ARCH_ROCKCHIP
+
+config CLOCKSOURCE_ATMEL_PIT
+       bool
+       depends on SOC_AT91SAM9 || SOC_SAMA5
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 39982ff..0564d8f 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_CLOCKSOURCE_NOMADIK) += nomadik.o
 obj-$(CONFIG_CLOCKSOURCE_ORION)   += orion.o
 obj-$(CONFIG_CLOCKSOURCE_UEMD)    += uemd.o
 obj-$(CONFIG_CLOCKSOURCE_ROCKCHIP)+= rk_timer.o
+obj-$(CONFIG_CLOCKSOURCE_ATMEL_PIT) += timer-atmel-pit.o
diff --git a/arch/arm/mach-at91/at91sam926x_time.c b/drivers/clocksource/timer-atmel-pit.c
similarity index 100%
rename from arch/arm/mach-at91/at91sam926x_time.c
rename to drivers/clocksource/timer-atmel-pit.c
-- 
2.9.3


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

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

* [PATCH 06/45] clocksource: at91: Add DT compatibility table
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (4 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 05/45] clocksource: at91: Move to 'drivers/clocksource' Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 07/45] serial: atmel: Check result of clk_get() Andrey Smirnov
                   ` (40 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/clocksource/timer-atmel-pit.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c
index cc7ad2f..d59efa6 100644
--- a/drivers/clocksource/timer-atmel-pit.c
+++ b/drivers/clocksource/timer-atmel-pit.c
@@ -102,9 +102,18 @@ static int at91_pit_probe(struct device_d *dev)
 	return init_clock(&cs);
 }
 
+static __maybe_unused struct of_device_id at91_pit_dt_ids[] = {
+	{
+		.compatible = "atmel,at91sam9260-pit",
+	}, {
+		/* sentinel */
+	}
+};
+
 static struct driver_d at91_pit_driver = {
 	.name = "at91-pit",
 	.probe = at91_pit_probe,
+	.of_compatible = DRV_OF_COMPAT(at91_pit_dt_ids),
 };
 
 static int at91_pit_init(void)
-- 
2.9.3


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

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

* [PATCH 07/45] serial: atmel: Check result of clk_get()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (5 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 06/45] clocksource: at91: Add DT compatibility table Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-07  7:46   ` Sascha Hauer
  2017-03-06 22:53 ` [PATCH 08/45] serial: atmel: Add DT compatibility table Andrey Smirnov
                   ` (39 subsequent siblings)
  46 siblings, 1 reply; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/serial/atmel.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
index 4e4624e..d47b926 100644
--- a/drivers/serial/atmel.c
+++ b/drivers/serial/atmel.c
@@ -403,6 +403,11 @@ static int atmel_serial_init_port(struct console_device *cdev)
 		return -ENOENT;
 
 	uart->clk = clk_get(dev, "usart");
+	if (IS_ERR(uart->clk)) {
+		dev_err(dev, "Faield to get 'usart' clock\n");
+		return PTR_ERR(uart->clk);
+	}
+
 	clk_enable(uart->clk);
 	uart->uartclk = clk_get_rate(uart->clk);
 
-- 
2.9.3


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

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

* [PATCH 08/45] serial: atmel: Add DT compatibility table
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (6 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 07/45] serial: atmel: Check result of clk_get() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 09/45] regmap: Implement syscon_node_to_regmap() Andrey Smirnov
                   ` (38 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/serial/atmel.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
index d47b926..0c174cd 100644
--- a/drivers/serial/atmel.c
+++ b/drivers/serial/atmel.c
@@ -446,8 +446,15 @@ static int atmel_serial_probe(struct device_d *dev)
 	return 0;
 }
 
+static const struct of_device_id __maybe_unused atmel_serial_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-usart" },
+	{ .compatible = "atmel,at91sam9260-usart" },
+	{ /* sentinel */ }
+};
+
 static struct driver_d atmel_serial_driver = {
         .name  = "atmel_usart",
         .probe = atmel_serial_probe,
+	.of_compatible = DRV_OF_COMPAT(atmel_serial_dt_ids),
 };
 console_platform_driver(atmel_serial_driver);
-- 
2.9.3


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

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

* [PATCH 09/45] regmap: Implement syscon_node_to_regmap()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (7 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 08/45] serial: atmel: Add DT compatibility table Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 10/45] clk: Port two helper functions from Linux Andrey Smirnov
                   ` (37 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Implement syscon_node_to_regmap() to simplify porting kernel code.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/mfd/syscon.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 include/mfd/syscon.h |  8 ++++++++
 2 files changed, 61 insertions(+), 1 deletion(-)

diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index 6ef30ce..957d9a7 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -28,6 +28,34 @@ struct syscon {
 	struct device_node *np;
 	void __iomem *base;
 	struct list_head list;
+	struct regmap *regmap;
+};
+
+static int syscon_reg_write(void *context, unsigned int reg,
+			    unsigned int val)
+{
+	struct syscon *syscon = context;
+	writel(val, syscon->base + reg);
+	return 0;
+}
+
+static int syscon_reg_read(void *context, unsigned int reg,
+			   unsigned int *val)
+{
+	struct syscon *syscon = context;
+	*val = readl(syscon->base + reg);
+	return 0;
+}
+
+static const struct regmap_bus syscon_regmap_bus = {
+	.reg_write = syscon_reg_write,
+	.reg_read  = syscon_reg_read,
+};
+
+static const struct regmap_config syscon_regmap_config = {
+	.reg_bits = 32,
+	.val_bits = 32,
+	.reg_stride = 4,
 };
 
 static struct syscon *of_syscon_register(struct device_node *np)
@@ -51,6 +79,10 @@ static struct syscon *of_syscon_register(struct device_node *np)
 
 	list_add_tail(&syscon->list, &syscon_list);
 
+	syscon->regmap = regmap_init(NULL,
+				     &syscon_regmap_bus,
+				     syscon,
+				     &syscon_regmap_config);
 	return syscon;
 
 err_map:
@@ -58,7 +90,7 @@ err_map:
 	return ERR_PTR(ret);
 }
 
-static void __iomem *syscon_node_to_base(struct device_node *np)
+static struct syscon *node_to_syscon(struct device_node *np)
 {
 	struct syscon *entry, *syscon = NULL;
 
@@ -74,6 +106,16 @@ static void __iomem *syscon_node_to_base(struct device_node *np)
 	if (IS_ERR(syscon))
 		return ERR_CAST(syscon);
 
+	return syscon;
+}
+
+static void __iomem *syscon_node_to_base(struct device_node *np)
+{
+	struct syscon *syscon = node_to_syscon(np);
+
+	if (IS_ERR(syscon))
+		return ERR_CAST(syscon);
+
 	return syscon->base;
 }
 
@@ -108,6 +150,16 @@ void __iomem *syscon_base_lookup_by_phandle(struct device_node *np,
 	return syscon_node_to_base(syscon_np);
 }
 
+struct regmap *syscon_node_to_regmap(struct device_node *np)
+{
+	struct syscon *syscon = node_to_syscon(np);
+
+	if (IS_ERR(syscon))
+		return ERR_CAST(syscon);
+
+	return syscon->regmap;
+}
+
 static int syscon_probe(struct device_d *dev)
 {
 	struct syscon *syscon;
diff --git a/include/mfd/syscon.h b/include/mfd/syscon.h
index 651d4c2..63b893e 100644
--- a/include/mfd/syscon.h
+++ b/include/mfd/syscon.h
@@ -14,10 +14,13 @@
 #ifndef __MFD_SYSCON_H__
 #define __MFD_SYSCON_H__
 
+#include <regmap.h>
+
 #ifdef CONFIG_MFD_SYSCON
 void __iomem *syscon_base_lookup_by_pdevname(const char *s);
 void __iomem *syscon_base_lookup_by_phandle
 	(struct device_node *np, const char *property);
+struct regmap *syscon_node_to_regmap(struct device_node *np);
 #else
 static inline void __iomem *syscon_base_lookup_by_pdevname(const char *s)
 {
@@ -29,6 +32,11 @@ static inline void __iomem *syscon_base_lookup_by_phandle
 {
 	return ERR_PTR(-ENOSYS);
 }
+
+static inline struct regmap *syscon_node_to_regmap(struct device_node *np)
+{
+	return ERR_PTR(-ENOSYS);
+}
 #endif
 
 #endif
-- 
2.9.3


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

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

* [PATCH 10/45] clk: Port two helper functions from Linux
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (8 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 09/45] regmap: Implement syscon_node_to_regmap() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 11/45] clk: Make COMMON_CLK_OF_PROVIDER depend on OFTREE Andrey Smirnov
                   ` (36 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port of_clk_get_parent_count() and of_clk_parent_fill() from Linux.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/clk/clk.c   | 39 +++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h |  3 +++
 2 files changed, 42 insertions(+)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 93e000c..9189521 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -452,6 +452,24 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
 	return clk;
 }
 
+/**
+ * of_clk_get_parent_count() - Count the number of clocks a device node has
+ * @np: device node to count
+ *
+ * Returns: The number of clocks that are possible parents of this node
+ */
+unsigned int of_clk_get_parent_count(struct device_node *np)
+{
+	int count;
+
+	count = of_count_phandle_with_args(np, "clocks", "#clock-cells");
+	if (count < 0)
+		return 0;
+
+	return count;
+}
+EXPORT_SYMBOL_GPL(of_clk_get_parent_count);
+
 char *of_clk_get_parent_name(struct device_node *np, unsigned int index)
 {
 	struct of_phandle_args clkspec;
@@ -472,6 +490,27 @@ char *of_clk_get_parent_name(struct device_node *np, unsigned int index)
 }
 EXPORT_SYMBOL_GPL(of_clk_get_parent_name);
 
+/**
+ * of_clk_parent_fill() - Fill @parents with names of @np's parents and return
+ * number of parents
+ * @np: Device node pointer associated with clock provider
+ * @parents: pointer to char array that hold the parents' names
+ * @size: size of the @parents array
+ *
+ * Return: number of parents for the clock node.
+ */
+int of_clk_parent_fill(struct device_node *np, const char **parents,
+		       unsigned int size)
+{
+	unsigned int i = 0;
+
+	while (i < size && (parents[i] = of_clk_get_parent_name(np, i)) != NULL)
+		i++;
+
+	return i;
+}
+EXPORT_SYMBOL_GPL(of_clk_parent_fill);
+
 struct clock_provider {
 	of_clk_init_cb_t clk_init_cb;
 	struct device_node *np;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index 7dd5238..f73b029 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -348,7 +348,10 @@ struct clk *of_clk_src_simple_get(struct of_phandle_args *clkspec, void *data);
 struct clk *of_clk_get(struct device_node *np, int index);
 struct clk *of_clk_get_by_name(struct device_node *np, const char *name);
 struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec);
+unsigned int of_clk_get_parent_count(struct device_node *np);
 char *of_clk_get_parent_name(struct device_node *np, unsigned int index);
+int of_clk_parent_fill(struct device_node *np, const char **parents,
+		       unsigned int size);
 int of_clk_init(struct device_node *root, const struct of_device_id *matches);
 #else
 static inline struct clk *of_clk_get(struct device_node *np, int index)
-- 
2.9.3


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

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

* [PATCH 11/45] clk: Make COMMON_CLK_OF_PROVIDER depend on OFTREE
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (9 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 10/45] clk: Port two helper functions from Linux Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 12/45] clk: No-op CLK_OF_DECLARE if not enabled Andrey Smirnov
                   ` (35 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Make COMMON_CLK_OF_PROVIDER depend on OFTREE, this way checking for:

	defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)

can be simplified to just:

	defined(CONFIG_COMMON_CLK_OF_PROVIDER)

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/clk/Kconfig            | 1 +
 drivers/clk/clk-fixed-factor.c | 2 +-
 drivers/clk/clk-fixed.c        | 2 +-
 drivers/clk/clk.c              | 2 +-
 drivers/clk/clkdev.c           | 2 +-
 include/linux/clk.h            | 2 +-
 6 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 1cf0ccb..dedbf6c 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -10,6 +10,7 @@ config COMMON_CLK
 
 config COMMON_CLK_OF_PROVIDER
 	bool
+	depends on OFTREE
 	help
 	  Clock driver provides OF-Tree based clock lookup.
 
diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index 40b63d6..a3dbf33 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -93,7 +93,7 @@ struct clk *clk_fixed_factor(const char *name,
 	return &f->clk;
 }
 
-#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 /**
  * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
  */
diff --git a/drivers/clk/clk-fixed.c b/drivers/clk/clk-fixed.c
index 8164005..f0f7fba 100644
--- a/drivers/clk/clk-fixed.c
+++ b/drivers/clk/clk-fixed.c
@@ -55,7 +55,7 @@ struct clk *clk_fixed(const char *name, int rate)
 	return &fix->clk;
 }
 
-#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 /**
  * of_fixed_clk_setup() - Setup function for simple fixed rate clock
  */
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 9189521..5bb147e 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -346,7 +346,7 @@ int clk_parent_set_rate(struct clk *clk, unsigned long rate,
 	return clk_set_rate(clk_get_parent(clk), rate);
 }
 
-#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 /**
  * struct of_clk_provider - Clock provider registration structure
  * @link: Entry in global list of clock providers
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index 1bc5c6d..7f9f8f2 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -24,7 +24,7 @@
 
 static LIST_HEAD(clocks);
 
-#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 struct clk *of_clk_get(struct device_node *np, int index)
 {
 	struct of_phandle_args clkspec;
diff --git a/include/linux/clk.h b/include/linux/clk.h
index f73b029..a061398 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -329,7 +329,7 @@ const struct of_device_id __clk_of_table_##name				\
 __attribute__ ((unused,section (".__clk_of_table"))) \
 	= { .compatible = compat, .data = fn }
 
-#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 int of_clk_add_provider(struct device_node *np,
 			struct clk *(*clk_src_get)(struct of_phandle_args *args,
 						   void *data),
-- 
2.9.3


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

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

* [PATCH 12/45] clk: No-op CLK_OF_DECLARE if not enabled
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (10 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 11/45] clk: Make COMMON_CLK_OF_PROVIDER depend on OFTREE Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 13/45] clk: at91: Port at91 DT clock code Andrey Smirnov
                   ` (34 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Instead of wrapping each defenition of CLK_OF_DECLARE hook with
preprocessor guards, change the definition of CLK_OF_DECLARE to expand
into no-op if COMMON_CLK_OF_PROVIDER is not enabled.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/clk/clk-fixed-factor.c | 2 --
 drivers/clk/clk-fixed.c        | 3 +--
 include/linux/clk.h            | 6 +++++-
 3 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/clk/clk-fixed-factor.c b/drivers/clk/clk-fixed-factor.c
index a3dbf33..0be4855 100644
--- a/drivers/clk/clk-fixed-factor.c
+++ b/drivers/clk/clk-fixed-factor.c
@@ -93,7 +93,6 @@ struct clk *clk_fixed_factor(const char *name,
 	return &f->clk;
 }
 
-#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 /**
  * of_fixed_factor_clk_setup() - Setup function for simple fixed factor clock
  */
@@ -127,4 +126,3 @@ static int of_fixed_factor_clk_setup(struct device_node *node)
 }
 CLK_OF_DECLARE(fixed_factor_clk, "fixed-factor-clock",
 		of_fixed_factor_clk_setup);
-#endif
diff --git a/drivers/clk/clk-fixed.c b/drivers/clk/clk-fixed.c
index f0f7fba..9fa9a93 100644
--- a/drivers/clk/clk-fixed.c
+++ b/drivers/clk/clk-fixed.c
@@ -55,7 +55,6 @@ struct clk *clk_fixed(const char *name, int rate)
 	return &fix->clk;
 }
 
-#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 /**
  * of_fixed_clk_setup() - Setup function for simple fixed rate clock
  */
@@ -76,4 +75,4 @@ static int of_fixed_clk_setup(struct device_node *node)
 	return of_clk_add_provider(node, of_clk_src_simple_get, clk);
 }
 CLK_OF_DECLARE(fixed_clk, "fixed-clock", of_fixed_clk_setup);
-#endif
+
diff --git a/include/linux/clk.h b/include/linux/clk.h
index a061398..f705532 100644
--- a/include/linux/clk.h
+++ b/include/linux/clk.h
@@ -324,12 +324,13 @@ struct clk *clk_register_composite(const char *name,
 struct device_node;
 struct of_phandle_args;
 
+#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+
 #define CLK_OF_DECLARE(name, compat, fn)				\
 const struct of_device_id __clk_of_table_##name				\
 __attribute__ ((unused,section (".__clk_of_table"))) \
 	= { .compatible = compat, .data = fn }
 
-#if defined(CONFIG_COMMON_CLK_OF_PROVIDER)
 int of_clk_add_provider(struct device_node *np,
 			struct clk *(*clk_src_get)(struct of_phandle_args *args,
 						   void *data),
@@ -354,6 +355,9 @@ int of_clk_parent_fill(struct device_node *np, const char **parents,
 		       unsigned int size);
 int of_clk_init(struct device_node *root, const struct of_device_id *matches);
 #else
+
+#define CLK_OF_DECLARE(name, compat, fn)
+
 static inline struct clk *of_clk_get(struct device_node *np, int index)
 {
 	return ERR_PTR(-ENOENT);
-- 
2.9.3


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

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

* [PATCH 13/45] clk: at91: Port at91 DT clock code
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (11 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 12/45] clk: No-op CLK_OF_DECLARE if not enabled Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 14/45] at91sam9x5ek: Convert to use DT clock tree Andrey Smirnov
                   ` (33 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port at91 DT clock code from Linux 4.9-rc3.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/Kconfig                    |   1 +
 arch/arm/mach-at91/Kconfig          |  20 ++
 drivers/clk/Makefile                |   1 +
 drivers/clk/at91/Makefile           |  15 +
 drivers/clk/at91/clk-generated.c    | 323 ++++++++++++++++++++
 drivers/clk/at91/clk-h32mx.c        | 125 ++++++++
 drivers/clk/at91/clk-main.c         | 576 ++++++++++++++++++++++++++++++++++++
 drivers/clk/at91/clk-master.c       | 245 +++++++++++++++
 drivers/clk/at91/clk-peripheral.c   | 430 +++++++++++++++++++++++++++
 drivers/clk/at91/clk-pll.c          | 516 ++++++++++++++++++++++++++++++++
 drivers/clk/at91/clk-plldiv.c       | 135 +++++++++
 drivers/clk/at91/clk-programmable.c | 254 ++++++++++++++++
 drivers/clk/at91/clk-slow.c         | 108 +++++++
 drivers/clk/at91/clk-smd.c          | 172 +++++++++++
 drivers/clk/at91/clk-system.c       | 160 ++++++++++
 drivers/clk/at91/clk-usb.c          | 397 +++++++++++++++++++++++++
 drivers/clk/at91/clk-utmi.c         | 138 +++++++++
 drivers/clk/at91/pmc.c              |  41 +++
 drivers/clk/at91/pmc.h              |  27 ++
 drivers/clk/at91/sckc.c             | 485 ++++++++++++++++++++++++++++++
 include/linux/clk/at91_pmc.h        | 188 ++++++++++++
 21 files changed, 4357 insertions(+)
 create mode 100644 drivers/clk/at91/Makefile
 create mode 100644 drivers/clk/at91/clk-generated.c
 create mode 100644 drivers/clk/at91/clk-h32mx.c
 create mode 100644 drivers/clk/at91/clk-main.c
 create mode 100644 drivers/clk/at91/clk-master.c
 create mode 100644 drivers/clk/at91/clk-peripheral.c
 create mode 100644 drivers/clk/at91/clk-pll.c
 create mode 100644 drivers/clk/at91/clk-plldiv.c
 create mode 100644 drivers/clk/at91/clk-programmable.c
 create mode 100644 drivers/clk/at91/clk-slow.c
 create mode 100644 drivers/clk/at91/clk-smd.c
 create mode 100644 drivers/clk/at91/clk-system.c
 create mode 100644 drivers/clk/at91/clk-usb.c
 create mode 100644 drivers/clk/at91/clk-utmi.c
 create mode 100644 drivers/clk/at91/pmc.c
 create mode 100644 drivers/clk/at91/pmc.h
 create mode 100644 drivers/clk/at91/sckc.c
 create mode 100644 include/linux/clk/at91_pmc.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cfa9214..13eed8f 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -54,6 +54,7 @@ config ARCH_AT91
 	select HAS_DEBUG_LL
 	select HAVE_CLK
 	select PINCTRL_AT91
+	select COMMON_CLK_AT91
 
 config ARCH_BCM2835
 	bool "Broadcom BCM2835 boards"
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index fe0269d..2870bf3 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -9,6 +9,26 @@ config HAVE_AT91_DBGU1
 config HAVE_AT91_DBGU2
 	bool
 
+config HAVE_AT91_UTMI
+	bool
+
+config HAVE_AT91_USB_CLK
+	bool
+
+config COMMON_CLK_AT91
+	bool
+	select COMMON_CLK
+	select MFD_SYSCON
+
+config HAVE_AT91_SMD
+	bool
+
+config HAVE_AT91_H32MX
+	bool
+
+config HAVE_AT91_GENERATED_CLK
+	bool
+
 config HAVE_AT91_LOWLEVEL_INIT
 	bool
 
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index 5811d28..d75b954 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_ARCH_TEGRA)	+= tegra/
 obj-$(CONFIG_CLK_SOCFPGA)	+= socfpga.o
 obj-$(CONFIG_MACH_MIPS_ATH79)	+= clk-ar933x.o
 obj-$(CONFIG_ARCH_IMX)		+= imx/
+obj-$(CONFIG_COMMON_CLK_AT91)	+= at91/
diff --git a/drivers/clk/at91/Makefile b/drivers/clk/at91/Makefile
new file mode 100644
index 0000000..bfd06a4
--- /dev/null
+++ b/drivers/clk/at91/Makefile
@@ -0,0 +1,15 @@
+#
+# Makefile for at91 specific clk
+#
+
+obj-y += pmc.o sckc.o
+obj-y += clk-slow.o clk-main.o clk-pll.o clk-plldiv.o clk-master.o
+obj-y += clk-system.o clk-peripheral.o clk-programmable.o
+
+obj-$(CONFIG_HAVE_AT91_UTMI)		+= clk-utmi.o
+obj-$(CONFIG_HAVE_AT91_USB_CLK)		+= clk-usb.o
+obj-$(CONFIG_HAVE_AT91_SMD)		+= clk-smd.o
+obj-$(CONFIG_HAVE_AT91_H32MX)		+= clk-h32mx.o
+obj-$(CONFIG_HAVE_AT91_GENERATED_CLK)	+= clk-generated.o
+
+
diff --git a/drivers/clk/at91/clk-generated.c b/drivers/clk/at91/clk-generated.c
new file mode 100644
index 0000000..4e1cd5a
--- /dev/null
+++ b/drivers/clk/at91/clk-generated.c
@@ -0,0 +1,323 @@
+/*
+ *  Copyright (C) 2015 Atmel Corporation,
+ *                     Nicolas Ferre <nicolas.ferre@atmel.com>
+ *
+ * Based on clk-programmable & clk-peripheral drivers by Boris BREZILLON.
+ *
+ * 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 <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "pmc.h"
+
+#define PERIPHERAL_MAX		64
+#define PERIPHERAL_ID_MIN	2
+
+#define GENERATED_SOURCE_MAX	6
+#define GENERATED_MAX_DIV	255
+
+struct clk_generated {
+	struct clk_hw hw;
+	struct regmap *regmap;
+	struct clk_range range;
+	spinlock_t *lock;
+	u32 id;
+	u32 gckdiv;
+	u8 parent_id;
+};
+
+#define to_clk_generated(hw) \
+	container_of(hw, struct clk_generated, hw)
+
+static int clk_generated_enable(struct clk_hw *hw)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+	unsigned long flags;
+
+	pr_debug("GCLK: %s, gckdiv = %d, parent id = %d\n",
+		 __func__, gck->gckdiv, gck->parent_id);
+
+	spin_lock_irqsave(gck->lock, flags);
+	regmap_write(gck->regmap, AT91_PMC_PCR,
+		     (gck->id & AT91_PMC_PCR_PID_MASK));
+	regmap_update_bits(gck->regmap, AT91_PMC_PCR,
+			   AT91_PMC_PCR_GCKDIV_MASK | AT91_PMC_PCR_GCKCSS_MASK |
+			   AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
+			   AT91_PMC_PCR_GCKCSS(gck->parent_id) |
+			   AT91_PMC_PCR_CMD |
+			   AT91_PMC_PCR_GCKDIV(gck->gckdiv) |
+			   AT91_PMC_PCR_GCKEN);
+	spin_unlock_irqrestore(gck->lock, flags);
+	return 0;
+}
+
+static void clk_generated_disable(struct clk_hw *hw)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+	unsigned long flags;
+
+	spin_lock_irqsave(gck->lock, flags);
+	regmap_write(gck->regmap, AT91_PMC_PCR,
+		     (gck->id & AT91_PMC_PCR_PID_MASK));
+	regmap_update_bits(gck->regmap, AT91_PMC_PCR,
+			   AT91_PMC_PCR_CMD | AT91_PMC_PCR_GCKEN,
+			   AT91_PMC_PCR_CMD);
+	spin_unlock_irqrestore(gck->lock, flags);
+}
+
+static int clk_generated_is_enabled(struct clk_hw *hw)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+	unsigned long flags;
+	unsigned int status;
+
+	spin_lock_irqsave(gck->lock, flags);
+	regmap_write(gck->regmap, AT91_PMC_PCR,
+		     (gck->id & AT91_PMC_PCR_PID_MASK));
+	regmap_read(gck->regmap, AT91_PMC_PCR, &status);
+	spin_unlock_irqrestore(gck->lock, flags);
+
+	return status & AT91_PMC_PCR_GCKEN ? 1 : 0;
+}
+
+static unsigned long
+clk_generated_recalc_rate(struct clk_hw *hw,
+			  unsigned long parent_rate)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+
+	return DIV_ROUND_CLOSEST(parent_rate, gck->gckdiv + 1);
+}
+
+static int clk_generated_determine_rate(struct clk_hw *hw,
+					struct clk_rate_request *req)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+	struct clk_hw *parent = NULL;
+	long best_rate = -EINVAL;
+	unsigned long tmp_rate, min_rate;
+	int best_diff = -1;
+	int tmp_diff;
+	int i;
+
+	for (i = 0; i < clk_hw_get_num_parents(hw); i++) {
+		u32 div;
+		unsigned long parent_rate;
+
+		parent = clk_hw_get_parent_by_index(hw, i);
+		if (!parent)
+			continue;
+
+		parent_rate = clk_hw_get_rate(parent);
+		min_rate = DIV_ROUND_CLOSEST(parent_rate, GENERATED_MAX_DIV + 1);
+		if (!parent_rate ||
+		    (gck->range.max && min_rate > gck->range.max))
+			continue;
+
+		for (div = 1; div < GENERATED_MAX_DIV + 2; div++) {
+			tmp_rate = DIV_ROUND_CLOSEST(parent_rate, div);
+			tmp_diff = abs(req->rate - tmp_rate);
+
+			if (best_diff < 0 || best_diff > tmp_diff) {
+				best_rate = tmp_rate;
+				best_diff = tmp_diff;
+				req->best_parent_rate = parent_rate;
+				req->best_parent_hw = parent;
+			}
+
+			if (!best_diff || tmp_rate < req->rate)
+				break;
+		}
+
+		if (!best_diff)
+			break;
+	}
+
+	pr_debug("GCLK: %s, best_rate = %ld, parent clk: %s @ %ld\n",
+		 __func__, best_rate,
+		 __clk_get_name((req->best_parent_hw)->clk),
+		 req->best_parent_rate);
+
+	if (best_rate < 0)
+		return best_rate;
+
+	req->rate = best_rate;
+	return 0;
+}
+
+/* No modification of hardware as we have the flag CLK_SET_PARENT_GATE set */
+static int clk_generated_set_parent(struct clk_hw *hw, u8 index)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+
+	if (index >= clk_hw_get_num_parents(hw))
+		return -EINVAL;
+
+	gck->parent_id = index;
+	return 0;
+}
+
+static u8 clk_generated_get_parent(struct clk_hw *hw)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+
+	return gck->parent_id;
+}
+
+/* No modification of hardware as we have the flag CLK_SET_RATE_GATE set */
+static int clk_generated_set_rate(struct clk_hw *hw,
+				  unsigned long rate,
+				  unsigned long parent_rate)
+{
+	struct clk_generated *gck = to_clk_generated(hw);
+	u32 div;
+
+	if (!rate)
+		return -EINVAL;
+
+	if (gck->range.max && rate > gck->range.max)
+		return -EINVAL;
+
+	div = DIV_ROUND_CLOSEST(parent_rate, rate);
+	if (div > GENERATED_MAX_DIV + 1 || !div)
+		return -EINVAL;
+
+	gck->gckdiv = div - 1;
+	return 0;
+}
+
+static const struct clk_ops generated_ops = {
+	.enable = clk_generated_enable,
+	.disable = clk_generated_disable,
+	.is_enabled = clk_generated_is_enabled,
+	.recalc_rate = clk_generated_recalc_rate,
+	.determine_rate = clk_generated_determine_rate,
+	.get_parent = clk_generated_get_parent,
+	.set_parent = clk_generated_set_parent,
+	.set_rate = clk_generated_set_rate,
+};
+
+/**
+ * clk_generated_startup - Initialize a given clock to its default parent and
+ * divisor parameter.
+ *
+ * @gck:	Generated clock to set the startup parameters for.
+ *
+ * Take parameters from the hardware and update local clock configuration
+ * accordingly.
+ */
+static void clk_generated_startup(struct clk_generated *gck)
+{
+	u32 tmp;
+	unsigned long flags;
+
+	spin_lock_irqsave(gck->lock, flags);
+	regmap_write(gck->regmap, AT91_PMC_PCR,
+		     (gck->id & AT91_PMC_PCR_PID_MASK));
+	regmap_read(gck->regmap, AT91_PMC_PCR, &tmp);
+	spin_unlock_irqrestore(gck->lock, flags);
+
+	gck->parent_id = (tmp & AT91_PMC_PCR_GCKCSS_MASK)
+					>> AT91_PMC_PCR_GCKCSS_OFFSET;
+	gck->gckdiv = (tmp & AT91_PMC_PCR_GCKDIV_MASK)
+					>> AT91_PMC_PCR_GCKDIV_OFFSET;
+}
+
+static struct clk_hw * __init
+at91_clk_register_generated(struct regmap *regmap, spinlock_t *lock,
+			    const char *name, const char **parent_names,
+			    u8 num_parents, u8 id,
+			    const struct clk_range *range)
+{
+	struct clk_generated *gck;
+	struct clk_init_data init;
+	struct clk_hw *hw;
+	int ret;
+
+	gck = kzalloc(sizeof(*gck), GFP_KERNEL);
+	if (!gck)
+		return ERR_PTR(-ENOMEM);
+
+	init.name = name;
+	init.ops = &generated_ops;
+	init.parent_names = parent_names;
+	init.num_parents = num_parents;
+	init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE;
+
+	gck->id = id;
+	gck->hw.init = &init;
+	gck->regmap = regmap;
+	gck->lock = lock;
+	gck->range = *range;
+
+	hw = &gck->hw;
+	ret = clk_hw_register(NULL, &gck->hw);
+	if (ret) {
+		kfree(gck);
+		hw = ERR_PTR(ret);
+	} else
+		clk_generated_startup(gck);
+
+	return hw;
+}
+
+static void __init of_sama5d2_clk_generated_setup(struct device_node *np)
+{
+	int num;
+	u32 id;
+	const char *name;
+	struct clk_hw *hw;
+	unsigned int num_parents;
+	const char *parent_names[GENERATED_SOURCE_MAX];
+	struct device_node *gcknp;
+	struct clk_range range = CLK_RANGE(0, 0);
+	struct regmap *regmap;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents == 0 || num_parents > GENERATED_SOURCE_MAX)
+		return;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+
+	num = of_get_child_count(np);
+	if (!num || num > PERIPHERAL_MAX)
+		return;
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return;
+
+	for_each_child_of_node(np, gcknp) {
+		if (of_property_read_u32(gcknp, "reg", &id))
+			continue;
+
+		if (id < PERIPHERAL_ID_MIN || id >= PERIPHERAL_MAX)
+			continue;
+
+		if (of_property_read_string(np, "clock-output-names", &name))
+			name = gcknp->name;
+
+		of_at91_get_clk_range(gcknp, "atmel,clk-output-range",
+				      &range);
+
+		hw = at91_clk_register_generated(regmap, &pmc_pcr_lock, name,
+						  parent_names, num_parents,
+						  id, &range);
+		if (IS_ERR(hw))
+			continue;
+
+		of_clk_add_hw_provider(gcknp, of_clk_hw_simple_get, hw);
+	}
+}
+CLK_OF_DECLARE(of_sama5d2_clk_generated_setup, "atmel,sama5d2-clk-generated",
+	       of_sama5d2_clk_generated_setup);
diff --git a/drivers/clk/at91/clk-h32mx.c b/drivers/clk/at91/clk-h32mx.c
new file mode 100644
index 0000000..e0daa4a
--- /dev/null
+++ b/drivers/clk/at91/clk-h32mx.c
@@ -0,0 +1,125 @@
+/*
+ * clk-h32mx.c
+ *
+ *  Copyright (C) 2014 Atmel
+ *
+ * Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * 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 <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/at91_pmc.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "pmc.h"
+
+#define H32MX_MAX_FREQ	90000000
+
+struct clk_sama5d4_h32mx {
+	struct clk_hw hw;
+	struct regmap *regmap;
+};
+
+#define to_clk_sama5d4_h32mx(hw) container_of(hw, struct clk_sama5d4_h32mx, hw)
+
+static unsigned long clk_sama5d4_h32mx_recalc_rate(struct clk_hw *hw,
+						 unsigned long parent_rate)
+{
+	struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
+	unsigned int mckr;
+
+	regmap_read(h32mxclk->regmap, AT91_PMC_MCKR, &mckr);
+	if (mckr & AT91_PMC_H32MXDIV)
+		return parent_rate / 2;
+
+	if (parent_rate > H32MX_MAX_FREQ)
+		pr_warn("H32MX clock is too fast\n");
+	return parent_rate;
+}
+
+static long clk_sama5d4_h32mx_round_rate(struct clk_hw *hw, unsigned long rate,
+				       unsigned long *parent_rate)
+{
+	unsigned long div;
+
+	if (rate > *parent_rate)
+		return *parent_rate;
+	div = *parent_rate / 2;
+	if (rate < div)
+		return div;
+
+	if (rate - div < *parent_rate - rate)
+		return div;
+
+	return *parent_rate;
+}
+
+static int clk_sama5d4_h32mx_set_rate(struct clk_hw *hw, unsigned long rate,
+				    unsigned long parent_rate)
+{
+	struct clk_sama5d4_h32mx *h32mxclk = to_clk_sama5d4_h32mx(hw);
+	u32 mckr = 0;
+
+	if (parent_rate != rate && (parent_rate / 2) != rate)
+		return -EINVAL;
+
+	if ((parent_rate / 2) == rate)
+		mckr = AT91_PMC_H32MXDIV;
+
+	regmap_update_bits(h32mxclk->regmap, AT91_PMC_MCKR,
+			   AT91_PMC_H32MXDIV, mckr);
+
+	return 0;
+}
+
+static const struct clk_ops h32mx_ops = {
+	.recalc_rate = clk_sama5d4_h32mx_recalc_rate,
+	.round_rate = clk_sama5d4_h32mx_round_rate,
+	.set_rate = clk_sama5d4_h32mx_set_rate,
+};
+
+static void __init of_sama5d4_clk_h32mx_setup(struct device_node *np)
+{
+	struct clk_sama5d4_h32mx *h32mxclk;
+	struct clk_init_data init;
+	const char *parent_name;
+	struct regmap *regmap;
+	int ret;
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return;
+
+	h32mxclk = kzalloc(sizeof(*h32mxclk), GFP_KERNEL);
+	if (!h32mxclk)
+		return;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	init.name = np->name;
+	init.ops = &h32mx_ops;
+	init.parent_names = parent_name ? &parent_name : NULL;
+	init.num_parents = parent_name ? 1 : 0;
+	init.flags = CLK_SET_RATE_GATE;
+
+	h32mxclk->hw.init = &init;
+	h32mxclk->regmap = regmap;
+
+	ret = clk_hw_register(NULL, &h32mxclk->hw);
+	if (ret) {
+		kfree(h32mxclk);
+		return;
+	}
+
+	of_clk_add_hw_provider(np, of_clk_hw_simple_get, &h32mxclk->hw);
+}
+CLK_OF_DECLARE(of_sama5d4_clk_h32mx_setup, "atmel,sama5d4-clk-h32mx",
+	       of_sama5d4_clk_h32mx_setup);
diff --git a/drivers/clk/at91/clk-main.c b/drivers/clk/at91/clk-main.c
new file mode 100644
index 0000000..c1f47c1
--- /dev/null
+++ b/drivers/clk/at91/clk-main.c
@@ -0,0 +1,576 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define SLOW_CLOCK_FREQ		32768
+#define MAINF_DIV		16
+#define MAINFRDY_TIMEOUT	(((MAINF_DIV + 1) * SECOND) / \
+				 SLOW_CLOCK_FREQ)
+#define MAINF_LOOP_MIN_WAIT	(SECOND / SLOW_CLOCK_FREQ)
+#define MAINF_LOOP_MAX_WAIT	MAINFRDY_TIMEOUT
+
+#define MOR_KEY_MASK		(0xff << 16)
+
+struct clk_main_osc {
+	struct clk clk;
+	struct regmap *regmap;
+	const char *parent;
+};
+
+#define to_clk_main_osc(clk) container_of(clk, struct clk_main_osc, clk)
+
+struct clk_main_rc_osc {
+	struct clk clk;
+	struct regmap *regmap;
+	unsigned long frequency;
+};
+
+#define to_clk_main_rc_osc(clk) container_of(clk, struct clk_main_rc_osc, clk)
+
+struct clk_rm9200_main {
+	struct clk clk;
+	struct regmap *regmap;
+	const char *parent;
+};
+
+#define to_clk_rm9200_main(clk) container_of(clk, struct clk_rm9200_main, clk)
+
+struct clk_sam9x5_main {
+	struct clk clk;
+	struct regmap *regmap;
+	u8 parent;
+};
+
+#define to_clk_sam9x5_main(clk) container_of(clk, struct clk_sam9x5_main, clk)
+
+static inline bool clk_main_osc_ready(struct regmap *regmap)
+{
+	unsigned int status;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return status & AT91_PMC_MOSCS;
+}
+
+static int clk_main_osc_enable(struct clk *clk)
+{
+	struct clk_main_osc *osc = to_clk_main_osc(clk);
+	struct regmap *regmap = osc->regmap;
+	u32 tmp;
+
+	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
+	tmp &= ~MOR_KEY_MASK;
+
+	if (tmp & AT91_PMC_OSCBYPASS)
+		return 0;
+
+	if (!(tmp & AT91_PMC_MOSCEN)) {
+		tmp |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
+		regmap_write(regmap, AT91_CKGR_MOR, tmp);
+	}
+
+	while (!clk_main_osc_ready(regmap))
+		barrier();
+
+	return 0;
+}
+
+static void clk_main_osc_disable(struct clk *clk)
+{
+	struct clk_main_osc *osc = to_clk_main_osc(clk);
+	struct regmap *regmap = osc->regmap;
+	u32 tmp;
+
+	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
+	if (tmp & AT91_PMC_OSCBYPASS)
+		return;
+
+	if (!(tmp & AT91_PMC_MOSCEN))
+		return;
+
+	tmp &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
+	regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_KEY);
+}
+
+static int clk_main_osc_is_enabled(struct clk *clk)
+{
+	struct clk_main_osc *osc = to_clk_main_osc(clk);
+	struct regmap *regmap = osc->regmap;
+	u32 tmp, status;
+
+	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
+	if (tmp & AT91_PMC_OSCBYPASS)
+		return 1;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return (status & AT91_PMC_MOSCS) && (tmp & AT91_PMC_MOSCEN);
+}
+
+static const struct clk_ops main_osc_ops = {
+	.enable = clk_main_osc_enable,
+	.disable = clk_main_osc_disable,
+	.is_enabled = clk_main_osc_is_enabled,
+};
+
+static struct clk *
+at91_clk_register_main_osc(struct regmap *regmap,
+			   const char *name,
+			   const char *parent_name,
+			   bool bypass)
+{
+	struct clk_main_osc *osc;
+	int ret;
+
+	if (!name || !parent_name)
+		return ERR_PTR(-EINVAL);
+
+	osc = xzalloc(sizeof(*osc));
+
+	osc->parent = parent_name;
+	osc->clk.name = name;
+	osc->clk.ops = &main_osc_ops;
+	osc->clk.parent_names = &osc->parent;
+	osc->clk.num_parents = 1;
+	osc->regmap = regmap;
+
+	if (bypass)
+		regmap_write_bits(regmap,
+				  AT91_CKGR_MOR, MOR_KEY_MASK |
+				  AT91_PMC_MOSCEN,
+				  AT91_PMC_OSCBYPASS | AT91_PMC_KEY);
+
+	ret = clk_register(&osc->clk);
+	if (ret) {
+		free(osc);
+		return ERR_PTR(ret);
+	}
+
+	return &osc->clk;
+}
+
+static int of_at91rm9200_clk_main_osc_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *name = np->name;
+	const char *parent_name;
+	struct regmap *regmap;
+	bool bypass;
+
+	of_property_read_string(np, "clock-output-names", &name);
+	bypass = of_property_read_bool(np, "atmel,osc-bypass");
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91_clk_register_main_osc(regmap, name, parent_name, bypass);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91rm9200_clk_main_osc, "atmel,at91rm9200-clk-main-osc",
+	       of_at91rm9200_clk_main_osc_setup);
+
+static bool clk_main_rc_osc_ready(struct regmap *regmap)
+{
+	unsigned int status;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return status & AT91_PMC_MOSCRCS;
+}
+
+static int clk_main_rc_osc_enable(struct clk *clk)
+{
+	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(clk);
+	struct regmap *regmap = osc->regmap;
+	unsigned int mor;
+
+	regmap_read(regmap, AT91_CKGR_MOR, &mor);
+
+	if (!(mor & AT91_PMC_MOSCRCEN))
+		regmap_write_bits(regmap, AT91_CKGR_MOR,
+				  MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
+				  AT91_PMC_MOSCRCEN | AT91_PMC_KEY);
+
+	while (!clk_main_rc_osc_ready(regmap))
+		barrier();
+
+	return 0;
+}
+
+static void clk_main_rc_osc_disable(struct clk *clk)
+{
+	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(clk);
+	struct regmap *regmap = osc->regmap;
+	unsigned int mor;
+
+	regmap_read(regmap, AT91_CKGR_MOR, &mor);
+
+	if (!(mor & AT91_PMC_MOSCRCEN))
+		return;
+
+	regmap_write_bits(regmap, AT91_CKGR_MOR,
+			  MOR_KEY_MASK | AT91_PMC_MOSCRCEN, AT91_PMC_KEY);
+}
+
+static int clk_main_rc_osc_is_enabled(struct clk *clk)
+{
+	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(clk);
+	struct regmap *regmap = osc->regmap;
+	unsigned int mor, status;
+
+	regmap_read(regmap, AT91_CKGR_MOR, &mor);
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return (mor & AT91_PMC_MOSCRCEN) && (status & AT91_PMC_MOSCRCS);
+}
+
+static unsigned long clk_main_rc_osc_recalc_rate(struct clk *clk,
+						 unsigned long parent_rate)
+{
+	struct clk_main_rc_osc *osc = to_clk_main_rc_osc(clk);
+
+	return osc->frequency;
+}
+
+static const struct clk_ops main_rc_osc_ops = {
+	.enable = clk_main_rc_osc_enable,
+	.disable = clk_main_rc_osc_disable,
+	.is_enabled = clk_main_rc_osc_is_enabled,
+	.recalc_rate = clk_main_rc_osc_recalc_rate,
+};
+
+static struct clk *
+at91_clk_register_main_rc_osc(struct regmap *regmap,
+			      const char *name,
+			      u32 frequency)
+{
+	int ret;
+	struct clk_main_rc_osc *osc;
+
+	if (!name || !frequency)
+		return ERR_PTR(-EINVAL);
+
+	osc = xzalloc(sizeof(*osc));
+
+	osc->clk.name = name;
+	osc->clk.ops = &main_rc_osc_ops;
+	osc->clk.parent_names = NULL;
+	osc->clk.num_parents = 0;
+
+	osc->regmap = regmap;
+	osc->frequency = frequency;
+
+	ret = clk_register(&osc->clk);
+	if (ret) {
+		kfree(osc);
+		return ERR_PTR(ret);
+	}
+
+	return &osc->clk;
+}
+
+static int of_at91sam9x5_clk_main_rc_osc_setup(struct device_node *np)
+{
+	struct clk *clk;
+	u32 frequency = 0;
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	of_property_read_string(np, "clock-output-names", &name);
+	of_property_read_u32(np, "clock-frequency", &frequency);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91_clk_register_main_rc_osc(regmap, name, frequency);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_main_rc_osc, "atmel,at91sam9x5-clk-main-rc-osc",
+	       of_at91sam9x5_clk_main_rc_osc_setup);
+
+
+static int clk_main_probe_frequency(struct regmap *regmap)
+{
+	unsigned int mcfr;
+	uint64_t start = get_time_ns();
+
+	do {
+		regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
+		if (mcfr & AT91_PMC_MAINRDY)
+			return 0;
+	} while (!is_timeout(start, MAINFRDY_TIMEOUT *  USECOND));
+
+	return -ETIMEDOUT;
+}
+
+static unsigned long clk_main_recalc_rate(struct regmap *regmap,
+					  unsigned long parent_rate)
+{
+	unsigned int mcfr;
+
+	if (parent_rate)
+		return parent_rate;
+
+	pr_warn("Main crystal frequency not set, using approximate value\n");
+	regmap_read(regmap, AT91_CKGR_MCFR, &mcfr);
+	if (!(mcfr & AT91_PMC_MAINRDY))
+		return 0;
+
+	return ((mcfr & AT91_PMC_MAINF) * SLOW_CLOCK_FREQ) / MAINF_DIV;
+}
+
+static int clk_rm9200_main_enable(struct clk *clk)
+{
+	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(clk);
+
+	return clk_main_probe_frequency(clkmain->regmap);
+}
+
+static int clk_rm9200_main_is_enabled(struct clk *clk)
+{
+	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(clk);
+	unsigned int status;
+
+	regmap_read(clkmain->regmap, AT91_CKGR_MCFR, &status);
+
+	return status & AT91_PMC_MAINRDY ? 1 : 0;
+}
+
+static unsigned long clk_rm9200_main_recalc_rate(struct clk *clk,
+						 unsigned long parent_rate)
+{
+	struct clk_rm9200_main *clkmain = to_clk_rm9200_main(clk);
+
+	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
+}
+
+static const struct clk_ops rm9200_main_ops = {
+	.enable = clk_rm9200_main_enable,
+	.is_enabled = clk_rm9200_main_is_enabled,
+	.recalc_rate = clk_rm9200_main_recalc_rate,
+};
+
+static struct clk *
+at91_clk_register_rm9200_main(struct regmap *regmap,
+			      const char *name,
+			      const char *parent_name)
+{
+	int ret;
+	struct clk_rm9200_main *clkmain;
+
+	if (!name)
+		return ERR_PTR(-EINVAL);
+
+	if (!parent_name)
+		return ERR_PTR(-EINVAL);
+
+	clkmain = xzalloc(sizeof(*clkmain));
+
+	clkmain->clk.name = name;
+	clkmain->clk.ops = &rm9200_main_ops;
+	clkmain->clk.parent_names = &clkmain->parent;
+	clkmain->clk.num_parents = 1;
+	clkmain->regmap = regmap;
+
+	ret = clk_register(&clkmain->clk);
+	if (ret) {
+		kfree(clkmain);
+		return ERR_PTR(ret);
+	}
+
+	return &clkmain->clk;
+}
+
+static int of_at91rm9200_clk_main_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91_clk_register_rm9200_main(regmap, name, parent_name);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91rm9200_clk_main, "atmel,at91rm9200-clk-main",
+	       of_at91rm9200_clk_main_setup);
+
+static inline bool clk_sam9x5_main_ready(struct regmap *regmap)
+{
+	unsigned int status;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return status & AT91_PMC_MOSCSELS ? 1 : 0;
+}
+
+static int clk_sam9x5_main_enable(struct clk *clk)
+{
+	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(clk);
+	struct regmap *regmap = clkmain->regmap;
+
+	while (!clk_sam9x5_main_ready(regmap))
+		barrier();
+
+	return clk_main_probe_frequency(regmap);
+}
+
+static int clk_sam9x5_main_is_enabled(struct clk *clk)
+{
+	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(clk);
+
+	return clk_sam9x5_main_ready(clkmain->regmap);
+}
+
+static unsigned long clk_sam9x5_main_recalc_rate(struct clk *clk,
+						 unsigned long parent_rate)
+{
+	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(clk);
+
+	return clk_main_recalc_rate(clkmain->regmap, parent_rate);
+}
+
+static int clk_sam9x5_main_set_parent(struct clk *clk, u8 index)
+{
+	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(clk);
+	struct regmap *regmap = clkmain->regmap;
+	unsigned int tmp;
+
+	if (index > 1)
+		return -EINVAL;
+
+	regmap_read(regmap, AT91_CKGR_MOR, &tmp);
+	tmp &= ~MOR_KEY_MASK;
+
+	if (index && !(tmp & AT91_PMC_MOSCSEL))
+		regmap_write(regmap, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
+	else if (!index && (tmp & AT91_PMC_MOSCSEL))
+		regmap_write(regmap, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
+
+	while (!clk_sam9x5_main_ready(regmap))
+		barrier();
+
+	return 0;
+}
+
+static int clk_sam9x5_main_get_parent(struct clk *clk)
+{
+	struct clk_sam9x5_main *clkmain = to_clk_sam9x5_main(clk);
+	unsigned int status;
+
+	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
+
+	return status & AT91_PMC_MOSCEN ? 1 : 0;
+}
+
+static const struct clk_ops sam9x5_main_ops = {
+	.enable = clk_sam9x5_main_enable,
+	.is_enabled = clk_sam9x5_main_is_enabled,
+	.recalc_rate = clk_sam9x5_main_recalc_rate,
+	.set_parent = clk_sam9x5_main_set_parent,
+	.get_parent = clk_sam9x5_main_get_parent,
+};
+
+static struct clk *
+at91_clk_register_sam9x5_main(struct regmap *regmap,
+			      const char *name,
+			      const char **parent_names,
+			      int num_parents)
+{
+	int ret;
+	unsigned int status;
+	size_t parents_array_size;
+	struct clk_sam9x5_main *clkmain;
+
+	if (!name)
+		return ERR_PTR(-EINVAL);
+
+	if (!parent_names || !num_parents)
+		return ERR_PTR(-EINVAL);
+
+	clkmain = xzalloc(sizeof(*clkmain));
+
+	clkmain->clk.name = name;
+	clkmain->clk.ops = &sam9x5_main_ops;
+	parents_array_size = num_parents * sizeof (clkmain->clk.parent_names[0]);
+	clkmain->clk.parent_names = xzalloc(parents_array_size);
+	memcpy(clkmain->clk.parent_names, parent_names, parents_array_size);
+	clkmain->clk.num_parents = num_parents;
+	
+	/* init.flags = CLK_SET_PARENT_GATE; */
+
+	clkmain->regmap = regmap;
+	regmap_read(clkmain->regmap, AT91_CKGR_MOR, &status);
+	clkmain->parent = status & AT91_PMC_MOSCEN ? 1 : 0;
+
+	ret = clk_register(&clkmain->clk);
+	if (ret) {
+		kfree(clkmain);
+		return ERR_PTR(ret);
+	}
+
+	return &clkmain->clk;
+}
+
+static int of_at91sam9x5_clk_main_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *parent_names[2];
+	unsigned int num_parents;
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents == 0 || num_parents > 2)
+		return -EINVAL;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	clk = at91_clk_register_sam9x5_main(regmap, name, parent_names,
+					    num_parents);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_main, "atmel,at91sam9x5-clk-main",
+	       of_at91sam9x5_clk_main_setup);
diff --git a/drivers/clk/at91/clk-master.c b/drivers/clk/at91/clk-master.c
new file mode 100644
index 0000000..b3a50ce
--- /dev/null
+++ b/drivers/clk/at91/clk-master.c
@@ -0,0 +1,245 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define MASTER_SOURCE_MAX	4
+
+#define MASTER_PRES_MASK	0x7
+#define MASTER_PRES_MAX		MASTER_PRES_MASK
+#define MASTER_DIV_SHIFT	8
+#define MASTER_DIV_MASK		0x3
+
+struct clk_master_characteristics {
+	struct clk_range output;
+	u32 divisors[4];
+	u8 have_div3_pres;
+};
+
+struct clk_master_layout {
+	u32 mask;
+	u8 pres_shift;
+};
+
+#define to_clk_master(clk) container_of(clk, struct clk_master, clk)
+
+struct clk_master {
+	struct clk clk;
+	struct regmap *regmap;
+	const struct clk_master_layout *layout;
+	const struct clk_master_characteristics *characteristics;
+	const char *parents[MASTER_SOURCE_MAX];
+};
+
+static inline bool clk_master_ready(struct regmap *regmap)
+{
+	unsigned int status;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return status & AT91_PMC_MCKRDY ? 1 : 0;
+}
+
+static int clk_master_enable(struct clk *clk)
+{
+	struct clk_master *master = to_clk_master(clk);
+
+	while (!clk_master_ready(master->regmap))
+		barrier();
+
+	return 0;
+}
+
+static int clk_master_is_enabled(struct clk *clk)
+{
+	struct clk_master *master = to_clk_master(clk);
+
+	return clk_master_ready(master->regmap);
+}
+
+static unsigned long clk_master_recalc_rate(struct clk *clk,
+					    unsigned long parent_rate)
+{
+	u8 pres;
+	u8 div;
+	unsigned long rate = parent_rate;
+	struct clk_master *master = to_clk_master(clk);
+	const struct clk_master_layout *layout = master->layout;
+	const struct clk_master_characteristics *characteristics =
+						master->characteristics;
+	unsigned int mckr;
+
+	regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
+	mckr &= layout->mask;
+
+	pres = (mckr >> layout->pres_shift) & MASTER_PRES_MASK;
+	div = (mckr >> MASTER_DIV_SHIFT) & MASTER_DIV_MASK;
+
+	if (characteristics->have_div3_pres && pres == MASTER_PRES_MAX)
+		rate /= 3;
+	else
+		rate >>= pres;
+
+	rate /= characteristics->divisors[div];
+
+	if (rate < characteristics->output.min)
+		pr_warn("master clk is underclocked");
+	else if (rate > characteristics->output.max)
+		pr_warn("master clk is overclocked");
+
+	return rate;
+}
+
+static int clk_master_get_parent(struct clk *clk)
+{
+	struct clk_master *master = to_clk_master(clk);
+	unsigned int mckr;
+
+	regmap_read(master->regmap, AT91_PMC_MCKR, &mckr);
+
+	return mckr & AT91_PMC_CSS;
+}
+
+static const struct clk_ops master_ops = {
+	.enable = clk_master_enable,
+	.is_enabled = clk_master_is_enabled,
+	.recalc_rate = clk_master_recalc_rate,
+	.get_parent = clk_master_get_parent,
+};
+
+static struct clk *
+at91_clk_register_master(struct regmap *regmap,
+			 const char *name, int num_parents,
+			 const char **parent_names,
+			 const struct clk_master_layout *layout,
+			 const struct clk_master_characteristics *characteristics)
+{
+	int ret;
+	const size_t parent_names_size = num_parents * sizeof(parent_names[0]);
+	struct clk_master *master;
+
+	if (!name || !num_parents || !parent_names)
+		return ERR_PTR(-EINVAL);
+
+	master = xzalloc(sizeof(*master));
+
+	master->clk.name = name;
+	master->clk.ops = &master_ops;
+	memcpy(master->parents, parent_names, parent_names_size);
+	master->clk.parent_names = master->parents;
+	master->clk.num_parents = num_parents;
+
+	master->layout = layout;
+	master->characteristics = characteristics;
+	master->regmap = regmap;
+
+	ret = clk_register(&master->clk);
+	if (ret) {
+		kfree(master);
+		return ERR_PTR(ret);
+	}
+
+	return &master->clk;
+}
+
+
+static const struct clk_master_layout at91rm9200_master_layout = {
+	.mask = 0x31F,
+	.pres_shift = 2,
+};
+
+static const struct clk_master_layout at91sam9x5_master_layout = {
+	.mask = 0x373,
+	.pres_shift = 4,
+};
+
+
+static struct clk_master_characteristics *
+of_at91_clk_master_get_characteristics(struct device_node *np)
+{
+	struct clk_master_characteristics *characteristics;
+
+	characteristics = xzalloc(sizeof(*characteristics));
+
+	if (of_at91_get_clk_range(np, "atmel,clk-output-range", &characteristics->output))
+		goto out_free_characteristics;
+
+	of_property_read_u32_array(np, "atmel,clk-divisors",
+				   characteristics->divisors, 4);
+
+	characteristics->have_div3_pres =
+		of_property_read_bool(np, "atmel,master-clk-have-div3-pres");
+
+	return characteristics;
+
+out_free_characteristics:
+	kfree(characteristics);
+	return NULL;
+}
+
+static int
+of_at91_clk_master_setup(struct device_node *np,
+			 const struct clk_master_layout *layout)
+{
+	struct clk *clk;
+	unsigned int num_parents;
+	const char *parent_names[MASTER_SOURCE_MAX];
+	const char *name = np->name;
+	struct clk_master_characteristics *characteristics;
+	struct regmap *regmap;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents == 0 || num_parents > MASTER_SOURCE_MAX)
+		return -EINVAL;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	characteristics = of_at91_clk_master_get_characteristics(np);
+	if (!characteristics)
+		return -EINVAL;
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91_clk_register_master(regmap, name, num_parents,
+				       parent_names, layout,
+				       characteristics);
+	if (IS_ERR(clk)) {
+		kfree(characteristics);
+		return PTR_ERR(clk);
+	}
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static void __init of_at91rm9200_clk_master_setup(struct device_node *np)
+{
+	of_at91_clk_master_setup(np, &at91rm9200_master_layout);
+}
+CLK_OF_DECLARE(at91rm9200_clk_master, "atmel,at91rm9200-clk-master",
+	       of_at91rm9200_clk_master_setup);
+
+static void __init of_at91sam9x5_clk_master_setup(struct device_node *np)
+{
+	of_at91_clk_master_setup(np, &at91sam9x5_master_layout);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_master, "atmel,at91sam9x5-clk-master",
+	       of_at91sam9x5_clk_master_setup);
diff --git a/drivers/clk/at91/clk-peripheral.c b/drivers/clk/at91/clk-peripheral.c
new file mode 100644
index 0000000..4a76c46
--- /dev/null
+++ b/drivers/clk/at91/clk-peripheral.c
@@ -0,0 +1,430 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define PERIPHERAL_MAX		64
+
+#define PERIPHERAL_AT91RM9200	0
+#define PERIPHERAL_AT91SAM9X5	1
+
+#define PERIPHERAL_ID_MIN	2
+#define PERIPHERAL_ID_MAX	31
+#define PERIPHERAL_MASK(id)	(1 << ((id) & PERIPHERAL_ID_MAX))
+
+#define PERIPHERAL_RSHIFT_MASK	0x3
+#define PERIPHERAL_RSHIFT(val)	(((val) >> 16) & PERIPHERAL_RSHIFT_MASK)
+
+#define PERIPHERAL_MAX_SHIFT	3
+
+struct clk_peripheral {
+	struct clk clk;
+	struct regmap *regmap;
+	u32 id;
+	const char *parent;
+};
+
+#define to_clk_peripheral(clk) container_of(clk, struct clk_peripheral, clk)
+
+struct clk_sam9x5_peripheral {
+	struct clk clk;
+	struct regmap *regmap;
+	struct clk_range range;
+	u32 id;
+	u32 div;
+	bool auto_div;
+	const char *parent;
+};
+
+#define to_clk_sam9x5_peripheral(clk) \
+	container_of(clk, struct clk_sam9x5_peripheral, clk)
+
+static int clk_peripheral_enable(struct clk *clk)
+{
+	struct clk_peripheral *periph = to_clk_peripheral(clk);
+	int offset = AT91_PMC_PCER;
+	u32 id = periph->id;
+
+	if (id < PERIPHERAL_ID_MIN)
+		return 0;
+	if (id > PERIPHERAL_ID_MAX)
+		offset = AT91_PMC_PCER1;
+	regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
+
+	return 0;
+}
+
+static void clk_peripheral_disable(struct clk *clk)
+{
+	struct clk_peripheral *periph = to_clk_peripheral(clk);
+	int offset = AT91_PMC_PCDR;
+	u32 id = periph->id;
+
+	if (id < PERIPHERAL_ID_MIN)
+		return;
+	if (id > PERIPHERAL_ID_MAX)
+		offset = AT91_PMC_PCDR1;
+	regmap_write(periph->regmap, offset, PERIPHERAL_MASK(id));
+}
+
+static int clk_peripheral_is_enabled(struct clk *clk)
+{
+	struct clk_peripheral *periph = to_clk_peripheral(clk);
+	int offset = AT91_PMC_PCSR;
+	unsigned int status;
+	u32 id = periph->id;
+
+	if (id < PERIPHERAL_ID_MIN)
+		return 1;
+	if (id > PERIPHERAL_ID_MAX)
+		offset = AT91_PMC_PCSR1;
+	regmap_read(periph->regmap, offset, &status);
+
+	return status & PERIPHERAL_MASK(id) ? 1 : 0;
+}
+
+static const struct clk_ops peripheral_ops = {
+	.enable = clk_peripheral_enable,
+	.disable = clk_peripheral_disable,
+	.is_enabled = clk_peripheral_is_enabled,
+};
+
+static struct clk *
+at91_clk_register_peripheral(struct regmap *regmap, const char *name,
+			     const char *parent_name, u32 id)
+{
+	int ret;
+	struct clk_peripheral *periph;
+
+	if (!name || !parent_name || id > PERIPHERAL_ID_MAX)
+		return ERR_PTR(-EINVAL);
+
+	periph = xzalloc(sizeof(*periph));
+
+	periph->clk.name = name;
+	periph->clk.ops = &peripheral_ops;
+
+	if (parent_name) {
+		periph->parent = parent_name;
+		periph->clk.parent_names = &periph->parent;
+		periph->clk.num_parents = 1;
+	}
+
+	periph->id = id;
+	periph->regmap = regmap;
+
+	ret = clk_register(&periph->clk);
+	if (ret) {
+		kfree(periph);
+		return ERR_PTR(ret);
+	}
+
+	return &periph->clk;
+}
+
+static void clk_sam9x5_peripheral_autodiv(struct clk_sam9x5_peripheral *periph)
+{
+	struct clk *parent;
+	unsigned long parent_rate;
+	int shift = 0;
+
+	if (!periph->auto_div)
+		return;
+
+	if (periph->range.max) {
+		parent = clk_get_parent(&periph->clk);
+		parent_rate = clk_get_rate(parent);
+		if (!parent_rate)
+			return;
+
+		for (; shift < PERIPHERAL_MAX_SHIFT; shift++) {
+			if (parent_rate >> shift <= periph->range.max)
+				break;
+		}
+	}
+
+	periph->auto_div = false;
+	periph->div = shift;
+}
+
+static int clk_sam9x5_peripheral_enable(struct clk *clk)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+
+	if (periph->id < PERIPHERAL_ID_MIN)
+		return 0;
+
+	regmap_write(periph->regmap, AT91_PMC_PCR,
+		     (periph->id & AT91_PMC_PCR_PID_MASK));
+	regmap_write_bits(periph->regmap, AT91_PMC_PCR,
+			  AT91_PMC_PCR_DIV_MASK | AT91_PMC_PCR_CMD |
+			  AT91_PMC_PCR_EN,
+			  AT91_PMC_PCR_DIV(periph->div) |
+			  AT91_PMC_PCR_CMD |
+			  AT91_PMC_PCR_EN);
+
+	return 0;
+}
+
+static void clk_sam9x5_peripheral_disable(struct clk *clk)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+
+	if (periph->id < PERIPHERAL_ID_MIN)
+		return;
+
+	regmap_write(periph->regmap, AT91_PMC_PCR,
+		     (periph->id & AT91_PMC_PCR_PID_MASK));
+	regmap_write_bits(periph->regmap, AT91_PMC_PCR,
+			  AT91_PMC_PCR_EN | AT91_PMC_PCR_CMD,
+			  AT91_PMC_PCR_CMD);
+}
+
+static int clk_sam9x5_peripheral_is_enabled(struct clk *clk)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+	unsigned int status;
+
+	if (periph->id < PERIPHERAL_ID_MIN)
+		return 1;
+
+	regmap_write(periph->regmap, AT91_PMC_PCR,
+		     (periph->id & AT91_PMC_PCR_PID_MASK));
+	regmap_read(periph->regmap, AT91_PMC_PCR, &status);
+
+	return status & AT91_PMC_PCR_EN ? 1 : 0;
+}
+
+static unsigned long
+clk_sam9x5_peripheral_recalc_rate(struct clk *clk,
+				  unsigned long parent_rate)
+{
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+	unsigned int status;
+
+	if (periph->id < PERIPHERAL_ID_MIN)
+		return parent_rate;
+
+	regmap_write(periph->regmap, AT91_PMC_PCR,
+		     (periph->id & AT91_PMC_PCR_PID_MASK));
+	regmap_read(periph->regmap, AT91_PMC_PCR, &status);
+
+	if (status & AT91_PMC_PCR_EN) {
+		periph->div = PERIPHERAL_RSHIFT(status);
+		periph->auto_div = false;
+	} else {
+		clk_sam9x5_peripheral_autodiv(periph);
+	}
+
+	return parent_rate >> periph->div;
+}
+
+static long clk_sam9x5_peripheral_round_rate(struct clk *clk,
+					     unsigned long rate,
+					     unsigned long *parent_rate)
+{
+	int shift = 0;
+	unsigned long best_rate;
+	unsigned long best_diff;
+	unsigned long cur_rate = *parent_rate;
+	unsigned long cur_diff;
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+
+	if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max)
+		return *parent_rate;
+
+	if (periph->range.max) {
+		for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
+			cur_rate = *parent_rate >> shift;
+			if (cur_rate <= periph->range.max)
+				break;
+		}
+	}
+
+	if (rate >= cur_rate)
+		return cur_rate;
+
+	best_diff = cur_rate - rate;
+	best_rate = cur_rate;
+	for (; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
+		cur_rate = *parent_rate >> shift;
+		if (cur_rate < rate)
+			cur_diff = rate - cur_rate;
+		else
+			cur_diff = cur_rate - rate;
+
+		if (cur_diff < best_diff) {
+			best_diff = cur_diff;
+			best_rate = cur_rate;
+		}
+
+		if (!best_diff || cur_rate < rate)
+			break;
+	}
+
+	return best_rate;
+}
+
+static int clk_sam9x5_peripheral_set_rate(struct clk *clk,
+					  unsigned long rate,
+					  unsigned long parent_rate)
+{
+	int shift;
+	struct clk_sam9x5_peripheral *periph = to_clk_sam9x5_peripheral(clk);
+	if (periph->id < PERIPHERAL_ID_MIN || !periph->range.max) {
+		if (parent_rate == rate)
+			return 0;
+		else
+			return -EINVAL;
+	}
+
+	if (periph->range.max && rate > periph->range.max)
+		return -EINVAL;
+
+	for (shift = 0; shift <= PERIPHERAL_MAX_SHIFT; shift++) {
+		if (parent_rate >> shift == rate) {
+			periph->auto_div = false;
+			periph->div = shift;
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct clk_ops sam9x5_peripheral_ops = {
+	.enable = clk_sam9x5_peripheral_enable,
+	.disable = clk_sam9x5_peripheral_disable,
+	.is_enabled = clk_sam9x5_peripheral_is_enabled,
+	.recalc_rate = clk_sam9x5_peripheral_recalc_rate,
+	.round_rate = clk_sam9x5_peripheral_round_rate,
+	.set_rate = clk_sam9x5_peripheral_set_rate,
+};
+
+static struct clk *
+at91_clk_register_sam9x5_peripheral(struct regmap *regmap,
+				    const char *name, const char *parent_name,
+				    u32 id, const struct clk_range *range)
+{
+	int ret;
+	struct clk_sam9x5_peripheral *periph;
+
+	if (!name || !parent_name)
+		return ERR_PTR(-EINVAL);
+
+	periph = xzalloc(sizeof(*periph));
+
+	periph->clk.name = name;
+	periph->clk.ops = &sam9x5_peripheral_ops;
+
+	if (parent_name) {
+		periph->parent = parent_name;
+		periph->clk.parent_names = &periph->parent;
+		periph->clk.num_parents = 1;
+	}
+
+	periph->id = id;
+	periph->div = 0;
+	periph->regmap = regmap;
+	periph->auto_div = true;
+	periph->range = *range;
+
+	ret = clk_register(&periph->clk);
+	if (ret) {
+		kfree(periph);
+		return ERR_PTR(ret);
+	}
+
+	clk_sam9x5_peripheral_autodiv(periph);
+
+	return &periph->clk;
+}
+
+static int
+of_at91_clk_periph_setup(struct device_node *np, u8 type)
+{
+	int num;
+	u32 id;
+	struct clk *clk;
+	const char *parent_name;
+	const char *name;
+	struct device_node *periphclknp;
+	struct regmap *regmap;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return -ENOENT;
+
+	num = of_get_child_count(np);
+	if (!num || num > PERIPHERAL_MAX)
+		return -EINVAL;
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	for_each_child_of_node(np, periphclknp) {
+		if (of_property_read_u32(periphclknp, "reg", &id))
+			continue;
+
+		if (id >= PERIPHERAL_MAX)
+			continue;
+
+		if (of_property_read_string(np, "clock-output-names", &name))
+			name = periphclknp->name;
+
+		if (type == PERIPHERAL_AT91RM9200) {
+			clk = at91_clk_register_peripheral(regmap, name,
+							   parent_name, id);
+		} else {
+			struct clk_range range = CLK_RANGE(0, 0);
+
+			of_at91_get_clk_range(periphclknp,
+					      "atmel,clk-output-range",
+					      &range);
+
+			clk = at91_clk_register_sam9x5_peripheral(regmap,
+								  name,
+								  parent_name,
+								  id, &range);
+		}
+
+		if (IS_ERR(clk))
+			continue;
+
+		of_clk_add_provider(periphclknp, of_clk_src_simple_get, clk);
+	}
+
+	return 0;
+}
+
+static int of_at91rm9200_clk_periph_setup(struct device_node *np)
+{
+	return of_at91_clk_periph_setup(np, PERIPHERAL_AT91RM9200);
+}
+CLK_OF_DECLARE(at91rm9200_clk_periph, "atmel,at91rm9200-clk-peripheral",
+	       of_at91rm9200_clk_periph_setup);
+
+static int of_at91sam9x5_clk_periph_setup(struct device_node *np)
+{
+	return of_at91_clk_periph_setup(np, PERIPHERAL_AT91SAM9X5);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_periph, "atmel,at91sam9x5-clk-peripheral",
+	       of_at91sam9x5_clk_periph_setup);
+
diff --git a/drivers/clk/at91/clk-pll.c b/drivers/clk/at91/clk-pll.c
new file mode 100644
index 0000000..cf38742
--- /dev/null
+++ b/drivers/clk/at91/clk-pll.c
@@ -0,0 +1,516 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define PLL_STATUS_MASK(id)	(1 << (1 + (id)))
+#define PLL_REG(id)		(AT91_CKGR_PLLAR + ((id) * 4))
+#define PLL_DIV_MASK		0xff
+#define PLL_DIV_MAX		PLL_DIV_MASK
+#define PLL_DIV(reg)		((reg) & PLL_DIV_MASK)
+#define PLL_MUL(reg, layout)	(((reg) >> (layout)->mul_shift) & \
+				 (layout)->mul_mask)
+#define PLL_MUL_MIN		2
+#define PLL_MUL_MASK(layout)	((layout)->mul_mask)
+#define PLL_MUL_MAX(layout)	(PLL_MUL_MASK(layout) + 1)
+#define PLL_ICPR_SHIFT(id)	((id) * 16)
+#define PLL_ICPR_MASK(id)	(0xffff << PLL_ICPR_SHIFT(id))
+#define PLL_MAX_COUNT		0x3f
+#define PLL_COUNT_SHIFT		8
+#define PLL_OUT_SHIFT		14
+#define PLL_MAX_ID		1
+
+struct clk_pll_characteristics {
+	struct clk_range input;
+	int num_output;
+	struct clk_range *output;
+	u16 *icpll;
+	u8 *out;
+};
+
+struct clk_pll_layout {
+	u32 pllr_mask;
+	u16 mul_mask;
+	u8 mul_shift;
+};
+
+#define to_clk_pll(clk) container_of(clk, struct clk_pll, clk)
+
+struct clk_pll {
+	struct clk clk;
+	struct regmap *regmap;
+	u8 id;
+	u8 div;
+	u8 range;
+	u16 mul;
+	const struct clk_pll_layout *layout;
+	const struct clk_pll_characteristics *characteristics;
+	const char *parent;
+};
+
+static inline bool clk_pll_ready(struct regmap *regmap, int id)
+{
+	unsigned int status;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return status & PLL_STATUS_MASK(id) ? 1 : 0;
+}
+
+static int clk_pll_enable(struct clk *clk)
+{
+	struct clk_pll *pll = to_clk_pll(clk);
+	struct regmap *regmap = pll->regmap;
+	const struct clk_pll_layout *layout = pll->layout;
+	const struct clk_pll_characteristics *characteristics =
+							pll->characteristics;
+	u8 id = pll->id;
+	u32 mask = PLL_STATUS_MASK(id);
+	int offset = PLL_REG(id);
+	u8 out = 0;
+	unsigned int pllr;
+	unsigned int status;
+	u8 div;
+	u16 mul;
+
+	regmap_read(regmap, offset, &pllr);
+	div = PLL_DIV(pllr);
+	mul = PLL_MUL(pllr, layout);
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+	if ((status & mask) &&
+	    (div == pll->div && mul == pll->mul))
+		return 0;
+
+	if (characteristics->out)
+		out = characteristics->out[pll->range];
+
+	if (characteristics->icpll)
+		regmap_write_bits(regmap, AT91_PMC_PLLICPR, PLL_ICPR_MASK(id),
+			characteristics->icpll[pll->range] << PLL_ICPR_SHIFT(id));
+
+	regmap_write_bits(regmap, offset, layout->pllr_mask,
+			  pll->div | (PLL_MAX_COUNT << PLL_COUNT_SHIFT) |
+			  (out << PLL_OUT_SHIFT) |
+			  ((pll->mul & layout->mul_mask) << layout->mul_shift));
+
+	while (!clk_pll_ready(regmap, pll->id))
+		barrier();
+
+	return 0;
+}
+
+static int clk_pll_is_enabled(struct clk *clk)
+{
+	struct clk_pll *pll = to_clk_pll(clk);
+
+	return clk_pll_ready(pll->regmap, pll->id);
+}
+
+static void clk_pll_disable(struct clk *clk)
+{
+	struct clk_pll *pll = to_clk_pll(clk);
+	unsigned int mask = pll->layout->pllr_mask;
+
+	regmap_write_bits(pll->regmap, PLL_REG(pll->id), mask, ~mask);
+}
+
+static unsigned long clk_pll_recalc_rate(struct clk *clk,
+					 unsigned long parent_rate)
+{
+	struct clk_pll *pll = to_clk_pll(clk);
+	unsigned int pllr;
+	u16 mul;
+	u8 div;
+
+	regmap_read(pll->regmap, PLL_REG(pll->id), &pllr);
+
+	div = PLL_DIV(pllr);
+	mul = PLL_MUL(pllr, pll->layout);
+
+	if (!div || !mul)
+		return 0;
+
+	return (parent_rate / div) * (mul + 1);
+}
+
+static long clk_pll_get_best_div_mul(struct clk_pll *pll, unsigned long rate,
+				     unsigned long parent_rate,
+				     u32 *div, u32 *mul,
+				     u32 *index) {
+	const struct clk_pll_layout *layout = pll->layout;
+	const struct clk_pll_characteristics *characteristics =
+							pll->characteristics;
+	unsigned long bestremainder = ULONG_MAX;
+	unsigned long maxdiv, mindiv, tmpdiv;
+	long bestrate = -ERANGE;
+	unsigned long bestdiv;
+	unsigned long bestmul;
+	int i = 0;
+
+	/* Check if parent_rate is a valid input rate */
+	if (parent_rate < characteristics->input.min)
+		return -ERANGE;
+
+	/*
+	 * Calculate minimum divider based on the minimum multiplier, the
+	 * parent_rate and the requested rate.
+	 * Should always be 2 according to the input and output characteristics
+	 * of the PLL blocks.
+	 */
+	mindiv = (parent_rate * PLL_MUL_MIN) / rate;
+	if (!mindiv)
+		mindiv = 1;
+
+	if (parent_rate > characteristics->input.max) {
+		tmpdiv = DIV_ROUND_UP(parent_rate, characteristics->input.max);
+		if (tmpdiv > PLL_DIV_MAX)
+			return -ERANGE;
+
+		if (tmpdiv > mindiv)
+			mindiv = tmpdiv;
+	}
+
+	/*
+	 * Calculate the maximum divider which is limited by PLL register
+	 * layout (limited by the MUL or DIV field size).
+	 */
+	maxdiv = DIV_ROUND_UP(parent_rate * PLL_MUL_MAX(layout), rate);
+	if (maxdiv > PLL_DIV_MAX)
+		maxdiv = PLL_DIV_MAX;
+
+	/*
+	 * Iterate over the acceptable divider values to find the best
+	 * divider/multiplier pair (the one that generates the closest
+	 * rate to the requested one).
+	 */
+	for (tmpdiv = mindiv; tmpdiv <= maxdiv; tmpdiv++) {
+		unsigned long remainder;
+		unsigned long tmprate;
+		unsigned long tmpmul;
+
+		/*
+		 * Calculate the multiplier associated with the current
+		 * divider that provide the closest rate to the requested one.
+		 */
+		tmpmul = DIV_ROUND_CLOSEST(rate, parent_rate / tmpdiv);
+		tmprate = (parent_rate / tmpdiv) * tmpmul;
+		if (tmprate > rate)
+			remainder = tmprate - rate;
+		else
+			remainder = rate - tmprate;
+
+		/*
+		 * Compare the remainder with the best remainder found until
+		 * now and elect a new best multiplier/divider pair if the
+		 * current remainder is smaller than the best one.
+		 */
+		if (remainder < bestremainder) {
+			bestremainder = remainder;
+			bestdiv = tmpdiv;
+			bestmul = tmpmul;
+			bestrate = tmprate;
+		}
+
+		/*
+		 * We've found a perfect match!
+		 * Stop searching now and use this multiplier/divider pair.
+		 */
+		if (!remainder)
+			break;
+	}
+
+	/* We haven't found any multiplier/divider pair => return -ERANGE */
+	if (bestrate < 0)
+		return bestrate;
+
+	/* Check if bestrate is a valid output rate  */
+	for (i = 0; i < characteristics->num_output; i++) {
+		if (bestrate >= characteristics->output[i].min &&
+		    bestrate <= characteristics->output[i].max)
+			break;
+	}
+
+	if (i >= characteristics->num_output)
+		return -ERANGE;
+
+	if (div)
+		*div = bestdiv;
+	if (mul)
+		*mul = bestmul - 1;
+	if (index)
+		*index = i;
+
+	return bestrate;
+}
+
+static long clk_pll_round_rate(struct clk *clk, unsigned long rate,
+			       unsigned long *parent_rate)
+{
+	struct clk_pll *pll = to_clk_pll(clk);
+
+	return clk_pll_get_best_div_mul(pll, rate, *parent_rate,
+					NULL, NULL, NULL);
+}
+
+static int clk_pll_set_rate(struct clk *clk, unsigned long rate,
+			    unsigned long parent_rate)
+{
+	struct clk_pll *pll = to_clk_pll(clk);
+	long ret;
+	u32 div;
+	u32 mul;
+	u32 index;
+
+	ret = clk_pll_get_best_div_mul(pll, rate, parent_rate,
+				       &div, &mul, &index);
+	if (ret < 0)
+		return ret;
+
+	pll->range = index;
+	pll->div = div;
+	pll->mul = mul;
+
+	return 0;
+}
+
+static const struct clk_ops pll_ops = {
+	.enable = clk_pll_enable,
+	.disable = clk_pll_disable,
+	.is_enabled = clk_pll_is_enabled,
+	.recalc_rate = clk_pll_recalc_rate,
+	.round_rate = clk_pll_round_rate,
+	.set_rate = clk_pll_set_rate,
+};
+
+static struct clk *
+at91_clk_register_pll(struct regmap *regmap, const char *name,
+		      const char *parent_name, u8 id,
+		      const struct clk_pll_layout *layout,
+		      const struct clk_pll_characteristics *characteristics)
+{
+	struct clk_pll *pll;
+	int offset = PLL_REG(id);
+	unsigned int pllr;
+	int ret;
+
+	if (id > PLL_MAX_ID)
+		return ERR_PTR(-EINVAL);
+
+	pll = xzalloc(sizeof(*pll));
+
+	pll->parent = parent_name;
+	pll->clk.name = name;
+	pll->clk.ops = &pll_ops;
+	pll->clk.parent_names = &pll->parent;
+	pll->clk.num_parents = 1;
+
+	/* init.flags = CLK_SET_RATE_GATE; */
+
+	pll->id = id;
+	pll->layout = layout;
+	pll->characteristics = characteristics;
+	pll->regmap = regmap;
+	regmap_read(regmap, offset, &pllr);
+	pll->div = PLL_DIV(pllr);
+	pll->mul = PLL_MUL(pllr, layout);
+
+	ret = clk_register(&pll->clk);
+	if (ret) {
+		kfree(pll);
+		return ERR_PTR(ret);
+	}
+
+	return &pll->clk;
+}
+
+
+static const struct clk_pll_layout at91rm9200_pll_layout = {
+	.pllr_mask = 0x7FFFFFF,
+	.mul_shift = 16,
+	.mul_mask = 0x7FF,
+};
+
+static const struct clk_pll_layout at91sam9g45_pll_layout = {
+	.pllr_mask = 0xFFFFFF,
+	.mul_shift = 16,
+	.mul_mask = 0xFF,
+};
+
+static const struct clk_pll_layout at91sam9g20_pllb_layout = {
+	.pllr_mask = 0x3FFFFF,
+	.mul_shift = 16,
+	.mul_mask = 0x3F,
+};
+
+static const struct clk_pll_layout sama5d3_pll_layout = {
+	.pllr_mask = 0x1FFFFFF,
+	.mul_shift = 18,
+	.mul_mask = 0x7F,
+};
+
+
+static struct clk_pll_characteristics *
+of_at91_clk_pll_get_characteristics(struct device_node *np)
+{
+	int i;
+	int offset;
+	u32 tmp;
+	int num_output;
+	u32 num_cells;
+	struct clk_range input;
+	struct clk_range *output;
+	u8 *out = NULL;
+	u16 *icpll = NULL;
+	struct clk_pll_characteristics *characteristics;
+
+	if (of_at91_get_clk_range(np, "atmel,clk-input-range", &input))
+		return NULL;
+
+	if (of_property_read_u32(np, "#atmel,pll-clk-output-range-cells",
+				 &num_cells))
+		return NULL;
+
+	if (num_cells < 2 || num_cells > 4)
+		return NULL;
+
+	if (!of_get_property(np, "atmel,pll-clk-output-ranges", &tmp))
+		return NULL;
+	num_output = tmp / (sizeof(u32) * num_cells);
+
+	characteristics = xzalloc(sizeof(*characteristics));
+	output = xzalloc(sizeof(*output) * num_output);
+
+	if (num_cells > 2)
+		out = xzalloc(sizeof(*out) * num_output);
+
+	if (num_cells > 3)
+		icpll = xzalloc(sizeof(*icpll) * num_output);
+
+
+	for (i = 0; i < num_output; i++) {
+		offset = i * num_cells;
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset, &tmp))
+			goto out_free_output;
+		output[i].min = tmp;
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset + 1, &tmp))
+			goto out_free_output;
+		output[i].max = tmp;
+
+		if (num_cells == 2)
+			continue;
+
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset + 2, &tmp))
+			goto out_free_output;
+		out[i] = tmp;
+
+		if (num_cells == 3)
+			continue;
+
+		if (of_property_read_u32_index(np,
+					       "atmel,pll-clk-output-ranges",
+					       offset + 3, &tmp))
+			goto out_free_output;
+		icpll[i] = tmp;
+	}
+
+	characteristics->input = input;
+	characteristics->num_output = num_output;
+	characteristics->output = output;
+	characteristics->out = out;
+	characteristics->icpll = icpll;
+	return characteristics;
+
+out_free_output:
+	kfree(icpll);
+	kfree(out);
+	kfree(output);
+	kfree(characteristics);
+	return NULL;
+}
+
+static int
+of_at91_clk_pll_setup(struct device_node *np,
+		      const struct clk_pll_layout *layout)
+{
+	u32 id;
+	struct clk *clk;
+	struct regmap *regmap;
+	const char *parent_name;
+	const char *name = np->name;
+	struct clk_pll_characteristics *characteristics;
+
+	if (of_property_read_u32(np, "reg", &id))
+		return -EINVAL;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	characteristics = of_at91_clk_pll_get_characteristics(np);
+	if (!characteristics)
+		return -EINVAL;
+
+	clk = at91_clk_register_pll(regmap, name, parent_name, id, layout,
+				    characteristics);
+	if (IS_ERR(clk)) {
+		kfree(characteristics);
+		return PTR_ERR(clk);
+	}
+	
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static int of_at91rm9200_clk_pll_setup(struct device_node *np)
+{
+	return of_at91_clk_pll_setup(np, &at91rm9200_pll_layout);
+}
+CLK_OF_DECLARE(at91rm9200_clk_pll, "atmel,at91rm9200-clk-pll",
+	       of_at91rm9200_clk_pll_setup);
+
+static int of_at91sam9g45_clk_pll_setup(struct device_node *np)
+{
+	return of_at91_clk_pll_setup(np, &at91sam9g45_pll_layout);
+}
+CLK_OF_DECLARE(at91sam9g45_clk_pll, "atmel,at91sam9g45-clk-pll",
+	       of_at91sam9g45_clk_pll_setup);
+
+static int of_at91sam9g20_clk_pllb_setup(struct device_node *np)
+{
+	return of_at91_clk_pll_setup(np, &at91sam9g20_pllb_layout);
+}
+CLK_OF_DECLARE(at91sam9g20_clk_pllb, "atmel,at91sam9g20-clk-pllb",
+	       of_at91sam9g20_clk_pllb_setup);
+
+static int of_sama5d3_clk_pll_setup(struct device_node *np)
+{
+	return of_at91_clk_pll_setup(np, &sama5d3_pll_layout);
+}
+CLK_OF_DECLARE(sama5d3_clk_pll, "atmel,sama5d3-clk-pll",
+	       of_sama5d3_clk_pll_setup);
diff --git a/drivers/clk/at91/clk-plldiv.c b/drivers/clk/at91/clk-plldiv.c
new file mode 100644
index 0000000..917108e
--- /dev/null
+++ b/drivers/clk/at91/clk-plldiv.c
@@ -0,0 +1,135 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define to_clk_plldiv(hw) container_of(clk, struct clk_plldiv, clk)
+
+struct clk_plldiv {
+	struct clk clk;
+	struct regmap *regmap;
+	const char *parent;
+};
+
+static unsigned long clk_plldiv_recalc_rate(struct clk *clk,
+					    unsigned long parent_rate)
+{
+	struct clk_plldiv *plldiv = to_clk_plldiv(clk);
+	unsigned int mckr;
+
+	regmap_read(plldiv->regmap, AT91_PMC_MCKR, &mckr);
+
+	if (mckr & AT91_PMC_PLLADIV2)
+		return parent_rate / 2;
+
+	return parent_rate;
+}
+
+static long clk_plldiv_round_rate(struct clk *clk, unsigned long rate,
+				  unsigned long *parent_rate)
+{
+	unsigned long div;
+
+	if (rate > *parent_rate)
+		return *parent_rate;
+	div = *parent_rate / 2;
+	if (rate < div)
+		return div;
+
+	if (rate - div < *parent_rate - rate)
+		return div;
+
+	return *parent_rate;
+}
+
+static int clk_plldiv_set_rate(struct clk *clk, unsigned long rate,
+			       unsigned long parent_rate)
+{
+	struct clk_plldiv *plldiv = to_clk_plldiv(clk);
+
+	if ((parent_rate != rate) && (parent_rate / 2 != rate))
+		return -EINVAL;
+
+	regmap_write_bits(plldiv->regmap, AT91_PMC_MCKR, AT91_PMC_PLLADIV2,
+			  parent_rate != rate ? AT91_PMC_PLLADIV2 : 0);
+
+	return 0;
+}
+
+static const struct clk_ops plldiv_ops = {
+	.recalc_rate = clk_plldiv_recalc_rate,
+	.round_rate = clk_plldiv_round_rate,
+	.set_rate = clk_plldiv_set_rate,
+};
+
+static struct clk *
+at91_clk_register_plldiv(struct regmap *regmap, const char *name,
+			 const char *parent_name)
+{
+	int ret;
+	struct clk_plldiv *plldiv;
+
+	plldiv = xzalloc(sizeof(*plldiv));
+
+	plldiv->clk.name = name;
+	plldiv->clk.ops  = &plldiv_ops;
+
+	if (parent_name) {
+		plldiv->parent = parent_name;
+		plldiv->clk.parent_names = &plldiv->parent;
+		plldiv->clk.num_parents = 1;
+	}
+
+	/* init.flags = CLK_SET_RATE_GATE; */
+
+	plldiv->regmap = regmap;
+
+	ret = clk_register(&plldiv->clk);
+	if (ret) {
+		kfree(plldiv);
+		return ERR_PTR(ret);
+	}
+
+	return &plldiv->clk;
+}
+
+static int
+of_at91sam9x5_clk_plldiv_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91_clk_register_plldiv(regmap, name, parent_name);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_plldiv, "atmel,at91sam9x5-clk-plldiv",
+	       of_at91sam9x5_clk_plldiv_setup);
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
new file mode 100644
index 0000000..ddb18c0
--- /dev/null
+++ b/drivers/clk/at91/clk-programmable.c
@@ -0,0 +1,254 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <io.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define PROG_SOURCE_MAX		5
+#define PROG_ID_MAX		7
+
+#define PROG_STATUS_MASK(id)	(1 << ((id) + 8))
+#define PROG_PRES_MASK		0x7
+#define PROG_PRES(layout, pckr)	((pckr >> layout->pres_shift) & PROG_PRES_MASK)
+#define PROG_MAX_RM9200_CSS	3
+
+struct clk_programmable_layout {
+	u8 pres_shift;
+	u8 css_mask;
+	u8 have_slck_mck;
+};
+
+struct clk_programmable {
+	struct clk clk;
+	struct regmap *regmap;
+	u8 id;
+	const struct clk_programmable_layout *layout;
+	const char *parent_names[PROG_SOURCE_MAX];
+};
+
+#define to_clk_programmable(clk) container_of(clk, struct clk_programmable, clk)
+
+static unsigned long clk_programmable_recalc_rate(struct clk *clk,
+						  unsigned long parent_rate)
+{
+	struct clk_programmable *prog = to_clk_programmable(clk);
+	unsigned int pckr;
+
+	regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
+
+	return parent_rate >> PROG_PRES(prog->layout, pckr);
+}
+
+static int clk_programmable_set_parent(struct clk *clk, u8 index)
+{
+	struct clk_programmable *prog = to_clk_programmable(clk);
+	const struct clk_programmable_layout *layout = prog->layout;
+	unsigned int mask = layout->css_mask;
+	unsigned int pckr = index;
+
+	if (layout->have_slck_mck)
+		mask |= AT91_PMC_CSSMCK_MCK;
+
+	if (index > layout->css_mask) {
+		if (index > PROG_MAX_RM9200_CSS && !layout->have_slck_mck)
+			return -EINVAL;
+
+		pckr |= AT91_PMC_CSSMCK_MCK;
+	}
+
+	regmap_write_bits(prog->regmap, AT91_PMC_PCKR(prog->id), mask, pckr);
+
+	return 0;
+}
+
+static int clk_programmable_get_parent(struct clk *clk)
+{
+	struct clk_programmable *prog = to_clk_programmable(clk);
+	const struct clk_programmable_layout *layout = prog->layout;
+	unsigned int pckr;
+	u8 ret;
+
+	regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
+
+	ret = pckr & layout->css_mask;
+
+	if (layout->have_slck_mck && (pckr & AT91_PMC_CSSMCK_MCK) && !ret)
+		ret = PROG_MAX_RM9200_CSS + 1;
+
+	return ret;
+}
+
+static int clk_programmable_set_rate(struct clk *clk, unsigned long rate,
+				     unsigned long parent_rate)
+{
+	struct clk_programmable *prog = to_clk_programmable(clk);
+	const struct clk_programmable_layout *layout = prog->layout;
+	unsigned long div = parent_rate / rate;
+	unsigned int pckr;
+	int shift = 0;
+
+	regmap_read(prog->regmap, AT91_PMC_PCKR(prog->id), &pckr);
+
+	if (!div)
+		return -EINVAL;
+
+	shift = fls(div) - 1;
+
+	if (div != (1 << shift))
+		return -EINVAL;
+
+	if (shift >= PROG_PRES_MASK)
+		return -EINVAL;
+
+	regmap_write_bits(prog->regmap, AT91_PMC_PCKR(prog->id),
+			   PROG_PRES_MASK << layout->pres_shift,
+			   shift << layout->pres_shift);
+
+	return 0;
+}
+
+static const struct clk_ops programmable_ops = {
+	.recalc_rate = clk_programmable_recalc_rate,
+	.get_parent = clk_programmable_get_parent,
+	.set_parent = clk_programmable_set_parent,
+	.set_rate = clk_programmable_set_rate,
+};
+
+static struct clk *
+at91_clk_register_programmable(struct regmap *regmap,
+			       const char *name, const char **parent_names,
+			       u8 num_parents, u8 id,
+			       const struct clk_programmable_layout *layout)
+{
+	struct clk_programmable *prog;
+	int ret;
+
+	if (id > PROG_ID_MAX)
+		return ERR_PTR(-EINVAL);
+
+	prog = kzalloc(sizeof(*prog), GFP_KERNEL);
+	if (!prog)
+		return ERR_PTR(-ENOMEM);
+
+	prog->clk.name = name;
+	prog->clk.ops = &programmable_ops;
+	memcpy(prog->parent_names, parent_names,
+	       num_parents * sizeof(prog->parent_names[0]));
+	prog->clk.parent_names = &prog->parent_names[0];
+	prog->clk.num_parents = num_parents;
+	/* init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; */
+
+	prog->id = id;
+	prog->layout = layout;
+	prog->regmap = regmap;
+
+	ret = clk_register(&prog->clk);
+	if (ret) {
+		kfree(prog);
+		return ERR_PTR(ret);
+	}
+
+	return &prog->clk;
+}
+
+static const struct clk_programmable_layout at91rm9200_programmable_layout = {
+	.pres_shift = 2,
+	.css_mask = 0x3,
+	.have_slck_mck = 0,
+};
+
+static const struct clk_programmable_layout at91sam9g45_programmable_layout = {
+	.pres_shift = 2,
+	.css_mask = 0x3,
+	.have_slck_mck = 1,
+};
+
+static const struct clk_programmable_layout at91sam9x5_programmable_layout = {
+	.pres_shift = 4,
+	.css_mask = 0x7,
+	.have_slck_mck = 0,
+};
+
+static int
+of_at91_clk_prog_setup(struct device_node *np,
+		       const struct clk_programmable_layout *layout)
+{
+	int num;
+	u32 id;
+	struct clk *clk;
+	unsigned int num_parents;
+	const char *parent_names[PROG_SOURCE_MAX];
+	const char *name;
+	struct device_node *progclknp;
+	struct regmap *regmap;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents == 0 || num_parents > PROG_SOURCE_MAX)
+		return -EINVAL;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+
+	num = of_get_child_count(np);
+	if (!num || num > (PROG_ID_MAX + 1))
+		return -EINVAL;
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	for_each_child_of_node(np, progclknp) {
+		if (of_property_read_u32(progclknp, "reg", &id))
+			continue;
+
+		if (of_property_read_string(np, "clock-output-names", &name))
+			name = progclknp->name;
+
+		clk = at91_clk_register_programmable(regmap, name,
+						     parent_names, num_parents,
+						     id, layout);
+		if (IS_ERR(clk))
+			continue;
+
+		of_clk_add_provider(progclknp, of_clk_src_simple_get, clk);
+	}
+
+	return 0;
+}
+
+
+static void __init of_at91rm9200_clk_prog_setup(struct device_node *np)
+{
+	of_at91_clk_prog_setup(np, &at91rm9200_programmable_layout);
+}
+CLK_OF_DECLARE(at91rm9200_clk_prog, "atmel,at91rm9200-clk-programmable",
+	       of_at91rm9200_clk_prog_setup);
+
+static int of_at91sam9g45_clk_prog_setup(struct device_node *np)
+{
+	return of_at91_clk_prog_setup(np, &at91sam9g45_programmable_layout);
+}
+CLK_OF_DECLARE(at91sam9g45_clk_prog, "atmel,at91sam9g45-clk-programmable",
+	       of_at91sam9g45_clk_prog_setup);
+
+static int of_at91sam9x5_clk_prog_setup(struct device_node *np)
+{
+	return of_at91_clk_prog_setup(np, &at91sam9x5_programmable_layout);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_prog, "atmel,at91sam9x5-clk-programmable",
+	       of_at91sam9x5_clk_prog_setup);
diff --git a/drivers/clk/at91/clk-slow.c b/drivers/clk/at91/clk-slow.c
new file mode 100644
index 0000000..d4981e7
--- /dev/null
+++ b/drivers/clk/at91/clk-slow.c
@@ -0,0 +1,108 @@
+/*
+ * drivers/clk/at91/clk-slow.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <io.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+struct clk_sam9260_slow {
+	struct clk clk;
+	struct regmap *regmap;
+	const char *parent_names[2];
+};
+
+#define to_clk_sam9260_slow(clk) container_of(clk, struct clk_sam9260_slow, clk)
+
+static int clk_sam9260_slow_get_parent(struct clk *clk)
+{
+	struct clk_sam9260_slow *slowck = to_clk_sam9260_slow(clk);
+	unsigned int status;
+
+	regmap_read(slowck->regmap, AT91_PMC_SR, &status);
+
+	return status & AT91_PMC_OSCSEL ? 1 : 0;
+}
+
+static const struct clk_ops sam9260_slow_ops = {
+	.get_parent = clk_sam9260_slow_get_parent,
+};
+
+static struct clk * __init
+at91_clk_register_sam9260_slow(struct regmap *regmap,
+			       const char *name,
+			       const char **parent_names,
+			       int num_parents)
+{
+	struct clk_sam9260_slow *slowck;
+	int ret;
+
+	if (!name)
+		return ERR_PTR(-EINVAL);
+
+	if (!parent_names || !num_parents)
+		return ERR_PTR(-EINVAL);
+
+	slowck = xzalloc(sizeof(*slowck));
+	slowck->clk.name = name;
+	slowck->clk.ops = &sam9260_slow_ops;
+	memcpy(slowck->parent_names, parent_names,
+	       num_parents * sizeof(slowck->parent_names[0]));
+	slowck->clk.parent_names = slowck->parent_names;
+	slowck->clk.num_parents = num_parents;
+	slowck->regmap = regmap;
+
+	ret = clk_register(&slowck->clk);
+	if (ret) {
+		kfree(slowck);
+		return ERR_PTR(ret);
+	}
+
+	return &slowck->clk;
+}
+
+static int of_at91sam9260_clk_slow_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *parent_names[2];
+	unsigned int num_parents;
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents != 2)
+		return -EINVAL;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	clk = at91_clk_register_sam9260_slow(regmap, name, parent_names,
+					     num_parents);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+CLK_OF_DECLARE(at91sam9260_clk_slow, "atmel,at91sam9260-clk-slow",
+	       of_at91sam9260_clk_slow_setup);
diff --git a/drivers/clk/at91/clk-smd.c b/drivers/clk/at91/clk-smd.c
new file mode 100644
index 0000000..0d72491
--- /dev/null
+++ b/drivers/clk/at91/clk-smd.c
@@ -0,0 +1,172 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <io.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define SMD_SOURCE_MAX		2
+
+#define SMD_DIV_SHIFT		8
+#define SMD_MAX_DIV		0xf
+
+struct at91sam9x5_clk_smd {
+	struct clk clk;
+	struct regmap *regmap;
+	const char *parent_names[SMD_SOURCE_MAX];	
+};
+
+#define to_at91sam9x5_clk_smd(clk) \
+	container_of(clk, struct at91sam9x5_clk_smd, clk)
+
+static unsigned long at91sam9x5_clk_smd_recalc_rate(struct clk *clk,
+						    unsigned long parent_rate)
+{
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(clk);
+	unsigned int smdr;
+	u8 smddiv;
+
+	regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
+	smddiv = (smdr & AT91_PMC_SMD_DIV) >> SMD_DIV_SHIFT;
+
+	return parent_rate / (smddiv + 1);
+}
+
+static long at91sam9x5_clk_smd_round_rate(struct clk *clk, unsigned long rate,
+					  unsigned long *parent_rate)
+{
+	unsigned long div;
+	unsigned long bestrate;
+	unsigned long tmp;
+
+	if (rate >= *parent_rate)
+		return *parent_rate;
+
+	div = *parent_rate / rate;
+	if (div > SMD_MAX_DIV)
+		return *parent_rate / (SMD_MAX_DIV + 1);
+
+	bestrate = *parent_rate / div;
+	tmp = *parent_rate / (div + 1);
+	if (bestrate - rate > rate - tmp)
+		bestrate = tmp;
+
+	return bestrate;
+}
+
+static int at91sam9x5_clk_smd_set_parent(struct clk *clk, u8 index)
+{
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(clk);
+
+	if (index > 1)
+		return -EINVAL;
+
+	regmap_write_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMDS,
+			  index ? AT91_PMC_SMDS : 0);
+
+	return 0;
+}
+
+static int at91sam9x5_clk_smd_get_parent(struct clk *clk)
+{
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(clk);
+	unsigned int smdr;
+
+	regmap_read(smd->regmap, AT91_PMC_SMD, &smdr);
+
+	return smdr & AT91_PMC_SMDS;
+}
+
+static int at91sam9x5_clk_smd_set_rate(struct clk *clk, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	struct at91sam9x5_clk_smd *smd = to_at91sam9x5_clk_smd(clk);
+	unsigned long div = parent_rate / rate;
+
+	if (parent_rate % rate || div < 1 || div > (SMD_MAX_DIV + 1))
+		return -EINVAL;
+
+	regmap_write_bits(smd->regmap, AT91_PMC_SMD, AT91_PMC_SMD_DIV,
+			  (div - 1) << SMD_DIV_SHIFT);
+
+	return 0;
+}
+
+static const struct clk_ops at91sam9x5_smd_ops = {
+	.recalc_rate = at91sam9x5_clk_smd_recalc_rate,
+	.round_rate = at91sam9x5_clk_smd_round_rate,
+	.get_parent = at91sam9x5_clk_smd_get_parent,
+	.set_parent = at91sam9x5_clk_smd_set_parent,
+	.set_rate = at91sam9x5_clk_smd_set_rate,
+};
+
+static struct clk *
+at91sam9x5_clk_register_smd(struct regmap *regmap, const char *name,
+			    const char **parent_names, u8 num_parents)
+{
+	struct at91sam9x5_clk_smd *smd;
+	int ret;
+
+	smd = xzalloc(sizeof(*smd));
+	smd->clk.name = name;
+	smd->clk.ops = &at91sam9x5_smd_ops;
+	memcpy(smd->parent_names, parent_names,
+	       num_parents * sizeof(smd->parent_names[0]));
+	smd->clk.parent_names = smd->parent_names;
+	smd->clk.num_parents = num_parents;
+	/* init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE; */
+	smd->regmap = regmap;
+
+	ret = clk_register(&smd->clk);
+	if (ret) {
+		kfree(smd);
+		return ERR_PTR(ret);
+	}
+
+	return &smd->clk;
+}
+
+static int of_at91sam9x5_clk_smd_setup(struct device_node *np)
+{
+	struct clk *clk;
+	unsigned int num_parents;
+	const char *parent_names[SMD_SOURCE_MAX];
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents == 0 || num_parents > SMD_SOURCE_MAX)
+		return -EINVAL;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91sam9x5_clk_register_smd(regmap, name, parent_names,
+					  num_parents);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_smd, "atmel,at91sam9x5-clk-smd",
+	       of_at91sam9x5_clk_smd_setup);
diff --git a/drivers/clk/at91/clk-system.c b/drivers/clk/at91/clk-system.c
new file mode 100644
index 0000000..021930e
--- /dev/null
+++ b/drivers/clk/at91/clk-system.c
@@ -0,0 +1,160 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <io.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define SYSTEM_MAX_ID		31
+
+#define SYSTEM_MAX_NAME_SZ	32
+
+#define to_clk_system(clk) container_of(clk, struct clk_system, clk)
+struct clk_system {
+	struct clk clk;
+	struct regmap *regmap;
+	u8 id;
+	const char *parent_name;
+};
+
+static inline int is_pck(int id)
+{
+	return (id >= 8) && (id <= 15);
+}
+
+static inline bool clk_system_ready(struct regmap *regmap, int id)
+{
+	unsigned int status;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return status & (1 << id) ? 1 : 0;
+}
+
+static int clk_system_enable(struct clk *clk)
+{
+	struct clk_system *sys = to_clk_system(clk);
+
+	regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);
+
+	if (!is_pck(sys->id))
+		return 0;
+
+	while (!clk_system_ready(sys->regmap, sys->id))
+		barrier();
+
+	return 0;
+}
+
+static void clk_system_disable(struct clk *clk)
+{
+	struct clk_system *sys = to_clk_system(clk);
+
+	regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
+}
+
+static int clk_system_is_enabled(struct clk *clk)
+{
+	struct clk_system *sys = to_clk_system(clk);
+	unsigned int status;
+
+	regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
+
+	if (!(status & (1 << sys->id)))
+		return 0;
+
+	if (!is_pck(sys->id))
+		return 1;
+
+	regmap_read(sys->regmap, AT91_PMC_SR, &status);
+
+	return status & (1 << sys->id) ? 1 : 0;
+}
+
+static const struct clk_ops system_ops = {
+	.enable = clk_system_enable,
+	.disable = clk_system_disable,
+	.is_enabled = clk_system_is_enabled,
+};
+
+static struct clk *
+at91_clk_register_system(struct regmap *regmap, const char *name,
+			 const char *parent_name, u8 id)
+{
+	struct clk_system *sys;
+	int ret;
+
+	if (!parent_name || id > SYSTEM_MAX_ID)
+		return ERR_PTR(-EINVAL);
+
+	sys = xzalloc(sizeof(*sys));
+	sys->clk.name = name;
+	sys->clk.ops = &system_ops;
+	sys->parent_name = parent_name;
+	sys->clk.parent_names = &sys->parent_name;
+	sys->clk.num_parents = 1;
+	/* init.flags = CLK_SET_RATE_PARENT; */
+	sys->id = id;
+	sys->regmap = regmap;
+
+	ret = clk_register(&sys->clk);
+	if (ret) {
+		kfree(sys);
+		return ERR_PTR(ret);
+	}
+
+	return &sys->clk;
+}
+
+static int of_at91rm9200_clk_sys_setup(struct device_node *np)
+{
+	int num;
+	u32 id;
+	struct clk *clk;
+	const char *name;
+	struct device_node *sysclknp;
+	const char *parent_name;
+	struct regmap *regmap;
+
+	num = of_get_child_count(np);
+	if (num > (SYSTEM_MAX_ID + 1))
+		return -EINVAL;
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	for_each_child_of_node(np, sysclknp) {
+		if (of_property_read_u32(sysclknp, "reg", &id))
+			continue;
+
+		if (of_property_read_string(np, "clock-output-names", &name))
+			name = sysclknp->name;
+
+		parent_name = of_clk_get_parent_name(sysclknp, 0);
+
+		clk = at91_clk_register_system(regmap, name, parent_name, id);
+		if (IS_ERR(clk))
+			continue;
+
+		of_clk_add_provider(sysclknp, of_clk_src_simple_get, clk);
+	}
+
+	return 0;
+}
+CLK_OF_DECLARE(at91rm9200_clk_sys, "atmel,at91rm9200-clk-system",
+	       of_at91rm9200_clk_sys_setup);
diff --git a/drivers/clk/at91/clk-usb.c b/drivers/clk/at91/clk-usb.c
new file mode 100644
index 0000000..99ba671
--- /dev/null
+++ b/drivers/clk/at91/clk-usb.c
@@ -0,0 +1,397 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <io.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define USB_SOURCE_MAX		2
+
+#define SAM9X5_USB_DIV_SHIFT	8
+#define SAM9X5_USB_MAX_DIV	0xf
+
+#define RM9200_USB_DIV_SHIFT	28
+#define RM9200_USB_DIV_TAB_SIZE	4
+
+struct at91sam9x5_clk_usb {
+	struct clk clk;
+	struct regmap *regmap;
+	const char *parent_names[USB_SOURCE_MAX];
+};
+
+#define to_at91sam9x5_clk_usb(clk) \
+	container_of(clk, struct at91sam9x5_clk_usb, clk)
+
+struct at91rm9200_clk_usb {
+	struct clk clk;
+	struct regmap *regmap;
+	u32 divisors[4];
+	const char *parent_name;
+};
+
+#define to_at91rm9200_clk_usb(clk) \
+	container_of(clk, struct at91rm9200_clk_usb, clk)
+
+static unsigned long at91sam9x5_clk_usb_recalc_rate(struct clk *clk,
+						    unsigned long parent_rate)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(clk);
+	unsigned int usbr;
+	u8 usbdiv;
+
+	regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
+	usbdiv = (usbr & AT91_PMC_OHCIUSBDIV) >> SAM9X5_USB_DIV_SHIFT;
+
+	return DIV_ROUND_CLOSEST(parent_rate, (usbdiv + 1));
+}
+
+static int at91sam9x5_clk_usb_set_parent(struct clk *clk, u8 index)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(clk);
+
+	if (index > 1)
+		return -EINVAL;
+
+	regmap_write_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
+			  index ? AT91_PMC_USBS : 0);
+
+	return 0;
+}
+
+static int at91sam9x5_clk_usb_get_parent(struct clk *clk)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(clk);
+	unsigned int usbr;
+
+	regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
+
+	return usbr & AT91_PMC_USBS;
+}
+
+static int at91sam9x5_clk_usb_set_rate(struct clk *clk, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(clk);
+	unsigned long div;
+
+	if (!rate)
+		return -EINVAL;
+
+	div = DIV_ROUND_CLOSEST(parent_rate, rate);
+	if (div > SAM9X5_USB_MAX_DIV + 1 || !div)
+		return -EINVAL;
+
+	regmap_write_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_OHCIUSBDIV,
+			  (div - 1) << SAM9X5_USB_DIV_SHIFT);
+
+	return 0;
+}
+
+static const struct clk_ops at91sam9x5_usb_ops = {
+	.recalc_rate = at91sam9x5_clk_usb_recalc_rate,
+	.get_parent = at91sam9x5_clk_usb_get_parent,
+	.set_parent = at91sam9x5_clk_usb_set_parent,
+	.set_rate = at91sam9x5_clk_usb_set_rate,
+};
+
+static int at91sam9n12_clk_usb_enable(struct clk *clk)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(clk);
+
+	regmap_write_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS,
+			  AT91_PMC_USBS);
+
+	return 0;
+}
+
+static void at91sam9n12_clk_usb_disable(struct clk *clk)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(clk);
+
+	regmap_write_bits(usb->regmap, AT91_PMC_USB, AT91_PMC_USBS, 0);
+}
+
+static int at91sam9n12_clk_usb_is_enabled(struct clk *clk)
+{
+	struct at91sam9x5_clk_usb *usb = to_at91sam9x5_clk_usb(clk);
+	unsigned int usbr;
+
+	regmap_read(usb->regmap, AT91_PMC_USB, &usbr);
+
+	return usbr & AT91_PMC_USBS;
+}
+
+static const struct clk_ops at91sam9n12_usb_ops = {
+	.enable = at91sam9n12_clk_usb_enable,
+	.disable = at91sam9n12_clk_usb_disable,
+	.is_enabled = at91sam9n12_clk_usb_is_enabled,
+	.recalc_rate = at91sam9x5_clk_usb_recalc_rate,
+	.set_rate = at91sam9x5_clk_usb_set_rate,
+};
+
+static struct clk *
+at91sam9x5_clk_register_usb(struct regmap *regmap, const char *name,
+			    const char **parent_names, u8 num_parents)
+{
+	struct at91sam9x5_clk_usb *usb;
+	int ret;
+
+	usb = kzalloc(sizeof(*usb), GFP_KERNEL);
+	usb->clk.name = name;
+	usb->clk.ops = &at91sam9x5_usb_ops;
+	memcpy(usb->parent_names, parent_names,
+	       num_parents * sizeof(usb->parent_names[0]));
+	usb->clk.parent_names = usb->parent_names;
+	usb->clk.num_parents = num_parents;
+	usb->clk.flags = CLK_SET_RATE_PARENT;
+	/* init.flags = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE | */
+	/* 	     CLK_SET_RATE_PARENT; */
+	usb->regmap = regmap;
+
+	ret = clk_register(&usb->clk);
+	if (ret) {
+		kfree(usb);
+		return ERR_PTR(ret);
+	}
+
+	return &usb->clk;
+}
+
+static struct clk *
+at91sam9n12_clk_register_usb(struct regmap *regmap, const char *name,
+			     const char *parent_name)
+{
+	struct at91sam9x5_clk_usb *usb;
+	int ret;
+
+	usb = xzalloc(sizeof(*usb));
+	usb->clk.name = name;
+	usb->clk.ops = &at91sam9n12_usb_ops;
+	usb->parent_names[0] = parent_name;
+	usb->clk.parent_names = &usb->parent_names[0];
+	usb->clk.num_parents = 1;
+	/* init.flags = CLK_SET_RATE_GATE | CLK_SET_RATE_PARENT; */
+	usb->regmap = regmap;
+
+	ret = clk_register(&usb->clk);
+	if (ret) {
+		kfree(usb);
+		return ERR_PTR(ret);
+	}
+
+	return &usb->clk;
+}
+
+static unsigned long at91rm9200_clk_usb_recalc_rate(struct clk *clk,
+						    unsigned long parent_rate)
+{
+	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(clk);
+	unsigned int pllbr;
+	u8 usbdiv;
+
+	regmap_read(usb->regmap, AT91_CKGR_PLLBR, &pllbr);
+
+	usbdiv = (pllbr & AT91_PMC_USBDIV) >> RM9200_USB_DIV_SHIFT;
+	if (usb->divisors[usbdiv])
+		return parent_rate / usb->divisors[usbdiv];
+
+	return 0;
+}
+
+static long at91rm9200_clk_usb_round_rate(struct clk *clk, unsigned long rate,
+					  unsigned long *parent_rate)
+{
+	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(clk);
+	struct clk *parent = clk_get_parent(clk);
+	unsigned long bestrate = 0;
+	int bestdiff = -1;
+	unsigned long tmprate;
+	int tmpdiff;
+	int i = 0;
+
+	for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
+		unsigned long tmp_parent_rate;
+
+		if (!usb->divisors[i])
+			continue;
+
+		tmp_parent_rate = rate * usb->divisors[i];
+		tmp_parent_rate = clk_round_rate(parent, tmp_parent_rate);
+		tmprate = DIV_ROUND_CLOSEST(tmp_parent_rate, usb->divisors[i]);
+		if (tmprate < rate)
+			tmpdiff = rate - tmprate;
+		else
+			tmpdiff = tmprate - rate;
+
+		if (bestdiff < 0 || bestdiff > tmpdiff) {
+			bestrate = tmprate;
+			bestdiff = tmpdiff;
+			*parent_rate = tmp_parent_rate;
+		}
+
+		if (!bestdiff)
+			break;
+	}
+
+	return bestrate;
+}
+
+static int at91rm9200_clk_usb_set_rate(struct clk *clk, unsigned long rate,
+				       unsigned long parent_rate)
+{
+	int i;
+	struct at91rm9200_clk_usb *usb = to_at91rm9200_clk_usb(clk);
+	unsigned long div;
+
+	if (!rate)
+		return -EINVAL;
+
+	div = DIV_ROUND_CLOSEST(parent_rate, rate);
+
+	for (i = 0; i < RM9200_USB_DIV_TAB_SIZE; i++) {
+		if (usb->divisors[i] == div) {
+			regmap_write_bits(usb->regmap, AT91_CKGR_PLLBR,
+					  AT91_PMC_USBDIV,
+					  i << RM9200_USB_DIV_SHIFT);
+
+			return 0;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static const struct clk_ops at91rm9200_usb_ops = {
+	.recalc_rate = at91rm9200_clk_usb_recalc_rate,
+	.round_rate = at91rm9200_clk_usb_round_rate,
+	.set_rate = at91rm9200_clk_usb_set_rate,
+};
+
+static struct clk *
+at91rm9200_clk_register_usb(struct regmap *regmap, const char *name,
+			    const char *parent_name, const u32 *divisors)
+{
+	struct at91rm9200_clk_usb *usb;
+	int ret;
+
+	usb = xzalloc(sizeof(*usb));
+	usb->clk.name = name;
+	usb->clk.ops = &at91rm9200_usb_ops;
+	usb->parent_name = parent_name;
+	usb->clk.parent_names = &usb->parent_name;
+	usb->clk.num_parents = 1;
+	/* init.flags = CLK_SET_RATE_PARENT; */
+
+	usb->regmap = regmap;
+	memcpy(usb->divisors, divisors, sizeof(usb->divisors));
+
+	ret = clk_register(&usb->clk);
+	if (ret) {
+		kfree(usb);
+		return ERR_PTR(ret);
+	}
+
+	return &usb->clk;
+}
+
+static int of_at91sam9x5_clk_usb_setup(struct device_node *np)
+{
+	struct clk *clk;
+	unsigned int num_parents;
+	const char *parent_names[USB_SOURCE_MAX];
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents == 0 || num_parents > USB_SOURCE_MAX)
+		return -EINVAL;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91sam9x5_clk_register_usb(regmap, name, parent_names,
+					 num_parents);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91sam9x5_clk_usb, "atmel,at91sam9x5-clk-usb",
+	       of_at91sam9x5_clk_usb_setup);
+
+static int of_at91sam9n12_clk_usb_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return -EINVAL;
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91sam9n12_clk_register_usb(regmap, name, parent_name);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91sam9n12_clk_usb, "atmel,at91sam9n12-clk-usb",
+	       of_at91sam9n12_clk_usb_setup);
+
+static int of_at91rm9200_clk_usb_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	u32 divisors[4] = {0, 0, 0, 0};
+	struct regmap *regmap;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	if (!parent_name)
+		return -EINVAL;
+
+	of_property_read_u32_array(np, "atmel,clk-divisors", divisors, 4);
+	if (!divisors[0])
+		return -EINVAL;
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	clk = at91rm9200_clk_register_usb(regmap, name, parent_name, divisors);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(at91rm9200_clk_usb, "atmel,at91rm9200-clk-usb",
+	       of_at91rm9200_clk_usb_setup);
diff --git a/drivers/clk/at91/clk-utmi.c b/drivers/clk/at91/clk-utmi.c
new file mode 100644
index 0000000..96ce35c
--- /dev/null
+++ b/drivers/clk/at91/clk-utmi.c
@@ -0,0 +1,138 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+#define UTMI_FIXED_MUL		40
+
+struct clk_utmi {
+	struct clk clk;
+	struct regmap *regmap;
+	const char *parent;
+};
+
+#define to_clk_utmi(clk) container_of(clk, struct clk_utmi, clk)
+
+static inline bool clk_utmi_ready(struct regmap *regmap)
+{
+	unsigned int status;
+
+	regmap_read(regmap, AT91_PMC_SR, &status);
+
+	return status & AT91_PMC_LOCKU;
+}
+
+static int clk_utmi_enable(struct clk *clk)
+{
+	struct clk_utmi *utmi = to_clk_utmi(clk);
+	unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
+			    AT91_PMC_BIASEN;
+
+	regmap_write_bits(utmi->regmap, AT91_CKGR_UCKR, uckr, uckr);
+
+	while (!clk_utmi_ready(utmi->regmap))
+		barrier();
+
+	return 0;
+}
+
+static int clk_utmi_is_enabled(struct clk *clk)
+{
+	struct clk_utmi *utmi = to_clk_utmi(clk);
+	
+	return clk_utmi_ready(utmi->regmap);
+}
+
+static void clk_utmi_disable(struct clk *clk)
+{
+	struct clk_utmi *utmi = to_clk_utmi(clk);
+
+	regmap_write_bits(utmi->regmap, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0);
+}
+
+static unsigned long clk_utmi_recalc_rate(struct clk *clk,
+					  unsigned long parent_rate)
+{
+	/* UTMI clk is a fixed clk multiplier */
+	return parent_rate * UTMI_FIXED_MUL;
+}
+
+static const struct clk_ops utmi_ops = {
+	.enable = clk_utmi_enable,
+	.disable = clk_utmi_disable,
+	.is_enabled = clk_utmi_is_enabled,
+	.recalc_rate = clk_utmi_recalc_rate,
+};
+
+static struct clk * __init
+at91_clk_register_utmi(struct regmap *regmap,
+		       const char *name, const char *parent_name)
+{
+	int ret;
+	struct clk_utmi *utmi;
+
+	utmi = xzalloc(sizeof(*utmi));
+
+	utmi->clk.name = name;
+	utmi->clk.ops = &utmi_ops;
+
+	if (parent_name) {
+		utmi->parent = parent_name;
+		utmi->clk.parent_names = &utmi->parent;
+		utmi->clk.num_parents = 1;
+	}
+
+	/* utmi->clk.flags = CLK_SET_RATE_GATE; */
+
+	utmi->regmap = regmap;
+
+	ret = clk_register(&utmi->clk);
+	if (ret) {
+		kfree(utmi);
+		return ERR_PTR(ret);
+	}
+
+	return &utmi->clk;
+}
+#if defined(CONFIG_OFTREE) && defined(CONFIG_COMMON_CLK_OF_PROVIDER)
+static void __init of_at91sam9x5_clk_utmi_setup(struct device_node *np)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	struct regmap *regmap;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	regmap = syscon_node_to_regmap(of_get_parent(np));
+	if (IS_ERR(regmap))
+		return;
+
+	clk = at91_clk_register_utmi(regmap, name, parent_name);
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+	return;
+}
+CLK_OF_DECLARE(at91sam9x5_clk_utmi, "atmel,at91sam9x5-clk-utmi",
+	       of_at91sam9x5_clk_utmi_setup);
+#endif
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
new file mode 100644
index 0000000..d156d50
--- /dev/null
+++ b/drivers/clk/at91/pmc.c
@@ -0,0 +1,41 @@
+/*
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <module.h>
+#include <linux/list.h>
+#include <linux/clkdev.h>
+#include <of.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+#include "pmc.h"
+
+int of_at91_get_clk_range(struct device_node *np, const char *propname,
+			  struct clk_range *range)
+{
+	u32 min, max;
+	int ret;
+
+	ret = of_property_read_u32_index(np, propname, 0, &min);
+	if (ret)
+		return ret;
+
+	ret = of_property_read_u32_index(np, propname, 1, &max);
+	if (ret)
+		return ret;
+
+	if (range) {
+		range->min = min;
+		range->max = max;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(of_at91_get_clk_range);
diff --git a/drivers/clk/at91/pmc.h b/drivers/clk/at91/pmc.h
new file mode 100644
index 0000000..c6c14a7
--- /dev/null
+++ b/drivers/clk/at91/pmc.h
@@ -0,0 +1,27 @@
+/*
+ * drivers/clk/at91/pmc.h
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 __PMC_H_
+#define __PMC_H_
+
+#include <io.h>
+
+struct clk_range {
+	unsigned long min;
+	unsigned long max;
+};
+
+#define CLK_RANGE(MIN, MAX) {.min = MIN, .max = MAX,}
+
+int of_at91_get_clk_range(struct device_node *np, const char *propname,
+			  struct clk_range *range);
+
+#endif /* __PMC_H_ */
diff --git a/drivers/clk/at91/sckc.c b/drivers/clk/at91/sckc.c
new file mode 100644
index 0000000..debaafb
--- /dev/null
+++ b/drivers/clk/at91/sckc.c
@@ -0,0 +1,485 @@
+/*
+ * drivers/clk/at91/sckc.c
+ *
+ *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
+ *
+ * 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 <clock.h>
+#include <of.h>
+#include <of_address.h>
+#include <io.h>
+#include <linux/list.h>
+#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
+#include <mfd/syscon.h>
+#include <regmap.h>
+
+
+
+#define SLOW_CLOCK_FREQ		32768
+#define SLOWCK_SW_CYCLES	5
+#define SLOWCK_SW_TIME_USEC	((SLOWCK_SW_CYCLES * SECOND) / \
+				 SLOW_CLOCK_FREQ)
+
+#define	AT91_SCKC_CR			0x00
+#define		AT91_SCKC_RCEN		(1 << 0)
+#define		AT91_SCKC_OSC32EN	(1 << 1)
+#define		AT91_SCKC_OSC32BYP	(1 << 2)
+#define		AT91_SCKC_OSCSEL	(1 << 3)
+
+struct clk_slow_osc {
+	struct clk clk;
+	void __iomem *sckcr;
+	unsigned long startup_usec;
+	const char *parent_name;
+};
+
+#define to_clk_slow_osc(clk) container_of(clk, struct clk_slow_osc, clk)
+
+struct clk_sama5d4_slow_osc {
+	struct clk clk;
+	void __iomem *sckcr;
+	unsigned long startup_usec;
+	bool prepared;
+	const char *parent_name;
+};
+
+#define to_clk_sama5d4_slow_osc(clk) container_of(clk, struct clk_sama5d4_slow_osc, clk)
+
+struct clk_slow_rc_osc {
+	struct clk clk;
+	void __iomem *sckcr;
+	unsigned long frequency;
+	unsigned long startup_usec;
+	const char *parent_name;
+};
+
+#define to_clk_slow_rc_osc(clk) container_of(clk, struct clk_slow_rc_osc, clk)
+
+struct clk_sam9x5_slow {
+	struct clk clk;
+	void __iomem *sckcr;
+	u8 parent;
+	const char *parent_names[2];
+};
+
+#define to_clk_sam9x5_slow(clk) container_of(clk, struct clk_sam9x5_slow, clk)
+
+static int clk_slow_osc_enable(struct clk *clk)
+{
+	struct clk_slow_osc *osc = to_clk_slow_osc(clk);
+	void __iomem *sckcr = osc->sckcr;
+	u32 tmp = readl(sckcr);
+
+	if (tmp & (AT91_SCKC_OSC32BYP | AT91_SCKC_OSC32EN))
+		return 0;
+
+	writel(tmp | AT91_SCKC_OSC32EN, sckcr);
+
+	udelay(osc->startup_usec);
+
+	return 0;
+}
+
+static void clk_slow_osc_disable(struct clk *clk)
+{
+	struct clk_slow_osc *osc = to_clk_slow_osc(clk);
+	void __iomem *sckcr = osc->sckcr;
+	u32 tmp = readl(sckcr);
+
+	if (tmp & AT91_SCKC_OSC32BYP)
+		return;
+
+	writel(tmp & ~AT91_SCKC_OSC32EN, sckcr);
+}
+
+static int clk_slow_osc_is_enabled(struct clk *clk)
+{
+	struct clk_slow_osc *osc = to_clk_slow_osc(clk);
+	void __iomem *sckcr = osc->sckcr;
+	u32 tmp = readl(sckcr);
+
+	if (tmp & AT91_SCKC_OSC32BYP)
+		return 1;
+
+	return !!(tmp & AT91_SCKC_OSC32EN);
+}
+
+static const struct clk_ops slow_osc_ops = {
+	.enable = clk_slow_osc_enable,
+	.disable = clk_slow_osc_disable,
+	.is_enabled = clk_slow_osc_is_enabled,
+};
+
+static struct clk * 
+at91_clk_register_slow_osc(void __iomem *sckcr,
+			   const char *name,
+			   const char *parent_name,
+			   unsigned long startup,
+			   bool bypass)
+{
+	int ret;
+	struct clk_slow_osc *osc;
+
+	if (!sckcr || !name || !parent_name)
+		return ERR_PTR(-EINVAL);
+
+	osc = xzalloc(sizeof(*osc));
+
+	osc->clk.name = name;
+	osc->clk.ops = &slow_osc_ops;
+	osc->parent_name = parent_name;
+	osc->clk.parent_names = &osc->parent_name;
+	osc->clk.num_parents = 1;
+
+	osc->sckcr = sckcr;
+	osc->startup_usec = startup;
+
+	if (bypass)
+		writel((readl(sckcr) & ~AT91_SCKC_OSC32EN) | AT91_SCKC_OSC32BYP,
+		       sckcr);
+
+	ret = clk_register(&osc->clk);
+	if (ret) {
+		kfree(osc);
+		return ERR_PTR(ret);
+	}
+
+	return &osc->clk;
+}
+
+static void 
+of_at91sam9x5_clk_slow_osc_setup(struct device_node *np, void __iomem *sckcr)
+{
+	struct clk *clk;
+	const char *parent_name;
+	const char *name = np->name;
+	u32 startup;
+	bool bypass;
+
+	parent_name = of_clk_get_parent_name(np, 0);
+	of_property_read_string(np, "clock-output-names", &name);
+	of_property_read_u32(np, "atmel,startup-time-usec", &startup);
+	bypass = of_property_read_bool(np, "atmel,osc-bypass");
+
+	clk = at91_clk_register_slow_osc(sckcr, name, parent_name, startup,
+					 bypass);
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static unsigned long clk_slow_rc_osc_recalc_rate(struct clk *clk,
+						 unsigned long parent_rate)
+{
+	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(clk);
+
+	return osc->frequency;
+}
+
+static int clk_slow_rc_osc_enable(struct clk *clk)
+{
+	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(clk);
+	void __iomem *sckcr = osc->sckcr;
+
+	writel(readl(sckcr) | AT91_SCKC_RCEN, sckcr);
+
+	udelay(osc->startup_usec);
+
+	return 0;
+}
+
+static void clk_slow_rc_osc_disable(struct clk *clk)
+{
+	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(clk);
+	void __iomem *sckcr = osc->sckcr;
+
+	writel(readl(sckcr) & ~AT91_SCKC_RCEN, sckcr);
+}
+
+static int clk_slow_rc_osc_is_enabled(struct clk *clk)
+{
+	struct clk_slow_rc_osc *osc = to_clk_slow_rc_osc(clk);
+
+	return !!(readl(osc->sckcr) & AT91_SCKC_RCEN);
+}
+
+static const struct clk_ops slow_rc_osc_ops = {
+	.enable = clk_slow_rc_osc_enable,
+	.disable = clk_slow_rc_osc_disable,
+	.is_enabled = clk_slow_rc_osc_is_enabled,
+	.recalc_rate = clk_slow_rc_osc_recalc_rate,
+};
+
+static struct clk * 
+at91_clk_register_slow_rc_osc(void __iomem *sckcr,
+			      const char *name,
+			      unsigned long frequency,
+			      unsigned long startup)
+{
+	struct clk_slow_rc_osc *osc;
+	int ret;
+
+	if (!sckcr || !name)
+		return ERR_PTR(-EINVAL);
+
+	osc = xzalloc(sizeof(*osc));
+	osc->clk.name = name;
+	osc->clk.ops = &slow_rc_osc_ops;
+	osc->clk.parent_names = NULL;
+	osc->clk.num_parents = 0;
+	/* init.flags = CLK_IGNORE_UNUSED; */
+
+	osc->sckcr = sckcr;
+	osc->frequency = frequency;
+	osc->startup_usec = startup;
+
+	ret = clk_register(&osc->clk);
+	if (ret) {
+		kfree(osc);
+		return ERR_PTR(ret);
+	}
+
+	return &osc->clk;
+}
+
+static void 
+of_at91sam9x5_clk_slow_rc_osc_setup(struct device_node *np, void __iomem *sckcr)
+{
+	struct clk *clk;
+	u32 frequency = 0;
+	u32 startup = 0;
+	const char *name = np->name;
+
+	of_property_read_string(np, "clock-output-names", &name);
+	of_property_read_u32(np, "clock-frequency", &frequency);
+	of_property_read_u32(np, "atmel,startup-time-usec", &startup);
+
+	clk = at91_clk_register_slow_rc_osc(sckcr, name, frequency, startup);
+	if (IS_ERR(clk))
+		return;
+
+	of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static int clk_sam9x5_slow_set_parent(struct clk *clk, u8 index)
+{
+	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(clk);
+	void __iomem *sckcr = slowck->sckcr;
+	u32 tmp;
+
+	if (index > 1)
+		return -EINVAL;
+
+	tmp = readl(sckcr);
+
+	if ((!index && !(tmp & AT91_SCKC_OSCSEL)) ||
+	    (index && (tmp & AT91_SCKC_OSCSEL)))
+		return 0;
+
+	if (index)
+		tmp |= AT91_SCKC_OSCSEL;
+	else
+		tmp &= ~AT91_SCKC_OSCSEL;
+
+	writel(tmp, sckcr);
+
+	udelay(SLOWCK_SW_TIME_USEC);
+
+	return 0;
+}
+
+static int clk_sam9x5_slow_get_parent(struct clk *clk)
+{
+	struct clk_sam9x5_slow *slowck = to_clk_sam9x5_slow(clk);
+
+	return !!(readl(slowck->sckcr) & AT91_SCKC_OSCSEL);
+}
+
+static const struct clk_ops sam9x5_slow_ops = {
+	.set_parent = clk_sam9x5_slow_set_parent,
+	.get_parent = clk_sam9x5_slow_get_parent,
+};
+
+static struct clk * 
+at91_clk_register_sam9x5_slow(void __iomem *sckcr,
+			      const char *name,
+			      const char **parent_names,
+			      int num_parents)
+{
+	struct clk_sam9x5_slow *slowck;
+	int ret;
+
+	if (!sckcr || !name || !parent_names || !num_parents)
+		return ERR_PTR(-EINVAL);
+
+	slowck = xzalloc(sizeof(*slowck));
+	slowck->clk.name = name;
+	slowck->clk.ops = &sam9x5_slow_ops;
+
+	memcpy(slowck->parent_names, parent_names,
+	       num_parents * sizeof(slowck->parent_names[0]));
+	slowck->clk.parent_names = slowck->parent_names;
+	slowck->clk.num_parents = num_parents;
+	slowck->sckcr = sckcr;
+	slowck->parent = !!(readl(sckcr) & AT91_SCKC_OSCSEL);
+
+	ret = clk_register(&slowck->clk);
+	if (ret) {
+		kfree(slowck);
+		return ERR_PTR(ret);
+	}
+
+	return &slowck->clk;
+}
+
+static int
+of_at91sam9x5_clk_slow_setup(struct device_node *np, void __iomem *sckcr)
+{
+	struct clk *clk;
+	const char *parent_names[2];
+	unsigned int num_parents;
+	const char *name = np->name;
+
+	num_parents = of_clk_get_parent_count(np);
+	if (num_parents == 0 || num_parents > 2)
+		return -EINVAL;
+
+	of_clk_parent_fill(np, parent_names, num_parents);
+
+	of_property_read_string(np, "clock-output-names", &name);
+
+	clk = at91_clk_register_sam9x5_slow(sckcr, name, parent_names,
+					    num_parents);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static const struct of_device_id sckc_clk_ids[] = {
+	/* Slow clock */
+	{
+		.compatible = "atmel,at91sam9x5-clk-slow-osc",
+		.data = of_at91sam9x5_clk_slow_osc_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-clk-slow-rc-osc",
+		.data = of_at91sam9x5_clk_slow_rc_osc_setup,
+	},
+	{
+		.compatible = "atmel,at91sam9x5-clk-slow",
+		.data = of_at91sam9x5_clk_slow_setup,
+	},
+	{ /*sentinel*/ }
+};
+
+static int of_at91sam9x5_sckc_setup(struct device_node *np)
+{
+	struct device_node *childnp;
+	void (*clk_setup)(struct device_node *, void __iomem *);
+	const struct of_device_id *clk_id;
+	void __iomem *regbase = of_iomap(np, 0);
+
+	if (!regbase)
+		return -ENOMEM;
+
+	for_each_child_of_node(np, childnp) {
+		clk_id = of_match_node(sckc_clk_ids, childnp);
+		if (!clk_id)
+			continue;
+		clk_setup = clk_id->data;
+		clk_setup(childnp, regbase);
+	}
+
+	return 0;
+}
+CLK_OF_DECLARE(at91sam9x5_clk_sckc, "atmel,at91sam9x5-sckc",
+	       of_at91sam9x5_sckc_setup);
+
+static int clk_sama5d4_slow_osc_enable(struct clk *clk)
+{
+	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(clk);
+
+	if (osc->prepared)
+		return 0;
+
+	/*
+	 * Assume that if it has already been selected (for example by the
+	 * bootloader), enough time has aready passed.
+	 */
+	if ((readl(osc->sckcr) & AT91_SCKC_OSCSEL)) {
+		osc->prepared = true;
+		return 0;
+	}
+
+	udelay(osc->startup_usec);
+	osc->prepared = true;
+
+	return 0;
+}
+
+static int clk_sama5d4_slow_osc_is_enabled(struct clk *clk)
+{
+	struct clk_sama5d4_slow_osc *osc = to_clk_sama5d4_slow_osc(clk);
+
+	return osc->prepared;
+}
+
+static const struct clk_ops sama5d4_slow_osc_ops = {
+	.enable = clk_sama5d4_slow_osc_enable,
+	.is_enabled = clk_sama5d4_slow_osc_is_enabled,
+};
+
+static int of_sama5d4_sckc_setup(struct device_node *np)
+{
+	void __iomem *regbase = of_iomap(np, 0);
+	struct clk *clk;
+	struct clk_sama5d4_slow_osc *osc;
+	const char *parent_names[2] = { "slow_rc_osc", "slow_osc" };
+	bool bypass;
+	int ret;
+
+	if (!regbase)
+		return -ENOMEM;
+
+	clk = clk_fixed(parent_names[0], 32768);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	bypass = of_property_read_bool(np, "atmel,osc-bypass");
+
+	osc = xzalloc(sizeof(*osc));
+	osc->parent_name = of_clk_get_parent_name(np, 0);
+	osc->clk.name = parent_names[1];
+	osc->clk.ops = &sama5d4_slow_osc_ops;
+	osc->clk.parent_names = &osc->parent_name;
+	osc->clk.num_parents = 1;
+	osc->sckcr = regbase;
+	osc->startup_usec = 1200000;
+
+	if (bypass)
+		writel((readl(regbase) | AT91_SCKC_OSC32BYP), regbase);
+
+	ret = clk_register(&osc->clk);
+	if (ret) {
+		kfree(osc);
+		return ret;
+	}
+
+	clk = at91_clk_register_sam9x5_slow(regbase, "slowck", parent_names, 2);
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	return of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+CLK_OF_DECLARE(sama5d4_clk_sckc, "atmel,sama5d4-sckc",
+	       of_sama5d4_sckc_setup);
diff --git a/include/linux/clk/at91_pmc.h b/include/linux/clk/at91_pmc.h
new file mode 100644
index 0000000..17f413b
--- /dev/null
+++ b/include/linux/clk/at91_pmc.h
@@ -0,0 +1,188 @@
+/*
+ * include/linux/clk/at91_pmc.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Power Management Controller (PMC) - 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_PMC_H
+#define AT91_PMC_H
+
+#define	AT91_PMC_SCER		0x00			/* System Clock Enable Register */
+#define	AT91_PMC_SCDR		0x04			/* System Clock Disable Register */
+
+#define	AT91_PMC_SCSR		0x08			/* System Clock Status Register */
+#define		AT91_PMC_PCK		(1 <<  0)		/* Processor Clock */
+#define		AT91RM9200_PMC_UDP	(1 <<  1)		/* USB Devcice Port Clock [AT91RM9200 only] */
+#define		AT91RM9200_PMC_MCKUDP	(1 <<  2)		/* USB Device Port Master Clock Automatic Disable on Suspend [AT91RM9200 only] */
+#define		AT91RM9200_PMC_UHP	(1 <<  4)		/* USB Host Port Clock [AT91RM9200 only] */
+#define		AT91SAM926x_PMC_UHP	(1 <<  6)		/* USB Host Port Clock [AT91SAM926x only] */
+#define		AT91SAM926x_PMC_UDP	(1 <<  7)		/* USB Devcice Port Clock [AT91SAM926x only] */
+#define		AT91_PMC_PCK0		(1 <<  8)		/* Programmable Clock 0 */
+#define		AT91_PMC_PCK1		(1 <<  9)		/* Programmable Clock 1 */
+#define		AT91_PMC_PCK2		(1 << 10)		/* Programmable Clock 2 */
+#define		AT91_PMC_PCK3		(1 << 11)		/* Programmable Clock 3 */
+#define		AT91_PMC_PCK4		(1 << 12)		/* Programmable Clock 4 [AT572D940HF only] */
+#define		AT91_PMC_HCK0		(1 << 16)		/* AHB Clock (USB host) [AT91SAM9261 only] */
+#define		AT91_PMC_HCK1		(1 << 17)		/* AHB Clock (LCD) [AT91SAM9261 only] */
+
+#define	AT91_PMC_PCER		0x10			/* Peripheral Clock Enable Register */
+#define	AT91_PMC_PCDR		0x14			/* Peripheral Clock Disable Register */
+#define	AT91_PMC_PCSR		0x18			/* Peripheral Clock Status Register */
+
+#define	AT91_CKGR_UCKR		0x1C			/* UTMI Clock Register [some SAM9] */
+#define		AT91_PMC_UPLLEN		(1   << 16)		/* UTMI PLL Enable */
+#define		AT91_PMC_UPLLCOUNT	(0xf << 20)		/* UTMI PLL Start-up Time */
+#define		AT91_PMC_BIASEN		(1   << 24)		/* UTMI BIAS Enable */
+#define		AT91_PMC_BIASCOUNT	(0xf << 28)		/* UTMI BIAS Start-up Time */
+
+#define	AT91_CKGR_MOR		0x20			/* Main Oscillator Register [not on SAM9RL] */
+#define		AT91_PMC_MOSCEN		(1    <<  0)		/* Main Oscillator Enable */
+#define		AT91_PMC_OSCBYPASS	(1    <<  1)		/* Oscillator Bypass */
+#define		AT91_PMC_MOSCRCEN	(1    <<  3)		/* Main On-Chip RC Oscillator Enable [some SAM9] */
+#define		AT91_PMC_OSCOUNT	(0xff <<  8)		/* Main Oscillator Start-up Time */
+#define		AT91_PMC_KEY		(0x37 << 16)		/* MOR Writing Key */
+#define		AT91_PMC_MOSCSEL	(1    << 24)		/* Main Oscillator Selection [some SAM9] */
+#define		AT91_PMC_CFDEN		(1    << 25)		/* Clock Failure Detector Enable [some SAM9] */
+
+#define	AT91_CKGR_MCFR		0x24			/* Main Clock Frequency Register */
+#define		AT91_PMC_MAINF		(0xffff <<  0)		/* Main Clock Frequency */
+#define		AT91_PMC_MAINRDY	(1	<< 16)		/* Main Clock Ready */
+
+#define	AT91_CKGR_PLLAR		0x28			/* PLL A Register */
+#define	AT91_CKGR_PLLBR		0x2c			/* PLL B Register */
+#define		AT91_PMC_DIV		(0xff  <<  0)		/* Divider */
+#define		AT91_PMC_PLLCOUNT	(0x3f  <<  8)		/* PLL Counter */
+#define		AT91_PMC_OUT		(3     << 14)		/* PLL Clock Frequency Range */
+#define		AT91_PMC_MUL		(0x7ff << 16)		/* PLL Multiplier */
+#define		AT91_PMC_MUL_GET(n)	((n) >> 16 & 0x7ff)
+#define		AT91_PMC3_MUL		(0x7f  << 18)		/* PLL Multiplier [SAMA5 only] */
+#define		AT91_PMC3_MUL_GET(n)	((n) >> 18 & 0x7f)
+#define		AT91_PMC_USBDIV		(3     << 28)		/* USB Divisor (PLLB only) */
+#define			AT91_PMC_USBDIV_1		(0 << 28)
+#define			AT91_PMC_USBDIV_2		(1 << 28)
+#define			AT91_PMC_USBDIV_4		(2 << 28)
+#define		AT91_PMC_USB96M		(1     << 28)		/* Divider by 2 Enable (PLLB only) */
+
+#define	AT91_PMC_MCKR		0x30			/* Master Clock Register */
+#define		AT91_PMC_CSS		(3 <<  0)		/* Master Clock Selection */
+#define			AT91_PMC_CSS_SLOW		(0 << 0)
+#define			AT91_PMC_CSS_MAIN		(1 << 0)
+#define			AT91_PMC_CSS_PLLA		(2 << 0)
+#define			AT91_PMC_CSS_PLLB		(3 << 0)
+#define			AT91_PMC_CSS_UPLL		(3 << 0)	/* [some SAM9 only] */
+#define		PMC_PRES_OFFSET		2
+#define		AT91_PMC_PRES		(7 <<  PMC_PRES_OFFSET)		/* Master Clock Prescaler */
+#define			AT91_PMC_PRES_1			(0 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_2			(1 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_4			(2 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_8			(3 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_16		(4 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_32		(5 << PMC_PRES_OFFSET)
+#define			AT91_PMC_PRES_64		(6 << PMC_PRES_OFFSET)
+#define		PMC_ALT_PRES_OFFSET	4
+#define		AT91_PMC_ALT_PRES	(7 <<  PMC_ALT_PRES_OFFSET)		/* Master Clock Prescaler [alternate location] */
+#define			AT91_PMC_ALT_PRES_1		(0 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_2		(1 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_4		(2 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_8		(3 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_16		(4 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_32		(5 << PMC_ALT_PRES_OFFSET)
+#define			AT91_PMC_ALT_PRES_64		(6 << PMC_ALT_PRES_OFFSET)
+#define		AT91_PMC_MDIV		(3 <<  8)		/* Master Clock Division */
+#define			AT91RM9200_PMC_MDIV_1		(0 << 8)	/* [AT91RM9200 only] */
+#define			AT91RM9200_PMC_MDIV_2		(1 << 8)
+#define			AT91RM9200_PMC_MDIV_3		(2 << 8)
+#define			AT91RM9200_PMC_MDIV_4		(3 << 8)
+#define			AT91SAM9_PMC_MDIV_1		(0 << 8)	/* [SAM9 only] */
+#define			AT91SAM9_PMC_MDIV_2		(1 << 8)
+#define			AT91SAM9_PMC_MDIV_4		(2 << 8)
+#define			AT91SAM9_PMC_MDIV_6		(3 << 8)	/* [some SAM9 only] */
+#define			AT91SAM9_PMC_MDIV_3		(3 << 8)	/* [some SAM9 only] */
+#define		AT91_PMC_PDIV		(1 << 12)		/* Processor Clock Division [some SAM9 only] */
+#define			AT91_PMC_PDIV_1			(0 << 12)
+#define			AT91_PMC_PDIV_2			(1 << 12)
+#define		AT91_PMC_PLLADIV2	(1 << 12)		/* PLLA divisor by 2 [some SAM9 only] */
+#define			AT91_PMC_PLLADIV2_OFF		(0 << 12)
+#define			AT91_PMC_PLLADIV2_ON		(1 << 12)
+#define		AT91_PMC_H32MXDIV	BIT(24)
+
+#define	AT91_PMC_USB		0x38			/* USB Clock Register [some SAM9 only] */
+#define		AT91_PMC_USBS		(0x1 <<  0)		/* USB OHCI Input clock selection */
+#define			AT91_PMC_USBS_PLLA		(0 << 0)
+#define			AT91_PMC_USBS_UPLL		(1 << 0)
+#define			AT91_PMC_USBS_PLLB		(1 << 0)	/* [AT91SAMN12 only] */
+#define		AT91_PMC_OHCIUSBDIV	(0xF <<  8)		/* Divider for USB OHCI Clock */
+#define			AT91_PMC_OHCIUSBDIV_1	(0x0 <<  8)
+#define			AT91_PMC_OHCIUSBDIV_2	(0x1 <<  8)
+
+#define	AT91_PMC_SMD		0x3c			/* Soft Modem Clock Register [some SAM9 only] */
+#define		AT91_PMC_SMDS		(0x1  <<  0)		/* SMD input clock selection */
+#define		AT91_PMC_SMD_DIV	(0x1f <<  8)		/* SMD input clock divider */
+#define		AT91_PMC_SMDDIV(n)	(((n) <<  8) & AT91_PMC_SMD_DIV)
+
+#define	AT91_PMC_PCKR(n)	(0x40 + ((n) * 4))	/* Programmable Clock 0-N Registers */
+#define		AT91_PMC_ALT_PCKR_CSS	(0x7 <<  0)		/* Programmable Clock Source Selection [alternate length] */
+#define			AT91_PMC_CSS_MASTER		(4 << 0)	/* [some SAM9 only] */
+#define		AT91_PMC_CSSMCK		(0x1 <<  8)		/* CSS or Master Clock Selection */
+#define			AT91_PMC_CSSMCK_CSS		(0 << 8)
+#define			AT91_PMC_CSSMCK_MCK		(1 << 8)
+
+#define	AT91_PMC_IER		0x60			/* Interrupt Enable Register */
+#define	AT91_PMC_IDR		0x64			/* Interrupt Disable Register */
+#define	AT91_PMC_SR		0x68			/* Status Register */
+#define		AT91_PMC_MOSCS		(1 <<  0)		/* MOSCS Flag */
+#define		AT91_PMC_LOCKA		(1 <<  1)		/* PLLA Lock */
+#define		AT91_PMC_LOCKB		(1 <<  2)		/* PLLB Lock */
+#define		AT91_PMC_MCKRDY		(1 <<  3)		/* Master Clock */
+#define		AT91_PMC_LOCKU		(1 <<  6)		/* UPLL Lock [some SAM9] */
+#define		AT91_PMC_OSCSEL		(1 <<  7)		/* Slow Oscillator Selection [some SAM9] */
+#define		AT91_PMC_PCK0RDY	(1 <<  8)		/* Programmable Clock 0 */
+#define		AT91_PMC_PCK1RDY	(1 <<  9)		/* Programmable Clock 1 */
+#define		AT91_PMC_PCK2RDY	(1 << 10)		/* Programmable Clock 2 */
+#define		AT91_PMC_PCK3RDY	(1 << 11)		/* Programmable Clock 3 */
+#define		AT91_PMC_MOSCSELS	(1 << 16)		/* Main Oscillator Selection [some SAM9] */
+#define		AT91_PMC_MOSCRCS	(1 << 17)		/* Main On-Chip RC [some SAM9] */
+#define		AT91_PMC_CFDEV		(1 << 18)		/* Clock Failure Detector Event [some SAM9] */
+#define		AT91_PMC_GCKRDY		(1 << 24)		/* Generated Clocks */
+#define	AT91_PMC_IMR		0x6c			/* Interrupt Mask Register */
+
+#define AT91_PMC_PLLICPR	0x80			/* PLL Charge Pump Current Register */
+
+#define AT91_PMC_PROT		0xe4			/* Write Protect Mode Register [some SAM9] */
+#define		AT91_PMC_WPEN		(0x1  <<  0)		/* Write Protect Enable */
+#define		AT91_PMC_WPKEY		(0xffffff << 8)		/* Write Protect Key */
+#define		AT91_PMC_PROTKEY	(0x504d43 << 8)		/* Activation Code */
+
+#define AT91_PMC_WPSR		0xe8			/* Write Protect Status Register [some SAM9] */
+#define		AT91_PMC_WPVS		(0x1  <<  0)		/* Write Protect Violation Status */
+#define		AT91_PMC_WPVSRC		(0xffff  <<  8)		/* Write Protect Violation Source */
+
+#define AT91_PMC_PCER1		0x100			/* Peripheral Clock Enable Register 1 [SAMA5 only]*/
+#define AT91_PMC_PCDR1		0x104			/* Peripheral Clock Enable Register 1 */
+#define AT91_PMC_PCSR1		0x108			/* Peripheral Clock Enable Register 1 */
+
+#define AT91_PMC_PCR		0x10c			/* Peripheral Control Register [some SAM9 and SAMA5] */
+#define		AT91_PMC_PCR_PID_MASK		0x3f
+#define		AT91_PMC_PCR_GCKCSS_OFFSET	8
+#define		AT91_PMC_PCR_GCKCSS_MASK	(0x7  << AT91_PMC_PCR_GCKCSS_OFFSET)
+#define		AT91_PMC_PCR_GCKCSS(n)		((n)  << AT91_PMC_PCR_GCKCSS_OFFSET)	/* GCK Clock Source Selection */
+#define		AT91_PMC_PCR_CMD		(0x1  <<  12)				/* Command (read=0, write=1) */
+#define		AT91_PMC_PCR_DIV_OFFSET		16
+#define		AT91_PMC_PCR_DIV_MASK		(0x3  << AT91_PMC_PCR_DIV_OFFSET)
+#define		AT91_PMC_PCR_DIV(n)		((n)  << AT91_PMC_PCR_DIV_OFFSET)	/* Divisor Value */
+#define		AT91_PMC_PCR_GCKDIV_OFFSET	20
+#define		AT91_PMC_PCR_GCKDIV_MASK	(0xff  << AT91_PMC_PCR_GCKDIV_OFFSET)
+#define		AT91_PMC_PCR_GCKDIV(n)		((n)  << AT91_PMC_PCR_GCKDIV_OFFSET)	/* Generated Clock Divisor Value */
+#define		AT91_PMC_PCR_EN			(0x1  <<  28)				/* Enable */
+#define		AT91_PMC_PCR_GCKEN		(0x1  <<  29)				/* GCK Enable */
+
+#endif
-- 
2.9.3


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

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

* [PATCH 14/45] at91sam9x5ek: Convert to use DT clock tree
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (12 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 13/45] clk: at91: Port at91 DT clock code Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 15/45] at91sam9x5ek: Remove at91sam9x5ek_mem_init() Andrey Smirnov
                   ` (32 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Convert board code to use clock tree form DT as well as converting UART,
GPIO and PIT devices to be instantiated from devicetree as well (to make
sure codebase is still bootable).

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c |  14 +-
 arch/arm/mach-at91/Kconfig          |   4 +
 arch/arm/mach-at91/Makefile         |   9 +-
 arch/arm/mach-at91/at91sam9x5.c     | 311 ------------------------------------
 arch/arm/mach-at91/setup.c          |   4 +-
 5 files changed, 19 insertions(+), 323 deletions(-)
 delete mode 100644 arch/arm/mach-at91/at91sam9x5.c

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 9fe117c..796ae84 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -87,6 +87,11 @@ static struct sam9_smc_config cm_nand_smc_config = {
 
 static void ek_add_device_nand(void)
 {
+	add_generic_device("at91sam9-smc",
+			   DEVICE_ID_SINGLE, NULL,
+			   AT91SAM9X5_BASE_SMC, 0x200,
+			   IORESOURCE_MEM, NULL);
+
 	/* setup bus-width (8 or 16) */
 	if (nand_pdata.bus_width_16)
 		cm_nand_smc_config.mode |= AT91_SMC_DBW_16;
@@ -333,15 +338,6 @@ static int at91sam9x5ek_console_init(void)
 	barebox_set_model("Atmel at91sam9x5-ek");
 	barebox_set_hostname("at91sam9x5-ek");
 
-	at91_register_uart(0, 0);
-	at91_register_uart(1, 0);
 	return 0;
 }
 console_initcall(at91sam9x5ek_console_init);
-
-static int at91sam9x5ek_main_clock(void)
-{
-	at91_set_main_clock(12000000);
-	return 0;
-}
-pure_initcall(at91sam9x5ek_main_clock);
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 2870bf3..28f66ac 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -38,6 +38,10 @@ config AT91SAM9_SMC
 config SOC_AT91SAM9
 	bool
 	select CPU_ARM926T
+	select HAVE_AT91_SMD
+	select HAVE_AT91_USB_CLK
+	select HAVE_AT91_UTMI
+	select COMMON_CLK_OF_PROVIDER
 	select AT91SAM9_SMC
 	select CLOCKSOURCE_ATMEL_PIT
 
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 1f63b09..edfa258 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -1,4 +1,9 @@
-obj-y += setup.o clock.o irq_fixup.o
+obj-y += setup.o irq_fixup.o
+
+ifeq ($(CONFIG_COMMON_CLK_OF_PROVIDER),)
+	obj-y + =clock.o
+endif
+
 obj-$(CONFIG_CMD_AT91_BOOT_TEST) += boot_test_cmd.o
 
 obj-$(CONFIG_AT91_BOOTSTRAP) += bootstrap.o
@@ -28,7 +33,7 @@ obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263.o at91sam9263_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9G10) += at91sam9261.o at91sam9261_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9G20) += at91sam9260.o at91sam9260_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45.o at91sam9g45_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9X5)	+= at91sam9x5.o at91sam9x5_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9X5)	+= at91sam9x5_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9N12)	+= at91sam9n12.o at91sam9n12_devices.o
 obj-$(CONFIG_ARCH_SAMA5D3)	+= sama5d3.o sama5d3_devices.o
 obj-$(CONFIG_ARCH_SAMA5D4)	+= sama5d4.o sama5d4_devices.o
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
deleted file mode 100644
index 000b748..0000000
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ /dev/null
@@ -1,311 +0,0 @@
-#include <common.h>
-#include <gpio.h>
-#include <init.h>
-#include <mach/hardware.h>
-#include <mach/at91_pmc.h>
-#include <mach/io.h>
-#include <mach/cpu.h>
-
-#include "soc.h"
-#include "generic.h"
-#include "clock.h"
-
-/* --------------------------------------------------------------------
- *  Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioAB_clk = {
-	.name		= "pioAB_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_PIOAB,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioCD_clk = {
-	.name		= "pioCD_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_PIOCD,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk smd_clk = {
-	.name		= "smd_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_SMD,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
-	.name		= "usart0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_USART0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
-	.name		= "usart1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_USART1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
-	.name		= "usart2_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_USART2,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-/* USART3 clock - Only for sam9g25/sam9x25 */
-static struct clk usart3_clk = {
-	.name		= "usart3_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_USART3,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi0_clk = {
-	.name		= "twi0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_TWI0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi1_clk = {
-	.name		= "twi1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_TWI1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi2_clk = {
-	.name		= "twi2_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_TWI2,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc0_clk = {
-	.name		= "mci0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_MCI0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
-	.name		= "spi0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_SPI0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
-	.name		= "spi1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_SPI1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk uart0_clk = {
-	.name		= "uart0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_UART0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk uart1_clk = {
-	.name		= "uart1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_UART1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk tcb0_clk = {
-	.name		= "tcb0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_TCB,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
-	.name		= "pwm_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_PWM,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_clk = {
-	.name		= "adc_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_ADC,
-	.type	= CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma0_clk = {
-	.name		= "dma0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_DMA0,
-	.type	= CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma1_clk = {
-	.name		= "dma1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_DMA1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk uhphs_clk = {
-	.name		= "uhphs",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_UHPHS,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk udphs_clk = {
-	.name		= "udphs_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_UDPHS,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-/* emac0 clock - Only for sam9g25/sam9x25/sam9g35/sam9x35 */
-static struct clk macb0_clk = {
-	.name		= "macb0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_EMAC0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-/* lcd clock - Only for sam9g15/sam9g35/sam9x35 */
-static struct clk lcdc_clk = {
-	.name		= "lcdc_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_LCDC,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-/* isi clock - Only for sam9g25 */
-static struct clk isi_clk = {
-	.name		= "isi_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_ISI,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc1_clk = {
-	.name		= "mci1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_MCI1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-/* emac1 clock - Only for sam9x25 */
-static struct clk macb1_clk = {
-	.name		= "macb1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_EMAC1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc_clk = {
-	.name		= "ssc_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_SSC,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-/* can0 clock - Only for sam9x35 */
-static struct clk can0_clk = {
-	.name		= "can0_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_CAN0,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-/* can1 clock - Only for sam9x35 */
-static struct clk can1_clk = {
-	.name		= "can1_clk",
-	.pmc_mask	= 1 << AT91SAM9X5_ID_CAN1,
-	.type		= CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
-	&pioAB_clk,
-	&pioCD_clk,
-	&smd_clk,
-	&usart0_clk,
-	&usart1_clk,
-	&usart2_clk,
-	&twi0_clk,
-	&twi1_clk,
-	&twi2_clk,
-	&mmc0_clk,
-	&spi0_clk,
-	&spi1_clk,
-	&uart0_clk,
-	&uart1_clk,
-	&tcb0_clk,
-	&pwm_clk,
-	&adc_clk,
-	&dma0_clk,
-	&dma1_clk,
-	&uhphs_clk,
-	&udphs_clk,
-	&mmc1_clk,
-	&ssc_clk,
-	// irq0
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
-	CLKDEV_CON_DEV_ID("macb_clk", "macb0", &macb0_clk),
-	CLKDEV_CON_DEV_ID("macb_clk", "macb1", &macb1_clk),
-	CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
-	CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci", &uhphs_clk),
-	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi0", &spi0_clk),
-	CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi1", &spi1_clk),
-	CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci0", &mmc0_clk),
-	CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci1", &mmc1_clk),
-	CLKDEV_DEV_ID("at91sam9x5-gpio0", &pioAB_clk),
-	CLKDEV_DEV_ID("at91sam9x5-gpio1", &pioAB_clk),
-	CLKDEV_DEV_ID("at91sam9x5-gpio2", &pioCD_clk),
-	CLKDEV_DEV_ID("at91sam9x5-gpio3", &pioCD_clk),
-	CLKDEV_DEV_ID("at91-pit", &mck),
-	CLKDEV_CON_DEV_ID("hck1", "atmel_hlcdfb", &lcdc_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart0", &mck),
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart1", &usart0_clk),
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart2", &usart1_clk),
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart3", &usart2_clk),
-	CLKDEV_CON_DEV_ID("usart", "atmel_usart4", &usart3_clk),
-};
-
-/*
- * 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 at91sam9x5_register_clocks(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
-		clk_register(periph_clocks[i]);
-
-	clkdev_add_table(periph_clocks_lookups,
-			 ARRAY_SIZE(periph_clocks_lookups));
-	clkdev_add_table(usart_clocks_lookups,
-			 ARRAY_SIZE(usart_clocks_lookups));
-
-	if (cpu_is_at91sam9g25()
-	|| cpu_is_at91sam9x25())
-		clk_register(&usart3_clk);
-
-	if (cpu_is_at91sam9g25()
-	|| cpu_is_at91sam9x25()
-	|| cpu_is_at91sam9g35()
-	|| cpu_is_at91sam9x35())
-		clk_register(&macb0_clk);
-
-	if (cpu_is_at91sam9g15()
-	|| cpu_is_at91sam9g35()
-	|| cpu_is_at91sam9x35())
-		clk_register(&lcdc_clk);
-
-	if (cpu_is_at91sam9g25())
-		clk_register(&isi_clk);
-
-	if (cpu_is_at91sam9x25())
-		clk_register(&macb1_clk);
-
-	if (cpu_is_at91sam9x25()
-	|| cpu_is_at91sam9x35()) {
-		clk_register(&can0_clk);
-		clk_register(&can1_clk);
-	}
-
-	clk_register(&pck0);
-	clk_register(&pck1);
-}
-
-/* --------------------------------------------------------------------
- *  AT91SAM9x5 processor initialization
- * -------------------------------------------------------------------- */
-
-static void at91sam9x5_initialize(void)
-{
-	/* Register the processor-specific clocks */
-	at91sam9x5_register_clocks();
-
-	/* Register GPIO subsystem */
-	at91_add_sam9x5_gpio(0, AT91SAM9X5_BASE_PIOA);
-	at91_add_sam9x5_gpio(1, AT91SAM9X5_BASE_PIOB);
-	at91_add_sam9x5_gpio(2, AT91SAM9X5_BASE_PIOC);
-	at91_add_sam9x5_gpio(3, AT91SAM9X5_BASE_PIOD);
-
-	at91_add_pit(AT91SAM9X5_BASE_PIT);
-	at91_add_sam9_smc(DEVICE_ID_SINGLE, AT91SAM9X5_BASE_SMC, 0x200);
-}
-
-AT91_SOC_START(sam9x5)
-	.init = at91sam9x5_initialize,
-AT91_SOC_END
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 1fa50ac..8f32af0 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -85,7 +85,6 @@ static void __init soc_detect(u32 dbgu_base)
 
 	case ARCH_ID_AT91SAM9X5:
 		at91_soc_initdata.type = AT91_SOC_SAM9X5;
-		at91_boot_soc = at91sam9x5_soc;
 		break;
 
 	case ARCH_ID_AT91SAM9N12:
@@ -284,6 +283,9 @@ static int at91_detect(void)
 	pr_info("AT91: Detected soc subtype: %s\n",
 		at91_get_soc_subtype(&at91_soc_initdata));
 
+	if (IS_ENABLED(CONFIG_COMMON_CLK_OF_PROVIDER))
+		return 0;
+
 	if (!at91_soc_is_enabled())
 		panic("AT91: Soc not enabled");
 
-- 
2.9.3


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

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

* [PATCH 15/45] at91sam9x5ek: Remove at91sam9x5ek_mem_init()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (13 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 14/45] at91sam9x5ek: Convert to use DT clock tree Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 16/45] at91sam9x5ek: Configure LEDs in DT Andrey Smirnov
                   ` (31 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

RAM device is created based on OF data now, so there's no need to call
this function.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 796ae84..068897a 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -286,14 +286,6 @@ static void __init ek_add_led(void)
 	led_set_trigger(LED_TRIGGER_HEARTBEAT, &leds[1].led);
 }
 
-static int at91sam9x5ek_mem_init(void)
-{
-	at91_add_device_sdram(0);
-
-	return 0;
-}
-mem_initcall(at91sam9x5ek_mem_init);
-
 static void ek_add_device_w1(void)
 {
 	at91_set_gpio_input(w1_pdata.pin, 0);
-- 
2.9.3


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

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

* [PATCH 16/45] at91sam9x5ek: Configure LEDs in DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (14 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 15/45] at91sam9x5ek: Remove at91sam9x5ek_mem_init() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 17/45] pinctrl-at91: Fix a bug in at91_pinctrl_set_conf() Andrey Smirnov
                   ` (30 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c     | 27 ---------------------------
 arch/arm/configs/at91sam9x5ek_defconfig |  1 +
 2 files changed, 1 insertion(+), 27 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 068897a..85f20a9 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -260,32 +260,6 @@ static void ek_add_device_usb(void)
 static void ek_add_device_usb(void) {}
 #endif
 
-struct gpio_led leds[] = {
-	{
-		.gpio	= AT91_PIN_PB18,
-		.active_low	= 1,
-		.led	= {
-			.name = "d1",
-		},
-	}, {
-		.gpio	= AT91_PIN_PD21,
-		.led	= {
-			.name = "d2",
-		},
-	},
-};
-
-static void __init ek_add_led(void)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(leds); i++) {
-		at91_set_gpio_output(leds[i].gpio, leds[i].active_low);
-		led_gpio_register(&leds[i]);
-	}
-	led_set_trigger(LED_TRIGGER_HEARTBEAT, &leds[1].led);
-}
-
 static void ek_add_device_w1(void)
 {
 	at91_set_gpio_input(w1_pdata.pin, 0);
@@ -303,7 +277,6 @@ static int at91sam9x5ek_devices_init(void)
 	ek_add_device_spi();
 	ek_add_device_mci();
 	ek_add_device_usb();
-	ek_add_led();
 	ek_add_device_i2c();
 	ek_add_device_lcdc();
 
diff --git a/arch/arm/configs/at91sam9x5ek_defconfig b/arch/arm/configs/at91sam9x5ek_defconfig
index 0691145..dd42755 100644
--- a/arch/arm/configs/at91sam9x5ek_defconfig
+++ b/arch/arm/configs/at91sam9x5ek_defconfig
@@ -90,3 +90,4 @@ CONFIG_FS_TFTP=y
 CONFIG_FS_FAT=y
 CONFIG_FS_FAT_WRITE=y
 CONFIG_FS_FAT_LFN=y
+CONFIG_LED_GPIO_OF=y
-- 
2.9.3


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

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

* [PATCH 17/45] pinctrl-at91: Fix a bug in at91_pinctrl_set_conf()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (15 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 16/45] at91sam9x5ek: Configure LEDs in DT Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 18/45] at91: Enable PINCTRL for SOC_AT91SAM9 Andrey Smirnov
                   ` (29 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Pin_to_controller returns struct at91_gpio_chip, whereas at91_mux_*
functions expect void __iomem * pointing to controller register
window. Fix the code to do appropriate conversion between the two.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pinctrl/pinctrl-at91.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index ebbc6f6..e24c9be 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -414,8 +414,10 @@ static int at91_pinctrl_set_conf(struct at91_pinctrl *info, unsigned int pin_num
 {
 	unsigned int mask;
 	void __iomem *pio;
+	struct at91_gpio_chip *at91_gpio;
 
-	pio = pin_to_controller(pin_num);
+	at91_gpio = pin_to_controller(pin_num);
+	pio  = at91_gpio->regbase;
 	mask = pin_to_mask(pin_num);
 
 	if (conf & PULL_UP && conf & PULL_DOWN)
-- 
2.9.3


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

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

* [PATCH 18/45] at91: Enable PINCTRL for SOC_AT91SAM9
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (16 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 17/45] pinctrl-at91: Fix a bug in at91_pinctrl_set_conf() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 19/45] at91sam9x5ek: Configure I2C via DT Andrey Smirnov
                   ` (28 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-at91/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 28f66ac..0b77653 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -44,6 +44,7 @@ config SOC_AT91SAM9
 	select COMMON_CLK_OF_PROVIDER
 	select AT91SAM9_SMC
 	select CLOCKSOURCE_ATMEL_PIT
+	select PINCTRL
 
 config SOC_SAMA5
 	bool
-- 
2.9.3


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

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

* [PATCH 19/45] at91sam9x5ek: Configure I2C via DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (17 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 18/45] at91: Enable PINCTRL for SOC_AT91SAM9 Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 20/45] mci: Allow parsing for explicit DT node Andrey Smirnov
                   ` (27 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c | 21 ---------------------
 arch/arm/dts/at91sam9x5ek.dts       | 10 ++++++++++
 2 files changed, 10 insertions(+), 21 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 85f20a9..fca5e7d 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -187,26 +187,6 @@ static void ek_add_device_mci(void)
 	at91_add_device_mci(0, &mci0_data);
 }
 
-struct qt1070_platform_data qt1070_pdata = {
-	.irq_pin	= AT91_PIN_PA7,
-};
-
-static struct i2c_board_info i2c_devices[] = {
-	{
-		.platform_data = &qt1070_pdata,
-		I2C_BOARD_INFO("qt1070", 0x1b),
-	}, {
-		I2C_BOARD_INFO("24c512", 0x51)
-	},
-};
-
-static void ek_add_device_i2c(void)
-{
-	at91_set_gpio_input(qt1070_pdata.irq_pin, 0);
-	at91_set_deglitch(qt1070_pdata.irq_pin, 1);
-	at91_add_device_i2c(0, i2c_devices, ARRAY_SIZE(i2c_devices));
-}
-
 static const struct spi_board_info ek_cm_cogent_spi_devices[] = {
 	{
 		.name		= "mtd_dataflash",
@@ -277,7 +257,6 @@ static int at91sam9x5ek_devices_init(void)
 	ek_add_device_spi();
 	ek_add_device_mci();
 	ek_add_device_usb();
-	ek_add_device_i2c();
 	ek_add_device_lcdc();
 
 	armlinux_set_architecture(CONFIG_MACH_AT91SAM9X5EK);
diff --git a/arch/arm/dts/at91sam9x5ek.dts b/arch/arm/dts/at91sam9x5ek.dts
index db1bd67..f9ae091 100644
--- a/arch/arm/dts/at91sam9x5ek.dts
+++ b/arch/arm/dts/at91sam9x5ek.dts
@@ -7,3 +7,13 @@
 #include <arm/at91sam9x5_lcd.dtsi>
 #include <arm/at91sam9x5dm.dtsi>
 #include <arm/at91sam9x5ek.dtsi>
+
+/ {
+	i2c-gpio-0 {
+		status = "okay";
+	};
+};
+
+&i2c0 {
+	status = "disabled";
+};
-- 
2.9.3


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

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

* [PATCH 20/45] mci: Allow parsing for explicit DT node
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (18 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 19/45] at91sam9x5ek: Configure I2C via DT Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 21/45] mci: atmel_mci: Add DT support Andrey Smirnov
                   ` (26 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Convert mci_of_parse into mci_of_parse_node, a function that takes
explicit deivce tree node pointer to be used for SD/MMC related
properties extraction. Implement original mci_of_parse as a wrapper
around the call to new function.

This is useful for controllers who specify parameter like bus witdth and
GPIOs as a part of main controller's child nodes (e.g. AT91 SoCs).

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/mci/mci-core.c | 13 ++++++++-----
 include/mci.h          |  1 +
 2 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/mci/mci-core.c b/drivers/mci/mci-core.c
index 055a5e2..928277a 100644
--- a/drivers/mci/mci-core.c
+++ b/drivers/mci/mci-core.c
@@ -1843,20 +1843,18 @@ err_free:
 	return ret;
 }
 
-void mci_of_parse(struct mci_host *host)
+void mci_of_parse_node(struct mci_host *host,
+		       struct device_node *np)
 {
-	struct device_node *np;
 	u32 bus_width;
 	u32 dsr_val;
 
 	if (!IS_ENABLED(CONFIG_OFDEVICE))
 		return;
 
-	if (!host->hw_dev || !host->hw_dev->device_node)
+	if (!host->hw_dev || !np)
 		return;
 
-	np = host->hw_dev->device_node;
-
 	/* "bus-width" is translated to MMC_CAP_*_BIT_DATA flags */
 	if (of_property_read_u32(np, "bus-width", &bus_width) < 0) {
 		/* If bus-width is missing we get the driver's default, which
@@ -1897,6 +1895,11 @@ void mci_of_parse(struct mci_host *host)
 	host->non_removable = of_property_read_bool(np, "non-removable");
 }
 
+void mci_of_parse(struct mci_host *host)
+{
+	return mci_of_parse_node(host, host->hw_dev->device_node);
+}
+
 struct mci *mci_get_device_by_name(const char *name)
 {
 	struct mci *mci;
diff --git a/include/mci.h b/include/mci.h
index cc4712c..781e6e0 100644
--- a/include/mci.h
+++ b/include/mci.h
@@ -480,6 +480,7 @@ struct mci {
 
 int mci_register(struct mci_host*);
 void mci_of_parse(struct mci_host *host);
+void mci_of_parse_node(struct mci_host *host, struct device_node *np);
 int mci_detect_card(struct mci_host *);
 int mci_send_ext_csd(struct mci *mci, char *ext_csd);
 int mci_switch(struct mci *mci, unsigned set, unsigned index,
-- 
2.9.3


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

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

* [PATCH 21/45] mci: atmel_mci: Add DT support
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (19 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 20/45] mci: Allow parsing for explicit DT node Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 22/45] at91sam9x5ek: Configure MMC in DT Andrey Smirnov
                   ` (25 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/mci/atmel_mci.c | 101 +++++++++++++++++++++++++++++++++---------------
 1 file changed, 70 insertions(+), 31 deletions(-)

diff --git a/drivers/mci/atmel_mci.c b/drivers/mci/atmel_mci.c
index 2a0ddb0..317cf46 100644
--- a/drivers/mci/atmel_mci.c
+++ b/drivers/mci/atmel_mci.c
@@ -24,6 +24,7 @@
 #include <mach/board.h>
 #include <linux/clk.h>
 #include <linux/err.h>
+#include <of_gpio.h>
 
 #include "atmel-mci-regs.h"
 
@@ -53,6 +54,7 @@ struct atmel_mci {
 	u32			cfg_reg;
 	u32			sdc_reg;
 	bool			need_reset;
+	int			detect_pin;
 };
 
 #define to_mci_host(mci)	container_of(mci, struct atmel_mci, mci)
@@ -360,14 +362,13 @@ static int atmci_start_cmd(struct atmel_mci *host, struct mci_cmd *cmd,
 static int atmci_card_present(struct mci_host *mci)
 {
 	struct atmel_mci *host = to_mci_host(mci);
-	struct atmel_mci_platform_data *pd = host->hw_dev->platform_data;
 	int ret;
 
 	/* No gpio, assume card is present */
-	if (!gpio_is_valid(pd->detect_pin))
+	if (!gpio_is_valid(host->detect_pin))
 		return 1;
 
-	ret = gpio_get_value(pd->detect_pin);
+	ret = gpio_get_value(host->detect_pin);
 
 	return ret == 0 ? 1 : 0;
 }
@@ -535,44 +536,71 @@ static int atmci_probe(struct device_d *hw_dev)
 {
 	struct resource *iores;
 	struct atmel_mci *host;
+	struct device_node *np = hw_dev->device_node;
 	struct atmel_mci_platform_data *pd = hw_dev->platform_data;
 	int ret;
 
-	if (!pd) {
-		dev_err(hw_dev, "missing platform data\n");
-		return -EINVAL;
+	host = xzalloc(sizeof(*host));
+	host->mci.send_cmd = atmci_request;
+	host->mci.set_ios = atmci_set_ios;
+	host->mci.init = atmci_reset;
+	host->mci.card_present = atmci_card_present;
+	host->mci.hw_dev = hw_dev;
+	host->detect_pin = -EINVAL;
+
+	if (pd) {
+		host->detect_pin  = pd->detect_pin;
+		host->mci.devname = pd->devname;
+
+		if (pd->bus_width >= 4)
+			host->mci.host_caps |= MMC_CAP_4_BIT_DATA;
+		if (pd->bus_width == 8)
+			host->mci.host_caps |= MMC_CAP_8_BIT_DATA;
+
+		host->slot_b = pd->slot_b;
+	} else if (np) {
+		u32 slot_id;
+		struct device_node *cnp;
+		const char *alias = of_alias_get(np);
+
+		if (alias)
+			host->mci.devname = xstrdup(alias);
+
+		host->detect_pin = of_get_named_gpio(np, "cd-gpios", 0);
+
+		for_each_child_of_node(np, cnp) {
+			if (of_property_read_u32(cnp, "reg", &slot_id)) {
+				dev_warn(hw_dev, "reg property is missing for %s\n",
+					 cnp->full_name);
+				continue;
+			}
+
+			host->slot_b = slot_id;
+			mci_of_parse_node(&host->mci, cnp);
+			break;
+		}
+	} else {
+		dev_err(hw_dev, "Missing device information\n");
+		ret = -EINVAL;
+		goto error_out;
 	}
 
-	if (gpio_is_valid(pd->detect_pin)) {
-		ret = gpio_request(pd->detect_pin, "mci_cd");
+	if (gpio_is_valid(host->detect_pin)) {
+		ret = gpio_request(host->detect_pin, "mci_cd");
 		if (ret) {
 			dev_err(hw_dev, "Impossible to request CD gpio %d (%d)\n",
-				ret, pd->detect_pin);
-			return ret;
+				ret, host->detect_pin);
+			goto error_out;
 		}
 
-		ret = gpio_direction_input(pd->detect_pin);
+		ret = gpio_direction_input(host->detect_pin);
 		if (ret) {
 			dev_err(hw_dev, "Impossible to configure CD gpio %d as input (%d)\n",
-				ret, pd->detect_pin);
-			goto err_gpio_cd_request;
+				ret, host->detect_pin);
+			goto error_out;
 		}
 	}
 
-	host = xzalloc(sizeof(*host));
-	host->mci.send_cmd = atmci_request;
-	host->mci.set_ios = atmci_set_ios;
-	host->mci.init = atmci_reset;
-	host->mci.card_present = atmci_card_present;
-	host->mci.hw_dev = hw_dev;
-	host->mci.devname = pd->devname;
-
-	if (pd->bus_width >= 4)
-		host->mci.host_caps |= MMC_CAP_4_BIT_DATA;
-	if (pd->bus_width == 8)
-		host->mci.host_caps |= MMC_CAP_8_BIT_DATA;
-	host->slot_b = pd->slot_b;
-
 	iores = dev_request_mem_resource(hw_dev, 0);
 	if (IS_ERR(iores))
 		return PTR_ERR(iores);
@@ -583,7 +611,7 @@ static int atmci_probe(struct device_d *hw_dev)
 	if (IS_ERR(host->clk)) {
 		dev_err(hw_dev, "no mci_clk\n");
 		ret = PTR_ERR(host->clk);
-		goto err_gpio_cd_request;
+		goto error_out;
 	}
 
 	clk_enable(host->clk);
@@ -614,15 +642,26 @@ static int atmci_probe(struct device_d *hw_dev)
 
 	return 0;
 
-err_gpio_cd_request:
-	if (gpio_is_valid(pd->detect_pin))
-		gpio_free(pd->detect_pin);
+error_out:
+	free(host);
+
+	if (gpio_is_valid(host->detect_pin))
+		gpio_free(host->detect_pin);
 
 	return ret;
 }
 
+static __maybe_unused struct of_device_id atmci_compatible[] = {
+	{
+		.compatible = "atmel,hsmci",
+	}, {
+		/* sentinel */
+	}
+};
+
 static struct driver_d atmci_driver = {
 	.name	= "atmel_mci",
 	.probe	= atmci_probe,
+	.of_compatible = DRV_OF_COMPAT(atmci_compatible),
 };
 device_platform_driver(atmci_driver);
-- 
2.9.3


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

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

* [PATCH 22/45] at91sam9x5ek: Configure MMC in DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (20 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 21/45] mci: atmel_mci: Add DT support Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 23/45] of: base: Use scoring in DT device matching Andrey Smirnov
                   ` (24 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c | 20 --------------------
 arch/arm/dts/at91sam9x5ek.dts       |  5 +++++
 2 files changed, 5 insertions(+), 20 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index fca5e7d..8acb23c 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -168,25 +168,6 @@ static void ek_add_device_lcdc(void)
 static void ek_add_device_lcdc(void) {}
 #endif
 
-/*
- * MCI (SD/MMC)
- */
-/* mci0 detect_pin is revision dependent */
-static struct atmel_mci_platform_data mci0_data = {
-	.bus_width	= 4,
-	.detect_pin	= AT91_PIN_PD15,
-	.wp_pin		= -EINVAL,
-};
-
-static void ek_add_device_mci(void)
-{
-	if (at91sam9x5ek_cm_is_vendor(VENDOR_COGENT))
-		mci0_data.detect_pin = -EINVAL;
-
-	/* MMC0 */
-	at91_add_device_mci(0, &mci0_data);
-}
-
 static const struct spi_board_info ek_cm_cogent_spi_devices[] = {
 	{
 		.name		= "mtd_dataflash",
@@ -255,7 +236,6 @@ static int at91sam9x5ek_devices_init(void)
 	ek_add_device_nand();
 	ek_add_device_eth();
 	ek_add_device_spi();
-	ek_add_device_mci();
 	ek_add_device_usb();
 	ek_add_device_lcdc();
 
diff --git a/arch/arm/dts/at91sam9x5ek.dts b/arch/arm/dts/at91sam9x5ek.dts
index f9ae091..00bb86a 100644
--- a/arch/arm/dts/at91sam9x5ek.dts
+++ b/arch/arm/dts/at91sam9x5ek.dts
@@ -9,6 +9,11 @@
 #include <arm/at91sam9x5ek.dtsi>
 
 / {
+	aliases {
+		mmc0 = &mmc0;
+		mmc1 = &mmc1;
+	};
+
 	i2c-gpio-0 {
 		status = "okay";
 	};
-- 
2.9.3


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

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

* [PATCH 23/45] of: base: Use scoring in DT device matching
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (21 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 22/45] at91sam9x5ek: Configure MMC in DT Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 24/45] pinctrl: at91: Fix a bug in at91_pinctrl_set_state Andrey Smirnov
                   ` (23 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Port Linux kernel algorithm for both of_device_is_compatible() and
of_match_node(). With this change former now returns a score on the
scale of 0 to INT_MAX/2, and the latter goes through all compatiblity
entries and selects the entry that has the best matching score.

This is needed for SoCs where IP blocks are backwards compatible and
corresponding OF nodes can proclaim compatibility with several entries
found in driver's compatiblity table. One such example would be PIO
pinctrl block on AT91SAM9x5 SoCs which declare compatibility with with
both "atmel,at91sam9x5-pinctrl" and "atmel,at91rm9200-pinctrl".

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/of/base.c | 37 +++++++++++++++++++++----------------
 1 file changed, 21 insertions(+), 16 deletions(-)

diff --git a/drivers/of/base.c b/drivers/of/base.c
index 0c20fcd..bef8f1d 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -472,21 +472,20 @@ EXPORT_SYMBOL(of_get_cpu_node);
 int of_device_is_compatible(const struct device_node *device,
 		const char *compat)
 {
+	struct property *prop;
 	const char *cp;
-	int cplen, l;
+	int index = 0, score = 0;
 
-	cp = of_get_property(device, "compatible", &cplen);
-	if (cp == NULL)
-		return 0;
-	while (cplen > 0) {
-		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
-			return 1;
-		l = strlen(cp) + 1;
-		cp += l;
-		cplen -= l;
+	prop = of_find_property(device, "compatible", NULL);
+	for (cp = of_prop_next_string(prop, NULL); cp;
+	     cp = of_prop_next_string(prop, cp), index++) {
+		if (of_compat_cmp(cp, compat, strlen(compat)) == 0) {
+			score = INT_MAX/2 - (index << 2);
+			break;
+		}
 	}
 
-	return 0;
+	return score;
 }
 EXPORT_SYMBOL(of_device_is_compatible);
 
@@ -602,16 +601,22 @@ EXPORT_SYMBOL(of_find_node_with_property);
 const struct of_device_id *of_match_node(const struct of_device_id *matches,
 					 const struct device_node *node)
 {
+	const struct of_device_id *best_match = NULL;
+	int score, best_score = 0;
+
 	if (!matches || !node)
 		return NULL;
 
-	while (matches->compatible) {
-		if (of_device_is_compatible(node, matches->compatible) == 1)
-			return matches;
-		matches++;
+	for (; matches->compatible; matches++) {
+		score = of_device_is_compatible(node, matches->compatible);
+
+		if (score > best_score) {
+			best_match = matches;
+			best_score = score;
+		}
 	}
 
-	return NULL;
+	return best_match;
 }
 
 /**
-- 
2.9.3


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

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

* [PATCH 24/45] pinctrl: at91: Fix a bug in at91_pinctrl_set_state
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (22 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 23/45] of: base: Use scoring in DT device matching Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 25/45] pinctrl: at91: Implement .get_direction hook Andrey Smirnov
                   ` (22 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Pin number, as specified in OF pinumx entries, is relative to each bank
start, whereas both at91_mux_pin() and at91_pinctrl_set_conf() asssume
absolute pin numbering, so we need to take into account each bank's pin
base and convert pin number appropriately. Failing to do so results in
any pinmux configuration being applied to pins in bank A.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pinctrl/pinctrl-at91.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index e24c9be..34fb0ae 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -462,6 +462,8 @@ static int at91_pinctrl_set_state(struct pinctrl_device *pdev, struct device_nod
 		mux = be32_to_cpu(*list++);
 		conf = be32_to_cpu(*list++);
 
+		pin_num += bank_num * MAX_NB_GPIO_PER_BANK;
+
 		ret = at91_mux_pin(pin_num, mux, conf & PULL_UP);
 		if (ret) {
 			dev_err(pdev->dev, "failed to mux pin %d\n", pin_num);
-- 
2.9.3


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

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

* [PATCH 25/45] pinctrl: at91: Implement .get_direction hook
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (23 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 24/45] pinctrl: at91: Fix a bug in at91_pinctrl_set_state Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 26/45] spi: atmel_spi: Add DT support Andrey Smirnov
                   ` (21 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/pinctrl/pinctrl-at91.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 34fb0ae..021c1e5 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -568,6 +568,21 @@ static int at91_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
 	return 0;
 }
 
+static int at91_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
+	void __iomem *pio = at91_gpio->regbase;
+	unsigned mask = 1 << offset;
+	u32 osr;
+
+	if (mask & __raw_readl(pio + PIO_PSR)) {
+		osr = __raw_readl(pio + PIO_OSR);
+		return !(osr & mask);
+	} else {
+		return -EBUSY;
+	}
+}
+
 static int at91_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
 {
 	struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
@@ -603,6 +618,7 @@ static struct gpio_ops at91_gpio_ops = {
 	.free = at91_gpio_free,
 	.direction_input = at91_gpio_direction_input,
 	.direction_output = at91_gpio_direction_output,
+	.get_direction = at91_gpio_get_direction,
 	.get = at91_gpio_get,
 	.set = at91_gpio_set,
 };
-- 
2.9.3


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

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

* [PATCH 26/45] spi: atmel_spi: Add DT support
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (24 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 25/45] pinctrl: at91: Implement .get_direction hook Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 27/45] spi: atmel_spi: Configure CS GPIO as output Andrey Smirnov
                   ` (20 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/spi/atmel_spi.c | 29 ++++++++++++++++++++++++++---
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 3f2c527..68466ef 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -29,6 +29,7 @@
 #include <clock.h>
 #include <xfuncs.h>
 #include <gpio.h>
+#include <of_gpio.h>
 #include <io.h>
 #include <spi/spi.h>
 #include <mach/io.h>
@@ -375,10 +376,11 @@ static int atmel_spi_probe(struct device_d *dev)
 	int ret = 0;
 	int i;
 	struct spi_master *master;
+	struct device_node *node = dev->device_node;
 	struct atmel_spi *as;
 	struct at91_spi_platform_data *pdata = dev->platform_data;
 
-	if (!pdata) {
+	if (!IS_ENABLED(CONFIG_OFDEVICE) && !pdata) {
 		dev_err(dev, "missing platform data\n");
 		return -EINVAL;
 	}
@@ -389,6 +391,23 @@ static int atmel_spi_probe(struct device_d *dev)
 	master->dev = dev;
 	master->bus_num = dev->id;
 
+	if (pdata) {
+		master->num_chipselect = pdata->num_chipselect;
+		as->cs_pins = pdata->chipselect;
+	} else {
+		master->num_chipselect = of_gpio_named_count(node, "cs-gpios");
+		as->cs_pins = xzalloc(sizeof(u32) * master->num_chipselect);
+
+		for (i = 0; i < master->num_chipselect; i++) {
+			as->cs_pins[i] = of_get_named_gpio(node, "cs-gpios", i);
+
+			if (!gpio_is_valid(as->cs_pins[i]))
+			    break;
+		}
+
+		master->num_chipselect = i;
+	}
+
 	as->clk = clk_get(dev, "spi_clk");
 	if (IS_ERR(as->clk)) {
 		dev_err(dev, "no spi_clk\n");
@@ -398,8 +417,6 @@ static int atmel_spi_probe(struct device_d *dev)
 
 	master->setup = atmel_spi_setup;
 	master->transfer = atmel_spi_transfer;
-	master->num_chipselect = pdata->num_chipselect;
-	as->cs_pins = pdata->chipselect;
 	iores = dev_request_mem_resource(dev, 0);
 	if (IS_ERR(iores))
 		return PTR_ERR(iores);
@@ -438,8 +455,14 @@ out_free:
 	return ret;
 }
 
+static __maybe_unused const struct of_device_id atmel_spi_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-spi" },
+	{ /* sentinel */ }
+};
+
 static struct driver_d atmel_spi_driver = {
 	.name  = "atmel_spi",
 	.probe = atmel_spi_probe,
+	.of_compatible = DRV_OF_COMPAT(atmel_spi_dt_ids),
 };
 device_platform_driver(atmel_spi_driver);
-- 
2.9.3


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

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

* [PATCH 27/45] spi: atmel_spi: Configure CS GPIO as output
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (25 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 26/45] spi: atmel_spi: Add DT support Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 28/45] spi: atmel_spi: Use VERSION register instead of CPU type Andrey Smirnov
                   ` (19 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

On AT91 GPIOs default to being inputs, so we need to explicitly
configure CS gpio to being an output.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/spi/atmel_spi.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index 68466ef..b183344 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -173,6 +173,8 @@ static int atmel_spi_setup(struct spi_device *spi)
 	struct spi_master	*master = spi->master;
 	struct atmel_spi	*as = to_atmel_spi(master);
 
+	int			npcs_pin;
+	unsigned		active = spi->mode & SPI_CS_HIGH;
 	u32			scbr, csr;
 	unsigned int		bits = spi->bits_per_word;
 	unsigned long		bus_hz;
@@ -184,6 +186,8 @@ static int atmel_spi_setup(struct spi_device *spi)
 		return -EINVAL;
 	}
 
+	npcs_pin = as->cs_pins[spi->chip_select];
+
 	if (bits < 8 || bits > 16) {
 		dev_dbg(&spi->dev,
 				"setup: invalid bits_per_word %u (8 to 16)\n",
@@ -236,7 +240,7 @@ static int atmel_spi_setup(struct spi_device *spi)
 	csr |= SPI_BF(DLYBS, 0);
 	csr |= SPI_BF(DLYBCT, 0);
 
-	/* gpio_direction_output(npcs_pin, !(spi->mode & SPI_CS_HIGH)); */
+	gpio_direction_output(npcs_pin, !active);
 	dev_dbg(master->dev,
 		"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
 		bus_hz / scbr, bits, spi->mode, spi->chip_select, csr);
-- 
2.9.3


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

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

* [PATCH 28/45] spi: atmel_spi: Use VERSION register instead of CPU type
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (26 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 27/45] spi: atmel_spi: Configure CS GPIO as output Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 29/45] at91sam9x5ek: Configure SPI in DT Andrey Smirnov
                   ` (18 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Use VERSION register instead of CPU type to determine IP block's version
and capabilities. This what corresponding Linux kernel driver does.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/spi/atmel_spi.c | 35 +++++++++++++++++++++++++++++------
 drivers/spi/atmel_spi.h |  1 +
 2 files changed, 30 insertions(+), 6 deletions(-)

diff --git a/drivers/spi/atmel_spi.c b/drivers/spi/atmel_spi.c
index b183344..55032be 100644
--- a/drivers/spi/atmel_spi.c
+++ b/drivers/spi/atmel_spi.c
@@ -41,11 +41,16 @@
 
 #include "atmel_spi.h"
 
+struct atmel_spi_caps {
+	bool	is_spi2;
+};
+
 struct atmel_spi {
 	struct spi_master	master;
 	void __iomem		*regs;
 	struct clk		*clk;
 	int			*cs_pins;
+	struct atmel_spi_caps	caps;
 };
 
 #define to_atmel_spi(p)		container_of(p, struct atmel_spi, master)
@@ -63,9 +68,9 @@ struct atmel_spi {
  * register, but I haven't checked that it exists on all chips, and
  * this is cheaper anyway.
  */
-static inline bool atmel_spi_is_v2(void)
+static inline bool atmel_spi_is_v2(struct atmel_spi *as)
 {
-	return !cpu_is_at91rm9200();
+	return as->caps.is_spi2;
 }
 
 /*
@@ -105,7 +110,7 @@ static void cs_activate(struct atmel_spi *as, struct spi_device *spi)
 
 	csr = (u32)spi->controller_data;
 
-	if (atmel_spi_is_v2()) {
+	if (atmel_spi_is_v2(as)) {
 		/*
 		 * Always use CSR0. This ensures that the clock
 		 * switches to the correct idle polarity before we
@@ -164,8 +169,9 @@ static void cs_deactivate(struct atmel_spi *as, struct spi_device *spi)
 			npcs_pin, active ? " (low)" : "",
 			mr);
 
-	if (atmel_spi_is_v2() || npcs_pin != AT91_PIN_PA3)
+	if (atmel_spi_is_v2(as) || npcs_pin != AT91_PIN_PA3) {
 		gpio_set_value(npcs_pin, !active);
+	}
 }
 
 static int atmel_spi_setup(struct spi_device *spi)
@@ -200,7 +206,7 @@ static int atmel_spi_setup(struct spi_device *spi)
 			spi->max_speed_hz);
 
 	bus_hz = clk_get_rate(as->clk);
-	if (!atmel_spi_is_v2())
+	if (!atmel_spi_is_v2(as))
 		bus_hz /= 2;
 
 	if (spi->max_speed_hz) {
@@ -249,7 +255,7 @@ static int atmel_spi_setup(struct spi_device *spi)
 
 	cs_deactivate(as, spi);
 
-	if (!atmel_spi_is_v2())
+	if (!atmel_spi_is_v2(as))
 		spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
 
 	return 0;
@@ -374,6 +380,21 @@ err:
 	return ret;
 }
 
+static inline unsigned int atmel_get_version(struct atmel_spi *as)
+{
+	return spi_readl(as, VERSION) & 0x00000fff;
+}
+
+static void atmel_get_caps(struct atmel_spi *as)
+{
+	unsigned int version;
+
+	version = atmel_get_version(as);
+	dev_info(as->master.dev, "version: 0x%x\n", version);
+
+	as->caps.is_spi2 = version > 0x121;
+}
+
 static int atmel_spi_probe(struct device_d *dev)
 {
 	struct resource *iores;
@@ -426,6 +447,8 @@ static int atmel_spi_probe(struct device_d *dev)
 		return PTR_ERR(iores);
 	as->regs = IOMEM(iores->start);
 
+	atmel_get_caps(as);
+
 	for (i = 0; i < master->num_chipselect; i++) {
 		ret = gpio_request(as->cs_pins[i], dev_name(dev));
 		if (ret)
diff --git a/drivers/spi/atmel_spi.h b/drivers/spi/atmel_spi.h
index 38ce119..3f4d7ba 100644
--- a/drivers/spi/atmel_spi.h
+++ b/drivers/spi/atmel_spi.h
@@ -23,6 +23,7 @@
 #define SPI_CSR1				0x0034
 #define SPI_CSR2				0x0038
 #define SPI_CSR3				0x003c
+#define SPI_VERSION				0x00fc
 #define SPI_RPR					0x0100
 #define SPI_RCR					0x0104
 #define SPI_TPR					0x0108
-- 
2.9.3


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

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

* [PATCH 29/45] at91sam9x5ek: Configure SPI in DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (27 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 28/45] spi: atmel_spi: Use VERSION register instead of CPU type Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 30/45] w1-gpio: Add DT support Andrey Smirnov
                   ` (17 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c | 36 ------------------------------------
 arch/arm/dts/at91sam9x5ek.dts       | 24 ++++++++++++++++++++++++
 2 files changed, 24 insertions(+), 36 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 8acb23c..2fe724c 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -168,41 +168,6 @@ static void ek_add_device_lcdc(void)
 static void ek_add_device_lcdc(void) {}
 #endif
 
-static const struct spi_board_info ek_cm_cogent_spi_devices[] = {
-	{
-		.name		= "mtd_dataflash",
-		.chip_select	= 0,
-		.max_speed_hz	= 15 * 1000 * 1000,
-		.bus_num	= 0,
-	}
-};
-
-static const struct spi_board_info ek_spi_devices[] = {
-	{
-		.name		= "m25p80",
-		.chip_select	= 0,
-		.max_speed_hz	= 30 * 1000 * 1000,
-		.bus_num	= 0,
-	}
-};
-
-static unsigned spi0_standard_cs[] = { AT91_PIN_PA14};
-static struct at91_spi_platform_data spi_pdata = {
-	.chipselect = spi0_standard_cs,
-	.num_chipselect = ARRAY_SIZE(spi0_standard_cs),
-};
-
-static void ek_add_device_spi(void)
-{
-	if (at91sam9x5ek_cm_is_vendor(VENDOR_COGENT))
-		spi_register_board_info(ek_cm_cogent_spi_devices,
-				ARRAY_SIZE(ek_cm_cogent_spi_devices));
-	else
-		spi_register_board_info(ek_spi_devices,
-				ARRAY_SIZE(ek_spi_devices));
-	at91_add_device_spi(0, &spi_pdata);
-}
-
 #if defined(CONFIG_USB_OHCI) || defined(CONFIG_USB_EHCI)
 /*
  * USB HS Host port (common to OHCI & EHCI)
@@ -235,7 +200,6 @@ static int at91sam9x5ek_devices_init(void)
 	ek_add_device_w1();
 	ek_add_device_nand();
 	ek_add_device_eth();
-	ek_add_device_spi();
 	ek_add_device_usb();
 	ek_add_device_lcdc();
 
diff --git a/arch/arm/dts/at91sam9x5ek.dts b/arch/arm/dts/at91sam9x5ek.dts
index 00bb86a..efdba61 100644
--- a/arch/arm/dts/at91sam9x5ek.dts
+++ b/arch/arm/dts/at91sam9x5ek.dts
@@ -17,8 +17,32 @@
 	i2c-gpio-0 {
 		status = "okay";
 	};
+
+	ahb {
+		apb {
+			pinctrl@fffff400 {
+				spi {
+					pinctrl_board_spi: spi-board {
+						atmel,pins = <AT91_PIOA 14 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+					};
+				};
+			};
+		};
+	};
+};
+
+&spi0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_spi0>, <&pinctrl_board_spi>;
 };
 
 &i2c0 {
 	status = "disabled";
 };
+
+/*
+ * This one conflicts with SPI NOR on the SoM
+ */
+&mmc1 {
+	status = "disabled";
+};
-- 
2.9.3


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

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

* [PATCH 30/45] w1-gpio: Add DT support
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (28 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 29/45] at91sam9x5ek: Configure SPI in DT Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 31/45] at91sam9x5ek: Configure 1-wire in DT Andrey Smirnov
                   ` (16 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/w1/masters/w1-gpio.c | 53 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/drivers/w1/masters/w1-gpio.c b/drivers/w1/masters/w1-gpio.c
index 946e9d3..916027e 100644
--- a/drivers/w1/masters/w1-gpio.c
+++ b/drivers/w1/masters/w1-gpio.c
@@ -16,6 +16,7 @@
 #include <driver.h>
 #include <linux/w1-gpio.h>
 #include <gpio.h>
+#include <of_gpio.h>
 
 #include "../w1.h"
 
@@ -43,12 +44,58 @@ static u8 w1_gpio_read_bit(struct w1_bus *bus)
 	return gpio_get_value(pdata->pin) ? 1 : 0;
 }
 
+static int w1_gpio_probe_dt(struct device_d *dev)
+{
+	struct w1_gpio_platform_data *pdata;
+	struct device_node *np = dev->device_node;
+	int gpio;
+
+	if (dev->platform_data)
+		return 0;
+
+	pdata = xzalloc(sizeof(*pdata));
+
+	if (of_get_property(np, "linux,open-drain", NULL))
+		pdata->is_open_drain = 1;
+
+	gpio = of_get_gpio(np, 0);
+	if (!gpio_is_valid(gpio)) {
+		if (gpio != -EPROBE_DEFER)
+			dev_err(dev,
+				"Failed to parse gpio property for data pin (%d)\n",
+				gpio);
+
+		goto free_pdata;
+	}
+	pdata->pin = gpio;
+
+	gpio = of_get_gpio(np, 1);
+	if (gpio == -EPROBE_DEFER)
+		goto free_pdata;
+
+	/* ignore other errors as the pullup gpio is optional */
+	pdata->ext_pullup_enable_pin = gpio;
+
+	dev->platform_data = pdata;
+	return 0;
+
+free_pdata:
+	free(pdata);
+	return gpio;
+}
+
 static int __init w1_gpio_probe(struct device_d *dev)
 {
 	struct w1_bus *master;
 	struct w1_gpio_platform_data *pdata;
 	int err;
 
+	if (IS_ENABLED(CONFIG_OFDEVICE)) {
+		err = w1_gpio_probe_dt(dev);
+		if (err < 0)
+			return err;
+	}
+
 	pdata = dev->platform_data;
 
 	if (!pdata)
@@ -104,8 +151,14 @@ static int __init w1_gpio_probe(struct device_d *dev)
 	return err;
 }
 
+static __maybe_unused const struct of_device_id w1_gpio_dt_ids[] = {
+	{ .compatible = "w1-gpio" },
+	{}
+};
+
 static struct driver_d w1_gpio_driver = {
 	.name	= "w1-gpio",
 	.probe	= w1_gpio_probe,
+	.of_compatible = DRV_OF_COMPAT(w1_gpio_dt_ids),
 };
 device_platform_driver(w1_gpio_driver);
-- 
2.9.3


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

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

* [PATCH 31/45] at91sam9x5ek: Configure 1-wire in DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (29 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 30/45] w1-gpio: Add DT support Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 32/45] usb: ohci-at91: Check result of clk_get() Andrey Smirnov
                   ` (15 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/hw_version.c |  6 +++++-
 arch/arm/boards/at91sam9x5ek/hw_version.h |  1 -
 arch/arm/boards/at91sam9x5ek/init.c       | 16 ----------------
 arch/arm/dts/at91sam9x5ek.dts             | 17 +++++++++++++++++
 4 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/hw_version.c b/arch/arm/boards/at91sam9x5ek/hw_version.c
index 2f84d82..d1ca036 100644
--- a/arch/arm/boards/at91sam9x5ek/hw_version.c
+++ b/arch/arm/boards/at91sam9x5ek/hw_version.c
@@ -15,6 +15,7 @@
  */
 
 #include <common.h>
+#include <init.h>
 #include <fs.h>
 #include <fcntl.h>
 #include <libbb.h>
@@ -250,7 +251,7 @@ static int cm_cogent_fixup(struct device_node *root, void *unused)
 	return 0;
 }
 
-void at91sam9x5ek_devices_detect_hw(void)
+static int at91sam9x5ek_devices_detect_hw(void)
 {
 	at91sam9x5ek_devices_detect_one("/dev/ds24310");
 	at91sam9x5ek_devices_detect_one("/dev/ds24311");
@@ -262,4 +263,7 @@ void at91sam9x5ek_devices_detect_hw(void)
 
 	if (at91sam9x5ek_cm_is_vendor(VENDOR_COGENT))
 		of_register_fixup(cm_cogent_fixup, NULL);
+
+	return 0;
 }
+late_initcall(at91sam9x5ek_devices_detect_hw);
diff --git a/arch/arm/boards/at91sam9x5ek/hw_version.h b/arch/arm/boards/at91sam9x5ek/hw_version.h
index 91fd429..3f3c800 100644
--- a/arch/arm/boards/at91sam9x5ek/hw_version.h
+++ b/arch/arm/boards/at91sam9x5ek/hw_version.h
@@ -29,6 +29,5 @@ enum vendor_id {
 bool at91sam9x5ek_cm_is_vendor(enum vendor_id vid);
 bool at91sam9x5ek_ek_is_vendor(enum vendor_id vid);
 bool at91sam9x5ek_dm_is_vendor(enum vendor_id vid);
-void at91sam9x5ek_devices_detect_hw(void);
 
 #endif /* __HW_REVISION_H__ */
diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 2fe724c..09b7d0f 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -45,12 +45,6 @@
 
 #include "hw_version.h"
 
-struct w1_gpio_platform_data w1_pdata = {
-	.pin = AT91_PIN_PB18,
-	.ext_pullup_enable_pin = -EINVAL,
-	.is_open_drain = 0,
-};
-
 static struct atmel_nand_data nand_pdata = {
 	.ale		= 21,
 	.cle		= 22,
@@ -186,18 +180,8 @@ static void ek_add_device_usb(void)
 static void ek_add_device_usb(void) {}
 #endif
 
-static void ek_add_device_w1(void)
-{
-	at91_set_gpio_input(w1_pdata.pin, 0);
-	at91_set_multi_drive(w1_pdata.pin, 1);
-	add_generic_device_res("w1-gpio", DEVICE_ID_SINGLE, NULL, 0, &w1_pdata);
-
-	at91sam9x5ek_devices_detect_hw();
-}
-
 static int at91sam9x5ek_devices_init(void)
 {
-	ek_add_device_w1();
 	ek_add_device_nand();
 	ek_add_device_eth();
 	ek_add_device_usb();
diff --git a/arch/arm/dts/at91sam9x5ek.dts b/arch/arm/dts/at91sam9x5ek.dts
index efdba61..fa79347 100644
--- a/arch/arm/dts/at91sam9x5ek.dts
+++ b/arch/arm/dts/at91sam9x5ek.dts
@@ -29,6 +29,23 @@
 			};
 		};
 	};
+
+	leds {
+		/*
+		 * PB18 has a resource conflict since it is both used
+                 * as a heartbeat LED and 1-wire bus in the kernel
+                 * device tree. Since 1-wire EEPROMs contains
+                 * importatnt revision information as a part of
+                 * Barebox DT stup we move heartbeat to PD21 and
+                 * remove the original pb18 node
+		 */
+
+		/delete-node/ pb18;
+
+		pd21 {
+			linux,default-trigger = "heartbeat";
+		};
+	};
 };
 
 &spi0 {
-- 
2.9.3


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

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

* [PATCH 32/45] usb: ohci-at91: Check result of clk_get()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (30 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 31/45] at91sam9x5ek: Configure 1-wire in DT Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-07 16:35   ` Sam Ravnborg
  2017-03-06 22:53 ` [PATCH 33/45] usb: ohci-at91: Convert global variables to private data Andrey Smirnov
                   ` (14 subsequent siblings)
  46 siblings, 1 reply; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ohci-at91.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 0f5c8f1..c70d898 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -47,7 +47,16 @@ static int at91_ohci_probe(struct device_d *dev)
 	struct ohci_regs __iomem *regs = (struct ohci_regs __iomem *)dev->resource[0].start;
 
 	iclk = clk_get(NULL, "ohci_clk");
+	if (IS_ERR(iclk)) {
+		dev_err(dev, "Failed to get 'iclk'\n");
+		return PTR_ERR(iclk);
+	}
+
 	fclk = clk_get(NULL, "uhpck");
+	if (IS_ERR(fclk)) {
+		dev_err(dev, "Failed to get 'fclk'\n");
+		return PTR_ERR(fclk);
+	}
 
 	/*
 	 * Start the USB clocks.
-- 
2.9.3


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

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

* [PATCH 33/45] usb: ohci-at91: Convert global variables to private data
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (31 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 32/45] usb: ohci-at91: Check result of clk_get() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 34/45] usb: ohci-at91: Check result of clk_enable() Andrey Smirnov
                   ` (13 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Store driver data in per-device private variable as opposed to storing
it in global vairables.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ohci-at91.c | 59 +++++++++++++++++++++++++++-----------------
 1 file changed, 37 insertions(+), 22 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index c70d898..57ca86a 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -27,66 +27,81 @@
 
 #include "ohci.h"
 
-/* interface and function clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk;
+struct ohci_at91_priv {
+	struct device_d *dev;
+	struct clk *iclk;
+	struct clk *fclk;
+	struct ohci_regs __iomem *regs;
+};
 
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
-	clk_enable(iclk);
-	clk_enable(fclk);
+	clk_enable(ohci_at91->iclk);
+	clk_enable(ohci_at91->fclk);
 }
 
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 {
-	clk_disable(fclk);
-	clk_disable(iclk);
+	clk_disable(ohci_at91->fclk);
+	clk_disable(ohci_at91->iclk);
 }
 
 static int at91_ohci_probe(struct device_d *dev)
 {
-	struct ohci_regs __iomem *regs = (struct ohci_regs __iomem *)dev->resource[0].start;
+	struct resource *io;
+	struct ohci_at91_priv *ohci_at91 = xzalloc(sizeof(*ohci_at91));
+
+	dev->priv = ohci_at91;
+	ohci_at91->dev = dev;
+
+	io = dev_get_resource(dev, IORESOURCE_MEM, 0);
+	if (IS_ERR(io)) {
+		dev_err(dev, "Failed to get IORESOURCE_MEM\n");
+		return PTR_ERR(io);
+	}
+	ohci_at91->regs = IOMEM(io->start);
 
-	iclk = clk_get(NULL, "ohci_clk");
-	if (IS_ERR(iclk)) {
+	ohci_at91->iclk = clk_get(NULL, "ohci_clk");
+	if (IS_ERR(ohci_at91->iclk)) {
 		dev_err(dev, "Failed to get 'iclk'\n");
-		return PTR_ERR(iclk);
+		return PTR_ERR(ohci_at91->iclk);
 	}
 
-	fclk = clk_get(NULL, "uhpck");
-	if (IS_ERR(fclk)) {
+	ohci_at91->fclk = clk_get(NULL, "uhpck");
+	if (IS_ERR(ohci_at91->fclk)) {
 		dev_err(dev, "Failed to get 'fclk'\n");
-		return PTR_ERR(fclk);
+		return PTR_ERR(ohci_at91->fclk);
 	}
 
 	/*
 	 * Start the USB clocks.
 	 */
-	at91_start_clock();
+	at91_start_clock(ohci_at91);
 
 	/*
 	 * The USB host controller must remain in reset.
 	 */
-	writel(0, &regs->control);
+	writel(0, &ohci_at91->regs->control);
 
-	add_generic_device("ohci", DEVICE_ID_DYNAMIC, NULL, dev->resource[0].start,
-			   resource_size(&dev->resource[0]), IORESOURCE_MEM, NULL);
+	add_generic_device("ohci", DEVICE_ID_DYNAMIC, NULL, io->start,
+			   resource_size(io), IORESOURCE_MEM, NULL);
 
 	return 0;
 }
 
 static void at91_ohci_remove(struct device_d *dev)
 {
-	struct ohci_regs __iomem *regs = (struct ohci_regs __iomem *)dev->resource[0].start;
+	struct ohci_at91_priv *ohci_at91 = dev->priv;
 
 	/*
 	 * Put the USB host controller into reset.
 	 */
-	writel(0, &regs->control);
+	writel(0, &ohci_at91->regs->control);
 
 	/*
 	 * Stop the USB clocks.
 	 */
-	at91_stop_clock();
+	at91_stop_clock(ohci_at91);
 }
 
 static struct driver_d at91_ohci_driver = {
-- 
2.9.3


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

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

* [PATCH 34/45] usb: ohci-at91: Check result of clk_enable()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (32 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 33/45] usb: ohci-at91: Convert global variables to private data Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 35/45] usb: ohci-at91: Add DT support Andrey Smirnov
                   ` (12 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ohci-at91.c | 24 ++++++++++++++++++++----
 1 file changed, 20 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 57ca86a..f413616 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -34,10 +34,23 @@ struct ohci_at91_priv {
 	struct ohci_regs __iomem *regs;
 };
 
-static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
+static int at91_start_clock(struct ohci_at91_priv *ohci_at91)
 {
-	clk_enable(ohci_at91->iclk);
-	clk_enable(ohci_at91->fclk);
+	int ret;
+
+	ret = clk_enable(ohci_at91->iclk);
+	if (ret < 0) {
+		dev_err(ohci_at91->dev, "Failed to enable 'iclk'\n");
+		return ret;
+	}
+
+	ret = clk_enable(ohci_at91->fclk);
+	if (ret < 0) {
+		dev_err(ohci_at91->dev, "Failed to enable 'fclk'\n");
+		return ret;
+	}
+
+	return 0;
 }
 
 static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
@@ -48,6 +61,7 @@ static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 
 static int at91_ohci_probe(struct device_d *dev)
 {
+	int ret;
 	struct resource *io;
 	struct ohci_at91_priv *ohci_at91 = xzalloc(sizeof(*ohci_at91));
 
@@ -76,7 +90,9 @@ static int at91_ohci_probe(struct device_d *dev)
 	/*
 	 * Start the USB clocks.
 	 */
-	at91_start_clock(ohci_at91);
+	ret = at91_start_clock(ohci_at91);
+	if (ret < 0)
+		return ret;
 
 	/*
 	 * The USB host controller must remain in reset.
-- 
2.9.3


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

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

* [PATCH 35/45] usb: ohci-at91: Add DT support
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (33 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 34/45] usb: ohci-at91: Check result of clk_enable() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-07 16:40   ` Sam Ravnborg
  2017-03-06 22:53 ` [PATCH 36/45] usb/host: Allow USB_OHCI_AT91 even if USB_OHCI is disabled Andrey Smirnov
                   ` (11 subsequent siblings)
  46 siblings, 1 reply; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/mach-at91/include/mach/board.h |  6 ++-
 drivers/usb/host/ohci-at91.c            | 84 ++++++++++++++++++++++++++++++++-
 2 files changed, 86 insertions(+), 4 deletions(-)

diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
index 491b220..5d76e00 100644
--- a/arch/arm/mach-at91/include/mach/board.h
+++ b/arch/arm/mach-at91/include/mach/board.h
@@ -32,11 +32,13 @@
 
 void at91_set_main_clock(unsigned long rate);
 
+#define AT91_MAX_USBH_PORTS	3
+
  /* USB Host */
 struct at91_usbh_data {
 	u8		ports;		/* number of ports on root hub */
-	int		vbus_pin[2];	/* port power-control pin */
-	u8	vbus_pin_active_low[2];	/* vbus polarity */
+	int		vbus_pin[AT91_MAX_USBH_PORTS];	/* port power-control pin */
+	u8	vbus_pin_active_low[AT91_MAX_USBH_PORTS];	/* vbus polarity */
 };
 extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
 extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data);
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index f413616..54fe45f 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -23,10 +23,18 @@
 #include <usb/usb.h>
 #include <usb/usb_defs.h>
 #include <errno.h>
+#include <gpio.h>
+#include <of_gpio.h>
 #include <io.h>
 
+#include <mach/board.h>
+
 #include "ohci.h"
 
+#define at91_for_each_port(index)					\
+	for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
+
+
 struct ohci_at91_priv {
 	struct device_d *dev;
 	struct clk *iclk;
@@ -59,6 +67,53 @@ static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
 	clk_disable(ohci_at91->iclk);
 }
 
+static void at91_ohci_probe_dt(struct device_d *dev)
+{
+	u32 ports;
+	int i, ret, gpio;
+	enum of_gpio_flags flags;
+	struct at91_usbh_data *pdata;
+	struct device_node *np = dev->device_node;
+
+	pdata = xzalloc(sizeof(*pdata));
+	dev->platform_data = pdata;
+
+	if (!of_property_read_u32(np, "num-ports", &ports))
+		pdata->ports = ports;
+
+	at91_for_each_port(i) {
+		/*
+		 * do not configure PIO if not in relation with
+		 * real USB port on board
+		 */
+		if (i >= pdata->ports) {
+			pdata->vbus_pin[i] = -EINVAL;
+			continue;
+		}
+
+		gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i,
+					       &flags);
+		pdata->vbus_pin[i] = gpio;
+		if (!gpio_is_valid(gpio))
+			continue;
+		pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW;
+
+		ret = gpio_request(gpio, "ohci_vbus");
+		if (ret) {
+			dev_err(dev, "can't request vbus gpio %d\n", gpio);
+			continue;
+		}
+		ret = gpio_direction_output(gpio,
+					    !pdata->vbus_pin_active_low[i]);
+		if (ret) {
+			dev_err(dev, "can't put vbus gpio %d as output %d\n",
+				gpio, !pdata->vbus_pin_active_low[i]);
+			gpio_free(gpio);
+			continue;
+		}
+	}
+}
+
 static int at91_ohci_probe(struct device_d *dev)
 {
 	int ret;
@@ -68,6 +123,9 @@ static int at91_ohci_probe(struct device_d *dev)
 	dev->priv = ohci_at91;
 	ohci_at91->dev = dev;
 
+	if (dev->device_node)
+		at91_ohci_probe_dt(dev);
+
 	io = dev_get_resource(dev, IORESOURCE_MEM, 0);
 	if (IS_ERR(io)) {
 		dev_err(dev, "Failed to get IORESOURCE_MEM\n");
@@ -75,13 +133,13 @@ static int at91_ohci_probe(struct device_d *dev)
 	}
 	ohci_at91->regs = IOMEM(io->start);
 
-	ohci_at91->iclk = clk_get(NULL, "ohci_clk");
+	ohci_at91->iclk = clk_get(dev, "ohci_clk");
 	if (IS_ERR(ohci_at91->iclk)) {
 		dev_err(dev, "Failed to get 'iclk'\n");
 		return PTR_ERR(ohci_at91->iclk);
 	}
 
-	ohci_at91->fclk = clk_get(NULL, "uhpck");
+	ohci_at91->fclk = clk_get(dev, "uhpck");
 	if (IS_ERR(ohci_at91->fclk)) {
 		dev_err(dev, "Failed to get 'fclk'\n");
 		return PTR_ERR(ohci_at91->fclk);
@@ -107,6 +165,7 @@ static int at91_ohci_probe(struct device_d *dev)
 
 static void at91_ohci_remove(struct device_d *dev)
 {
+	struct at91_usbh_data *pdata = dev->platform_data;
 	struct ohci_at91_priv *ohci_at91 = dev->priv;
 
 	/*
@@ -118,11 +177,32 @@ static void at91_ohci_remove(struct device_d *dev)
 	 * Stop the USB clocks.
 	 */
 	at91_stop_clock(ohci_at91);
+
+	if (pdata) {
+		bool active_low;
+		int  i, gpio;
+
+		at91_for_each_port(i) {
+			gpio = pdata->vbus_pin[i];
+			active_low = pdata->vbus_pin_active_low[i];
+
+			if (gpio_is_valid(gpio)) {
+				gpio_set_value(gpio, active_low);
+				gpio_free(gpio);
+			}
+		}
+	}
 }
 
+static const struct of_device_id at91_ohci_dt_ids[] = {
+	{ .compatible = "atmel,at91rm9200-ohci" },
+	{ /* sentinel */ }
+};
+
 static struct driver_d at91_ohci_driver = {
 	.name = "at91_ohci",
 	.probe = at91_ohci_probe,
 	.remove = at91_ohci_remove,
+	.of_compatible = DRV_OF_COMPAT(at91_ohci_dt_ids),
 };
 device_platform_driver(at91_ohci_driver);
-- 
2.9.3


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

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

* [PATCH 36/45] usb/host: Allow USB_OHCI_AT91 even if USB_OHCI is disabled
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (34 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 35/45] usb: ohci-at91: Add DT support Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 37/45] usb: ehci-atmel: Check result of clk_enable() Andrey Smirnov
                   ` (10 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

When probing devices from DT, AT91 SoCs rely on OHCI driver to setup
various GPIO (e.g. VBUS enabled) for EHCI block as well. So enable
USB_OHCI_AT91 to be selected even if USB_OHCI is unavailible (due to its
dependency on !MMU).

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/Kconfig | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 54eaf46..db44052 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -10,20 +10,17 @@ config USB_EHCI_OMAP
 config USB_EHCI_ATMEL
 	depends on ARCH_AT91
 	depends on USB_EHCI
+	select USB_OHCI_AT91
 	bool "Atmel EHCI driver"
 
 config USB_OHCI
 	bool "OHCI driver"
 	depends on !MMU
 
-if USB_OHCI
-
 config USB_OHCI_AT91
 	depends on ARCH_AT91
 	bool "AT91 OHCI driver"
 
-endif
-
 config USB_XHCI
 	bool "xHCI driver"
 	depends on HAS_DMA
-- 
2.9.3


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

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

* [PATCH 37/45] usb: ehci-atmel: Check result of clk_enable()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (35 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 36/45] usb/host: Allow USB_OHCI_AT91 even if USB_OHCI is disabled Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 38/45] usb: echi-atmel: Convert global variables to private data Andrey Smirnov
                   ` (9 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ehci-atmel.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index cc9636c..fa9ca7d 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -32,10 +32,20 @@
 /* interface and function clocks; sometimes also an AHB clock */
 static struct clk *iclk, *fclk;
 
-static void atmel_start_clock(void)
+static int atmel_start_clock(void)
 {
-	clk_enable(iclk);
-	clk_enable(fclk);
+	int ret;
+	ret = clk_enable(iclk);
+	if (ret < 0) {
+		pr_err("Error enabling interface clock\n");
+		return ret;
+	}
+
+	ret = clk_enable(fclk);
+	if (ret < 0)
+		pr_err("Error enabling function clock\n");
+
+	return ret;
 }
 
 static void atmel_stop_clock(void)
@@ -46,6 +56,7 @@ static void atmel_stop_clock(void)
 
 static int atmel_ehci_probe(struct device_d *dev)
 {
+	int ret;
 	struct resource *iores;
 	struct ehci_data data;
 
@@ -64,7 +75,9 @@ static int atmel_ehci_probe(struct device_d *dev)
 	/*
 	 * Start the USB clocks.
 	 */
-	atmel_start_clock();
+	ret = atmel_start_clock();
+	if (ret < 0)
+		return ret;
 
 	data.flags = 0;
 
-- 
2.9.3


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

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

* [PATCH 38/45] usb: echi-atmel: Convert global variables to private data
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (36 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 37/45] usb: ehci-atmel: Check result of clk_enable() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 39/45] usb: ehci-atmel: Zero ehci_data before using it Andrey Smirnov
                   ` (8 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ehci-atmel.c | 42 ++++++++++++++++++++++++++----------------
 1 file changed, 26 insertions(+), 16 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index fa9ca7d..7a9d942 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -29,29 +29,34 @@
 
 #include "ehci.h"
 
-/* interface and function clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk;
+struct atmel_ehci_priv {
+	struct device_d *dev;
+	struct clk *iclk;
+	struct clk *uclk;
+};
 
-static int atmel_start_clock(void)
+static int atmel_start_clock(struct atmel_ehci_priv *atehci)
 {
 	int ret;
-	ret = clk_enable(iclk);
+	ret = clk_enable(atehci->iclk);
 	if (ret < 0) {
-		pr_err("Error enabling interface clock\n");
+		dev_err(atehci->dev,
+			"Error enabling interface clock\n");
 		return ret;
 	}
 
-	ret = clk_enable(fclk);
+	ret = clk_enable(atehci->uclk);
 	if (ret < 0)
-		pr_err("Error enabling function clock\n");
+		dev_err(atehci->dev,
+			"Error enabling function clock\n");
 
 	return ret;
 }
 
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atehci)
 {
-	clk_disable(fclk);
-	clk_disable(iclk);
+	clk_disable(atehci->iclk);
+	clk_disable(atehci->uclk);
 }
 
 static int atmel_ehci_probe(struct device_d *dev)
@@ -59,15 +64,20 @@ static int atmel_ehci_probe(struct device_d *dev)
 	int ret;
 	struct resource *iores;
 	struct ehci_data data;
+	struct atmel_ehci_priv *atehci;
+
+	atehci = xzalloc(sizeof(*atehci));
+	atehci->dev = dev;
+	dev->priv = atehci;
 
-	iclk = clk_get(dev, "ehci_clk");
-	if (IS_ERR(iclk)) {
+	atehci->iclk = clk_get(dev, "ehci_clk");
+	if (IS_ERR(atehci->iclk)) {
 		dev_err(dev, "Error getting interface clock\n");
 		return -ENOENT;
 	}
 
-	fclk = clk_get(dev, "uhpck");
-	if (IS_ERR(fclk)) {
+	atehci->uclk = clk_get(dev, "uhpck");
+	if (IS_ERR(atehci->iclk)) {
 		dev_err(dev, "Error getting function clock\n");
 		return -ENOENT;
 	}
@@ -75,7 +85,7 @@ static int atmel_ehci_probe(struct device_d *dev)
 	/*
 	 * Start the USB clocks.
 	 */
-	ret = atmel_start_clock();
+	ret = atmel_start_clock(atehci);
 	if (ret < 0)
 		return ret;
 
@@ -96,7 +106,7 @@ static void atmel_ehci_remove(struct device_d *dev)
 	/*
 	 * Stop the USB clocks.
 	 */
-	atmel_stop_clock();
+	atmel_stop_clock(dev->priv);
 }
 
 static struct driver_d atmel_ehci_driver = {
-- 
2.9.3


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

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

* [PATCH 39/45] usb: ehci-atmel: Zero ehci_data before using it
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (37 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 38/45] usb: echi-atmel: Convert global variables to private data Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 40/45] usb: echi-atmel: Check result of ehci_register() Andrey Smirnov
                   ` (7 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Zero ehci_data before using it as an argument for echi_register,
otherwise bogus values (some of which are interpreted as callbacks) will
be passed through, resulting in illegal memory accesses.

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ehci-atmel.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 7a9d942..4b9fc0a 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -89,7 +89,7 @@ static int atmel_ehci_probe(struct device_d *dev)
 	if (ret < 0)
 		return ret;
 
-	data.flags = 0;
+	memset(&data, 0, sizeof(data));
 
 	iores = dev_request_mem_resource(dev, 0);
 	if (IS_ERR(iores))
-- 
2.9.3


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

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

* [PATCH 40/45] usb: echi-atmel: Check result of ehci_register()
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (38 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 39/45] usb: ehci-atmel: Zero ehci_data before using it Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 41/45] usb: echi-atmel: Add DT support Andrey Smirnov
                   ` (6 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ehci-atmel.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 4b9fc0a..f075b50 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -96,9 +96,7 @@ static int atmel_ehci_probe(struct device_d *dev)
 		return PTR_ERR(iores);
 	data.hccr = IOMEM(iores->start);
 
-	ehci_register(dev, &data);
-
-	return 0;
+	return ehci_register(dev, &data);
 }
 
 static void atmel_ehci_remove(struct device_d *dev)
-- 
2.9.3


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

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

* [PATCH 41/45] usb: echi-atmel: Add DT support
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (39 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 40/45] usb: echi-atmel: Check result of ehci_register() Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 42/45] at91sam9x5ek: Configure USB in DT Andrey Smirnov
                   ` (5 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/usb/host/ehci-atmel.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index f075b50..1132879 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -65,6 +65,9 @@ static int atmel_ehci_probe(struct device_d *dev)
 	struct resource *iores;
 	struct ehci_data data;
 	struct atmel_ehci_priv *atehci;
+	const char *uclk_name;
+
+	uclk_name = (dev->device_node) ? "usb_clk" : "uhpck";
 
 	atehci = xzalloc(sizeof(*atehci));
 	atehci->dev = dev;
@@ -76,7 +79,7 @@ static int atmel_ehci_probe(struct device_d *dev)
 		return -ENOENT;
 	}
 
-	atehci->uclk = clk_get(dev, "uhpck");
+	atehci->uclk = clk_get(dev, uclk_name);
 	if (IS_ERR(atehci->iclk)) {
 		dev_err(dev, "Error getting function clock\n");
 		return -ENOENT;
@@ -107,9 +110,15 @@ static void atmel_ehci_remove(struct device_d *dev)
 	atmel_stop_clock(dev->priv);
 }
 
+static const struct of_device_id atmel_ehci_dt_ids[] = {
+	{ .compatible = "atmel,at91sam9g45-ehci" },
+	{ /* sentinel */ }
+};
+
 static struct driver_d atmel_ehci_driver = {
 	.name = "atmel-ehci",
 	.probe = atmel_ehci_probe,
 	.remove = atmel_ehci_remove,
+	.of_compatible = DRV_OF_COMPAT(atmel_ehci_dt_ids),
 };
 device_platform_driver(atmel_ehci_driver);
-- 
2.9.3


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

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

* [PATCH 42/45] at91sam9x5ek: Configure USB in DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (40 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 41/45] usb: echi-atmel: Add DT support Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 43/45] net: macb: Add DT support Andrey Smirnov
                   ` (4 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c | 19 -------------------
 1 file changed, 19 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 09b7d0f..ff0ef22 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -162,29 +162,10 @@ static void ek_add_device_lcdc(void)
 static void ek_add_device_lcdc(void) {}
 #endif
 
-#if defined(CONFIG_USB_OHCI) || defined(CONFIG_USB_EHCI)
-/*
- * USB HS Host port (common to OHCI & EHCI)
- */
-static struct at91_usbh_data ek_usbh_hs_data = {
-	.ports			= 2,
-	.vbus_pin		= {AT91_PIN_PD19, AT91_PIN_PD20},
-};
-
-static void ek_add_device_usb(void)
-{
-	at91_add_device_usbh_ohci(&ek_usbh_hs_data);
-	at91_add_device_usbh_ehci(&ek_usbh_hs_data);
-}
-#else
-static void ek_add_device_usb(void) {}
-#endif
-
 static int at91sam9x5ek_devices_init(void)
 {
 	ek_add_device_nand();
 	ek_add_device_eth();
-	ek_add_device_usb();
 	ek_add_device_lcdc();
 
 	armlinux_set_architecture(CONFIG_MACH_AT91SAM9X5EK);
-- 
2.9.3


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

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

* [PATCH 43/45] net: macb: Add DT support
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (41 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 42/45] at91sam9x5ek: Configure USB in DT Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 44/45] at91sam9x5ek: Configure Ethernet in DT Andrey Smirnov
                   ` (3 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 drivers/net/macb.c | 56 ++++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 42 insertions(+), 14 deletions(-)

diff --git a/drivers/net/macb.c b/drivers/net/macb.c
index 5f2e5e5..36e49c3 100644
--- a/drivers/net/macb.c
+++ b/drivers/net/macb.c
@@ -48,6 +48,7 @@
 #include <linux/clk.h>
 #include <linux/err.h>
 #include <linux/phy.h>
+#include <of_net.h>
 
 #include "macb.h"
 
@@ -615,14 +616,8 @@ static int macb_probe(struct device_d *dev)
 	struct resource *iores;
 	struct eth_device *edev;
 	struct macb_device *macb;
+	const char *pclk_name;
 	u32 ncfgr;
-	struct macb_platform_data *pdata;
-
-	if (!dev->platform_data) {
-		dev_err(dev, "macb: no platform_data\n");
-		return -ENODEV;
-	}
-	pdata = dev->platform_data;
 
 	edev = xzalloc(sizeof(struct eth_device) + sizeof(struct macb_device));
 	edev->priv = (struct macb_device *)(edev + 1);
@@ -633,22 +628,49 @@ static int macb_probe(struct device_d *dev)
 	edev->open = macb_open;
 	edev->send = macb_send;
 	edev->halt = macb_halt;
-	edev->get_ethaddr = pdata->get_ethaddr ? pdata->get_ethaddr : macb_get_ethaddr;
+	edev->get_ethaddr = macb_get_ethaddr;
 	edev->set_ethaddr = macb_set_ethaddr;
 	edev->parent = dev;
 
 	macb->miibus.read = macb_phy_read;
 	macb->miibus.write = macb_phy_write;
-	macb->phy_addr = pdata->phy_addr;
 	macb->miibus.priv = macb;
 	macb->miibus.parent = dev;
 
-	if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
-		macb->interface = PHY_INTERFACE_MODE_MII;
-	else
-		macb->interface = pdata->phy_interface;
+	if (dev->platform_data) {
+		struct macb_platform_data *pdata = dev->platform_data;
+
+		if (pdata->phy_interface == PHY_INTERFACE_MODE_NA)
+			macb->interface = PHY_INTERFACE_MODE_MII;
+		else
+			macb->interface = pdata->phy_interface;
+
+		if (pdata->get_ethaddr)
+			edev->get_ethaddr = pdata->get_ethaddr;
+
+		macb->phy_addr = pdata->phy_addr;
+		macb->phy_flags = pdata->phy_flags;
+		pclk_name = "macb_clk";
+	} else if (dev->device_node) {
+		int ret;
+		struct device_node *mdiobus;
 
-	macb->phy_flags = pdata->phy_flags;
+		ret = of_get_phy_mode(dev->device_node);
+		if (ret < 0)
+			macb->interface = PHY_INTERFACE_MODE_MII;
+		else
+			macb->interface = ret;
+
+		mdiobus = of_get_child_by_name(dev->device_node, "mdio");
+		if (mdiobus)
+			macb->miibus.dev.device_node = mdiobus;
+
+		macb->phy_addr = -1;
+		pclk_name = NULL;
+	} else {
+		dev_err(dev, "macb: no platform_data\n");
+		return -ENODEV;
+	}
 
 	iores = dev_request_mem_resource(dev, 0);
 	if (IS_ERR(iores))
@@ -698,8 +720,14 @@ static int macb_probe(struct device_d *dev)
 	return 0;
 }
 
+static const struct of_device_id macb_dt_ids[] = {
+	{ .compatible = "cdns,at91sam9260-macb",},
+	{ /* sentinel */ }
+};
+
 static struct driver_d macb_driver = {
 	.name  = "macb",
 	.probe = macb_probe,
+	.of_compatible = DRV_OF_COMPAT(macb_dt_ids),
 };
 device_platform_driver(macb_driver);
-- 
2.9.3


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

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

* [PATCH 44/45] at91sam9x5ek: Configure Ethernet in DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (42 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 43/45] net: macb: Add DT support Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-06 22:53 ` [PATCH 45/45] at91sam9x5ek: Configure NAND " Andrey Smirnov
                   ` (2 subsequent siblings)
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c | 18 ++++++++----------
 arch/arm/dts/at91sam9x5ek.dts       |  7 +++++++
 2 files changed, 15 insertions(+), 10 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index ff0ef22..29da97d 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -106,18 +106,17 @@ static void ek_add_device_nand(void)
 	at91_add_device_nand(&nand_pdata);
 }
 
-static struct macb_platform_data macb_pdata = {
-	.phy_interface = PHY_INTERFACE_MODE_RMII,
-	.phy_addr = 0,
-};
-
-static void ek_add_device_eth(void)
+static int ek_register_mac_address(void)
 {
-	if (w1_local_mac_address_register(0, "tml", "w1-2d-0"))
-		w1_local_mac_address_register(0, "tml", "w1-23-0");
+	int ret;
+
+	ret = w1_local_mac_address_register(0, "tml", "w1-2d-0");
+	if (!ret)
+		return ret;
 
-	at91_add_device_eth(0, &macb_pdata);
+	return w1_local_mac_address_register(0, "tml", "w1-23-0");
 }
+late_initcall(ek_register_mac_address);
 
 #if defined(CONFIG_DRIVER_VIDEO_ATMEL_HLCD)
 /*
@@ -165,7 +164,6 @@ static void ek_add_device_lcdc(void) {}
 static int at91sam9x5ek_devices_init(void)
 {
 	ek_add_device_nand();
-	ek_add_device_eth();
 	ek_add_device_lcdc();
 
 	armlinux_set_architecture(CONFIG_MACH_AT91SAM9X5EK);
diff --git a/arch/arm/dts/at91sam9x5ek.dts b/arch/arm/dts/at91sam9x5ek.dts
index fa79347..f9e8a94 100644
--- a/arch/arm/dts/at91sam9x5ek.dts
+++ b/arch/arm/dts/at91sam9x5ek.dts
@@ -4,6 +4,7 @@
 #include <dt-bindings/pinctrl/at91.h>
 
 #include <arm/at91sam9x5.dtsi>
+#include <arm/at91sam9x5_macb0.dtsi>
 #include <arm/at91sam9x5_lcd.dtsi>
 #include <arm/at91sam9x5dm.dtsi>
 #include <arm/at91sam9x5ek.dtsi>
@@ -63,3 +64,9 @@
 &mmc1 {
 	status = "disabled";
 };
+
+&macb0 {
+	status = "okay";
+	phy-mode = "rmii";
+};
+
-- 
2.9.3


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

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

* [PATCH 45/45] at91sam9x5ek: Configure NAND in DT
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (43 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 44/45] at91sam9x5ek: Configure Ethernet in DT Andrey Smirnov
@ 2017-03-06 22:53 ` Andrey Smirnov
  2017-03-07  8:13 ` [PATCH 00/45] AT91, at91sam9x5ek updates Sascha Hauer
  2017-03-07 16:34 ` Sam Ravnborg
  46 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-06 22:53 UTC (permalink / raw)
  To: barebox; +Cc: Andrey Smirnov

Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
---
 arch/arm/boards/at91sam9x5ek/init.c | 47 +++++++++++++------------------------
 1 file changed, 16 insertions(+), 31 deletions(-)

diff --git a/arch/arm/boards/at91sam9x5ek/init.c b/arch/arm/boards/at91sam9x5ek/init.c
index 29da97d..646cff5 100644
--- a/arch/arm/boards/at91sam9x5ek/init.c
+++ b/arch/arm/boards/at91sam9x5ek/init.c
@@ -45,22 +45,6 @@
 
 #include "hw_version.h"
 
-static struct atmel_nand_data nand_pdata = {
-	.ale		= 21,
-	.cle		= 22,
-	.det_pin	= -EINVAL,
-	.rdy_pin	= AT91_PIN_PD5,
-	.enable_pin	= AT91_PIN_PD4,
-	.has_pmecc	= 1,
-	.ecc_mode	= NAND_ECC_HW,
-	.pmecc_sector_size = 512,
-	.pmecc_corr_cap = 2,
-#if defined(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16)
-	.bus_width_16	= 1,
-#endif
-	.on_flash_bbt	= 1,
-};
-
 static struct sam9_smc_config cm_nand_smc_config = {
 	.ncs_read_setup		= 0,
 	.nrd_setup		= 1,
@@ -79,15 +63,27 @@ static struct sam9_smc_config cm_nand_smc_config = {
 	.tdf_cycles		= 1,
 };
 
-static void ek_add_device_nand(void)
+static int ek_add_device_smc(void)
 {
+	unsigned long csa;
+	csa = at91_sys_read(AT91_MATRIX_EBICSA);
+
+	/* Enable CS3 */
+	csa |= AT91_MATRIX_EBI_CS3A_SMC_NANDFLASH;
+	/* NAND flash on D16 */
+	csa |= AT91_MATRIX_NFD0_ON_D16;
+
+	/* Configure IO drive */
+	csa &= ~AT91_MATRIX_EBI_EBI_IOSR_NORMAL;
+	at91_sys_write(AT91_MATRIX_EBICSA, csa);
+
 	add_generic_device("at91sam9-smc",
 			   DEVICE_ID_SINGLE, NULL,
 			   AT91SAM9X5_BASE_SMC, 0x200,
 			   IORESOURCE_MEM, NULL);
 
 	/* setup bus-width (8 or 16) */
-	if (nand_pdata.bus_width_16)
+	if (IS_ENABLED(CONFIG_MTD_NAND_ATMEL_BUSWIDTH_16))
 		cm_nand_smc_config.mode |= AT91_SMC_DBW_16;
 	else
 		cm_nand_smc_config.mode |= AT91_SMC_DBW_8;
@@ -96,15 +92,14 @@ static void ek_add_device_nand(void)
 	sam9_smc_configure(0, 3, &cm_nand_smc_config);
 
 	if (at91sam9x5ek_cm_is_vendor(VENDOR_COGENT)) {
-		unsigned long csa;
-
 		csa = at91_sys_read(AT91_MATRIX_EBICSA);
 		csa |= AT91_MATRIX_EBI_VDDIOMSEL_1_8V;
 		at91_sys_write(AT91_MATRIX_EBICSA, csa);
 	}
 
-	at91_add_device_nand(&nand_pdata);
+	return 0;
 }
+fs_initcall(ek_add_device_smc);
 
 static int ek_register_mac_address(void)
 {
@@ -163,20 +158,10 @@ static void ek_add_device_lcdc(void) {}
 
 static int at91sam9x5ek_devices_init(void)
 {
-	ek_add_device_nand();
 	ek_add_device_lcdc();
 
 	armlinux_set_architecture(CONFIG_MACH_AT91SAM9X5EK);
 
-	devfs_add_partition("nand0", 0x00000, SZ_256K, DEVFS_PARTITION_FIXED, "at91bootstrap_raw");
-	dev_add_bb_dev("at91bootstrap_raw", "at91bootstrap");
-	devfs_add_partition("nand0", SZ_256K, SZ_256K + SZ_128K, DEVFS_PARTITION_FIXED, "self_raw");
-	dev_add_bb_dev("self_raw", "self0");
-	devfs_add_partition("nand0", SZ_512K + SZ_128K, SZ_128K, DEVFS_PARTITION_FIXED, "env_raw");
-	dev_add_bb_dev("env_raw", "env0");
-	devfs_add_partition("nand0", SZ_512K + SZ_256K, SZ_128K, DEVFS_PARTITION_FIXED, "env_raw1");
-	dev_add_bb_dev("env_raw1", "env1");
-
 	if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT_GENERIC))
 		defaultenv_append_directory(defaultenv_at91sam9x5ek);
 
-- 
2.9.3


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

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

* Re: [PATCH 07/45] serial: atmel: Check result of clk_get()
  2017-03-06 22:53 ` [PATCH 07/45] serial: atmel: Check result of clk_get() Andrey Smirnov
@ 2017-03-07  7:46   ` Sascha Hauer
  0 siblings, 0 replies; 58+ messages in thread
From: Sascha Hauer @ 2017-03-07  7:46 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Mon, Mar 06, 2017 at 02:53:18PM -0800, Andrey Smirnov wrote:
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  drivers/serial/atmel.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/drivers/serial/atmel.c b/drivers/serial/atmel.c
> index 4e4624e..d47b926 100644
> --- a/drivers/serial/atmel.c
> +++ b/drivers/serial/atmel.c
> @@ -403,6 +403,11 @@ static int atmel_serial_init_port(struct console_device *cdev)
>  		return -ENOENT;
>  
>  	uart->clk = clk_get(dev, "usart");
> +	if (IS_ERR(uart->clk)) {
> +		dev_err(dev, "Faield to get 'usart' clock\n");

s/Faield/Failed/

Sascha

> +		return PTR_ERR(uart->clk);
> +	}
> +
>  	clk_enable(uart->clk);
>  	uart->uartclk = clk_get_rate(uart->clk);
>  
> -- 
> 2.9.3
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox
> 

-- 
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] 58+ messages in thread

* Re: [PATCH 00/45] AT91, at91sam9x5ek updates
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (44 preceding siblings ...)
  2017-03-06 22:53 ` [PATCH 45/45] at91sam9x5ek: Configure NAND " Andrey Smirnov
@ 2017-03-07  8:13 ` Sascha Hauer
  2017-03-07 21:09   ` Andrey Smirnov
  2017-03-07 16:34 ` Sam Ravnborg
  46 siblings, 1 reply; 58+ messages in thread
From: Sascha Hauer @ 2017-03-07  8:13 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

Hi Andrey,

On Mon, Mar 06, 2017 at 02:53:11PM -0800, Andrey Smirnov wrote:
> Hi everyone,
> 
> I recently had a chance to work with at91sam9x5ek board and as a part
> of that effort I converted the code to support features found in
> Barebox for i.MX based SoCs. Most notably this patchset converts
> at91sam9x5ek to use multi-image PBL build process as well as adds
> support for board initialization from attached devicetree blob.
> 
> Sascha, at least for now, all of the patches, in chronological order,
> are included in this submission. However if this proves to be too
> burdensome to review, I'd be more than happy to split it into several
> individual submissions. One such division could be:
> 
> 	   - Generic bug fixes/infrastructure enhancements
> 	   - Peripheral drivers updates
> 	   - at91sam9x5ek specific changes
> 
> Please let me know if that is preferrable.

I had a short look at all patches, overall they look good. Nevertheless
it would be good to sort them like you suggested. It just makes it
easier to apply.

Thanks for working on this, a general AT91 overhaul was long overdue. I
hope this series prepares a path to cleanup the other AT91 SoCs aswell.

The clock support you ported over from the kernel is for all AT91 SoCs
and not only one, right?

Sascha

-- 
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] 58+ messages in thread

* Re: [PATCH 00/45] AT91, at91sam9x5ek updates
  2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
                   ` (45 preceding siblings ...)
  2017-03-07  8:13 ` [PATCH 00/45] AT91, at91sam9x5ek updates Sascha Hauer
@ 2017-03-07 16:34 ` Sam Ravnborg
  2017-03-07 16:56   ` Jean-Christophe PLAGNIOL-VILLARD
  46 siblings, 1 reply; 58+ messages in thread
From: Sam Ravnborg @ 2017-03-07 16:34 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

Hi Andrey.

On Mon, Mar 06, 2017 at 02:53:11PM -0800, Andrey Smirnov wrote:
> Hi everyone,
> 
> I recently had a chance to work with at91sam9x5ek board and as a part
> of that effort I converted the code to support features found in
> Barebox for i.MX based SoCs. Most notably this patchset converts
> at91sam9x5ek to use multi-image PBL build process as well as adds
> support for board initialization from attached devicetree blob.

Impressive series - looks good! And timing was good.

I have a proprietary at91sam9263 based bord that is familiar
with the 9263 evaluation kit.
The current bootloader is latest bootstrap + an ancient U-Boot.
As we have another board (i.MX6 based) there is some synergy into
using the same bootloader on both boards.

Can you give any hints on what needs to be done on top of
your patch-set to support the 9263 evalutation kit?

When booting from an SD-Card/NOR-Flash/USB would I then need
to use at91bootstrap, or can I use only barebox?

If I move forward with this and I can find an 9263
evaluation kit I would then also update this.

	Sam

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

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

* Re: [PATCH 32/45] usb: ohci-at91: Check result of clk_get()
  2017-03-06 22:53 ` [PATCH 32/45] usb: ohci-at91: Check result of clk_get() Andrey Smirnov
@ 2017-03-07 16:35   ` Sam Ravnborg
  2017-03-07 21:21     ` Andrey Smirnov
  0 siblings, 1 reply; 58+ messages in thread
From: Sam Ravnborg @ 2017-03-07 16:35 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Mon, Mar 06, 2017 at 02:53:43PM -0800, Andrey Smirnov wrote:
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  drivers/usb/host/ohci-at91.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
> 
> diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
> index 0f5c8f1..c70d898 100644
> --- a/drivers/usb/host/ohci-at91.c
> +++ b/drivers/usb/host/ohci-at91.c
> @@ -47,7 +47,16 @@ static int at91_ohci_probe(struct device_d *dev)
>  	struct ohci_regs __iomem *regs = (struct ohci_regs __iomem *)dev->resource[0].start;
>  
>  	iclk = clk_get(NULL, "ohci_clk");
> +	if (IS_ERR(iclk)) {
> +		dev_err(dev, "Failed to get 'iclk'\n");
iclk is the internal name. Woudl it make more sense to use "ohci_clk" here?

> +		return PTR_ERR(iclk);
> +	}
> +
>  	fclk = clk_get(NULL, "uhpck");
> +	if (IS_ERR(fclk)) {
> +		dev_err(dev, "Failed to get 'fclk'\n");
Likewise - uhpck?


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

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

* Re: [PATCH 35/45] usb: ohci-at91: Add DT support
  2017-03-06 22:53 ` [PATCH 35/45] usb: ohci-at91: Add DT support Andrey Smirnov
@ 2017-03-07 16:40   ` Sam Ravnborg
  0 siblings, 0 replies; 58+ messages in thread
From: Sam Ravnborg @ 2017-03-07 16:40 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Mon, Mar 06, 2017 at 02:53:46PM -0800, Andrey Smirnov wrote:
> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> ---
>  arch/arm/mach-at91/include/mach/board.h |  6 ++-
>  drivers/usb/host/ohci-at91.c            | 84 ++++++++++++++++++++++++++++++++-
>  2 files changed, 86 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/mach-at91/include/mach/board.h b/arch/arm/mach-at91/include/mach/board.h
> index 491b220..5d76e00 100644
> --- a/arch/arm/mach-at91/include/mach/board.h
> +++ b/arch/arm/mach-at91/include/mach/board.h
> @@ -32,11 +32,13 @@
>  
>  void at91_set_main_clock(unsigned long rate);
>  
> +#define AT91_MAX_USBH_PORTS	3
> +
>   /* USB Host */
>  struct at91_usbh_data {
>  	u8		ports;		/* number of ports on root hub */
> -	int		vbus_pin[2];	/* port power-control pin */
> -	u8	vbus_pin_active_low[2];	/* vbus polarity */
> +	int		vbus_pin[AT91_MAX_USBH_PORTS];	/* port power-control pin */
> +	u8	vbus_pin_active_low[AT91_MAX_USBH_PORTS];	/* vbus polarity */
>  };
>  extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
>  extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data);
> diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
> index f413616..54fe45f 100644
> --- a/drivers/usb/host/ohci-at91.c
> +++ b/drivers/usb/host/ohci-at91.c
> @@ -23,10 +23,18 @@
>  #include <usb/usb.h>
>  #include <usb/usb_defs.h>
>  #include <errno.h>
> +#include <gpio.h>
> +#include <of_gpio.h>
>  #include <io.h>
>  
> +#include <mach/board.h>
> +
>  #include "ohci.h"
>  
> +#define at91_for_each_port(index)					\
> +	for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
> +
> +
>  struct ohci_at91_priv {
>  	struct device_d *dev;
>  	struct clk *iclk;
> @@ -59,6 +67,53 @@ static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
>  	clk_disable(ohci_at91->iclk);
>  }
>  
> +static void at91_ohci_probe_dt(struct device_d *dev)
> +{
> +	u32 ports;
> +	int i, ret, gpio;
> +	enum of_gpio_flags flags;
> +	struct at91_usbh_data *pdata;
> +	struct device_node *np = dev->device_node;
> +
> +	pdata = xzalloc(sizeof(*pdata));
> +	dev->platform_data = pdata;
> +
> +	if (!of_property_read_u32(np, "num-ports", &ports))
> +		pdata->ports = ports;
If we fail to read "num-ports" then we will fail in the following when dereferencing pdata->ports
> +
> +	at91_for_each_port(i) {
> +		/*
> +		 * do not configure PIO if not in relation with
> +		 * real USB port on board
> +		 */
> +		if (i >= pdata->ports) {
                         ^ here

> +			pdata->vbus_pin[i] = -EINVAL;
> +			continue;
> +		}

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

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

* Re: [PATCH 00/45] AT91, at91sam9x5ek updates
  2017-03-07 16:34 ` Sam Ravnborg
@ 2017-03-07 16:56   ` Jean-Christophe PLAGNIOL-VILLARD
  2017-03-07 20:58     ` Sam Ravnborg
  0 siblings, 1 reply; 58+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2017-03-07 16:56 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: Andrey Smirnov, barebox


> On Mar 8, 2017, at 12:34 AM, Sam Ravnborg <sam@ravnborg.org> wrote:
> 
> Hi Andrey.
> 
> On Mon, Mar 06, 2017 at 02:53:11PM -0800, Andrey Smirnov wrote:
>> Hi everyone,
>> 
>> I recently had a chance to work with at91sam9x5ek board and as a part
>> of that effort I converted the code to support features found in
>> Barebox for i.MX based SoCs. Most notably this patchset converts
>> at91sam9x5ek to use multi-image PBL build process as well as adds
>> support for board initialization from attached devicetree blob.
> 
> Impressive series - looks good! And timing was good.
> 
> I have a proprietary at91sam9263 based bord that is familiar
> with the 9263 evaluation kit.
> The current bootloader is latest bootstrap + an ancient U-Boot.
> As we have another board (i.MX6 based) there is some synergy into
> using the same bootloader on both boards.
> 
> Can you give any hints on what needs to be done on top of
> your patch-set to support the 9263 evalutation kit?
> 
> When booting from an SD-Card/NOR-Flash/USB would I then need
> to use at91bootstrap, or can I use only barebox?
> 
> If I move forward with this and I can find an 9263
> evaluation kit I would then also update this.
On 9263 the sram is huge so you can build barebox as first stage

I add this a long time ago on usb_a9263_bootstrap_defconfig
or other (all the EK).

This will build a barebox that can load you image from multiple source in a sequence

and then use a std barebox

To switch to DT you will have to import the DT I did for the kernel
and replace the hw i2c by a i2c gpio as the i2c IP on at91 has a lot of quirks
and for barebox it will not make sense to port it

Best Regards,
J.
_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 00/45] AT91, at91sam9x5ek updates
  2017-03-07 16:56   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2017-03-07 20:58     ` Sam Ravnborg
  2017-03-07 21:18       ` Andrey Smirnov
  0 siblings, 1 reply; 58+ messages in thread
From: Sam Ravnborg @ 2017-03-07 20:58 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: Andrey Smirnov, barebox

> > 
> > When booting from an SD-Card/NOR-Flash/USB would I then need
> > to use at91bootstrap, or can I use only barebox?
> > 
> > If I move forward with this and I can find an 9263
> > evaluation kit I would then also update this.
> On 9263 the sram is huge so you can build barebox as first stage

Good - simplicity is good.

> 
> I add this a long time ago on usb_a9263_bootstrap_defconfig
> or other (all the EK).
> 
> This will build a barebox that can load you image from multiple source in a sequence
> 
> and then use a std barebox
> 
> To switch to DT you will have to import the DT I did for the kernel
OK, should be straighforward.

> and replace the hw i2c by a i2c gpio as the i2c IP on at91 has a lot of quirks
> and for barebox it will not make sense to port it
Seems less straightforward but doable.

I will see if I can find time to give it a try and then post patches.

	Sam

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

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

* Re: [PATCH 00/45] AT91, at91sam9x5ek updates
  2017-03-07  8:13 ` [PATCH 00/45] AT91, at91sam9x5ek updates Sascha Hauer
@ 2017-03-07 21:09   ` Andrey Smirnov
  0 siblings, 0 replies; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-07 21:09 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On Tue, Mar 7, 2017 at 12:13 AM, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> Hi Andrey,
>
> On Mon, Mar 06, 2017 at 02:53:11PM -0800, Andrey Smirnov wrote:
>> Hi everyone,
>>
>> I recently had a chance to work with at91sam9x5ek board and as a part
>> of that effort I converted the code to support features found in
>> Barebox for i.MX based SoCs. Most notably this patchset converts
>> at91sam9x5ek to use multi-image PBL build process as well as adds
>> support for board initialization from attached devicetree blob.
>>
>> Sascha, at least for now, all of the patches, in chronological order,
>> are included in this submission. However if this proves to be too
>> burdensome to review, I'd be more than happy to split it into several
>> individual submissions. One such division could be:
>>
>>          - Generic bug fixes/infrastructure enhancements
>>          - Peripheral drivers updates
>>          - at91sam9x5ek specific changes
>>
>> Please let me know if that is preferrable.
>
> I had a short look at all patches, overall they look good. Nevertheless
> it would be good to sort them like you suggested. It just makes it
> easier to apply.
>

OK, will do.

> Thanks for working on this, a general AT91 overhaul was long overdue. I
> hope this series prepares a path to cleanup the other AT91 SoCs aswell.
>

Yeah, I have a bit more AT91 based hardware (at least SAMA5D3 Xplained
board and maybe more), so I was hoping to get those done after this
merge request.

> The clock support you ported over from the kernel is for all AT91 SoCs
> and not only one, right?

Yeah, I belive it should be usable by the whole AT91 family.

Thanks,
Andrey

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

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

* Re: [PATCH 00/45] AT91, at91sam9x5ek updates
  2017-03-07 20:58     ` Sam Ravnborg
@ 2017-03-07 21:18       ` Andrey Smirnov
  2017-03-07 21:47         ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-07 21:18 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: barebox

On Tue, Mar 7, 2017 at 12:58 PM, Sam Ravnborg <sam@ravnborg.org> wrote:
>> >
>> > When booting from an SD-Card/NOR-Flash/USB would I then need
>> > to use at91bootstrap, or can I use only barebox?
>> >
>> > If I move forward with this and I can find an 9263
>> > evaluation kit I would then also update this.
>> On 9263 the sram is huge so you can build barebox as first stage
>
> Good - simplicity is good.
>

For  at91sam9x5ek I had to use at91bootstrap since there is first
stage loader in Barebox for it. I don't know about 9263, but I trust
Jean-Christophe to be correct on this one.

>>
>> I add this a long time ago on usb_a9263_bootstrap_defconfig
>> or other (all the EK).
>>
>> This will build a barebox that can load you image from multiple source in a sequence
>>
>> and then use a std barebox
>>
>> To switch to DT you will have to import the DT I did for the kernel
> OK, should be straighforward.
>
>> and replace the hw i2c by a i2c gpio as the i2c IP on at91 has a lot of quirks
>> and for barebox it will not make sense to port it
> Seems less straightforward but doable.
>

Not sure what the situation on 9263 is, but FWIW, kernel DT file from
the kernel for 9x5ek secifies I2C0 as GPIO bitbanged on, and I believe
I had it working so hopefully it would be just a DT related change
that you'd need to do.

Thanks,
Andrey Smirnov

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

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

* Re: [PATCH 32/45] usb: ohci-at91: Check result of clk_get()
  2017-03-07 16:35   ` Sam Ravnborg
@ 2017-03-07 21:21     ` Andrey Smirnov
  2017-03-07 21:52       ` Sam Ravnborg
  0 siblings, 1 reply; 58+ messages in thread
From: Andrey Smirnov @ 2017-03-07 21:21 UTC (permalink / raw)
  To: Sam Ravnborg; +Cc: barebox

On Tue, Mar 7, 2017 at 8:35 AM, Sam Ravnborg <sam@ravnborg.org> wrote:
> On Mon, Mar 06, 2017 at 02:53:43PM -0800, Andrey Smirnov wrote:
>> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
>> ---
>>  drivers/usb/host/ohci-at91.c | 9 +++++++++
>>  1 file changed, 9 insertions(+)
>>
>> diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
>> index 0f5c8f1..c70d898 100644
>> --- a/drivers/usb/host/ohci-at91.c
>> +++ b/drivers/usb/host/ohci-at91.c
>> @@ -47,7 +47,16 @@ static int at91_ohci_probe(struct device_d *dev)
>>       struct ohci_regs __iomem *regs = (struct ohci_regs __iomem *)dev->resource[0].start;
>>
>>       iclk = clk_get(NULL, "ohci_clk");
>> +     if (IS_ERR(iclk)) {
>> +             dev_err(dev, "Failed to get 'iclk'\n");
> iclk is the internal name. Woudl it make more sense to use "ohci_clk" here?
>

I was looking at the corresponding kernel driver and that's where I
got the name for the variable. If you think 'ohci_clk' is a better
name I have no problem changing it.

>> +             return PTR_ERR(iclk);
>> +     }
>> +
>>       fclk = clk_get(NULL, "uhpck");
>> +     if (IS_ERR(fclk)) {
>> +             dev_err(dev, "Failed to get 'fclk'\n");
> Likewise - uhpck?

Ditto here.

Thanks,
Andrey Smirnov

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

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

* Re: [PATCH 00/45] AT91, at91sam9x5ek updates
  2017-03-07 21:18       ` Andrey Smirnov
@ 2017-03-07 21:47         ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 58+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2017-03-07 21:47 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: Sam Ravnborg, barebox


> On Mar 8, 2017, at 5:18 AM, Andrey Smirnov <andrew.smirnov@gmail.com> wrote:
> 
> On Tue, Mar 7, 2017 at 12:58 PM, Sam Ravnborg <sam@ravnborg.org> wrote:
>>>> 
>>>> When booting from an SD-Card/NOR-Flash/USB would I then need
>>>> to use at91bootstrap, or can I use only barebox?
>>>> 
>>>> If I move forward with this and I can find an 9263
>>>> evaluation kit I would then also update this.
>>> On 9263 the sram is huge so you can build barebox as first stage
>> 
>> Good - simplicity is good.
>> 
> 
> For  at91sam9x5ek I had to use at91bootstrap since there is first
> stage loader in Barebox for it. I don't know about 9263, but I trust
> Jean-Christophe to be correct on this one.

I’ve patch for all the at91 soc for the pbl and nand and mmc

but I’m really busy those days on EFI boot support 
and secure boot. To be able to pass microsoft certification so we can use barebox
to boot linux or even windows.

So I’ll try to dig them later

Best Regards,
J.
> 
>>> 
>>> I add this a long time ago on usb_a9263_bootstrap_defconfig
>>> or other (all the EK).
>>> 
>>> This will build a barebox that can load you image from multiple source in a sequence
>>> 
>>> and then use a std barebox
>>> 
>>> To switch to DT you will have to import the DT I did for the kernel
>> OK, should be straighforward.
>> 
>>> and replace the hw i2c by a i2c gpio as the i2c IP on at91 has a lot of quirks
>>> and for barebox it will not make sense to port it
>> Seems less straightforward but doable.
>> 
> 
> Not sure what the situation on 9263 is, but FWIW, kernel DT file from
> the kernel for 9x5ek secifies I2C0 as GPIO bitbanged on, and I believe
> I had it working so hopefully it would be just a DT related change
> that you'd need to do.
> 
> Thanks,
> Andrey Smirnov


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

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

* Re: [PATCH 32/45] usb: ohci-at91: Check result of clk_get()
  2017-03-07 21:21     ` Andrey Smirnov
@ 2017-03-07 21:52       ` Sam Ravnborg
  0 siblings, 0 replies; 58+ messages in thread
From: Sam Ravnborg @ 2017-03-07 21:52 UTC (permalink / raw)
  To: Andrey Smirnov; +Cc: barebox

On Tue, Mar 07, 2017 at 01:21:40PM -0800, Andrey Smirnov wrote:
> On Tue, Mar 7, 2017 at 8:35 AM, Sam Ravnborg <sam@ravnborg.org> wrote:
> > On Mon, Mar 06, 2017 at 02:53:43PM -0800, Andrey Smirnov wrote:
> >> Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
> >> ---
> >>  drivers/usb/host/ohci-at91.c | 9 +++++++++
> >>  1 file changed, 9 insertions(+)
> >>
> >> diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
> >> index 0f5c8f1..c70d898 100644
> >> --- a/drivers/usb/host/ohci-at91.c
> >> +++ b/drivers/usb/host/ohci-at91.c
> >> @@ -47,7 +47,16 @@ static int at91_ohci_probe(struct device_d *dev)
> >>       struct ohci_regs __iomem *regs = (struct ohci_regs __iomem *)dev->resource[0].start;
> >>
> >>       iclk = clk_get(NULL, "ohci_clk");
> >> +     if (IS_ERR(iclk)) {
> >> +             dev_err(dev, "Failed to get 'iclk'\n");
> > iclk is the internal name. Woudl it make more sense to use "ohci_clk" here?
> >
> 
> I was looking at the corresponding kernel driver and that's where I
> got the name for the variable. If you think 'ohci_clk' is a better
> name I have no problem changing it.

It is not something I have strong opinions about.
But I later noticed you sued "interface clk" and "function clk".
So it would be good to be consistent.

Even if the kernel is not consistent we can do better in barebox.

	Sam

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

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

end of thread, other threads:[~2017-03-07 21:53 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-06 22:53 [PATCH 00/45] AT91, at91sam9x5ek updates Andrey Smirnov
2017-03-06 22:53 ` [PATCH 01/45] at91: Fix bug/typo in debug_ll.h Andrey Smirnov
2017-03-06 22:53 ` [PATCH 02/45] at91sam9x5ek: Convert to mult-image build Andrey Smirnov
2017-03-06 22:53 ` [PATCH 03/45] at91sam9x5ek: Add CONFIG_KALLSYMS to defconfig Andrey Smirnov
2017-03-06 22:53 ` [PATCH 04/45] at91sam9x5ek: Add preliminary device tree support Andrey Smirnov
2017-03-06 22:53 ` [PATCH 05/45] clocksource: at91: Move to 'drivers/clocksource' Andrey Smirnov
2017-03-06 22:53 ` [PATCH 06/45] clocksource: at91: Add DT compatibility table Andrey Smirnov
2017-03-06 22:53 ` [PATCH 07/45] serial: atmel: Check result of clk_get() Andrey Smirnov
2017-03-07  7:46   ` Sascha Hauer
2017-03-06 22:53 ` [PATCH 08/45] serial: atmel: Add DT compatibility table Andrey Smirnov
2017-03-06 22:53 ` [PATCH 09/45] regmap: Implement syscon_node_to_regmap() Andrey Smirnov
2017-03-06 22:53 ` [PATCH 10/45] clk: Port two helper functions from Linux Andrey Smirnov
2017-03-06 22:53 ` [PATCH 11/45] clk: Make COMMON_CLK_OF_PROVIDER depend on OFTREE Andrey Smirnov
2017-03-06 22:53 ` [PATCH 12/45] clk: No-op CLK_OF_DECLARE if not enabled Andrey Smirnov
2017-03-06 22:53 ` [PATCH 13/45] clk: at91: Port at91 DT clock code Andrey Smirnov
2017-03-06 22:53 ` [PATCH 14/45] at91sam9x5ek: Convert to use DT clock tree Andrey Smirnov
2017-03-06 22:53 ` [PATCH 15/45] at91sam9x5ek: Remove at91sam9x5ek_mem_init() Andrey Smirnov
2017-03-06 22:53 ` [PATCH 16/45] at91sam9x5ek: Configure LEDs in DT Andrey Smirnov
2017-03-06 22:53 ` [PATCH 17/45] pinctrl-at91: Fix a bug in at91_pinctrl_set_conf() Andrey Smirnov
2017-03-06 22:53 ` [PATCH 18/45] at91: Enable PINCTRL for SOC_AT91SAM9 Andrey Smirnov
2017-03-06 22:53 ` [PATCH 19/45] at91sam9x5ek: Configure I2C via DT Andrey Smirnov
2017-03-06 22:53 ` [PATCH 20/45] mci: Allow parsing for explicit DT node Andrey Smirnov
2017-03-06 22:53 ` [PATCH 21/45] mci: atmel_mci: Add DT support Andrey Smirnov
2017-03-06 22:53 ` [PATCH 22/45] at91sam9x5ek: Configure MMC in DT Andrey Smirnov
2017-03-06 22:53 ` [PATCH 23/45] of: base: Use scoring in DT device matching Andrey Smirnov
2017-03-06 22:53 ` [PATCH 24/45] pinctrl: at91: Fix a bug in at91_pinctrl_set_state Andrey Smirnov
2017-03-06 22:53 ` [PATCH 25/45] pinctrl: at91: Implement .get_direction hook Andrey Smirnov
2017-03-06 22:53 ` [PATCH 26/45] spi: atmel_spi: Add DT support Andrey Smirnov
2017-03-06 22:53 ` [PATCH 27/45] spi: atmel_spi: Configure CS GPIO as output Andrey Smirnov
2017-03-06 22:53 ` [PATCH 28/45] spi: atmel_spi: Use VERSION register instead of CPU type Andrey Smirnov
2017-03-06 22:53 ` [PATCH 29/45] at91sam9x5ek: Configure SPI in DT Andrey Smirnov
2017-03-06 22:53 ` [PATCH 30/45] w1-gpio: Add DT support Andrey Smirnov
2017-03-06 22:53 ` [PATCH 31/45] at91sam9x5ek: Configure 1-wire in DT Andrey Smirnov
2017-03-06 22:53 ` [PATCH 32/45] usb: ohci-at91: Check result of clk_get() Andrey Smirnov
2017-03-07 16:35   ` Sam Ravnborg
2017-03-07 21:21     ` Andrey Smirnov
2017-03-07 21:52       ` Sam Ravnborg
2017-03-06 22:53 ` [PATCH 33/45] usb: ohci-at91: Convert global variables to private data Andrey Smirnov
2017-03-06 22:53 ` [PATCH 34/45] usb: ohci-at91: Check result of clk_enable() Andrey Smirnov
2017-03-06 22:53 ` [PATCH 35/45] usb: ohci-at91: Add DT support Andrey Smirnov
2017-03-07 16:40   ` Sam Ravnborg
2017-03-06 22:53 ` [PATCH 36/45] usb/host: Allow USB_OHCI_AT91 even if USB_OHCI is disabled Andrey Smirnov
2017-03-06 22:53 ` [PATCH 37/45] usb: ehci-atmel: Check result of clk_enable() Andrey Smirnov
2017-03-06 22:53 ` [PATCH 38/45] usb: echi-atmel: Convert global variables to private data Andrey Smirnov
2017-03-06 22:53 ` [PATCH 39/45] usb: ehci-atmel: Zero ehci_data before using it Andrey Smirnov
2017-03-06 22:53 ` [PATCH 40/45] usb: echi-atmel: Check result of ehci_register() Andrey Smirnov
2017-03-06 22:53 ` [PATCH 41/45] usb: echi-atmel: Add DT support Andrey Smirnov
2017-03-06 22:53 ` [PATCH 42/45] at91sam9x5ek: Configure USB in DT Andrey Smirnov
2017-03-06 22:53 ` [PATCH 43/45] net: macb: Add DT support Andrey Smirnov
2017-03-06 22:53 ` [PATCH 44/45] at91sam9x5ek: Configure Ethernet in DT Andrey Smirnov
2017-03-06 22:53 ` [PATCH 45/45] at91sam9x5ek: Configure NAND " Andrey Smirnov
2017-03-07  8:13 ` [PATCH 00/45] AT91, at91sam9x5ek updates Sascha Hauer
2017-03-07 21:09   ` Andrey Smirnov
2017-03-07 16:34 ` Sam Ravnborg
2017-03-07 16:56   ` Jean-Christophe PLAGNIOL-VILLARD
2017-03-07 20:58     ` Sam Ravnborg
2017-03-07 21:18       ` Andrey Smirnov
2017-03-07 21:47         ` 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