All of lore.kernel.org
 help / color / mirror / Atom feed
* Patch series For U6/U6715 platform support
@ 2010-08-05 12:28 ` Philippe Langlais
  0 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux, gregkh
  Cc: akpm, STEricsson_nomadik_linux, etienne.carriere, vincent.guittot


Hi,

This patch series is almost the final one, if no more comment.
I only change the changelog of [PATCH 5/5] to my previous submission.
The 3 first patches are U6715 ARM platform concern only, may be merged
in Russell arm tree.
The 2 latest patches concern the 8250 serial driver, Greg must update
the changelog of patch "U6715 16550A serial driver support" in linux-next
tree and merge the platform U6715 serial driver patch synchronized with
Russell ack (see Andrew previous suggestion). 

Thanks
Philippe

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

* Patch series For U6/U6715 platform support
@ 2010-08-05 12:28 ` Philippe Langlais
  0 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-arm-kernel


Hi,

This patch series is almost the final one, if no more comment.
I only change the changelog of [PATCH 5/5] to my previous submission.
The 3 first patches are U6715 ARM platform concern only, may be merged
in Russell arm tree.
The 2 latest patches concern the 8250 serial driver, Greg must update
the changelog of patch "U6715 16550A serial driver support" in linux-next
tree and merge the platform U6715 serial driver patch synchronized with
Russell ack (see Andrew previous suggestion). 

Thanks
Philippe

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

* [PATCH 1/5] U6/U6715 ARM architecture files
  2010-08-05 12:28 ` Philippe Langlais
@ 2010-08-05 12:28   ` Philippe Langlais
  -1 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux, gregkh
  Cc: akpm, STEricsson_nomadik_linux, etienne.carriere,
	vincent.guittot, Philippe Langlais

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 arch/arm/Kconfig                               |   11 +
 arch/arm/Makefile                              |    2 +
 arch/arm/mach-u67xx/Kconfig                    |   12 +
 arch/arm/mach-u67xx/Makefile                   |   11 +
 arch/arm/mach-u67xx/Makefile.boot              |    4 +
 arch/arm/mach-u67xx/board_u67xx_wavex.c        |   47 +++
 arch/arm/mach-u67xx/devices.c                  |   28 ++
 arch/arm/plat-u6xxx/Kconfig                    |   22 ++
 arch/arm/plat-u6xxx/Makefile                   |    8 +
 arch/arm/plat-u6xxx/include/mach/cpu.h         |   36 ++
 arch/arm/plat-u6xxx/include/mach/debug-macro.S |   38 ++
 arch/arm/plat-u6xxx/include/mach/entry-macro.S |   32 ++
 arch/arm/plat-u6xxx/include/mach/hardware.h    |   41 +++
 arch/arm/plat-u6xxx/include/mach/io.h          |   30 ++
 arch/arm/plat-u6xxx/include/mach/irqs.h        |  102 ++++++
 arch/arm/plat-u6xxx/include/mach/memory.h      |   17 +
 arch/arm/plat-u6xxx/include/mach/regs-u6.h     |  121 +++++++
 arch/arm/plat-u6xxx/include/mach/system.h      |   42 +++
 arch/arm/plat-u6xxx/include/mach/timer.h       |   16 +
 arch/arm/plat-u6xxx/include/mach/timex.h       |   23 ++
 arch/arm/plat-u6xxx/include/mach/uncompress.h  |   47 +++
 arch/arm/plat-u6xxx/include/mach/vmalloc.h     |   10 +
 arch/arm/plat-u6xxx/io.c                       |   34 ++
 arch/arm/plat-u6xxx/irq.c                      |  254 ++++++++++++++
 arch/arm/plat-u6xxx/timer.c                    |  442 ++++++++++++++++++++++++
 25 files changed, 1430 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-u67xx/Kconfig
 create mode 100644 arch/arm/mach-u67xx/Makefile
 create mode 100644 arch/arm/mach-u67xx/Makefile.boot
 create mode 100644 arch/arm/mach-u67xx/board_u67xx_wavex.c
 create mode 100644 arch/arm/mach-u67xx/devices.c
 create mode 100644 arch/arm/plat-u6xxx/Kconfig
 create mode 100644 arch/arm/plat-u6xxx/Makefile
 create mode 100644 arch/arm/plat-u6xxx/include/mach/cpu.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/debug-macro.S
 create mode 100644 arch/arm/plat-u6xxx/include/mach/entry-macro.S
 create mode 100644 arch/arm/plat-u6xxx/include/mach/hardware.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/io.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/irqs.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/memory.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/regs-u6.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/system.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/timer.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/timex.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/uncompress.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/vmalloc.h
 create mode 100644 arch/arm/plat-u6xxx/io.c
 create mode 100644 arch/arm/plat-u6xxx/irq.c
 create mode 100644 arch/arm/plat-u6xxx/timer.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cf30fc9..1ae089c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -739,6 +739,14 @@ config ARCH_U300
 	help
 	  Support for ST-Ericsson U300 series mobile platforms.
 
+config PLAT_U6XXX
+	bool "ST-Ericsson U6XXX Series"
+	select CPU_ARM926T
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  Support for ST-Ericsson's U6XXX architecture
+
 config ARCH_U8500
 	bool "ST-Ericsson U8500 Series"
 	select CPU_V7
@@ -910,6 +918,9 @@ source "arch/arm/mach-tegra/Kconfig"
 
 source "arch/arm/mach-u300/Kconfig"
 
+source "arch/arm/plat-u6xxx/Kconfig"
+source "arch/arm/mach-u67xx/Kconfig"
+
 source "arch/arm/mach-ux500/Kconfig"
 
 source "arch/arm/mach-versatile/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2de67c9..c510a64 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -176,6 +176,7 @@ machine-$(CONFIG_ARCH_STMP378X)		:= stmp378x
 machine-$(CONFIG_ARCH_STMP37XX)		:= stmp37xx
 machine-$(CONFIG_ARCH_TEGRA)		:= tegra
 machine-$(CONFIG_ARCH_U300)		:= u300
+machine-$(CONFIG_ARCH_U67XX)		:= u67xx
 machine-$(CONFIG_ARCH_U8500)		:= ux500
 machine-$(CONFIG_ARCH_VERSATILE)	:= versatile
 machine-$(CONFIG_ARCH_VEXPRESS)		:= vexpress
@@ -200,6 +201,7 @@ plat-$(CONFIG_PLAT_PXA)		:= pxa
 plat-$(CONFIG_PLAT_S3C24XX)	:= s3c24xx samsung
 plat-$(CONFIG_PLAT_S5P)		:= s5p samsung
 plat-$(CONFIG_PLAT_SPEAR)	:= spear
+plat-$(CONFIG_PLAT_U6XXX)	:= u6xxx
 plat-$(CONFIG_PLAT_VERSATILE)	:= versatile
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
diff --git a/arch/arm/mach-u67xx/Kconfig b/arch/arm/mach-u67xx/Kconfig
new file mode 100644
index 0000000..f02f6e2
--- /dev/null
+++ b/arch/arm/mach-u67xx/Kconfig
@@ -0,0 +1,12 @@
+comment "U67XX Board Type"
+	depends on ARCH_U67XX
+
+choice
+	depends on ARCH_U67XX
+	prompt "Choose the U67XX Board type"
+	default MACH_U67XX_WAVEC_2GB
+	help
+		Choose the ST-Ericsson Reference Design Board
+config MACH_U67XX_WAVEC_2GB
+	bool "U67XX WaveC Board with 2Gb Micron combo"
+endchoice
diff --git a/arch/arm/mach-u67xx/Makefile b/arch/arm/mach-u67xx/Makefile
new file mode 100644
index 0000000..38cf624
--- /dev/null
+++ b/arch/arm/mach-u67xx/Makefile
@@ -0,0 +1,11 @@
+#
+## Makefile for the linux kernel, hardware dependent part of ST-Ericsson U67xx
+#
+#
+## Object file lists.
+
+# Common support
+obj-y			:= devices.o
+
+# Specific board support
+obj-$(CONFIG_MACH_U67XX_WAVEC_2GB) += board_u67xx_wavex.o
diff --git a/arch/arm/mach-u67xx/Makefile.boot b/arch/arm/mach-u67xx/Makefile.boot
new file mode 100644
index 0000000..c4e8c02
--- /dev/null
+++ b/arch/arm/mach-u67xx/Makefile.boot
@@ -0,0 +1,4 @@
+   zreladdr-y		:= 0x20008000
+params_phys-y		:= 0x20000100
+initrd_phys-y		:= 0x26000000
+
diff --git a/arch/arm/mach-u67xx/board_u67xx_wavex.c b/arch/arm/mach-u67xx/board_u67xx_wavex.c
new file mode 100644
index 0000000..633989f
--- /dev/null
+++ b/arch/arm/mach-u67xx/board_u67xx_wavex.c
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-u67xx/board_u67xx_wavex.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Platform machine definition for U6XXX WAVEx Board.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/timer.h>
+
+/* List of board specific devices */
+static struct platform_device *devices[] __initdata = {
+};
+
+void __init u67xx_init(void)
+{
+	/* Add specific board devices */
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+MACHINE_START(U6715, "STE_U67xx_refd")
+	/* Maintainer: Philippe Langlais <philippe.langlais@stericsson.com> */
+	.phys_io	= UART1_BASE,
+	.io_pg_offst	= (IO_ADDRESS(UART1_BASE) >> 18) & 0xfffc,
+	.boot_params	= PHYS_OFFSET + 0x100,
+	.map_io		= u6xxx_map_io,
+	.init_irq	= u6_init_irq,
+	.init_machine	= u67xx_init,
+	.timer		= &u6_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-u67xx/devices.c b/arch/arm/mach-u67xx/devices.c
new file mode 100644
index 0000000..1d00b35
--- /dev/null
+++ b/arch/arm/mach-u67xx/devices.c
@@ -0,0 +1,28 @@
+/*
+ * linux/arch/arm/mach-u67xx/devices.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Device specification for the U67XX
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+/* list of devices */
+static struct platform_device *platform_devs[] __initdata = {
+};
+
+/* register generic devices */
+
+static int __init u67xx_devices_init(void)
+{
+	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+	return 0;
+}
+
+arch_initcall(u67xx_devices_init);
diff --git a/arch/arm/plat-u6xxx/Kconfig b/arch/arm/plat-u6xxx/Kconfig
new file mode 100644
index 0000000..10929ea
--- /dev/null
+++ b/arch/arm/plat-u6xxx/Kconfig
@@ -0,0 +1,22 @@
+if PLAT_U6XXX
+
+menu "STE U6XXX Implementations"
+
+choice
+	prompt "U67XX System Type"
+	default ARCH_U67XX
+
+config ARCH_U67XX
+	bool "U67XX"
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select U6_MTU_TIMER
+endchoice
+
+endmenu
+
+config U6_MTU_TIMER
+	bool
+	default y
+
+endif
diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
new file mode 100644
index 0000000..12c832c
--- /dev/null
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel hardware independant part of STE U6XXX.
+#
+
+# Common support
+obj-y := io.o irq.o
+
+obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/include/mach/cpu.h b/arch/arm/plat-u6xxx/include/mach/cpu.h
new file mode 100644
index 0000000..4f1f57f
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/cpu.h
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/cpu.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * U6 cpu type detection
+ */
+
+#ifndef __ASM_PLAT_CPU_H
+#define __ASM_PLAT_CPU_H
+
+/*
+ * Macros to group U6xxx into cpu classes.
+ * These can be used in most places.
+ * cpu_is_u67xx():	True for U67XX
+ */
+
+#define GET_U6XXX_CLASS		((readl(SCON_SYSVER_REG)&0x0F00)>>8)
+#define GET_U6XXX_SUBCLASS	((readl(SCON_SYSVER_REG)&0x0FF0)>>4)
+
+#define cpu_is_u67xx()		0
+#define cpu_is_u67xx_v2()	0
+#define cpu_is_u67xx_v3()	0
+
+#if defined(CONFIG_ARCH_U67XX)
+#  undef cpu_is_u67xx
+#  undef cpu_is_u67xx_v2
+#  undef cpu_is_u67xx_v3
+#  define cpu_is_u67xx()	(GET_U6XXX_CLASS == 0x6)
+#  define cpu_is_u67xx_v2()	(GET_U6XXX_SUBCLASS == 0x62)
+#  define cpu_is_u67xx_v3()	(GET_U6XXX_SUBCLASS == 0x63)
+#endif
+
+#endif /* __ASM_PLAT_CPU_H */
+
diff --git a/arch/arm/plat-u6xxx/include/mach/debug-macro.S b/arch/arm/plat-u6xxx/include/mach/debug-macro.S
new file mode 100644
index 0000000..039c810
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/debug-macro.S
@@ -0,0 +1,38 @@
+/* linux/arch/arm/plat-u6xxx/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ *  Copyright (C) 2010 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <mach/hardware.h>
+
+		.macro	addruart,rx
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1                       @ MMU enabled?
+		ldreq	\rx, = UART1_BASE             @ physical base address
+		ldrne	\rx, = IO_ADDRESS(UART1_BASE) @ virtual base
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	waituart,rd,rx
+1001:
+		ldr	\rd, [\rx, #20]
+		tst	\rd, #1 << 5	@ LSR_THRE - 0 when full
+		beq	1001b
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:
+		ldr	\rd, [\rx, #20]
+		tst	\rd, #1 << 6	@ LSR_TEMT - 0 when busy
+		beq	1001b
+		.endm
diff --git a/arch/arm/plat-u6xxx/include/mach/entry-macro.S b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
new file mode 100644
index 0000000..cae8824
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
@@ -0,0 +1,32 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for U6-based platforms
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	.macro	disable_fiq
+	.endm
+
+	.macro  get_irqnr_preamble, base, tmp
+	ldr	\base, =IO_ADDRESS(INTC_BASE)
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	ldr	\irqnr, [\base, #INTC_VECTOR_IRQ_OFFSET] @ load intc vector reg
+	mov	\irqnr, \irqnr, lsr #3              @ Bits[0..2] are reserved
+	ands	\irqnr, \irqnr, #0x00FF             @ mask Bits[11..31]
+	.endm
+
+	.macro	irq_prio_table
+	.endm
+
diff --git a/arch/arm/plat-u6xxx/include/mach/hardware.h b/arch/arm/plat-u6xxx/include/mach/hardware.h
new file mode 100644
index 0000000..79199ec
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/hardware.h
@@ -0,0 +1,41 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/hardware.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#ifndef __ASSEMBLER__
+#include <mach/cpu.h>
+#endif
+
+/*
+ * Processor specific registers defines
+ */
+#include "regs-u6.h"
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+
+#define IO_BASE_VIRT            0xE8000000        /* VA of IO */
+
+/* macro to get at IO space when running virtually */
+/* this version gives more IO address range to map*/
+#define IO_ADDRESS(x)   ((x) - IO_BASE_PHYS + IO_BASE_VIRT)
+
+/* typesafe io address */
+#define __io_address(n)		__io(IO_ADDRESS(n))
+
+/*
+ * Board specific defines
+ */
+
+#endif
+
diff --git a/arch/arm/plat-u6xxx/include/mach/io.h b/arch/arm/plat-u6xxx/include/mach/io.h
new file mode 100644
index 0000000..e8a93b4
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/io.h
@@ -0,0 +1,30 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/io.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Dummy IO map & IO definitions
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)       __typesafe_io(a)
+#define __mem_pci(a)  (a)
+
+/*
+ * I/O mapping
+ */
+#ifdef __ASSEMBLER__
+#define IOMEM(x)		(x)
+#else
+#define IOMEM(x)		((void __force __iomem *)(x))
+#endif
+#define U6_IO_ADDRESS(pa)	IOMEM(IO_ADDRESS(pa))
+
+void u6xxx_map_io(void);
+
+#endif /* __ASM_ARM_ARCH_IO_H */
diff --git a/arch/arm/plat-u6xxx/include/mach/irqs.h b/arch/arm/plat-u6xxx/include/mach/irqs.h
new file mode 100644
index 0000000..2943882
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/irqs.h
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/irqs.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_PLAT_U6_IRQS_H
+#define __ASM_PLAT_U6_IRQS_H
+
+#define IRQ_COUNT             65
+
+/* external IRQ definition EXTINT */
+#define IRQ_EXTINT(num)       (IRQ_COUNT+(num))
+#define EXTINT_NUM(irq)       ((irq)-IRQ_COUNT)
+
+#define NR_EXTINT             24
+#define NR_IRQS	              (IRQ_COUNT+NR_EXTINT)
+
+#ifndef __ASSEMBLY__
+extern unsigned char extint_to_gpio[NR_EXTINT];
+
+#define EXTINT_TO_GPIO(gpio_irq)    extint_to_gpio[gpio_irq-IRQ_COUNT]
+
+void /*__init */ u6_init_irq(void);
+void u6_monitor_irq_enter(unsigned int irq);
+void u6_monitor_irq_exit(unsigned int irq);
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Interrupt numbers
+ */
+#define IRQ_GHOST                       0
+#define IRQ_EXTINT1                     1
+#define IRQ_EXTINT2                     2
+#define IRQ_EXTINT3                     3
+#define IRQ_RFRD                        4
+#define IRQ_MMTU                        5
+#define IRQ_IIS                         6
+#define IRQ_USB                         7
+#define IRQ_I2C2                        8
+#define IRQ_TVO                         9
+#define IRQ_3G_WUP                      10
+#define IRQ_3G_CALINT                   11
+#define IRQ_3G_FRAME_IT                 12
+#define IRQ_GPADCINT                    13
+#define IRQ_ARM9_COMMTX                 14
+#define IRQ_ARM9_COMMRX                 15
+#define IRQ_KBS                         16
+#define IRQ_SCTU2                       17
+#define IRQ_SCTU1                       18
+#define IRQ_PIO1                        19
+#define IRQ_PIO2                        20
+#define IRQ_FINT0                       21
+#define IRQ_FINT1                       22
+#define IRQ_UART2                       23
+#define IRQ_UART1                       24
+#define IRQ_SPI2                        25
+#define IRQ_SPI1                        26
+#define IRQ_FCI                         27
+#define IRQ_I2C1                        28
+#define IRQ_DMAU                        29
+#define IRQ_USIM                        30
+#define IRQ_HSDPA                       31    /* reserved */
+#define IRQ_MSI                         32
+#define IRQ_JDI                         33
+#define IRQ_JDU                         34
+#define IRQ_NFI                         35
+#define IRQ_IPP                         36
+#define IRQ_VDC                         37
+#define IRQ_VEC                         38
+#define IRQ_VDE                         39
+#define IRQ_CAM                         40
+#define IRQ_ETB_ACQ                     41
+#define IRQ_ETB_FULL                    42
+#define IRQ_RESERVED43                  43
+#define IRQ_RESERVED44                  44
+#define IRQ_RESERVED45                  45    /* reserved */
+#define IRQ_RESERVED46                  46
+#define IRQ_RESERVED47                  47
+#define IRQ_PDCU                        48
+#define IRQ_MC2SC0                      49
+#define IRQ_MC2SC1                      50
+#define IRQ_MC2SC2                      51
+#define IRQ_MC2SC3                      52
+#define IRQ_MC2SC4                      53
+#define IRQ_MC2SC5                      54
+#define IRQ_MC2SC6                      55
+#define IRQ_MC2SC7                      56
+
+/* INTC VECTOR_IRQ Register (32 bits) */
+#define INTC_VECTOR_IRQ_OFFSET   0x100
+
+/* INTC REQUEST 64 Registers (32 bits) */
+#define INTC_REQUEST1_OFFSET     0x404
+#define INTC_REQUEST64_OFFSET    0x500
+
+/* interrupt x [1..64] request configuration */
+#define INTC_REQUESTx(x)  U6_IO_ADDRESS(INTC_BASE+INTC_REQUEST1_OFFSET+(x-1)*4)
+
+#endif /* __ASM_PLAT_U6_IRQS_H */
diff --git a/arch/arm/plat-u6xxx/include/mach/memory.h b/arch/arm/plat-u6xxx/include/mach/memory.h
new file mode 100644
index 0000000..71a5c60
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/memory.h
@@ -0,0 +1,17 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/memory.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET		UL(0x20000000)
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/regs-u6.h b/arch/arm/plat-u6xxx/include/mach/regs-u6.h
new file mode 100644
index 0000000..aa2fbb0
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/regs-u6.h
@@ -0,0 +1,121 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/regs-u6.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * Basic register address definitions in physical memory
+ */
+
+#if !defined(__REGS_U6_H__)
+#define __REGS_U6_H__
+
+#define IO_BASE_PHYS              0xC1000000  /* phys base address of reg */
+#define IO_SIZE                   0x03400000  /* How much */
+
+/*
+ * System Controller Core devices base address table
+ */
+
+/* DMA Controller */
+#define DMAU_BASE                 (IO_BASE_PHYS + 0x0000000)
+
+/* Interrupt Controller */
+#define INTC_BASE                 (IO_BASE_PHYS + 0x0100000)
+
+/* SDRam controller */
+#define SDI_BASE                  (IO_BASE_PHYS + 0x0200000)
+
+/* Nand Flash Inteface controller */
+#define NFI_BASE                  (IO_BASE_PHYS + 0x0300000)
+
+/* USB controller */
+#define USB_BASE                  (IO_BASE_PHYS + 0x0400000)
+
+/* Video Display Engine */
+#define VDE_BASE                  (IO_BASE_PHYS + 0x0500000)
+
+/* Video Decoder */
+#define VDC_BASE                  (IO_BASE_PHYS + 0x1000000)
+
+/* Viedo Encoder */
+#define VEC_BASE                  (IO_BASE_PHYS + 0x1100000)
+
+/* Texture Codec, MPEG4 encoder sub module */
+#define TC_BASE                   (IO_BASE_PHYS + 0x1102000)
+
+/* Image Post-Processor */
+#define IPP2_BASE                 (IO_BASE_PHYS + 0x1200000)
+
+/* JPEG Decoder Unit */
+#define JDU_BASE                  (IO_BASE_PHYS + 0x1300000)
+
+/* TV output controller */
+#define TVO_BASE                  (IO_BASE_PHYS + 0x1400000)
+
+/* Camera controller */
+#define CAM_BASE                  (IO_BASE_PHYS + 0x1800000)
+
+/* External Bus Interfaces */
+#define EBI_BASE                  (IO_BASE_PHYS + 0x2001000)
+
+/* SPI controllers */
+#define SPI1_BASE                 (IO_BASE_PHYS + 0x2002000)
+#define SPI2_BASE                 (IO_BASE_PHYS + 0x2003000)
+
+/* SD/MMC controller */
+#define FCI_BASE                  (IO_BASE_PHYS + 0x2008000)
+
+/* Crypto Acceleration Engine */
+#define CAE_BASE                  (IO_BASE_PHYS + 0x2009000)
+
+/* Multimedia Timer Unit, aka MTU in Datasheet */
+#define MMTU_BASE                 (IO_BASE_PHYS + 0x2101000)
+
+/* System controller timer units */
+#define SCTU1_BASE                (IO_BASE_PHYS + 0x2102000)
+#define SCTU2_BASE                (IO_BASE_PHYS + 0x2103000)
+
+/* General Purpose I/O units */
+#define GPIOA_BASE                (IO_BASE_PHYS + 0x2104000)
+#define GPIOB_BASE                (IO_BASE_PHYS + 0x2104200)
+#define GPIOC_BASE                (IO_BASE_PHYS + 0x2104400)
+#define GPIOD_BASE                (IO_BASE_PHYS + 0x2104600)
+#define GPIOE_BASE                (IO_BASE_PHYS + 0x2104800)
+#define GPIOF_BASE                (IO_BASE_PHYS + 0x2104A00)
+
+/* External Interrupt controller */
+#define EXTINT_BASE               (IO_BASE_PHYS + 0x2105000)
+
+/* Keyboard Scanner */
+#define KBS_BASE                  (IO_BASE_PHYS + 0x2106000)
+
+/* Pulse Width Modulators */
+#define PWM1_BASE                 (IO_BASE_PHYS + 0x2108000)
+#define PWM2_BASE                 (IO_BASE_PHYS + 0x2109000)
+#define PWM3_BASE                 (IO_BASE_PHYS + 0x210A000)
+
+/* I2C controllers */
+#define I2C1_BASE                 (IO_BASE_PHYS + 0x210C000)
+#define I2C2_BASE                 (IO_BASE_PHYS + 0x210D000)
+
+/* UARTs */
+#define UART1_BASE                (IO_BASE_PHYS + 0x210E000)
+#define UART2_BASE                (IO_BASE_PHYS + 0x210F000)
+
+/* Clock Generation Unit */
+#define CGU_BASE                  (IO_BASE_PHYS + 0x2200000)
+
+/* Time base Unit */
+#define TBU_BASE                  (IO_BASE_PHYS + 0x2201000)
+
+/* Power Down Control Unit */
+#define PDCU_BASE                 (IO_BASE_PHYS + 0x2202000)
+
+/* Watchdog & Reset Unit */
+#define WDRU_BASE                 (IO_BASE_PHYS + 0x2203000)
+
+/* System Configuration */
+#define SCON_BASE                 (IO_BASE_PHYS + 0x2204000)
+
+#endif /* __REGS_U6_H__ */
diff --git a/arch/arm/plat-u6xxx/include/mach/system.h b/arch/arm/plat-u6xxx/include/mach/system.h
new file mode 100644
index 0000000..8799e57
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/system.h
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/system.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <mach/hardware.h>
+
+/* Watchdog & Reset Unit TIMER Register (16 bits) */
+#define WDRU_TIM_OFFSET                0x4
+
+static inline void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks
+	 */
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	unsigned long flags;
+	/*
+	 * To reset, we hit the on-board reset register
+	 * in the system FPGA
+	 */
+	/* diasble HW interruption */
+	raw_local_irq_save(flags);
+	/* load watchdog with reset value */
+	writel(0x5, IO_ADDRESS(WDRU_BASE + WDRU_TIM_OFFSET));
+	/* wait for wachdog expiration */
+	while (1)
+		;
+}
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/timer.h b/arch/arm/plat-u6xxx/include/mach/timer.h
new file mode 100644
index 0000000..614d6cf
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/timer.h
@@ -0,0 +1,16 @@
+/*
+ *  linux/arch/arm/plat-u6xxx/include/mach/timer.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __PLAT_TIMER_H
+#define __PLAT_TIMER_H
+
+struct sys_timer;
+
+extern struct sys_timer u6_timer;
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/timex.h b/arch/arm/plat-u6xxx/include/mach/timex.h
new file mode 100644
index 0000000..1e71241
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/timex.h
@@ -0,0 +1,23 @@
+/*
+ *  linux/arch/arm/plat-u6xxx/include/mach/timex.h
+ *
+ *  Integrator architecture timex specifications
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define CLOCK_TICK_RATE		(50000000 / 16)
diff --git a/arch/arm/plat-u6xxx/include/mach/uncompress.h b/arch/arm/plat-u6xxx/include/mach/uncompress.h
new file mode 100644
index 0000000..e37f0b4
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/uncompress.h
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/uncompress.h
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2003 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/io.h>
+#include "mach/hardware.h"
+
+/* UART THR Register (8 bits) */
+#define UART1_THR_OFFSET      0x0
+#define UART1_THR_REG         IO_ADDRESS(UART1_BASE + UART1_THR_OFFSET)
+
+/* UART LSR Register (8 bits) */
+#define UART1_LSR_OFFSET      0x14
+#define UART1_LSR_REG         IO_ADDRESS(UART1_BASE + UART1_LSR_OFFSET)
+
+static void putc(int c)
+{
+	while (!(readb(UART1_LSR_REG) & (1<<5)))
+		barrier();
+	writeb(c, UART1_THR_REG);
+}
+
+static inline void flush(void)
+{
+}
+
+/* nothing to do */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
diff --git a/arch/arm/plat-u6xxx/include/mach/vmalloc.h b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
new file mode 100644
index 0000000..cb89107
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
@@ -0,0 +1,10 @@
+/*
+ * linux/arch/arm/plat-u6/include/mach/vmalloc.h
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Virtual memory allocations
+ * End must be above the I/O registers and on an even 2MiB boundary.
+ */
+#define VMALLOC_END       0xe8000000UL
diff --git a/arch/arm/plat-u6xxx/io.c b/arch/arm/plat-u6xxx/io.c
new file mode 100644
index 0000000..01d447c
--- /dev/null
+++ b/arch/arm/plat-u6xxx/io.c
@@ -0,0 +1,34 @@
+/*
+ * linux/arch/arm/plat-u6xxx/io.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+
+
+static struct map_desc u6xxx_io_desc[] __initdata = {
+	{
+		.virtual  = IO_BASE_VIRT,	/* only peripherals */
+		.pfn      = __phys_to_pfn(IO_BASE_PHYS),
+		.length   = IO_SIZE,
+		.type     = MT_DEVICE,
+	}
+};
+
+void __init u6xxx_map_io(void)
+{
+    iotable_init(u6xxx_io_desc, ARRAY_SIZE(u6xxx_io_desc));
+}
+
diff --git a/arch/arm/plat-u6xxx/irq.c b/arch/arm/plat-u6xxx/irq.c
new file mode 100644
index 0000000..2ede5f0
--- /dev/null
+++ b/arch/arm/plat-u6xxx/irq.c
@@ -0,0 +1,254 @@
+/*
+ *  linux/arch/arm/plat-u6xxx/irq.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <mach/irqs.h>		/* U6 specific constants, types */
+
+/* INTC PRIOMASK_IRQ Register (32 bits) */
+#define INTC_PRIOMASK_IRQ_OFFSET 0x0
+#define INTC_PRIOMASK_IRQ_REG  IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_IRQ_OFFSET)
+
+/* INTC PRIOMASK_FIQ Register (32 bits) */
+#define INTC_PRIOMASK_FIQ_OFFSET 0x4
+#define INTC_PRIOMASK_FIQ_REG  IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_FIQ_OFFSET)
+
+/* INTC VECTOR_IRQ Register (32 bits) */
+#define INTC_VECTOR_IRQ_REG      IO_ADDRESS(INTC_BASE + INTC_VECTOR_IRQ_OFFSET)
+
+/* INTC VECTOR_FIQ Register (32 bits) */
+#define INTC_VECTOR_FIQ_OFFSET   0x104
+#define INTC_VECTOR_FIQ_REG      IO_ADDRESS(INTC_BASE + INTC_VECTOR_FIQ_OFFSET)
+
+/* INTC PENDING_* Registers (32 bits) */
+#define INTC_PENDING_1_OFFSET    0x200
+#define INTC_PENDING_2_OFFSET    0x204
+#define INTC_PENDING_3_OFFSET    0x208
+#define INTC_FEATURES_OFFSET     0x300
+
+#define INTC_REQUESTx_PENDING_MASK       (1 << 31)
+#define INTC_REQUESTx_SET_SWINT_MASK     (1 << 30)
+#define INTC_REQUESTx_CLR_SWINT_MASK     (1 << 29)
+#define INTC_REQUESTx_WE_PRIORITY_MASK   (1 << 28)
+#define INTC_REQUESTx_WE_TARGET_MASK     (1 << 27)
+#define INTC_REQUESTx_WE_ENABLE_MASK     (1 << 26)
+#define INTC_REQUESTx_WE_ACTIVE_LOW_MASK (1 << 25)
+#define INTC_REQUESTx_ACTIVE_LOW_MASK    (1 << 17)
+#define INTC_REQUESTx_ENABLE_MASK        (1 << 16)
+#define INTC_REQUESTx_TARGET_MASK        (1 <<  8)
+
+#define INTC_IID_USB_LP_INT 13
+
+static void u6_irq_mask(uint32_t irqno)
+{
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		unsigned long flags;
+		void __iomem *a;
+		uint32_t v;
+
+		raw_local_irq_save(flags);
+
+		a = INTC_REQUESTx(irqno);
+		v = readl(a);
+		v &= ~INTC_REQUESTx_ENABLE_MASK;
+		v |= INTC_REQUESTx_WE_ENABLE_MASK;
+		v |= INTC_REQUESTx_CLR_SWINT_MASK;
+		writel(v, a);
+
+		raw_local_irq_restore(flags);
+	}
+}
+
+static void u6_irq_unmask(uint32_t irqno)
+{
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		unsigned long flags;
+		void __iomem *a;
+		uint32_t v;
+
+		raw_local_irq_save(flags);
+
+		a = INTC_REQUESTx(irqno);
+		v = readl(a);
+		v |= INTC_REQUESTx_ENABLE_MASK;
+		v |= INTC_REQUESTx_WE_ENABLE_MASK;
+		v |= INTC_REQUESTx_CLR_SWINT_MASK;
+		writel(v, a);
+
+		raw_local_irq_restore(flags);
+	}
+}
+
+static int u6_irq_type(unsigned irqno, unsigned type)
+{
+	int l;
+	void __iomem *reg = INTC_REQUESTx(irqno);
+
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		if (type == IRQF_TRIGGER_LOW) {
+			l = (INTC_REQUESTx_ACTIVE_LOW_MASK
+			     | INTC_REQUESTx_WE_ACTIVE_LOW_MASK);
+		} else if (type == IRQF_TRIGGER_HIGH) {
+			l = (INTC_REQUESTx_WE_ACTIVE_LOW_MASK);
+		} else {
+			goto bad;
+		}
+
+		writel(l, reg);
+		return 0;
+
+	}
+
+bad:
+	return -EINVAL;
+}
+
+int u6_irq_enabled(uint32_t irqno)
+{
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		void __iomem *a = INTC_REQUESTx(irqno);
+		uint32_t v = readl(a);
+
+		return v & INTC_REQUESTx_ENABLE_MASK;
+	} else
+		return 0;
+}
+
+static struct irq_chip u6_irq_chip = {
+	.ack = u6_irq_mask,
+	.mask = u6_irq_mask,	/* disable irqs */
+	.unmask = u6_irq_unmask,	/* enable irqs */
+	.set_type = u6_irq_type,
+};
+
+
+#if defined(CONFIG_ARCH_U67XX)
+
+static const uint32_t u6_irq_config[] = {
+	0,			/* GHOST      0 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* EXTINT1    1 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* EXTINT2    2 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* EXTINT3    3 */
+	0,			/* RFRD       4 */
+	0,			/* MTU        5 */
+	0,			/* IIS        6 */
+	0,			/* USB        7 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* I2C2       8 */
+	0,			/* TVO        9 */
+	0,			/* 3G_WUP     10 */
+	0,			/* 3G_CALINT  11 */
+	0,			/* 3G_FRAME_IT 12 */
+	0,			/* GPADCINT    13 */
+	0,			/* ARM9_COMMTX 14 */
+	0,			/* ARM9_COMMRX 15 */
+	0,			/* KBS        16 */
+	0,			/* SCTU2      17 */
+	0,			/* SCTU1      18 */
+	0,			/* PIO1       19 */
+	0,			/* PIO2       20 */
+	0,			/* FINT0      21 */
+	0,			/* FINT1      22 */
+	0,			/* UART2      23 */
+	0,			/* UART1      24 */
+	0,			/* SPI2       25 */
+	0,			/* SPI1       26 */
+	0,			/* FCI        27 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* I2C1       28 */
+	0,			/* DMAU       29 */
+	0,			/* USIM       30 */
+	0,			/* RESERVED31 31 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* MSI        32 */
+	0,			/* JDI        33 */
+	0,			/* JDU        34 */
+	0,			/* NFI        35 */
+	0,			/* IPP        36 */
+	0,			/* VDC        37 */
+	0,			/* VEC        38 */
+	0,			/* VDE        39 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* CAM        40 */
+	0,			/* ETB_ACQ    41 */
+	0,			/* ETB_FULL   42 */
+	0,			/* DIGRF_TX   43 */
+	0,			/* DIGRF_RX   44 */
+	0,			/* RESERVED45 45 */
+	0,			/* FIR_FI     46 */
+	0,			/* FIR        47 */
+	0,			/* PDCU       48 */
+	0,			/* MC2SC0     49 */
+	0,			/* MC2SC1     50 */
+	0,			/* MC2SC2     51 */
+	0,			/* MC2SC3     52 */
+	0,			/* MC2SC4     53 */
+	0,			/* MC2SC5     54 */
+	0,			/* MC2SC6     55 */
+	0,			/* MC2SC7     56 */
+	0,			/* Reserved   57 */
+	0,			/* Reserved   58 */
+	0,			/* Reserved   59 */
+	0,			/* Reserved   60 */
+	0,			/* Reserved   61 */
+	0,			/* Reserved   62 */
+	0,			/* Reserved   63 */
+	0,			/* Reserved   64 */
+};
+
+#endif
+
+static const uint32_t u6_irq_irq_priority;
+static const uint32_t u6_irq_fiq_priority;
+
+void __init u6_init_irq(void)
+{
+	unsigned int irqno;
+
+	/* Clock interrupt controller.
+	 */
+	struct clk *clk = clk_get(NULL, "INTC");
+	clk_enable(clk);
+	clk_put(clk);
+
+	/* The address of the vector table INTCdata.asm is assumed to be aligned
+	 * to a 2KB boundary. Thus the register access value will be padded with
+	 * zeroes, which is conforming to the 'READ_ONLY' attributes of the LS
+	 * 11 bits. We are using the same table for both IRQ and FIQ.
+	 */
+	writel(0, INTC_VECTOR_FIQ_REG);	/* no vector IRQ */
+	writel(0, INTC_VECTOR_IRQ_REG);	/* no vector FIQ */
+
+	writel(u6_irq_irq_priority, INTC_PRIOMASK_IRQ_REG);
+	writel(u6_irq_fiq_priority, INTC_PRIOMASK_FIQ_REG);
+
+	/* Initialize the individual interrupt sources.
+	 */
+	for (irqno = 1; irqno < IRQ_COUNT; irqno += 1) {
+		void __iomem *a = INTC_REQUESTx(irqno);
+		uint32_t v = u6_irq_config[irqno];
+
+		v |= 4;
+		v |= INTC_REQUESTx_WE_ACTIVE_LOW_MASK;
+		v |= INTC_REQUESTx_WE_TARGET_MASK;
+		v |= INTC_REQUESTx_WE_PRIORITY_MASK;
+		v |= INTC_REQUESTx_WE_ENABLE_MASK;
+		v |= INTC_REQUESTx_CLR_SWINT_MASK;
+
+		writel(v, a);
+
+		set_irq_chip(irqno, &u6_irq_chip);
+		set_irq_handler(irqno, handle_level_irq);
+		set_irq_flags(irqno, IRQF_VALID | IRQF_PROBE);
+	}
+}
diff --git a/arch/arm/plat-u6xxx/timer.c b/arch/arm/plat-u6xxx/timer.c
new file mode 100644
index 0000000..b72e8cf
--- /dev/null
+++ b/arch/arm/plat-u6xxx/timer.c
@@ -0,0 +1,442 @@
+/*
+ * linux/arch/arm/plat-u6xxx/timer.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/clock.h>
+
+/*** System timer variable ***/
+struct sys_timer u6_timer;
+
+/*** Module definition ***/
+/*************************/
+
+#define MODULE_NAME "U6_TIMER"
+#define PKMOD MODULE_NAME ": "
+
+/*#define DEBUG*/
+#define U6_MMTU_CLOCK_SOURCE
+
+/*** MMTU clock devices ***/
+/*************************/
+
+/*** MMTU HW ip register index definition ***/
+#define MMTU_CON_IDX 0
+#define MMTU_TCVAL_IDX 0x4
+#define MMTU_PRESCALER_IDX 0x8
+#define MMTU_MATCH_CON_IDX 0xC
+#define MMTU_MATCH0_IDX 0x14
+#define MMTU_MATCH1_IDX 0x18
+
+#define MMTU_INT_OFFSET 0xFD0
+#define MMTU_MOD_CONF_IDX 0x4
+#define MMTU_INT_CLR_ENA_IDX 0x8
+#define MMTU_INT_SET_ENA_IDX 0xC
+#define MMTU_INT_STATUS_IDX 0x10
+#define MMTU_INT_ENABLE_IDX 0x14
+#define MMTU_INT_CLR_STAT_IDX 0x18
+#define MMTU_INT_SET_STAT_IDX 0x1C
+
+#define MMTU_IRQ_MASK		0x1
+#define MMTU_USED_MATCH_IDX	MMTU_MATCH0_IDX
+
+/* MMTU sys clock definition */
+#define MMTU_SYS_FRQ 13000000
+
+/*** MMTU Clock event device ***/
+#define MMTU_ROOT_FRQ 8000
+static int u6_mmtu_set_next_event(unsigned long cycles,
+				struct clock_event_device *evt);
+static void u6_mmtu_set_mode(enum clock_event_mode mode,
+				struct clock_event_device *evt);
+
+static struct clock_event_device clockevent_mmtu = {
+	.name = "mmtu_timer",
+	.rating = 360,
+	.shift = 30,
+	.features = CLOCK_EVT_FEAT_ONESHOT,
+	.set_next_event = u6_mmtu_set_next_event,
+	.set_mode = u6_mmtu_set_mode,
+};
+
+/*** MMTU Clock source device ***/
+#ifdef U6_MMTU_CLOCK_SOURCE
+static cycle_t u6_mmtu_read(struct clocksource *);
+
+static struct clocksource clocksource_mmtu = {
+	.name = "mmtu_timer",
+	.rating = 360,
+	.read = u6_mmtu_read,
+	.mask = CLOCKSOURCE_MASK(32),
+	.shift = 8,
+	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+#endif
+
+/*** MMTU driver ***/
+#define RELOAD_COUNTER_POWER_MMTU 32
+#define RELOAD_COUNTER_MMTU (1 << RELOAD_COUNTER_POWER_MMTU)
+
+struct mmtu_ctxt {
+	void __iomem *base;
+	uint32_t compvalue;
+	uint32_t endvalue;
+	struct clk *clk;
+	int mode;
+};
+
+struct mmtu_ctxt mmtu_table[1] = {
+	{
+		.base = U6_IO_ADDRESS(MMTU_BASE),
+	},
+};
+
+static inline struct mmtu_ctxt *u6_mmtu_get_context(int id)
+{
+	return &(mmtu_table[id]);
+}
+
+static inline int u6_mmtu_timer_start(unsigned long cycles, int id);
+static inline void u6_mmtu_clk_enable(int id);
+static inline void u6_mmtu_clk_disable(int id);
+
+static irqreturn_t
+u6_mmtu_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	uint8_t status, enable;
+	struct mmtu_ctxt *mmtu;
+
+	mmtu = u6_mmtu_get_context(0);
+
+	status = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_STATUS_IDX));
+	enable = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_ENABLE_IDX));
+
+	pr_debug(PKMOD "mmtu_timer_interrupt %d\n", status);
+
+	if (status & enable & MMTU_IRQ_MASK) {
+		struct clock_event_device *evt = &clockevent_mmtu;
+
+		writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
+					+ MMTU_INT_CLR_STAT_IDX));
+		writel(MMTU_IRQ_MASK,
+				(mmtu->base + MMTU_INT_OFFSET +
+				 MMTU_INT_CLR_ENA_IDX));
+
+		if (evt->event_handler)
+			evt->event_handler(evt);
+	}
+	return IRQ_HANDLED;
+}
+
+static struct irqaction u6_mmtu_timer_irq = {
+	.name = "U6 MMTU timer Tick",
+	.flags = IRQF_DISABLED,
+	.handler = (irq_handler_t) u6_mmtu_timer_interrupt,
+};
+
+static inline void u6_mmtu_clk_enable(int id)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	/* Clock Multimedia Timer Unit.
+	 */
+	if ((mmtu->clk != NULL) && (mmtu->mode == 0)) {
+		pr_debug(PKMOD "mmtu_clk_enable\n");
+		mmtu->mode = 1;
+		clk_enable(mmtu->clk);
+	}
+}
+
+static inline void u6_mmtu_clk_disable(int id)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	/* Clock Multimedia Timer Unit.
+	 */
+	if ((mmtu->clk != NULL) && (mmtu->mode == 1)) {
+		pr_debug(PKMOD "mmtu_clk_disable\n");
+		clk_disable(mmtu->clk);
+		mmtu->mode = 0;
+	}
+}
+
+static inline int u6_mmtu_timer_start(unsigned long cycles, int id)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	pr_debug(PKMOD "mmtu_timer_start %ld\n", cycles);
+	u6_mmtu_clk_enable(id);
+
+	/* MMTU limitation : can't set a value smaller or equal to tcval + 1 */
+	cycles = cycles < 2 ? 2 : cycles;
+
+	mmtu->compvalue = cycles;
+
+	mmtu->endvalue = mmtu->compvalue
+		+ readl((mmtu->base + MMTU_TCVAL_IDX));
+
+	writel(MMTU_IRQ_MASK,
+	       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+	writel(mmtu->endvalue, (mmtu->base + MMTU_USED_MATCH_IDX));
+
+	writel(MMTU_IRQ_MASK,
+	       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+
+	/* the value has already expired */
+	if ((mmtu->endvalue <= readl((mmtu->base + MMTU_TCVAL_IDX)))
+	    && (mmtu->endvalue > mmtu->compvalue)
+	    && !(readl((mmtu->base + MMTU_INT_OFFSET
+				    + MMTU_INT_STATUS_IDX)) & MMTU_IRQ_MASK))
+		writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
+					+ MMTU_INT_SET_STAT_IDX));
+
+	return 0;
+}
+
+static int u6_mmtu_timer_init(int id, unsigned long reload,
+			     unsigned long prescale, int over_it)
+{
+
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	pr_debug(PKMOD "mmtu_timer_init %d\n", id);
+
+	/* Enable clock */
+/*
+	u6_mmtu_clk_enable(id);
+	clk mngt not available yet
+	directly enable it
+*/
+	{
+		unsigned long flags;
+		unsigned long reg;
+		local_irq_save(flags);
+		reg = readl(CGU_GATESC2_REG);
+		reg |= 0x1 << 2;
+		writel(reg, CGU_GATESC2_REG);
+		local_irq_restore(flags);
+	}
+
+	/* Reset timer */
+	/* reset control register */
+	writel(0x0000, (mmtu->base + MMTU_CON_IDX));
+	writel(0x0002, (mmtu->base + MMTU_CON_IDX));
+	/* reset control register */
+	writel(0x0000, (mmtu->base + MMTU_CON_IDX));
+
+	/* clear whole enable irq register */
+	writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
+	/* clear whole status register */
+	writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+	/* reset pre-scaler reload register */
+	writel(0x00000000, (mmtu->base + MMTU_PRESCALER_IDX));
+
+	/* reset match control register */
+	writel(0x0000, (mmtu->base + MMTU_MATCH_CON_IDX));
+	/* reset match 0 register */
+	writel(0x00000000, (mmtu->base + MMTU_MATCH0_IDX));
+	/* reset match 1 register */
+	writel(0x00000000, (mmtu->base + MMTU_MATCH1_IDX));
+
+	/* Initialize timer */
+	writel(prescale - 1, (mmtu->base + MMTU_PRESCALER_IDX));
+	/* power of 2 system clock */
+	writel(reload, (mmtu->base + MMTU_MATCH0_IDX));
+
+	/* enable counter register */
+	writel(0x0001, (mmtu->base + MMTU_CON_IDX));
+
+	/* clear whole status register */
+	writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+	if (id == 0)
+		setup_irq(IRQ_MMTU, &u6_mmtu_timer_irq);
+
+	/* Disable clock */
+#ifndef U6_MMTU_CLOCK_SOURCE
+	u6_mmtu_clk_disable(id);
+#endif
+	return 0;
+}
+
+/*** MMTU Clock event device ***/
+
+static int u6_mmtu_set_next_event(unsigned long cycles,
+				 struct clock_event_device *evt)
+{
+	pr_debug(PKMOD "mmtu_set_next_event %ld\n", cycles);
+	u6_mmtu_timer_start(cycles, 0);
+
+	return 0;
+}
+
+static void u6_mmtu_set_mode(enum clock_event_mode mode,
+			    struct clock_event_device *evt)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
+	unsigned long reg;
+
+	pr_debug(PKMOD "mmtu_set_mode %d\n", mode);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_UNUSED:
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+		reg = readl((mmtu->base + MMTU_TCVAL_IDX));
+		writel(reg - 1, (mmtu->base + MMTU_USED_MATCH_IDX));
+
+#ifndef U6_MMTU_CLOCK_SOURCE
+		u6_mmtu_clk_disable(0);
+
+		if (mmtu->clk != NULL)
+			clk_put(mmtu->clk);
+#endif
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		if (mmtu->clk == NULL) {
+			mmtu->clk = clk_get(NULL, "MMTU");
+			if (IS_ERR(mmtu->clk))
+				mmtu->clk = NULL;
+		}
+
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+		break;
+	}
+}
+
+static void u6_clockevent_init_mmtu(void)
+{
+	printk(PKMOD "clockevent_init_mmtu\n");
+
+	/* prescale 13Mhz -> 1Mhz */
+#ifndef U6_MMTU_CLOCK_SOURCE
+	u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
+#endif
+
+	/* issue it is shorter than reality and generates spurious irq */
+	/*      clockevent_mmtu.mult = div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC,
+	 *      clockevent_mmtu.shift) + 1;*/
+	clockevent_mmtu.mult =
+		div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC, clockevent_mmtu.shift);
+
+	/*      clockevent_mmtu.max_delta_ns = div_sc(RELOAD_COUNTER_MMTU,
+	 *      clockevent_mmtu.mult, clockevent_mmtu.shift);*/
+	/*  In fact it is wider than the 32bits variable !!! */
+	clockevent_mmtu.max_delta_ns = 0xFFFFFFFF;
+
+	/*  MMTU HW limitation: match register can't be set w/ tcval+1 */
+	/*      clockevent_mmtu.min_delta_ns = div_sc(1, clockevent_mmtu.mult,
+	 *      clockevent_mmtu.shift)+1;*/
+	clockevent_mmtu.min_delta_ns =
+		div_sc(2, clockevent_mmtu.mult, clockevent_mmtu.shift) + 1;
+	/* avoid to much timer interrupt with 10us min between 2 irq */
+	if (clockevent_mmtu.min_delta_ns < 10000)
+		clockevent_mmtu.min_delta_ns = 10000;
+	else if (clockevent_mmtu.max_delta_ns < 10000)
+		clockevent_mmtu.min_delta_ns = clockevent_mmtu.max_delta_ns>>1;
+
+	clockevent_mmtu.cpumask = get_cpu_mask(0);
+	clockevents_register_device(&clockevent_mmtu);
+
+	u6_mmtu_set_next_event(MMTU_ROOT_FRQ / HZ, &clockevent_mmtu);
+}
+
+/*** MMTU Clock source device ***/
+#ifdef U6_MMTU_CLOCK_SOURCE
+
+static cycle_t u6_mmtu_read(struct clocksource *source)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
+
+	return readl(mmtu->base + MMTU_TCVAL_IDX);
+}
+
+static void u6_clocksource_init_mmtu(void)
+{
+	printk(PKMOD "clocksource_init_mmtu\n");
+
+	if (MMTU_ROOT_FRQ >= 1000000)
+		clocksource_mmtu.mult =
+			clocksource_khz2mult((MMTU_ROOT_FRQ / 1000),
+					clocksource_mmtu.shift);
+	else
+		clocksource_mmtu.mult = clocksource_hz2mult((MMTU_ROOT_FRQ),
+				clocksource_mmtu.shift);
+
+	u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
+
+	clocksource_register(&clocksource_mmtu);
+}
+
+#endif
+
+/*** System timer init ***/
+/*************************/
+
+void __init u6_timer_init(void)
+{
+	printk(PKMOD "mmtu_timer_init\n");
+
+#ifdef U6_MMTU_CLOCK_SOURCE
+	u6_clocksource_init_mmtu();
+#endif
+
+	u6_clockevent_init_mmtu();
+}
+
+struct sys_timer u6_timer = {
+	.init = u6_timer_init,
+};
+
+#ifdef CONFIG_U6_POWER_SYSFS
+static int __init u6_mmtu_init_sysfs(void)
+{
+	printk(PKMOD "mmtu_init_sysfs\n");
+
+#ifdef U6_MMTU_CLOCK_SOURCE
+	if (sysfs_create_group(&u6_power_kobj, &dbs_attr_srce_group))
+		printk(PKMOD "Unable to register %s in sysfs\n",
+		       dbs_attr_srce_group.name);
+#endif
+
+	if (sysfs_create_group(&u6_power_kobj, &dbs_attr_event_group))
+		printk(PKMOD "Unable to register %s in sysfs\n",
+		       dbs_attr_event_group.name);
+
+	return 0;
+}
+
+module_init(u6_mmtu_init_sysfs);
+#endif
-- 
1.7.1


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

* [PATCH 1/5] U6/U6715 ARM architecture files
@ 2010-08-05 12:28   ` Philippe Langlais
  0 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 arch/arm/Kconfig                               |   11 +
 arch/arm/Makefile                              |    2 +
 arch/arm/mach-u67xx/Kconfig                    |   12 +
 arch/arm/mach-u67xx/Makefile                   |   11 +
 arch/arm/mach-u67xx/Makefile.boot              |    4 +
 arch/arm/mach-u67xx/board_u67xx_wavex.c        |   47 +++
 arch/arm/mach-u67xx/devices.c                  |   28 ++
 arch/arm/plat-u6xxx/Kconfig                    |   22 ++
 arch/arm/plat-u6xxx/Makefile                   |    8 +
 arch/arm/plat-u6xxx/include/mach/cpu.h         |   36 ++
 arch/arm/plat-u6xxx/include/mach/debug-macro.S |   38 ++
 arch/arm/plat-u6xxx/include/mach/entry-macro.S |   32 ++
 arch/arm/plat-u6xxx/include/mach/hardware.h    |   41 +++
 arch/arm/plat-u6xxx/include/mach/io.h          |   30 ++
 arch/arm/plat-u6xxx/include/mach/irqs.h        |  102 ++++++
 arch/arm/plat-u6xxx/include/mach/memory.h      |   17 +
 arch/arm/plat-u6xxx/include/mach/regs-u6.h     |  121 +++++++
 arch/arm/plat-u6xxx/include/mach/system.h      |   42 +++
 arch/arm/plat-u6xxx/include/mach/timer.h       |   16 +
 arch/arm/plat-u6xxx/include/mach/timex.h       |   23 ++
 arch/arm/plat-u6xxx/include/mach/uncompress.h  |   47 +++
 arch/arm/plat-u6xxx/include/mach/vmalloc.h     |   10 +
 arch/arm/plat-u6xxx/io.c                       |   34 ++
 arch/arm/plat-u6xxx/irq.c                      |  254 ++++++++++++++
 arch/arm/plat-u6xxx/timer.c                    |  442 ++++++++++++++++++++++++
 25 files changed, 1430 insertions(+), 0 deletions(-)
 create mode 100644 arch/arm/mach-u67xx/Kconfig
 create mode 100644 arch/arm/mach-u67xx/Makefile
 create mode 100644 arch/arm/mach-u67xx/Makefile.boot
 create mode 100644 arch/arm/mach-u67xx/board_u67xx_wavex.c
 create mode 100644 arch/arm/mach-u67xx/devices.c
 create mode 100644 arch/arm/plat-u6xxx/Kconfig
 create mode 100644 arch/arm/plat-u6xxx/Makefile
 create mode 100644 arch/arm/plat-u6xxx/include/mach/cpu.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/debug-macro.S
 create mode 100644 arch/arm/plat-u6xxx/include/mach/entry-macro.S
 create mode 100644 arch/arm/plat-u6xxx/include/mach/hardware.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/io.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/irqs.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/memory.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/regs-u6.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/system.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/timer.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/timex.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/uncompress.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/vmalloc.h
 create mode 100644 arch/arm/plat-u6xxx/io.c
 create mode 100644 arch/arm/plat-u6xxx/irq.c
 create mode 100644 arch/arm/plat-u6xxx/timer.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index cf30fc9..1ae089c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -739,6 +739,14 @@ config ARCH_U300
 	help
 	  Support for ST-Ericsson U300 series mobile platforms.
 
+config PLAT_U6XXX
+	bool "ST-Ericsson U6XXX Series"
+	select CPU_ARM926T
+	select GENERIC_GPIO
+	select ARCH_REQUIRE_GPIOLIB
+	help
+	  Support for ST-Ericsson's U6XXX architecture
+
 config ARCH_U8500
 	bool "ST-Ericsson U8500 Series"
 	select CPU_V7
@@ -910,6 +918,9 @@ source "arch/arm/mach-tegra/Kconfig"
 
 source "arch/arm/mach-u300/Kconfig"
 
+source "arch/arm/plat-u6xxx/Kconfig"
+source "arch/arm/mach-u67xx/Kconfig"
+
 source "arch/arm/mach-ux500/Kconfig"
 
 source "arch/arm/mach-versatile/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 2de67c9..c510a64 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -176,6 +176,7 @@ machine-$(CONFIG_ARCH_STMP378X)		:= stmp378x
 machine-$(CONFIG_ARCH_STMP37XX)		:= stmp37xx
 machine-$(CONFIG_ARCH_TEGRA)		:= tegra
 machine-$(CONFIG_ARCH_U300)		:= u300
+machine-$(CONFIG_ARCH_U67XX)		:= u67xx
 machine-$(CONFIG_ARCH_U8500)		:= ux500
 machine-$(CONFIG_ARCH_VERSATILE)	:= versatile
 machine-$(CONFIG_ARCH_VEXPRESS)		:= vexpress
@@ -200,6 +201,7 @@ plat-$(CONFIG_PLAT_PXA)		:= pxa
 plat-$(CONFIG_PLAT_S3C24XX)	:= s3c24xx samsung
 plat-$(CONFIG_PLAT_S5P)		:= s5p samsung
 plat-$(CONFIG_PLAT_SPEAR)	:= spear
+plat-$(CONFIG_PLAT_U6XXX)	:= u6xxx
 plat-$(CONFIG_PLAT_VERSATILE)	:= versatile
 
 ifeq ($(CONFIG_ARCH_EBSA110),y)
diff --git a/arch/arm/mach-u67xx/Kconfig b/arch/arm/mach-u67xx/Kconfig
new file mode 100644
index 0000000..f02f6e2
--- /dev/null
+++ b/arch/arm/mach-u67xx/Kconfig
@@ -0,0 +1,12 @@
+comment "U67XX Board Type"
+	depends on ARCH_U67XX
+
+choice
+	depends on ARCH_U67XX
+	prompt "Choose the U67XX Board type"
+	default MACH_U67XX_WAVEC_2GB
+	help
+		Choose the ST-Ericsson Reference Design Board
+config MACH_U67XX_WAVEC_2GB
+	bool "U67XX WaveC Board with 2Gb Micron combo"
+endchoice
diff --git a/arch/arm/mach-u67xx/Makefile b/arch/arm/mach-u67xx/Makefile
new file mode 100644
index 0000000..38cf624
--- /dev/null
+++ b/arch/arm/mach-u67xx/Makefile
@@ -0,0 +1,11 @@
+#
+## Makefile for the linux kernel, hardware dependent part of ST-Ericsson U67xx
+#
+#
+## Object file lists.
+
+# Common support
+obj-y			:= devices.o
+
+# Specific board support
+obj-$(CONFIG_MACH_U67XX_WAVEC_2GB) += board_u67xx_wavex.o
diff --git a/arch/arm/mach-u67xx/Makefile.boot b/arch/arm/mach-u67xx/Makefile.boot
new file mode 100644
index 0000000..c4e8c02
--- /dev/null
+++ b/arch/arm/mach-u67xx/Makefile.boot
@@ -0,0 +1,4 @@
+   zreladdr-y		:= 0x20008000
+params_phys-y		:= 0x20000100
+initrd_phys-y		:= 0x26000000
+
diff --git a/arch/arm/mach-u67xx/board_u67xx_wavex.c b/arch/arm/mach-u67xx/board_u67xx_wavex.c
new file mode 100644
index 0000000..633989f
--- /dev/null
+++ b/arch/arm/mach-u67xx/board_u67xx_wavex.c
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/mach-u67xx/board_u67xx_wavex.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Platform machine definition for U6XXX WAVEx Board.
+ */
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/timer.h>
+
+/* List of board specific devices */
+static struct platform_device *devices[] __initdata = {
+};
+
+void __init u67xx_init(void)
+{
+	/* Add specific board devices */
+	platform_add_devices(devices, ARRAY_SIZE(devices));
+}
+
+MACHINE_START(U6715, "STE_U67xx_refd")
+	/* Maintainer: Philippe Langlais <philippe.langlais@stericsson.com> */
+	.phys_io	= UART1_BASE,
+	.io_pg_offst	= (IO_ADDRESS(UART1_BASE) >> 18) & 0xfffc,
+	.boot_params	= PHYS_OFFSET + 0x100,
+	.map_io		= u6xxx_map_io,
+	.init_irq	= u6_init_irq,
+	.init_machine	= u67xx_init,
+	.timer		= &u6_timer,
+MACHINE_END
+
diff --git a/arch/arm/mach-u67xx/devices.c b/arch/arm/mach-u67xx/devices.c
new file mode 100644
index 0000000..1d00b35
--- /dev/null
+++ b/arch/arm/mach-u67xx/devices.c
@@ -0,0 +1,28 @@
+/*
+ * linux/arch/arm/mach-u67xx/devices.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Device specification for the U67XX
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+
+/* list of devices */
+static struct platform_device *platform_devs[] __initdata = {
+};
+
+/* register generic devices */
+
+static int __init u67xx_devices_init(void)
+{
+	platform_add_devices(platform_devs, ARRAY_SIZE(platform_devs));
+	return 0;
+}
+
+arch_initcall(u67xx_devices_init);
diff --git a/arch/arm/plat-u6xxx/Kconfig b/arch/arm/plat-u6xxx/Kconfig
new file mode 100644
index 0000000..10929ea
--- /dev/null
+++ b/arch/arm/plat-u6xxx/Kconfig
@@ -0,0 +1,22 @@
+if PLAT_U6XXX
+
+menu "STE U6XXX Implementations"
+
+choice
+	prompt "U67XX System Type"
+	default ARCH_U67XX
+
+config ARCH_U67XX
+	bool "U67XX"
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	select U6_MTU_TIMER
+endchoice
+
+endmenu
+
+config U6_MTU_TIMER
+	bool
+	default y
+
+endif
diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
new file mode 100644
index 0000000..12c832c
--- /dev/null
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for the linux kernel hardware independant part of STE U6XXX.
+#
+
+# Common support
+obj-y := io.o irq.o
+
+obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/include/mach/cpu.h b/arch/arm/plat-u6xxx/include/mach/cpu.h
new file mode 100644
index 0000000..4f1f57f
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/cpu.h
@@ -0,0 +1,36 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/cpu.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * U6 cpu type detection
+ */
+
+#ifndef __ASM_PLAT_CPU_H
+#define __ASM_PLAT_CPU_H
+
+/*
+ * Macros to group U6xxx into cpu classes.
+ * These can be used in most places.
+ * cpu_is_u67xx():	True for U67XX
+ */
+
+#define GET_U6XXX_CLASS		((readl(SCON_SYSVER_REG)&0x0F00)>>8)
+#define GET_U6XXX_SUBCLASS	((readl(SCON_SYSVER_REG)&0x0FF0)>>4)
+
+#define cpu_is_u67xx()		0
+#define cpu_is_u67xx_v2()	0
+#define cpu_is_u67xx_v3()	0
+
+#if defined(CONFIG_ARCH_U67XX)
+#  undef cpu_is_u67xx
+#  undef cpu_is_u67xx_v2
+#  undef cpu_is_u67xx_v3
+#  define cpu_is_u67xx()	(GET_U6XXX_CLASS == 0x6)
+#  define cpu_is_u67xx_v2()	(GET_U6XXX_SUBCLASS == 0x62)
+#  define cpu_is_u67xx_v3()	(GET_U6XXX_SUBCLASS == 0x63)
+#endif
+
+#endif /* __ASM_PLAT_CPU_H */
+
diff --git a/arch/arm/plat-u6xxx/include/mach/debug-macro.S b/arch/arm/plat-u6xxx/include/mach/debug-macro.S
new file mode 100644
index 0000000..039c810
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/debug-macro.S
@@ -0,0 +1,38 @@
+/* linux/arch/arm/plat-u6xxx/include/mach/debug-macro.S
+ *
+ * Debugging macro include header
+ *
+ *  Copyright (C) 2010 ST-Ericsson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+*/
+
+#include <mach/hardware.h>
+
+		.macro	addruart,rx
+		mrc	p15, 0, \rx, c1, c0
+		tst	\rx, #1                       @ MMU enabled?
+		ldreq	\rx, = UART1_BASE             @ physical base address
+		ldrne	\rx, = IO_ADDRESS(UART1_BASE) @ virtual base
+		.endm
+
+		.macro	senduart,rd,rx
+		strb	\rd, [\rx]
+		.endm
+
+		.macro	waituart,rd,rx
+1001:
+		ldr	\rd, [\rx, #20]
+		tst	\rd, #1 << 5	@ LSR_THRE - 0 when full
+		beq	1001b
+		.endm
+
+		.macro	busyuart,rd,rx
+1001:
+		ldr	\rd, [\rx, #20]
+		tst	\rd, #1 << 6	@ LSR_TEMT - 0 when busy
+		beq	1001b
+		.endm
diff --git a/arch/arm/plat-u6xxx/include/mach/entry-macro.S b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
new file mode 100644
index 0000000..cae8824
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/entry-macro.S
@@ -0,0 +1,32 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/entry-macro.S
+ *
+ * Low-level IRQ helper macros for U6-based platforms
+ * Copyright (C) ST-Ericsson SA 2010
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
+	.macro	disable_fiq
+	.endm
+
+	.macro  get_irqnr_preamble, base, tmp
+	ldr	\base, =IO_ADDRESS(INTC_BASE)
+	.endm
+
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	ldr	\irqnr, [\base, #INTC_VECTOR_IRQ_OFFSET] @ load intc vector reg
+	mov	\irqnr, \irqnr, lsr #3              @ Bits[0..2] are reserved
+	ands	\irqnr, \irqnr, #0x00FF             @ mask Bits[11..31]
+	.endm
+
+	.macro	irq_prio_table
+	.endm
+
diff --git a/arch/arm/plat-u6xxx/include/mach/hardware.h b/arch/arm/plat-u6xxx/include/mach/hardware.h
new file mode 100644
index 0000000..79199ec
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/hardware.h
@@ -0,0 +1,41 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/hardware.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+#ifndef __ASSEMBLER__
+#include <mach/cpu.h>
+#endif
+
+/*
+ * Processor specific registers defines
+ */
+#include "regs-u6.h"
+
+/*
+ * Where in virtual memory the IO devices (timers, system controllers
+ * and so on)
+ */
+
+#define IO_BASE_VIRT            0xE8000000        /* VA of IO */
+
+/* macro to get at IO space when running virtually */
+/* this version gives more IO address range to map*/
+#define IO_ADDRESS(x)   ((x) - IO_BASE_PHYS + IO_BASE_VIRT)
+
+/* typesafe io address */
+#define __io_address(n)		__io(IO_ADDRESS(n))
+
+/*
+ * Board specific defines
+ */
+
+#endif
+
diff --git a/arch/arm/plat-u6xxx/include/mach/io.h b/arch/arm/plat-u6xxx/include/mach/io.h
new file mode 100644
index 0000000..e8a93b4
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/io.h
@@ -0,0 +1,30 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/io.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Dummy IO map & IO definitions
+ */
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT 0xffffffff
+
+#define __io(a)       __typesafe_io(a)
+#define __mem_pci(a)  (a)
+
+/*
+ * I/O mapping
+ */
+#ifdef __ASSEMBLER__
+#define IOMEM(x)		(x)
+#else
+#define IOMEM(x)		((void __force __iomem *)(x))
+#endif
+#define U6_IO_ADDRESS(pa)	IOMEM(IO_ADDRESS(pa))
+
+void u6xxx_map_io(void);
+
+#endif /* __ASM_ARM_ARCH_IO_H */
diff --git a/arch/arm/plat-u6xxx/include/mach/irqs.h b/arch/arm/plat-u6xxx/include/mach/irqs.h
new file mode 100644
index 0000000..2943882
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/irqs.h
@@ -0,0 +1,102 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/irqs.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_PLAT_U6_IRQS_H
+#define __ASM_PLAT_U6_IRQS_H
+
+#define IRQ_COUNT             65
+
+/* external IRQ definition EXTINT */
+#define IRQ_EXTINT(num)       (IRQ_COUNT+(num))
+#define EXTINT_NUM(irq)       ((irq)-IRQ_COUNT)
+
+#define NR_EXTINT             24
+#define NR_IRQS	              (IRQ_COUNT+NR_EXTINT)
+
+#ifndef __ASSEMBLY__
+extern unsigned char extint_to_gpio[NR_EXTINT];
+
+#define EXTINT_TO_GPIO(gpio_irq)    extint_to_gpio[gpio_irq-IRQ_COUNT]
+
+void /*__init */ u6_init_irq(void);
+void u6_monitor_irq_enter(unsigned int irq);
+void u6_monitor_irq_exit(unsigned int irq);
+#endif /* __ASSEMBLY__ */
+
+/*
+ * Interrupt numbers
+ */
+#define IRQ_GHOST                       0
+#define IRQ_EXTINT1                     1
+#define IRQ_EXTINT2                     2
+#define IRQ_EXTINT3                     3
+#define IRQ_RFRD                        4
+#define IRQ_MMTU                        5
+#define IRQ_IIS                         6
+#define IRQ_USB                         7
+#define IRQ_I2C2                        8
+#define IRQ_TVO                         9
+#define IRQ_3G_WUP                      10
+#define IRQ_3G_CALINT                   11
+#define IRQ_3G_FRAME_IT                 12
+#define IRQ_GPADCINT                    13
+#define IRQ_ARM9_COMMTX                 14
+#define IRQ_ARM9_COMMRX                 15
+#define IRQ_KBS                         16
+#define IRQ_SCTU2                       17
+#define IRQ_SCTU1                       18
+#define IRQ_PIO1                        19
+#define IRQ_PIO2                        20
+#define IRQ_FINT0                       21
+#define IRQ_FINT1                       22
+#define IRQ_UART2                       23
+#define IRQ_UART1                       24
+#define IRQ_SPI2                        25
+#define IRQ_SPI1                        26
+#define IRQ_FCI                         27
+#define IRQ_I2C1                        28
+#define IRQ_DMAU                        29
+#define IRQ_USIM                        30
+#define IRQ_HSDPA                       31    /* reserved */
+#define IRQ_MSI                         32
+#define IRQ_JDI                         33
+#define IRQ_JDU                         34
+#define IRQ_NFI                         35
+#define IRQ_IPP                         36
+#define IRQ_VDC                         37
+#define IRQ_VEC                         38
+#define IRQ_VDE                         39
+#define IRQ_CAM                         40
+#define IRQ_ETB_ACQ                     41
+#define IRQ_ETB_FULL                    42
+#define IRQ_RESERVED43                  43
+#define IRQ_RESERVED44                  44
+#define IRQ_RESERVED45                  45    /* reserved */
+#define IRQ_RESERVED46                  46
+#define IRQ_RESERVED47                  47
+#define IRQ_PDCU                        48
+#define IRQ_MC2SC0                      49
+#define IRQ_MC2SC1                      50
+#define IRQ_MC2SC2                      51
+#define IRQ_MC2SC3                      52
+#define IRQ_MC2SC4                      53
+#define IRQ_MC2SC5                      54
+#define IRQ_MC2SC6                      55
+#define IRQ_MC2SC7                      56
+
+/* INTC VECTOR_IRQ Register (32 bits) */
+#define INTC_VECTOR_IRQ_OFFSET   0x100
+
+/* INTC REQUEST 64 Registers (32 bits) */
+#define INTC_REQUEST1_OFFSET     0x404
+#define INTC_REQUEST64_OFFSET    0x500
+
+/* interrupt x [1..64] request configuration */
+#define INTC_REQUESTx(x)  U6_IO_ADDRESS(INTC_BASE+INTC_REQUEST1_OFFSET+(x-1)*4)
+
+#endif /* __ASM_PLAT_U6_IRQS_H */
diff --git a/arch/arm/plat-u6xxx/include/mach/memory.h b/arch/arm/plat-u6xxx/include/mach/memory.h
new file mode 100644
index 0000000..71a5c60
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/memory.h
@@ -0,0 +1,17 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/memory.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset.
+ */
+#define PHYS_OFFSET		UL(0x20000000)
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/regs-u6.h b/arch/arm/plat-u6xxx/include/mach/regs-u6.h
new file mode 100644
index 0000000..aa2fbb0
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/regs-u6.h
@@ -0,0 +1,121 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/regs-u6.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * Basic register address definitions in physical memory
+ */
+
+#if !defined(__REGS_U6_H__)
+#define __REGS_U6_H__
+
+#define IO_BASE_PHYS              0xC1000000  /* phys base address of reg */
+#define IO_SIZE                   0x03400000  /* How much */
+
+/*
+ * System Controller Core devices base address table
+ */
+
+/* DMA Controller */
+#define DMAU_BASE                 (IO_BASE_PHYS + 0x0000000)
+
+/* Interrupt Controller */
+#define INTC_BASE                 (IO_BASE_PHYS + 0x0100000)
+
+/* SDRam controller */
+#define SDI_BASE                  (IO_BASE_PHYS + 0x0200000)
+
+/* Nand Flash Inteface controller */
+#define NFI_BASE                  (IO_BASE_PHYS + 0x0300000)
+
+/* USB controller */
+#define USB_BASE                  (IO_BASE_PHYS + 0x0400000)
+
+/* Video Display Engine */
+#define VDE_BASE                  (IO_BASE_PHYS + 0x0500000)
+
+/* Video Decoder */
+#define VDC_BASE                  (IO_BASE_PHYS + 0x1000000)
+
+/* Viedo Encoder */
+#define VEC_BASE                  (IO_BASE_PHYS + 0x1100000)
+
+/* Texture Codec, MPEG4 encoder sub module */
+#define TC_BASE                   (IO_BASE_PHYS + 0x1102000)
+
+/* Image Post-Processor */
+#define IPP2_BASE                 (IO_BASE_PHYS + 0x1200000)
+
+/* JPEG Decoder Unit */
+#define JDU_BASE                  (IO_BASE_PHYS + 0x1300000)
+
+/* TV output controller */
+#define TVO_BASE                  (IO_BASE_PHYS + 0x1400000)
+
+/* Camera controller */
+#define CAM_BASE                  (IO_BASE_PHYS + 0x1800000)
+
+/* External Bus Interfaces */
+#define EBI_BASE                  (IO_BASE_PHYS + 0x2001000)
+
+/* SPI controllers */
+#define SPI1_BASE                 (IO_BASE_PHYS + 0x2002000)
+#define SPI2_BASE                 (IO_BASE_PHYS + 0x2003000)
+
+/* SD/MMC controller */
+#define FCI_BASE                  (IO_BASE_PHYS + 0x2008000)
+
+/* Crypto Acceleration Engine */
+#define CAE_BASE                  (IO_BASE_PHYS + 0x2009000)
+
+/* Multimedia Timer Unit, aka MTU in Datasheet */
+#define MMTU_BASE                 (IO_BASE_PHYS + 0x2101000)
+
+/* System controller timer units */
+#define SCTU1_BASE                (IO_BASE_PHYS + 0x2102000)
+#define SCTU2_BASE                (IO_BASE_PHYS + 0x2103000)
+
+/* General Purpose I/O units */
+#define GPIOA_BASE                (IO_BASE_PHYS + 0x2104000)
+#define GPIOB_BASE                (IO_BASE_PHYS + 0x2104200)
+#define GPIOC_BASE                (IO_BASE_PHYS + 0x2104400)
+#define GPIOD_BASE                (IO_BASE_PHYS + 0x2104600)
+#define GPIOE_BASE                (IO_BASE_PHYS + 0x2104800)
+#define GPIOF_BASE                (IO_BASE_PHYS + 0x2104A00)
+
+/* External Interrupt controller */
+#define EXTINT_BASE               (IO_BASE_PHYS + 0x2105000)
+
+/* Keyboard Scanner */
+#define KBS_BASE                  (IO_BASE_PHYS + 0x2106000)
+
+/* Pulse Width Modulators */
+#define PWM1_BASE                 (IO_BASE_PHYS + 0x2108000)
+#define PWM2_BASE                 (IO_BASE_PHYS + 0x2109000)
+#define PWM3_BASE                 (IO_BASE_PHYS + 0x210A000)
+
+/* I2C controllers */
+#define I2C1_BASE                 (IO_BASE_PHYS + 0x210C000)
+#define I2C2_BASE                 (IO_BASE_PHYS + 0x210D000)
+
+/* UARTs */
+#define UART1_BASE                (IO_BASE_PHYS + 0x210E000)
+#define UART2_BASE                (IO_BASE_PHYS + 0x210F000)
+
+/* Clock Generation Unit */
+#define CGU_BASE                  (IO_BASE_PHYS + 0x2200000)
+
+/* Time base Unit */
+#define TBU_BASE                  (IO_BASE_PHYS + 0x2201000)
+
+/* Power Down Control Unit */
+#define PDCU_BASE                 (IO_BASE_PHYS + 0x2202000)
+
+/* Watchdog & Reset Unit */
+#define WDRU_BASE                 (IO_BASE_PHYS + 0x2203000)
+
+/* System Configuration */
+#define SCON_BASE                 (IO_BASE_PHYS + 0x2204000)
+
+#endif /* __REGS_U6_H__ */
diff --git a/arch/arm/plat-u6xxx/include/mach/system.h b/arch/arm/plat-u6xxx/include/mach/system.h
new file mode 100644
index 0000000..8799e57
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/system.h
@@ -0,0 +1,42 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/system.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+#include <mach/hardware.h>
+
+/* Watchdog & Reset Unit TIMER Register (16 bits) */
+#define WDRU_TIM_OFFSET                0x4
+
+static inline void arch_idle(void)
+{
+	/*
+	 * This should do all the clock switching
+	 * and wait for interrupt tricks
+	 */
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	unsigned long flags;
+	/*
+	 * To reset, we hit the on-board reset register
+	 * in the system FPGA
+	 */
+	/* diasble HW interruption */
+	raw_local_irq_save(flags);
+	/* load watchdog with reset value */
+	writel(0x5, IO_ADDRESS(WDRU_BASE + WDRU_TIM_OFFSET));
+	/* wait for wachdog expiration */
+	while (1)
+		;
+}
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/timer.h b/arch/arm/plat-u6xxx/include/mach/timer.h
new file mode 100644
index 0000000..614d6cf
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/timer.h
@@ -0,0 +1,16 @@
+/*
+ *  linux/arch/arm/plat-u6xxx/include/mach/timer.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef __PLAT_TIMER_H
+#define __PLAT_TIMER_H
+
+struct sys_timer;
+
+extern struct sys_timer u6_timer;
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/timex.h b/arch/arm/plat-u6xxx/include/mach/timex.h
new file mode 100644
index 0000000..1e71241
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/timex.h
@@ -0,0 +1,23 @@
+/*
+ *  linux/arch/arm/plat-u6xxx/include/mach/timex.h
+ *
+ *  Integrator architecture timex specifications
+ *
+ *  Copyright (C) 1999 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#define CLOCK_TICK_RATE		(50000000 / 16)
diff --git a/arch/arm/plat-u6xxx/include/mach/uncompress.h b/arch/arm/plat-u6xxx/include/mach/uncompress.h
new file mode 100644
index 0000000..e37f0b4
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/uncompress.h
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/uncompress.h
+ *
+ * Copyright (C) 2010 ST-Ericsson SA
+ * Copyright (C) 2003 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/io.h>
+#include "mach/hardware.h"
+
+/* UART THR Register (8 bits) */
+#define UART1_THR_OFFSET      0x0
+#define UART1_THR_REG         IO_ADDRESS(UART1_BASE + UART1_THR_OFFSET)
+
+/* UART LSR Register (8 bits) */
+#define UART1_LSR_OFFSET      0x14
+#define UART1_LSR_REG         IO_ADDRESS(UART1_BASE + UART1_LSR_OFFSET)
+
+static void putc(int c)
+{
+	while (!(readb(UART1_LSR_REG) & (1<<5)))
+		barrier();
+	writeb(c, UART1_THR_REG);
+}
+
+static inline void flush(void)
+{
+}
+
+/* nothing to do */
+#define arch_decomp_setup()
+
+#define arch_decomp_wdog()
diff --git a/arch/arm/plat-u6xxx/include/mach/vmalloc.h b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
new file mode 100644
index 0000000..cb89107
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/vmalloc.h
@@ -0,0 +1,10 @@
+/*
+ * linux/arch/arm/plat-u6/include/mach/vmalloc.h
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Virtual memory allocations
+ * End must be above the I/O registers and on an even 2MiB boundary.
+ */
+#define VMALLOC_END       0xe8000000UL
diff --git a/arch/arm/plat-u6xxx/io.c b/arch/arm/plat-u6xxx/io.c
new file mode 100644
index 0000000..01d447c
--- /dev/null
+++ b/arch/arm/plat-u6xxx/io.c
@@ -0,0 +1,34 @@
+/*
+ * linux/arch/arm/plat-u6xxx/io.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+
+#include <asm/mach/map.h>
+
+
+static struct map_desc u6xxx_io_desc[] __initdata = {
+	{
+		.virtual  = IO_BASE_VIRT,	/* only peripherals */
+		.pfn      = __phys_to_pfn(IO_BASE_PHYS),
+		.length   = IO_SIZE,
+		.type     = MT_DEVICE,
+	}
+};
+
+void __init u6xxx_map_io(void)
+{
+    iotable_init(u6xxx_io_desc, ARRAY_SIZE(u6xxx_io_desc));
+}
+
diff --git a/arch/arm/plat-u6xxx/irq.c b/arch/arm/plat-u6xxx/irq.c
new file mode 100644
index 0000000..2ede5f0
--- /dev/null
+++ b/arch/arm/plat-u6xxx/irq.c
@@ -0,0 +1,254 @@
+/*
+ *  linux/arch/arm/plat-u6xxx/irq.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <asm/irq.h>
+#include <mach/hardware.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/irq.h>
+#include <mach/irqs.h>		/* U6 specific constants, types */
+
+/* INTC PRIOMASK_IRQ Register (32 bits) */
+#define INTC_PRIOMASK_IRQ_OFFSET 0x0
+#define INTC_PRIOMASK_IRQ_REG  IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_IRQ_OFFSET)
+
+/* INTC PRIOMASK_FIQ Register (32 bits) */
+#define INTC_PRIOMASK_FIQ_OFFSET 0x4
+#define INTC_PRIOMASK_FIQ_REG  IO_ADDRESS(INTC_BASE + INTC_PRIOMASK_FIQ_OFFSET)
+
+/* INTC VECTOR_IRQ Register (32 bits) */
+#define INTC_VECTOR_IRQ_REG      IO_ADDRESS(INTC_BASE + INTC_VECTOR_IRQ_OFFSET)
+
+/* INTC VECTOR_FIQ Register (32 bits) */
+#define INTC_VECTOR_FIQ_OFFSET   0x104
+#define INTC_VECTOR_FIQ_REG      IO_ADDRESS(INTC_BASE + INTC_VECTOR_FIQ_OFFSET)
+
+/* INTC PENDING_* Registers (32 bits) */
+#define INTC_PENDING_1_OFFSET    0x200
+#define INTC_PENDING_2_OFFSET    0x204
+#define INTC_PENDING_3_OFFSET    0x208
+#define INTC_FEATURES_OFFSET     0x300
+
+#define INTC_REQUESTx_PENDING_MASK       (1 << 31)
+#define INTC_REQUESTx_SET_SWINT_MASK     (1 << 30)
+#define INTC_REQUESTx_CLR_SWINT_MASK     (1 << 29)
+#define INTC_REQUESTx_WE_PRIORITY_MASK   (1 << 28)
+#define INTC_REQUESTx_WE_TARGET_MASK     (1 << 27)
+#define INTC_REQUESTx_WE_ENABLE_MASK     (1 << 26)
+#define INTC_REQUESTx_WE_ACTIVE_LOW_MASK (1 << 25)
+#define INTC_REQUESTx_ACTIVE_LOW_MASK    (1 << 17)
+#define INTC_REQUESTx_ENABLE_MASK        (1 << 16)
+#define INTC_REQUESTx_TARGET_MASK        (1 <<  8)
+
+#define INTC_IID_USB_LP_INT 13
+
+static void u6_irq_mask(uint32_t irqno)
+{
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		unsigned long flags;
+		void __iomem *a;
+		uint32_t v;
+
+		raw_local_irq_save(flags);
+
+		a = INTC_REQUESTx(irqno);
+		v = readl(a);
+		v &= ~INTC_REQUESTx_ENABLE_MASK;
+		v |= INTC_REQUESTx_WE_ENABLE_MASK;
+		v |= INTC_REQUESTx_CLR_SWINT_MASK;
+		writel(v, a);
+
+		raw_local_irq_restore(flags);
+	}
+}
+
+static void u6_irq_unmask(uint32_t irqno)
+{
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		unsigned long flags;
+		void __iomem *a;
+		uint32_t v;
+
+		raw_local_irq_save(flags);
+
+		a = INTC_REQUESTx(irqno);
+		v = readl(a);
+		v |= INTC_REQUESTx_ENABLE_MASK;
+		v |= INTC_REQUESTx_WE_ENABLE_MASK;
+		v |= INTC_REQUESTx_CLR_SWINT_MASK;
+		writel(v, a);
+
+		raw_local_irq_restore(flags);
+	}
+}
+
+static int u6_irq_type(unsigned irqno, unsigned type)
+{
+	int l;
+	void __iomem *reg = INTC_REQUESTx(irqno);
+
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		if (type == IRQF_TRIGGER_LOW) {
+			l = (INTC_REQUESTx_ACTIVE_LOW_MASK
+			     | INTC_REQUESTx_WE_ACTIVE_LOW_MASK);
+		} else if (type == IRQF_TRIGGER_HIGH) {
+			l = (INTC_REQUESTx_WE_ACTIVE_LOW_MASK);
+		} else {
+			goto bad;
+		}
+
+		writel(l, reg);
+		return 0;
+
+	}
+
+bad:
+	return -EINVAL;
+}
+
+int u6_irq_enabled(uint32_t irqno)
+{
+	if (irqno > 0 || irqno < IRQ_COUNT) {
+		void __iomem *a = INTC_REQUESTx(irqno);
+		uint32_t v = readl(a);
+
+		return v & INTC_REQUESTx_ENABLE_MASK;
+	} else
+		return 0;
+}
+
+static struct irq_chip u6_irq_chip = {
+	.ack = u6_irq_mask,
+	.mask = u6_irq_mask,	/* disable irqs */
+	.unmask = u6_irq_unmask,	/* enable irqs */
+	.set_type = u6_irq_type,
+};
+
+
+#if defined(CONFIG_ARCH_U67XX)
+
+static const uint32_t u6_irq_config[] = {
+	0,			/* GHOST      0 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* EXTINT1    1 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* EXTINT2    2 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* EXTINT3    3 */
+	0,			/* RFRD       4 */
+	0,			/* MTU        5 */
+	0,			/* IIS        6 */
+	0,			/* USB        7 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* I2C2       8 */
+	0,			/* TVO        9 */
+	0,			/* 3G_WUP     10 */
+	0,			/* 3G_CALINT  11 */
+	0,			/* 3G_FRAME_IT 12 */
+	0,			/* GPADCINT    13 */
+	0,			/* ARM9_COMMTX 14 */
+	0,			/* ARM9_COMMRX 15 */
+	0,			/* KBS        16 */
+	0,			/* SCTU2      17 */
+	0,			/* SCTU1      18 */
+	0,			/* PIO1       19 */
+	0,			/* PIO2       20 */
+	0,			/* FINT0      21 */
+	0,			/* FINT1      22 */
+	0,			/* UART2      23 */
+	0,			/* UART1      24 */
+	0,			/* SPI2       25 */
+	0,			/* SPI1       26 */
+	0,			/* FCI        27 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* I2C1       28 */
+	0,			/* DMAU       29 */
+	0,			/* USIM       30 */
+	0,			/* RESERVED31 31 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* MSI        32 */
+	0,			/* JDI        33 */
+	0,			/* JDU        34 */
+	0,			/* NFI        35 */
+	0,			/* IPP        36 */
+	0,			/* VDC        37 */
+	0,			/* VEC        38 */
+	0,			/* VDE        39 */
+	INTC_REQUESTx_ACTIVE_LOW_MASK,	/* CAM        40 */
+	0,			/* ETB_ACQ    41 */
+	0,			/* ETB_FULL   42 */
+	0,			/* DIGRF_TX   43 */
+	0,			/* DIGRF_RX   44 */
+	0,			/* RESERVED45 45 */
+	0,			/* FIR_FI     46 */
+	0,			/* FIR        47 */
+	0,			/* PDCU       48 */
+	0,			/* MC2SC0     49 */
+	0,			/* MC2SC1     50 */
+	0,			/* MC2SC2     51 */
+	0,			/* MC2SC3     52 */
+	0,			/* MC2SC4     53 */
+	0,			/* MC2SC5     54 */
+	0,			/* MC2SC6     55 */
+	0,			/* MC2SC7     56 */
+	0,			/* Reserved   57 */
+	0,			/* Reserved   58 */
+	0,			/* Reserved   59 */
+	0,			/* Reserved   60 */
+	0,			/* Reserved   61 */
+	0,			/* Reserved   62 */
+	0,			/* Reserved   63 */
+	0,			/* Reserved   64 */
+};
+
+#endif
+
+static const uint32_t u6_irq_irq_priority;
+static const uint32_t u6_irq_fiq_priority;
+
+void __init u6_init_irq(void)
+{
+	unsigned int irqno;
+
+	/* Clock interrupt controller.
+	 */
+	struct clk *clk = clk_get(NULL, "INTC");
+	clk_enable(clk);
+	clk_put(clk);
+
+	/* The address of the vector table INTCdata.asm is assumed to be aligned
+	 * to a 2KB boundary. Thus the register access value will be padded with
+	 * zeroes, which is conforming to the 'READ_ONLY' attributes of the LS
+	 * 11 bits. We are using the same table for both IRQ and FIQ.
+	 */
+	writel(0, INTC_VECTOR_FIQ_REG);	/* no vector IRQ */
+	writel(0, INTC_VECTOR_IRQ_REG);	/* no vector FIQ */
+
+	writel(u6_irq_irq_priority, INTC_PRIOMASK_IRQ_REG);
+	writel(u6_irq_fiq_priority, INTC_PRIOMASK_FIQ_REG);
+
+	/* Initialize the individual interrupt sources.
+	 */
+	for (irqno = 1; irqno < IRQ_COUNT; irqno += 1) {
+		void __iomem *a = INTC_REQUESTx(irqno);
+		uint32_t v = u6_irq_config[irqno];
+
+		v |= 4;
+		v |= INTC_REQUESTx_WE_ACTIVE_LOW_MASK;
+		v |= INTC_REQUESTx_WE_TARGET_MASK;
+		v |= INTC_REQUESTx_WE_PRIORITY_MASK;
+		v |= INTC_REQUESTx_WE_ENABLE_MASK;
+		v |= INTC_REQUESTx_CLR_SWINT_MASK;
+
+		writel(v, a);
+
+		set_irq_chip(irqno, &u6_irq_chip);
+		set_irq_handler(irqno, handle_level_irq);
+		set_irq_flags(irqno, IRQF_VALID | IRQF_PROBE);
+	}
+}
diff --git a/arch/arm/plat-u6xxx/timer.c b/arch/arm/plat-u6xxx/timer.c
new file mode 100644
index 0000000..b72e8cf
--- /dev/null
+++ b/arch/arm/plat-u6xxx/timer.c
@@ -0,0 +1,442 @@
+/*
+ * linux/arch/arm/plat-u6xxx/timer.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/clock.h>
+
+/*** System timer variable ***/
+struct sys_timer u6_timer;
+
+/*** Module definition ***/
+/*************************/
+
+#define MODULE_NAME "U6_TIMER"
+#define PKMOD MODULE_NAME ": "
+
+/*#define DEBUG*/
+#define U6_MMTU_CLOCK_SOURCE
+
+/*** MMTU clock devices ***/
+/*************************/
+
+/*** MMTU HW ip register index definition ***/
+#define MMTU_CON_IDX 0
+#define MMTU_TCVAL_IDX 0x4
+#define MMTU_PRESCALER_IDX 0x8
+#define MMTU_MATCH_CON_IDX 0xC
+#define MMTU_MATCH0_IDX 0x14
+#define MMTU_MATCH1_IDX 0x18
+
+#define MMTU_INT_OFFSET 0xFD0
+#define MMTU_MOD_CONF_IDX 0x4
+#define MMTU_INT_CLR_ENA_IDX 0x8
+#define MMTU_INT_SET_ENA_IDX 0xC
+#define MMTU_INT_STATUS_IDX 0x10
+#define MMTU_INT_ENABLE_IDX 0x14
+#define MMTU_INT_CLR_STAT_IDX 0x18
+#define MMTU_INT_SET_STAT_IDX 0x1C
+
+#define MMTU_IRQ_MASK		0x1
+#define MMTU_USED_MATCH_IDX	MMTU_MATCH0_IDX
+
+/* MMTU sys clock definition */
+#define MMTU_SYS_FRQ 13000000
+
+/*** MMTU Clock event device ***/
+#define MMTU_ROOT_FRQ 8000
+static int u6_mmtu_set_next_event(unsigned long cycles,
+				struct clock_event_device *evt);
+static void u6_mmtu_set_mode(enum clock_event_mode mode,
+				struct clock_event_device *evt);
+
+static struct clock_event_device clockevent_mmtu = {
+	.name = "mmtu_timer",
+	.rating = 360,
+	.shift = 30,
+	.features = CLOCK_EVT_FEAT_ONESHOT,
+	.set_next_event = u6_mmtu_set_next_event,
+	.set_mode = u6_mmtu_set_mode,
+};
+
+/*** MMTU Clock source device ***/
+#ifdef U6_MMTU_CLOCK_SOURCE
+static cycle_t u6_mmtu_read(struct clocksource *);
+
+static struct clocksource clocksource_mmtu = {
+	.name = "mmtu_timer",
+	.rating = 360,
+	.read = u6_mmtu_read,
+	.mask = CLOCKSOURCE_MASK(32),
+	.shift = 8,
+	.flags = CLOCK_SOURCE_IS_CONTINUOUS,
+};
+#endif
+
+/*** MMTU driver ***/
+#define RELOAD_COUNTER_POWER_MMTU 32
+#define RELOAD_COUNTER_MMTU (1 << RELOAD_COUNTER_POWER_MMTU)
+
+struct mmtu_ctxt {
+	void __iomem *base;
+	uint32_t compvalue;
+	uint32_t endvalue;
+	struct clk *clk;
+	int mode;
+};
+
+struct mmtu_ctxt mmtu_table[1] = {
+	{
+		.base = U6_IO_ADDRESS(MMTU_BASE),
+	},
+};
+
+static inline struct mmtu_ctxt *u6_mmtu_get_context(int id)
+{
+	return &(mmtu_table[id]);
+}
+
+static inline int u6_mmtu_timer_start(unsigned long cycles, int id);
+static inline void u6_mmtu_clk_enable(int id);
+static inline void u6_mmtu_clk_disable(int id);
+
+static irqreturn_t
+u6_mmtu_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	uint8_t status, enable;
+	struct mmtu_ctxt *mmtu;
+
+	mmtu = u6_mmtu_get_context(0);
+
+	status = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_STATUS_IDX));
+	enable = readl((mmtu->base + MMTU_INT_OFFSET + MMTU_INT_ENABLE_IDX));
+
+	pr_debug(PKMOD "mmtu_timer_interrupt %d\n", status);
+
+	if (status & enable & MMTU_IRQ_MASK) {
+		struct clock_event_device *evt = &clockevent_mmtu;
+
+		writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
+					+ MMTU_INT_CLR_STAT_IDX));
+		writel(MMTU_IRQ_MASK,
+				(mmtu->base + MMTU_INT_OFFSET +
+				 MMTU_INT_CLR_ENA_IDX));
+
+		if (evt->event_handler)
+			evt->event_handler(evt);
+	}
+	return IRQ_HANDLED;
+}
+
+static struct irqaction u6_mmtu_timer_irq = {
+	.name = "U6 MMTU timer Tick",
+	.flags = IRQF_DISABLED,
+	.handler = (irq_handler_t) u6_mmtu_timer_interrupt,
+};
+
+static inline void u6_mmtu_clk_enable(int id)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	/* Clock Multimedia Timer Unit.
+	 */
+	if ((mmtu->clk != NULL) && (mmtu->mode == 0)) {
+		pr_debug(PKMOD "mmtu_clk_enable\n");
+		mmtu->mode = 1;
+		clk_enable(mmtu->clk);
+	}
+}
+
+static inline void u6_mmtu_clk_disable(int id)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	/* Clock Multimedia Timer Unit.
+	 */
+	if ((mmtu->clk != NULL) && (mmtu->mode == 1)) {
+		pr_debug(PKMOD "mmtu_clk_disable\n");
+		clk_disable(mmtu->clk);
+		mmtu->mode = 0;
+	}
+}
+
+static inline int u6_mmtu_timer_start(unsigned long cycles, int id)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	pr_debug(PKMOD "mmtu_timer_start %ld\n", cycles);
+	u6_mmtu_clk_enable(id);
+
+	/* MMTU limitation : can't set a value smaller or equal to tcval + 1 */
+	cycles = cycles < 2 ? 2 : cycles;
+
+	mmtu->compvalue = cycles;
+
+	mmtu->endvalue = mmtu->compvalue
+		+ readl((mmtu->base + MMTU_TCVAL_IDX));
+
+	writel(MMTU_IRQ_MASK,
+	       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+	writel(mmtu->endvalue, (mmtu->base + MMTU_USED_MATCH_IDX));
+
+	writel(MMTU_IRQ_MASK,
+	       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+
+	/* the value has already expired */
+	if ((mmtu->endvalue <= readl((mmtu->base + MMTU_TCVAL_IDX)))
+	    && (mmtu->endvalue > mmtu->compvalue)
+	    && !(readl((mmtu->base + MMTU_INT_OFFSET
+				    + MMTU_INT_STATUS_IDX)) & MMTU_IRQ_MASK))
+		writel(MMTU_IRQ_MASK, (mmtu->base + MMTU_INT_OFFSET
+					+ MMTU_INT_SET_STAT_IDX));
+
+	return 0;
+}
+
+static int u6_mmtu_timer_init(int id, unsigned long reload,
+			     unsigned long prescale, int over_it)
+{
+
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(id);
+
+	pr_debug(PKMOD "mmtu_timer_init %d\n", id);
+
+	/* Enable clock */
+/*
+	u6_mmtu_clk_enable(id);
+	clk mngt not available yet
+	directly enable it
+*/
+	{
+		unsigned long flags;
+		unsigned long reg;
+		local_irq_save(flags);
+		reg = readl(CGU_GATESC2_REG);
+		reg |= 0x1 << 2;
+		writel(reg, CGU_GATESC2_REG);
+		local_irq_restore(flags);
+	}
+
+	/* Reset timer */
+	/* reset control register */
+	writel(0x0000, (mmtu->base + MMTU_CON_IDX));
+	writel(0x0002, (mmtu->base + MMTU_CON_IDX));
+	/* reset control register */
+	writel(0x0000, (mmtu->base + MMTU_CON_IDX));
+
+	/* clear whole enable irq register */
+	writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
+	/* clear whole status register */
+	writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+	/* reset pre-scaler reload register */
+	writel(0x00000000, (mmtu->base + MMTU_PRESCALER_IDX));
+
+	/* reset match control register */
+	writel(0x0000, (mmtu->base + MMTU_MATCH_CON_IDX));
+	/* reset match 0 register */
+	writel(0x00000000, (mmtu->base + MMTU_MATCH0_IDX));
+	/* reset match 1 register */
+	writel(0x00000000, (mmtu->base + MMTU_MATCH1_IDX));
+
+	/* Initialize timer */
+	writel(prescale - 1, (mmtu->base + MMTU_PRESCALER_IDX));
+	/* power of 2 system clock */
+	writel(reload, (mmtu->base + MMTU_MATCH0_IDX));
+
+	/* enable counter register */
+	writel(0x0001, (mmtu->base + MMTU_CON_IDX));
+
+	/* clear whole status register */
+	writel(0xFF, (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+	if (id == 0)
+		setup_irq(IRQ_MMTU, &u6_mmtu_timer_irq);
+
+	/* Disable clock */
+#ifndef U6_MMTU_CLOCK_SOURCE
+	u6_mmtu_clk_disable(id);
+#endif
+	return 0;
+}
+
+/*** MMTU Clock event device ***/
+
+static int u6_mmtu_set_next_event(unsigned long cycles,
+				 struct clock_event_device *evt)
+{
+	pr_debug(PKMOD "mmtu_set_next_event %ld\n", cycles);
+	u6_mmtu_timer_start(cycles, 0);
+
+	return 0;
+}
+
+static void u6_mmtu_set_mode(enum clock_event_mode mode,
+			    struct clock_event_device *evt)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
+	unsigned long reg;
+
+	pr_debug(PKMOD "mmtu_set_mode %d\n", mode);
+
+	switch (mode) {
+	case CLOCK_EVT_MODE_UNUSED:
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_ENA_IDX));
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+
+		reg = readl((mmtu->base + MMTU_TCVAL_IDX));
+		writel(reg - 1, (mmtu->base + MMTU_USED_MATCH_IDX));
+
+#ifndef U6_MMTU_CLOCK_SOURCE
+		u6_mmtu_clk_disable(0);
+
+		if (mmtu->clk != NULL)
+			clk_put(mmtu->clk);
+#endif
+		break;
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		if (mmtu->clk == NULL) {
+			mmtu->clk = clk_get(NULL, "MMTU");
+			if (IS_ERR(mmtu->clk))
+				mmtu->clk = NULL;
+		}
+
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_CLR_STAT_IDX));
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	case CLOCK_EVT_MODE_PERIODIC:
+		writel(MMTU_IRQ_MASK,
+		       (mmtu->base + MMTU_INT_OFFSET + MMTU_INT_SET_ENA_IDX));
+		break;
+	}
+}
+
+static void u6_clockevent_init_mmtu(void)
+{
+	printk(PKMOD "clockevent_init_mmtu\n");
+
+	/* prescale 13Mhz -> 1Mhz */
+#ifndef U6_MMTU_CLOCK_SOURCE
+	u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
+#endif
+
+	/* issue it is shorter than reality and generates spurious irq */
+	/*      clockevent_mmtu.mult = div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC,
+	 *      clockevent_mmtu.shift) + 1;*/
+	clockevent_mmtu.mult =
+		div_sc(MMTU_ROOT_FRQ, NSEC_PER_SEC, clockevent_mmtu.shift);
+
+	/*      clockevent_mmtu.max_delta_ns = div_sc(RELOAD_COUNTER_MMTU,
+	 *      clockevent_mmtu.mult, clockevent_mmtu.shift);*/
+	/*  In fact it is wider than the 32bits variable !!! */
+	clockevent_mmtu.max_delta_ns = 0xFFFFFFFF;
+
+	/*  MMTU HW limitation: match register can't be set w/ tcval+1 */
+	/*      clockevent_mmtu.min_delta_ns = div_sc(1, clockevent_mmtu.mult,
+	 *      clockevent_mmtu.shift)+1;*/
+	clockevent_mmtu.min_delta_ns =
+		div_sc(2, clockevent_mmtu.mult, clockevent_mmtu.shift) + 1;
+	/* avoid to much timer interrupt with 10us min between 2 irq */
+	if (clockevent_mmtu.min_delta_ns < 10000)
+		clockevent_mmtu.min_delta_ns = 10000;
+	else if (clockevent_mmtu.max_delta_ns < 10000)
+		clockevent_mmtu.min_delta_ns = clockevent_mmtu.max_delta_ns>>1;
+
+	clockevent_mmtu.cpumask = get_cpu_mask(0);
+	clockevents_register_device(&clockevent_mmtu);
+
+	u6_mmtu_set_next_event(MMTU_ROOT_FRQ / HZ, &clockevent_mmtu);
+}
+
+/*** MMTU Clock source device ***/
+#ifdef U6_MMTU_CLOCK_SOURCE
+
+static cycle_t u6_mmtu_read(struct clocksource *source)
+{
+	struct mmtu_ctxt *mmtu = u6_mmtu_get_context(0);
+
+	return readl(mmtu->base + MMTU_TCVAL_IDX);
+}
+
+static void u6_clocksource_init_mmtu(void)
+{
+	printk(PKMOD "clocksource_init_mmtu\n");
+
+	if (MMTU_ROOT_FRQ >= 1000000)
+		clocksource_mmtu.mult =
+			clocksource_khz2mult((MMTU_ROOT_FRQ / 1000),
+					clocksource_mmtu.shift);
+	else
+		clocksource_mmtu.mult = clocksource_hz2mult((MMTU_ROOT_FRQ),
+				clocksource_mmtu.shift);
+
+	u6_mmtu_timer_init(0, 0, (MMTU_SYS_FRQ / MMTU_ROOT_FRQ), 0);
+
+	clocksource_register(&clocksource_mmtu);
+}
+
+#endif
+
+/*** System timer init ***/
+/*************************/
+
+void __init u6_timer_init(void)
+{
+	printk(PKMOD "mmtu_timer_init\n");
+
+#ifdef U6_MMTU_CLOCK_SOURCE
+	u6_clocksource_init_mmtu();
+#endif
+
+	u6_clockevent_init_mmtu();
+}
+
+struct sys_timer u6_timer = {
+	.init = u6_timer_init,
+};
+
+#ifdef CONFIG_U6_POWER_SYSFS
+static int __init u6_mmtu_init_sysfs(void)
+{
+	printk(PKMOD "mmtu_init_sysfs\n");
+
+#ifdef U6_MMTU_CLOCK_SOURCE
+	if (sysfs_create_group(&u6_power_kobj, &dbs_attr_srce_group))
+		printk(PKMOD "Unable to register %s in sysfs\n",
+		       dbs_attr_srce_group.name);
+#endif
+
+	if (sysfs_create_group(&u6_power_kobj, &dbs_attr_event_group))
+		printk(PKMOD "Unable to register %s in sysfs\n",
+		       dbs_attr_event_group.name);
+
+	return 0;
+}
+
+module_init(u6_mmtu_init_sysfs);
+#endif
-- 
1.7.1

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

* [PATCH 2/5] U6715 clocks gating management U6 clock generic driver & U6715 cgu clock specific
  2010-08-05 12:28 ` Philippe Langlais
@ 2010-08-05 12:28   ` Philippe Langlais
  -1 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux, gregkh
  Cc: akpm, STEricsson_nomadik_linux, etienne.carriere,
	vincent.guittot, Philippe Langlais

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 arch/arm/Kconfig                          |    1 +
 arch/arm/mach-u67xx/Makefile              |    5 +-
 arch/arm/mach-u67xx/cgu.c                 |  753 +++++++++++++++++++++++++
 arch/arm/mach-u67xx/cgu.h                 |   57 ++
 arch/arm/mach-u67xx/clock_data_u67xx.c    |  864 +++++++++++++++++++++++++++++
 arch/arm/plat-u6xxx/Makefile              |    2 +-
 arch/arm/plat-u6xxx/clock.c               |  621 +++++++++++++++++++++
 arch/arm/plat-u6xxx/include/mach/clkdev.h |   13 +
 arch/arm/plat-u6xxx/include/mach/clock.h  |  378 +++++++++++++
 9 files changed, 2692 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-u67xx/cgu.c
 create mode 100644 arch/arm/mach-u67xx/cgu.h
 create mode 100644 arch/arm/mach-u67xx/clock_data_u67xx.c
 create mode 100644 arch/arm/plat-u6xxx/clock.c
 create mode 100644 arch/arm/plat-u6xxx/include/mach/clkdev.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/clock.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1ae089c..a250f2e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -742,6 +742,7 @@ config ARCH_U300
 config PLAT_U6XXX
 	bool "ST-Ericsson U6XXX Series"
 	select CPU_ARM926T
+	select COMMON_CLKDEV
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
 	help
diff --git a/arch/arm/mach-u67xx/Makefile b/arch/arm/mach-u67xx/Makefile
index 38cf624..d4e35a7 100644
--- a/arch/arm/mach-u67xx/Makefile
+++ b/arch/arm/mach-u67xx/Makefile
@@ -5,7 +5,10 @@
 ## Object file lists.
 
 # Common support
-obj-y			:= devices.o
+obj-y			:= devices.o cgu.o
+
+# Specific machine support
+obj-y += clock_data_u67xx.o
 
 # Specific board support
 obj-$(CONFIG_MACH_U67XX_WAVEC_2GB) += board_u67xx_wavex.o
diff --git a/arch/arm/mach-u67xx/cgu.c b/arch/arm/mach-u67xx/cgu.c
new file mode 100644
index 0000000..68401ff
--- /dev/null
+++ b/arch/arm/mach-u67xx/cgu.c
@@ -0,0 +1,753 @@
+/*
+ *  arch/arm/mach-u67xx/cgu.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Arnaud Troel <arnaud.troel@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * U67XX Clock Gating Unit basic driver/wrapper
+ * Based on the code from Michel Jaouen
+ */
+
+/*#define DEBUG */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <asm/clkdev.h>
+#include <mach/hardware.h>
+#include <mach/clock.h>
+#include "cgu.h"
+
+#define MODULE_NAME "U6_CGU"
+#define PKMOD MODULE_NAME ": "
+
+/*
+ * Public U6 platform access clock functions
+ */
+
+/**
+ * @brief Disable a device clock.
+ * @param clk clock description structure
+ */
+void u6_clk_disable(struct clk *clk)
+{
+	/*    BUG_ON(!clk->ref_count); */
+	if ((clk->flags & ALWAYS_ENABLED) == ALWAYS_ENABLED)
+		return;
+
+	if (clk->usecount > 0 && !(--clk->usecount)) {
+		if (clk->disable)
+			clk->disable(clk);
+		else
+			u67xx_cgu_disable_clock(clk);
+
+		if (likely((u32) clk->parent))
+			u6_clk_disable(clk->parent);
+	}
+}
+
+/**
+ * @brief Enable a device clock.
+ * @param clk clock description structure
+ */
+int u6_clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	/*   BUG_ON(!clk->ref_count); */
+	if ((clk->flags & ALWAYS_ENABLED) == ALWAYS_ENABLED)
+		return 0;
+
+	if (clk->usecount++ == 0) {
+		if (likely((u32) clk->parent))
+			ret = u6_clk_enable(clk->parent);
+
+		if (unlikely(ret != 0)) {
+			clk->usecount--;
+			return ret;
+		}
+
+		if (clk->enable)
+			ret = clk->enable(clk);
+		else
+			ret = u67xx_cgu_enable_clock(clk);
+
+		if (unlikely(ret != 0) && clk->parent) {
+			u6_clk_disable(clk->parent);
+			clk->usecount--;
+		}
+	}
+	return 0;
+}
+
+/**
+ * HW enable clock function.
+ **/
+
+int u67xx_cgu_enable_fake_clock(struct clk *clk)
+{
+	pr_debug("u67xx_cgu_enable_fake_clock for %s\n", clk->name);
+	return 0;
+}
+
+int u67xx_cgu_enable_hw_clock(struct clk *clk)
+{
+	unsigned long value;
+	pr_debug("u67xx_cgu_enable_hw_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	return 0;
+}
+
+int u67xx_cgu_enable_tvo_pll_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_enable_tvo_pll_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	/* wait pll lock */
+	do {
+		value = readl(clk->enable_reg);
+	} while (!(value & (0x1 << 16)));
+
+	return 0;
+}
+
+int u67xx_cgu_enable_shared_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_enable_shared_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	return 0;
+}
+
+int u67xx_cgu_enable_clock(struct clk *clk)
+{
+	printk(PKMOD "No enable clock method for %s."
+	       " You should use new one !!!\n", clk->name);
+	return 0;
+}
+
+int u67xx_cgu_enable_camout(struct clk *clk)
+{
+	unsigned long value;
+	pr_debug("u67xx_cgu_enable_hw_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	u6_clk_enable(&fix_ck);
+	u6_clk_enable(&plltv_ck);
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	udelay(1);
+
+	u6_clk_disable(&fix_ck);
+	u6_clk_disable(&plltv_ck);
+
+	return 0;
+}
+
+/**
+ * HW disable clock function.
+ **/
+
+void u67xx_cgu_disable_fake_clock(struct clk *clk)
+{
+	pr_debug("u67xx_cgu_disable_fake_clock for %s\n", clk->name);
+}
+
+void u67xx_cgu_disable_hw_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_disable_hw_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Disable for %s without enable register\n",
+		       clk->name);
+		return;
+	}
+
+	value = readl(clk->enable_reg);
+	value &= ~(1 << clk->enable_bit);
+	writel(value, clk->enable_reg);
+
+	return;
+}
+
+void u67xx_cgu_disable_shared_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_disable_shared_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Disable for %s without enable register\n",
+		       clk->name);
+		return;
+	}
+
+	value = readl(clk->enable_reg);
+	value &= ~(1 << clk->enable_bit);
+	writel(value, clk->enable_reg);
+}
+
+void u67xx_cgu_disable_clock(struct clk *clk)
+{
+	printk(PKMOD
+	       " No disable clock method for %s. You should use one !!!\n",
+	       clk->name);
+}
+
+/**
+ * set rate clock function.
+ **/
+
+int u6_clk_set_rate_fci(struct clk *clk, unsigned long rate)
+{
+	int ret = 0;
+	unsigned long ratio = 0;
+	unsigned long reg;
+
+	if (!rate)
+		ratio = 31;
+	else {
+		if (rate > CLK_FC_CLK_MAX_FREQ)
+			rate = CLK_FC_CLK_MAX_FREQ;
+
+		/* compute diviser ratio */
+		ratio = (clk->parent->rate / rate) - 1;
+		if (ratio < 2)
+			ratio = 2;
+		if (ratio > 31)
+			ratio = 31;
+	}
+	clk->rate = clk->parent->rate / (ratio + 1);
+
+	/* for voltage working point only */
+	/* u67xx_set_freq(FC_CLK, clk->rate/1000 , clk->rate/1000); */
+
+	reg = readl(CGU_FIXCON_REG);
+	reg &= ~(0x1F << 22);
+	reg |= (ratio << 22);
+	writel(reg, CGU_FIXCON_REG);
+
+	reg = readl(CGU_SCCON_REG);
+	writel(reg, CGU_SCCON_REG);
+
+	return ret;
+}
+
+int u6_clk_set_rate_camout(struct clk *clk, unsigned long rate)
+{
+	int ret = 0;
+	unsigned long ratio = 0;
+	unsigned long reg;
+
+	if (!rate)
+		return -EINVAL;
+
+	if (rate > CLK_CAM_CLK_MAX_FREQ)
+		rate = CLK_CAM_CLK_MAX_FREQ;
+
+	/* compute diviser ratio */
+	ratio = (clk->parent->rate / rate) - 1;
+	if (ratio < 1)
+		ratio = 1;
+	if (ratio > 63)
+		ratio = 63;
+
+	clk->rate = clk->parent->rate / (ratio + 1);
+
+	/* for voltage working point only */
+	/* u67xx_set_freq(CAM_CLK, clk->rate/1000 , clk->rate/1000); */
+
+	reg = readl(CGU_CAMCON_REG);
+
+	reg &= ~(0x3F << 0);
+	reg |= (ratio << 0);
+
+	writel(reg, CGU_CAMCON_REG);
+
+	return ret;
+}
+
+/**
+ * set parent clock function.
+ **/
+int u6_clk_set_parent_camout(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+	unsigned long srce = 0;
+	unsigned long reg;
+
+	if (!strcmp(parent->name, "TVOPLL"))
+		srce = 0;
+	else if (!strcmp(parent->name, "fix_ck"))
+		srce = 1;
+	else
+		return -EINVAL;
+
+	u6_clk_enable(&fix_ck);
+	u6_clk_enable(&plltv_ck);
+
+	reg = readl(CGU_CAMCON_REG);
+
+	reg &= ~(0x1 << 6);
+	reg |= (srce << 6);
+
+	writel(reg, CGU_CAMCON_REG);
+
+	udelay(1);
+
+	u6_clk_disable(&fix_ck);
+	u6_clk_disable(&plltv_ck);
+
+	clk->parent = parent;
+
+	return ret;
+}
+
+int u6_clk_set_parent_uart(struct clk *clk, struct clk *parent)
+{
+
+	if (!strcmp(parent->name, "pclk2_ck")) {
+		clk->parent = parent;
+		return 0;
+	} else if (!strcmp(parent->name, "clk26m_ck")) {
+		clk->parent = parent;
+		return 0;
+	} else if (!strcmp(parent->name, "clk13m_ck")) {
+		clk->parent = parent;
+		return 0;
+	} else {
+		return -EINVAL;
+	}
+}
+
+/**
+ * HW init clock function.
+ **/
+
+void u6_clk_dflt_init(struct clk *clk)
+{
+	if (clk->usecount == 0)
+		u67xx_cgu_disable_hw_clock(clk);
+	else
+		u67xx_cgu_enable_hw_clock(clk);
+	/* default rate to parent one */
+	clk->rate = clk->parent->rate;
+}
+
+void u6_clk_init_hclk2(struct clk *clk)
+{
+	/* nothing to do */
+}
+
+void u6_clk_init_fci(struct clk *clk)
+{
+	u6_clk_set_rate_fci(clk, clk->rate);
+}
+
+void u6_clk_init_camout(struct clk *clk)
+{
+	u6_clk_set_parent_camout(clk, &fix_ck);
+	u6_clk_set_rate_camout(clk, clk->rate);
+}
+
+/*
+ * Update clock rate
+ */
+void followparent_ivs_recalc(struct clk *clk)
+{
+	clk->rate = clk->parent->rate;
+	propagate_rate(clk);
+}
+
+/*
+ * Private U6 platform access clock functions
+ */
+static long u6_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->round_rate)
+		return clk->round_rate(clk, rate);
+	else
+		return rate;
+}
+
+static int u6_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = 0;
+
+	/*   BUG_ON(!clk->ref_count); */
+	if (clk->usecount > 0) {
+		if (clk->disable)
+			clk->disable(clk);
+		else
+			u67xx_cgu_disable_clock(clk);
+	}
+
+	if (clk->set_rate)
+		ret = clk->set_rate(clk, rate);
+	else
+		ret = -EINVAL;
+
+	if (clk->usecount > 0) {
+		if (clk->enable)
+			clk->enable(clk);
+		else
+			u67xx_cgu_enable_clock(clk);
+	}
+
+	/* propagate rate */
+	propagate_rate(clk);
+
+	return ret;
+}
+
+static int u6_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+	int old_rate;
+
+	if (clk->usecount > 0) {
+		if (clk->disable)
+			clk->disable(clk);
+		else
+			u67xx_cgu_disable_clock(clk);
+
+		if (likely((u32) clk->parent))
+			u6_clk_disable(clk->parent);
+	}
+
+	old_rate = clk->rate;
+
+	if (clk->set_parent)
+		ret = clk->set_parent(clk, parent);
+	else
+		ret = -EINVAL;
+
+	if (clk->round_rate)
+		old_rate = clk->round_rate(clk, old_rate);
+
+	u6_clk_set_rate(clk, old_rate);
+
+	if (clk->usecount > 0) {
+		if (likely((u32) clk->parent))
+			u6_clk_enable(clk->parent);
+
+		if (clk->enable)
+			ret = clk->enable(clk);
+		else
+			ret = u67xx_cgu_enable_clock(clk);
+	}
+
+	/* propagate rate */
+	if (clk->flags & RATE_PROPAGATES)
+		propagate_rate(clk);
+
+	return ret;
+}
+
+static struct clk *u6_clk_get_parent(struct clk *clk)
+{
+	return clk->parent;
+}
+
+/*
+ * U6 platform clock constraint functions
+ */
+
+unsigned long clk_get_hw_constraint(void __iomem *reg_addr)
+{
+	unsigned long reg;
+
+	reg = readl(reg_addr);
+
+	return reg;
+}
+
+ssize_t u6_clk_show_hw_rates(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+	unsigned long reg, rate, msc, psc, mclk;
+
+	size += sprintf(&buf[size], "--HW-- : \n");
+
+	mclk = clk_get_hw_constraint(CGU_FIXCON_REG);
+	mclk = osc_ck.rate / 1000000 / (((mclk & (0x3 << 17)) >> 17) + 1);
+
+	reg = clk_get_hw_constraint(CGU_SCCON_REG);
+
+	msc = (((reg & (0xF << 25)) >> 25) + 1);
+	psc = (((reg & (0x3 << 15)) >> 15) + 1);
+	size += sprintf(&buf[size], "arm_ck is ");
+	if (reg & (1 << 17)) {
+		if (reg & (1 << 18))
+			rate = 312;
+		else
+			rate = 156;
+		rate = rate / msc / psc;
+		size += sprintf(&buf[size], "%lu", rate);
+		size += sprintf(&buf[size], "Mhz fix_ck pll\n");
+	} else {
+		rate = mclk * (((reg & (0xFF << 3)) >> 3) + 1)
+		    / (((reg & (0xF << 11)) >> 11) + 1);
+		rate = rate / msc / psc;
+		size += sprintf(&buf[size], "%lu", rate);
+		size += sprintf(&buf[size], "Mhz sc_ck pll\n");
+	}
+
+	rate = rate / (((reg & (0xF << 21)) >> 21) + 1);
+
+	size += sprintf(&buf[size], "hclk_ck is %luMhz\n", rate);
+
+	reg = clk_get_hw_constraint(CGU_FIXCON_REG);
+
+	rate = 13 * (((reg & (0x3 << 20)) >> 20) + 1);
+
+	size += sprintf(&buf[size], "pclk2_ck is %luMhz\n", rate);
+
+	if (reg & (1 << 31)) {
+		if (reg & (1 << 29))
+			rate = 104;
+		else
+			rate = 78;
+	} else
+		rate = 13 + (13 * ((reg & (0x7 << 29)) >> 29));
+
+	size += sprintf(&buf[size], "hclk2_ck is %luMhz\n", rate);
+
+	reg = clk_get_hw_constraint(CGU_SDMCON_REG);
+
+	msc = (((reg & (0x7 << 0)) >> 0) + 1);
+
+	size += sprintf(&buf[size], "sdm_ck is ");
+	if (reg & (1 << 17)) {
+		if (reg & (1 << 18))
+			rate = 312;
+		else
+			rate = 156;
+		size += sprintf(&buf[size], "%lu", rate / msc);
+		size += sprintf(&buf[size], "Mhz fix_ck pll\n");
+	} else {
+		rate = mclk * 2 * (((reg & (0xFF << 3)) >> 3) + 1)
+		    / (((reg & (0x3F << 11)) >> 11) + 1);
+		size += sprintf(&buf[size], "%lu", rate / msc);
+		size += sprintf(&buf[size], "Mhz sdm pll\n");
+	}
+
+	if (reg & (1 << 23))
+		size += sprintf(&buf[size], "ivs-sdm concentrator is enable\n");
+	else
+		size += sprintf(&buf[size],
+				"ivs-sdm concentrator is disable\n");
+
+	return size;
+}
+
+unsigned char *cgu_name_sc1[32] = {
+	"EBI", "01", "NFI", "SDI", "04", "MSI", "UCC", "JDI",
+	"08", "09", "10", "DMAU", "RFSM1", "IIS", "USBD", "FCI",
+	"USIM", "GEAC", "PWM3", "PWM2", "PWM1", "KBS", "GPIO", "UART2",
+	"UART1", "IIC2", "IIC1", "SPI2", "SPI1", "SCTU", "EXTINT", "INTC"
+};
+
+unsigned char *cgu_name_sc2[32] = {
+	"32", "33", "34", "35", "36", "37", "38", "39",
+	"40", "41", "42", "43", "44", "45", "46", "47",
+	"48", "49", "50", "51", "52", "53", "BBIP", "55",
+	"56", "57", "58", "ETB", "60", "MMTU", "62", "CAE"
+};
+
+ssize_t u6_clk_show_sc_constraints(struct kobject *kobj, char *buf)
+{
+	int i, size = 0;
+	unsigned long reg;
+
+	size += sprintf(&buf[size], "--SC-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_GATESC1_REG);
+
+	for (i = 0; i < 32; i++) {
+		if ((reg >> i) & 0x1)
+			size +=
+			    sprintf(&buf[size], "%s ,", cgu_name_sc1[31 - i]);
+	}
+
+	size += sprintf(&buf[size], "\n");
+
+	reg = clk_get_hw_constraint(CGU_GATESC2_REG);
+
+	for (i = 0; i < 32; i++) {
+		if ((reg >> i) & 0x1)
+			size +=
+			    sprintf(&buf[size], "%s ,", cgu_name_sc2[31 - i]);
+	}
+
+	size += sprintf(&buf[size], "\n");
+
+	return size;
+}
+
+unsigned char *cgu_name_ivs[32] = {
+	"", "", "", "", "", "", "", "",
+	"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+	"CAMJPE", "TVO", "JDU", "VDC", "VEC", "IPP", "VDE", "CAM"
+};
+
+ssize_t u6_clk_show_ivs_constraints(struct kobject *kobj, char *buf)
+{
+	int i, size = 0;
+	unsigned long reg;
+
+	size += sprintf(&buf[size], "--IVS-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_GATEIVS_REG);
+
+	for (i = 0; i < 32; i++) {
+		if ((reg >> i) & 0x1)
+			size +=
+			    sprintf(&buf[size], "%s ,", cgu_name_ivs[31 - i]);
+	}
+
+	size += sprintf(&buf[size], "\n");
+
+	return size;
+}
+
+ssize_t u6_clk_show_tvo_constraints(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+	unsigned long reg;
+
+	size += sprintf(&buf[size], "--TVO-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_TVCON_REG);
+
+	if ((reg >> 15) & 0x1)
+		size += sprintf(&buf[size], "tvclk_ck pll enable\n");
+	else
+		size += sprintf(&buf[size], "tvclk_ck pll disable\n");
+
+	if ((reg >> 12) & 0x1)
+		size += sprintf(&buf[size], "TVOPLL enable\n");
+	else
+		size += sprintf(&buf[size], "TVOPLL disable\n");
+
+	return size;
+}
+
+ssize_t u6_clk_show_cam_constraints(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+	unsigned long reg, rate, div;
+
+	size += sprintf(&buf[size], "--CAM-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_CAMCON_REG);
+
+	if ((reg >> 6) & 0x1) {
+		size += sprintf(&buf[size], "fix_clock is source\n");
+		rate = 312;
+	} else {
+		size += sprintf(&buf[size], "TVOPLL is source\n");
+		rate = 216;
+	}
+
+	div = ((reg & (0x3F << 0)) >> 0);
+
+	size += sprintf(&buf[size], "camo_ck is %luMhz\n", rate / (div + 1));
+
+	if ((reg >> 7) & 0x1)
+		size += sprintf(&buf[size], "camo_ck enable\n");
+	else
+		size += sprintf(&buf[size], "camo_ck disable\n");
+
+	return size;
+}
+
+/*
+ * U6 clock reset and init functions
+ */
+
+static struct clk_functions u6_clk_functions = {
+	.clk_enable = u6_clk_enable,
+	.clk_disable = u6_clk_disable,
+	.clk_round_rate = u6_clk_round_rate,
+	.clk_set_rate = u6_clk_set_rate,
+	.clk_set_parent = u6_clk_set_parent,
+	.clk_get_parent = u6_clk_get_parent,
+};
+
+/**
+ * @brief Attempts to connect the primary description structure for DMA case.
+ *
+ * We don't do any initialization since we expect the primary OS to have done
+ * it for us.
+ */
+static int __init u67xx_cgu_init(void)
+{
+	struct clk_lookup *clkp;
+	printk(PKMOD "clk management init\n");
+
+	if (mpurate)
+		sc_ck.rate = mpurate;
+
+	/* init clock function pointer table */
+	clk_init(&u6_clk_functions);
+
+	/* register and init clock elements */
+	for (clkp = onchip_clks; clkp->clk != NULL; clkp++) {
+		clkp->con_id = clkp->clk->name;
+		clkdev_add(clkp);
+		clk_register(clkp->clk);
+	}
+
+	return 0;
+}
+
+arch_initcall(u67xx_cgu_init);
diff --git a/arch/arm/mach-u67xx/cgu.h b/arch/arm/mach-u67xx/cgu.h
new file mode 100644
index 0000000..c029991
--- /dev/null
+++ b/arch/arm/mach-u67xx/cgu.h
@@ -0,0 +1,57 @@
+/*
+ *  arch/arm/mach-u67xx/cgu.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef CGU_INC
+#define CGU_INC
+
+extern struct clk arm_ck;
+extern struct clk hclk_ck;
+extern struct clk sdm_ck;
+extern struct clk hclk2_ck;
+extern struct clk pclk2_ck;
+extern struct clk sc_ck;
+extern struct clk fix_ck;
+extern struct clk plltv_ck;
+extern struct clk osc_ck;
+
+extern struct clk_lookup onchip_clks[];
+
+extern void u6_clk_init_hclk2(struct clk *clk);
+extern void u6_clk_init_rtke(struct clk *clk);
+extern void u6_clk_init_fci(struct clk *clk);
+extern void u6_clk_init_camout(struct clk *clk);
+
+extern void followparent_ivs_recalc(struct clk *clk);
+
+extern void u6_clk_rtke_recalc(struct clk *clk);
+
+extern int u67xx_cgu_enable_fake_clock(struct clk *clk);
+extern int u67xx_cgu_enable_hw_clock(struct clk *clk);
+extern int u67xx_cgu_enable_tvo_pll_clock(struct clk *clk);
+extern int u67xx_cgu_enable_rtke_clock(struct clk *clk);
+extern int u67xx_cgu_enable_shared_clock(struct clk *clk);
+extern int u67xx_cgu_enable_clock(struct clk *clk);
+extern int u67xx_cgu_enable_camout(struct clk *clk);
+
+extern void u67xx_cgu_disable_fake_clock(struct clk *clk);
+extern void u67xx_cgu_disable_hw_clock(struct clk *clk);
+extern void u67xx_cgu_disable_rtke_clock(struct clk *clk);
+extern void u67xx_cgu_disable_shared_clock(struct clk *clk);
+extern void u67xx_cgu_disable_clock(struct clk *clk);
+
+extern int u6_clk_set_rate_fci(struct clk *clk, unsigned long rate);
+extern int u6_clk_set_rate_camout(struct clk *clk, unsigned long rate);
+extern int u6_clk_set_rate_rtke(struct clk *clk, unsigned long rate);
+
+extern int u6_clk_set_parent_camout(struct clk *clk, struct clk *parent);
+extern int u6_clk_set_parent_uart(struct clk *clk, struct clk *parent);
+
+extern void u6_clk_dflt_init(struct clk *clk);
+
+#endif   /* ----- #ifndef CGU_INC  ----- */
+
diff --git a/arch/arm/mach-u67xx/clock_data_u67xx.c b/arch/arm/mach-u67xx/clock_data_u67xx.c
new file mode 100644
index 0000000..e3d8156
--- /dev/null
+++ b/arch/arm/mach-u67xx/clock_data_u67xx.c
@@ -0,0 +1,864 @@
+/*
+ *  arch/arm/mach-u67xx/clock_data_u67xx.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ */
+#include <linux/device.h>
+#include <asm/clkdev.h>
+#include <mach/hardware.h>
+#include <mach/clock.h>
+#include "cgu.h"
+
+#define MODULE_NAME "U6_CGU"
+#define PKMOD MODULE_NAME ": "
+
+/* used to remove useless clock cells */
+#undef U6_OPTIMIZED_TREE
+
+/*
+ * U6 clock tree.
+ *
+ * NOTE:In many cases here we are assigning a 'default' parent.	In many
+ *	cases the parent is selectable.	The get/set parent calls will also
+ *	switch sources.
+ *
+ *	Many some clocks say always_enabled, but they can be auto idled for
+ *	power savings. They will always be available upon clock request.
+ *
+ *	Several sources are given initial rates which may be wrong, this will
+ *	be fixed up in the init func.
+ *
+ *	Things are broadly separated below by clock domains. It is
+ *	noteworthy that most periferals have dependencies on multiple clock
+ *	domains. Many get their interface clocks from the L4 domain, but get
+ *	functional clocks from fixed sources or other core domain derived
+ *	clock.
+ */
+
+/*** Basic clocks ***/
+
+/* Base external input clocks */
+static struct clk func_32k_ck = {
+	.name = "func_32k_ck",
+	.rate = 32000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED,
+	.usecount = 1,
+};
+
+/* Typical 26MHz in standalone mode */
+struct clk osc_ck = {	/* (*12, *13, 19.2, *26, 38.4)MHz */
+	.name = "osc_ck",
+	.rate = 26000000,	/* fixed up in clock init */
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.usecount = 1,
+};
+
+/* System clock MCLK */
+/* With out modem likely 12MHz, with modem likely 13MHz */
+static struct clk sys_ck = {	/* (*12, *13, 19.2, 26, 38.4)MHz */
+	.name = "sys_ck",	/* ~ ref_clk also */
+	.parent = &osc_ck,
+	.rate = 13000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.usecount = 1,
+};
+
+/*** System PLLs ***/
+
+struct clk sc_ck = {	/* 275-550MHz */
+	.name = "sc_ck",
+	.parent = &sys_ck,
+	.rate = 416000000,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+struct clk fix_ck = {	/* 312MHz */
+	.name = "fix_ck",
+	.parent = &sys_ck,
+	.rate = 312000000,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 0,
+};
+
+static struct clk tv_ck = {	/* 216MHz */
+	.name = "tv_ck",
+	.parent = &fix_ck,
+	.rate = 216000000,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk dsp2_ck = {	/* 156-320MHz */
+	.name = "dsp2_ck",
+	.parent = &sys_ck,
+	.rate = 208000000,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 8,
+};
+#endif
+
+struct clk sdm_ck = {	/* 275-550MHz */
+	.name = "sdm_ck",
+	.parent = &sys_ck,
+	.rate = 200000000,
+/*      .flags          = RATE_PROPAGATES,*/
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 3,
+};
+
+/*** Master clock sources ***/
+
+struct clk arm_ck = {
+	.name = "arm_ck",
+	.rate = 416000000,
+	.parent = &sc_ck,
+/*	.flags          = RATE_PROPAGATES,*/
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+struct clk hclk_ck = {
+	.name = "hclk_ck",
+	.rate = 208000000,
+	.parent = &arm_ck,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 1,
+};
+
+struct clk hclk2_ck = {
+	.name = "hclk2_ck",
+/*	.rate           = 104000000,*/
+	.rate = 52000000,
+	.parent = &fix_ck,
+	.flags = RATE_PROPAGATES,
+	.init = u6_clk_init_hclk2,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 2,
+};
+
+static struct clk sdm_ivs_ck = {
+	.name = "sdm_ivs_ck",
+	.parent = &hclk2_ck,
+	.rate = 104000000,
+	.flags = RATE_PROPAGATES,
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_ivs_recalc,
+	.enable_reg = CGU_SDMCON_REG,
+	.enable_bit = 23,
+};
+
+static struct clk pclk1_ck = {
+	.name = "pclk1_ck",
+	.rate = 104000000,
+	.parent = &hclk2_ck,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+static struct clk tvclk_ck = {
+	.name = "tvclk_ck",
+	.rate = 27000000,
+	.parent = &tv_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_tvo_pll_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_TVCON_REG,
+	.enable_bit = 15,
+};
+
+struct clk pclk2_ck = {
+	.name = "pclk2_ck",
+	.rate = 52000000,
+	.parent = &fix_ck,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 4,
+};
+
+static struct clk clk24m_ck = {
+	.name = "clk24m_ck",
+	.rate = 24000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 5,
+};
+
+static struct clk clk26m_ck = {
+	.name = "clk26m_ck",
+	.rate = 26000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 6,
+};
+
+static struct clk clk13m_ck = {
+	.name = "clk13m_ck",
+	.rate = 13000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 7,
+};
+
+static struct clk clk4m_ck = {
+	.name = "clk4m_ck",
+	.rate = 4000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk sioy1clk_ck = {
+	.name = "sioy1clk_ck",
+	.rate = 208000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk sioy2clk_ck = {
+	.name = "sioy2clk_ck",
+	.rate = 208000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk rfclk_ck = {
+	.name = "rfclk_ck",
+	.rate = 208000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+#endif
+
+static struct clk fc_ck = {
+	.name = "fc_ck",
+/*	.rate = 104000000,*/
+	.rate = 52000000,
+	.init = u6_clk_init_fci,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.set_rate = u6_clk_set_rate_fci,
+	.parent = &fix_ck,
+};
+
+static struct clk usb_d_ck = {
+	.name = "usb_d_ck",
+	.rate = 24000000,
+	.parent = &clk24m_ck,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+static struct clk usb_h_ck = {
+	.name = "usb_h_ck",
+	.rate = 24000000,
+	.parent = &clk24m_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk dcclk1_ck = {
+	.name = "dcclk1_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk diclk1_ck = {
+	.name = "diclk1_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk dcclk2_ck = {
+	.name = "dcclk2_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk diclk2_ck = {
+	.name = "dicl2_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+#endif
+
+static struct clk camo_ck = {
+	.name = "camo_ck",
+	.rate = 12000000,
+	.parent = &fix_ck,
+	.flags = RATE_PROPAGATES,
+	.init = u6_clk_init_camout,
+	.enable = u67xx_cgu_enable_camout,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.set_rate = u6_clk_set_rate_camout,
+	.set_parent = u6_clk_set_parent_camout,
+	.enable_reg = CGU_CAMCON_REG,
+	.enable_bit = 7,
+};
+
+/*** Peripheral clocks ***/
+
+/* CGUTVCON */
+struct clk plltv_ck = {
+	.name = "TVOPLL",
+	.enable_reg = CGU_TVCON_REG,
+	.enable_bit = 12,
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.parent = &tvclk_ck,
+};
+
+/* CGUGATESC1 */
+#ifndef U6_OPTIMIZED_TREE
+static struct clk intc_ck = {
+	.name = "INTC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 0,
+	.parent = &hclk2_ck,
+	.usecount = 1,
+};
+
+static struct clk extint_ck = {
+	.name = "EXTINT",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 1,
+	.parent = &pclk2_ck,
+	.usecount = 1,
+};
+
+static struct clk sctu_ck = {
+	.name = "SCTU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 2,
+	.parent = &clk13m_ck,
+};
+#endif
+
+static struct clk spi1_ck = {
+	.name = "SPI1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 3,
+	.parent = &pclk1_ck,
+};
+
+static struct clk spi2_ck = {
+	.name = "SPI2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 4,
+	.parent = &pclk1_ck,
+};
+
+static struct clk iic1_ck = {
+	.name = "IIC1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 5,
+	.parent = &pclk2_ck,
+};
+
+static struct clk iic2_ck = {
+	.name = "IIC2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 6,
+	.parent = &pclk2_ck,
+};
+
+static struct clk uart1_ck = {
+	.name = "UART1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.set_parent = u6_clk_set_parent_uart,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 7,
+	.parent = &clk13m_ck,
+};
+
+static struct clk uart2_ck = {
+	.name = "UART2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.set_parent = u6_clk_set_parent_uart,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 8,
+	.parent = &clk13m_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk gpio_ck = {
+	.name = "GPIO",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 9,
+	.parent = &pclk2_ck,
+	.usecount = 1,
+};
+#endif
+
+static struct clk kbs_ck = {
+	.name = "KBS",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 10,
+	.parent = &func_32k_ck,
+};
+
+static struct clk pwm1_ck = {
+	.name = "PWM1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 11,
+	.parent = &clk13m_ck,
+};
+
+static struct clk pwm2_ck = {
+	.name = "PWM2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 12,
+	.parent = &clk13m_ck,
+};
+
+static struct clk pwm3_ck = {
+	.name = "PWM3",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 13,
+	.parent = &clk13m_ck,
+};
+
+static struct clk geac_ck = {
+	.name = "GEAC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 14,
+	.parent = &pclk1_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk usim_ck = {
+	.name = "USIM",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 15,
+	.parent = &pclk2_ck,
+};
+#endif
+
+static struct clk fci_ck = {
+	.name = "FCI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 16,
+	.parent = &fc_ck,
+};
+
+static struct clk usbd_ck = {
+	.name = "USBD",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 17,
+	.parent = &hclk2_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk iis_ck = {
+	.name = "IIS",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 18,
+	.parent = &clk24m_ck,
+};
+
+static struct clk rfsm1_ck = {
+	.name = "RFSM1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 19,
+	.parent = &pclk1_ck,
+};
+#endif
+
+static struct clk dmau_ck = {
+	.name = "DMAU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_shared_clock,
+	.disable = u67xx_cgu_disable_shared_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 20,
+	.parent = &hclk2_ck,
+};
+
+static struct clk jdi_ck = {
+	.name = "JDI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 24,
+	.parent = &pclk2_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk ucc_ck = {
+	.name = "UCC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 25,
+	.parent = &pclk1_ck,
+};
+#endif
+
+static struct clk msi_ck = {
+	.name = "MSI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 26,
+	.parent = &fc_ck,
+};
+
+static struct clk sdi_ck = {
+	.name = "SDI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 28,
+	.parent = &hclk2_ck,
+};
+
+static struct clk nfi_ck = {
+	.name = "NFI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 29,
+	.parent = &hclk2_ck,
+
+};
+
+static struct clk ebi_ck = {
+	.name = "EBI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 31,
+	.parent = &hclk2_ck,
+
+};
+
+/* CGUGATESC2 */
+static struct clk cae_ck = {
+	.name = "CAE",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC2_REG,
+	.enable_bit = 0,
+	.parent = &pclk1_ck,
+};
+
+static struct clk mmtu_ck = {
+	.name = "MMTU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_shared_clock,
+	.disable = u67xx_cgu_disable_shared_clock,
+	.enable_reg = CGU_GATESC2_REG,
+	.enable_bit = 2,
+	.parent = &clk13m_ck,
+	.usecount = 1,
+};
+
+/* OCL-2008-07-02: how to manage etbclk ? */
+/* static struct clk ETB_ck = */
+/* { */
+/* 	.name = "ETB", */
+/* 	.enable_reg = CGU_GATESC2_REG, */
+/* 	.enable_bit = 4, */
+/* 	.parent = &etbclk_ck, */
+/* }; */
+
+/* CGUGATEIVS */
+static struct clk cam_ck = {
+	.name = "CAM",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 0,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk vde_ck = {
+	.name = "VDE",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 1,
+	.parent = &hclk2_ck,
+};
+
+static struct clk ipp_ck = {
+	.name = "IPP",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 2,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk vec_ck = {
+	.name = "VEC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 3,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk vdc_ck = {
+	.name = "VDC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 4,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk jdu_ck = {
+	.name = "JDU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 5,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk tvoclk_ck = {
+	.name = "TVO",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 6,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk camjpe_ck = {
+	.name = "CAMJPE",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 7,
+	.parent = &hclk_ck,
+};
+
+#define CLK(pck)	\
+	{			\
+		.dev_id = NULL,	\
+		.con_id = NULL,	\
+		.clk = pck,	\
+	}
+
+struct clk_lookup onchip_clks[] = {
+	/* external root sources */
+	CLK(&func_32k_ck),
+	CLK(&osc_ck),
+	CLK(&sys_ck),
+	CLK(&sc_ck),
+	CLK(&fix_ck),
+	CLK(&tv_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&dsp2_ck),
+#endif
+	CLK(&sdm_ck),
+	CLK(&arm_ck),
+	CLK(&hclk_ck),
+	CLK(&hclk2_ck),
+	CLK(&pclk1_ck),
+	CLK(&pclk2_ck),
+	CLK(&tvclk_ck),
+	CLK(&clk24m_ck),
+	CLK(&clk26m_ck),
+	CLK(&clk13m_ck),
+	CLK(&clk4m_ck),
+	CLK(&fc_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&sioy1clk_ck),
+	CLK(&sioy2clk_ck),
+	CLK(&rfclk_ck),
+#endif
+	CLK(&usb_h_ck),
+	CLK(&usb_d_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&dcclk1_ck),
+	CLK(&diclk1_ck),
+	CLK(&dcclk2_ck),
+	CLK(&diclk2_ck),
+#endif
+	CLK(&camo_ck),
+	CLK(&tvoclk_ck),
+	CLK(&plltv_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&intc_ck),
+	CLK(&extint_ck),
+	CLK(&sctu_ck),
+#endif
+	CLK(&spi1_ck),
+	CLK(&spi2_ck),
+	CLK(&iic1_ck),
+	CLK(&iic2_ck),
+	CLK(&uart1_ck),
+	CLK(&uart2_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&gpio_ck),
+#endif
+	CLK(&kbs_ck),
+	CLK(&pwm1_ck),
+	CLK(&pwm2_ck),
+	CLK(&pwm3_ck),
+	CLK(&geac_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&usim_ck),
+#endif
+	CLK(&fci_ck),
+	CLK(&usbd_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&iis_ck),
+	CLK(&rfsm1_ck),
+#endif
+	CLK(&dmau_ck),
+	CLK(&jdi_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&ucc_ck),
+#endif
+	CLK(&msi_ck),
+	CLK(&sdi_ck),
+	CLK(&nfi_ck),
+	CLK(&ebi_ck),
+	CLK(&cae_ck),
+	CLK(&mmtu_ck),
+	CLK(&sdm_ivs_ck),
+	CLK(&cam_ck),
+	CLK(&vde_ck),
+	CLK(&vdc_ck),
+	CLK(&vec_ck),
+	CLK(&ipp_ck),
+	CLK(&jdu_ck),
+	CLK(&camjpe_ck),
+	CLK(NULL)
+};
+
diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
index 12c832c..afdf82b 100644
--- a/arch/arm/plat-u6xxx/Makefile
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -3,6 +3,6 @@
 #
 
 # Common support
-obj-y := io.o irq.o
+obj-y := io.o irq.o clock.o
 
 obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/clock.c b/arch/arm/plat-u6xxx/clock.c
new file mode 100644
index 0000000..ecff187
--- /dev/null
+++ b/arch/arm/plat-u6xxx/clock.c
@@ -0,0 +1,621 @@
+/*
+ * linux/arch/arm/plat-u6xxx/clock.c
+ *
+ *  Copyright (C) 2004 - 2005 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
+ *
+ *  Modified for u6 shared clock framework by Loic Pallardy @ ST-Ericsson.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+
+#include <linux/io.h>
+
+#include <mach/clock.h>
+
+LIST_HEAD(clocks);
+
+static DEFINE_MUTEX(clocks_mutex);
+DEFINE_SPINLOCK(clockfw_lock);
+
+static struct clk_functions *arch_clock;
+
+/*
+ * Additionnal specific clock functions define in include/mach/clock.h
+ */
+
+/**
+ *	clk_register_notifier - register a driver with clock mngt
+ *	@nb: notifier function to register
+ *  @clk: clock element rate change to be notified
+ *
+ *	Add a driver to one of two lists: either a list of drivers that
+ *      are notified about clock rate changes (once before and once after
+ *      the transition),
+ *	This function may sleep, and has the same return conditions as
+ *	sru_blocking_notifier_chain_register.
+ */
+int clk_register_notifier(struct notifier_block *nb, struct clk *clk)
+{
+	int ret;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+	if (clk->notifier)
+		ret = srcu_notifier_chain_register(clk->notifier, nb);
+	else
+		ret = -EINVAL;
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_register_notifier);
+
+/**
+ *	clk_unregister_notifier - unregister a driver with clock mngt
+ *	@nb: notifier function to be unregistered
+ *  @clk: clock element rate change to be notified
+ *
+ *	Remove a driver from the clock mngt notifier list.
+ *
+ *	This function may sleep, and has the same return conditions as
+ *	sru_blocking_notifier_chain_unregister.
+ */
+int clk_unregister_notifier(struct notifier_block *nb, struct clk *clk)
+{
+	int ret;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+	if (clk->notifier)
+		ret = srcu_notifier_chain_unregister(clk->notifier, nb);
+	else
+		ret = -EINVAL;
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_unregister_notifier);
+
+/**
+ * clk_notify_transition - call notifier chain
+ *
+ * This function calls the transition notifiers and the and set rate
+ * It is called twice on all frequency changes that have
+ * external effects.
+ */
+int clk_notify_transition(struct clk *clk, unsigned int state, void *data)
+{
+	BUG_ON(irqs_disabled());
+
+	if (clk == ERR_PTR(-ENOENT))
+		return NOTIFY_BAD;
+
+	switch (state) {
+
+	case CLK_RATE_PRECHANGE:
+	case CLK_RATE_POSTCHANGE:
+/*		printk("notif %u of frequency transition of %s to %lu Hz\n",
+			state, clk->name, (unsigned long)data);
+*/
+		break;
+
+	case CLK_SRCE_PRECHANGE:
+	case CLK_SRCE_POSTCHANGE:
+/*              printk("notif %u of srce transition of %s to %s\n",
+			state, clk->name, ((struct clk *)data)->name);
+*/
+		break;
+	default:
+		printk(KERN_ERR "Unknown notification srce transition\n");
+		return NOTIFY_BAD;
+		break;
+	}
+
+	return srcu_notifier_call_chain(clk->notifier, state, data);
+}
+
+/*
+ * Standard clock functions defined in include/linux/clk.h
+ */
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_enable)
+		ret = arch_clock->clk_enable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_disable)
+		arch_clock->clk_disable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_get_usecount(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = clk->usecount;
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_usecount);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long flags;
+	unsigned long ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = clk->rate;
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/*
+ * Optional clock functions defined in include/linux/clk.h
+ */
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long flags;
+	long ret = rate;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_round_rate)
+		ret = arch_clock->clk_round_rate(clk, rate);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	/* notification pre change */
+	if (clk->notifier)
+		ret = clk_notify_transition(clk,
+					    CLK_RATE_PRECHANGE, (void *)rate);
+
+	if (!(ret & NOTIFY_STOP_MASK)) {
+		spin_lock_irqsave(&clockfw_lock, flags);
+		if (arch_clock->clk_set_rate)
+			ret = arch_clock->clk_set_rate(clk, rate);
+		spin_unlock_irqrestore(&clockfw_lock, flags);
+
+		/* notification post change */
+		if (clk->notifier)
+			clk_notify_transition(clk,
+					      CLK_RATE_POSTCHANGE,
+					      (void *)clk->rate);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	/* notification pre change */
+	if (clk->notifier)
+		ret = clk_notify_transition(clk,
+					    CLK_SRCE_PRECHANGE, (void *)parent);
+
+	if (!(ret & NOTIFY_STOP_MASK)) {
+		spin_lock_irqsave(&clockfw_lock, flags);
+		if (arch_clock->clk_set_parent)
+			ret = arch_clock->clk_set_parent(clk, parent);
+		spin_unlock_irqrestore(&clockfw_lock, flags);
+
+		/* notification post change */
+		if (clk->notifier)
+			clk_notify_transition(clk,
+					      CLK_SRCE_POSTCHANGE,
+					      (void *)clk->parent);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	unsigned long flags;
+	struct clk *ret = ERR_PTR(-ENOENT);
+
+	if (clk == ERR_PTR(-ENOENT))
+		return ret;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_get_parent)
+		ret = arch_clock->clk_get_parent(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+/*
+ * Internal clock functions
+ */
+
+unsigned int __initdata mpurate;
+/*
+ * By default we use the rate set by the bootloader.
+ * You can override this with mpurate= cmdline option.
+ */
+static int __init u6_clk_setup(char *str)
+{
+	unsigned int tmp_rate;
+
+	get_option(&str, &tmp_rate);
+
+	if (!tmp_rate)
+		return 1;
+
+	mpurate = tmp_rate;
+
+	return 1;
+}
+
+__setup("mpurate=", u6_clk_setup);
+
+/* Used for clocks that always have same value as the parent clock */
+void followparent_recalc(struct clk *clk)
+{
+	clk->rate = clk->parent->rate;
+}
+
+/* Propagate rate to children */
+void propagate_rate(struct clk *tclk)
+{
+	struct clk *clkp;
+
+	list_for_each_entry(clkp, &clocks, node) {
+		if (likely(clkp->parent != tclk))
+			continue;
+		if (likely((u32) clkp->recalc))
+			clkp->recalc(clkp);
+	}
+}
+
+int clk_register(struct clk *clk)
+{
+	mutex_lock(&clocks_mutex);
+	list_add(&clk->node, &clocks);
+	if (clk->init)
+		clk->init(clk);
+	mutex_unlock(&clocks_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+	mutex_lock(&clocks_mutex);
+	list_del(&clk->node);
+	mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+void clk_deny_idle(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_deny_idle)
+		arch_clock->clk_deny_idle(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_deny_idle);
+
+void clk_allow_idle(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_allow_idle)
+		arch_clock->clk_allow_idle(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_allow_idle);
+
+#ifdef CONFIG_U6_POWER_SYSFS
+/*
+ * SysFs interface
+ */
+
+/*** Clock mngt sysfs interface **/
+static char clk_name[64] = "MMTU";
+
+static ssize_t show_select(struct kobject *kobj, char *buf)
+{
+	return sprintf(buf, "%s \n", clk_name);
+}
+
+static ssize_t store_select(struct kobject *kobj, const char *buf, size_t size)
+{
+	strcpy(clk_name, buf);
+
+	clk_name[strlen(clk_name) - 1] = 0;
+
+	return size;
+}
+
+static ssize_t show_enable(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%d \n", clk_get_usecount(clk));
+}
+
+static ssize_t store_enable(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return size;
+	clk_enable(clk);
+	clk_put(clk);
+	return size;
+}
+
+static ssize_t show_disable(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%d \n", clk_get_usecount(clk));
+}
+
+static ssize_t store_disable(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return size;
+	clk_disable(clk);
+	clk_put(clk);
+	return size;
+}
+
+static ssize_t show_usecount(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%d \n", clk_get_usecount(clk));
+}
+
+static ssize_t show_rate(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%lu \n", clk_get_rate(clk));
+}
+
+static ssize_t store_rate(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk;
+	unsigned long rate;
+	if (strict_strtoul(buf, 10, &rate) == 0) {
+		clk = clk_get(NULL, clk_name);
+		if (clk == ERR_PTR(-ENOENT))
+			return size;
+		clk_set_rate(clk, rate);
+		clk_put(clk);
+	}
+	return size;
+}
+
+static ssize_t show_parent(struct kobject *kobj, char *buf)
+{
+	struct clk *clk, *pclk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	pclk = clk_get_parent(clk);
+	clk_put(clk);
+	if ((pclk) && (pclk->name))
+		return sprintf(buf, "%s\n", pclk->name);
+	else
+		return sprintf(buf, "root\n");
+}
+
+static ssize_t store_parent(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk, *pclk;
+	char parent[32];
+	strcpy(parent, buf);
+	parent[strlen(parent) - 1] = 0;
+
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return size;
+
+	pclk = clk_get(NULL, parent);
+	if (pclk == ERR_PTR(-ENOENT)) {
+		clk_put(clk);
+		return size;
+	}
+	clk_put(pclk);
+	clk_set_parent(clk, pclk);
+	clk_put(clk);
+	return size;
+}
+
+static ssize_t show_list(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+
+	struct clk *p;
+
+	list_for_each_entry(p, &clocks, node) {
+		size += sprintf(&buf[size], "%s\n", p->name);
+	}
+	return size;
+}
+
+/*** Clock mngt hw debug ***/
+static ssize_t show_hw_constraints(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+
+	size += u6_clk_show_hw_rates(kobj, &buf[size]);
+
+	size += u6_clk_show_sc_constraints(kobj, &buf[size]);
+
+	size += u6_clk_show_ivs_constraints(kobj, &buf[size]);
+
+	size += u6_clk_show_tvo_constraints(kobj, &buf[size]);
+
+	size += u6_clk_show_cam_constraints(kobj, &buf[size]);
+
+	return size;
+}
+
+static ssize_t show_hw_rates(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+
+	size += u6_clk_show_hw_rates(kobj, buf);
+
+	return size;
+}
+
+define_one_ro(hw_rates);
+define_one_ro(hw_constraints);
+define_one_rw(parent);
+define_one_rw(rate);
+define_one_ro(usecount);
+define_one_rw(disable);
+define_one_rw(enable);
+define_one_rw(select);
+define_one_ro(list);
+
+static struct attribute *dbs_attributes_clock[] = {
+
+	&hw_rates.attr,
+	&hw_constraints.attr,
+	&parent.attr,
+	&rate.attr,
+	&usecount.attr,
+	&disable.attr,
+	&enable.attr,
+	&select.attr,
+	&list.attr,
+	NULL
+};
+
+static struct attribute_group dbs_attr_clock_group = {
+	.attrs = dbs_attributes_clock,
+	.name = "clk_mngt",
+};
+
+#endif
+
+/*
+ * Init functions
+ */
+
+int __init clk_init(struct clk_functions *custom_clocks)
+{
+	if (!custom_clocks) {
+		printk(KERN_ERR "No custom clock functions registered\n");
+		BUG();
+	}
+
+	arch_clock = custom_clocks;
+
+	return 0;
+}
+
+#ifdef CONFIG_U6_POWER_SYSFS
+static int __init u6_clock_init_sysfs(void)
+{
+	if (sysfs_create_group(&u6_power_kobj, &dbs_attr_clock_group))
+		printk(KERN_ERR "Unable to register %s in sysfs\n",
+		       dbs_attr_clock_group.name);
+
+	return 0;
+}
+
+module_init(u6_clock_init_sysfs);
+#endif
+
diff --git a/arch/arm/plat-u6xxx/include/mach/clkdev.h b/arch/arm/plat-u6xxx/include/mach/clkdev.h
new file mode 100644
index 0000000..730c49d
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/clkdev.h
@@ -0,0 +1,13 @@
+#ifndef __MACH_CLKDEV_H
+#define __MACH_CLKDEV_H
+
+static inline int __clk_get(struct clk *clk)
+{
+	return 1;
+}
+
+static inline void __clk_put(struct clk *clk)
+{
+}
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/clock.h b/arch/arm/plat-u6xxx/include/mach/clock.h
new file mode 100644
index 0000000..ded9fdd
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/clock.h
@@ -0,0 +1,378 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/clock.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ */
+
+#ifndef __PLAT_CLOCK_H
+#define __PLAT_CLOCK_H
+
+#include <linux/io.h>
+
+struct module;
+
+struct clk {
+	struct list_head	node;
+	struct module		*owner;
+	const char		*name;
+	struct clk		*parent;
+	unsigned long		rate;
+	__u32			flags;
+	void __iomem		*enable_reg;
+	__u8			enable_bit;
+	__u8			rate_offset;
+	__u8			src_offset;
+	__s8			usecount;
+	void			(*recalc)(struct clk *);
+	int			(*set_rate)(struct clk *, unsigned long);
+	long			(*round_rate)(struct clk *, unsigned long);
+	void			(*init)(struct clk *);
+	int			(*enable)(struct clk *);
+	void			(*disable)(struct clk *);
+	int			(*set_parent)(struct clk *, struct clk *);
+	struct srcu_notifier_head *notifier;
+};
+
+struct clk_functions {
+	int		(*clk_enable)(struct clk *clk);
+	void		(*clk_disable)(struct clk *clk);
+	long		(*clk_round_rate)(struct clk *clk, unsigned long rate);
+	int		(*clk_set_rate)(struct clk *clk, unsigned long rate);
+	int		(*clk_set_parent)(struct clk *clk, struct clk *parent);
+	struct clk *	(*clk_get_parent)(struct clk *clk);
+	void		(*clk_allow_idle)(struct clk *clk);
+	void		(*clk_deny_idle)(struct clk *clk);
+};
+
+extern unsigned int mpurate;
+extern struct list_head clocks;
+extern spinlock_t clockfw_lock;
+
+extern int clk_init(struct clk_functions *custom_clocks);
+extern int clk_register(struct clk *clk);
+extern void clk_unregister(struct clk *clk);
+
+extern void propagate_rate(struct clk *clk);
+extern void followparent_recalc(struct clk *clk);
+extern void clk_allow_idle(struct clk *clk);
+extern void clk_deny_idle(struct clk *clk);
+extern int clk_get_usecount(struct clk *clk);
+
+extern ssize_t u6_clk_show_hw_rates(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_sc_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_usb_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_ivs_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_tvo_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_cam_constraints(struct kobject *kobj, char *buf);
+
+extern unsigned long clk_get_hw_constraint(void __iomem *reg_addr);
+
+
+/* Clock flags */
+#define RATE_CKCTL		(1 << 0)	/* Main fixed ratio clocks */
+#define RATE_FIXED		(1 << 1)	/* Fixed clock rate */
+#define RATE_PROPAGATES		(1 << 2)	/* Program children too */
+#define VIRTUAL_CLOCK		(1 << 3)	/* Composite clock from table */
+#define ALWAYS_ENABLED		(1 << 4)	/* Clock cannot be disabled */
+#define ENABLE_REG_32BIT	(1 << 5)	/* Use 32-bit access */
+#define VIRTUAL_IO_ADDRESS	(1 << 6)	/* Clock in virtual address */
+#define CLOCK_IDLE_CONTROL	(1 << 7)
+#define CLOCK_NO_IDLE_PARENT	(1 << 8)
+#define DELAYED_APP		(1 << 9)	/* Delay application of clock */
+#define CONFIG_PARTICIPANT	(1 << 10)	/* Fundamental clock */
+
+
+#define CLK_HCLK2_MAX_FREQ	104000000
+#define CLK_FC_CLK_MAX_FREQ	104000000
+#define CLK_CAM_CLK_MAX_FREQ	 78000000
+
+/**
+ * clk_register_notifier - register a driver with clock mngt
+ *	@nb: notifier function to register
+ *  @clk: clock element rate change to be notified
+ */
+extern int clk_register_notifier(struct notifier_block *nb, struct clk *clk);
+
+/**
+ * clk_unregister_notifier - unregister a driver with clock mngt
+ *	@nb: notifier function to register
+ *  @clk: clock element rate change to be notified
+ */
+extern int clk_unregister_notifier(struct notifier_block *nb, struct clk *clk);
+
+/**
+ * clk_notify_transition - call notifier chain
+ *
+ * This function calls the transition notifiers and the and set rate
+ * It is called twice on all frequency changes that have
+ * external effects.
+ */
+extern int clk_notify_transition(struct clk *clk,
+		unsigned int state, void *data);
+
+#define CLK_RATE_PRECHANGE 0
+#define CLK_RATE_POSTCHANGE 1
+#define CLK_SRCE_PRECHANGE 2
+#define CLK_SRCE_POSTCHANGE 3
+
+/* Hardware Register Definitions CGU (Clock Gating Unit) */
+
+/* CGU DSP1CON Register (32 bits) */
+#define CGU_DSP1CON_OFFSET             0x0
+#define CGU_DSP1CON_REG                U6_IO_ADDRESS(CGU_BASE + CGU_DSP1CON_OFFSET)
+
+/* CGU SCCON Register (32 bits) */
+#define CGU_SCCON_OFFSET               0x4
+#define CGU_SCCON_REG                  U6_IO_ADDRESS(CGU_BASE + CGU_SCCON_OFFSET)
+
+/* CGU GATESC1 Register (32 bits) */
+#define CGU_GATESC1_OFFSET             0x8
+#define CGU_GATESC1_REG                U6_IO_ADDRESS(CGU_BASE + CGU_GATESC1_OFFSET)
+
+/* CGU SLEEPSC Register (32 bits) */
+#define CGU_SLEEPSC_OFFSET             0xC
+#define CGU_SLEEPSC_REG                U6_IO_ADDRESS(CGU_BASE + CGU_SLEEPSC_OFFSET)
+
+/* CGU FDIV Register (32 bits) */
+#define CGU_FDIV_OFFSET                0x10
+#define CGU_FDIV_REG                   U6_IO_ADDRESS(CGU_BASE + CGU_FDIV_OFFSET)
+
+/* CGU GATEIVS Register (32 bits) */
+#define CGU_GATEIVS_OFFSET             0x14
+#define CGU_GATEIVS_REG                U6_IO_ADDRESS(CGU_BASE + CGU_GATEIVS_OFFSET)
+
+/* CGU DSP2CON Register (32 bits) */
+#define CGU_DSP2CON_OFFSET             0x18
+#define CGU_DSP2CON_REG                U6_IO_ADDRESS(CGU_BASE + CGU_DSP2CON_OFFSET)
+
+/* CGU CAMCON Register (32 bits) */
+#define CGU_CAMCON_OFFSET              0x1C
+#define CGU_CAMCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_CAMCON_OFFSET)
+
+/* CGU GATESC2 Register (32 bits) */
+#define CGU_GATESC2_OFFSET             0x20
+#define CGU_GATESC2_REG                U6_IO_ADDRESS(CGU_BASE + CGU_GATESC2_OFFSET)
+
+/* CGU SDMCON Register (32 bits) */
+#define CGU_SDMCON_OFFSET              0x24
+#define CGU_SDMCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_SDMCON_OFFSET)
+
+/* CGU TVCON Register (32 bits) */
+#define CGU_TVCON_OFFSET               0x28
+#define CGU_TVCON_REG                  U6_IO_ADDRESS(CGU_BASE + CGU_TVCON_OFFSET)
+
+/* CGU IDLESC Register (32 bits) */
+#define CGU_IDLESC_OFFSET              0x2C
+#define CGU_IDLESC_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_IDLESC_OFFSET)
+
+/* CGU FIXCON Register (32 bits) */
+#define CGU_FIXCON_OFFSET              0x30
+#define CGU_FIXCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_FIXCON_OFFSET)
+
+/* CGU CNTCON Register (32 bits) */
+#define CGU_CNTCON_OFFSET              0x38
+#define CGU_CNTCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_CNTCON_OFFSET)
+
+/* Register description for GATESC1 */
+
+/* Bits definition for register CGU_GATESC1 */
+#define CGU_EBIEN_SHIFT            31
+#define CGU_EBIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_EBIEN_SHIFT))
+#define CGU_EBIEN_0                (0x0UL<<CGU_EBIEN_SHIFT)
+#define CGU_EBIEN_1                (0x1UL<<CGU_EBIEN_SHIFT)
+#define CGU_EBIEN                  (0x1UL<<CGU_EBIEN_SHIFT)
+#define CGU_NFIEN_SHIFT            29
+#define CGU_NFIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_NFIEN_SHIFT))
+#define CGU_NFIEN_0                (0x0UL<<CGU_NFIEN_SHIFT)
+#define CGU_NFIEN_1                (0x1UL<<CGU_NFIEN_SHIFT)
+#define CGU_NFIEN                  (0x1UL<<CGU_NFIEN_SHIFT)
+#define CGU_SDIEN_SHIFT            28
+#define CGU_SDIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_SDIEN_SHIFT))
+#define CGU_SDIEN_0                (0x0UL<<CGU_SDIEN_SHIFT)
+#define CGU_SDIEN_1                (0x1UL<<CGU_SDIEN_SHIFT)
+#define CGU_SDIEN                  (0x1UL<<CGU_SDIEN_SHIFT)
+#define CGU_MSIEN_SHIFT            26
+#define CGU_MSIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_MSIEN_SHIFT))
+#define CGU_MSIEN_0                (0x0UL<<CGU_MSIEN_SHIFT)
+#define CGU_MSIEN_1                (0x1UL<<CGU_MSIEN_SHIFT)
+#define CGU_MSIEN                  (0x1UL<<CGU_MSIEN_SHIFT)
+#define CGU_UCCEN_SHIFT            25
+#define CGU_UCCEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_UCCEN_SHIFT))
+#define CGU_UCCEN_0                (0x0UL<<CGU_UCCEN_SHIFT)
+#define CGU_UCCEN_1                (0x1UL<<CGU_UCCEN_SHIFT)
+#define CGU_UCCEN                  (0x1UL<<CGU_UCCEN_SHIFT)
+#define CGU_JDIEN_SHIFT            24
+#define CGU_JDIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_JDIEN_SHIFT))
+#define CGU_JDIEN_0                (0x0UL<<CGU_JDIEN_SHIFT)
+#define CGU_JDIEN_1                (0x1UL<<CGU_JDIEN_SHIFT)
+#define CGU_JDIEN                  (0x1UL<<CGU_JDIEN_SHIFT)
+#define CGU_DMAUEN_SHIFT           20
+#define CGU_DMAUEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_DMAUEN_SHIFT))
+#define CGU_DMAUEN_0               (0x0UL<<CGU_DMAUEN_SHIFT)
+#define CGU_DMAUEN_1               (0x1UL<<CGU_DMAUEN_SHIFT)
+#define CGU_DMAUEN                 (0x1UL<<CGU_DMAUEN_SHIFT)
+#define CGU_RFSM1EN_SHIFT          19
+#define CGU_RFSM1EN_FIELD          (0xFFFFFFFF - (0x1UL<<CGU_RFSM1EN_SHIFT))
+#define CGU_RFSM1EN_0              (0x0UL<<CGU_RFSM1EN_SHIFT)
+#define CGU_RFSM1EN_1              (0x1UL<<CGU_RFSM1EN_SHIFT)
+#define CGU_RFSM1EN                (0x1UL<<CGU_RFSM1EN_SHIFT)
+#define CGU_SIISEN_SHIFT           18
+#define CGU_SIISEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SIISEN_SHIFT))
+#define CGU_SIISEN_0               (0x0UL<<CGU_SIISEN_SHIFT)
+#define CGU_SIISEN_1               (0x1UL<<CGU_SIISEN_SHIFT)
+#define CGU_SIISEN                 (0x1UL<<CGU_SIISEN_SHIFT)
+#define CGU_USBEN_SHIFT            17
+#define CGU_USBEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_USBEN_SHIFT))
+#define CGU_USBEN_0                (0x0UL<<CGU_USBEN_SHIFT)
+#define CGU_USBEN_1                (0x1UL<<CGU_USBEN_SHIFT)
+#define CGU_USBEN                  (0x1UL<<CGU_USBEN_SHIFT)
+#define CGU_FCIEN_SHIFT            16
+#define CGU_FCIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_FCIEN_SHIFT))
+#define CGU_FCIEN_0                (0x0UL<<CGU_FCIEN_SHIFT)
+#define CGU_FCIEN_1                (0x1UL<<CGU_FCIEN_SHIFT)
+#define CGU_FCIEN                  (0x1UL<<CGU_FCIEN_SHIFT)
+#define CGU_USIMEN_SHIFT           15
+#define CGU_USIMEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_USIMEN_SHIFT))
+#define CGU_USIMEN_0               (0x0UL<<CGU_USIMEN_SHIFT)
+#define CGU_USIMEN_1               (0x1UL<<CGU_USIMEN_SHIFT)
+#define CGU_USIMEN                 (0x1UL<<CGU_USIMEN_SHIFT)
+#define CGU_GEACEN_SHIFT           14
+#define CGU_GEACEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_GEACEN_SHIFT))
+#define CGU_GEACEN_0               (0x0UL<<CGU_GEACEN_SHIFT)
+#define CGU_GEACEN_1               (0x1UL<<CGU_GEACEN_SHIFT)
+#define CGU_GEACEN                 (0x1UL<<CGU_GEACEN_SHIFT)
+#define CGU_PWM3EN_SHIFT           13
+#define CGU_PWM3EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_PWM3EN_SHIFT))
+#define CGU_PWM3EN_0               (0x0UL<<CGU_PWM3EN_SHIFT)
+#define CGU_PWM3EN_1               (0x1UL<<CGU_PWM3EN_SHIFT)
+#define CGU_PWM3EN                 (0x1UL<<CGU_PWM3EN_SHIFT)
+#define CGU_PWM2EN_SHIFT           12
+#define CGU_PWM2EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_PWM2EN_SHIFT))
+#define CGU_PWM2EN_0               (0x0UL<<CGU_PWM2EN_SHIFT)
+#define CGU_PWM2EN_1               (0x1UL<<CGU_PWM2EN_SHIFT)
+#define CGU_PWM2EN                 (0x1UL<<CGU_PWM2EN_SHIFT)
+#define CGU_PWM1EN_SHIFT           11
+#define CGU_PWM1EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_PWM1EN_SHIFT))
+#define CGU_PWM1EN_0               (0x0UL<<CGU_PWM1EN_SHIFT)
+#define CGU_PWM1EN_1               (0x1UL<<CGU_PWM1EN_SHIFT)
+#define CGU_PWM1EN                 (0x1UL<<CGU_PWM1EN_SHIFT)
+#define CGU_KBSEN_SHIFT            10
+#define CGU_KBSEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_KBSEN_SHIFT))
+#define CGU_KBSEN_0                (0x0UL<<CGU_KBSEN_SHIFT)
+#define CGU_KBSEN_1                (0x1UL<<CGU_KBSEN_SHIFT)
+#define CGU_KBSEN                  (0x1UL<<CGU_KBSEN_SHIFT)
+#define CGU_GPIOEN_SHIFT           9
+#define CGU_GPIOEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_GPIOEN_SHIFT))
+#define CGU_GPIOEN_0               (0x0UL<<CGU_GPIOEN_SHIFT)
+#define CGU_GPIOEN_1               (0x1UL<<CGU_GPIOEN_SHIFT)
+#define CGU_GPIOEN                 (0x1UL<<CGU_GPIOEN_SHIFT)
+#define CGU_UART2EN_SHIFT          8
+#define CGU_UART2EN_FIELD          (0xFFFFFFFF - (0x1UL<<CGU_UART2EN_SHIFT))
+#define CGU_UART2EN_0              (0x0UL<<CGU_UART2EN_SHIFT)
+#define CGU_UART2EN_1              (0x1UL<<CGU_UART2EN_SHIFT)
+#define CGU_UART2EN                (0x1UL<<CGU_UART2EN_SHIFT)
+#define CGU_UART1EN_SHIFT          7
+#define CGU_UART1EN_FIELD          (0xFFFFFFFF - (0x1UL<<CGU_UART1EN_SHIFT))
+#define CGU_UART1EN_0              (0x0UL<<CGU_UART1EN_SHIFT)
+#define CGU_UART1EN_1              (0x1UL<<CGU_UART1EN_SHIFT)
+#define CGU_UART1EN                (0x1UL<<CGU_UART1EN_SHIFT)
+#define CGU_IIC2EN_SHIFT           6
+#define CGU_IIC2EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_IIC2EN_SHIFT))
+#define CGU_IIC2EN_0               (0x0UL<<CGU_IIC2EN_SHIFT)
+#define CGU_IIC2EN_1               (0x1UL<<CGU_IIC2EN_SHIFT)
+#define CGU_IIC2EN                 (0x1UL<<CGU_IIC2EN_SHIFT)
+#define CGU_IIC1EN_SHIFT           5
+#define CGU_IIC1EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_IIC1EN_SHIFT))
+#define CGU_IIC1EN_0               (0x0UL<<CGU_IIC1EN_SHIFT)
+#define CGU_IIC1EN_1               (0x1UL<<CGU_IIC1EN_SHIFT)
+#define CGU_IIC1EN                 (0x1UL<<CGU_IIC1EN_SHIFT)
+#define CGU_SPI2EN_SHIFT           4
+#define CGU_SPI2EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SPI2EN_SHIFT))
+#define CGU_SPI2EN_0               (0x0UL<<CGU_SPI2EN_SHIFT)
+#define CGU_SPI2EN_1               (0x1UL<<CGU_SPI2EN_SHIFT)
+#define CGU_SPI2EN                 (0x1UL<<CGU_SPI2EN_SHIFT)
+#define CGU_SPI1EN_SHIFT           3
+#define CGU_SPI1EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SPI1EN_SHIFT))
+#define CGU_SPI1EN_0               (0x0UL<<CGU_SPI1EN_SHIFT)
+#define CGU_SPI1EN_1               (0x1UL<<CGU_SPI1EN_SHIFT)
+#define CGU_SPI1EN                 (0x1UL<<CGU_SPI1EN_SHIFT)
+#define CGU_SCTUEN_SHIFT           2
+#define CGU_SCTUEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SCTUEN_SHIFT))
+#define CGU_SCTUEN_0               (0x0UL<<CGU_SCTUEN_SHIFT)
+#define CGU_SCTUEN_1               (0x1UL<<CGU_SCTUEN_SHIFT)
+#define CGU_SCTUEN                 (0x1UL<<CGU_SCTUEN_SHIFT)
+#define CGU_EXTINTEN_SHIFT         1
+#define CGU_EXTINTEN_FIELD         (0xFFFFFFFF - (0x1UL<<CGU_EXTINTEN_SHIFT))
+#define CGU_EXTINTEN_0             (0x0UL<<CGU_EXTINTEN_SHIFT)
+#define CGU_EXTINTEN_1             (0x1UL<<CGU_EXTINTEN_SHIFT)
+#define CGU_EXTINTEN               (0x1UL<<CGU_EXTINTEN_SHIFT)
+#define CGU_INTCEN_SHIFT           0
+#define CGU_INTCEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_INTCEN_SHIFT))
+#define CGU_INTCEN_0               (0x0UL<<CGU_INTCEN_SHIFT)
+#define CGU_INTCEN_1               (0x1UL<<CGU_INTCEN_SHIFT)
+#define CGU_INTCEN                 (0x1UL<<CGU_INTCEN_SHIFT)
+
+/* Register description for GATESC2 */
+
+/* Bits definition for register CGU_GATESC2 */
+#define CGU_TRAUPCLKEN_SHIFT       15
+#define CGU_TRAUPCLKEN_FIELD       (0xFFFFFFFF - (0x1UL<<CGU_TRAUPCLKEN_SHIFT))
+#define CGU_TRAUPCLKEN_0           (0x0UL<<CGU_TRAUPCLKEN_SHIFT)
+#define CGU_TRAUPCLKEN_1           (0x1UL<<CGU_TRAUPCLKEN_SHIFT)
+#define CGU_TRAUPCLKEN             (0x1UL<<CGU_TRAUPCLKEN_SHIFT)
+#define CGU_AUTRXPCLKEN_SHIFT      12
+#define CGU_AUTRXPCLKEN_FIELD      (0xFFFFFFFF - (0x1UL<<CGU_AUTRXPCLKEN_SHIFT))
+#define CGU_AUTRXPCLKEN_0          (0x0UL<<CGU_AUTRXPCLKEN_SHIFT)
+#define CGU_AUTRXPCLKEN_1          (0x1UL<<CGU_AUTRXPCLKEN_SHIFT)
+#define CGU_AUTRXPCLKEN            (0x1UL<<CGU_AUTRXPCLKEN_SHIFT)
+#define CGU_AUTRXMCLK2EN_SHIFT     11
+#define CGU_AUTRXMCLK2EN_FIELD    (0xFFFFFFFF - (0x1UL<<CGU_AUTRXMCLK2EN_SHIFT))
+#define CGU_AUTRXMCLK2EN_0         (0x0UL<<CGU_AUTRXMCLK2EN_SHIFT)
+#define CGU_AUTRXMCLK2EN_1         (0x1UL<<CGU_AUTRXMCLK2EN_SHIFT)
+#define CGU_AUTRXMCLK2EN           (0x1UL<<CGU_AUTRXMCLK2EN_SHIFT)
+#define CGU_AUTRXMCLK1EN_SHIFT     10
+#define CGU_AUTRXMCLK1EN_FIELD    (0xFFFFFFFF - (0x1UL<<CGU_AUTRXMCLK1EN_SHIFT))
+#define CGU_AUTRXMCLK1EN_0         (0x0UL<<CGU_AUTRXMCLK1EN_SHIFT)
+#define CGU_AUTRXMCLK1EN_1         (0x1UL<<CGU_AUTRXMCLK1EN_SHIFT)
+#define CGU_AUTRXMCLK1EN           (0x1UL<<CGU_AUTRXMCLK1EN_SHIFT)
+#define CGU_BBIPCLKEN_SHIFT        9
+#define CGU_BBIPCLKEN_FIELD        (0xFFFFFFFF - (0x1UL<<CGU_BBIPCLKEN_SHIFT))
+#define CGU_BBIPCLKEN_0            (0x0UL<<CGU_BBIPCLKEN_SHIFT)
+#define CGU_BBIPCLKEN_1            (0x1UL<<CGU_BBIPCLKEN_SHIFT)
+#define CGU_BBIPCLKEN              (0x1UL<<CGU_BBIPCLKEN_SHIFT)
+#define CGU_HSDPAHCLKEN_SHIFT      8
+#define CGU_HSDPAHCLKEN_FIELD      (0xFFFFFFFF - (0x1UL<<CGU_HSDPAHCLKEN_SHIFT))
+#define CGU_HSDPAHCLKEN_0          (0x0UL<<CGU_HSDPAHCLKEN_SHIFT)
+#define CGU_HSDPAHCLKEN_1          (0x1UL<<CGU_HSDPAHCLKEN_SHIFT)
+#define CGU_HSDPAHCLKEN            (0x1UL<<CGU_HSDPAHCLKEN_SHIFT)
+#define CGU_3GMHCLKEN_SHIFT        7
+#define CGU_3GMHCLKEN_FIELD        (0xFFFFFFFF - (0x1UL<<CGU_3GMHCLKEN_SHIFT))
+#define CGU_3GMHCLKEN_0            (0x0UL<<CGU_3GMHCLKEN_SHIFT)
+#define CGU_3GMHCLKEN_1            (0x1UL<<CGU_3GMHCLKEN_SHIFT)
+#define CGU_3GMHCLKEN              (0x1UL<<CGU_3GMHCLKEN_SHIFT)
+#define CGU_3GMMCLKEN_SHIFT        6
+#define CGU_3GMMCLKEN_FIELD        (0xFFFFFFFF - (0x1UL<<CGU_3GMMCLKEN_SHIFT))
+#define CGU_3GMMCLKEN_0            (0x0UL<<CGU_3GMMCLKEN_SHIFT)
+#define CGU_3GMMCLKEN_1            (0x1UL<<CGU_3GMMCLKEN_SHIFT)
+#define CGU_3GMMCLKEN              (0x1UL<<CGU_3GMMCLKEN_SHIFT)
+#define CGU_ETBEN_SHIFT            4
+#define CGU_ETBEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_ETBEN_SHIFT))
+#define CGU_ETBEN_0                (0x0UL<<CGU_ETBEN_SHIFT)
+#define CGU_ETBEN_1                (0x1UL<<CGU_ETBEN_SHIFT)
+#define CGU_ETBEN                  (0x1UL<<CGU_ETBEN_SHIFT)
+#define CGU_MMTUEN_SHIFT           2
+#define CGU_MMTUEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_MMTUEN_SHIFT))
+#define CGU_MMTUEN_0               (0x0UL<<CGU_MMTUEN_SHIFT)
+#define CGU_MMTUEN_1               (0x1UL<<CGU_MMTUEN_SHIFT)
+#define CGU_MMTUEN                 (0x1UL<<CGU_MMTUEN_SHIFT)
+#define CGU_CAEEN_SHIFT            0
+#define CGU_CAEEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_CAEEN_SHIFT))
+#define CGU_CAEEN_0                (0x0UL<<CGU_CAEEN_SHIFT)
+#define CGU_CAEEN_1                (0x1UL<<CGU_CAEEN_SHIFT)
+#define CGU_CAEEN                  (0x1UL<<CGU_CAEEN_SHIFT)
+
+#endif
-- 
1.7.1


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

* [PATCH 2/5] U6715 clocks gating management U6 clock generic driver & U6715 cgu clock specific
@ 2010-08-05 12:28   ` Philippe Langlais
  0 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 arch/arm/Kconfig                          |    1 +
 arch/arm/mach-u67xx/Makefile              |    5 +-
 arch/arm/mach-u67xx/cgu.c                 |  753 +++++++++++++++++++++++++
 arch/arm/mach-u67xx/cgu.h                 |   57 ++
 arch/arm/mach-u67xx/clock_data_u67xx.c    |  864 +++++++++++++++++++++++++++++
 arch/arm/plat-u6xxx/Makefile              |    2 +-
 arch/arm/plat-u6xxx/clock.c               |  621 +++++++++++++++++++++
 arch/arm/plat-u6xxx/include/mach/clkdev.h |   13 +
 arch/arm/plat-u6xxx/include/mach/clock.h  |  378 +++++++++++++
 9 files changed, 2692 insertions(+), 2 deletions(-)
 create mode 100644 arch/arm/mach-u67xx/cgu.c
 create mode 100644 arch/arm/mach-u67xx/cgu.h
 create mode 100644 arch/arm/mach-u67xx/clock_data_u67xx.c
 create mode 100644 arch/arm/plat-u6xxx/clock.c
 create mode 100644 arch/arm/plat-u6xxx/include/mach/clkdev.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/clock.h

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 1ae089c..a250f2e 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -742,6 +742,7 @@ config ARCH_U300
 config PLAT_U6XXX
 	bool "ST-Ericsson U6XXX Series"
 	select CPU_ARM926T
+	select COMMON_CLKDEV
 	select GENERIC_GPIO
 	select ARCH_REQUIRE_GPIOLIB
 	help
diff --git a/arch/arm/mach-u67xx/Makefile b/arch/arm/mach-u67xx/Makefile
index 38cf624..d4e35a7 100644
--- a/arch/arm/mach-u67xx/Makefile
+++ b/arch/arm/mach-u67xx/Makefile
@@ -5,7 +5,10 @@
 ## Object file lists.
 
 # Common support
-obj-y			:= devices.o
+obj-y			:= devices.o cgu.o
+
+# Specific machine support
+obj-y += clock_data_u67xx.o
 
 # Specific board support
 obj-$(CONFIG_MACH_U67XX_WAVEC_2GB) += board_u67xx_wavex.o
diff --git a/arch/arm/mach-u67xx/cgu.c b/arch/arm/mach-u67xx/cgu.c
new file mode 100644
index 0000000..68401ff
--- /dev/null
+++ b/arch/arm/mach-u67xx/cgu.c
@@ -0,0 +1,753 @@
+/*
+ *  arch/arm/mach-u67xx/cgu.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Arnaud Troel <arnaud.troel@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * U67XX Clock Gating Unit basic driver/wrapper
+ * Based on the code from Michel Jaouen
+ */
+
+/*#define DEBUG */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <asm/clkdev.h>
+#include <mach/hardware.h>
+#include <mach/clock.h>
+#include "cgu.h"
+
+#define MODULE_NAME "U6_CGU"
+#define PKMOD MODULE_NAME ": "
+
+/*
+ * Public U6 platform access clock functions
+ */
+
+/**
+ * @brief Disable a device clock.
+ * @param clk clock description structure
+ */
+void u6_clk_disable(struct clk *clk)
+{
+	/*    BUG_ON(!clk->ref_count); */
+	if ((clk->flags & ALWAYS_ENABLED) == ALWAYS_ENABLED)
+		return;
+
+	if (clk->usecount > 0 && !(--clk->usecount)) {
+		if (clk->disable)
+			clk->disable(clk);
+		else
+			u67xx_cgu_disable_clock(clk);
+
+		if (likely((u32) clk->parent))
+			u6_clk_disable(clk->parent);
+	}
+}
+
+/**
+ * @brief Enable a device clock.
+ * @param clk clock description structure
+ */
+int u6_clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	/*   BUG_ON(!clk->ref_count); */
+	if ((clk->flags & ALWAYS_ENABLED) == ALWAYS_ENABLED)
+		return 0;
+
+	if (clk->usecount++ == 0) {
+		if (likely((u32) clk->parent))
+			ret = u6_clk_enable(clk->parent);
+
+		if (unlikely(ret != 0)) {
+			clk->usecount--;
+			return ret;
+		}
+
+		if (clk->enable)
+			ret = clk->enable(clk);
+		else
+			ret = u67xx_cgu_enable_clock(clk);
+
+		if (unlikely(ret != 0) && clk->parent) {
+			u6_clk_disable(clk->parent);
+			clk->usecount--;
+		}
+	}
+	return 0;
+}
+
+/**
+ * HW enable clock function.
+ **/
+
+int u67xx_cgu_enable_fake_clock(struct clk *clk)
+{
+	pr_debug("u67xx_cgu_enable_fake_clock for %s\n", clk->name);
+	return 0;
+}
+
+int u67xx_cgu_enable_hw_clock(struct clk *clk)
+{
+	unsigned long value;
+	pr_debug("u67xx_cgu_enable_hw_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	return 0;
+}
+
+int u67xx_cgu_enable_tvo_pll_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_enable_tvo_pll_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	/* wait pll lock */
+	do {
+		value = readl(clk->enable_reg);
+	} while (!(value & (0x1 << 16)));
+
+	return 0;
+}
+
+int u67xx_cgu_enable_shared_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_enable_shared_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	return 0;
+}
+
+int u67xx_cgu_enable_clock(struct clk *clk)
+{
+	printk(PKMOD "No enable clock method for %s."
+	       " You should use new one !!!\n", clk->name);
+	return 0;
+}
+
+int u67xx_cgu_enable_camout(struct clk *clk)
+{
+	unsigned long value;
+	pr_debug("u67xx_cgu_enable_hw_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Enable for %s without enable register\n",
+		       clk->name);
+		return 0;
+	}
+
+	u6_clk_enable(&fix_ck);
+	u6_clk_enable(&plltv_ck);
+
+	value = readl(clk->enable_reg);
+	value |= 1 << clk->enable_bit;
+	writel(value, clk->enable_reg);
+
+	udelay(1);
+
+	u6_clk_disable(&fix_ck);
+	u6_clk_disable(&plltv_ck);
+
+	return 0;
+}
+
+/**
+ * HW disable clock function.
+ **/
+
+void u67xx_cgu_disable_fake_clock(struct clk *clk)
+{
+	pr_debug("u67xx_cgu_disable_fake_clock for %s\n", clk->name);
+}
+
+void u67xx_cgu_disable_hw_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_disable_hw_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Disable for %s without enable register\n",
+		       clk->name);
+		return;
+	}
+
+	value = readl(clk->enable_reg);
+	value &= ~(1 << clk->enable_bit);
+	writel(value, clk->enable_reg);
+
+	return;
+}
+
+void u67xx_cgu_disable_shared_clock(struct clk *clk)
+{
+	unsigned long value;
+
+	pr_debug("u67xx_cgu_disable_shared_clock for %s\n", clk->name);
+
+	if (unlikely(clk->enable_reg == NULL)) {
+		printk(KERN_ERR "Disable for %s without enable register\n",
+		       clk->name);
+		return;
+	}
+
+	value = readl(clk->enable_reg);
+	value &= ~(1 << clk->enable_bit);
+	writel(value, clk->enable_reg);
+}
+
+void u67xx_cgu_disable_clock(struct clk *clk)
+{
+	printk(PKMOD
+	       " No disable clock method for %s. You should use one !!!\n",
+	       clk->name);
+}
+
+/**
+ * set rate clock function.
+ **/
+
+int u6_clk_set_rate_fci(struct clk *clk, unsigned long rate)
+{
+	int ret = 0;
+	unsigned long ratio = 0;
+	unsigned long reg;
+
+	if (!rate)
+		ratio = 31;
+	else {
+		if (rate > CLK_FC_CLK_MAX_FREQ)
+			rate = CLK_FC_CLK_MAX_FREQ;
+
+		/* compute diviser ratio */
+		ratio = (clk->parent->rate / rate) - 1;
+		if (ratio < 2)
+			ratio = 2;
+		if (ratio > 31)
+			ratio = 31;
+	}
+	clk->rate = clk->parent->rate / (ratio + 1);
+
+	/* for voltage working point only */
+	/* u67xx_set_freq(FC_CLK, clk->rate/1000 , clk->rate/1000); */
+
+	reg = readl(CGU_FIXCON_REG);
+	reg &= ~(0x1F << 22);
+	reg |= (ratio << 22);
+	writel(reg, CGU_FIXCON_REG);
+
+	reg = readl(CGU_SCCON_REG);
+	writel(reg, CGU_SCCON_REG);
+
+	return ret;
+}
+
+int u6_clk_set_rate_camout(struct clk *clk, unsigned long rate)
+{
+	int ret = 0;
+	unsigned long ratio = 0;
+	unsigned long reg;
+
+	if (!rate)
+		return -EINVAL;
+
+	if (rate > CLK_CAM_CLK_MAX_FREQ)
+		rate = CLK_CAM_CLK_MAX_FREQ;
+
+	/* compute diviser ratio */
+	ratio = (clk->parent->rate / rate) - 1;
+	if (ratio < 1)
+		ratio = 1;
+	if (ratio > 63)
+		ratio = 63;
+
+	clk->rate = clk->parent->rate / (ratio + 1);
+
+	/* for voltage working point only */
+	/* u67xx_set_freq(CAM_CLK, clk->rate/1000 , clk->rate/1000); */
+
+	reg = readl(CGU_CAMCON_REG);
+
+	reg &= ~(0x3F << 0);
+	reg |= (ratio << 0);
+
+	writel(reg, CGU_CAMCON_REG);
+
+	return ret;
+}
+
+/**
+ * set parent clock function.
+ **/
+int u6_clk_set_parent_camout(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+	unsigned long srce = 0;
+	unsigned long reg;
+
+	if (!strcmp(parent->name, "TVOPLL"))
+		srce = 0;
+	else if (!strcmp(parent->name, "fix_ck"))
+		srce = 1;
+	else
+		return -EINVAL;
+
+	u6_clk_enable(&fix_ck);
+	u6_clk_enable(&plltv_ck);
+
+	reg = readl(CGU_CAMCON_REG);
+
+	reg &= ~(0x1 << 6);
+	reg |= (srce << 6);
+
+	writel(reg, CGU_CAMCON_REG);
+
+	udelay(1);
+
+	u6_clk_disable(&fix_ck);
+	u6_clk_disable(&plltv_ck);
+
+	clk->parent = parent;
+
+	return ret;
+}
+
+int u6_clk_set_parent_uart(struct clk *clk, struct clk *parent)
+{
+
+	if (!strcmp(parent->name, "pclk2_ck")) {
+		clk->parent = parent;
+		return 0;
+	} else if (!strcmp(parent->name, "clk26m_ck")) {
+		clk->parent = parent;
+		return 0;
+	} else if (!strcmp(parent->name, "clk13m_ck")) {
+		clk->parent = parent;
+		return 0;
+	} else {
+		return -EINVAL;
+	}
+}
+
+/**
+ * HW init clock function.
+ **/
+
+void u6_clk_dflt_init(struct clk *clk)
+{
+	if (clk->usecount == 0)
+		u67xx_cgu_disable_hw_clock(clk);
+	else
+		u67xx_cgu_enable_hw_clock(clk);
+	/* default rate to parent one */
+	clk->rate = clk->parent->rate;
+}
+
+void u6_clk_init_hclk2(struct clk *clk)
+{
+	/* nothing to do */
+}
+
+void u6_clk_init_fci(struct clk *clk)
+{
+	u6_clk_set_rate_fci(clk, clk->rate);
+}
+
+void u6_clk_init_camout(struct clk *clk)
+{
+	u6_clk_set_parent_camout(clk, &fix_ck);
+	u6_clk_set_rate_camout(clk, clk->rate);
+}
+
+/*
+ * Update clock rate
+ */
+void followparent_ivs_recalc(struct clk *clk)
+{
+	clk->rate = clk->parent->rate;
+	propagate_rate(clk);
+}
+
+/*
+ * Private U6 platform access clock functions
+ */
+static long u6_clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	if (clk->round_rate)
+		return clk->round_rate(clk, rate);
+	else
+		return rate;
+}
+
+static int u6_clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = 0;
+
+	/*   BUG_ON(!clk->ref_count); */
+	if (clk->usecount > 0) {
+		if (clk->disable)
+			clk->disable(clk);
+		else
+			u67xx_cgu_disable_clock(clk);
+	}
+
+	if (clk->set_rate)
+		ret = clk->set_rate(clk, rate);
+	else
+		ret = -EINVAL;
+
+	if (clk->usecount > 0) {
+		if (clk->enable)
+			clk->enable(clk);
+		else
+			u67xx_cgu_enable_clock(clk);
+	}
+
+	/* propagate rate */
+	propagate_rate(clk);
+
+	return ret;
+}
+
+static int u6_clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	int ret = 0;
+	int old_rate;
+
+	if (clk->usecount > 0) {
+		if (clk->disable)
+			clk->disable(clk);
+		else
+			u67xx_cgu_disable_clock(clk);
+
+		if (likely((u32) clk->parent))
+			u6_clk_disable(clk->parent);
+	}
+
+	old_rate = clk->rate;
+
+	if (clk->set_parent)
+		ret = clk->set_parent(clk, parent);
+	else
+		ret = -EINVAL;
+
+	if (clk->round_rate)
+		old_rate = clk->round_rate(clk, old_rate);
+
+	u6_clk_set_rate(clk, old_rate);
+
+	if (clk->usecount > 0) {
+		if (likely((u32) clk->parent))
+			u6_clk_enable(clk->parent);
+
+		if (clk->enable)
+			ret = clk->enable(clk);
+		else
+			ret = u67xx_cgu_enable_clock(clk);
+	}
+
+	/* propagate rate */
+	if (clk->flags & RATE_PROPAGATES)
+		propagate_rate(clk);
+
+	return ret;
+}
+
+static struct clk *u6_clk_get_parent(struct clk *clk)
+{
+	return clk->parent;
+}
+
+/*
+ * U6 platform clock constraint functions
+ */
+
+unsigned long clk_get_hw_constraint(void __iomem *reg_addr)
+{
+	unsigned long reg;
+
+	reg = readl(reg_addr);
+
+	return reg;
+}
+
+ssize_t u6_clk_show_hw_rates(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+	unsigned long reg, rate, msc, psc, mclk;
+
+	size += sprintf(&buf[size], "--HW-- : \n");
+
+	mclk = clk_get_hw_constraint(CGU_FIXCON_REG);
+	mclk = osc_ck.rate / 1000000 / (((mclk & (0x3 << 17)) >> 17) + 1);
+
+	reg = clk_get_hw_constraint(CGU_SCCON_REG);
+
+	msc = (((reg & (0xF << 25)) >> 25) + 1);
+	psc = (((reg & (0x3 << 15)) >> 15) + 1);
+	size += sprintf(&buf[size], "arm_ck is ");
+	if (reg & (1 << 17)) {
+		if (reg & (1 << 18))
+			rate = 312;
+		else
+			rate = 156;
+		rate = rate / msc / psc;
+		size += sprintf(&buf[size], "%lu", rate);
+		size += sprintf(&buf[size], "Mhz fix_ck pll\n");
+	} else {
+		rate = mclk * (((reg & (0xFF << 3)) >> 3) + 1)
+		    / (((reg & (0xF << 11)) >> 11) + 1);
+		rate = rate / msc / psc;
+		size += sprintf(&buf[size], "%lu", rate);
+		size += sprintf(&buf[size], "Mhz sc_ck pll\n");
+	}
+
+	rate = rate / (((reg & (0xF << 21)) >> 21) + 1);
+
+	size += sprintf(&buf[size], "hclk_ck is %luMhz\n", rate);
+
+	reg = clk_get_hw_constraint(CGU_FIXCON_REG);
+
+	rate = 13 * (((reg & (0x3 << 20)) >> 20) + 1);
+
+	size += sprintf(&buf[size], "pclk2_ck is %luMhz\n", rate);
+
+	if (reg & (1 << 31)) {
+		if (reg & (1 << 29))
+			rate = 104;
+		else
+			rate = 78;
+	} else
+		rate = 13 + (13 * ((reg & (0x7 << 29)) >> 29));
+
+	size += sprintf(&buf[size], "hclk2_ck is %luMhz\n", rate);
+
+	reg = clk_get_hw_constraint(CGU_SDMCON_REG);
+
+	msc = (((reg & (0x7 << 0)) >> 0) + 1);
+
+	size += sprintf(&buf[size], "sdm_ck is ");
+	if (reg & (1 << 17)) {
+		if (reg & (1 << 18))
+			rate = 312;
+		else
+			rate = 156;
+		size += sprintf(&buf[size], "%lu", rate / msc);
+		size += sprintf(&buf[size], "Mhz fix_ck pll\n");
+	} else {
+		rate = mclk * 2 * (((reg & (0xFF << 3)) >> 3) + 1)
+		    / (((reg & (0x3F << 11)) >> 11) + 1);
+		size += sprintf(&buf[size], "%lu", rate / msc);
+		size += sprintf(&buf[size], "Mhz sdm pll\n");
+	}
+
+	if (reg & (1 << 23))
+		size += sprintf(&buf[size], "ivs-sdm concentrator is enable\n");
+	else
+		size += sprintf(&buf[size],
+				"ivs-sdm concentrator is disable\n");
+
+	return size;
+}
+
+unsigned char *cgu_name_sc1[32] = {
+	"EBI", "01", "NFI", "SDI", "04", "MSI", "UCC", "JDI",
+	"08", "09", "10", "DMAU", "RFSM1", "IIS", "USBD", "FCI",
+	"USIM", "GEAC", "PWM3", "PWM2", "PWM1", "KBS", "GPIO", "UART2",
+	"UART1", "IIC2", "IIC1", "SPI2", "SPI1", "SCTU", "EXTINT", "INTC"
+};
+
+unsigned char *cgu_name_sc2[32] = {
+	"32", "33", "34", "35", "36", "37", "38", "39",
+	"40", "41", "42", "43", "44", "45", "46", "47",
+	"48", "49", "50", "51", "52", "53", "BBIP", "55",
+	"56", "57", "58", "ETB", "60", "MMTU", "62", "CAE"
+};
+
+ssize_t u6_clk_show_sc_constraints(struct kobject *kobj, char *buf)
+{
+	int i, size = 0;
+	unsigned long reg;
+
+	size += sprintf(&buf[size], "--SC-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_GATESC1_REG);
+
+	for (i = 0; i < 32; i++) {
+		if ((reg >> i) & 0x1)
+			size +=
+			    sprintf(&buf[size], "%s ,", cgu_name_sc1[31 - i]);
+	}
+
+	size += sprintf(&buf[size], "\n");
+
+	reg = clk_get_hw_constraint(CGU_GATESC2_REG);
+
+	for (i = 0; i < 32; i++) {
+		if ((reg >> i) & 0x1)
+			size +=
+			    sprintf(&buf[size], "%s ,", cgu_name_sc2[31 - i]);
+	}
+
+	size += sprintf(&buf[size], "\n");
+
+	return size;
+}
+
+unsigned char *cgu_name_ivs[32] = {
+	"", "", "", "", "", "", "", "",
+	"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
+	"CAMJPE", "TVO", "JDU", "VDC", "VEC", "IPP", "VDE", "CAM"
+};
+
+ssize_t u6_clk_show_ivs_constraints(struct kobject *kobj, char *buf)
+{
+	int i, size = 0;
+	unsigned long reg;
+
+	size += sprintf(&buf[size], "--IVS-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_GATEIVS_REG);
+
+	for (i = 0; i < 32; i++) {
+		if ((reg >> i) & 0x1)
+			size +=
+			    sprintf(&buf[size], "%s ,", cgu_name_ivs[31 - i]);
+	}
+
+	size += sprintf(&buf[size], "\n");
+
+	return size;
+}
+
+ssize_t u6_clk_show_tvo_constraints(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+	unsigned long reg;
+
+	size += sprintf(&buf[size], "--TVO-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_TVCON_REG);
+
+	if ((reg >> 15) & 0x1)
+		size += sprintf(&buf[size], "tvclk_ck pll enable\n");
+	else
+		size += sprintf(&buf[size], "tvclk_ck pll disable\n");
+
+	if ((reg >> 12) & 0x1)
+		size += sprintf(&buf[size], "TVOPLL enable\n");
+	else
+		size += sprintf(&buf[size], "TVOPLL disable\n");
+
+	return size;
+}
+
+ssize_t u6_clk_show_cam_constraints(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+	unsigned long reg, rate, div;
+
+	size += sprintf(&buf[size], "--CAM-- : \n");
+
+	reg = clk_get_hw_constraint(CGU_CAMCON_REG);
+
+	if ((reg >> 6) & 0x1) {
+		size += sprintf(&buf[size], "fix_clock is source\n");
+		rate = 312;
+	} else {
+		size += sprintf(&buf[size], "TVOPLL is source\n");
+		rate = 216;
+	}
+
+	div = ((reg & (0x3F << 0)) >> 0);
+
+	size += sprintf(&buf[size], "camo_ck is %luMhz\n", rate / (div + 1));
+
+	if ((reg >> 7) & 0x1)
+		size += sprintf(&buf[size], "camo_ck enable\n");
+	else
+		size += sprintf(&buf[size], "camo_ck disable\n");
+
+	return size;
+}
+
+/*
+ * U6 clock reset and init functions
+ */
+
+static struct clk_functions u6_clk_functions = {
+	.clk_enable = u6_clk_enable,
+	.clk_disable = u6_clk_disable,
+	.clk_round_rate = u6_clk_round_rate,
+	.clk_set_rate = u6_clk_set_rate,
+	.clk_set_parent = u6_clk_set_parent,
+	.clk_get_parent = u6_clk_get_parent,
+};
+
+/**
+ * @brief Attempts to connect the primary description structure for DMA case.
+ *
+ * We don't do any initialization since we expect the primary OS to have done
+ * it for us.
+ */
+static int __init u67xx_cgu_init(void)
+{
+	struct clk_lookup *clkp;
+	printk(PKMOD "clk management init\n");
+
+	if (mpurate)
+		sc_ck.rate = mpurate;
+
+	/* init clock function pointer table */
+	clk_init(&u6_clk_functions);
+
+	/* register and init clock elements */
+	for (clkp = onchip_clks; clkp->clk != NULL; clkp++) {
+		clkp->con_id = clkp->clk->name;
+		clkdev_add(clkp);
+		clk_register(clkp->clk);
+	}
+
+	return 0;
+}
+
+arch_initcall(u67xx_cgu_init);
diff --git a/arch/arm/mach-u67xx/cgu.h b/arch/arm/mach-u67xx/cgu.h
new file mode 100644
index 0000000..c029991
--- /dev/null
+++ b/arch/arm/mach-u67xx/cgu.h
@@ -0,0 +1,57 @@
+/*
+ *  arch/arm/mach-u67xx/cgu.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#ifndef CGU_INC
+#define CGU_INC
+
+extern struct clk arm_ck;
+extern struct clk hclk_ck;
+extern struct clk sdm_ck;
+extern struct clk hclk2_ck;
+extern struct clk pclk2_ck;
+extern struct clk sc_ck;
+extern struct clk fix_ck;
+extern struct clk plltv_ck;
+extern struct clk osc_ck;
+
+extern struct clk_lookup onchip_clks[];
+
+extern void u6_clk_init_hclk2(struct clk *clk);
+extern void u6_clk_init_rtke(struct clk *clk);
+extern void u6_clk_init_fci(struct clk *clk);
+extern void u6_clk_init_camout(struct clk *clk);
+
+extern void followparent_ivs_recalc(struct clk *clk);
+
+extern void u6_clk_rtke_recalc(struct clk *clk);
+
+extern int u67xx_cgu_enable_fake_clock(struct clk *clk);
+extern int u67xx_cgu_enable_hw_clock(struct clk *clk);
+extern int u67xx_cgu_enable_tvo_pll_clock(struct clk *clk);
+extern int u67xx_cgu_enable_rtke_clock(struct clk *clk);
+extern int u67xx_cgu_enable_shared_clock(struct clk *clk);
+extern int u67xx_cgu_enable_clock(struct clk *clk);
+extern int u67xx_cgu_enable_camout(struct clk *clk);
+
+extern void u67xx_cgu_disable_fake_clock(struct clk *clk);
+extern void u67xx_cgu_disable_hw_clock(struct clk *clk);
+extern void u67xx_cgu_disable_rtke_clock(struct clk *clk);
+extern void u67xx_cgu_disable_shared_clock(struct clk *clk);
+extern void u67xx_cgu_disable_clock(struct clk *clk);
+
+extern int u6_clk_set_rate_fci(struct clk *clk, unsigned long rate);
+extern int u6_clk_set_rate_camout(struct clk *clk, unsigned long rate);
+extern int u6_clk_set_rate_rtke(struct clk *clk, unsigned long rate);
+
+extern int u6_clk_set_parent_camout(struct clk *clk, struct clk *parent);
+extern int u6_clk_set_parent_uart(struct clk *clk, struct clk *parent);
+
+extern void u6_clk_dflt_init(struct clk *clk);
+
+#endif   /* ----- #ifndef CGU_INC  ----- */
+
diff --git a/arch/arm/mach-u67xx/clock_data_u67xx.c b/arch/arm/mach-u67xx/clock_data_u67xx.c
new file mode 100644
index 0000000..e3d8156
--- /dev/null
+++ b/arch/arm/mach-u67xx/clock_data_u67xx.c
@@ -0,0 +1,864 @@
+/*
+ *  arch/arm/mach-u67xx/clock_data_u67xx.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Vincent Guittot <vincent.guittot@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ */
+#include <linux/device.h>
+#include <asm/clkdev.h>
+#include <mach/hardware.h>
+#include <mach/clock.h>
+#include "cgu.h"
+
+#define MODULE_NAME "U6_CGU"
+#define PKMOD MODULE_NAME ": "
+
+/* used to remove useless clock cells */
+#undef U6_OPTIMIZED_TREE
+
+/*
+ * U6 clock tree.
+ *
+ * NOTE:In many cases here we are assigning a 'default' parent.	In many
+ *	cases the parent is selectable.	The get/set parent calls will also
+ *	switch sources.
+ *
+ *	Many some clocks say always_enabled, but they can be auto idled for
+ *	power savings. They will always be available upon clock request.
+ *
+ *	Several sources are given initial rates which may be wrong, this will
+ *	be fixed up in the init func.
+ *
+ *	Things are broadly separated below by clock domains. It is
+ *	noteworthy that most periferals have dependencies on multiple clock
+ *	domains. Many get their interface clocks from the L4 domain, but get
+ *	functional clocks from fixed sources or other core domain derived
+ *	clock.
+ */
+
+/*** Basic clocks ***/
+
+/* Base external input clocks */
+static struct clk func_32k_ck = {
+	.name = "func_32k_ck",
+	.rate = 32000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED,
+	.usecount = 1,
+};
+
+/* Typical 26MHz in standalone mode */
+struct clk osc_ck = {	/* (*12, *13, 19.2, *26, 38.4)MHz */
+	.name = "osc_ck",
+	.rate = 26000000,	/* fixed up in clock init */
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.usecount = 1,
+};
+
+/* System clock MCLK */
+/* With out modem likely 12MHz, with modem likely 13MHz */
+static struct clk sys_ck = {	/* (*12, *13, 19.2, 26, 38.4)MHz */
+	.name = "sys_ck",	/* ~ ref_clk also */
+	.parent = &osc_ck,
+	.rate = 13000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.usecount = 1,
+};
+
+/*** System PLLs ***/
+
+struct clk sc_ck = {	/* 275-550MHz */
+	.name = "sc_ck",
+	.parent = &sys_ck,
+	.rate = 416000000,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+struct clk fix_ck = {	/* 312MHz */
+	.name = "fix_ck",
+	.parent = &sys_ck,
+	.rate = 312000000,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 0,
+};
+
+static struct clk tv_ck = {	/* 216MHz */
+	.name = "tv_ck",
+	.parent = &fix_ck,
+	.rate = 216000000,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk dsp2_ck = {	/* 156-320MHz */
+	.name = "dsp2_ck",
+	.parent = &sys_ck,
+	.rate = 208000000,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 8,
+};
+#endif
+
+struct clk sdm_ck = {	/* 275-550MHz */
+	.name = "sdm_ck",
+	.parent = &sys_ck,
+	.rate = 200000000,
+/*      .flags          = RATE_PROPAGATES,*/
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 3,
+};
+
+/*** Master clock sources ***/
+
+struct clk arm_ck = {
+	.name = "arm_ck",
+	.rate = 416000000,
+	.parent = &sc_ck,
+/*	.flags          = RATE_PROPAGATES,*/
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+struct clk hclk_ck = {
+	.name = "hclk_ck",
+	.rate = 208000000,
+	.parent = &arm_ck,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 1,
+};
+
+struct clk hclk2_ck = {
+	.name = "hclk2_ck",
+/*	.rate           = 104000000,*/
+	.rate = 52000000,
+	.parent = &fix_ck,
+	.flags = RATE_PROPAGATES,
+	.init = u6_clk_init_hclk2,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 2,
+};
+
+static struct clk sdm_ivs_ck = {
+	.name = "sdm_ivs_ck",
+	.parent = &hclk2_ck,
+	.rate = 104000000,
+	.flags = RATE_PROPAGATES,
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_ivs_recalc,
+	.enable_reg = CGU_SDMCON_REG,
+	.enable_bit = 23,
+};
+
+static struct clk pclk1_ck = {
+	.name = "pclk1_ck",
+	.rate = 104000000,
+	.parent = &hclk2_ck,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+static struct clk tvclk_ck = {
+	.name = "tvclk_ck",
+	.rate = 27000000,
+	.parent = &tv_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_tvo_pll_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_TVCON_REG,
+	.enable_bit = 15,
+};
+
+struct clk pclk2_ck = {
+	.name = "pclk2_ck",
+	.rate = 52000000,
+	.parent = &fix_ck,
+	.flags = RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 4,
+};
+
+static struct clk clk24m_ck = {
+	.name = "clk24m_ck",
+	.rate = 24000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 5,
+};
+
+static struct clk clk26m_ck = {
+	.name = "clk26m_ck",
+	.rate = 26000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 6,
+};
+
+static struct clk clk13m_ck = {
+	.name = "clk13m_ck",
+	.rate = 13000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.enable_bit = 7,
+};
+
+static struct clk clk4m_ck = {
+	.name = "clk4m_ck",
+	.rate = 4000000,
+	.parent = &fix_ck,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk sioy1clk_ck = {
+	.name = "sioy1clk_ck",
+	.rate = 208000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk sioy2clk_ck = {
+	.name = "sioy2clk_ck",
+	.rate = 208000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk rfclk_ck = {
+	.name = "rfclk_ck",
+	.rate = 208000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+#endif
+
+static struct clk fc_ck = {
+	.name = "fc_ck",
+/*	.rate = 104000000,*/
+	.rate = 52000000,
+	.init = u6_clk_init_fci,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+	.set_rate = u6_clk_set_rate_fci,
+	.parent = &fix_ck,
+};
+
+static struct clk usb_d_ck = {
+	.name = "usb_d_ck",
+	.rate = 24000000,
+	.parent = &clk24m_ck,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+static struct clk usb_h_ck = {
+	.name = "usb_h_ck",
+	.rate = 24000000,
+	.parent = &clk24m_ck,
+	.flags = RATE_FIXED,
+	.enable = u67xx_cgu_enable_fake_clock,
+	.disable = u67xx_cgu_disable_fake_clock,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk dcclk1_ck = {
+	.name = "dcclk1_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk diclk1_ck = {
+	.name = "diclk1_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk dcclk2_ck = {
+	.name = "dcclk2_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+
+static struct clk diclk2_ck = {
+	.name = "dicl2_ck",
+	.rate = 130000000,
+	.flags = RATE_FIXED | ALWAYS_ENABLED | RATE_PROPAGATES,
+};
+#endif
+
+static struct clk camo_ck = {
+	.name = "camo_ck",
+	.rate = 12000000,
+	.parent = &fix_ck,
+	.flags = RATE_PROPAGATES,
+	.init = u6_clk_init_camout,
+	.enable = u67xx_cgu_enable_camout,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.set_rate = u6_clk_set_rate_camout,
+	.set_parent = u6_clk_set_parent_camout,
+	.enable_reg = CGU_CAMCON_REG,
+	.enable_bit = 7,
+};
+
+/*** Peripheral clocks ***/
+
+/* CGUTVCON */
+struct clk plltv_ck = {
+	.name = "TVOPLL",
+	.enable_reg = CGU_TVCON_REG,
+	.enable_bit = 12,
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.parent = &tvclk_ck,
+};
+
+/* CGUGATESC1 */
+#ifndef U6_OPTIMIZED_TREE
+static struct clk intc_ck = {
+	.name = "INTC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 0,
+	.parent = &hclk2_ck,
+	.usecount = 1,
+};
+
+static struct clk extint_ck = {
+	.name = "EXTINT",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 1,
+	.parent = &pclk2_ck,
+	.usecount = 1,
+};
+
+static struct clk sctu_ck = {
+	.name = "SCTU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 2,
+	.parent = &clk13m_ck,
+};
+#endif
+
+static struct clk spi1_ck = {
+	.name = "SPI1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 3,
+	.parent = &pclk1_ck,
+};
+
+static struct clk spi2_ck = {
+	.name = "SPI2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 4,
+	.parent = &pclk1_ck,
+};
+
+static struct clk iic1_ck = {
+	.name = "IIC1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 5,
+	.parent = &pclk2_ck,
+};
+
+static struct clk iic2_ck = {
+	.name = "IIC2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 6,
+	.parent = &pclk2_ck,
+};
+
+static struct clk uart1_ck = {
+	.name = "UART1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.set_parent = u6_clk_set_parent_uart,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 7,
+	.parent = &clk13m_ck,
+};
+
+static struct clk uart2_ck = {
+	.name = "UART2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.set_parent = u6_clk_set_parent_uart,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 8,
+	.parent = &clk13m_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk gpio_ck = {
+	.name = "GPIO",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 9,
+	.parent = &pclk2_ck,
+	.usecount = 1,
+};
+#endif
+
+static struct clk kbs_ck = {
+	.name = "KBS",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 10,
+	.parent = &func_32k_ck,
+};
+
+static struct clk pwm1_ck = {
+	.name = "PWM1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 11,
+	.parent = &clk13m_ck,
+};
+
+static struct clk pwm2_ck = {
+	.name = "PWM2",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 12,
+	.parent = &clk13m_ck,
+};
+
+static struct clk pwm3_ck = {
+	.name = "PWM3",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 13,
+	.parent = &clk13m_ck,
+};
+
+static struct clk geac_ck = {
+	.name = "GEAC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 14,
+	.parent = &pclk1_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk usim_ck = {
+	.name = "USIM",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 15,
+	.parent = &pclk2_ck,
+};
+#endif
+
+static struct clk fci_ck = {
+	.name = "FCI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 16,
+	.parent = &fc_ck,
+};
+
+static struct clk usbd_ck = {
+	.name = "USBD",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 17,
+	.parent = &hclk2_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk iis_ck = {
+	.name = "IIS",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 18,
+	.parent = &clk24m_ck,
+};
+
+static struct clk rfsm1_ck = {
+	.name = "RFSM1",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 19,
+	.parent = &pclk1_ck,
+};
+#endif
+
+static struct clk dmau_ck = {
+	.name = "DMAU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_shared_clock,
+	.disable = u67xx_cgu_disable_shared_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 20,
+	.parent = &hclk2_ck,
+};
+
+static struct clk jdi_ck = {
+	.name = "JDI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 24,
+	.parent = &pclk2_ck,
+};
+
+#ifndef U6_OPTIMIZED_TREE
+static struct clk ucc_ck = {
+	.name = "UCC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 25,
+	.parent = &pclk1_ck,
+};
+#endif
+
+static struct clk msi_ck = {
+	.name = "MSI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 26,
+	.parent = &fc_ck,
+};
+
+static struct clk sdi_ck = {
+	.name = "SDI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 28,
+	.parent = &hclk2_ck,
+};
+
+static struct clk nfi_ck = {
+	.name = "NFI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 29,
+	.parent = &hclk2_ck,
+
+};
+
+static struct clk ebi_ck = {
+	.name = "EBI",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATESC1_REG,
+	.enable_bit = 31,
+	.parent = &hclk2_ck,
+
+};
+
+/* CGUGATESC2 */
+static struct clk cae_ck = {
+	.name = "CAE",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.enable_reg = CGU_GATESC2_REG,
+	.enable_bit = 0,
+	.parent = &pclk1_ck,
+};
+
+static struct clk mmtu_ck = {
+	.name = "MMTU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_shared_clock,
+	.disable = u67xx_cgu_disable_shared_clock,
+	.enable_reg = CGU_GATESC2_REG,
+	.enable_bit = 2,
+	.parent = &clk13m_ck,
+	.usecount = 1,
+};
+
+/* OCL-2008-07-02: how to manage etbclk ? */
+/* static struct clk ETB_ck = */
+/* { */
+/* 	.name = "ETB", */
+/* 	.enable_reg = CGU_GATESC2_REG, */
+/* 	.enable_bit = 4, */
+/* 	.parent = &etbclk_ck, */
+/* }; */
+
+/* CGUGATEIVS */
+static struct clk cam_ck = {
+	.name = "CAM",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 0,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk vde_ck = {
+	.name = "VDE",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 1,
+	.parent = &hclk2_ck,
+};
+
+static struct clk ipp_ck = {
+	.name = "IPP",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 2,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk vec_ck = {
+	.name = "VEC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 3,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk vdc_ck = {
+	.name = "VDC",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 4,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk jdu_ck = {
+	.name = "JDU",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 5,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk tvoclk_ck = {
+	.name = "TVO",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 6,
+	.parent = &sdm_ivs_ck,
+};
+
+static struct clk camjpe_ck = {
+	.name = "CAMJPE",
+	.init = u6_clk_dflt_init,
+	.enable = u67xx_cgu_enable_hw_clock,
+	.disable = u67xx_cgu_disable_hw_clock,
+	.recalc = followparent_recalc,
+	.enable_reg = CGU_GATEIVS_REG,
+	.enable_bit = 7,
+	.parent = &hclk_ck,
+};
+
+#define CLK(pck)	\
+	{			\
+		.dev_id = NULL,	\
+		.con_id = NULL,	\
+		.clk = pck,	\
+	}
+
+struct clk_lookup onchip_clks[] = {
+	/* external root sources */
+	CLK(&func_32k_ck),
+	CLK(&osc_ck),
+	CLK(&sys_ck),
+	CLK(&sc_ck),
+	CLK(&fix_ck),
+	CLK(&tv_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&dsp2_ck),
+#endif
+	CLK(&sdm_ck),
+	CLK(&arm_ck),
+	CLK(&hclk_ck),
+	CLK(&hclk2_ck),
+	CLK(&pclk1_ck),
+	CLK(&pclk2_ck),
+	CLK(&tvclk_ck),
+	CLK(&clk24m_ck),
+	CLK(&clk26m_ck),
+	CLK(&clk13m_ck),
+	CLK(&clk4m_ck),
+	CLK(&fc_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&sioy1clk_ck),
+	CLK(&sioy2clk_ck),
+	CLK(&rfclk_ck),
+#endif
+	CLK(&usb_h_ck),
+	CLK(&usb_d_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&dcclk1_ck),
+	CLK(&diclk1_ck),
+	CLK(&dcclk2_ck),
+	CLK(&diclk2_ck),
+#endif
+	CLK(&camo_ck),
+	CLK(&tvoclk_ck),
+	CLK(&plltv_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&intc_ck),
+	CLK(&extint_ck),
+	CLK(&sctu_ck),
+#endif
+	CLK(&spi1_ck),
+	CLK(&spi2_ck),
+	CLK(&iic1_ck),
+	CLK(&iic2_ck),
+	CLK(&uart1_ck),
+	CLK(&uart2_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&gpio_ck),
+#endif
+	CLK(&kbs_ck),
+	CLK(&pwm1_ck),
+	CLK(&pwm2_ck),
+	CLK(&pwm3_ck),
+	CLK(&geac_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&usim_ck),
+#endif
+	CLK(&fci_ck),
+	CLK(&usbd_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&iis_ck),
+	CLK(&rfsm1_ck),
+#endif
+	CLK(&dmau_ck),
+	CLK(&jdi_ck),
+#ifndef U6_OPTIMIZED_TREE
+	CLK(&ucc_ck),
+#endif
+	CLK(&msi_ck),
+	CLK(&sdi_ck),
+	CLK(&nfi_ck),
+	CLK(&ebi_ck),
+	CLK(&cae_ck),
+	CLK(&mmtu_ck),
+	CLK(&sdm_ivs_ck),
+	CLK(&cam_ck),
+	CLK(&vde_ck),
+	CLK(&vdc_ck),
+	CLK(&vec_ck),
+	CLK(&ipp_ck),
+	CLK(&jdu_ck),
+	CLK(&camjpe_ck),
+	CLK(NULL)
+};
+
diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
index 12c832c..afdf82b 100644
--- a/arch/arm/plat-u6xxx/Makefile
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -3,6 +3,6 @@
 #
 
 # Common support
-obj-y := io.o irq.o
+obj-y := io.o irq.o clock.o
 
 obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/clock.c b/arch/arm/plat-u6xxx/clock.c
new file mode 100644
index 0000000..ecff187
--- /dev/null
+++ b/arch/arm/plat-u6xxx/clock.c
@@ -0,0 +1,621 @@
+/*
+ * linux/arch/arm/plat-u6xxx/clock.c
+ *
+ *  Copyright (C) 2004 - 2005 Nokia corporation
+ *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
+ *  Copyright (C) 2010 ST-Ericsson SA
+ *
+ *  Modified for omap shared clock framework by Tony Lindgren <tony@atomide.com>
+ *
+ *  Modified for u6 shared clock framework by Loic Pallardy @ ST-Ericsson.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/version.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/mutex.h>
+#include <linux/notifier.h>
+
+#include <linux/io.h>
+
+#include <mach/clock.h>
+
+LIST_HEAD(clocks);
+
+static DEFINE_MUTEX(clocks_mutex);
+DEFINE_SPINLOCK(clockfw_lock);
+
+static struct clk_functions *arch_clock;
+
+/*
+ * Additionnal specific clock functions define in include/mach/clock.h
+ */
+
+/**
+ *	clk_register_notifier - register a driver with clock mngt
+ *	@nb: notifier function to register
+ *  @clk: clock element rate change to be notified
+ *
+ *	Add a driver to one of two lists: either a list of drivers that
+ *      are notified about clock rate changes (once before and once after
+ *      the transition),
+ *	This function may sleep, and has the same return conditions as
+ *	sru_blocking_notifier_chain_register.
+ */
+int clk_register_notifier(struct notifier_block *nb, struct clk *clk)
+{
+	int ret;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+	if (clk->notifier)
+		ret = srcu_notifier_chain_register(clk->notifier, nb);
+	else
+		ret = -EINVAL;
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_register_notifier);
+
+/**
+ *	clk_unregister_notifier - unregister a driver with clock mngt
+ *	@nb: notifier function to be unregistered
+ *  @clk: clock element rate change to be notified
+ *
+ *	Remove a driver from the clock mngt notifier list.
+ *
+ *	This function may sleep, and has the same return conditions as
+ *	sru_blocking_notifier_chain_unregister.
+ */
+int clk_unregister_notifier(struct notifier_block *nb, struct clk *clk)
+{
+	int ret;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	mutex_lock(&clocks_mutex);
+	if (clk->notifier)
+		ret = srcu_notifier_chain_unregister(clk->notifier, nb);
+	else
+		ret = -EINVAL;
+	mutex_unlock(&clocks_mutex);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_unregister_notifier);
+
+/**
+ * clk_notify_transition - call notifier chain
+ *
+ * This function calls the transition notifiers and the and set rate
+ * It is called twice on all frequency changes that have
+ * external effects.
+ */
+int clk_notify_transition(struct clk *clk, unsigned int state, void *data)
+{
+	BUG_ON(irqs_disabled());
+
+	if (clk == ERR_PTR(-ENOENT))
+		return NOTIFY_BAD;
+
+	switch (state) {
+
+	case CLK_RATE_PRECHANGE:
+	case CLK_RATE_POSTCHANGE:
+/*		printk("notif %u of frequency transition of %s to %lu Hz\n",
+			state, clk->name, (unsigned long)data);
+*/
+		break;
+
+	case CLK_SRCE_PRECHANGE:
+	case CLK_SRCE_POSTCHANGE:
+/*              printk("notif %u of srce transition of %s to %s\n",
+			state, clk->name, ((struct clk *)data)->name);
+*/
+		break;
+	default:
+		printk(KERN_ERR "Unknown notification srce transition\n");
+		return NOTIFY_BAD;
+		break;
+	}
+
+	return srcu_notifier_call_chain(clk->notifier, state, data);
+}
+
+/*
+ * Standard clock functions defined in include/linux/clk.h
+ */
+int clk_enable(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_enable)
+		ret = arch_clock->clk_enable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+void clk_disable(struct clk *clk)
+{
+	unsigned long flags;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_disable)
+		arch_clock->clk_disable(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_disable);
+
+int clk_get_usecount(struct clk *clk)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = clk->usecount;
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_usecount);
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long flags;
+	unsigned long ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	ret = clk->rate;
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/*
+ * Optional clock functions defined in include/linux/clk.h
+ */
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long flags;
+	long ret = rate;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_round_rate)
+		ret = arch_clock->clk_round_rate(clk, rate);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	/* notification pre change */
+	if (clk->notifier)
+		ret = clk_notify_transition(clk,
+					    CLK_RATE_PRECHANGE, (void *)rate);
+
+	if (!(ret & NOTIFY_STOP_MASK)) {
+		spin_lock_irqsave(&clockfw_lock, flags);
+		if (arch_clock->clk_set_rate)
+			ret = arch_clock->clk_set_rate(clk, rate);
+		spin_unlock_irqrestore(&clockfw_lock, flags);
+
+		/* notification post change */
+		if (clk->notifier)
+			clk_notify_transition(clk,
+					      CLK_RATE_POSTCHANGE,
+					      (void *)clk->rate);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	unsigned long flags;
+	int ret = 0;
+
+	if (clk == ERR_PTR(-ENOENT))
+		return -EINVAL;
+
+	/* notification pre change */
+	if (clk->notifier)
+		ret = clk_notify_transition(clk,
+					    CLK_SRCE_PRECHANGE, (void *)parent);
+
+	if (!(ret & NOTIFY_STOP_MASK)) {
+		spin_lock_irqsave(&clockfw_lock, flags);
+		if (arch_clock->clk_set_parent)
+			ret = arch_clock->clk_set_parent(clk, parent);
+		spin_unlock_irqrestore(&clockfw_lock, flags);
+
+		/* notification post change */
+		if (clk->notifier)
+			clk_notify_transition(clk,
+					      CLK_SRCE_POSTCHANGE,
+					      (void *)clk->parent);
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	unsigned long flags;
+	struct clk *ret = ERR_PTR(-ENOENT);
+
+	if (clk == ERR_PTR(-ENOENT))
+		return ret;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_get_parent)
+		ret = arch_clock->clk_get_parent(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+/*
+ * Internal clock functions
+ */
+
+unsigned int __initdata mpurate;
+/*
+ * By default we use the rate set by the bootloader.
+ * You can override this with mpurate= cmdline option.
+ */
+static int __init u6_clk_setup(char *str)
+{
+	unsigned int tmp_rate;
+
+	get_option(&str, &tmp_rate);
+
+	if (!tmp_rate)
+		return 1;
+
+	mpurate = tmp_rate;
+
+	return 1;
+}
+
+__setup("mpurate=", u6_clk_setup);
+
+/* Used for clocks that always have same value as the parent clock */
+void followparent_recalc(struct clk *clk)
+{
+	clk->rate = clk->parent->rate;
+}
+
+/* Propagate rate to children */
+void propagate_rate(struct clk *tclk)
+{
+	struct clk *clkp;
+
+	list_for_each_entry(clkp, &clocks, node) {
+		if (likely(clkp->parent != tclk))
+			continue;
+		if (likely((u32) clkp->recalc))
+			clkp->recalc(clkp);
+	}
+}
+
+int clk_register(struct clk *clk)
+{
+	mutex_lock(&clocks_mutex);
+	list_add(&clk->node, &clocks);
+	if (clk->init)
+		clk->init(clk);
+	mutex_unlock(&clocks_mutex);
+
+	return 0;
+}
+EXPORT_SYMBOL(clk_register);
+
+void clk_unregister(struct clk *clk)
+{
+	mutex_lock(&clocks_mutex);
+	list_del(&clk->node);
+	mutex_unlock(&clocks_mutex);
+}
+EXPORT_SYMBOL(clk_unregister);
+
+void clk_deny_idle(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_deny_idle)
+		arch_clock->clk_deny_idle(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_deny_idle);
+
+void clk_allow_idle(struct clk *clk)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&clockfw_lock, flags);
+	if (arch_clock->clk_allow_idle)
+		arch_clock->clk_allow_idle(clk);
+	spin_unlock_irqrestore(&clockfw_lock, flags);
+}
+EXPORT_SYMBOL(clk_allow_idle);
+
+#ifdef CONFIG_U6_POWER_SYSFS
+/*
+ * SysFs interface
+ */
+
+/*** Clock mngt sysfs interface **/
+static char clk_name[64] = "MMTU";
+
+static ssize_t show_select(struct kobject *kobj, char *buf)
+{
+	return sprintf(buf, "%s \n", clk_name);
+}
+
+static ssize_t store_select(struct kobject *kobj, const char *buf, size_t size)
+{
+	strcpy(clk_name, buf);
+
+	clk_name[strlen(clk_name) - 1] = 0;
+
+	return size;
+}
+
+static ssize_t show_enable(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%d \n", clk_get_usecount(clk));
+}
+
+static ssize_t store_enable(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return size;
+	clk_enable(clk);
+	clk_put(clk);
+	return size;
+}
+
+static ssize_t show_disable(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%d \n", clk_get_usecount(clk));
+}
+
+static ssize_t store_disable(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return size;
+	clk_disable(clk);
+	clk_put(clk);
+	return size;
+}
+
+static ssize_t show_usecount(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%d \n", clk_get_usecount(clk));
+}
+
+static ssize_t show_rate(struct kobject *kobj, char *buf)
+{
+	struct clk *clk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	clk_put(clk);
+	return sprintf(buf, "%lu \n", clk_get_rate(clk));
+}
+
+static ssize_t store_rate(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk;
+	unsigned long rate;
+	if (strict_strtoul(buf, 10, &rate) == 0) {
+		clk = clk_get(NULL, clk_name);
+		if (clk == ERR_PTR(-ENOENT))
+			return size;
+		clk_set_rate(clk, rate);
+		clk_put(clk);
+	}
+	return size;
+}
+
+static ssize_t show_parent(struct kobject *kobj, char *buf)
+{
+	struct clk *clk, *pclk;
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return sprintf(buf, "unable to get clk\n");
+	pclk = clk_get_parent(clk);
+	clk_put(clk);
+	if ((pclk) && (pclk->name))
+		return sprintf(buf, "%s\n", pclk->name);
+	else
+		return sprintf(buf, "root\n");
+}
+
+static ssize_t store_parent(struct kobject *kobj, const char *buf, size_t size)
+{
+	struct clk *clk, *pclk;
+	char parent[32];
+	strcpy(parent, buf);
+	parent[strlen(parent) - 1] = 0;
+
+	clk = clk_get(NULL, clk_name);
+	if (clk == ERR_PTR(-ENOENT))
+		return size;
+
+	pclk = clk_get(NULL, parent);
+	if (pclk == ERR_PTR(-ENOENT)) {
+		clk_put(clk);
+		return size;
+	}
+	clk_put(pclk);
+	clk_set_parent(clk, pclk);
+	clk_put(clk);
+	return size;
+}
+
+static ssize_t show_list(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+
+	struct clk *p;
+
+	list_for_each_entry(p, &clocks, node) {
+		size += sprintf(&buf[size], "%s\n", p->name);
+	}
+	return size;
+}
+
+/*** Clock mngt hw debug ***/
+static ssize_t show_hw_constraints(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+
+	size += u6_clk_show_hw_rates(kobj, &buf[size]);
+
+	size += u6_clk_show_sc_constraints(kobj, &buf[size]);
+
+	size += u6_clk_show_ivs_constraints(kobj, &buf[size]);
+
+	size += u6_clk_show_tvo_constraints(kobj, &buf[size]);
+
+	size += u6_clk_show_cam_constraints(kobj, &buf[size]);
+
+	return size;
+}
+
+static ssize_t show_hw_rates(struct kobject *kobj, char *buf)
+{
+	int size = 0;
+
+	size += u6_clk_show_hw_rates(kobj, buf);
+
+	return size;
+}
+
+define_one_ro(hw_rates);
+define_one_ro(hw_constraints);
+define_one_rw(parent);
+define_one_rw(rate);
+define_one_ro(usecount);
+define_one_rw(disable);
+define_one_rw(enable);
+define_one_rw(select);
+define_one_ro(list);
+
+static struct attribute *dbs_attributes_clock[] = {
+
+	&hw_rates.attr,
+	&hw_constraints.attr,
+	&parent.attr,
+	&rate.attr,
+	&usecount.attr,
+	&disable.attr,
+	&enable.attr,
+	&select.attr,
+	&list.attr,
+	NULL
+};
+
+static struct attribute_group dbs_attr_clock_group = {
+	.attrs = dbs_attributes_clock,
+	.name = "clk_mngt",
+};
+
+#endif
+
+/*
+ * Init functions
+ */
+
+int __init clk_init(struct clk_functions *custom_clocks)
+{
+	if (!custom_clocks) {
+		printk(KERN_ERR "No custom clock functions registered\n");
+		BUG();
+	}
+
+	arch_clock = custom_clocks;
+
+	return 0;
+}
+
+#ifdef CONFIG_U6_POWER_SYSFS
+static int __init u6_clock_init_sysfs(void)
+{
+	if (sysfs_create_group(&u6_power_kobj, &dbs_attr_clock_group))
+		printk(KERN_ERR "Unable to register %s in sysfs\n",
+		       dbs_attr_clock_group.name);
+
+	return 0;
+}
+
+module_init(u6_clock_init_sysfs);
+#endif
+
diff --git a/arch/arm/plat-u6xxx/include/mach/clkdev.h b/arch/arm/plat-u6xxx/include/mach/clkdev.h
new file mode 100644
index 0000000..730c49d
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/clkdev.h
@@ -0,0 +1,13 @@
+#ifndef __MACH_CLKDEV_H
+#define __MACH_CLKDEV_H
+
+static inline int __clk_get(struct clk *clk)
+{
+	return 1;
+}
+
+static inline void __clk_put(struct clk *clk)
+{
+}
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/clock.h b/arch/arm/plat-u6xxx/include/mach/clock.h
new file mode 100644
index 0000000..ded9fdd
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/clock.h
@@ -0,0 +1,378 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/clock.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * Based on clocks.h by Tony Lindgren, Gordon McNutt and RidgeRun, Inc
+ */
+
+#ifndef __PLAT_CLOCK_H
+#define __PLAT_CLOCK_H
+
+#include <linux/io.h>
+
+struct module;
+
+struct clk {
+	struct list_head	node;
+	struct module		*owner;
+	const char		*name;
+	struct clk		*parent;
+	unsigned long		rate;
+	__u32			flags;
+	void __iomem		*enable_reg;
+	__u8			enable_bit;
+	__u8			rate_offset;
+	__u8			src_offset;
+	__s8			usecount;
+	void			(*recalc)(struct clk *);
+	int			(*set_rate)(struct clk *, unsigned long);
+	long			(*round_rate)(struct clk *, unsigned long);
+	void			(*init)(struct clk *);
+	int			(*enable)(struct clk *);
+	void			(*disable)(struct clk *);
+	int			(*set_parent)(struct clk *, struct clk *);
+	struct srcu_notifier_head *notifier;
+};
+
+struct clk_functions {
+	int		(*clk_enable)(struct clk *clk);
+	void		(*clk_disable)(struct clk *clk);
+	long		(*clk_round_rate)(struct clk *clk, unsigned long rate);
+	int		(*clk_set_rate)(struct clk *clk, unsigned long rate);
+	int		(*clk_set_parent)(struct clk *clk, struct clk *parent);
+	struct clk *	(*clk_get_parent)(struct clk *clk);
+	void		(*clk_allow_idle)(struct clk *clk);
+	void		(*clk_deny_idle)(struct clk *clk);
+};
+
+extern unsigned int mpurate;
+extern struct list_head clocks;
+extern spinlock_t clockfw_lock;
+
+extern int clk_init(struct clk_functions *custom_clocks);
+extern int clk_register(struct clk *clk);
+extern void clk_unregister(struct clk *clk);
+
+extern void propagate_rate(struct clk *clk);
+extern void followparent_recalc(struct clk *clk);
+extern void clk_allow_idle(struct clk *clk);
+extern void clk_deny_idle(struct clk *clk);
+extern int clk_get_usecount(struct clk *clk);
+
+extern ssize_t u6_clk_show_hw_rates(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_sc_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_usb_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_ivs_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_tvo_constraints(struct kobject *kobj, char *buf);
+extern ssize_t u6_clk_show_cam_constraints(struct kobject *kobj, char *buf);
+
+extern unsigned long clk_get_hw_constraint(void __iomem *reg_addr);
+
+
+/* Clock flags */
+#define RATE_CKCTL		(1 << 0)	/* Main fixed ratio clocks */
+#define RATE_FIXED		(1 << 1)	/* Fixed clock rate */
+#define RATE_PROPAGATES		(1 << 2)	/* Program children too */
+#define VIRTUAL_CLOCK		(1 << 3)	/* Composite clock from table */
+#define ALWAYS_ENABLED		(1 << 4)	/* Clock cannot be disabled */
+#define ENABLE_REG_32BIT	(1 << 5)	/* Use 32-bit access */
+#define VIRTUAL_IO_ADDRESS	(1 << 6)	/* Clock in virtual address */
+#define CLOCK_IDLE_CONTROL	(1 << 7)
+#define CLOCK_NO_IDLE_PARENT	(1 << 8)
+#define DELAYED_APP		(1 << 9)	/* Delay application of clock */
+#define CONFIG_PARTICIPANT	(1 << 10)	/* Fundamental clock */
+
+
+#define CLK_HCLK2_MAX_FREQ	104000000
+#define CLK_FC_CLK_MAX_FREQ	104000000
+#define CLK_CAM_CLK_MAX_FREQ	 78000000
+
+/**
+ * clk_register_notifier - register a driver with clock mngt
+ *	@nb: notifier function to register
+ *  @clk: clock element rate change to be notified
+ */
+extern int clk_register_notifier(struct notifier_block *nb, struct clk *clk);
+
+/**
+ * clk_unregister_notifier - unregister a driver with clock mngt
+ *	@nb: notifier function to register
+ *  @clk: clock element rate change to be notified
+ */
+extern int clk_unregister_notifier(struct notifier_block *nb, struct clk *clk);
+
+/**
+ * clk_notify_transition - call notifier chain
+ *
+ * This function calls the transition notifiers and the and set rate
+ * It is called twice on all frequency changes that have
+ * external effects.
+ */
+extern int clk_notify_transition(struct clk *clk,
+		unsigned int state, void *data);
+
+#define CLK_RATE_PRECHANGE 0
+#define CLK_RATE_POSTCHANGE 1
+#define CLK_SRCE_PRECHANGE 2
+#define CLK_SRCE_POSTCHANGE 3
+
+/* Hardware Register Definitions CGU (Clock Gating Unit) */
+
+/* CGU DSP1CON Register (32 bits) */
+#define CGU_DSP1CON_OFFSET             0x0
+#define CGU_DSP1CON_REG                U6_IO_ADDRESS(CGU_BASE + CGU_DSP1CON_OFFSET)
+
+/* CGU SCCON Register (32 bits) */
+#define CGU_SCCON_OFFSET               0x4
+#define CGU_SCCON_REG                  U6_IO_ADDRESS(CGU_BASE + CGU_SCCON_OFFSET)
+
+/* CGU GATESC1 Register (32 bits) */
+#define CGU_GATESC1_OFFSET             0x8
+#define CGU_GATESC1_REG                U6_IO_ADDRESS(CGU_BASE + CGU_GATESC1_OFFSET)
+
+/* CGU SLEEPSC Register (32 bits) */
+#define CGU_SLEEPSC_OFFSET             0xC
+#define CGU_SLEEPSC_REG                U6_IO_ADDRESS(CGU_BASE + CGU_SLEEPSC_OFFSET)
+
+/* CGU FDIV Register (32 bits) */
+#define CGU_FDIV_OFFSET                0x10
+#define CGU_FDIV_REG                   U6_IO_ADDRESS(CGU_BASE + CGU_FDIV_OFFSET)
+
+/* CGU GATEIVS Register (32 bits) */
+#define CGU_GATEIVS_OFFSET             0x14
+#define CGU_GATEIVS_REG                U6_IO_ADDRESS(CGU_BASE + CGU_GATEIVS_OFFSET)
+
+/* CGU DSP2CON Register (32 bits) */
+#define CGU_DSP2CON_OFFSET             0x18
+#define CGU_DSP2CON_REG                U6_IO_ADDRESS(CGU_BASE + CGU_DSP2CON_OFFSET)
+
+/* CGU CAMCON Register (32 bits) */
+#define CGU_CAMCON_OFFSET              0x1C
+#define CGU_CAMCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_CAMCON_OFFSET)
+
+/* CGU GATESC2 Register (32 bits) */
+#define CGU_GATESC2_OFFSET             0x20
+#define CGU_GATESC2_REG                U6_IO_ADDRESS(CGU_BASE + CGU_GATESC2_OFFSET)
+
+/* CGU SDMCON Register (32 bits) */
+#define CGU_SDMCON_OFFSET              0x24
+#define CGU_SDMCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_SDMCON_OFFSET)
+
+/* CGU TVCON Register (32 bits) */
+#define CGU_TVCON_OFFSET               0x28
+#define CGU_TVCON_REG                  U6_IO_ADDRESS(CGU_BASE + CGU_TVCON_OFFSET)
+
+/* CGU IDLESC Register (32 bits) */
+#define CGU_IDLESC_OFFSET              0x2C
+#define CGU_IDLESC_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_IDLESC_OFFSET)
+
+/* CGU FIXCON Register (32 bits) */
+#define CGU_FIXCON_OFFSET              0x30
+#define CGU_FIXCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_FIXCON_OFFSET)
+
+/* CGU CNTCON Register (32 bits) */
+#define CGU_CNTCON_OFFSET              0x38
+#define CGU_CNTCON_REG                 U6_IO_ADDRESS(CGU_BASE + CGU_CNTCON_OFFSET)
+
+/* Register description for GATESC1 */
+
+/* Bits definition for register CGU_GATESC1 */
+#define CGU_EBIEN_SHIFT            31
+#define CGU_EBIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_EBIEN_SHIFT))
+#define CGU_EBIEN_0                (0x0UL<<CGU_EBIEN_SHIFT)
+#define CGU_EBIEN_1                (0x1UL<<CGU_EBIEN_SHIFT)
+#define CGU_EBIEN                  (0x1UL<<CGU_EBIEN_SHIFT)
+#define CGU_NFIEN_SHIFT            29
+#define CGU_NFIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_NFIEN_SHIFT))
+#define CGU_NFIEN_0                (0x0UL<<CGU_NFIEN_SHIFT)
+#define CGU_NFIEN_1                (0x1UL<<CGU_NFIEN_SHIFT)
+#define CGU_NFIEN                  (0x1UL<<CGU_NFIEN_SHIFT)
+#define CGU_SDIEN_SHIFT            28
+#define CGU_SDIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_SDIEN_SHIFT))
+#define CGU_SDIEN_0                (0x0UL<<CGU_SDIEN_SHIFT)
+#define CGU_SDIEN_1                (0x1UL<<CGU_SDIEN_SHIFT)
+#define CGU_SDIEN                  (0x1UL<<CGU_SDIEN_SHIFT)
+#define CGU_MSIEN_SHIFT            26
+#define CGU_MSIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_MSIEN_SHIFT))
+#define CGU_MSIEN_0                (0x0UL<<CGU_MSIEN_SHIFT)
+#define CGU_MSIEN_1                (0x1UL<<CGU_MSIEN_SHIFT)
+#define CGU_MSIEN                  (0x1UL<<CGU_MSIEN_SHIFT)
+#define CGU_UCCEN_SHIFT            25
+#define CGU_UCCEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_UCCEN_SHIFT))
+#define CGU_UCCEN_0                (0x0UL<<CGU_UCCEN_SHIFT)
+#define CGU_UCCEN_1                (0x1UL<<CGU_UCCEN_SHIFT)
+#define CGU_UCCEN                  (0x1UL<<CGU_UCCEN_SHIFT)
+#define CGU_JDIEN_SHIFT            24
+#define CGU_JDIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_JDIEN_SHIFT))
+#define CGU_JDIEN_0                (0x0UL<<CGU_JDIEN_SHIFT)
+#define CGU_JDIEN_1                (0x1UL<<CGU_JDIEN_SHIFT)
+#define CGU_JDIEN                  (0x1UL<<CGU_JDIEN_SHIFT)
+#define CGU_DMAUEN_SHIFT           20
+#define CGU_DMAUEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_DMAUEN_SHIFT))
+#define CGU_DMAUEN_0               (0x0UL<<CGU_DMAUEN_SHIFT)
+#define CGU_DMAUEN_1               (0x1UL<<CGU_DMAUEN_SHIFT)
+#define CGU_DMAUEN                 (0x1UL<<CGU_DMAUEN_SHIFT)
+#define CGU_RFSM1EN_SHIFT          19
+#define CGU_RFSM1EN_FIELD          (0xFFFFFFFF - (0x1UL<<CGU_RFSM1EN_SHIFT))
+#define CGU_RFSM1EN_0              (0x0UL<<CGU_RFSM1EN_SHIFT)
+#define CGU_RFSM1EN_1              (0x1UL<<CGU_RFSM1EN_SHIFT)
+#define CGU_RFSM1EN                (0x1UL<<CGU_RFSM1EN_SHIFT)
+#define CGU_SIISEN_SHIFT           18
+#define CGU_SIISEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SIISEN_SHIFT))
+#define CGU_SIISEN_0               (0x0UL<<CGU_SIISEN_SHIFT)
+#define CGU_SIISEN_1               (0x1UL<<CGU_SIISEN_SHIFT)
+#define CGU_SIISEN                 (0x1UL<<CGU_SIISEN_SHIFT)
+#define CGU_USBEN_SHIFT            17
+#define CGU_USBEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_USBEN_SHIFT))
+#define CGU_USBEN_0                (0x0UL<<CGU_USBEN_SHIFT)
+#define CGU_USBEN_1                (0x1UL<<CGU_USBEN_SHIFT)
+#define CGU_USBEN                  (0x1UL<<CGU_USBEN_SHIFT)
+#define CGU_FCIEN_SHIFT            16
+#define CGU_FCIEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_FCIEN_SHIFT))
+#define CGU_FCIEN_0                (0x0UL<<CGU_FCIEN_SHIFT)
+#define CGU_FCIEN_1                (0x1UL<<CGU_FCIEN_SHIFT)
+#define CGU_FCIEN                  (0x1UL<<CGU_FCIEN_SHIFT)
+#define CGU_USIMEN_SHIFT           15
+#define CGU_USIMEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_USIMEN_SHIFT))
+#define CGU_USIMEN_0               (0x0UL<<CGU_USIMEN_SHIFT)
+#define CGU_USIMEN_1               (0x1UL<<CGU_USIMEN_SHIFT)
+#define CGU_USIMEN                 (0x1UL<<CGU_USIMEN_SHIFT)
+#define CGU_GEACEN_SHIFT           14
+#define CGU_GEACEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_GEACEN_SHIFT))
+#define CGU_GEACEN_0               (0x0UL<<CGU_GEACEN_SHIFT)
+#define CGU_GEACEN_1               (0x1UL<<CGU_GEACEN_SHIFT)
+#define CGU_GEACEN                 (0x1UL<<CGU_GEACEN_SHIFT)
+#define CGU_PWM3EN_SHIFT           13
+#define CGU_PWM3EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_PWM3EN_SHIFT))
+#define CGU_PWM3EN_0               (0x0UL<<CGU_PWM3EN_SHIFT)
+#define CGU_PWM3EN_1               (0x1UL<<CGU_PWM3EN_SHIFT)
+#define CGU_PWM3EN                 (0x1UL<<CGU_PWM3EN_SHIFT)
+#define CGU_PWM2EN_SHIFT           12
+#define CGU_PWM2EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_PWM2EN_SHIFT))
+#define CGU_PWM2EN_0               (0x0UL<<CGU_PWM2EN_SHIFT)
+#define CGU_PWM2EN_1               (0x1UL<<CGU_PWM2EN_SHIFT)
+#define CGU_PWM2EN                 (0x1UL<<CGU_PWM2EN_SHIFT)
+#define CGU_PWM1EN_SHIFT           11
+#define CGU_PWM1EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_PWM1EN_SHIFT))
+#define CGU_PWM1EN_0               (0x0UL<<CGU_PWM1EN_SHIFT)
+#define CGU_PWM1EN_1               (0x1UL<<CGU_PWM1EN_SHIFT)
+#define CGU_PWM1EN                 (0x1UL<<CGU_PWM1EN_SHIFT)
+#define CGU_KBSEN_SHIFT            10
+#define CGU_KBSEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_KBSEN_SHIFT))
+#define CGU_KBSEN_0                (0x0UL<<CGU_KBSEN_SHIFT)
+#define CGU_KBSEN_1                (0x1UL<<CGU_KBSEN_SHIFT)
+#define CGU_KBSEN                  (0x1UL<<CGU_KBSEN_SHIFT)
+#define CGU_GPIOEN_SHIFT           9
+#define CGU_GPIOEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_GPIOEN_SHIFT))
+#define CGU_GPIOEN_0               (0x0UL<<CGU_GPIOEN_SHIFT)
+#define CGU_GPIOEN_1               (0x1UL<<CGU_GPIOEN_SHIFT)
+#define CGU_GPIOEN                 (0x1UL<<CGU_GPIOEN_SHIFT)
+#define CGU_UART2EN_SHIFT          8
+#define CGU_UART2EN_FIELD          (0xFFFFFFFF - (0x1UL<<CGU_UART2EN_SHIFT))
+#define CGU_UART2EN_0              (0x0UL<<CGU_UART2EN_SHIFT)
+#define CGU_UART2EN_1              (0x1UL<<CGU_UART2EN_SHIFT)
+#define CGU_UART2EN                (0x1UL<<CGU_UART2EN_SHIFT)
+#define CGU_UART1EN_SHIFT          7
+#define CGU_UART1EN_FIELD          (0xFFFFFFFF - (0x1UL<<CGU_UART1EN_SHIFT))
+#define CGU_UART1EN_0              (0x0UL<<CGU_UART1EN_SHIFT)
+#define CGU_UART1EN_1              (0x1UL<<CGU_UART1EN_SHIFT)
+#define CGU_UART1EN                (0x1UL<<CGU_UART1EN_SHIFT)
+#define CGU_IIC2EN_SHIFT           6
+#define CGU_IIC2EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_IIC2EN_SHIFT))
+#define CGU_IIC2EN_0               (0x0UL<<CGU_IIC2EN_SHIFT)
+#define CGU_IIC2EN_1               (0x1UL<<CGU_IIC2EN_SHIFT)
+#define CGU_IIC2EN                 (0x1UL<<CGU_IIC2EN_SHIFT)
+#define CGU_IIC1EN_SHIFT           5
+#define CGU_IIC1EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_IIC1EN_SHIFT))
+#define CGU_IIC1EN_0               (0x0UL<<CGU_IIC1EN_SHIFT)
+#define CGU_IIC1EN_1               (0x1UL<<CGU_IIC1EN_SHIFT)
+#define CGU_IIC1EN                 (0x1UL<<CGU_IIC1EN_SHIFT)
+#define CGU_SPI2EN_SHIFT           4
+#define CGU_SPI2EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SPI2EN_SHIFT))
+#define CGU_SPI2EN_0               (0x0UL<<CGU_SPI2EN_SHIFT)
+#define CGU_SPI2EN_1               (0x1UL<<CGU_SPI2EN_SHIFT)
+#define CGU_SPI2EN                 (0x1UL<<CGU_SPI2EN_SHIFT)
+#define CGU_SPI1EN_SHIFT           3
+#define CGU_SPI1EN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SPI1EN_SHIFT))
+#define CGU_SPI1EN_0               (0x0UL<<CGU_SPI1EN_SHIFT)
+#define CGU_SPI1EN_1               (0x1UL<<CGU_SPI1EN_SHIFT)
+#define CGU_SPI1EN                 (0x1UL<<CGU_SPI1EN_SHIFT)
+#define CGU_SCTUEN_SHIFT           2
+#define CGU_SCTUEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_SCTUEN_SHIFT))
+#define CGU_SCTUEN_0               (0x0UL<<CGU_SCTUEN_SHIFT)
+#define CGU_SCTUEN_1               (0x1UL<<CGU_SCTUEN_SHIFT)
+#define CGU_SCTUEN                 (0x1UL<<CGU_SCTUEN_SHIFT)
+#define CGU_EXTINTEN_SHIFT         1
+#define CGU_EXTINTEN_FIELD         (0xFFFFFFFF - (0x1UL<<CGU_EXTINTEN_SHIFT))
+#define CGU_EXTINTEN_0             (0x0UL<<CGU_EXTINTEN_SHIFT)
+#define CGU_EXTINTEN_1             (0x1UL<<CGU_EXTINTEN_SHIFT)
+#define CGU_EXTINTEN               (0x1UL<<CGU_EXTINTEN_SHIFT)
+#define CGU_INTCEN_SHIFT           0
+#define CGU_INTCEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_INTCEN_SHIFT))
+#define CGU_INTCEN_0               (0x0UL<<CGU_INTCEN_SHIFT)
+#define CGU_INTCEN_1               (0x1UL<<CGU_INTCEN_SHIFT)
+#define CGU_INTCEN                 (0x1UL<<CGU_INTCEN_SHIFT)
+
+/* Register description for GATESC2 */
+
+/* Bits definition for register CGU_GATESC2 */
+#define CGU_TRAUPCLKEN_SHIFT       15
+#define CGU_TRAUPCLKEN_FIELD       (0xFFFFFFFF - (0x1UL<<CGU_TRAUPCLKEN_SHIFT))
+#define CGU_TRAUPCLKEN_0           (0x0UL<<CGU_TRAUPCLKEN_SHIFT)
+#define CGU_TRAUPCLKEN_1           (0x1UL<<CGU_TRAUPCLKEN_SHIFT)
+#define CGU_TRAUPCLKEN             (0x1UL<<CGU_TRAUPCLKEN_SHIFT)
+#define CGU_AUTRXPCLKEN_SHIFT      12
+#define CGU_AUTRXPCLKEN_FIELD      (0xFFFFFFFF - (0x1UL<<CGU_AUTRXPCLKEN_SHIFT))
+#define CGU_AUTRXPCLKEN_0          (0x0UL<<CGU_AUTRXPCLKEN_SHIFT)
+#define CGU_AUTRXPCLKEN_1          (0x1UL<<CGU_AUTRXPCLKEN_SHIFT)
+#define CGU_AUTRXPCLKEN            (0x1UL<<CGU_AUTRXPCLKEN_SHIFT)
+#define CGU_AUTRXMCLK2EN_SHIFT     11
+#define CGU_AUTRXMCLK2EN_FIELD    (0xFFFFFFFF - (0x1UL<<CGU_AUTRXMCLK2EN_SHIFT))
+#define CGU_AUTRXMCLK2EN_0         (0x0UL<<CGU_AUTRXMCLK2EN_SHIFT)
+#define CGU_AUTRXMCLK2EN_1         (0x1UL<<CGU_AUTRXMCLK2EN_SHIFT)
+#define CGU_AUTRXMCLK2EN           (0x1UL<<CGU_AUTRXMCLK2EN_SHIFT)
+#define CGU_AUTRXMCLK1EN_SHIFT     10
+#define CGU_AUTRXMCLK1EN_FIELD    (0xFFFFFFFF - (0x1UL<<CGU_AUTRXMCLK1EN_SHIFT))
+#define CGU_AUTRXMCLK1EN_0         (0x0UL<<CGU_AUTRXMCLK1EN_SHIFT)
+#define CGU_AUTRXMCLK1EN_1         (0x1UL<<CGU_AUTRXMCLK1EN_SHIFT)
+#define CGU_AUTRXMCLK1EN           (0x1UL<<CGU_AUTRXMCLK1EN_SHIFT)
+#define CGU_BBIPCLKEN_SHIFT        9
+#define CGU_BBIPCLKEN_FIELD        (0xFFFFFFFF - (0x1UL<<CGU_BBIPCLKEN_SHIFT))
+#define CGU_BBIPCLKEN_0            (0x0UL<<CGU_BBIPCLKEN_SHIFT)
+#define CGU_BBIPCLKEN_1            (0x1UL<<CGU_BBIPCLKEN_SHIFT)
+#define CGU_BBIPCLKEN              (0x1UL<<CGU_BBIPCLKEN_SHIFT)
+#define CGU_HSDPAHCLKEN_SHIFT      8
+#define CGU_HSDPAHCLKEN_FIELD      (0xFFFFFFFF - (0x1UL<<CGU_HSDPAHCLKEN_SHIFT))
+#define CGU_HSDPAHCLKEN_0          (0x0UL<<CGU_HSDPAHCLKEN_SHIFT)
+#define CGU_HSDPAHCLKEN_1          (0x1UL<<CGU_HSDPAHCLKEN_SHIFT)
+#define CGU_HSDPAHCLKEN            (0x1UL<<CGU_HSDPAHCLKEN_SHIFT)
+#define CGU_3GMHCLKEN_SHIFT        7
+#define CGU_3GMHCLKEN_FIELD        (0xFFFFFFFF - (0x1UL<<CGU_3GMHCLKEN_SHIFT))
+#define CGU_3GMHCLKEN_0            (0x0UL<<CGU_3GMHCLKEN_SHIFT)
+#define CGU_3GMHCLKEN_1            (0x1UL<<CGU_3GMHCLKEN_SHIFT)
+#define CGU_3GMHCLKEN              (0x1UL<<CGU_3GMHCLKEN_SHIFT)
+#define CGU_3GMMCLKEN_SHIFT        6
+#define CGU_3GMMCLKEN_FIELD        (0xFFFFFFFF - (0x1UL<<CGU_3GMMCLKEN_SHIFT))
+#define CGU_3GMMCLKEN_0            (0x0UL<<CGU_3GMMCLKEN_SHIFT)
+#define CGU_3GMMCLKEN_1            (0x1UL<<CGU_3GMMCLKEN_SHIFT)
+#define CGU_3GMMCLKEN              (0x1UL<<CGU_3GMMCLKEN_SHIFT)
+#define CGU_ETBEN_SHIFT            4
+#define CGU_ETBEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_ETBEN_SHIFT))
+#define CGU_ETBEN_0                (0x0UL<<CGU_ETBEN_SHIFT)
+#define CGU_ETBEN_1                (0x1UL<<CGU_ETBEN_SHIFT)
+#define CGU_ETBEN                  (0x1UL<<CGU_ETBEN_SHIFT)
+#define CGU_MMTUEN_SHIFT           2
+#define CGU_MMTUEN_FIELD           (0xFFFFFFFF - (0x1UL<<CGU_MMTUEN_SHIFT))
+#define CGU_MMTUEN_0               (0x0UL<<CGU_MMTUEN_SHIFT)
+#define CGU_MMTUEN_1               (0x1UL<<CGU_MMTUEN_SHIFT)
+#define CGU_MMTUEN                 (0x1UL<<CGU_MMTUEN_SHIFT)
+#define CGU_CAEEN_SHIFT            0
+#define CGU_CAEEN_FIELD            (0xFFFFFFFF - (0x1UL<<CGU_CAEEN_SHIFT))
+#define CGU_CAEEN_0                (0x0UL<<CGU_CAEEN_SHIFT)
+#define CGU_CAEEN_1                (0x1UL<<CGU_CAEEN_SHIFT)
+#define CGU_CAEEN                  (0x1UL<<CGU_CAEEN_SHIFT)
+
+#endif
-- 
1.7.1

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

* [PATCH 3/5] U6715 gpio platform driver This driver is U6XXX platform generic
  2010-08-05 12:28 ` Philippe Langlais
                   ` (2 preceding siblings ...)
  (?)
@ 2010-08-05 12:28 ` Philippe Langlais
  -1 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 arch/arm/mach-u67xx/board_u67xx_wavex.c |  468 ++++++++++++++++++++++
 arch/arm/mach-u67xx/devices.c           |   67 +++
 arch/arm/plat-u6xxx/Makefile            |    2 +-
 arch/arm/plat-u6xxx/gpio.c              |  665 +++++++++++++++++++++++++++++++
 arch/arm/plat-u6xxx/include/mach/gpio.h |  391 ++++++++++++++++++
 arch/arm/plat-u6xxx/include/mach/scon.h |  123 ++++++
 6 files changed, 1715 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/plat-u6xxx/gpio.c
 create mode 100644 arch/arm/plat-u6xxx/include/mach/gpio.h
 create mode 100644 arch/arm/plat-u6xxx/include/mach/scon.h

diff --git a/arch/arm/mach-u67xx/board_u67xx_wavex.c b/arch/arm/mach-u67xx/board_u67xx_wavex.c
index 633989f..c54a79b 100644
--- a/arch/arm/mach-u67xx/board_u67xx_wavex.c
+++ b/arch/arm/mach-u67xx/board_u67xx_wavex.c
@@ -14,6 +14,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/init.h>
+#include <linux/gpio.h>
 #include <linux/platform_device.h>
 
 #include <asm/setup.h>
@@ -23,6 +24,472 @@
 #include <mach/hardware.h>
 #include <mach/irqs.h>
 #include <mach/timer.h>
+#include <mach/scon.h>
+
+/**
+ * SCON initial settings
+ * Allows to define the PIN multiplexing for all the platform (Linux and Modem)
+ */
+struct u6_scon_config u6_scon_init_config[SCON_REGISTER_NB] = {
+ {
+	SCON_SYSMUX0_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A0  & 0xF))) | /* FM IRQ */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_A1  & 0xF))) | /* UART 2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_A2  & 0xF))) | /* UART 2 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A3  & 0xF))) |
+	(GPIO_MODE_MUX3 << (2 * (GPIO_A4  & 0xF))) | /* SIMOFF_copy for modem */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A5  & 0xF))) | /* for AGPS */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A6  & 0xF))) | /* LCD backlight
+							-> ressource backligth*/
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A7  & 0xF))) | /* Bluetooth */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A8  & 0xF))) | /* Reserved for mode DPWS*/
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A9  & 0xF))) | /* Reserved for mode DPWS*/
+	(GPIO_MODE_MUX1 << (2 * (GPIO_A10 & 0xF))) | /* UART2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_A11 & 0xF))) | /* UART2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_A12 & 0xF))) | /* UART 1, configured
+							by boot, don't touch */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A13 & 0xF))) | /* free */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A14 & 0xF))) | /* PMU irq */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A15 & 0xF)))
+ },
+ {
+	SCON_SYSMUX1_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A16 & 0xF))) | /* FCI data 3 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A17 & 0xF))) | /* free */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A18 & 0xF))) | /* FCI data 2 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A19 & 0xF))) | /* FCI data 1 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A20 & 0xF))) | /* Cam Ligth copy */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A21 & 0xF))) | /* RF on -> GPIO */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_A22 & 0xF))) | /* RF RF_DPN */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A23 & 0xF))) | /* RF reset -> GPIO */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A24 & 0xF))) | /* AGPS reset */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A25 & 0xF))) | /* AGPS wake up */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A26 & 0xF))) | /* free */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A27 & 0xF))) | /* SPI1 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A28 & 0xF))) | /* SPI1 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_A29 & 0xF))) | /* Audio IIS */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A30 & 0xF))) | /* AGPS pwr on */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_A31 & 0xF)))  /* free */
+ },
+ {
+	SCON_SYSMUX2_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B0  & 0xF))) | /* RF DD */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B1  & 0xF))) | /* RF DU */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B2  & 0xF))) | /* RF FSC */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B3  & 0xF))) | /* RF DCL */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B4  & 0xF))) | /* UART RTS1 -> console */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B5  & 0xF))) | /* UART TXD1 -> console */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B6  & 0xF))) | /* NFI ready -> for NFI */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B7  & 0xF))) | /* VDE_EOFI -> VDE already
+						configured by splashscreen */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B8  & 0xF))) | /* RFEN0 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_B9  & 0xF))) | /* FCICMD -> for FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_B10 & 0xF))) | /* FCICLK -> for FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_B11 & 0xF))) | /* FCIDATA0 -> for FCI */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B12 & 0xF))) | /* RFSIG6 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B13 & 0xF))) | /* RFSIG7 */
+	(GPIO_MODE_MUX3 << (2 * (GPIO_B14 & 0xF))) |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_B15 & 0xF)))  /* RFDATA */
+ },
+ {
+	SCON_SYSMUX3_REG,
+	0
+ },
+ {
+	SCON_SYSMUX4_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C0  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C1  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C2  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C3  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C4  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C5  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C6  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C7  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C8  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C9  & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C10 & 0xF))) | /* VDE */
+#ifdef CONFIG_EBI_BUS
+	(GPIO_MODE_MUX2 << (2 * (GPIO_C11 & 0xF))) | /* EBI_CS0 */
+#else
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C11 & 0xF))) | /* VDE */
+#endif
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C12 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C13 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C14 & 0xF))) | /* KCOL0 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C15 & 0xF)))  /* KCOL1 -> keypad */
+
+ },
+ {
+	SCON_SYSMUX5_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C16 & 0xF))) | /* KCOL2 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C17 & 0xF))) | /* KCOL3 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C18 & 0xF))) | /* KCOL4 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C19 & 0xF))) | /* KROW0 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C20 & 0xF))) | /* KROW1 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C21 & 0xF))) | /* KROW2 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C22 & 0xF))) | /* KROW3 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C23 & 0xF))) | /* KROW4 -> keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C24 & 0xF))) | /* RF3GSPIEN0 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C25 & 0xF))) | /* RF3GSPIDATA */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C26 & 0xF))) | /* RF3GSPICLK */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C27 & 0xF))) | /* RFSM_OUT0 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C28 & 0xF))) | /* RFSM_OUT1 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_C29 & 0xF))) | /* RFSM_OUT2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_C30 & 0xF))) | /* I2C -> ressource */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_C31 & 0xF)))  /* I2C -> ressource */
+ },
+ {
+	SCON_SYSMUX6_REG,
+	0 |
+	(GPIO_MODE_MUX1 << (2 * (GPIO_D0  & 0xF))) | /* CAM PWRDN1 -> CAM */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D1  & 0xF))) | /* CAM DATA 0 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D2  & 0xF))) | /* CAM DATA 1 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D3  & 0xF))) | /* CAM DATA 2 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D4  & 0xF))) | /* CAM DATA 3 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D5  & 0xF))) | /* CAM DATA 4 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D6  & 0xF))) | /* CAM DATA 5 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D7  & 0xF))) | /* CAM DATA 6 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D8  & 0xF))) | /* CAM DATA 7 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D9  & 0xF))) | /* CAM DATA 8 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D10 & 0xF))) | /* CAM DATA 9 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D11 & 0xF))) | /* CAMVS */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D12 & 0xF))) | /* CAMHS */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D13 & 0xF))) | /* CAMCLKI */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D14 & 0xF))) | /* CAMCLKO */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_D15 & 0xF)))  /* VDDC2EN */
+ },
+ {
+	SCON_SYSMUX7_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D16 & 0xF))) | /* RF3GGPO9 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D17 & 0xF))) | /* RF3GGPO8 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_D18 & 0xF))) | /* FCI card detect, FCI */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_D19 & 0xF))) | /* CAM_Prelight copy, CAM*/
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D20 & 0xF))) | /* UART1 RXD1 -> Console */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D21 & 0xF))) | /* DIISWS */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D22 & 0xF))) | /* DIISSDO */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D23 & 0xF))) | /* DIISCK */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_D24 & 0xF))) | /* GPIOD24 ->FM Reset */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_D25 & 0xF))) | /* RFSIG3 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D26 & 0xF))) | /* RF3GGPO6 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D27 & 0xF))) | /* RF3GGPO7 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D28 & 0xF))) | /* RF3GGPO5 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_D29 & 0xF))) | /* GPIOD29 USB suspend */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D30 & 0xF))) | /* RF3GGPO4 */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_D31 & 0xF)))  /* RFCLK */
+ },
+#ifdef CONFIG_MACH_U67XX_V2_WAVEB_2GB
+{
+	SCON_SYSMUX8_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E0  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E1  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E2  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E3  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E4  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E5  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E6  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E7  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E8  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E9  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E10 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E11 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E12 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E13 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E14 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E15 & 0xF)))  /* DEBUG */
+ },
+ {
+	SCON_SYSMUX9_REG,
+	0 |
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E16 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E17 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E18 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E19 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E20 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E21 & 0xF))) | /* SDATO2 -> SPI2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E22 & 0xF))) | /* SDATIN2 -> SPI2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E23 & 0xF))) | /* SCLK2 -> SPI2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E24 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E25 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E26 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E27 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E28 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E29 & 0xF))) | /* FCI_copy
+							-> FCI USB suspend */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E30 & 0xF))) | /* RFSM_OUT3 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E31 & 0xF)))  /* GPIO CAM */
+ },
+#else
+{
+	SCON_SYSMUX8_REG,
+	0 |
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E0  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E1  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E2  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E3  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E4  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E5  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E6  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E7  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E8  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E9  & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E10 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E11 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E12 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E13 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E14 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E15 & 0xF)))  /* DEBUG */
+ },
+ {
+	SCON_SYSMUX9_REG,
+	0 |
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E16 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E17 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E18 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E19 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX2 << (2 * (GPIO_E20 & 0xF))) | /* DEBUG */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E21 & 0xF))) | /* SDATO2 -> SPI2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E22 & 0xF))) | /* SDATIN2 -> SPI2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E23 & 0xF))) | /* SCLK2 -> SPI2 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E24 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E25 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E26 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E27 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E28 & 0xF))) | /* FCI_copy -> FCI */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E29 & 0xF))) | /* FCI_copy
+							-> FCI USB suspend */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_E30 & 0xF))) | /* RFSM_OUT3 */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_E31 & 0xF)))  /* GPIO CAM */
+ },
+
+#endif
+ {
+	SCON_SYSMUX10_REG,
+	0 |
+#ifdef CONFIG_EBI_BUS
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F0  & 0xF))) | /* EBI_IO0_copy */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F1  & 0xF))) | /* EBI_OE_RW_copy */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F2  & 0xF))) | /* EBI_WE_E_copy */
+#else
+	(GPIO_MODE_MUX1 << (2 * (GPIO_F0  & 0xF))) | /* CAM_PWR_REG -> CAM */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_F1  & 0xF))) | /* AGPS FRAME_SYNC, AGPS */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F2  & 0xF))) | /* free */
+#endif
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F3  & 0xF))) | /* KCOL5 -> Keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F4  & 0xF))) | /* KCOL6 -> Keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F5  & 0xF))) | /* KCOL7 -> Keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F6  & 0xF))) | /* KROW5 -> Keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F7  & 0xF))) | /* KROW6 -> Keypad */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F8  & 0xF))) | /* KROW7 -> Keypad */
+	(GPIO_MODE_MUX1 << (2 * (GPIO_F9  & 0xF))) | /* eMMC_PDn -> FCI */
+#ifdef CONFIG_EBI_BUS
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F10 & 0xF))) | /* VDE_CS0_copy */
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F11 & 0xF))) | /* EBI_IO1_copy */
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F12 & 0xF))) | /* EBI_IO2_copy */
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F13 & 0xF))) | /* EBI_IO3_copy */
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F14 & 0xF))) | /* EBI_IO4_copy */
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F15 & 0xF)))  /* EBI_IO5_copy */
+#else
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F10 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F11 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F12 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F13 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F14 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F15 & 0xF)))  /* VDE */
+#endif
+ },
+ {
+	SCON_SYSMUX11_REG,
+	0 |
+#ifdef CONFIG_EBI_BUS
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F16 & 0xF))) | /* EBI_IO6_copy */
+	(GPIO_MODE_MUX3 << (2 * (GPIO_F17 & 0xF))) | /* EBI_IO7_copy */
+#else
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F16 & 0xF))) | /* VDE */
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F17 & 0xF))) | /* VDE */
+#endif
+	(GPIO_MODE_MUX0 << (2 * (GPIO_F18 & 0xF)))  /* NFI_CE_n -> NFI */
+ },
+ /* Configure PAD Value */
+ {
+	SCON_SYSPAD0_REG,
+	0 |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A0   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A1   & 0xF))) |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_A2   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A3   & 0xF))) |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_A4   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A5   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A6   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A7   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A8   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A9   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A10  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A11  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A12  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A13  & 0xF))) |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_A14  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A15  & 0xF)))
+ },
+ {
+	SCON_SYSPAD1_REG,
+	0 |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_A16  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A17  & 0xF))) |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_A18  & 0xF))) |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_A19  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A20  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A21  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A22  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A23  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A24  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A25  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A26  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A27  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A28  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A29  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A30  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_A31  & 0xF)))
+ },
+ {
+	SCON_SYSPAD2_REG,
+	0 |
+	(SCON_PAD_PULL_DOWN   << (2 * (GPIO_B0   & 0xF))) |
+	(SCON_PAD_PULL_DOWN   << (2 * (GPIO_B1   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B2   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B3   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B4   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B5   & 0xF))) |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_B6   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B7   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B8   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B9   & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B10  & 0xF))) |
+	(SCON_PAD_PLAIN_INPUT << (2 * (GPIO_B11  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B12  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B13  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B14  & 0xF))) |
+	(SCON_PAD_REPEATER    << (2 * (GPIO_B15  & 0xF)))
+ },
+};
+
+/* GPIO def settings to avoid HW issue */
+struct u6_gpio_config u6_gpio_init_config[] = {
+	/* GPIO A bank */
+	{
+		.gpio = GPIO_A5,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A6,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A7,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A8,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A9,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A13,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A17,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A21,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A23,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A24,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 1,
+	},
+	{
+		.gpio = GPIO_A25,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_A30,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	/* GPIO B bank */
+	/* GPIO C bank */
+	/* GPIO D bank */
+	{
+		.gpio = GPIO_D0,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_D24,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_D29,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	/* GPIO E bank */
+	{
+		.gpio = GPIO_E31,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	/* GPIO F bank */
+	{
+		.gpio = GPIO_F0,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_F1,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_F2,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	},
+	{
+		.gpio = GPIO_F9,
+		.dir = GPIO_DIR_OUTPUT,
+		.value = 0,
+	}
+};
+
+u32 gpio_to_configure = ARRAY_SIZE(u6_gpio_init_config);
 
 /* List of board specific devices */
 static struct platform_device *devices[] __initdata = {
@@ -30,6 +497,7 @@ static struct platform_device *devices[] __initdata = {
 
 void __init u67xx_init(void)
 {
+	u6_gpio_init();
 	/* Add specific board devices */
 	platform_add_devices(devices, ARRAY_SIZE(devices));
 }
diff --git a/arch/arm/mach-u67xx/devices.c b/arch/arm/mach-u67xx/devices.c
index 1d00b35..f558fca 100644
--- a/arch/arm/mach-u67xx/devices.c
+++ b/arch/arm/mach-u67xx/devices.c
@@ -11,10 +11,77 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/device.h>
+#include <linux/ioport.h>
 #include <linux/platform_device.h>
+#include <linux/fs.h>
+#include <linux/gpio.h>
+#include <mach/hardware.h>
+#include <mach/scon.h>
+
+/* EXTINT to GPIO mapping */
+unsigned char extint_to_gpio[NR_EXTINT] = {
+	GPIO_A0,  /*extint 0 */
+	GPIO_A1,  /*extint 1 */
+	GPIO_A2,  /*extint 2 */
+	GPIO_A3,  /*extint 3 */
+	GPIO_A4,  /*extint 4 */
+	GPIO_A5,  /*extint 5 */
+	GPIO_A12, /*extint 6 */
+	GPIO_A13, /*extint 7 */
+	GPIO_A14, /*extint 8 */
+	GPIO_A15, /*extint 9 */
+	GPIO_A16, /*extint 10 */
+	GPIO_A17, /*extint 11 */
+	GPIO_D19, /*extint 12 */
+	GPIO_A19, /*extint 13 */
+	GPIO_A20, /*extint 14 */
+	GPIO_B11, /*extint 15 */
+	GPIO_E30, /*extint 16 */
+	GPIO_D15, /*extint 17 */
+	GPIO_D20, /*extint 18 */
+	GPIO_B9,  /*extint 19 */
+	GPIO_B7,  /*extint 20 */
+	GPIO_A25, /*extint 21 */
+	GPIO_D18, /*extint 22 */
+	GPIO_A6   /*extint 23 */
+};
+EXPORT_SYMBOL(extint_to_gpio);
+
+struct gpio_bank u6_gpio_bank[6] = {
+	{GPIOA_PINS_REG, SCON_SYSMUX0_REG},
+	{GPIOB_PINS_REG, SCON_SYSMUX2_REG},
+	{GPIOC_PINS_REG, SCON_SYSMUX4_REG},
+	{GPIOD_PINS_REG, SCON_SYSMUX6_REG},
+	{GPIOE_PINS_REG, SCON_SYSMUX8_REG},
+	{GPIOF_PINS_REG, SCON_SYSMUX10_REG},
+};
+
+static struct gpio_data u6_gpio_data = {
+	ARRAY_SIZE(u6_gpio_bank),	/* nb bank */
+	u6_gpio_bank
+};
+
+static struct resource u6_wavex_gpio_resources[] = {
+	[0] = {
+	       .start = GPIOA_BASE,	/* Physical address */
+	       .end = GPIOA_BASE + SZ_4K - 1,
+	       .flags = IORESOURCE_MEM,
+	       },
+};
+
+static struct platform_device u6_wavex_gpio_device = {
+	.name = "u6-gpio",
+	.id = -1,
+	.dev = {
+		.platform_data = &u6_gpio_data,
+		},
+	.num_resources = ARRAY_SIZE(u6_wavex_gpio_resources),
+	.resource = u6_wavex_gpio_resources,
+};
 
 /* list of devices */
 static struct platform_device *platform_devs[] __initdata = {
+	&u6_wavex_gpio_device,
 };
 
 /* register generic devices */
diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
index afdf82b..3d6898e 100644
--- a/arch/arm/plat-u6xxx/Makefile
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -3,6 +3,6 @@
 #
 
 # Common support
-obj-y := io.o irq.o clock.o
+obj-y := io.o irq.o clock.o gpio.o
 
 obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/gpio.c b/arch/arm/plat-u6xxx/gpio.c
new file mode 100644
index 0000000..b064ee2
--- /dev/null
+++ b/arch/arm/plat-u6xxx/gpio.c
@@ -0,0 +1,665 @@
+/*
+ * linux/arch/arm/plat-u6xxx/gpio.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * Support functions for GPIO
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/gpio.h>
+
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/scon.h>
+
+#define DRV_NAME "u6-gpio"
+
+/*
+ * PN5220 GPIO/MUX registers
+ * defined in asm/arch/registers.h
+ */
+
+#define U6_GPIO_PINS_OFFSET	0
+#define U6_GPIO_OUTPUT_OFFSET	4
+#define U6_GPIO_DIR_OFFSET	8
+
+#define U6_MUX2_OFFSET		4
+
+static struct gpio_bank *gpio_bank_desc;
+static int gpio_bank_count;
+
+static inline struct gpio_bank *get_gpio_bank(int gpio)
+{
+	/* 32 GPIOs per bank */
+	return &(gpio_bank_desc[gpio >> 5]);
+}
+
+static inline int get_gpio_index(int gpio)
+{
+	return gpio & 0x1f;
+}
+
+static int check_gpio(int gpio)
+{
+	int retval = ((unsigned int)gpio) < U6_GPIO_COUNT;
+	WARN(!retval, DRV_NAME": invalid GPIO %d\n", gpio);
+	return retval;
+}
+
+static inline int gpio_is_requested(struct gpio_bank *bank, unsigned long mask)
+{
+	return bank->reserved_map & mask;
+}
+
+static int check_gpio_requested(struct gpio_bank *bank, int index)
+{
+	int retval = gpio_is_requested(bank, 1 << index);
+	if (unlikely(!retval)) {
+		char c = 'A' + (bank - get_gpio_bank(0));
+		printk(KERN_ERR DRV_NAME": GPIO %c%d is not requested yet\n",
+		       c, index);
+		dump_stack();
+	}
+	return retval;
+}
+
+static int check_gpio_unrequested(struct gpio_bank *bank, int index)
+{
+	int retval = !gpio_is_requested(bank, 1 << index);
+	if (unlikely(!retval)) {
+		char c = 'A' + (bank - get_gpio_bank(0));
+		printk(KERN_ERR DRV_NAME": GPIO %c%d is already requested\n",
+		       c, index);
+		dump_stack();
+	}
+	return retval;
+}
+
+static int check_gpio_irq(int gpio_irq)
+{
+	int retval = ((unsigned int)gpio_irq) < NR_EXTINT;
+	if (unlikely(!retval)) {
+		printk(KERN_ERR DRV_NAME": invalid GPIO-IRQ %d\n", gpio_irq);
+		dump_stack();
+	}
+	return retval;
+}
+
+static void _set_gpio_direction(struct gpio_bank *bank, int gpio, int is_input)
+{
+	void __iomem *reg = bank->gpio_base;
+	u32 l;
+
+	/* select direction register */
+	reg += U6_GPIO_DIR_OFFSET;
+
+	/* in register 0 = input, 1 = output */
+	l = readl(reg);
+	if (is_input)
+		l &= ~(1 << gpio);
+	else
+		l |= (1 << gpio);
+	writel(l, reg);
+}
+
+int u6_gpio_set_direction(int gpio, int is_input)
+{
+	unsigned long flags, index;
+	struct gpio_bank *bank;
+
+	if (!check_gpio(gpio))
+		return -EINVAL;
+
+	bank = get_gpio_bank(gpio);
+	index = get_gpio_index(gpio);
+	if (!check_gpio_requested(bank, index))
+		return -EINVAL;
+
+	spin_lock_irqsave(&bank->lock, flags);
+	_set_gpio_direction(bank, index, is_input);
+	spin_unlock_irqrestore(&bank->lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL(u6_gpio_set_direction);
+
+static void _set_gpio_mode(struct gpio_bank *bank, int gpio, int mode)
+{
+	void __iomem *reg = bank->mux_base;
+	unsigned long l;
+
+	/* select direction register */
+	if (gpio >= 16) {
+		reg += U6_MUX2_OFFSET;
+		gpio -= 16;
+	}
+
+	/* apply mux mode */
+	/* width 2 bit */
+	l = readl(reg);
+	l &= ~(3 << (gpio * 2));
+	l |= (mode << (gpio * 2));
+	writel(l, reg);
+}
+
+int u6_gpio_set_mode(int gpio, int mode)
+{
+	struct gpio_bank *bank;
+	int index;
+
+	if (!check_gpio(gpio))
+		return -EINVAL;
+
+	bank = get_gpio_bank(gpio);
+	index = get_gpio_index(gpio);
+	if (!check_gpio_requested(bank, index))
+		return -EINVAL;
+
+	spin_lock(&bank->lock);
+	_set_gpio_mode(bank, get_gpio_index(gpio), mode);
+	spin_unlock(&bank->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(u6_gpio_set_mode);
+
+int u6_gpio_set_mode_gpio(int gpio)
+{
+	int muxmode = gpio >= GPIO_B0 ? GPIO_MODE_MUX1 : GPIO_MODE_MUX0;
+	return u6_gpio_set_mode(gpio, muxmode);
+}
+EXPORT_SYMBOL(u6_gpio_set_mode_gpio);
+
+static void _write_gpio_pin(struct gpio_bank *bank, int gpio, int gpio_value)
+{
+	void __iomem *reg = bank->gpio_base;
+	unsigned long l = 0;
+
+	reg += U6_GPIO_OUTPUT_OFFSET;
+	l = readl(reg);
+	if (gpio_value)
+		l |= 1 << gpio;
+	else
+		l &= ~(1 << gpio);
+	writel(l, reg);
+}
+
+static int u6_gpio_to_extint(int gpio)
+{
+	int extint_idx;
+
+	for (extint_idx = 0; extint_idx < NR_EXTINT; extint_idx++)
+		if (extint_to_gpio[extint_idx] == gpio)
+			return extint_idx;
+
+	return -1;
+}
+
+int u6_gpio_write_pin(int gpio, int gpio_value)
+{
+	struct gpio_bank *bank;
+	unsigned long index;
+
+	if (!check_gpio(gpio))
+		return -EINVAL;
+
+	bank = get_gpio_bank(gpio);
+	index = get_gpio_index(gpio);
+	if (!check_gpio_requested(bank, index))
+		return -EINVAL;
+
+	spin_lock(&bank->lock);
+	_write_gpio_pin(bank, index, gpio_value);
+	spin_unlock(&bank->lock);
+
+	return 0;
+}
+EXPORT_SYMBOL(u6_gpio_write_pin);
+
+int u6_gpio_read_pin(int gpio)
+{
+	struct gpio_bank *bank;
+	void __iomem *reg;
+	u32 l = 0;
+	int irq, index;
+
+	if (!check_gpio(gpio))
+		return -EINVAL;
+
+	bank = get_gpio_bank(gpio);
+	index = get_gpio_index(gpio);
+	if (!check_gpio_requested(bank, index))
+		return -EINVAL;
+
+	/* check if the GPIO is used as extint */
+	irq = u6_gpio_to_extint(gpio);
+	if (irq >= 0) {
+		/* and if it's an alternate internal signal */
+		/* (cf U67xx datasheet table 444) */
+		reg = EXTINT_CFGx(irq);
+		l = readl(reg);
+		if (l & EXTINT_SEL_ALTERNATE) {
+			reg = EXTINT_SIGNAL_REG;
+			return (readl(reg) & (1 << irq)) != 0;
+		}
+	}
+
+	reg = bank->gpio_base;
+	reg += U6_GPIO_PINS_OFFSET;
+	return (readl(reg) & (1 << index)) != 0;
+}
+EXPORT_SYMBOL(u6_gpio_read_pin);
+
+static int _u6_gpio_request(struct gpio_bank *bank, int index)
+{
+	int retval = 0;
+	unsigned long mask = 1 << index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bank->lock, flags);
+	if (unlikely(!check_gpio_unrequested(bank, index)))
+		retval = -EINVAL;
+	else
+		bank->reserved_map |= mask;
+	spin_unlock_irqrestore(&bank->lock, flags);
+
+	return retval;
+}
+
+static int u6_gpio_acquire(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+
+	return _u6_gpio_request(bank, offset);
+}
+
+int u6_gpio_request(int gpio)
+{
+	int index;
+	struct gpio_bank *bank;
+
+	if (!check_gpio(gpio))
+		return -EINVAL;
+
+	index = get_gpio_index(gpio);
+	bank = get_gpio_bank(gpio);
+
+	return _u6_gpio_request(bank, index);
+}
+EXPORT_SYMBOL(u6_gpio_request);
+
+static void _u6_gpio_free(struct gpio_bank *bank, int index)
+{
+	unsigned long mask = 1 << index;
+	unsigned long flags;
+
+	spin_lock_irqsave(&bank->lock, flags);
+	if (likely(check_gpio_requested(bank, index)))
+		bank->reserved_map &= ~mask;
+	spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static void u6_gpio_release(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
+
+	return _u6_gpio_free(bank, offset);
+}
+
+void u6_gpio_free(int gpio)
+{
+	int index;
+	struct gpio_bank *bank;
+
+	if (!check_gpio(gpio))
+		return;
+
+	index = get_gpio_index(gpio);
+	bank = get_gpio_bank(gpio);
+	_u6_gpio_free(bank, index);
+}
+EXPORT_SYMBOL(u6_gpio_free);
+
+/* New GPIO_GENERIC interface */
+
+static int gpio_input(struct gpio_chip *chip, unsigned offset)
+{
+	struct gpio_bank *bank;
+	unsigned long flags;
+
+	bank = container_of(chip, struct gpio_bank, chip);
+	spin_lock_irqsave(&bank->lock, flags);
+	_set_gpio_direction(bank, offset, 1);
+	spin_unlock_irqrestore(&bank->lock, flags);
+	return 0;
+}
+
+static int gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+	return u6_gpio_read_pin(chip->base + offset);
+}
+
+static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct gpio_bank *bank;
+	unsigned long flags;
+
+	bank = container_of(chip, struct gpio_bank, chip);
+	spin_lock_irqsave(&bank->lock, flags);
+	_write_gpio_pin(bank, offset, value);
+	_set_gpio_direction(bank, offset, 0);
+	spin_unlock_irqrestore(&bank->lock, flags);
+	return 0;
+}
+
+static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+	struct gpio_bank *bank;
+	unsigned long flags;
+
+	bank = container_of(chip, struct gpio_bank, chip);
+	spin_lock_irqsave(&bank->lock, flags);
+	_write_gpio_pin(bank, offset, value);
+	spin_unlock_irqrestore(&bank->lock, flags);
+}
+
+static int gpio_2irq(struct gpio_chip *chip, unsigned offset)
+{
+	return u6_gpio_to_extint(chip->base + offset);
+}
+
+/*
+ * U6 EXTINT : only EXTINT 3 is managed by Linux
+ * We need to unmask the GPIO bank interrupt as soon as possible to
+ * avoid missing GPIO interrupts for other lines in the bank.
+ * Then we need to mask-read-clear-unmask the triggered GPIO lines
+ * in the bank to avoid missing nested interrupts for a GPIO line.
+ * If we wait to unmask individual GPIO lines in the bank after the
+ * line's interrupt handler has been run, we may miss some nested
+ * interrupts.
+ */
+static void gpio_irq_handler(unsigned int irq, struct irq_desc *desc)
+{
+	unsigned long isr;
+	unsigned long flags;
+	unsigned int gpio_irq;
+
+	/* LPA TBD */
+	desc->chip->ack(irq);
+
+	/* read status */
+	local_irq_save(flags);
+	isr = readl(EXTINT_STATUS_REG) & readl(EXTINT_ENABLE3_REG);
+	/* clear IRQ source(s) */
+	writel(~isr, EXTINT_STATUS_REG);
+	local_irq_restore(flags);
+
+	gpio_irq = IRQ_COUNT;
+	for (; isr != 0; isr >>= 1, gpio_irq++) {
+		struct irq_desc *d;
+		if (!(isr & 1))
+			continue;
+		d = irq_desc + gpio_irq;
+#ifdef CONFIG_DEBUG_EXTINT
+		printk(KERN_ERR "got something from EXTINT#%i line\n",
+		       gpio_irq - IRQ_COUNT);
+#endif
+		desc_handle_irq(gpio_irq, d);
+	}
+
+}
+
+static void gpio_ack_irq(unsigned int irq)
+{
+	unsigned int gpio_irq = irq - IRQ_COUNT;
+	writel(~(1 << gpio_irq), EXTINT_STATUS_REG);
+}
+
+static void gpio_mask_irq(unsigned int irq)
+{
+	unsigned int gpio_irq = irq - IRQ_COUNT;
+	writel(readl(EXTINT_ENABLE3_REG) & ~(1 << gpio_irq),
+		     EXTINT_ENABLE3_REG);
+}
+
+static void gpio_unmask_irq(unsigned int irq)
+{
+	unsigned int gpio_irq = irq - IRQ_COUNT;
+	writel(readl(EXTINT_ENABLE3_REG) | (1 << gpio_irq),
+		     EXTINT_ENABLE3_REG);
+}
+
+int u6_gpio_clear_irq(unsigned int irq)
+{
+	unsigned int gpio_irq;
+	gpio_irq = irq - IRQ_COUNT;
+	if (!check_gpio_irq(gpio_irq))
+		return -EINVAL;
+	writel(~(1 << gpio_irq), EXTINT_STATUS_REG);
+	return 0;
+}
+EXPORT_SYMBOL(u6_gpio_clear_irq);
+
+int u6_gpio_set_irq_debounce(int irq, int cycles)
+{
+	int gpio;
+	struct gpio_bank *bank;
+	void __iomem *reg;
+	int mode;
+	u32 l = 0;
+
+	gpio = EXTINT_TO_GPIO(irq);
+	irq -= IRQ_COUNT;
+	if (!check_gpio_irq(irq))
+		goto err;
+
+	bank = get_gpio_bank(gpio);
+	if (!check_gpio_requested(bank, get_gpio_index(gpio)))
+		return -EINVAL;
+
+	reg = EXTINT_CFGx(irq);
+	l = readl(reg);
+
+	mode = l & (3 << EXTINT_MODE_SHIFT);
+	if (mode == EXTINT_MODE_BYPASS)
+		goto err;
+
+	/* clear mode and set streching to debounce */
+	if (mode == EXTINT_MODE_STRETCHING) {
+		l &= ~(3 << EXTINT_MODE_SHIFT);
+		l |= EXTINT_MODE_DEBOUNCE;
+	}
+	/* clear and set the debounce field */
+	l &= ~(7 << EXTINT_DEBOUNCE_SHIFT);
+	l |= ((cycles & 0x7) << EXTINT_DEBOUNCE_SHIFT);
+	writel(l, reg);
+
+	return 0;
+err:
+	return -EINVAL;
+}
+EXPORT_SYMBOL(u6_gpio_set_irq_debounce);
+
+int u6_gpio_set_irq_selection(int irq, int selection)
+{
+	int gpio, index;
+	struct gpio_bank *bank;
+	u32 l = 0;
+	void __iomem *reg;
+
+	gpio = EXTINT_TO_GPIO(irq);
+	irq -= IRQ_COUNT;
+	if (!check_gpio_irq(irq))
+		return -EINVAL;
+
+	bank = get_gpio_bank(gpio);
+	index = get_gpio_index(gpio);
+	if (!check_gpio_requested(bank, index))
+		return -EINVAL;
+
+	reg = EXTINT_CFGx(irq);
+	l = readl(reg);
+
+	if (selection == EXTINT_SEL_ALTERNATE)
+		l |= EXTINT_SEL_ALTERNATE;
+	else
+		l &= ~EXTINT_SEL_ALTERNATE;
+	writel(l, reg);
+
+	return 0;
+}
+EXPORT_SYMBOL(u6_gpio_set_irq_selection);
+
+/*
+ * -the level type set the bypass mode
+ * -and by default the edge type select the stretching mode.
+ * if you would a debounce you must defined your nb
+ * cycle with u6_set_gpio_debounce
+ */
+static int _set_gpio_triggering(int gpio_irq, int trigger)
+{
+	void __iomem *reg = EXTINT_CFGx(gpio_irq);
+	u32 l = 0;
+
+	l = readl(reg);
+	l &= ~(3 << 6 | 1 << 2);
+
+	if (trigger == IRQ_TYPE_LEVEL_LOW)
+		l |= EXTINT_POL_NEGATIVE;
+	else if (trigger == IRQ_TYPE_LEVEL_HIGH)
+		l |= EXTINT_POL_POSITIVE;
+	else if (trigger == IRQ_TYPE_EDGE_RISING)
+		l |= (EXTINT_MODE_STRETCHING | EXTINT_POL_POSITIVE);
+	else if (trigger == IRQ_TYPE_EDGE_FALLING)
+		l |= (EXTINT_MODE_STRETCHING | EXTINT_POL_NEGATIVE);
+	else if (trigger == IRQ_TYPE_EDGE_BOTH)
+		l |= EXTINT_MODE_DUAL_EDGE;
+	else
+		goto err;
+
+	writel(l, reg);
+
+	return 0;
+err:
+	return -EINVAL;
+}
+
+static int gpio_irq_type(unsigned irq, unsigned type)
+{
+	unsigned gpio_irq;
+	int retval;
+
+	gpio_irq = irq - IRQ_COUNT;
+
+	if (!check_gpio_irq(gpio_irq))
+		return -EINVAL;
+
+	if (type & (IRQF_TRIGGER_PROBE))
+		return -EINVAL;
+
+	retval = _set_gpio_triggering(gpio_irq, type);
+	return retval;
+}
+
+static struct irq_chip gpio_irq_chip = {
+	.ack = gpio_ack_irq,
+	.disable = gpio_mask_irq,
+	.enable = gpio_unmask_irq,
+	.mask = gpio_mask_irq,
+	.unmask = gpio_unmask_irq,
+	.set_type = gpio_irq_type,
+	/*.set_wake     = gpio_wake_enable, */
+};
+
+static int __devinit u6_gpio_probe(struct platform_device *pdev)
+{
+	int i, j;
+	int gpio = 0;
+	struct gpio_bank *bank;
+	struct gpio_data *data = pdev->dev.platform_data;
+	unsigned long flags;
+
+	printk(KERN_INFO "U6 GPIO\n");
+	gpio_bank_desc = data->gpio_bank_desc;
+	gpio_bank_count = data->nb_banks;
+
+	for (i = 0; i < gpio_bank_count; i++) {
+		int gpio_count = 32;	/* 32 GPIO per bank */
+		bank = &gpio_bank_desc[i];
+		bank->reserved_map = 0;
+		spin_lock_init(&bank->lock);
+
+		bank->chip.request = u6_gpio_acquire;
+		bank->chip.free = u6_gpio_release;
+		bank->chip.direction_input = gpio_input;
+		bank->chip.get = gpio_get;
+		bank->chip.direction_output = gpio_output;
+		bank->chip.set = gpio_set;
+		bank->chip.to_irq = gpio_2irq;
+		bank->chip.label = "gpio";
+		bank->chip.base = gpio;
+		gpio += gpio_count;
+
+		bank->chip.ngpio = gpio_count;
+
+		gpiochip_add(&bank->chip);
+
+	}
+
+	/* configure MUX and PAD settings */
+	for (i = 0; i < SCON_REGISTER_NB; i++)
+		writel(u6_scon_init_config[i].scon_reg_value,
+			     u6_scon_init_config[i].scon_reg_addr);
+
+	/* for extint */
+	for (j = IRQ_COUNT; j < IRQ_COUNT + NR_EXTINT; j++) {
+		set_irq_chip(j, &gpio_irq_chip);
+		set_irq_handler(j, handle_simple_irq);
+		set_irq_flags(j, IRQF_VALID);
+	}
+
+	local_irq_save(flags);
+	/* mask all EXT IRQ sources before registring handler */
+	/* read status */
+	j = readl(EXTINT_STATUS_REG) & readl(EXTINT_ENABLE3_REG);
+	/* clear IRQ source(s) */
+	writel(j, EXTINT_STATUS_REG);
+
+	writel(0, EXTINT_ENABLE3_REG);
+
+	/* set irq in low level */
+	set_irq_type(IRQ_EXTINT3, IRQF_TRIGGER_LOW);
+
+	/* chained GPIO-IRQ on EXTINT3 */
+	set_irq_chained_handler(IRQ_EXTINT3, gpio_irq_handler);
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static struct platform_driver u6_gpio_driver = {
+	.probe = u6_gpio_probe,
+	.driver = {
+		.name = DRV_NAME,
+	},
+};
+
+int __init u6_gpio_init(void)
+{
+	return platform_driver_register(&u6_gpio_driver);
+}
diff --git a/arch/arm/plat-u6xxx/include/mach/gpio.h b/arch/arm/plat-u6xxx/include/mach/gpio.h
new file mode 100644
index 0000000..72e8147
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/gpio.h
@@ -0,0 +1,391 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/gpio.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * GPIO handling defines and functions
+ */
+
+#ifndef __ASM_PLAT_U6_GPIO_H
+#define __ASM_PLAT_U6_GPIO_H
+
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <asm-generic/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+
+/* GPIO bank description */
+struct gpio_bank {
+	void __iomem *gpio_base;
+	void __iomem *mux_base;
+	u16 irq;
+	u16 virtual_irq_start;
+	int method;
+	u32 reserved_map;
+	u32 suspend_wakeup;
+	u32 saved_wakeup;
+	spinlock_t lock;
+	struct gpio_chip chip;
+};
+
+
+struct gpio_data {
+	u32 nb_banks;
+	struct gpio_bank *gpio_bank_desc;
+};
+
+
+/* GPIO Init configuration */
+
+struct u6_gpio_config {
+	u32 gpio;
+	u32 dir;
+	u32 value;
+};
+
+
+/* list of GPIO */
+enum U6_GPIO_LIST {
+	GPIO_A0 = 0,
+	GPIO_A1,
+	GPIO_A2,
+	GPIO_A3,
+	GPIO_A4,
+	GPIO_A5,
+	GPIO_A6,
+	GPIO_A7,
+	GPIO_A8,
+	GPIO_A9,
+	GPIO_A10,
+	GPIO_A11,
+	GPIO_A12,
+	GPIO_A13,
+	GPIO_A14,
+	GPIO_A15,
+	GPIO_A16,
+	GPIO_A17,
+	GPIO_A18,
+	GPIO_A19,
+	GPIO_A20,
+	GPIO_A21,
+	GPIO_A22,
+	GPIO_A23,
+	GPIO_A24,
+	GPIO_A25,
+	GPIO_A26,
+	GPIO_A27,
+	GPIO_A28,
+	GPIO_A29,
+	GPIO_A30,
+	GPIO_A31,
+	GPIO_B0,
+	GPIO_B1,
+	GPIO_B2,
+	GPIO_B3,
+	GPIO_B4,
+	GPIO_B5,
+	GPIO_B6,
+	GPIO_B7,
+	GPIO_B8,
+	GPIO_B9,
+	GPIO_B10,
+	GPIO_B11,
+	GPIO_B12,
+	GPIO_B13,
+	GPIO_B14,
+	GPIO_B15,
+	GPIO_B16,
+	GPIO_B17,
+	GPIO_B18,
+	GPIO_B19,
+	GPIO_B20,
+	GPIO_B21,
+	GPIO_B22,
+	GPIO_B23,
+	GPIO_B24,
+	GPIO_B25,
+	GPIO_B26,
+	GPIO_B27,
+	GPIO_B28,
+	GPIO_B29,
+	GPIO_B30,
+	GPIO_B31,
+	GPIO_C0,
+	GPIO_C1,
+	GPIO_C2,
+	GPIO_C3,
+	GPIO_C4,
+	GPIO_C5,
+	GPIO_C6,
+	GPIO_C7,
+	GPIO_C8,
+	GPIO_C9,
+	GPIO_C10,
+	GPIO_C11,
+	GPIO_C12,
+	GPIO_C13,
+	GPIO_C14,
+	GPIO_C15,
+	GPIO_C16,
+	GPIO_C17,
+	GPIO_C18,
+	GPIO_C19,
+	GPIO_C20,
+	GPIO_C21,
+	GPIO_C22,
+	GPIO_C23,
+	GPIO_C24,
+	GPIO_C25,
+	GPIO_C26,
+	GPIO_C27,
+	GPIO_C28,
+	GPIO_C29,
+	GPIO_C30,
+	GPIO_C31,
+	GPIO_D0,
+	GPIO_D1,
+	GPIO_D2,
+	GPIO_D3,
+	GPIO_D4,
+	GPIO_D5,
+	GPIO_D6,
+	GPIO_D7,
+	GPIO_D8,
+	GPIO_D9,
+	GPIO_D10,
+	GPIO_D11,
+	GPIO_D12,
+	GPIO_D13,
+	GPIO_D14,
+	GPIO_D15,
+	GPIO_D16,
+	GPIO_D17,
+	GPIO_D18,
+	GPIO_D19,
+	GPIO_D20,
+	GPIO_D21,
+	GPIO_D22,
+	GPIO_D23,
+	GPIO_D24,
+	GPIO_D25,
+	GPIO_D26,
+	GPIO_D27,
+	GPIO_D28,
+	GPIO_D29,
+	GPIO_D30,
+	GPIO_D31,
+	GPIO_E0,
+	GPIO_E1,
+	GPIO_E2,
+	GPIO_E3,
+	GPIO_E4,
+	GPIO_E5,
+	GPIO_E6,
+	GPIO_E7,
+	GPIO_E8,
+	GPIO_E9,
+	GPIO_E10,
+	GPIO_E11,
+	GPIO_E12,
+	GPIO_E13,
+	GPIO_E14,
+	GPIO_E15,
+	GPIO_E16,
+	GPIO_E17,
+	GPIO_E18,
+	GPIO_E19,
+	GPIO_E20,
+	GPIO_E21,
+	GPIO_E22,
+	GPIO_E23,
+	GPIO_E24,
+	GPIO_E25,
+	GPIO_E26,
+	GPIO_E27,
+	GPIO_E28,
+	GPIO_E29,
+	GPIO_E30,
+	GPIO_E31,
+	GPIO_F0,
+	GPIO_F1,
+	GPIO_F2,
+	GPIO_F3,
+	GPIO_F4,
+	GPIO_F5,
+	GPIO_F6,
+	GPIO_F7,
+	GPIO_F8,
+	GPIO_F9,
+	GPIO_F10,
+	GPIO_F11,
+	GPIO_F12,
+	GPIO_F13,
+	GPIO_F14,
+	GPIO_F15,
+	GPIO_F16,
+	GPIO_F17,
+	GPIO_F18,
+	GPIO_F19,
+	GPIO_F20,
+	GPIO_F21,
+	GPIO_F22,
+	GPIO_F23,
+	GPIO_F24,
+	GPIO_F25,
+	GPIO_F26,
+	GPIO_F27,
+	GPIO_F28,
+	GPIO_F29,
+	GPIO_F30,
+	GPIO_F31,
+	U6_GPIO_COUNT,
+};
+
+enum U6_GPIO_MODE {
+	GPIO_MODE_MUX0 = 0,
+	GPIO_MODE_MUX1,
+	GPIO_MODE_MUX2,
+	GPIO_MODE_MUX3
+};
+
+
+#define GPIO_DIR_INPUT  1
+#define GPIO_DIR_OUTPUT 0
+
+
+extern int  u6_gpio_init(void);	/* Call from board init only */
+extern int  u6_gpio_request(int gpio);
+extern void u6_gpio_free(int gpio);
+extern int  u6_gpio_set_mode(int gpio, int mode);
+extern int  u6_gpio_set_mode_gpio(int gpio);
+extern int  u6_gpio_set_direction(int gpio, int is_input);
+extern int  u6_gpio_write_pin(int gpio, int gpio_value);
+extern int  u6_gpio_read_pin(int gpio);
+extern int  u6_gpio_set_irq_debounce(int irq, int cycles);
+extern int  u6_gpio_set_irq_selection(int irq, int selection);
+extern int  u6_gpio_clear_irq(unsigned int irq);
+
+
+/*
+ * Wrappers for "new style" GPIO calls, using the new infrastructure
+ * which lets us plug in FPGA, I2C, and other implementations.
+ */
+
+static inline int gpio_get_value(unsigned gpio)
+{
+	return __gpio_get_value(gpio);
+}
+
+static inline void gpio_set_value(unsigned gpio, int value)
+{
+	__gpio_set_value(gpio, value);
+}
+
+static inline int gpio_cansleep(unsigned gpio)
+{
+	return __gpio_cansleep(gpio);
+}
+
+static inline int gpio_to_irq(unsigned gpio)
+{
+	return __gpio_to_irq(gpio);
+}
+
+static inline int irq_to_gpio(unsigned irq)
+{
+	return EXTINT_TO_GPIO(irq);
+}
+
+/*
+* Hardware Register Definitions for EXTINT
+ */
+
+/* EXTINT ENABLE1 Register (32 bits) */
+#define EXTINT_ENABLE1_OFFSET  0x60
+#define EXTINT_ENABLE1_REG     U6_IO_ADDRESS(EXTINT_BASE + EXTINT_ENABLE1_OFFSET)
+
+/* EXTINT ENABLE2 Register (32 bits) */
+#define EXTINT_ENABLE2_OFFSET  0x64
+#define EXTINT_ENABLE2_REG     U6_IO_ADDRESS(EXTINT_BASE + EXTINT_ENABLE2_OFFSET)
+
+/* EXTINT ENABLE3 Register (32 bits) */
+#define EXTINT_ENABLE3_OFFSET  0x68
+#define EXTINT_ENABLE3_REG     U6_IO_ADDRESS(EXTINT_BASE + EXTINT_ENABLE3_OFFSET)
+
+/* EXTINT STATUS Register (32 bits) */
+#define EXTINT_STATUS_OFFSET   0x6C
+#define EXTINT_STATUS_REG      U6_IO_ADDRESS(EXTINT_BASE + EXTINT_STATUS_OFFSET)
+
+/* EXTINT SIGNAL Register (32 bits) */
+#define EXTINT_SIGNAL_OFFSET   0x70
+#define EXTINT_SIGNAL_REG      U6_IO_ADDRESS(EXTINT_BASE + EXTINT_SIGNAL_OFFSET)
+
+/* Bits definition for register EXTINT_CFG[23:0] */
+#define EXTINT_MODE_SHIFT      6
+#define EXTINT_MODE_FIELD      (0xFFFFFFFF - (0x3UL<<EXTINT_MODE_SHIFT))
+#define EXTINT_MODE_BYPASS     (0x0UL<<EXTINT_MODE_SHIFT)
+#define EXTINT_MODE_STRETCHING (0x1UL<<EXTINT_MODE_SHIFT)
+#define EXTINT_MODE_DEBOUNCE   (0x2UL<<EXTINT_MODE_SHIFT)
+#define EXTINT_MODE_DUAL_EDGE  (0x3UL<<EXTINT_MODE_SHIFT)
+#define EXTINT_DEBOUNCE_SHIFT  3
+#define EXTINT_DEBOUNCE_FIELD  (0xFFFFFFFF - (0x7UL<<EXTINT_DEBOUNCE_SHIFT))
+#define EXTINT_DEBOUNCE_0      (0x0UL<<EXTINT_DEBOUNCE_SHIFT)
+#define EXTINT_DEBOUNCE_1      (0x1UL<<EXTINT_DEBOUNCE_SHIFT)
+#define EXTINT_DEBOUNCE_2      (0x2UL<<EXTINT_DEBOUNCE_SHIFT)
+#define EXTINT_DEBOUNCE_3      (0x3UL<<EXTINT_DEBOUNCE_SHIFT)
+#define EXTINT_DEBOUNCE_7      (0x7UL<<EXTINT_DEBOUNCE_SHIFT)
+#define EXTINT_POL_SHIFT       2
+#define EXTINT_POL_FIELD       (0xFFFFFFFF - (0x1UL<<EXTINT_POL_SHIFT))
+#define EXTINT_POL_NEGATIVE    (0x0UL<<EXTINT_POL_SHIFT)
+#define EXTINT_POL_POSITIVE    (0x1UL<<EXTINT_POL_SHIFT)
+#define EXTINT_POL             (0x1UL<<EXTINT_POL_SHIFT)
+#define EXTINT_SEL_SHIFT       1
+#define EXTINT_SEL_FIELD       (0xFFFFFFFF - (0x1UL<<EXTINT_SEL_SHIFT))
+#define EXTINT_SEL_EXTINT      (0x0UL<<EXTINT_SEL_SHIFT)
+#define EXTINT_SEL_ALTERNATE   (0x1UL<<EXTINT_SEL_SHIFT)
+#define EXTINT_SEL             (0x1UL<<EXTINT_SEL_SHIFT)
+
+/*****************************************************************************/
+/* Register description for ENABLE[3:1] */
+
+/* Bits definition for register EXTINT_ENABLE[3:1] */
+#define EXTINT_ENABLE_SHIFT    0
+#define EXTINT_ENABLE_FIELD    (0xFFFFFFFF - (0xFFFFFFUL<<EXTINT_ENABLE_SHIFT))
+#define EXTINT_ENABLE_0        (0x0UL<<EXTINT_ENABLE_SHIFT)
+#define EXTINT_ENABLE_1        (0x1UL<<EXTINT_ENABLE_SHIFT)
+
+/*****************************************************************************/
+/* Register description for STATUS */
+
+/* Bits definition for register EXTINT_STATUS */
+#define EXTINT_STATUS_SHIFT    0
+#define EXTINT_STATUS_FIELD    (0xFFFFFFFF - (0xFFFFFFUL<<EXTINT_STATUS_SHIFT))
+#define EXTINT_STATUS_0        (0x0UL<<EXTINT_STATUS_SHIFT)
+#define EXTINT_STATUS_1        (0x1UL<<EXTINT_STATUS_SHIFT)
+
+/* EXTINTx [0..23] configuration register */
+#define EXTINT_CFGx(x)         U6_IO_ADDRESS(EXTINT_BASE+(x)*4)
+
+/*****************************************************************************
+* Hardware Register Definitions for GPIOx
+*****************************************************************************/
+/* Offsets */
+#define GPIO_PINS_OFFSET       0x0
+#define GPIO_OR_OFFSET         0x4
+#define GPIO_DR_OFFSET         0x8
+
+/* GPIOx PINS Registers (32 bits) */
+#define GPIOA_PINS_REG         U6_IO_ADDRESS(GPIOA_BASE + GPIO_PINS_OFFSET)
+#define GPIOB_PINS_REG         U6_IO_ADDRESS(GPIOB_BASE + GPIO_PINS_OFFSET)
+#define GPIOC_PINS_REG         U6_IO_ADDRESS(GPIOC_BASE + GPIO_PINS_OFFSET)
+#define GPIOD_PINS_REG         U6_IO_ADDRESS(GPIOD_BASE + GPIO_PINS_OFFSET)
+#define GPIOE_PINS_REG         U6_IO_ADDRESS(GPIOE_BASE + GPIO_PINS_OFFSET)
+#define GPIOF_PINS_REG         U6_IO_ADDRESS(GPIOF_BASE + GPIO_PINS_OFFSET)
+
+/* GPIOx OR Registers (32 bits) */
+#define GPIOA_OR_REG           U6_IO_ADDRESS(GPIOC_BASE + GPIO_OR_OFFSET)
+
+#endif
diff --git a/arch/arm/plat-u6xxx/include/mach/scon.h b/arch/arm/plat-u6xxx/include/mach/scon.h
new file mode 100644
index 0000000..180aeeb
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/scon.h
@@ -0,0 +1,123 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/scon.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Loic Pallardy <loic.pallardy@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ *
+ * System Configuration Block registers
+ */
+
+#ifndef __ARCH_SCON_H
+#define __ARCH_SCON_H
+
+/*
+ * this structure allows to store SCON register values to set
+ * during initialization step
+ */
+
+struct u6_scon_config {
+	void __iomem *scon_reg_addr;
+	u32 scon_reg_value;
+};
+
+#define SCON_REGISTER_NB         15
+
+extern struct u6_scon_config u6_scon_init_config[SCON_REGISTER_NB];
+
+/* SCON SYSVER Register (32 bits) */
+#define SCON_SYSVER_OFFSET       0x0
+#define SCON_SYSVER_REG          U6_IO_ADDRESS(SCON_BASE + SCON_SYSVER_OFFSET)
+
+/* SCON SYSCON0 Register (32 bits) */
+#define SCON_SYSCON0_OFFSET      0x4
+#define SCON_SYSCON0_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSCON0_OFFSET)
+
+/* SCON SYSPROT Register (32 bits) */
+#define SCON_SYSPROT_OFFSET      0x8
+#define SCON_SYSPROT_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSPROT_OFFSET)
+
+/* SCON SYSMUX0 Register (32 bits) */
+#define SCON_SYSMUX0_OFFSET      0xC
+#define SCON_SYSMUX0_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX0_OFFSET)
+
+/* SCON SYSMUX1 Register (32 bits) */
+#define SCON_SYSMUX1_OFFSET      0x10
+#define SCON_SYSMUX1_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX1_OFFSET)
+
+/* SCON SYSMUX2 Register (32 bits) */
+#define SCON_SYSMUX2_OFFSET      0x14
+#define SCON_SYSMUX2_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX2_OFFSET)
+
+/* SCON SYSMUX3 Register (32 bits) */
+#define SCON_SYSMUX3_OFFSET      0x18
+#define SCON_SYSMUX3_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX3_OFFSET)
+
+/* SCON SYSMUX4 Register (32 bits) */
+#define SCON_SYSMUX4_OFFSET      0x1C
+#define SCON_SYSMUX4_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX4_OFFSET)
+
+/* SCON SYSMUX5 Register (32 bits) */
+#define SCON_SYSMUX5_OFFSET      0x20
+#define SCON_SYSMUX5_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX5_OFFSET)
+
+/* SCON SYSMUX6 Register (32 bits) */
+#define SCON_SYSMUX6_OFFSET      0x24
+#define SCON_SYSMUX6_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX6_OFFSET)
+
+/* SCON SYSMUX7 Register (32 bits) */
+#define SCON_SYSMUX7_OFFSET      0x28
+#define SCON_SYSMUX7_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX7_OFFSET)
+
+/* SCON SYSMUX8 Register (32 bits) */
+#define SCON_SYSMUX8_OFFSET      0x2C
+#define SCON_SYSMUX8_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX8_OFFSET)
+
+/* SCON SYSMUX9 Register (32 bits) */
+#define SCON_SYSMUX9_OFFSET      0x30
+#define SCON_SYSMUX9_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX9_OFFSET)
+
+/* SCON SYSMUX10 Register (32 bits) */
+#define SCON_SYSMUX10_OFFSET     0x34
+#define SCON_SYSMUX10_REG        U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX10_OFFSET)
+
+/* SCON SYSMUX11 Register (32 bits) */
+#define SCON_SYSMUX11_OFFSET     0x38
+#define SCON_SYSMUX11_REG        U6_IO_ADDRESS(SCON_BASE + SCON_SYSMUX11_OFFSET)
+
+/* SCON SYSPAD0 Register (32 bits) */
+#define SCON_SYSPAD0_OFFSET      0x50
+#define SCON_SYSPAD0_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSPAD0_OFFSET)
+
+/* SCON SYSPAD1 Register (32 bits) */
+#define SCON_SYSPAD1_OFFSET      0x54
+#define SCON_SYSPAD1_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSPAD1_OFFSET)
+
+/* SCON SYSPAD2 Register (32 bits) */
+#define SCON_SYSPAD2_OFFSET      0x58
+#define SCON_SYSPAD2_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSPAD2_OFFSET)
+
+/* SCON SYSCON1 Register (32 bits) */
+#define SCON_SYSCON1_OFFSET      0x70
+#define SCON_SYSCON1_REG         U6_IO_ADDRESS(SCON_BASE + SCON_SYSCON1_OFFSET)
+
+/* SCON SYSIISMUX Register (32 bits) */
+#define SCON_SYSIISMUX_OFFSET    0x74
+#define SCON_SYSIISMUX_REG       U6_IO_ADDRESS(SCON_BASE + SCON_SYSIISMUX_OFFSET)
+
+/* SCON SYSAHBPROT Register (32 bits) */
+#define SCON_SYSAHBPROT_OFFSET   0x78
+#define SCON_SYSAHBPROT_REG      U6_IO_ADDRESS(SCON_BASE + SCON_SYSAHBPROT_OFFSET)
+
+/* SCON SYSIVSBRIDGE Register (32 bits) */
+#define SCON_SYSIVSBRIDGE_OFFSET 0x7C
+#define SCON_SYSIVSBRIDGE_REG   U6_IO_ADDRESS(SCON_BASE + SCON_SYSIVSBRIDGE_OFFSET)
+
+/* Register description for SYSPADx */
+/* SYSPAD configuration defines */
+#define SCON_PAD_PULL_UP        0
+#define SCON_PAD_REPEATER       1
+#define SCON_PAD_PLAIN_INPUT    2
+#define SCON_PAD_PULL_DOWN      3
+
+#endif
-- 
1.7.1

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

* [PATCH 4/5] U6715 platform serial driver It's a generic driver for all U6XXX platform
  2010-08-05 12:28 ` Philippe Langlais
                   ` (3 preceding siblings ...)
  (?)
@ 2010-08-05 12:28 ` Philippe Langlais
  -1 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-arm-kernel

Clock specificity:
  It's parent clock depend on baud rate.
  The UART port can be used before u6xxx clock framework initialization

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 arch/arm/plat-u6xxx/Makefile              |    2 +-
 arch/arm/plat-u6xxx/include/mach/serial.h |   23 +++
 arch/arm/plat-u6xxx/serial.c              |  268 +++++++++++++++++++++++++++++
 3 files changed, 292 insertions(+), 1 deletions(-)
 create mode 100644 arch/arm/plat-u6xxx/include/mach/serial.h
 create mode 100644 arch/arm/plat-u6xxx/serial.c

diff --git a/arch/arm/plat-u6xxx/Makefile b/arch/arm/plat-u6xxx/Makefile
index 3d6898e..f12068c 100644
--- a/arch/arm/plat-u6xxx/Makefile
+++ b/arch/arm/plat-u6xxx/Makefile
@@ -3,6 +3,6 @@
 #
 
 # Common support
-obj-y := io.o irq.o clock.o gpio.o
+obj-y := io.o irq.o clock.o gpio.o serial.o
 
 obj-$(CONFIG_U6_MTU_TIMER) += timer.o
diff --git a/arch/arm/plat-u6xxx/include/mach/serial.h b/arch/arm/plat-u6xxx/include/mach/serial.h
new file mode 100644
index 0000000..321e406
--- /dev/null
+++ b/arch/arm/plat-u6xxx/include/mach/serial.h
@@ -0,0 +1,23 @@
+/*
+ * linux/arch/arm/plat-u6xxx/include/mach/serial.h
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Author: Ludovic Barre <ludovic.barre@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+
+#ifndef __SERIAL_H
+#define __SERIAL_H
+
+#include <linux/clk.h>
+
+struct u6_uart {
+	struct clk *uartClk;
+	char   uart_name[7];
+};
+
+extern unsigned int u6_serial8250_enable_clock(struct uart_port *port);
+extern unsigned int u6_serial8250_disable_clock(struct uart_port *port);
+
+#endif   /* __SERIAL_H */
diff --git a/arch/arm/plat-u6xxx/serial.c b/arch/arm/plat-u6xxx/serial.c
new file mode 100644
index 0000000..85dbbb6
--- /dev/null
+++ b/arch/arm/plat-u6xxx/serial.c
@@ -0,0 +1,268 @@
+/*
+ * linux/arch/arm/plat-u6xxx/serial.c
+ *
+ * Copyright (C) ST-Ericsson SA 2010
+ * Authors: Ludovic Barre <ludovic.barre@stericsson.com> for ST-Ericsson.
+ *         Philippe Langlais <philippe.langlais@stericsson.com> for ST-Ericsson.
+ * License terms:  GNU General Public License (GPL), version 2
+ * U6 cpu type detection
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/serial_8250.h>
+#include <linux/slab.h>
+
+#include <mach/hardware.h>
+#include <mach/serial.h>
+#include <mach/clock.h>
+
+#define U6_MAX_BAUDRATE 3250000  /* 3.25MBds is the maximum baudrate supported */
+#define BASE_BAUD	7372800
+
+/* Register description for FDIV_CTRL */
+/* UART FDIV_CTRL Register (8 bits) */
+#define UARTX_FDIV_CTRL_OFFSET         0xC00
+/* UART FDIV_M Register (16 bits) */
+#define UARTX_FDIV_M_OFFSET            0xC04
+/* UART FDIV_N Register (16 bits) */
+#define UARTX_FDIV_N_OFFSET            0xC08
+
+/* Bits definition for register UARTX_FDIV_CTRL */
+#define UARTX_FDIV_ENABLE_SHIFT  7
+#define UARTX_FDIV_ENABLE_FIELD  (0xFFFFFFFF - (0x1UL<<UARTX_FDIV_ENABLE_SHIFT))
+#define UARTX_FDIV_ENABLE_OFF    (0x0UL<<UARTX_FDIV_ENABLE_SHIFT)
+#define UARTX_FDIV_ENABLE_ON     (0x1UL<<UARTX_FDIV_ENABLE_SHIFT)
+#define UARTX_FDIV_ENABLE        (0x1UL<<UARTX_FDIV_ENABLE_SHIFT)
+#define UARTX_CLKSEL_SHIFT       0
+#define UARTX_CLKSEL_FIELD       (0xFFFFFFFF - (0x3UL<<UARTX_CLKSEL_SHIFT))
+#define UARTX_CLKSEL_PCLK        (0x0UL<<UARTX_CLKSEL_SHIFT)
+#define UARTX_CLKSEL_13M         (0x1UL<<UARTX_CLKSEL_SHIFT)
+#define UARTX_CLKSEL_26M         (0x2UL<<UARTX_CLKSEL_SHIFT)
+#define UARTX_CLKSEL_3           (0x3UL<<UARTX_CLKSEL_SHIFT)
+
+/*
+ * console and pctools has needed to start before serial_init
+ * (without cgu interface)
+ */
+static int uart_enable_clock(struct uart_port *port)
+{
+	u32 v;
+	v = readl(CGU_GATESC1_REG);
+
+	if (port->irq == IRQ_UART1)
+		v |= CGU_UART1EN_1;
+	else if (port->irq == IRQ_UART2)
+		v |= CGU_UART2EN_1;
+
+	writel(v, CGU_GATESC1_REG);
+
+	return 0;
+}
+
+static int uart_disable_clock(struct uart_port *port)
+{
+	u32 v;
+	v = readl(CGU_GATESC1_REG);
+
+	if (port->irq == IRQ_UART1)
+		v &= ~CGU_UART1EN_0;
+	else if (port->irq == IRQ_UART2)
+		v &= ~CGU_UART2EN_0;
+
+	writel(v, CGU_GATESC1_REG);
+
+	return 0;
+}
+
+unsigned int u6_serial8250_enable_clock(struct uart_port *port)
+{
+	struct u6_uart *uart_u6 = port->private_data;
+
+	if (!uart_u6)
+		return uart_enable_clock(port);
+
+	if (IS_ERR(uart_u6->uartClk)) {
+		pr_warning("%s - uart clock failed error:%ld\n",
+		       __func__, PTR_ERR(uart_u6->uartClk));
+		return PTR_ERR(uart_u6->uartClk);
+	}
+
+	clk_enable(uart_u6->uartClk);
+
+	return 0;
+}
+
+unsigned int u6_serial8250_disable_clock(struct uart_port *port)
+{
+	struct u6_uart *uart_u6 = port->private_data;
+
+	if (!uart_u6)
+		return uart_disable_clock(port);
+
+	if (IS_ERR(uart_u6->uartClk)) {
+		pr_warning("%s - uart clk error :%ld\n", __func__,
+		       PTR_ERR(uart_u6->uartClk));
+		return PTR_ERR(uart_u6->uartClk);
+	}
+	clk_disable(uart_u6->uartClk);
+
+	return 0;
+}
+
+static unsigned int u6_get_setdiv_clock(struct uart_port *port,
+					 unsigned int baud)
+{
+	unsigned int uartclk;
+	u32 fdiv_m = 0x5F37;
+	u32 fdiv_n = 0x3600;
+	u32 fdiv_ctrl = UARTX_FDIV_ENABLE_ON;
+	struct u6_uart *uart_u6 = port->private_data;
+
+	/*  Compute uart clock from baudrate */
+	if (baud > 2000000)
+		uartclk = 52000000;
+	else if (baud > 1843200)
+		uartclk = 32000000;
+	else if (baud > 921600)
+		uartclk = 29491200;
+	else if (baud > 460800)
+		uartclk = 14745600;
+	else
+		uartclk = 7372800;
+
+	/* Set divisors & parent clock accordingly */
+	switch (uartclk) {
+	case 7372800: /* clk=13MHz */
+		fdiv_ctrl |= UARTX_CLKSEL_13M;
+		break;
+	case 14745600: /* clk=26MHz */
+		fdiv_ctrl |= UARTX_CLKSEL_26M;
+		break;
+	case 29491200: /* clk=pclk */
+		fdiv_ctrl |= UARTX_CLKSEL_PCLK;
+		break;
+	case 32000000: /* clk=pclk */
+		fdiv_n = 0x3A98;
+		fdiv_ctrl |= UARTX_CLKSEL_PCLK;
+		break;
+	case 52000000: /* clk=pclk */
+		fdiv_n = 0x5F37;
+		fdiv_ctrl |= UARTX_CLKSEL_PCLK;
+		break;
+	}
+
+	if (uart_u6 != NULL && !IS_ERR(uart_u6->uartClk)) {
+		/* if clock interface is ready and u6_serial_init */
+		struct clk *parentClk;
+
+		if (fdiv_ctrl & UARTX_CLKSEL_26M)
+			parentClk = clk_get(NULL, "clk26m_ck");
+		else if (fdiv_ctrl & UARTX_CLKSEL_PCLK)
+			parentClk = clk_get(NULL, "pclk2_ck");
+		else
+			parentClk = clk_get(NULL, "clk13m_ck");
+
+		if (!IS_ERR(parentClk)) {
+			u6_serial8250_disable_clock(port);
+
+			if (clk_set_parent(uart_u6->uartClk, parentClk) != 0)
+				pr_warning("%s: set parent failed\n", __func__);
+
+			u6_serial8250_enable_clock(port);
+			clk_put(parentClk);
+		}
+	}
+
+	writel(fdiv_m, port->membase + UARTX_FDIV_M_OFFSET);
+	writel(fdiv_n, port->membase + UARTX_FDIV_N_OFFSET);
+	writel(fdiv_ctrl, port->membase + UARTX_FDIV_CTRL_OFFSET);
+	return uartclk;
+}
+
+static void u6_set_termios(struct uart_port *port,
+		struct ktermios *termios, struct ktermios *old)
+{
+	unsigned int baud;
+
+	baud = uart_get_baud_rate(port, termios, old, 0, U6_MAX_BAUDRATE);
+	/* Calculate the new uart clock frequency & set divisors */
+	port->uartclk = u6_get_setdiv_clock(port, baud);
+	/* Call standard 8250 set_termios() */
+	serial8250_do_set_termios(port, termios, old);
+}
+
+/*
+ * Internal UARTs need to be initialized for the 8250 autoconfig to work
+ * properly.
+ */
+static struct plat_serial8250_port serial_platform_data[] = {
+	{
+		.membase	= U6_IO_ADDRESS(UART1_BASE),
+		.mapbase	= UART1_BASE,
+		.irq		= IRQ_UART1,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= BASE_BAUD,
+		.set_termios	= u6_set_termios,
+	},
+	{
+		.membase	= U6_IO_ADDRESS(UART2_BASE),
+		.mapbase	= UART2_BASE,
+		.irq		= IRQ_UART2,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_SKIP_TEST,
+		.iotype		= UPIO_MEM,
+		.regshift	= 2,
+		.uartclk	= BASE_BAUD,
+		.set_termios	= u6_set_termios,
+	},
+	/* void declaration needed by serial core */
+	{
+		.flags		= 0
+	},
+};
+
+static struct platform_device serial_device = {
+	.name = "serial8250",
+	.id = 0,
+	.dev = {.platform_data = serial_platform_data,},
+};
+
+static int __init u6_serial_init(void)
+{
+	int i;
+	struct u6_uart *uart_u6;
+
+	/* supress void element from loop */
+	for (i = 0; i < (ARRAY_SIZE(serial_platform_data) - 1); i++) {
+		struct clk *uartClk = NULL;
+
+		/* Allocation of u6 struct on uart X */
+		uart_u6 = kzalloc(sizeof(*uart_u6), GFP_KERNEL);
+		if (!uart_u6)
+			continue;
+
+		if (serial_platform_data[i].irq == IRQ_UART1) {
+			uartClk = clk_get(NULL, "UART1");
+			strcpy(uart_u6->uart_name, "UART1");
+		} else if (serial_platform_data[i].irq == IRQ_UART2) {
+			uartClk = clk_get(NULL, "UART2");
+			strcpy(uart_u6->uart_name, "UART2");
+		}
+		if (!IS_ERR(uartClk) && uartClk != NULL) {
+			uart_u6->uartClk = uartClk;
+			serial_platform_data[i].private_data = uart_u6;
+			/*  Clock Uart for autoconfigure detection */
+			clk_enable(uartClk);
+		} else {
+			pr_warning("%s - get uart clock failed error:%ld\n",
+			       __func__, PTR_ERR(uartClk));
+			kfree(uart_u6);
+			continue;
+		}
+	}
+	return platform_device_register(&serial_device);
+}
+
+arch_initcall(u6_serial_init);
-- 
1.7.1

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

* [PATCH 5/5] U6715 16550A serial driver support
  2010-08-05 12:28 ` Philippe Langlais
@ 2010-08-05 12:28   ` Philippe Langlais
  -1 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel, linux, gregkh
  Cc: akpm, STEricsson_nomadik_linux, etienne.carriere,
	vincent.guittot, Philippe Langlais

UART Features extract from STEricsson U6715 data-sheet (arm926 SoC for mobile phone):
* Fully compatible with industry standard 16C550 and 16C450 from various
manufacturers
* RX and TX 64 byte FIFO reduces CPU interrupts
* Full double buffering
* Modem control signals include CTS, RTS, (and DSR, DTR on UART1 only)
* Automatic baud rate selection
* Manual or automatic RTS/CTS smart hardware flow control
* Programmable serial characteristics:
– Baud rate generation (50 to 3.25M baud)
– 5, 6, 7 or 8-bit characters
– Even, odd or no-parity bit generation and detection
– 1, 1.5 or 2 stop bit generation
* Independent control of transmit, receive, line status, data set interrupts and FIFOs
* Full status-reporting capabilities
* Separate DMA signaling for RX and TX
* Timed interrupt to spread receive interrupt on known duration
* DMA time-out interrupt to allow detection of end of reception
* Carkit pulse coding and decoding compliant with USB carkit control interface [40]

In 16550A auto-configuration, if the fifo size is 64 then it's an U6 16550A port.
Add set_termios hook & export serial8250_do_set_termios,
this feature is used in our U6715 8250 platform serial driver, to avoid
hack in 8250.c set_termios.
In this driver the input uart clock frequency depends on baud rate and
is computed in our set_termios override function.

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 drivers/serial/8250.c       |   39 ++++++++++++++++++++++++++++++++++++---
 include/linux/serial.h      |    3 ++-
 include/linux/serial_8250.h |    5 +++++
 include/linux/serial_core.h |    3 +++
 4 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 607ed7f..702f0fa 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -300,6 +300,13 @@ static const struct serial8250_config uart_config[] = {
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
 	},
+	[PORT_U6_16550A] = {
+		.name		= "U6_16550A",
+		.fifo_size	= 64,
+		.tx_loadsz	= 64,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
+	},
 };
 
 #if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -1075,6 +1082,15 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 		DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
 	}
 	serial_outp(up, UART_IER, iersave);
+
+	/*
+	 * We distinguish between 16550A and U6 16550A by counting
+	 * how many bytes are in the FIFO.
+	 */
+	if (up->port.type == PORT_16550A && size_fifo(up) == 64) {
+		up->port.type = PORT_U6_16550A;
+		up->capabilities |= UART_CAP_AFE;
+	}
 }
 
 /*
@@ -2229,9 +2245,9 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
 	return quot;
 }
 
-static void
-serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
-		       struct ktermios *old)
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+		          struct ktermios *old)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned char cval, fcr = 0;
@@ -2407,6 +2423,17 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
 	if (tty_termios_baud_rate(termios))
 		tty_termios_encode_baud_rate(termios, baud, baud);
 }
+EXPORT_SYMBOL(serial8250_do_set_termios);
+
+static void
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+		       struct ktermios *old)
+{
+	if (port->set_termios)
+		port->set_termios(port, termios, old);
+	else
+		serial8250_do_set_termios(port, termios, old);
+}
 
 static void
 serial8250_set_ldisc(struct uart_port *port, int new)
@@ -2917,6 +2944,8 @@ int __init early_serial_setup(struct uart_port *port)
 		p->serial_in = port->serial_in;
 	if (port->serial_out)
 		p->serial_out = port->serial_out;
+	if (port->set_termios)
+		p->set_termios = port->set_termios;
 
 	return 0;
 }
@@ -2989,6 +3018,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
 		port.type		= p->type;
 		port.serial_in		= p->serial_in;
 		port.serial_out		= p->serial_out;
+		port.set_termios	= p->set_termios;
 		port.dev		= &dev->dev;
 		port.irqflags		|= irqflag;
 		ret = serial8250_register_port(&port);
@@ -3152,6 +3182,9 @@ int serial8250_register_port(struct uart_port *port)
 			uart->port.serial_in = port->serial_in;
 		if (port->serial_out)
 			uart->port.serial_out = port->serial_out;
+		/*  Possibly override set_termios call */
+		if (port->set_termios)
+			uart->port.set_termios = port->set_termios;
 
 		ret = uart_add_one_port(&serial8250_reg, &uart->port);
 		if (ret == 0)
diff --git a/include/linux/serial.h b/include/linux/serial.h
index c8613c3..06c99b6 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -77,7 +77,8 @@ struct serial_struct {
 #define PORT_16654	11
 #define PORT_16850	12
 #define PORT_RSA	13	/* RSA-DV II/S card */
-#define PORT_MAX	13
+#define PORT_U6_16550A	14
+#define PORT_MAX	14
 
 #define SERIAL_IO_PORT	0
 #define SERIAL_IO_HUB6	1
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index fb46aba..7638dea 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -32,6 +32,9 @@ struct plat_serial8250_port {
 	unsigned int	type;		/* If UPF_FIXED_TYPE */
 	unsigned int	(*serial_in)(struct uart_port *, int);
 	void		(*serial_out)(struct uart_port *, int, int);
+	void		(*set_termios)(struct uart_port *,
+			               struct ktermios *new,
+			               struct ktermios *old);
 };
 
 /*
@@ -71,5 +74,7 @@ extern int early_serial_setup(struct uart_port *port);
 extern int serial8250_find_port(struct uart_port *p);
 extern int serial8250_find_port_for_earlycon(void);
 extern int setup_early_serial8250_console(char *cmdline);
+extern void serial8250_do_set_termios(struct uart_port *port,
+		struct ktermios *termios, struct ktermios *old);
 
 #endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 18f2fe0..119354f 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -279,6 +279,9 @@ struct uart_port {
 	unsigned char __iomem	*membase;		/* read/write[bwl] */
 	unsigned int		(*serial_in)(struct uart_port *, int);
 	void			(*serial_out)(struct uart_port *, int, int);
+	void			(*set_termios)(struct uart_port *,
+				               struct ktermios *new,
+				               struct ktermios *old);
 	unsigned int		irq;			/* irq number */
 	unsigned long		irqflags;		/* irq flags  */
 	unsigned int		uartclk;		/* base uart clock */
-- 
1.7.1


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

* [PATCH 5/5] U6715 16550A serial driver support
@ 2010-08-05 12:28   ` Philippe Langlais
  0 siblings, 0 replies; 14+ messages in thread
From: Philippe Langlais @ 2010-08-05 12:28 UTC (permalink / raw)
  To: linux-arm-kernel

UART Features extract from STEricsson U6715 data-sheet (arm926 SoC for mobile phone):
* Fully compatible with industry standard 16C550 and 16C450 from various
manufacturers
* RX and TX 64 byte FIFO reduces CPU interrupts
* Full double buffering
* Modem control signals include CTS, RTS, (and DSR, DTR on UART1 only)
* Automatic baud rate selection
* Manual or automatic RTS/CTS smart hardware flow control
* Programmable serial characteristics:
? Baud rate generation (50 to 3.25M baud)
? 5, 6, 7 or 8-bit characters
? Even, odd or no-parity bit generation and detection
? 1, 1.5 or 2 stop bit generation
* Independent control of transmit, receive, line status, data set interrupts and FIFOs
* Full status-reporting capabilities
* Separate DMA signaling for RX and TX
* Timed interrupt to spread receive interrupt on known duration
* DMA time-out interrupt to allow detection of end of reception
* Carkit pulse coding and decoding compliant with USB carkit control interface [40]

In 16550A auto-configuration, if the fifo size is 64 then it's an U6 16550A port.
Add set_termios hook & export serial8250_do_set_termios,
this feature is used in our U6715 8250 platform serial driver, to avoid
hack in 8250.c set_termios.
In this driver the input uart clock frequency depends on baud rate and
is computed in our set_termios override function.

Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>
---
 drivers/serial/8250.c       |   39 ++++++++++++++++++++++++++++++++++++---
 include/linux/serial.h      |    3 ++-
 include/linux/serial_8250.h |    5 +++++
 include/linux/serial_core.h |    3 +++
 4 files changed, 46 insertions(+), 4 deletions(-)

diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c
index 607ed7f..702f0fa 100644
--- a/drivers/serial/8250.c
+++ b/drivers/serial/8250.c
@@ -300,6 +300,13 @@ static const struct serial8250_config uart_config[] = {
 		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_00,
 		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
 	},
+	[PORT_U6_16550A] = {
+		.name		= "U6_16550A",
+		.fifo_size	= 64,
+		.tx_loadsz	= 64,
+		.fcr		= UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
+		.flags		= UART_CAP_FIFO | UART_CAP_AFE,
+	},
 };
 
 #if defined (CONFIG_SERIAL_8250_AU1X00)
@@ -1075,6 +1082,15 @@ static void autoconfig_16550a(struct uart_8250_port *up)
 		DEBUG_AUTOCONF("Couldn't force IER_UUE to 0 ");
 	}
 	serial_outp(up, UART_IER, iersave);
+
+	/*
+	 * We distinguish between 16550A and U6 16550A by counting
+	 * how many bytes are in the FIFO.
+	 */
+	if (up->port.type == PORT_16550A && size_fifo(up) == 64) {
+		up->port.type = PORT_U6_16550A;
+		up->capabilities |= UART_CAP_AFE;
+	}
 }
 
 /*
@@ -2229,9 +2245,9 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
 	return quot;
 }
 
-static void
-serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
-		       struct ktermios *old)
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+		          struct ktermios *old)
 {
 	struct uart_8250_port *up = (struct uart_8250_port *)port;
 	unsigned char cval, fcr = 0;
@@ -2407,6 +2423,17 @@ serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
 	if (tty_termios_baud_rate(termios))
 		tty_termios_encode_baud_rate(termios, baud, baud);
 }
+EXPORT_SYMBOL(serial8250_do_set_termios);
+
+static void
+serial8250_set_termios(struct uart_port *port, struct ktermios *termios,
+		       struct ktermios *old)
+{
+	if (port->set_termios)
+		port->set_termios(port, termios, old);
+	else
+		serial8250_do_set_termios(port, termios, old);
+}
 
 static void
 serial8250_set_ldisc(struct uart_port *port, int new)
@@ -2917,6 +2944,8 @@ int __init early_serial_setup(struct uart_port *port)
 		p->serial_in = port->serial_in;
 	if (port->serial_out)
 		p->serial_out = port->serial_out;
+	if (port->set_termios)
+		p->set_termios = port->set_termios;
 
 	return 0;
 }
@@ -2989,6 +3018,7 @@ static int __devinit serial8250_probe(struct platform_device *dev)
 		port.type		= p->type;
 		port.serial_in		= p->serial_in;
 		port.serial_out		= p->serial_out;
+		port.set_termios	= p->set_termios;
 		port.dev		= &dev->dev;
 		port.irqflags		|= irqflag;
 		ret = serial8250_register_port(&port);
@@ -3152,6 +3182,9 @@ int serial8250_register_port(struct uart_port *port)
 			uart->port.serial_in = port->serial_in;
 		if (port->serial_out)
 			uart->port.serial_out = port->serial_out;
+		/*  Possibly override set_termios call */
+		if (port->set_termios)
+			uart->port.set_termios = port->set_termios;
 
 		ret = uart_add_one_port(&serial8250_reg, &uart->port);
 		if (ret == 0)
diff --git a/include/linux/serial.h b/include/linux/serial.h
index c8613c3..06c99b6 100644
--- a/include/linux/serial.h
+++ b/include/linux/serial.h
@@ -77,7 +77,8 @@ struct serial_struct {
 #define PORT_16654	11
 #define PORT_16850	12
 #define PORT_RSA	13	/* RSA-DV II/S card */
-#define PORT_MAX	13
+#define PORT_U6_16550A	14
+#define PORT_MAX	14
 
 #define SERIAL_IO_PORT	0
 #define SERIAL_IO_HUB6	1
diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h
index fb46aba..7638dea 100644
--- a/include/linux/serial_8250.h
+++ b/include/linux/serial_8250.h
@@ -32,6 +32,9 @@ struct plat_serial8250_port {
 	unsigned int	type;		/* If UPF_FIXED_TYPE */
 	unsigned int	(*serial_in)(struct uart_port *, int);
 	void		(*serial_out)(struct uart_port *, int, int);
+	void		(*set_termios)(struct uart_port *,
+			               struct ktermios *new,
+			               struct ktermios *old);
 };
 
 /*
@@ -71,5 +74,7 @@ extern int early_serial_setup(struct uart_port *port);
 extern int serial8250_find_port(struct uart_port *p);
 extern int serial8250_find_port_for_earlycon(void);
 extern int setup_early_serial8250_console(char *cmdline);
+extern void serial8250_do_set_termios(struct uart_port *port,
+		struct ktermios *termios, struct ktermios *old);
 
 #endif
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 18f2fe0..119354f 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -279,6 +279,9 @@ struct uart_port {
 	unsigned char __iomem	*membase;		/* read/write[bwl] */
 	unsigned int		(*serial_in)(struct uart_port *, int);
 	void			(*serial_out)(struct uart_port *, int, int);
+	void			(*set_termios)(struct uart_port *,
+				               struct ktermios *new,
+				               struct ktermios *old);
 	unsigned int		irq;			/* irq number */
 	unsigned long		irqflags;		/* irq flags  */
 	unsigned int		uartclk;		/* base uart clock */
-- 
1.7.1

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

* Re: [PATCH 5/5] U6715 16550A serial driver support
  2010-08-05 12:28   ` Philippe Langlais
@ 2010-08-06 15:39     ` Greg KH
  -1 siblings, 0 replies; 14+ messages in thread
From: Greg KH @ 2010-08-06 15:39 UTC (permalink / raw)
  To: Philippe Langlais
  Cc: linux-kernel, linux-arm-kernel, linux, akpm,
	STEricsson_nomadik_linux, etienne.carriere, vincent.guittot

On Thu, Aug 05, 2010 at 02:28:55PM +0200, Philippe Langlais wrote:
> UART Features extract from STEricsson U6715 data-sheet (arm926 SoC for mobile phone):
> * Fully compatible with industry standard 16C550 and 16C450 from various
> manufacturers
> * RX and TX 64 byte FIFO reduces CPU interrupts
> * Full double buffering
> * Modem control signals include CTS, RTS, (and DSR, DTR on UART1 only)
> * Automatic baud rate selection
> * Manual or automatic RTS/CTS smart hardware flow control
> * Programmable serial characteristics:
> – Baud rate generation (50 to 3.25M baud)
> – 5, 6, 7 or 8-bit characters
> – Even, odd or no-parity bit generation and detection
> – 1, 1.5 or 2 stop bit generation
> * Independent control of transmit, receive, line status, data set interrupts and FIFOs
> * Full status-reporting capabilities
> * Separate DMA signaling for RX and TX
> * Timed interrupt to spread receive interrupt on known duration
> * DMA time-out interrupt to allow detection of end of reception
> * Carkit pulse coding and decoding compliant with USB carkit control interface [40]
> 
> In 16550A auto-configuration, if the fifo size is 64 then it's an U6 16550A port.
> Add set_termios hook & export serial8250_do_set_termios,
> this feature is used in our U6715 8250 platform serial driver, to avoid
> hack in 8250.c set_termios.
> In this driver the input uart clock frequency depends on baud rate and
> is computed in our set_termios override function.
> 
> Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>

Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

But isn't this patch needed before the last one in this series in order
to keep everything building properly?

You might want to move it up to the first one.

thanks,

greg k-h

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

* [PATCH 5/5] U6715 16550A serial driver support
@ 2010-08-06 15:39     ` Greg KH
  0 siblings, 0 replies; 14+ messages in thread
From: Greg KH @ 2010-08-06 15:39 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 05, 2010 at 02:28:55PM +0200, Philippe Langlais wrote:
> UART Features extract from STEricsson U6715 data-sheet (arm926 SoC for mobile phone):
> * Fully compatible with industry standard 16C550 and 16C450 from various
> manufacturers
> * RX and TX 64 byte FIFO reduces CPU interrupts
> * Full double buffering
> * Modem control signals include CTS, RTS, (and DSR, DTR on UART1 only)
> * Automatic baud rate selection
> * Manual or automatic RTS/CTS smart hardware flow control
> * Programmable serial characteristics:
> ? Baud rate generation (50 to 3.25M baud)
> ? 5, 6, 7 or 8-bit characters
> ? Even, odd or no-parity bit generation and detection
> ? 1, 1.5 or 2 stop bit generation
> * Independent control of transmit, receive, line status, data set interrupts and FIFOs
> * Full status-reporting capabilities
> * Separate DMA signaling for RX and TX
> * Timed interrupt to spread receive interrupt on known duration
> * DMA time-out interrupt to allow detection of end of reception
> * Carkit pulse coding and decoding compliant with USB carkit control interface [40]
> 
> In 16550A auto-configuration, if the fifo size is 64 then it's an U6 16550A port.
> Add set_termios hook & export serial8250_do_set_termios,
> this feature is used in our U6715 8250 platform serial driver, to avoid
> hack in 8250.c set_termios.
> In this driver the input uart clock frequency depends on baud rate and
> is computed in our set_termios override function.
> 
> Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>

Acked-by: Greg Kroah-Hartman <gregkh@suse.de>

But isn't this patch needed before the last one in this series in order
to keep everything building properly?

You might want to move it up to the first one.

thanks,

greg k-h

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

* Re: [PATCH 1/5] U6/U6715 ARM architecture files
  2010-08-05 12:28   ` Philippe Langlais
@ 2010-09-02 14:18     ` Russell King - ARM Linux
  -1 siblings, 0 replies; 14+ messages in thread
From: Russell King - ARM Linux @ 2010-09-02 14:18 UTC (permalink / raw)
  To: Philippe Langlais
  Cc: linux-kernel, linux-arm-kernel, gregkh, akpm,
	STEricsson_nomadik_linux, etienne.carriere, vincent.guittot

On Thu, Aug 05, 2010 at 02:28:51PM +0200, Philippe Langlais wrote:
> Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>

One last thing - better commentry about the patches in the commit
messages would be a good idea, so that others know what these
changes are about without having to read the code.

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

* [PATCH 1/5] U6/U6715 ARM architecture files
@ 2010-09-02 14:18     ` Russell King - ARM Linux
  0 siblings, 0 replies; 14+ messages in thread
From: Russell King - ARM Linux @ 2010-09-02 14:18 UTC (permalink / raw)
  To: linux-arm-kernel

On Thu, Aug 05, 2010 at 02:28:51PM +0200, Philippe Langlais wrote:
> Signed-off-by: Philippe Langlais <philippe.langlais@stericsson.com>

One last thing - better commentry about the patches in the commit
messages would be a good idea, so that others know what these
changes are about without having to read the code.

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

end of thread, other threads:[~2010-09-02 14:18 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-08-05 12:28 Patch series For U6/U6715 platform support Philippe Langlais
2010-08-05 12:28 ` Philippe Langlais
2010-08-05 12:28 ` [PATCH 1/5] U6/U6715 ARM architecture files Philippe Langlais
2010-08-05 12:28   ` Philippe Langlais
2010-09-02 14:18   ` Russell King - ARM Linux
2010-09-02 14:18     ` Russell King - ARM Linux
2010-08-05 12:28 ` [PATCH 2/5] U6715 clocks gating management U6 clock generic driver & U6715 cgu clock specific Philippe Langlais
2010-08-05 12:28   ` Philippe Langlais
2010-08-05 12:28 ` [PATCH 3/5] U6715 gpio platform driver This driver is U6XXX platform generic Philippe Langlais
2010-08-05 12:28 ` [PATCH 4/5] U6715 platform serial driver It's a generic driver for all U6XXX platform Philippe Langlais
2010-08-05 12:28 ` [PATCH 5/5] U6715 16550A serial driver support Philippe Langlais
2010-08-05 12:28   ` Philippe Langlais
2010-08-06 15:39   ` Greg KH
2010-08-06 15:39     ` Greg KH

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.