All of lore.kernel.org
 help / color / mirror / Atom feed
* LPC32XX architecture files (updated)
@ 2010-01-28  1:43 wellsk40 at gmail.com
  2010-01-28  1:43 ` [PATCH 01/13] i2c_pnx: Added Kconfig support for the LCP32XX wellsk40 at gmail.com
                   ` (14 more replies)
  0 siblings, 15 replies; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel


The initial LCP32xx arch files are in these patches. Changes from
yesterdays posting:

gpiolib.c updated from user review comments, thanks!

Files all send via git send-email now, thanks for pointing me in
the right direction and sorry about the wraps. (if gmail wasn't
available, I'd be stuck!)

These have been checked with checkpatch.

thanks,
Kevin Wells
NXP Semiconductors

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

* [PATCH 01/13] i2c_pnx: Added Kconfig support for the LCP32XX
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-01-28  1:43 ` [PATCH 02/13] pnx4008_wdt: Added Kconfig support for the LPC32XX wellsk40 at gmail.com
                   ` (13 subsequent siblings)
  14 siblings, 0 replies; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

The existing PNX4008 support for I2C was re-used. The option to select
the PNX4008 driver in the kernel config is now also based on the
ARCH_LCP32XX config flag.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 drivers/i2c/busses/Kconfig |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 5f318ce..590a441 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -467,8 +467,8 @@ config I2C_PASEMI
 	  Supports the PA Semi PWRficient on-chip SMBus interfaces.
 
 config I2C_PNX
-	tristate "I2C bus support for Philips PNX targets"
-	depends on ARCH_PNX4008
+	tristate "I2C bus support for Philips/NXP devices"
+	depends on ARCH_PNX4008 || ARCH_LPC32XX
 	help
 	  This driver supports the Philips IP3204 I2C IP block master and/or
 	  slave controller
-- 
1.6.6

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

* [PATCH 02/13] pnx4008_wdt: Added Kconfig support for the LPC32XX
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
  2010-01-28  1:43 ` [PATCH 01/13] i2c_pnx: Added Kconfig support for the LCP32XX wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-01-28  1:43 ` [PATCH 03/13] amba clcd: Swapped CTRL/IENB registers for LCP32XX wellsk40 at gmail.com
                   ` (12 subsequent siblings)
  14 siblings, 0 replies; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

The existing PNX4008 support for the WDT was re-used. The option to
select the PNX4008 driver in the kernel config is now also based on
the ARCH_LCP32XX config flag.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 drivers/watchdog/Kconfig |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 050ee14..3019415 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -200,11 +200,11 @@ config OMAP_WATCHDOG
 	  here to enable the OMAP1610/OMAP1710/OMAP2420/OMAP3430 watchdog timer.
 
 config PNX4008_WATCHDOG
-	tristate "PNX4008 Watchdog"
-	depends on ARCH_PNX4008
+	tristate "PNX4008/LPC32XX Watchdog"
+	depends on ARCH_PNX4008 || ARCH_LPC32XX
 	help
 	  Say Y here if to include support for the watchdog timer
-	  in the PNX4008 processor.
+	  in the PNX4008 or LPC32XX processors.
 	  This driver can be built as a module by choosing M. The module
 	  will be called pnx4008_wdt.
 
-- 
1.6.6

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

* [PATCH 03/13] amba clcd: Swapped CTRL/IENB registers for LCP32XX
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
  2010-01-28  1:43 ` [PATCH 01/13] i2c_pnx: Added Kconfig support for the LCP32XX wellsk40 at gmail.com
  2010-01-28  1:43 ` [PATCH 02/13] pnx4008_wdt: Added Kconfig support for the LPC32XX wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-01-28  1:43 ` [PATCH 04/13] ARM: LPC32XX arch support in Kconfig and Makefile wellsk40 at gmail.com
                   ` (11 subsequent siblings)
  14 siblings, 0 replies; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

The LPC32XX needs the PL11x CTRL and IENB registers swapped. The
swap will also occur for ARCH_LPC32XX.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 include/linux/amba/clcd.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/include/linux/amba/clcd.h b/include/linux/amba/clcd.h
index 29c0448..8d0d491 100644
--- a/include/linux/amba/clcd.h
+++ b/include/linux/amba/clcd.h
@@ -21,7 +21,8 @@
 #define CLCD_UBAS 		0x00000010
 #define CLCD_LBAS 		0x00000014
 
-#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW)
+#if !defined(CONFIG_ARCH_VERSATILE) && !defined(CONFIG_ARCH_REALVIEW)\
+	&& !defined(CONFIG_ARCH_LPC32XX)
 #define CLCD_IENB 		0x00000018
 #define CLCD_CNTL 		0x0000001c
 #else
-- 
1.6.6

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

* [PATCH 04/13] ARM: LPC32XX arch support in Kconfig and Makefile
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (2 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 03/13] amba clcd: Swapped CTRL/IENB registers for LCP32XX wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-02-03 10:31   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles wellsk40 at gmail.com
                   ` (10 subsequent siblings)
  14 siblings, 1 reply; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

Added support and default config flags in Kconfig for the LCP32XX
arch. Updated the Makefile to include the mach-lpc32xx dir when
the ARCH_LCP32XX arch is selected.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/Kconfig  |   16 ++++++++++++++++
 arch/arm/Makefile |    1 +
 2 files changed, 17 insertions(+), 0 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 4c33ca8..cc2dbf9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -550,6 +550,20 @@ config ARCH_W90X900
 	  <http://www.nuvoton.com/hq/enu/ProductAndSales/ProductLines/
 		ConsumerElectronicsIC/ARMMicrocontroller/ARMMicrocontroller>
 
+config ARCH_LPC32XX
+	bool "NXP LPC32XX"
+	select CPU_ARM926T
+	select ARCH_REQUIRE_GPIOLIB
+	select GENERIC_GPIO
+	select HAVE_IDE
+	select ARM_AMBA
+	select USB_ARCH_HAS_OHCI
+	select COMMON_CLKDEV
+	select GENERIC_TIME
+	select GENERIC_CLOCKEVENTS
+	help
+	  Support for the NXP LPC32XX family of processors
+
 config ARCH_PNX4008
 	bool "Philips Nexperia PNX4008 Mobile"
 	select CPU_ARM926T
@@ -771,6 +785,8 @@ source "arch/arm/mach-lh7a40x/Kconfig"
 
 source "arch/arm/mach-loki/Kconfig"
 
+source "arch/arm/mach-lpc32xx/Kconfig"
+
 source "arch/arm/mach-msm/Kconfig"
 
 source "arch/arm/mach-mv78xx0/Kconfig"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 9e75825..b6ec4f7 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -139,6 +139,7 @@ machine-$(CONFIG_ARCH_KS8695)		:= ks8695
 machine-$(CONFIG_ARCH_L7200)		:= l7200
 machine-$(CONFIG_ARCH_LH7A40X)		:= lh7a40x
 machine-$(CONFIG_ARCH_LOKI) 		:= loki
+machine-$(CONFIG_ARCH_LPC32XX)		:= lpc32xx
 machine-$(CONFIG_ARCH_MMP)		:= mmp
 machine-$(CONFIG_ARCH_MSM)		:= msm
 machine-$(CONFIG_ARCH_MV78XX0)		:= mv78xx0
-- 
1.6.6

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

* [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (3 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 04/13] ARM: LPC32XX arch support in Kconfig and Makefile wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-02-03 10:51   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 06/13] ARM: LPC32XX: Core architecture files wellsk40 at gmail.com
                   ` (9 subsequent siblings)
  14 siblings, 1 reply; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

Added Kconfig for the LPC32XX arch, Kconfig.plat for platforms based
on the LPC32XX, and the initial makefiles. Kconfig.plat currently
supports the Phytec PHY3250 platform.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/Kconfig       |  158 +++++++++++++++++++++++++++++++++++
 arch/arm/mach-lpc32xx/Kconfig.plat  |   98 ++++++++++++++++++++++
 arch/arm/mach-lpc32xx/Makefile      |    9 ++
 arch/arm/mach-lpc32xx/Makefile.boot |    4 +
 4 files changed, 269 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig
new file mode 100644
index 0000000..a277885
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/Kconfig
@@ -0,0 +1,158 @@
+if ARCH_LPC32XX
+
+menu "LPC32XX chip options"
+
+config ARCH_LPC32XX_IRAM_SIZE
+	int
+	default 131072 if ARCH_LPC32XX_20
+	default 262144 if ARCH_LPC32XX_30 || ARCH_LPC32XX_40 || ARCH_LPC32XX_50
+
+choice
+    prompt "Select 32x0 device variation"
+    default ARCH_LPC32XX_50
+
+	config ARCH_LPC32XX_20
+		bool "LPC3220"
+		help
+		 128K IRAM, no ethernet or LCD
+
+	config ARCH_LPC32XX_30
+		bool "LPC3230"
+		help
+		 256K IRAM and LCD, no ethernet
+
+	config ARCH_LPC32XX_40
+		bool "LPC3240"
+		help
+		 256K IRAM and ethernet, no LCD
+
+	config ARCH_LPC32XX_50
+		bool "LPC3250"
+		help
+		 256K IRAM and ethernet and LCD
+
+endchoice
+
+menu "Serial port configuration"
+
+menu "Individual UART enable selections"
+
+config ARCH_LPC32XX_HSUART1_ENABLE
+	bool "Enable high speed UART1"
+	help
+	 Also enable LPC32xx high speed serial support in drivers/serial
+
+config ARCH_LPC32XX_HSUART2_ENABLE
+	bool "Enable high speed UART2"
+	help
+	 Also enable LPC32xx high speed serial support in drivers/serial
+
+config ARCH_LPC32XX_UART3_ENABLE
+	bool "Enable standard UART3"
+	help
+	 Also enable 8250 serial support in drivers/serial
+
+config ARCH_LPC32XX_UART4_ENABLE
+	bool "Enable standard UART4"
+	help
+	 Also enable 8250 serial support in drivers/serial
+
+config ARCH_LPC32XX_UART5_ENABLE
+	bool "Enable standard UART5"
+	default y
+	help
+	 Also enable 8250 serial support in drivers/serial
+
+config ARCH_LPC32XX_UART6_ENABLE
+	bool "Enable standard UART6"
+	help
+	 Also enable 8250 serial support in drivers/serial
+
+config ARCH_LPC32XX_HSUART7_ENABLE
+	bool "Enable high speed UART7"
+	help
+	 Also enable LPC32xx high speed serial support in drivers/serial
+
+endmenu
+
+config ARCH_LPC32XX_UART6_IRDAMODE
+	bool "Use IRDA mode on UART6"
+	depends on ARCH_LPC32XX_UART6_ENABLE
+	help
+		Enables the IrDA modulator for UART6
+
+choice
+	prompt "Kernel uncompress status output UART selection"
+	default ARCH_LPC32XX_UNCOMP_U5
+
+	config ARCH_LPC32XX_UNCOMP_HSU1
+		bool "High speed UART 1"
+		help
+		 Kernel uncompress output is on high speed UART 1
+
+	config ARCH_LPC32XX_UNCOMP_HSU2
+		bool "High speed UART 2"
+		help
+		 Kernel uncompress output is on high speed UART 2
+
+	config ARCH_LPC32XX_UNCOMP_U3
+		bool "Standard UART 3"
+		help
+		 Kernel uncompress output is on standard UART 3
+
+	config ARCH_LPC32XX_UNCOMP_U4
+		bool "Standard UART 4"
+		help
+		 Kernel uncompress output is on standard UART 4
+
+	config ARCH_LPC32XX_UNCOMP_U5
+		bool "Standard UART 5"
+		help
+		 Kernel uncompress output is on standard UART 5
+
+	config ARCH_LPC32XX_UNCOMP_U6
+		bool "Standard UART 6"
+		help
+		 Kernel uncompress output is on standard UART 6
+
+	config ARCH_LPC32XX_UNCOMP_HSU7
+		bool "High speed UART 7"
+		help
+		 Kernel uncompress output is on high speed UART 7
+
+endchoice
+
+choice
+	prompt "debug output (printascii) UART selection"
+	default ARCH_LPC32XX_DEBUGO_U5
+
+	config ARCH_LPC32XX_DEBUGO_U3
+		bool "Standard UART 3"
+		help
+		 printascii messages are output on standard UART 3
+
+	config ARCH_LPC32XX_DEBUGO_U4
+		bool "Standard UART 4"
+		help
+		 printascii messages are output on standard UART 4
+
+	config ARCH_LPC32XX_DEBUGO_U5
+		bool "Standard UART 5"
+		help
+		 printascii messages are output on standard UART 5
+
+	config ARCH_LPC32XX_DEBUGO_U6
+		bool "Standard UART 6"
+		help
+		 printascii messages are output on standard UART 6
+
+endchoice
+
+endmenu
+
+endmenu
+
+source "arch/arm/mach-lpc32xx/Kconfig.plat"
+
+endif
+
diff --git a/arch/arm/mach-lpc32xx/Kconfig.plat b/arch/arm/mach-lpc32xx/Kconfig.plat
new file mode 100644
index 0000000..a67d1ad
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/Kconfig.plat
@@ -0,0 +1,98 @@
+menu "LPC32XX platform choices"
+
+choice
+    prompt "Choose your board"
+    default MACH_PHY3250
+    help
+        This menu selects the LPC3250 board to support for this build
+
+    config MACH_PHY3250
+        bool "Phytec 3250 development board"
+	help
+	    Support for the Phytec 3250 development board
+
+endchoice
+
+choice
+	prompt "Phytec LCD module revisions"
+	depends on MACH_PHY3250
+	default PHY3250_QVGA_PANEL_1307_1
+	help
+	  Select one of the supported LCD panel revisions
+
+config PHY3250_QVGA_PANEL_1307_0
+	bool "1307.0 QVGA panel (portrait mode RGB565)"
+	help
+	  Use LCD module version 1307.0
+
+config PHY3250_QVGA_PANEL_1307_1
+	bool "1307.1 QVGA panel (portrait mode RGB565)"
+	help
+	  Use LCD module version 1307.1
+
+endchoice
+
+choice
+	prompt "Phytec CPU module revisions"
+	depends on MACH_PHY3250
+	default PHY3250_CPU_MODULE_1304_1
+	help
+	  Select one of the supported CPU module revisions
+
+config PHY3250_CPU_MODULE_1304_0
+	bool "1304.0 CPU module"
+	help
+	  Use CPU module version 1304.0
+
+config PHY3250_CPU_MODULE_1304_1
+	bool "1304.1 CPU module"
+	help
+	  Use CPU module version 1304.1
+
+endchoice
+
+choice
+	prompt "Phytec Carrier board revisions"
+	depends on MACH_PHY3250
+	default PHY3250_CARRIER_1305_3
+	help
+	  Select one of the supported carrier board revisions
+
+config PHY3250_CARRIER_1305_01
+	bool "1305.0 or 1305.1 carrier board"
+	help
+	  Use carrier board version 1305.0 or 1305.1
+
+config PHY3250_CARRIER_1305_2
+	bool "1305.2 carrier board"
+	help
+	  Use carrier board version 1305.2
+
+config PHY3250_CARRIER_1305_3
+	bool "1305.3 carrier board"
+	help
+	  Use carrier board version 1305.3
+
+endchoice
+
+choice
+	prompt "Internal IRAM use"
+	default MACH_LPC32XX_IRAM_RESERVED
+	depends on MACH_PHY3250
+
+config MACH_LPC32XX_IRAM_RESERVED
+	bool "IRAM is not used (reserved)"
+	help
+	  IRAM is not used for video or networking and can be used for
+	  other purposes or drivers
+
+config MACH_LPC32XX_IRAM_FOR_CLCD
+	bool "Use IRAM as a video frame buffer"
+	help
+	  IRAM will be used for the LCD frame buffer. If the required buffer
+	  size is larger than the size of IRAM, then SDRAM will be used
+	  instead.
+
+endchoice
+
+endmenu
diff --git a/arch/arm/mach-lpc32xx/Makefile b/arch/arm/mach-lpc32xx/Makefile
new file mode 100644
index 0000000..9c76c70
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/Makefile
@@ -0,0 +1,9 @@
+#
+# Makefile for the linux kernel.
+#
+
+obj-y				:= timer.o irq.o common.o serial.o clock.o
+obj-y				+= gpiolib.o pm.o pm_events.o suspend.o
+
+obj-$(CONFIG_MACH_PHY3250)	+= phy3250.o
+
diff --git a/arch/arm/mach-lpc32xx/Makefile.boot b/arch/arm/mach-lpc32xx/Makefile.boot
new file mode 100644
index 0000000..b796b41
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/Makefile.boot
@@ -0,0 +1,4 @@
+   zreladdr-y	:= 0x80008000
+params_phys-y	:= 0x80000100
+initrd_phys-y	:= 0x82000000
+
-- 
1.6.6

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (4 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-01-28 17:58   ` H Hartley Sweeten
  2010-02-03 15:55   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 07/13] ARM: LPC32XX: common architecture functions and structures wellsk40 at gmail.com
                   ` (8 subsequent siblings)
  14 siblings, 2 replies; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

GPIO support functions for gpiolib, irq setup and handling, serial
port support, and high resolution timer support used in the LPC32XX
architecture.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/gpiolib.c |  418 +++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-lpc32xx/irq.c     |  237 ++++++++++++++++++++++
 arch/arm/mach-lpc32xx/serial.c  |  200 +++++++++++++++++++
 arch/arm/mach-lpc32xx/timer.c   |  187 +++++++++++++++++
 4 files changed, 1042 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/gpiolib.c b/arch/arm/mach-lpc32xx/gpiolib.c
new file mode 100644
index 0000000..30cf252
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/gpiolib.c
@@ -0,0 +1,418 @@
+/*
+ * arch/arm/mach-lpc32xx/gpiolib.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+#define GPIOBASE io_p2v(GPIO_BASE)
+
+struct gpio_regs {
+	void __iomem *inp_state;
+	void __iomem *outp_set;
+	void __iomem *outp_clr;
+	void __iomem *dir_set;
+	void __iomem *dir_clr;
+};
+
+/*
+ * GPIO names
+ */
+static char *gpio_p0_names[GPIO_P0_MAX] = {
+	"p0.0", "p0.1", "p0.2", "p0.3",
+	"p0.4", "p0.5", "p0.6", "p0.7"
+};
+
+static char *gpio_p1_names[GPIO_P1_MAX] = {
+	"p1.0", "p1.1", "p1.2", "p1.3",
+	"p1.4", "p1.5", "p1.6", "p1.7",
+	"p1.8", "p1.9", "p1.10", "p1.11",
+	"p1.12", "p1.13", "p1.14", "p1.15",
+	"p1.16", "p1.17", "p1.18", "p1.19",
+	"p1.20", "p1.21", "p1.22", "p1.23",
+};
+
+static char *gpio_p2_names[GPIO_P2_MAX] = {
+	"p2.0", "p2.1", "p2.2", "p2.3",
+	"p2.4", "p2.5", "p2.6", "p2.7",
+	"p2.8", "p2.9", "p2.10", "p2.11",
+	"p2.12"
+};
+
+static char *gpio_p3_names[GPIO_P3_MAX] = {
+	"gpi000", "gpio01", "gpio02", "gpio03",
+	"gpio04", "gpio05"
+};
+
+static char *gpi_p3_names[GPI_P3_MAX] = {
+	"gpi00", "gpi01", "gpi02", "gpi03",
+	"gpi04", "gpi05", "gpi06", "gpi07",
+	"gpi08", "gpi09", "na",    "na",
+	"na",    "na",    "na",    "gpi15",
+	"gpi16", "gpi17", "gpi18", "gpi19",
+	"gpi20", "gpi21", "gpi22", "gpi23",
+	"gpi24", "gpi25", "gpi26", "gpi27"
+};
+
+static char *gpo_p3_names[GPO_P3_MAX] = {
+	"gpo00", "gpo01", "gpo02", "gpo03",
+	"gpo04", "gpo05", "gpo06", "gpo07",
+	"gpo08", "gpo09", "gpo10", "gpo11",
+	"gpo12", "gpo13", "gpo14", "gpo15",
+	"gpo16", "gpo17", "gpo18", "gpo19",
+	"gpo20", "gpo21", "gpo22", "gpo23"
+};
+
+static struct gpio_regs gpio_grp_regs[] = {
+	{
+		.inp_state	= (void __iomem *) GPIO_P0_INP_STATE(GPIOBASE),
+		.outp_set	= (void __iomem *) GPIO_P0_OUTP_SET(GPIOBASE),
+		.outp_clr	= (void __iomem *) GPIO_P0_OUTP_CLR(GPIOBASE),
+		.dir_set	= (void __iomem *) GPIO_P0_DIR_SET(GPIOBASE),
+		.dir_clr	= (void __iomem *) GPIO_P0_DIR_CLR(GPIOBASE),
+	},
+	{
+		.inp_state	= (void __iomem *) GPIO_P1_INP_STATE(GPIOBASE),
+		.outp_set	= (void __iomem *) GPIO_P1_OUTP_SET(GPIOBASE),
+		.outp_clr	= (void __iomem *) GPIO_P1_OUTP_CLR(GPIOBASE),
+		.dir_set	= (void __iomem *) GPIO_P1_DIR_SET(GPIOBASE),
+		.dir_clr	= (void __iomem *) GPIO_P1_DIR_CLR(GPIOBASE),
+	},
+	{
+		.inp_state	= (void __iomem *) GPIO_P2_INP_STATE(GPIOBASE),
+		.outp_set	= (void __iomem *) GPIO_P2_OUTP_SET(GPIOBASE),
+		.outp_clr	= (void __iomem *) GPIO_P2_OUTP_CLR(GPIOBASE),
+		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
+		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
+	},
+	{
+		.inp_state	= (void __iomem *) GPIO_P3_INP_STATE(GPIOBASE),
+		.outp_set	= (void __iomem *) GPIO_P3_OUTP_SET(GPIOBASE),
+		.outp_clr	= (void __iomem *) GPIO_P3_OUTP_CLR(GPIOBASE),
+		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
+		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
+	},
+};
+
+struct lpc32xx_gpio_chip {
+	struct gpio_chip	chip;
+	struct gpio_regs	*gpio_grp;
+};
+
+static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio(
+	struct gpio_chip *gpc)
+{
+	return container_of(gpc, struct lpc32xx_gpio_chip, chip);
+}
+
+static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
+	unsigned pin, int input)
+{
+	if (input)
+		writel(1 << pin, group->gpio_grp->dir_clr);
+	else
+		writel(1 << pin, group->gpio_grp->dir_set);
+}
+
+static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group,
+	unsigned pin, int input)
+{
+	u32 u;
+
+	/* P3 GPIO pins are offset in the register to pin mapping */
+	u = (1 << (pin + 25));
+
+	if (input)
+		writel(u, group->gpio_grp->dir_clr);
+	else
+		writel(u, group->gpio_grp->dir_set);
+}
+
+static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group,
+	unsigned pin, int high)
+{
+	if (high)
+		writel(1 << pin, group->gpio_grp->outp_set);
+	else
+		writel(1 << pin, group->gpio_grp->outp_clr);
+}
+
+static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group,
+	unsigned pin, int high)
+{
+	u32 u;
+
+	/* P3 GPIO pins are offset in the register to pin mapping */
+	u = (1 << (pin + 25));
+
+	if (high)
+		writel(u, group->gpio_grp->outp_set);
+	else
+		writel(u, group->gpio_grp->outp_clr);
+}
+
+static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group,
+	unsigned pin, int high)
+{
+	if (high)
+		writel(1 << pin, group->gpio_grp->outp_set);
+	else
+		writel(1 << pin, group->gpio_grp->outp_clr);
+}
+
+static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group,
+	unsigned pin)
+{
+	return (readl(group->gpio_grp->inp_state) >> pin) & 1;
+}
+
+static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
+	unsigned pin)
+{
+	int state;
+
+	state = readl(group->gpio_grp->inp_state);
+
+	/* P3 GPIO pin input mapping is not contiguous */
+	if (pin == 5)
+		state = (state >> 24) & 1;
+	else
+		state = (state >> (10 + pin)) & 1;
+
+	return state;
+}
+
+static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
+	unsigned pin)
+{
+	return (readl(group->gpio_grp->inp_state) >> pin) & 1;
+}
+
+/*
+ * GENERIC_GPIO primitives.
+ */
+static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
+	unsigned pin)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpio_dir_p012(group, pin, 1);
+
+	return 0;
+}
+
+static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip,
+	unsigned pin)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpio_dir_p3(group, pin, 1);
+
+	return 0;
+}
+
+static int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip,
+	unsigned pin)
+{
+	return 0;
+}
+
+static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	return __get_gpio_state_p012(group, pin);
+}
+
+static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	return __get_gpio_state_p3(group, pin);
+}
+
+static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	return __get_gpi_state_p3(group, pin);
+}
+
+static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
+	int value)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpio_dir_p012(group, pin, 0);
+
+	return 0;
+}
+
+static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
+	int value)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpio_dir_p3(group, pin, 0);
+
+	return 0;
+}
+
+static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
+	int value)
+{
+	return 0;
+}
+
+static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
+	int value)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpio_level_p012(group, pin, value);
+}
+
+static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
+	int value)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpio_level_p3(group, pin, value);
+}
+
+static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
+	int value)
+{
+	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
+
+	__set_gpo_level_p3(group, pin, value);
+}
+
+static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
+{
+	if (pin < chip->ngpio)
+		return 0;
+
+	return -EINVAL;
+}
+
+static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
+	{
+		.chip = {
+			.label			= "gpio_p0",
+			.direction_input	= lpc32xx_gpio_dir_input_p012,
+			.get			= lpc32xx_gpio_get_value_p012,
+			.direction_output	= lpc32xx_gpio_dir_output_p012,
+			.set			= lpc32xx_gpio_set_value_p012,
+			.request		= lpc32xx_gpio_request,
+			.base			= GPIO_P0_GRP,
+			.ngpio			= GPIO_P0_MAX,
+			.names			= gpio_p0_names,
+			.can_sleep		= 0,
+		},
+		.gpio_grp = &gpio_grp_regs[0],
+	},
+	{
+		.chip = {
+			.label			= "gpio_p1",
+			.direction_input	= lpc32xx_gpio_dir_input_p012,
+			.get			= lpc32xx_gpio_get_value_p012,
+			.direction_output	= lpc32xx_gpio_dir_output_p012,
+			.set			= lpc32xx_gpio_set_value_p012,
+			.request		= lpc32xx_gpio_request,
+			.base			= GPIO_P1_GRP,
+			.ngpio			= GPIO_P1_MAX,
+			.names			= gpio_p1_names,
+			.can_sleep		= 0,
+		},
+		.gpio_grp = &gpio_grp_regs[1],
+	},
+	{
+		.chip = {
+			.label			= "gpio_p2",
+			.direction_input	= lpc32xx_gpio_dir_input_p012,
+			.get			= lpc32xx_gpio_get_value_p012,
+			.direction_output	= lpc32xx_gpio_dir_output_p012,
+			.set			= lpc32xx_gpio_set_value_p012,
+			.request		= lpc32xx_gpio_request,
+			.base			= GPIO_P2_GRP,
+			.ngpio			= GPIO_P2_MAX,
+			.names			= gpio_p2_names,
+			.can_sleep		= 0,
+		},
+		.gpio_grp = &gpio_grp_regs[2],
+	},
+	{
+		.chip = {
+			.label			= "gpio_p3",
+			.direction_input	= lpc32xx_gpio_dir_input_p3,
+			.get			= lpc32xx_gpio_get_value_p3,
+			.direction_output	= lpc32xx_gpio_dir_output_p3,
+			.set			= lpc32xx_gpio_set_value_p3,
+			.request		= lpc32xx_gpio_request,
+			.base			= GPIO_P3_GRP,
+			.ngpio			= GPIO_P3_MAX,
+			.names			= gpio_p3_names,
+			.can_sleep		= 0,
+		},
+		.gpio_grp = &gpio_grp_regs[3],
+	},
+	{
+		.chip = {
+			.label			= "gpi_p3",
+			.direction_input	= lpc32xx_gpio_dir_in_always,
+			.get			= lpc32xx_gpi_get_value,
+			.request		= lpc32xx_gpio_request,
+			.base			= GPI_P3_GRP,
+			.ngpio			= GPI_P3_MAX,
+			.names			= gpi_p3_names,
+			.can_sleep		= 0,
+		},
+		.gpio_grp = &gpio_grp_regs[3],
+	},
+	{
+		.chip = {
+			.label			= "gpo_p3",
+			.direction_output	= lpc32xx_gpio_dir_out_always,
+			.set			= lpc32xx_gpo_set_value,
+			.request		= lpc32xx_gpio_request,
+			.base			= GPO_P3_GRP,
+			.ngpio			= GPO_P3_MAX,
+			.names			= gpo_p3_names,
+			.can_sleep		= 0,
+		},
+		.gpio_grp = &gpio_grp_regs[3],
+	},
+};
+
+void __init lpc32xx_gpio_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++)
+		gpiochip_add(&lpc32xx_gpiochip[i].chip);
+}
diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
new file mode 100644
index 0000000..8a1b57d
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/irq.c
@@ -0,0 +1,237 @@
+/*
+ * arch/arm/mach-lpc32xx/irq.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/io.h>
+
+#include <mach/irqs.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+
+/*
+ * Default value represeting the Activation polarity of all internal
+ * interrupt sources
+ */
+#define MIC_APR_DEFAULT		0x3FF0EFE0
+#define SIC1_APR_DEFAULT	0xFBD27186
+#define SIC2_APR_DEFAULT	0x801810C0
+
+/*
+ * Default value represeting the Activation Type of all internal
+ * interrupt sources. All are level senesitive.
+ */
+#define MIC_ATR_DEFAULT		0x00000000
+#define SIC1_ATR_DEFAULT	0x00026000
+#define SIC2_ATR_DEFAULT	0x00000000
+
+static void get_controller(unsigned int irq, unsigned int *base,
+	unsigned int *irqbit)
+{
+	if (irq < 32) {
+		*base = io_p2v(MIC_BASE);
+		*irqbit = 1 << irq;
+	} else if (irq < 64) {
+		*base = io_p2v(SIC1_BASE);
+		*irqbit = 1 << (irq - 32);
+	} else {
+		*base = io_p2v(SIC2_BASE);
+		*irqbit = 1 << (irq - 64);
+	}
+}
+
+static void lpc32xx_mask_irq(unsigned int irq)
+{
+	unsigned int reg, ctrl, mask;
+
+	get_controller(irq, &ctrl, &mask);
+
+	reg = readl(ctrl + INTC_MASK);
+	reg &= ~mask;
+	writel(reg, (ctrl + INTC_MASK));
+}
+
+static void lpc32xx_unmask_irq(unsigned int irq)
+{
+	unsigned int reg, ctrl, mask;
+
+	get_controller(irq, &ctrl, &mask);
+
+	reg = readl(ctrl + INTC_MASK);
+	reg |= mask;
+	writel(reg, (ctrl + INTC_MASK));
+}
+
+static void lpc32xx_mask_ack_irq(unsigned int irq)
+{
+	unsigned int ctrl, mask;
+
+	get_controller(irq, &ctrl, &mask);
+
+	writel(mask, (ctrl + INTC_RAW_STAT));
+}
+
+static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
+{
+	unsigned int reg, ctrl, mask;
+
+	get_controller(irq, &ctrl, &mask);
+
+	switch (type) {
+	case IRQ_TYPE_EDGE_RISING:
+		/* Rising edge sensitive */
+		reg = readl(ctrl + INTC_POLAR);
+		reg |= mask;
+		writel(reg, (ctrl + INTC_POLAR));
+		reg = readl(ctrl + INTC_ACT_TYPE);
+		reg |= mask;
+		writel(reg, (ctrl + INTC_ACT_TYPE));
+		set_irq_handler(irq, handle_edge_irq);
+		break;
+
+	case IRQ_TYPE_EDGE_FALLING:
+		/* Falling edge sensitive */
+		reg = readl(ctrl + INTC_POLAR);
+		reg &= ~mask;
+		writel(reg, (ctrl + INTC_POLAR));
+		reg = readl(ctrl + INTC_ACT_TYPE);
+		reg |= mask;
+		writel(reg, (ctrl + INTC_ACT_TYPE));
+		set_irq_handler(irq, handle_edge_irq);
+		break;
+
+	case IRQ_TYPE_LEVEL_LOW:
+		/* Low level sensitive */
+		reg = readl(ctrl + INTC_POLAR);
+		reg &= ~mask;
+		writel(reg, (ctrl + INTC_POLAR));
+		reg = readl(ctrl + INTC_ACT_TYPE);
+		reg &= ~mask;
+		writel(reg, (ctrl + INTC_ACT_TYPE));
+		set_irq_handler(irq, handle_level_irq);
+		break;
+
+	case IRQ_TYPE_LEVEL_HIGH:
+		/* High level sensitive */
+		reg = readl(ctrl + INTC_POLAR);
+		reg |= mask;
+		writel(reg, (ctrl + INTC_POLAR));
+		reg = readl(ctrl + INTC_ACT_TYPE);
+		reg &= ~mask;
+		writel(reg, (ctrl + INTC_ACT_TYPE));
+		set_irq_handler(irq, handle_level_irq);
+		break;
+
+	/* Other modes are not supported */
+	default:
+		return -ENOTSUPP;
+	}
+
+	return 0;
+}
+
+static void __init lpc32xx_set_default_mappings(unsigned int base,
+	unsigned int apr, unsigned int atr, unsigned int offset)
+{
+	unsigned int i, lvl, type;
+
+	/* Set activation levels for each interrupt */
+	i = 0;
+	while (i < 32) 	{
+		lvl = ((apr >> i) & 0x1) | (((atr >> i) & 0x1) << 1);
+		switch (lvl) {
+		case 0x0: /* Low polarity and level operation */
+			type = IRQ_TYPE_LEVEL_LOW;
+			break;
+
+		case 0x1: /* High polarity and level operation */
+			type = IRQ_TYPE_LEVEL_HIGH;
+			break;
+
+		case 0x2: /* Low polarity and edge operation */
+			type = IRQ_TYPE_EDGE_FALLING;
+			break;
+
+		case 0x3: /* High polarity and edge operation */
+		default:
+			type = IRQ_TYPE_EDGE_RISING;
+			break;
+		}
+
+		lpc32xx_set_irq_type((offset + i), type);
+		i++;
+	}
+}
+
+static struct irq_chip lpc32xx_irq_chip = {
+	.ack = lpc32xx_mask_ack_irq,
+	.mask = lpc32xx_mask_irq,
+	.unmask = lpc32xx_unmask_irq,
+	.set_type = lpc32xx_set_irq_type,
+};
+
+void __init lpc32xx_init_irq(void)
+{
+	unsigned int i, vloc;
+
+	/* Setup MIC */
+	vloc = io_p2v(MIC_BASE);
+	writel(0, (vloc + INTC_MASK));
+	writel(MIC_APR_DEFAULT, (vloc + INTC_POLAR));
+	writel(MIC_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
+
+	/* Setup SIC1 */
+	vloc = io_p2v(SIC1_BASE);
+	writel(0, (vloc + INTC_MASK));
+	writel(SIC1_APR_DEFAULT, (vloc + INTC_POLAR));
+	writel(SIC1_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
+
+	/* Setup SIC2 */
+	vloc = io_p2v(SIC2_BASE);
+	writel(0, (vloc + INTC_MASK));
+	writel(SIC2_APR_DEFAULT, (vloc + INTC_POLAR));
+	writel(SIC2_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
+
+	/* Configure supported IRQ's */
+	for (i = 0; i < NR_IRQS; i++) {
+		set_irq_flags(i, IRQF_VALID);
+		set_irq_chip(i, &lpc32xx_irq_chip);
+	}
+
+	/* Set default mappings */
+	lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT,
+		MIC_ATR_DEFAULT, 0);
+	lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT,
+		SIC1_ATR_DEFAULT, 32);
+	lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT,
+		SIC2_ATR_DEFAULT, 64);
+
+	/* mask all interrupts except SUBIRQA and SUBFIQ */
+	writel((1 << IRQ_SUB1IRQ) | (1 << IRQ_SUB2IRQ) |
+			(1 << IRQ_SUB1FIQ) | (1 << IRQ_SUB2FIQ),
+		(io_p2v(MIC_BASE) + INTC_MASK));
+	writel(0, (io_p2v(SIC1_BASE) + INTC_MASK));
+	writel(0, (io_p2v(SIC2_BASE) + INTC_MASK));
+}
diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-lpc32xx/serial.c
new file mode 100644
index 0000000..1c15121
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/serial.c
@@ -0,0 +1,200 @@
+/*
+ * arch/arm/mach-lpc32xx/serial.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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/kernel.h>
+#include <linux/types.h>
+#include <linux/serial.h>
+#include <linux/serial_core.h>
+#include <linux/serial_reg.h>
+#include <linux/serial_8250.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include <mach/io.h>
+#include "common.h"
+
+/* Standard 8250/16550 compatible serial ports */
+static struct plat_serial8250_port serial_std_platform_data[] = {
+#ifdef CONFIG_ARCH_LPC32XX_UART5_ENABLE
+	{
+		.membase        = (void *) io_p2v(UART5_BASE),
+		.mapbase        = UART5_BASE,
+		.irq		= IRQ_UART_IIR5,
+		.uartclk	= MAIN_OSC_FREQ,
+		.regshift	= 2,
+		.iotype		= UPIO_MEM32,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+					UPF_SKIP_TEST,
+	},
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART3_ENABLE
+	{
+		.membase	= (void *) io_p2v(UART3_BASE),
+		.mapbase        = UART3_BASE,
+		.irq		= IRQ_UART_IIR3,
+		.uartclk	= MAIN_OSC_FREQ,
+		.regshift	= 2,
+		.iotype		= UPIO_MEM32,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+					UPF_SKIP_TEST,
+	},
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART4_ENABLE
+	{
+		.membase	= (void *) io_p2v(UART4_BASE),
+		.mapbase        = UART4_BASE,
+		.irq		= IRQ_UART_IIR4,
+		.uartclk	= MAIN_OSC_FREQ,
+		.regshift	= 2,
+		.iotype		= UPIO_MEM32,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+					UPF_SKIP_TEST,
+	},
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART6_ENABLE
+	{
+		.membase	= (void *) io_p2v(UART6_BASE),
+		.mapbase        = UART6_BASE,
+		.irq		= IRQ_UART_IIR6,
+		.uartclk	= MAIN_OSC_FREQ,
+		.regshift	= 2,
+		.iotype		= UPIO_MEM32,
+		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
+					UPF_SKIP_TEST,
+	},
+#endif
+	{ },
+};
+
+struct uartinit {
+	char *uart_ck_name;
+	u32 ck_mode_mask;
+	u32 pdiv_clk_reg;
+};
+
+static struct uartinit uartinit_data[] __initdata = {
+#ifdef CONFIG_ARCH_LPC32XX_UART5_ENABLE
+	{
+		.uart_ck_name = "uart5_ck",
+		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 5),
+		.pdiv_clk_reg = CLKPWR_UART5_CLK_CTRL(CLKPWR_IOBASE),
+	},
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART3_ENABLE
+	{
+		.uart_ck_name = "uart3_ck",
+		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 3),
+		.pdiv_clk_reg = CLKPWR_UART3_CLK_CTRL(CLKPWR_IOBASE),
+	},
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART4_ENABLE
+	{
+		.uart_ck_name = "uart4_ck",
+		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 4),
+		.pdiv_clk_reg = CLKPWR_UART4_CLK_CTRL(CLKPWR_IOBASE),
+	},
+#endif
+#ifdef CONFIG_ARCH_LPC32XX_UART6_ENABLE
+	{
+		.uart_ck_name = "uart6_ck",
+		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 6),
+		.pdiv_clk_reg = CLKPWR_UART6_CLK_CTRL(CLKPWR_IOBASE),
+	},
+#endif
+};
+
+static struct platform_device serial_std_platform_device = {
+	.name			= "serial8250",
+	.id			= 0,
+	.dev			= {
+		.platform_data	= serial_std_platform_data,
+	},
+};
+
+static struct platform_device *lpc32xx_serial_devs[] __initdata = {
+	&serial_std_platform_device,
+};
+
+void __init lpc32xx_serial_init(void)
+{
+	u32 tmp, clkmodes = 0;
+	struct clk *clk;
+	void *puart;
+	int i;
+
+	/* UART clocks are off, let clock driver manage them */
+	__raw_writel(0, CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE));
+
+	for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
+		clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
+		if (IS_ERR(clk)) {
+#ifdef CONFIG_DEBUG_LL
+			/* A clock get failure can mean the console might
+			   not work. It's possible this might not even
+			   work. */
+			printascii("Serial port clock get failure!\n");
+#endif
+		} else {
+			clk_enable(clk);
+			serial_std_platform_data[i].uartclk =
+				clk_get_rate(clk);
+		}
+
+		/* Setup UART clock modes for all UARTs, disable autoclock */
+		clkmodes |= uartinit_data[i].ck_mode_mask;
+
+		/* pre-UART clock divider set to 1 */
+		writel(0x0101, uartinit_data[i].pdiv_clk_reg);
+	}
+
+	/* This needs to be done after all UART clocks are setup */
+	writel(clkmodes, UARTCTL_CLKMODE(io_p2v(UART_CTRL_BASE)));
+	for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) {
+		/* Force a flush of the RX FIFOs to work around a HW bug */
+		puart = serial_std_platform_data[i].membase;
+		writel(0xC1, UART_IIR_FCR(puart));
+		writel(0x00, UART_DLL_FIFO(puart));
+		clkmodes = 64;
+		while (clkmodes--)
+			tmp = readl(UART_DLL_FIFO(puart));
+		writel(0, UART_IIR_FCR(puart));
+	}
+
+	/* IrDA pulsing support on UART6. This only enables the IrDA mux */
+	tmp = readl(UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
+#ifdef CONFIG_ARCH_LPC32XX_UART6_IRDAMODE
+	tmp &= ~UART_UART6_IRDAMOD_BYPASS;
+#else
+	tmp |= UART_UART6_IRDAMOD_BYPASS;
+#endif
+	writel(tmp, UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
+
+	/* Disable UART5->USB transparent mode or USB won't work */
+	tmp = readl(UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
+	tmp &= ~UART_U5_ROUTE_TO_USB;
+	writel(tmp, UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
+
+	platform_add_devices(lpc32xx_serial_devs,
+		ARRAY_SIZE(lpc32xx_serial_devs));
+}
diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-lpc32xx/timer.c
new file mode 100644
index 0000000..9c06346
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/timer.c
@@ -0,0 +1,187 @@
+/*
+ * arch/arm/mach-lpc32xx/timer.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2009 - 2010 NXP Semiconductors
+ * Copyright (C) 2009 Fontys University of Applied Sciences, Eindhoven
+ *                    Ed Schouten <e.schouten@fontys.nl>
+ *                    Laurens Timmermans <l.timmermans@fontys.nl>
+ *
+ * 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/interrupt.h>
+#include <linux/irq.h>
+#include <linux/time.h>
+#include <linux/err.h>
+#include <linux/clockchips.h>
+
+#include <asm/mach/time.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+#define TIMER0_IOBASE io_p2v(TIMER0_BASE)
+#define TIMER1_IOBASE io_p2v(TIMER1_BASE)
+
+static cycle_t lpc32xx_clksrc_read(struct clocksource *cs)
+{
+	return (cycle_t)readl(TIMER_TC(TIMER1_IOBASE));
+}
+
+static struct clocksource lpc32xx_clksrc = {
+	.name	= "lpc32xx_clksrc",
+	.shift	= 24,
+	.rating	= 300,
+	.read	= lpc32xx_clksrc_read,
+	.mask	= CLOCKSOURCE_MASK(32),
+	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
+};
+
+static int lpc32xx_clkevt_next_event(unsigned long delta,
+    struct clock_event_device *dev)
+{
+	unsigned long flags;
+
+	if (delta < 1)
+		return -ETIME;
+
+	local_irq_save(flags);
+
+	writel(TIMER_CNTR_TCR_RESET, TIMER_TCR(TIMER0_IOBASE));
+	writel(delta, TIMER_PR(TIMER0_IOBASE));
+	writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER0_IOBASE));
+
+	local_irq_restore(flags);
+
+	return 0;
+}
+
+static void lpc32xx_clkevt_mode(enum clock_event_mode mode,
+    struct clock_event_device *dev)
+{
+	switch (mode) {
+	case CLOCK_EVT_MODE_PERIODIC:
+		WARN_ON(1);
+		break;
+
+	case CLOCK_EVT_MODE_ONESHOT:
+	case CLOCK_EVT_MODE_SHUTDOWN:
+		/*
+		 * Disable the timer. When using oneshot, we must also
+		 * disable the timer to wait for the first call to
+		 * set_next_event().
+		 */
+		writel(0, TIMER_TCR(TIMER0_IOBASE));
+		break;
+
+	case CLOCK_EVT_MODE_UNUSED:
+	case CLOCK_EVT_MODE_RESUME:
+		break;
+	}
+}
+
+static struct clock_event_device lpc32xx_clkevt = {
+	.name		= "lpc32xx_clkevt",
+	.features	= CLOCK_EVT_FEAT_ONESHOT,
+	.shift		= 32,
+	.rating		= 300,
+	.set_next_event	= lpc32xx_clkevt_next_event,
+	.set_mode	= lpc32xx_clkevt_mode,
+};
+
+static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *evt = &lpc32xx_clkevt;
+
+	/* Clear match */
+	writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE));
+
+	evt->event_handler(evt);
+
+	return IRQ_HANDLED;
+}
+
+static struct irqaction lpc32xx_timer_irq = {
+	.name		= "LPC32XX Timer Tick",
+	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
+	.handler	= lpc32xx_timer_interrupt,
+};
+
+/*
+ * The clock management driver isn't initialized at this point, so the
+ * clocks need to be enabled here manually and then tagged as used in
+ * the clock driver initialization
+ */
+static void __init lpc32xx_timer_init(void)
+{
+	u32 clkrate, pllreg;
+
+	/* Enable timer clock */
+	writel(
+		(CLKPWR_TMRPWMCLK_TIMER0_EN | CLKPWR_TMRPWMCLK_TIMER1_EN),
+		CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE));
+
+	/* The clock driver isn't initialized at this point. So determine if
+	   the SYSCLK is driven from the PLL397 or main oscillator and then use
+	   it to compute the PLL frequency and the PCLK divider to get the base
+	   timer rates. This rate is needed to compute the tick rate. */
+	if (clk_is_sysclk_mainosc() != 0)
+		clkrate = MAIN_OSC_FREQ;
+	else
+		clkrate = 397 * CLOCK_OSC_FREQ;
+
+	/* Get ARM HCLKPLL register and convert it into a frequency*/
+	pllreg = readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & 0x1FFFF;
+	clkrate = clk_get_pllrate_from_reg(clkrate, pllreg);
+
+	/* Get PCLK divider and divide ARM PLL clock by it to get timer rate */
+	clkrate = clkrate / clk_get_pclk_div();
+
+	/* Initial timer setup */
+	writel(0, TIMER_TCR(TIMER0_IOBASE));
+	writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE));
+	writel(1, TIMER_MR0(TIMER0_IOBASE));
+	writel(TIMER_CNTR_MCR_MTCH(0) | TIMER_CNTR_MCR_STOP(0) |
+	    TIMER_CNTR_MCR_RESET(0), TIMER_MCR(TIMER0_IOBASE));
+
+	/* Setup tick interrupt */
+	setup_irq(IRQ_TIMER0, &lpc32xx_timer_irq);
+
+	/* Setup the clockevent structure. */
+	lpc32xx_clkevt.mult = div_sc(clkrate, NSEC_PER_SEC,
+		lpc32xx_clkevt.shift);
+	lpc32xx_clkevt.max_delta_ns = clockevent_delta2ns(-1,
+		&lpc32xx_clkevt);
+	lpc32xx_clkevt.min_delta_ns = clockevent_delta2ns(1, &lpc32xx_clkevt);
+	lpc32xx_clkevt.cpumask = cpumask_of(0);
+	clockevents_register_device(&lpc32xx_clkevt);
+
+	/* Use timer1 as clock source. */
+	writel(TIMER_CNTR_TCR_RESET, TIMER_TCR(TIMER1_IOBASE));
+	writel(0, TIMER_PR(TIMER1_IOBASE));
+	writel(0, TIMER_MCR(TIMER1_IOBASE));
+	writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER1_IOBASE));
+	lpc32xx_clksrc.mult = clocksource_hz2mult(clkrate,
+		lpc32xx_clksrc.shift);
+	clocksource_register(&lpc32xx_clksrc);
+}
+
+struct sys_timer lpc32xx_timer = {
+	.init		= &lpc32xx_timer_init,
+};
+
-- 
1.6.6

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

* [PATCH 07/13] ARM: LPC32XX: common architecture functions and structures
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (5 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 06/13] ARM: LPC32XX: Core architecture files wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-02-03 16:01   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 08/13] ARM: LPC32XX: clock tree support wellsk40 at gmail.com
                   ` (7 subsequent siblings)
  14 siblings, 1 reply; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

LPC32XX arch specific functions and drivers that may be used
in platforms based on the LCP32XX.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/common.c |  269 ++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-lpc32xx/common.h |   76 +++++++++++
 2 files changed, 345 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
new file mode 100644
index 0000000..77c98b4
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/common.c
@@ -0,0 +1,269 @@
+/*
+ * arch/arm/mach-lpc32xx/common.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/i2c-pnx.h>
+#include <linux/io.h>
+
+#include <asm/mach/map.h>
+
+#include <mach/i2c.h>
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+
+#define WDT_IOBASE io_p2v(WDTIM_BASE)
+
+/*
+ * Watchdog timer
+ */
+static struct resource watchdog_resources[] = {
+	[0] = {
+		.start = WDTIM_BASE,
+		.end = WDTIM_BASE + SZ_4K - 1,
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+struct platform_device watchdog_device = {
+	.name = "pnx4008-watchdog",
+	.id = -1,
+	.num_resources = ARRAY_SIZE(watchdog_resources),
+	.resource = watchdog_resources,
+};
+
+/*
+ * I2C busses
+ */
+static struct i2c_pnx_data i2c0_data = {
+	.name = I2C_CHIP_NAME "0",
+	.base = I2C1_BASE,
+	.irq = IRQ_I2C_1,
+};
+
+static struct i2c_pnx_data i2c1_data = {
+	.name = I2C_CHIP_NAME "1",
+	.base = I2C2_BASE,
+	.irq = IRQ_I2C_2,
+};
+
+static struct i2c_pnx_data i2c2_data = {
+	.name = "USB-I2C",
+	.base = OTG_I2C_BASE,
+	.irq = IRQ_USB_I2C,
+};
+
+struct platform_device i2c0_device = {
+	.name = "pnx-i2c",
+	.id = 0,
+	.dev = {
+		.platform_data = &i2c0_data,
+	},
+};
+
+struct platform_device i2c1_device = {
+	.name = "pnx-i2c",
+	.id = 1,
+	.dev = {
+		.platform_data = &i2c1_data,
+	},
+};
+
+struct platform_device i2c2_device = {
+	.name = "pnx-i2c",
+	.id = 2,
+	.dev = {
+		.platform_data = &i2c2_data,
+	},
+};
+
+/*
+ * Returns the unique ID for the device
+ */
+void lpc32xx_get_uid(u32 devid[4])
+{
+	int i;
+
+	for (i = 0; i < 4; i++)
+		devid[i] = readl(CLKPWR_DEVID(CLKPWR_IOBASE, i << 2));
+}
+
+/*
+ * Returns SYSCLK source
+ * 0 = PLL397, 1 = main oscillator
+ */
+int clk_is_sysclk_mainosc(void)
+{
+	if ((readl(CLKPWR_SYSCLK_CTRL(CLKPWR_IOBASE)) &
+		CLKPWR_SYSCTRL_SYSCLKMUX) == 0)
+		return 1;
+
+	return 0;
+}
+
+/*
+ * System reset via the watchdog timer
+ */
+void lpc32xx_watchdog_reset(void)
+{
+	/* Make sure WDT clocks are enabled */
+	writel(CLKPWR_PWMCLK_WDOG_EN,
+		CLKPWR_TIMER_CLK_CTRL(CLKPWR_IOBASE));
+
+	/* Instand assert of RESETOUT_N with pulse length 1mS */
+	writel(13000, WDT_IOBASE + 0x18);
+	writel(0x70, WDT_IOBASE + 0xC);
+}
+
+/*
+ * Computes PLL rate from PLL register and input clock
+ */
+u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup)
+{
+	u32 ilfreq, p, m, n, fcco, fref, cfreq;
+	int mode;
+
+	/* PLL requirements */
+	/* ifreq must be >= 1MHz and <= 20MHz */
+	/* FCCO must be >= 156MHz and <= 320MHz */
+	/* FREF must be >= 1MHz and <= 27MHz. */
+	/* Assume the passed input data is not valid */
+
+	ilfreq = ifreq;
+	m = pllsetup->pll_m;
+	n = pllsetup->pll_n;
+	p = pllsetup->pll_p;
+
+	mode = (pllsetup->cco_bypass_b15 << 2) |
+		(pllsetup->direct_output_b14 << 1) |
+	pllsetup->fdbk_div_ctrl_b13;
+
+	switch (mode) {
+	case 0x0: /* Non-integer mode */
+		cfreq = (m * ilfreq) / (2 * p * n);
+		fcco = (m * ilfreq) / n;
+		fref = ilfreq / n;
+		break;
+
+	case 0x1: /* integer mode */
+		cfreq = (m * ilfreq) / n;
+		fcco = (m * ilfreq) / (n * 2 * p);
+		fref = ilfreq / n;
+		break;
+
+	case 0x2:
+	case 0x3: /* Direct mode */
+		cfreq = (m * ilfreq) / n;
+		fcco = cfreq;
+		fref = ilfreq / n;
+		break;
+
+	case 0x4:
+	case 0x5: /* Bypass mode */
+		cfreq = ilfreq / (2 * p);
+		fcco = 156000000;
+		fref = 1000000;
+		break;
+
+	case 0x6:
+	case 0x7: /* Direct bypass mode */
+	default:
+		cfreq = ilfreq;
+		fcco = 156000000;
+		fref = 1000000;
+		break;
+	}
+
+	if (fcco < 156000000 || fcco > 320000000)
+		cfreq = 0;
+
+	if (fref < 1000000 || fref > 27000000)
+		cfreq = 0;
+
+	return (u32) cfreq;
+}
+
+/*
+ * Convert a PLL register value to a PLL output frequency
+ */
+u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval)
+{
+	struct clk_pll_setup pllcfg;
+
+	pllcfg.cco_bypass_b15 = 0;
+	pllcfg.direct_output_b14 = 0;
+	pllcfg.fdbk_div_ctrl_b13 = 0;
+	if ((regval & CLKPWR_HCLKPLL_CCO_BYPASS) != 0)
+		pllcfg.cco_bypass_b15 = 1;
+	if ((regval & CLKPWR_HCLKPLL_POSTDIV_BYPASS) != 0)
+		pllcfg.direct_output_b14 = 1;
+	if ((regval & CLKPWR_HCLKPLL_FDBK_SEL_FCLK) != 0)
+		pllcfg.fdbk_div_ctrl_b13 = 1;
+	pllcfg.pll_m = 1 + ((regval >> 1) & 0xFF);
+	pllcfg.pll_n = 1 + ((regval >> 9) & 0x3);
+	pllcfg.pll_p = pll_postdivs[((regval >> 11) & 0x3)];
+
+	return clk_check_pll_setup(inputclk, &pllcfg);
+}
+
+u32 clk_get_pclk_div(void)
+{
+	return 1 + ((readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)) >> 2) &
+		0x1F);
+}
+
+static struct map_desc lpc32xx_io_desc[] __initdata = {
+	{
+		.virtual	= io_p2v(AHB0_START),
+		.pfn		= __phys_to_pfn(AHB0_START),
+		.length		= AHB0_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= io_p2v(AHB1_START),
+		.pfn		= __phys_to_pfn(AHB1_START),
+		.length		= AHB1_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= io_p2v(FABAPB_START),
+		.pfn		= __phys_to_pfn(FABAPB_START),
+		.length		= FABAPB_SIZE,
+		.type		= MT_DEVICE
+	},
+	{
+		.virtual	= io_p2v(IRAM_BASE),
+		.pfn		= __phys_to_pfn(IRAM_BASE),
+		.length		= CONFIG_ARCH_LPC32XX_IRAM_SIZE,
+		.type		= MT_DEVICE
+	},
+};
+
+void __init lpc32xx_map_io(void)
+{
+	iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
+}
diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
new file mode 100644
index 0000000..ab8d2b2
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/common.h
@@ -0,0 +1,76 @@
+/*
+ * arch/arm/mach-lpc32xx/common.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2009-2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LPC32XX_COMMON_H
+#define __LPC32XX_COMMON_H
+
+#include <linux/platform_device.h>
+
+#define CLKPWR_IOBASE io_p2v(CLK_PM_BASE)
+
+/*
+ * Arch specific platform device structures
+ */
+extern struct platform_device watchdog_device;
+extern struct platform_device i2c0_device;
+extern struct platform_device i2c1_device;
+extern struct platform_device i2c2_device;
+
+/*
+ * Other arch specific structures and functions
+ */
+extern struct sys_timer lpc32xx_timer;
+extern void __init lpc32xx_init_irq(void);
+extern void __init lpc32xx_map_io(void);
+extern void __init lpc32xx_serial_init(void);
+extern void __init lpc32xx_gpio_init(void);
+
+/*
+ * Structure used for setting up and querying the PLLS
+ */
+struct clk_pll_setup {
+	int analog_on;
+	int cco_bypass_b15;
+	int direct_output_b14;
+	int fdbk_div_ctrl_b13;
+	int pll_p;
+	int pll_n;
+	u32 pll_m;
+};
+
+extern const u32 pll_postdivs[4];
+
+extern int clk_is_sysclk_mainosc(void);
+extern u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup);
+extern u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval);
+extern u32 clk_get_pclk_div(void);
+
+/*
+ * Returns the LPC32xx unique 128-bit chip ID
+ */
+extern void lpc32xx_get_uid(u32 devid[4]);
+
+#ifdef CONFIG_DEBUG_LL
+extern void printascii(const char *);
+#endif
+
+#endif
-- 
1.6.6

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (6 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 07/13] ARM: LPC32XX: common architecture functions and structures wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-01-28 17:07   ` Rabin Vincent
  2010-02-03 16:32   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 09/13] ARM: LPC32XX: power and event management wellsk40 at gmail.com
                   ` (6 subsequent siblings)
  14 siblings, 2 replies; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

LPC32XX clock control and query functions

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/clock.c | 1042 +++++++++++++++++++++++++++++++++++++++++
 arch/arm/mach-lpc32xx/clock.h |   41 ++
 2 files changed, 1083 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
new file mode 100644
index 0000000..615c091
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/clock.c
@@ -0,0 +1,1042 @@
+/*
+ * arch/arm/mach-lpc32xx/clock.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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
+ */
+
+/*
+ * LPC32xx clock mamagement driver overview
+ *
+ * The LPC32XX contains a number of high level system clocks that can be
+ * generated from different sources. These system clocks are used to
+ * generate the CPU and bus rates and the individual peripheral clocks in
+ * the system. When Linux is started by the boot loader, the system
+ * clocks are already running. Stopping a system clock during normal
+ * Linux operation should never be attempted, as peripherals that require
+ * those clocks will quit working (ie, DRAM).
+ *
+ * The LPC32xx high level clock tree looks as follows. Clocks marked with
+ * an asterisk are always on and cannot be disabled. Clocks marked with
+ * an ampersand can only be disabled in CPU suspend mode. Clocks marked
+ * with a carot are always on if it is the selected clock for the SYSCLK
+ * source. The clock that isn't used for SYSCLK can be enabled and
+ * disabled normally.
+ *                               32KHz oscillator*
+ *                               /      |      \
+ *                             RTC*   PLL397^ TOUCH
+ *                                     /
+ *               Main oscillator^     /
+ *                   |        \      /
+ *                   |         SYSCLK&
+ *                   |            \
+ *                   |             \
+ *                USB_PLL       HCLK_PLL&
+ *                   |           |    |
+ *            USB host/device  PCLK&  |
+ *                               |    |
+ *                             Peripherals
+ *
+ * The CPU and chip bus rates are derived from the HCLK PLL, which can
+ * generate various clock rates up to 266MHz and beyond. The internal bus
+ * rates (PCLK and HCLK) are generated from dividers based on the HCLK
+ * PLL rate. HCLK can be a ratio of 1:1, 1:2, or 1:4 or HCLK PLL rate,
+ * while PCLK can be 1:1 to 1:32 of HCLK PLL rate. Most peripherals high
+ * level clocks are based on either HCLK or PCLK, but have their own
+ * dividers as part of the IP itself. Because of this, the system clock
+ * rates should not be changed.
+ *
+ * The HCLK PLL is clocked from SYSCLK, which can be derived from the
+ * main oscillator or PLL397. PLL397 generates a rate that is 397 times
+ * the 32KHz oscillator rate. The main oscillator runs at the selected
+ * oscillator/crystal rate on the mosc_in pin of the LPC32xx. This rate
+ * is normally 13MHz, but depends on the selection of external crystals
+ * or oscillators. If USB operation is required, the main oscillator must
+ * be used in the system.
+ *
+ * Switching SYSCLK between sources during normal Linux operation is not
+ * supported. SYSCLK is preset in the bootloader. Because of the
+ * complexities of clock management during clock frequency changes,
+ * there are some limitations to the clock driver explained below:
+ * - The PLL397 and main oscillator can be enabled and disabled by the
+ *   clk_enable() and clk_disable() functions unless SYSCLK is based
+ *   on that clock. This allows the other oscillator that isn't driving
+ *   the HCLK PLL to be used as another system clock that can be routed
+ *   to an external pin.
+ * - The muxed SYSCLK input and HCLK_PLL rate cannot be changed with
+ *   this driver.
+ * - HCLK and PCLK rates cannot be changed as part of this driver.
+ * - Most peripherals have their own dividers are part of the peripheral
+ *   block. Changing SYSCLK, HCLK PLL, HCLK, or PCLK sources or rates
+ *   will also impact the individual peripheral rates.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+
+#include <mach/hardware.h>
+#include <asm/clkdev.h>
+#include <mach/clkdev.h>
+#include <mach/platform.h>
+#include "clock.h"
+#include "common.h"
+
+static struct clk clk_armpll;
+static struct clk clk_usbpll;
+
+/*
+ * Post divider values for PLLs based on selected register value
+ */
+const u32 pll_postdivs[4] = {1, 2, 4, 8};
+
+#define USB_OTG_IOBASE io_p2v(USB_BASE)
+
+/* 32KHz clock has a fixed rate and is not stoppable */
+static struct clk osc_32KHz = {
+	.rate		= CLOCK_OSC_FREQ,
+};
+
+static int local_pll397_enable(struct clk *clk, int enable)
+{
+	u32 reg;
+	unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+	reg = readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE));
+
+	if (enable == 0) 	{
+		reg |= CLKPWR_SYSCTRL_PLL397_DIS;
+		writel(reg, CLKPWR_PLL397_CTRL(CLKPWR_IOBASE));
+		clk->rate = 0;
+	} else {
+		/* Enable PLL397 */
+		reg &= ~CLKPWR_SYSCTRL_PLL397_DIS;
+		writel(reg, CLKPWR_PLL397_CTRL(CLKPWR_IOBASE));
+		clk->rate = CLOCK_OSC_FREQ * 397;
+
+		/* Wait for PLL397 lock */
+		while (((readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)) &
+			CLKPWR_SYSCTRL_PLL397_STS) == 0) &&
+			(timeout > jiffies))
+			cpu_relax();
+
+		if ((readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)) &
+			CLKPWR_SYSCTRL_PLL397_STS) == 0)
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
+static int local_oscmain_enable(struct clk *clk, int enable)
+{
+	u32 reg;
+	unsigned long timeout = 1 + msecs_to_jiffies(10);
+
+	reg = readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE));
+
+	if (enable == 0) {
+		reg |= CLKPWR_MOSC_DISABLE;
+		writel(reg, CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE));
+		clk->rate = 0;
+	} else {
+		/* Enable main oscillator */
+		reg &= ~CLKPWR_MOSC_DISABLE;
+		writel(reg, CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE));
+		clk->rate = MAIN_OSC_FREQ;
+
+		/* Wait for main oscillator to start */
+		while (((readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)) &
+			CLKPWR_MOSC_DISABLE) != 0) &&
+			(timeout > jiffies))
+			cpu_relax();
+
+		if ((readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)) &
+			CLKPWR_MOSC_DISABLE) != 0)
+			return -ENODEV;
+	}
+
+	return 0;
+}
+
+static struct clk osc_pll397 = {
+	.parent		= &osc_32KHz,
+	.enable		= &local_pll397_enable,
+	.rate		= CLOCK_OSC_FREQ * 397,
+};
+
+static struct clk osc_main = {
+	.enable		= &local_oscmain_enable,
+	.rate		= MAIN_OSC_FREQ,
+};
+
+static struct clk clk_sys;
+
+/*
+ * Setup the HCLK PLL with a PLL structure
+ */
+static u32 local_clk_pll_setup(struct clk_pll_setup *PllSetup)
+{
+	u32 tv, tmp = 0;
+
+	if (PllSetup->analog_on != 0)
+		tmp |= CLKPWR_HCLKPLL_POWER_UP;
+	if (PllSetup->cco_bypass_b15 != 0)
+		tmp |= CLKPWR_HCLKPLL_CCO_BYPASS;
+	if (PllSetup->direct_output_b14 != 0)
+		tmp |= CLKPWR_HCLKPLL_POSTDIV_BYPASS;
+	if (PllSetup->fdbk_div_ctrl_b13 != 0)
+		tmp |= CLKPWR_HCLKPLL_FDBK_SEL_FCLK;
+
+	switch (PllSetup->pll_p) {
+	case 1:
+		tv = 0;
+		break;
+
+	case 2:
+		tv = 1;
+		break;
+
+	case 4:
+		tv = 2;
+		break;
+
+	case 8:
+		tv = 3;
+		break;
+
+	default:
+		return 0;
+	}
+
+	tmp |= CLKPWR_HCLKPLL_POSTDIV_2POW(tv);
+	tmp |= CLKPWR_HCLKPLL_PREDIV_PLUS1(PllSetup->pll_n - 1);
+	tmp |= CLKPWR_HCLKPLL_PLLM(PllSetup->pll_m - 1);
+
+	return tmp;
+}
+
+/*
+ * Update the ARM core PLL frequency rate variable from the actual PLL setting
+ */
+static void local_update_armpll_rate(void)
+{
+	u32 clkin, pllreg;
+
+	clkin = clk_armpll.parent->rate;
+	pllreg = readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & 0x1FFFF;
+
+	clk_armpll.rate = clk_get_pllrate_from_reg(clkin, pllreg);
+}
+
+static int clkpwr_abs(int v1, int v2)
+{
+	if (v1 > v2)
+		return v1 - v2;
+
+	return v2 - v1;
+}
+
+/*
+ * Find a PLL configuration for the selected input frequency
+ */
+static u32 local_clk_find_pll_cfg(u32 pllin_freq, u32 target_freq,
+	struct clk_pll_setup *pllsetup)
+{
+	u32 ifreq, freqtol, m, n, p, fclkout = 0;
+	u32 flag = 0, freqret = 0;
+
+	/* Determine frequency tolerance limits */
+	freqtol = target_freq / 250;
+	ifreq = pllin_freq;
+
+	/* Is direct bypass mode possible? */
+	if (clkpwr_abs(pllin_freq, target_freq) <= freqtol) {
+		flag = 1;
+		pllsetup->analog_on = 0;
+		pllsetup->cco_bypass_b15 = 1;
+		pllsetup->direct_output_b14 = 1;
+		pllsetup->fdbk_div_ctrl_b13 = 1;
+		pllsetup->pll_p = pll_postdivs[0];
+		pllsetup->pll_n = 1;
+		pllsetup->pll_m = 1;
+		fclkout = clk_check_pll_setup(ifreq, pllsetup);
+	} else if (target_freq <= ifreq) {
+		pllsetup->analog_on = 0;
+		pllsetup->cco_bypass_b15 = 1;
+		pllsetup->direct_output_b14 = 0;
+		pllsetup->fdbk_div_ctrl_b13 = 1;
+		pllsetup->pll_n = 1;
+		pllsetup->pll_m = 1;
+		for (p = 0; ((p <= 3) && (flag == 0)); p++) {
+			pllsetup->pll_p = pll_postdivs[p];
+			fclkout = clk_check_pll_setup(ifreq, pllsetup);
+			if (clkpwr_abs(target_freq, fclkout) <= freqtol)
+				flag = 1;
+		}
+	}
+
+	/* Is direct mode possible? */
+	if (flag == 0) {
+		pllsetup->analog_on = 1;
+		pllsetup->cco_bypass_b15 = 0;
+		pllsetup->direct_output_b14 = 1;
+		pllsetup->fdbk_div_ctrl_b13 = 0;
+		pllsetup->pll_p = pll_postdivs[0];
+		for (m = 1; ((m <= 256) && (flag == 0)); m++) {
+			for (n = 1; ((n <= 4) && (flag == 0)); n++) {
+				/* Compute output frequency for this value */
+				pllsetup->pll_n = n;
+				pllsetup->pll_m = m;
+				fclkout = clk_check_pll_setup(ifreq,
+					pllsetup);
+				if (clkpwr_abs(target_freq, fclkout) <=
+					freqtol)
+					flag = 1;
+			}
+		}
+	}
+
+	/* Is integer mode possible? */
+	if (flag == 0) {
+		pllsetup->analog_on = 1;
+		pllsetup->cco_bypass_b15 = 0;
+		pllsetup->direct_output_b14 = 0;
+		pllsetup->fdbk_div_ctrl_b13 = 1;
+		for (m = 1; ((m <= 256) && (flag == 0)); m++) {
+			for (n = 1; ((n <= 4) && (flag == 0)); n++) {
+				for (p = 0; ((p < 4) && (flag == 0)); p++) {
+					/* Compute output frequency */
+					pllsetup->pll_p = pll_postdivs[p];
+					pllsetup->pll_n = n;
+					pllsetup->pll_m = m;
+					fclkout = clk_check_pll_setup(
+						ifreq, pllsetup);
+					if (clkpwr_abs(target_freq,
+						fclkout) <= freqtol)
+						flag = 1;
+				}
+			}
+		}
+	}
+
+	if (flag == 0)  {
+		/* Try non-integer mode */
+		pllsetup->analog_on = 1;
+		pllsetup->cco_bypass_b15 = 0;
+		pllsetup->direct_output_b14 = 0;
+		pllsetup->fdbk_div_ctrl_b13 = 0;
+		for (m = 1; ((m <= 256) && (flag == 0)); m++) {
+			for (n = 1; ((n <= 4) && (flag == 0)); n++) {
+				for (p = 0; ((p < 4) && (flag == 0)); p++) {
+					/* Compute output frequency */
+					pllsetup->pll_p = pll_postdivs[p];
+					pllsetup->pll_n = n;
+					pllsetup->pll_m = m;
+					fclkout = clk_check_pll_setup(
+						ifreq, pllsetup);
+					if (clkpwr_abs(target_freq,
+						fclkout) <= freqtol)
+						flag = 1;
+				}
+			}
+		}
+	}
+
+	if (flag == 1)
+		freqret = fclkout;
+
+	return freqret;
+}
+
+static struct clk clk_armpll = {
+	.parent		= &clk_sys,
+};
+
+/*
+ * Update the USB PLL frequency rate variable from the actual PLL setting
+ */
+static void local_update_usbpll_rate(void)
+{
+	u32 clkin, pllreg;
+
+	clkin = (u32) clk_get_rate(&clk_usbpll);
+	pllreg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)) & 0x1FFFF;
+
+	if ((pllreg & CLKPWR_USBCTRL_PLL_PWRUP) == 0)
+		clk_usbpll.rate = 0;
+	else
+		clk_usbpll.rate = clk_get_pllrate_from_reg(clkin,
+			pllreg);
+}
+
+/*
+ * Setup the USB PLL with a PLL structure
+ */
+static u32 local_clk_usbpll_setup(struct clk_pll_setup *pHCLKPllSetup)
+{
+	u32 reg, tmp = local_clk_pll_setup(pHCLKPllSetup);
+
+	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)) & ~0x1FFFF;
+	reg |= tmp;
+	writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+
+	return clk_check_pll_setup(clk_usbpll.parent->rate,
+		pHCLKPllSetup);
+}
+
+static int local_usbpll_enable(struct clk *clk, int enable)
+{
+	u32 reg;
+	int ret = -ENODEV, qj = (jiffies / 4);
+
+	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+
+	if (enable == 0) {
+		reg &= ~(CLKPWR_USBCTRL_CLK_EN1 | CLKPWR_USBCTRL_CLK_EN2);
+		writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+	} else if (reg & CLKPWR_USBCTRL_PLL_PWRUP) {
+		reg |= CLKPWR_USBCTRL_CLK_EN1;
+		writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+
+		/* Wait for PLL lock */
+		while (qj < jiffies) {
+			reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+			if (reg & CLKPWR_USBCTRL_PLL_STS)
+				ret = 0;
+		}
+
+		if (ret == 0) {
+			reg |= CLKPWR_USBCTRL_CLK_EN2;
+			writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+		}
+	}
+
+	return ret;
+}
+
+static int local_usbpll_set_rate(struct clk *clk, u32 rate)
+{
+	u32 clkin, reg, usbdiv;
+	struct clk_pll_setup pllsetup;
+
+	/* Unlike other clocks, this clock has a KHz input rate, so bump
+	   it up to work with the PLL function */
+	rate = rate * 1000;
+
+	local_usbpll_enable(clk, 0);
+
+	if (rate == 0)
+		return 0;
+
+	clkin = clk->parent->rate;
+	usbdiv = readl(CLKPWR_USBCLK_PDIV(CLKPWR_IOBASE)) + 1;
+	clkin = clkin / usbdiv;
+
+	/* Try to find a good rate setup */
+	if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
+		return -EINVAL;
+
+	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+	reg |= CLKPWR_USBCTRL_CLK_EN1;
+	writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+
+	pllsetup.analog_on = 1;
+	local_clk_usbpll_setup(&pllsetup);
+
+	clk->rate = clk_check_pll_setup(clkin, &pllsetup);
+
+	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+	reg |= CLKPWR_USBCTRL_CLK_EN2;
+	writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
+
+	return 0;
+}
+
+static struct clk clk_usbpll = {
+	.parent		= &osc_main,
+	.set_rate	= &local_usbpll_set_rate,
+	.enable		= &local_usbpll_enable,
+};
+
+static u32 clk_get_hclk_div(void)
+{
+	static const u32 hclkdivs[4] = {1, 2, 4, 4};
+	return hclkdivs[CLKPWR_HCLKDIV_DIV_2POW(
+		readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)))];
+}
+
+static struct clk clk_hclk = {
+	.parent		= &clk_armpll,
+};
+
+static struct clk clk_pclk = {
+	.parent		= &clk_armpll,
+};
+
+static int local_onoff_enable(struct clk *clk, int enable)
+{
+	u32 tmp;
+
+	tmp = readl(clk->enable_reg);
+
+	if (enable == 0)
+		tmp &= ~clk->enable_mask;
+	else
+		tmp |= clk->enable_mask;
+
+	writel(tmp, clk->enable_reg);
+
+	return 0;
+}
+
+/* Peripheral clock sources */
+static struct clk clk_timer0 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER0_EN,
+};
+static struct clk clk_timer1 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER1_EN,
+};
+static struct clk clk_timer2 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER2_EN,
+};
+static struct clk clk_timer3 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER3_EN,
+};
+static struct clk clk_wdt = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_TIMER_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_PWMCLK_WDOG_EN,
+};
+static struct clk clk_vfp9 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_DEBUG_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_VFP_CLOCK_ENABLE_BIT,
+};
+static struct clk clk_dma = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_DMA_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_DMACLKCTRL_CLK_EN,
+};
+
+static struct clk clk_uart3 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_UARTCLKCTRL_UART3_EN,
+};
+
+static struct clk clk_uart4 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_UARTCLKCTRL_UART4_EN,
+};
+
+static struct clk clk_uart5 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_UARTCLKCTRL_UART5_EN,
+};
+
+static struct clk clk_uart6 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_UARTCLKCTRL_UART6_EN,
+};
+
+static struct clk clk_i2c0 = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_I2CCLK_I2C1CLK_EN,
+};
+
+static struct clk clk_i2c1 = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_I2CCLK_I2C2CLK_EN,
+};
+
+static struct clk clk_i2c2 = {
+	.parent		= &clk_pclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= USB_OTG_IOBASE + 0xFF4,
+	.enable_mask	= 0x4,
+};
+
+static struct clk clk_ssp0 = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_SSPCTRL_SSPCLK0_EN,
+};
+static struct clk clk_ssp1 = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_SSPCTRL_SSPCLK1_EN,
+};
+
+static struct clk clk_kscan = {
+	.parent		= &osc_32KHz,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_KEY_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_KEYCLKCTRL_CLK_EN,
+};
+
+static struct clk clk_nand = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_NAND_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_NANDCLK_SLCCLK_EN,
+};
+
+static struct clk clk_i2s0 = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_I2SCTRL_I2SCLK0_EN,
+};
+static struct clk clk_i2s1 = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_I2SCTRL_I2SCLK1_EN,
+};
+
+static struct clk clk_net = {
+	.parent		= &clk_hclk,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_MACCLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= (CLKPWR_MACCTRL_DMACLK_EN |
+		CLKPWR_MACCTRL_MMIOCLK_EN | CLKPWR_MACCTRL_HRCCLK_EN),
+};
+
+static struct clk clk_rtc = {
+	.parent		= &osc_32KHz,
+	.rate		= 1, /* 1 Hz */
+};
+
+static struct clk clk_usbd = {
+	.parent		= &clk_usbpll,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_USB_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_USBCTRL_HCLK_EN,
+};
+
+static int tsc_onoff_enable(struct clk *clk, int enable)
+{
+	u32 tmp;
+
+	/* Make sure 32KHz clock is the selected clock */
+	tmp = readl(CLKPWR_ADC_CLK_CTRL_1(CLKPWR_IOBASE));
+	tmp &= ~CLKPWR_ADCCTRL1_PCLK_SEL;
+	writel(tmp, CLKPWR_ADC_CLK_CTRL_1(CLKPWR_IOBASE));
+
+	if (enable == 0)
+		writel(0, clk->enable_reg);
+	else
+		writel(clk->enable_mask, clk->enable_reg);
+
+	return 0;
+}
+
+static struct clk clk_tsc = {
+	.parent		= &osc_32KHz,
+	.enable		= &tsc_onoff_enable,
+	.enable_reg	= CLKPWR_ADC_CLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_ADC32CLKCTRL_CLK_EN,
+};
+
+static int mmc_onoff_enable(struct clk *clk, int enable)
+{
+	u32 tmp;
+
+	tmp = readl(CLKPWR_MS_CTRL(CLKPWR_IOBASE)) &
+		~(CLKPWR_MSCARD_SDCARD_EN|CLKPWR_MSCARD_SDCARD_DIV(15));
+
+	/* If rate is 0, disable clock */
+	if (enable != 0)
+		tmp |= CLKPWR_MSCARD_SDCARD_EN | CLKPWR_MSCARD_SDCARD_DIV(1);
+
+	writel(tmp, CLKPWR_MS_CTRL(CLKPWR_IOBASE));
+
+	return 0;
+}
+
+static u32 mmc_get_rate(struct clk *clk)
+{
+	u32 div, tmp, rate;
+
+	div = readl(CLKPWR_MS_CTRL(CLKPWR_IOBASE));
+	tmp = div & CLKPWR_MSCARD_SDCARD_EN;
+
+	if (!tmp)
+		return 0;
+
+	/* Get the parent clock rate */
+	rate = clk_get_rate(clk->parent);
+
+	/* Get the LCD controller clock divider value */
+	div = div & 0xF;
+
+	if (!div)
+		return 0;
+
+	tmp = rate / div;
+
+	return tmp;
+}
+
+static int mmc_set_rate(struct clk *clk, u32 rate)
+{
+	if (rate == 0)
+		mmc_onoff_enable(clk, 0);
+	else
+		mmc_onoff_enable(clk, 1);
+
+	return 0;
+}
+
+static struct clk clk_mmc = {
+	.parent		= &clk_armpll,
+	.set_rate	= &mmc_set_rate,
+	.get_rate	= &mmc_get_rate,
+	.enable		= &mmc_onoff_enable,
+	.enable_reg	= CLKPWR_MS_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_MSCARD_SDCARD_EN,
+};
+
+static u32 clcd_get_rate(struct clk *clk)
+{
+	u32 tmp, div, rate;
+
+	tmp = readl(CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)) &
+		CLKPWR_LCDCTRL_CLK_EN;
+
+	if (!tmp)
+		return 0;
+
+	rate = clk_get_rate(clk->parent);
+	tmp = readl((io_p2v(LCD_BASE)) + CLCD_TIM2);
+
+	/* Only supports internal clocking */
+	if (tmp & TIM2_BCD)
+		return rate;
+
+	div = (tmp & 0x1F) | ((tmp & 0xF8) >> 22);
+	tmp = rate / (2 + div);
+
+	return tmp;
+}
+
+static int clcd_set_rate(struct clk *clk, u32 rate)
+{
+	u32 tmp, prate, div;
+
+	tmp = readl((io_p2v(LCD_BASE)) + CLCD_TIM2);
+	prate = clk_get_rate(clk->parent);
+
+	if (rate == prate) {
+		tmp |= TIM2_BCD;
+		local_onoff_enable(clk, 1);
+	} else {
+		/* Find closest divider */
+		div = prate / rate;
+		if (div == 1)
+			div = 0;
+		else
+			div -= 2;
+
+		tmp &= ~(0xF800001F);
+		tmp &= ~TIM2_BCD;
+		tmp |= (div & 0x1F);
+		tmp |= (((div >> 5) & 0x1F) << 27);
+		writel(tmp, ((io_p2v(LCD_BASE)) + CLCD_TIM2));
+		local_onoff_enable(clk, 1);
+	}
+
+	return 0;
+}
+static struct clk clk_lcd = {
+	.parent		= &clk_hclk,
+	.set_rate	= &clcd_set_rate,
+	.get_rate	= &clcd_get_rate,
+	.enable		= &local_onoff_enable,
+	.enable_reg	= CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE),
+	.enable_mask	= CLKPWR_LCDCTRL_CLK_EN,
+};
+
+static inline void clk_lock(void)
+{
+	local_irq_disable();
+}
+
+static inline void clk_unlock(void)
+{
+	local_irq_enable();
+}
+
+static void local_clk_disable(struct clk *clk)
+{
+	/* Don't attempt to disable clock if it has no users */
+	if (clk->usecount > 0) {
+		clk->usecount--;
+
+		/* Only disable clock when it has no more users */
+		if ((clk->usecount == 0) && (clk->enable))
+			clk->enable(clk, 0);
+
+		/* Check parent clocks, they may need to be disabled too */
+		if (clk->parent)
+			local_clk_disable(clk->parent);
+	}
+}
+
+static int local_clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (clk->usecount == 0) {
+		/* Enable parent clocks first */
+		if (clk->parent)
+			ret = local_clk_enable(clk->parent);
+
+		/* Enable clock on first use */
+		if ((ret == 0) && (clk->enable)) {
+			ret = clk->enable(clk, 1);
+			clk->usecount++;
+		}
+
+		/* Back out use counters if enable fails */
+		if (ret < 0)
+			local_clk_disable(clk);
+	}
+
+	return ret;
+}
+
+/*
+ * clk_enable - inform the system when the clock source should be running.
+ */
+int clk_enable(struct clk *clk)
+{
+	int ret;
+
+	clk_lock();
+	ret = local_clk_enable(clk);
+	clk_unlock();
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_enable);
+
+/*
+ * clk_disable - inform the system when the clock source is no longer required
+ */
+void clk_disable(struct clk *clk)
+{
+	clk_lock();
+	local_clk_disable(clk);
+	clk_unlock();
+}
+EXPORT_SYMBOL(clk_disable);
+
+/*
+ * clk_get_rate - obtain the current clock rate (in Hz) for a clock source
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+	if (clk->get_rate)
+		return (clk->get_rate)(clk);
+
+	/* If a clocks rate is 0, it uses the parent's rate instead. */
+	while (clk->rate == 0)
+		clk = clk->parent;
+
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_get_rate);
+
+/*
+ * clk_set_rate - set the clock rate for a clock source
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = -EINVAL;
+
+	/* Most system clocks can only be enabled or disabled, with
+	   the actual rate set as part of the peripheral dividers
+	   instead of high level clock control */
+	if (clk->set_rate) {
+		clk_lock();
+		ret = (clk->set_rate)(clk, rate);
+		clk_unlock();
+	}
+
+	return ret;
+}
+EXPORT_SYMBOL(clk_set_rate);
+
+/*
+ * clk_round_rate - adjust a rate to the exact rate a clock can provide
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	int ret;
+
+	/* Use set_rate to try to adjust the rate if it supports it */
+	ret = clk_set_rate(clk, rate);
+	if (ret < 0)
+		return (long) ret;
+
+	return clk->rate;
+}
+EXPORT_SYMBOL(clk_round_rate);
+
+/*
+ * clk_set_parent - set the parent clock source for this clock
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	/* Clock re-parenting is not supported */
+	return -EINVAL;
+}
+EXPORT_SYMBOL(clk_set_parent);
+
+/*
+ * clk_get_parent - get the parent clock source for this clock
+ */
+struct clk *clk_get_parent(struct clk *clk)
+{
+	return clk->parent;
+}
+EXPORT_SYMBOL(clk_get_parent);
+
+#define _REGISTER_CLOCK(d, n, c) \
+	{ \
+		.dev_id = (d), \
+		.con_id = (n), \
+		.clk = &(c), \
+	},
+
+static struct clk_lookup lookups[] __initdata = {
+	_REGISTER_CLOCK(NULL, "osc_32KHz", osc_32KHz)
+	_REGISTER_CLOCK(NULL, "osc_pll397", osc_pll397)
+	_REGISTER_CLOCK(NULL, "osc_main", osc_main)
+	_REGISTER_CLOCK(NULL, "sys_ck", clk_sys)
+	_REGISTER_CLOCK(NULL, "arm_pll_ck", clk_armpll)
+	_REGISTER_CLOCK(NULL, "ck_pll5", clk_usbpll)
+	_REGISTER_CLOCK(NULL, "hclk_ck", clk_hclk)
+	_REGISTER_CLOCK(NULL, "pclk_ck", clk_pclk)
+	_REGISTER_CLOCK(NULL, "timer0_ck", clk_timer0)
+	_REGISTER_CLOCK(NULL, "timer1_ck", clk_timer1)
+	_REGISTER_CLOCK(NULL, "timer2_ck", clk_timer2)
+	_REGISTER_CLOCK(NULL, "timer3_ck", clk_timer3)
+	_REGISTER_CLOCK(NULL, "vfp9_ck", clk_vfp9)
+	_REGISTER_CLOCK(NULL, "clk_dmac", clk_dma)
+	_REGISTER_CLOCK("pnx4008-watchdog", NULL, clk_wdt)
+	_REGISTER_CLOCK(NULL, "uart3_ck", clk_uart3)
+	_REGISTER_CLOCK(NULL, "uart4_ck", clk_uart4)
+	_REGISTER_CLOCK(NULL, "uart5_ck", clk_uart5)
+	_REGISTER_CLOCK(NULL, "uart6_ck", clk_uart6)
+	_REGISTER_CLOCK("pnx-i2c.0", NULL, clk_i2c0)
+	_REGISTER_CLOCK("pnx-i2c.1", NULL, clk_i2c1)
+	_REGISTER_CLOCK("pnx-i2c.2", NULL, clk_i2c2)
+	_REGISTER_CLOCK("dev:ssp0", NULL, clk_ssp0)
+	_REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
+	_REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
+	_REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
+	_REGISTER_CLOCK("tbd", "i2s0_ck", clk_i2s0)
+	_REGISTER_CLOCK("tbd", "i2s1_ck", clk_i2s1)
+	_REGISTER_CLOCK("lpc32xx-ts", NULL, clk_tsc)
+	_REGISTER_CLOCK("dev:mmc0", "MCLK", clk_mmc)
+	_REGISTER_CLOCK("lpc-net.0", NULL, clk_net)
+	_REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
+	_REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
+	_REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc)
+};
+
+int __init clk_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(lookups); i++)
+		clkdev_add(&lookups[i]);
+
+	/* Setup muxed SYSCLK for HCLK PLL base -this selects the
+	   parent clock used for the ARM PLL and is used to derive
+	   the many system clock rates in the device. */
+	if (clk_is_sysclk_mainosc() != 0)
+		clk_sys.parent = &osc_main;
+	else
+		clk_sys.parent = &osc_pll397;
+
+	clk_sys.rate = clk_sys.parent->rate;
+
+	/* Compute the current ARM PLL and USB PLL frequencies */
+	local_update_armpll_rate();
+	local_update_usbpll_rate();
+
+	/* Compute HCLK and PCLK bus rates */
+	clk_hclk.rate = clk_hclk.parent->rate / clk_get_hclk_div();
+	clk_pclk.rate = clk_pclk.parent->rate / clk_get_pclk_div();
+
+	/* Enable system clocks - this step is somewhat formal, as the
+	   clocks are already running, but it does get the clock data
+	   inline with the actual system state. Never disable these
+	   clocks as they will only stop if the system is going to sleep.
+	   In that case, the chip/system power management functions will
+	   handle clock gating. */
+	clk_enable(&clk_hclk);
+	clk_enable(&clk_pclk);
+
+	/* Timers 0 and 1 were enabled and are being used by the high
+	   resolution tick function prior to this driver being initialized.
+	   Tag them now as used */
+	clk_enable(&clk_timer0);
+	clk_enable(&clk_timer1);
+
+	return 0;
+}
+core_initcall(clk_init);
+
diff --git a/arch/arm/mach-lpc32xx/clock.h b/arch/arm/mach-lpc32xx/clock.h
new file mode 100644
index 0000000..f37f245
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/clock.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/mach-lpc32xx/clock.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LPC32XX_CLOCK_H
+#define __LPC32XX_CLOCK_H
+
+struct clk {
+	struct list_head node;
+	struct clk *parent;
+	u32 rate;
+	s8 usecount;
+
+	int (*set_rate) (struct clk *, u32);
+	int (*enable) (struct clk *clk, int);
+	u32 (*get_rate) (struct clk *clk);
+
+	/* Register address and bit mask for simple clocks */
+	u32 enable_reg;
+	u32 enable_mask;
+};
+
+#endif
-- 
1.6.6

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

* [PATCH 09/13] ARM: LPC32XX: power and event management
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (7 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 08/13] ARM: LPC32XX: clock tree support wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-02-03 16:44   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 10/13] ARM: LPC32XX: Phytec PHY3250 platform support file wellsk40 at gmail.com
                   ` (5 subsequent siblings)
  14 siblings, 1 reply; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

Power mode suspend code and event management code used for device,
system, and memory sleep/wakeup

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/pm.c        |  170 +++++++++++++++
 arch/arm/mach-lpc32xx/pm.h        |  140 ++++++++++++
 arch/arm/mach-lpc32xx/pm_events.c |  426 +++++++++++++++++++++++++++++++++++++
 arch/arm/mach-lpc32xx/suspend.S   |  155 ++++++++++++++
 4 files changed, 891 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/pm.c b/arch/arm/mach-lpc32xx/pm.c
new file mode 100644
index 0000000..8535e99
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/pm.c
@@ -0,0 +1,170 @@
+/*
+ * arch/arm/mach-lpc32xx/pm.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ * Based in part on PNX4008 power management code
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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
+ */
+
+/*
+ * LPC32XX CPU and system power management
+ *
+ * The LCP32XX has three CPU modes for controlling system power: run,
+ * direct-run, and halt modes. When switching between halt and run modes,
+ * the CPU transistions through direct-run mode. For Linux, direct-run
+ * mode is not used in normal operation. Halt mode is used when the
+ * system is fully suspended.
+ *
+ * Run mode:
+ * The ARM CPU clock (HCLK_PLL), HCLK bus clock, and PCLK bus clocks are
+ * derived from the HCLK PLL. The HCLK and PCLK bus rates are divided from
+ * the HCLK_PLL rate. Linux runs in this mode.
+ *
+ * Direct-run mode:
+ * The ARM CPU clock, HCLK bus clock, and PCLK bus clocks are driven from
+ * SYSCLK. SYSCLK is usually around 13MHz, but may vary based on SYSCLK
+ * source or the frequency of the main oscillator. In this mode, the
+ * HCLK_PLL can be safely enabled, changed, or disabled.
+ *
+ * Halt mode:
+ * SYSCLK is gated off and the CPU and system clocks are halted.
+ * Peripherals based on the 32KHz oscillator clock (ie, RTC, touch,
+ * key scanner, etc.) still operate if enabled. In this state, an enabled
+ * system event (ie, GPIO state change, RTC match, key press, etc.) will
+ * wake the system up back into direct-run mode.
+ *
+ * DRAM refresh
+ * DRAM clocking and refresh are slightly different for systems with DDR
+ * DRAM or regular SDRAM devices. If SDRAM is used in the system, the
+ * SDRAM will still be accessible in direct-run mode. In DDR based systems,
+ * a transistion to direct-run mode will stop all DDR accesses (no clocks).
+ * Because of this, the code to switch power modes and the code to enter
+ * and exit DRAM self-refresh modes must not be executed in DRAM. A small
+ * section of IRAM is used instead for this.
+ *
+ * Suspend is handled with the following logic:
+ *  Backup a small area of IRAM used for the suspend code
+ *  Copy suspend code to IRAM
+ *  Transfer control to code in IRAM
+ *  Places DRAMs in self-refresh mode
+ *  Enter direct-run mode
+ *  Save state of HCLK_PLL PLL
+ *  Disable HCLK_PLL PLL
+ *  Enter halt mode - CPU and buses will stop
+ *  System enters direct-run mode when an enabled event occurs
+ *  HCLK PLL state is restored
+ *  Run mode is entered
+ *  DRAMS are placed back into normal mode
+ *  Code execution returns from IRAM
+ *  IRAM code are used for suspend is restored
+ *  Suspend mode is exited
+ */
+
+#include <linux/suspend.h>
+#include <linux/io.h>
+
+#include <asm/irq.h>
+#include <asm/atomic.h>
+#include <asm/mach/time.h>
+#include <asm/mach/irq.h>
+#include <asm/cacheflush.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+#include "clock.h"
+#include "pm.h"
+
+#define TEMP_IRAM_AREA  io_p2v(IRAM_BASE)
+
+static void *iram_swap_area;
+
+static int lpc32xx_pm_valid_state(suspend_state_t state)
+{
+	return (state == PM_SUSPEND_STANDBY) ||
+	       (state == PM_SUSPEND_MEM);
+}
+
+/*
+ * Both STANDBY and MEM suspend states are handled the same with no
+ * loss of CPU or memory state
+ */
+static int lpc32xx_pm_enter(suspend_state_t state)
+{
+	int (*lpc32xx_suspend_ptr) (void);
+
+	if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY) {
+		/* The CPU and MEM suspend code do the same thing. Wakeup
+		   from both states is very quick. */
+
+		/* Backup a small area of IRAM used for the suspend code */
+		memcpy(iram_swap_area, (void *) TEMP_IRAM_AREA,
+			lpc32xx_sys_suspend_sz);
+		flush_cache_all();
+
+		/* Copy code to suspend system into IRAM. The suspend code
+		   needs to run from IRAM as DRAM may no longer be available
+		   when the PLL is stopped. */
+		memcpy((void *) TEMP_IRAM_AREA, &lpc32xx_sys_suspend,
+			lpc32xx_sys_suspend_sz);
+
+		/* Transfer to suspend code in IRAM */
+		lpc32xx_suspend_ptr = (void *) TEMP_IRAM_AREA;
+		(void) lpc32xx_suspend_ptr();
+
+		/* Restore original IRAM contents */
+		memcpy((void *) TEMP_IRAM_AREA, iram_swap_area,
+			lpc32xx_sys_suspend_sz);
+	} else
+		return -ENOTSUPP;
+
+	/* Clear any pending wakeup events */
+	lpc32xx_event_clear_all();
+
+	return 0;
+}
+
+static struct platform_suspend_ops lpc32xx_pm_ops = {
+	.valid	= lpc32xx_pm_valid_state,
+	.enter	= lpc32xx_pm_enter,
+};
+
+#define EMC_DYN_MEM_CTRL_OFS 0x20
+#define EMC_SRMMC           (1 << 3)
+
+static int __init lpc32xx_pm_init(void)
+{
+	/* Setup SDRAM self-refresh clock to automatically
+	   disable on start of self-refresh */
+	writel(readl(io_p2v(EMC_BASE) + EMC_DYN_MEM_CTRL_OFS) | EMC_SRMMC,
+		io_p2v(EMC_BASE) + EMC_DYN_MEM_CTRL_OFS);
+
+	/* Allocate some space for temporary IRAM storage */
+	iram_swap_area = kmalloc(lpc32xx_sys_suspend_sz, GFP_ATOMIC);
+	if (!iram_swap_area) {
+		printk(KERN_ERR
+		       "PM Suspend: cannot allocate memory to save portion "
+			"of SRAM\n");
+		return -ENOMEM;
+	}
+
+	suspend_set_ops(&lpc32xx_pm_ops);
+
+	return 0;
+}
+arch_initcall(lpc32xx_pm_init);
diff --git a/arch/arm/mach-lpc32xx/pm.h b/arch/arm/mach-lpc32xx/pm.h
new file mode 100644
index 0000000..9d7d548
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/pm.h
@@ -0,0 +1,140 @@
+/*
+ * arch/arm/mach-lpc32xx/pm.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __LPC32XX__PM_H
+#define __LPC32XX__PM_H
+
+/*
+ * This file allows the enable and disable of events that can wake up
+ * the system when in sleep mode. Events fire on either the low or
+ * high edge transistion and can be configured in hardware.
+ */
+
+enum lpc32xx_events {
+	/* For the following group, an active transistion on the pin
+	   associated with the event will wakeup the chip if the
+	   event is enabled. */
+	LPC32XX_WKUP_GPI_08,
+	LPC32XX_WKUP_GPI_09,
+	LPC32XX_WKUP_GPI_19,
+	LPC32XX_WKUP_SPI2_DATIN,
+	LPC32XX_WKUP_GPI_07,
+	LPC32XX_WKUP_SPI1_DATIN,
+	LPC32XX_WKUP_SYSCLKEN,
+	LPC32XX_WKUP_GPI00, /* Input mode only */
+	LPC32XX_WKUP_GPI01, /* Input mode only */
+	LPC32XX_WKUP_GPI02, /* Input mode only */
+	LPC32XX_WKUP_GPI03, /* Input mode only */
+	LPC32XX_WKUP_GPI04, /* Input mode only */
+	LPC32XX_WKUP_GPI05, /* Input mode only */
+	LPC32XX_WKUP_GPI06, /* Input mode only */
+	LPC32XX_WKUP_MSDIO_START, /* All SD data signals Or'ed */
+	LPC32XX_WKUP_SDIO_INT_N, /* SDIO D1 only */
+	LPC32XX_WKUP_U1_RX,
+	LPC32XX_WKUP_U2_RX,
+	LPC32XX_WKUP_U2_HCTS,
+	LPC32XX_WKUP_U3_RX,
+	LPC32XX_WKUP_GPI_28,
+	LPC32XX_WKUP_U5_RX,
+	LPC32XX_WKUP_U6_IRRX,
+	LPC32XX_WKUP_U7_HCTS,
+	LPC32XX_WKUP_U7_RX,
+
+	/* For the following group, an interrupt for the peripheral
+	   will wakeup the chip if the event is enabled. */
+	LPC32XX_WKUP_GPIO_00,
+	LPC32XX_WKUP_GPIO_01,
+	LPC32XX_WKUP_GPIO_02,
+	LPC32XX_WKUP_GPIO_03,
+	LPC32XX_WKUP_GPIO_04,
+	LPC32XX_WKUP_GPIO_05,
+	LPC32XX_WKUP_P0_P1_ALL, /* One or more sources in P0/P1 */
+	LPC32XX_WKUP_MAC_START,
+	LPC32XX_WKUP_KEY_IRQ,
+	LPC32XX_WKUP_USB_OTG_ATX_INT_N,
+	LPC32XX_WKUP_USB_OTG_TIMER,
+	LPC32XX_WKUP_USB_I2C_INT,
+	LPC32XX_WKUP_USB_INT,
+	LPC32XX_WKUP_USB_NEED_CLK,
+	LPC32XX_WKUP_RTC_INT,
+	LPC32XX_WKUP_MSTIMER_INT,
+	LPC32XX_WKUP_USB_AHC_NEED_CLK,
+	LPC32XX_WKUP_TS_AUX_INT,
+	LPC32XX_WKUP_TS_P_INT,
+	LPC32XX_WKUP_TS_INT,
+
+	/* P0/P1 group signals. These signals are all routed through the
+	   LPC32XX_WKUP_P0_P1_ALL event in the previous group, so be sure
+	   to enable LPC32XX_WKUP_P0_P1_ALL if any of these are used. Any
+	   one enabled and active event will generate the
+	   LPC32XX_WKUP_P0_P1_ALL event */
+	LPC32XX_WKUP_P0_0,
+	LPC32XX_WKUP_P0_1,
+	LPC32XX_WKUP_P0_2,
+	LPC32XX_WKUP_P0_3,
+	LPC32XX_WKUP_P0_4,
+	LPC32XX_WKUP_P0_5,
+	LPC32XX_WKUP_P0_6,
+	LPC32XX_WKUP_P0_7,
+	LPC32XX_WKUP_P1_3,
+	LPC32XX_WKUP_P1_4,
+	LPC32XX_WKUP_P1_5,
+	LPC32XX_WKUP_P1_6,
+	LPC32XX_WKUP_P1_7,
+	LPC32XX_WKUP_P1_8,
+	LPC32XX_WKUP_P1_9,
+	LPC32XX_WKUP_P1_10,
+	LPC32XX_WKUP_P1_11,
+	LPC32XX_WKUP_P1_12,
+	LPC32XX_WKUP_P1_13,
+	LPC32XX_WKUP_P1_14,
+	LPC32XX_WKUP_P1_15,
+	LPC32XX_WKUP_P1_16,
+	LPC32XX_WKUP_P1_17,
+	LPC32XX_WKUP_P1_18,
+	LPC32XX_WKUP_P1_19,
+	LPC32XX_WKUP_P1_20,
+	LPC32XX_WKUP_P1_21,
+	LPC32XX_WKUP_P1_22,
+	LPC32XX_WKUP_P1_23,
+	LPC32XX_LAST_EVENT = LPC32XX_WKUP_P1_23
+};
+
+/*
+ * Wakeup event support
+ */
+extern void lpc32xx_event_init(void);
+extern void lpc32xx_event_enable(enum lpc32xx_events event_id);
+extern void lpc32xx_event_disable(enum lpc32xx_events event_id);
+extern int lpc32xx_event_set(enum lpc32xx_events event_id,
+	int high_edge);
+extern int lpc32xx_event_enabled(enum lpc32xx_events event_id);
+extern void lpc32xx_event_clear(enum lpc32xx_events event_id);
+extern void lpc32xx_event_clear_all(void);
+
+/*
+ * Pointers used for sizing and copying suspend function data
+ */
+extern int lpc32xx_sys_suspend(void);
+extern int lpc32xx_sys_suspend_sz;
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/pm_events.c b/arch/arm/mach-lpc32xx/pm_events.c
new file mode 100644
index 0000000..d3b1b54
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/pm_events.c
@@ -0,0 +1,426 @@
+/*
+ * arch/arm/mach-lpc32xx/pm_events.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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/types.h>
+#include <linux/io.h>
+#include <linux/err.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include "common.h"
+#include "pm.h"
+
+struct lpc32xx_event_info {
+	u32 offs;
+	u32 mask;
+};
+
+static const struct lpc32xx_event_info events[LPC32XX_LAST_EVENT + 1] = {
+	[LPC32XX_WKUP_GPI_08] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O8_BIT,
+	},
+	[LPC32XX_WKUP_GPI_09] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O9_BIT,
+	},
+	[LPC32XX_WKUP_GPI_19] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_19_BIT,
+	},
+	[LPC32XX_WKUP_SPI2_DATIN] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_SPI2_DATIN_BIT,
+	},
+	[LPC32XX_WKUP_GPI_07] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O7_BIT,
+	},
+	[LPC32XX_WKUP_SPI1_DATIN] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_SPI1_DATIN_BIT,
+	},
+	[LPC32XX_WKUP_SYSCLKEN] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_SYSCLKEN_BIT,
+	},
+	[LPC32XX_WKUP_GPI00] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O0_BIT,
+	},
+	[LPC32XX_WKUP_GPI01] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O1_BIT,
+	},
+	[LPC32XX_WKUP_GPI02] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O2_BIT,
+	},
+	[LPC32XX_WKUP_GPI03] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O3_BIT,
+	},
+	[LPC32XX_WKUP_GPI04] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O4_BIT,
+	},
+	[LPC32XX_WKUP_GPI05] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O5_BIT,
+	},
+	[LPC32XX_WKUP_GPI06] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPIO_O6_BIT,
+	},
+	[LPC32XX_WKUP_MSDIO_START] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_MSDIO_SRT_BIT,
+	},
+	[LPC32XX_WKUP_SDIO_INT_N] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_MSDIO_INT_BIT,
+	},
+	[LPC32XX_WKUP_U1_RX] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U1_RX_BIT,
+	},
+	[LPC32XX_WKUP_U2_RX] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U2_RX_BIT,
+	},
+	[LPC32XX_WKUP_U2_HCTS] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U2_HCTS_BIT,
+	},
+	[LPC32XX_WKUP_U3_RX] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U3_RX_BIT,
+	},
+	[LPC32XX_WKUP_GPI_28] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_GPI_11_BIT,
+	},
+	[LPC32XX_WKUP_U5_RX] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U5_RX_BIT,
+	},
+	[LPC32XX_WKUP_U6_IRRX] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U6_IRRX_BIT,
+	},
+	[LPC32XX_WKUP_U7_HCTS] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U7_HCTS_BIT,
+	},
+	[LPC32XX_WKUP_U7_RX] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_EXTSRC_U7_RX_BIT,
+	},
+
+	[LPC32XX_WKUP_GPIO_00] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_GPIO_00_BIT,
+	},
+	[LPC32XX_WKUP_GPIO_01] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_GPIO_01_BIT,
+	},
+	[LPC32XX_WKUP_GPIO_02] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_GPIO_02_BIT,
+	},
+	[LPC32XX_WKUP_GPIO_03] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_GPIO_03_BIT,
+	},
+	[LPC32XX_WKUP_GPIO_04] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_GPIO_04_BIT,
+	},
+	[LPC32XX_WKUP_GPIO_05] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_GPIO_05_BIT,
+	},
+	[LPC32XX_WKUP_P0_P1_ALL] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_P0P1_BIT,
+	},
+	[LPC32XX_WKUP_MAC_START] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_MAC_BIT,
+	},
+	[LPC32XX_WKUP_KEY_IRQ] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_KEY_BIT,
+	},
+	[LPC32XX_WKUP_USB_OTG_ATX_INT_N] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_USBATXINT_BIT,
+	},
+	[LPC32XX_WKUP_USB_OTG_TIMER] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_USBOTGTIMER_BIT,
+	},
+	[LPC32XX_WKUP_USB_I2C_INT] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_I2C_BIT,
+	},
+	[LPC32XX_WKUP_USB_INT] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_USB_BIT,
+	},
+	[LPC32XX_WKUP_USB_NEED_CLK] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_USBNEEDCLK_BIT,
+	},
+	[LPC32XX_WKUP_RTC_INT] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_RTC_BIT,
+	},
+	[LPC32XX_WKUP_MSTIMER_INT] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_MSTIMER_BIT,
+	},
+	[LPC32XX_WKUP_USB_AHC_NEED_CLK] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_USBAHNEEDCLK_BIT,
+	},
+	[LPC32XX_WKUP_TS_AUX_INT] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_TS_AUX_BIT,
+	},
+	[LPC32XX_WKUP_TS_P_INT] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_TS_P_BIT,
+	},
+	[LPC32XX_WKUP_TS_INT] = {
+		.offs = CLKPWR_INT_ER(0),
+		.mask = CLKPWR_INTSRC_ADC_BIT,
+	},
+	[LPC32XX_WKUP_P0_0] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO0_BIT,
+	},
+	[LPC32XX_WKUP_P0_1] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO1_BIT,
+	},
+	[LPC32XX_WKUP_P0_2] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO2_BIT,
+	},
+	[LPC32XX_WKUP_P0_3] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO3_BIT,
+	},
+	[LPC32XX_WKUP_P0_4] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO4_BIT,
+	},
+	[LPC32XX_WKUP_P0_5] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO5_BIT,
+	},
+	[LPC32XX_WKUP_P0_6] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO6_BIT,
+	},
+	[LPC32XX_WKUP_P0_7] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P0IO7_BIT,
+	},
+	[LPC32XX_WKUP_P1_3] = {
+		.offs = CLKPWR_PIN_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO3_BIT,
+	},
+	[LPC32XX_WKUP_P1_4] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO4_BIT,
+	},
+	[LPC32XX_WKUP_P1_5] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO5_BIT,
+	},
+	[LPC32XX_WKUP_P1_6] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO6_BIT,
+	},
+	[LPC32XX_WKUP_P1_7] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO7_BIT,
+	},
+	[LPC32XX_WKUP_P1_8] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO8_BIT,
+	},
+	[LPC32XX_WKUP_P1_9] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO9_BIT,
+	},
+	[LPC32XX_WKUP_P1_10] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO10_BIT,
+	},
+	[LPC32XX_WKUP_P1_11] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO11_BIT,
+	},
+	[LPC32XX_WKUP_P1_12] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO12_BIT,
+	},
+	[LPC32XX_WKUP_P1_13] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO13_BIT,
+	},
+	[LPC32XX_WKUP_P1_14] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO14_BIT,
+	},
+	[LPC32XX_WKUP_P1_15] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO15_BIT,
+	},
+	[LPC32XX_WKUP_P1_16] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO16_BIT,
+	},
+	[LPC32XX_WKUP_P1_17] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO17_BIT,
+	},
+	[LPC32XX_WKUP_P1_18] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO18_BIT,
+	},
+	[LPC32XX_WKUP_P1_19] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO19_BIT,
+	},
+	[LPC32XX_WKUP_P1_20] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO20_BIT,
+	},
+	[LPC32XX_WKUP_P1_21] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO21_BIT,
+	},
+	[LPC32XX_WKUP_P1_22] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO22_BIT,
+	},
+	[LPC32XX_WKUP_P1_23] = {
+		.offs = CLKPWR_P01_ER(0),
+		.mask = CLKPWR_GPIOSRC_P1IO23_BIT,
+	},
+};
+
+void lpc32xx_event_init(void)
+{
+	/* Initially disable all events, set all events to default
+	   type and polarity per chip User guide, and clear any
+	   pending event statuses */
+	writel(0, CLKPWR_P01_ER(CLKPWR_IOBASE));
+	writel(0, CLKPWR_INT_ER(CLKPWR_IOBASE));
+	writel(0, CLKPWR_PIN_ER(CLKPWR_IOBASE));
+
+	/* Default activation polarities, all pin sources are low edge
+	   triggered */
+	writel(CLKPWR_INTSRC_TS_P_BIT | CLKPWR_INTSRC_MSTIMER_BIT |
+		CLKPWR_INTSRC_RTC_BIT, CLKPWR_INT_AP(CLKPWR_IOBASE));
+	writel(0, CLKPWR_PIN_AP(CLKPWR_IOBASE));
+
+	/* Clear latched event states */
+	writel(readl(CLKPWR_PIN_RS(CLKPWR_IOBASE)),
+		CLKPWR_PIN_RS(CLKPWR_IOBASE));
+	writel(readl(CLKPWR_INT_RS(CLKPWR_IOBASE)),
+		CLKPWR_INT_RS(CLKPWR_IOBASE));
+}
+
+void lpc32xx_event_enable(enum lpc32xx_events event_id)
+{
+	writel(readl(CLKPWR_IOBASE + events[event_id].offs) |
+		events[event_id].mask, CLKPWR_IOBASE + events[event_id].offs);
+}
+
+void lpc32xx_event_disable(enum lpc32xx_events event_id)
+{
+	writel(readl(CLKPWR_IOBASE + events[event_id].offs) &
+		~events[event_id].mask, CLKPWR_IOBASE + events[event_id].offs);
+}
+
+extern int lpc32xx_event_set(enum lpc32xx_events event_id,
+	int high_edge)
+{
+	u32 tmp;
+
+	if (event_id <= LPC32XX_WKUP_U7_RX) {
+		tmp = readl(CLKPWR_PIN_AP(CLKPWR_IOBASE));
+
+		if (high_edge)
+			tmp |= events[event_id].mask;
+		else
+			tmp &= ~events[event_id].mask;
+
+		writel(tmp, CLKPWR_PIN_AP(CLKPWR_IOBASE));
+	} else if (event_id <= LPC32XX_WKUP_TS_INT) {
+		tmp = readl(CLKPWR_INT_AP(CLKPWR_IOBASE));
+
+		if (high_edge)
+			tmp |= events[event_id].mask;
+		else
+			tmp &= ~events[event_id].mask;
+
+		writel(tmp, CLKPWR_INT_AP(CLKPWR_IOBASE));
+	} else
+		return -EINVAL;
+
+	return 0;
+}
+
+int lpc32xx_event_enabled(enum lpc32xx_events event_id)
+{
+	u32 tmp;
+
+	tmp = readl(CLKPWR_IOBASE + events[event_id].offs) &
+		events[event_id].mask;
+
+	return (tmp != 0);
+}
+
+void lpc32xx_event_clear(enum lpc32xx_events event_id)
+{
+	if (event_id <= LPC32XX_WKUP_U7_RX)
+		writel(events[event_id].mask, CLKPWR_PIN_RS(CLKPWR_IOBASE));
+	else if (event_id <= LPC32XX_WKUP_TS_INT)
+		writel(events[event_id].mask, CLKPWR_INT_RS(CLKPWR_IOBASE));
+}
+
+void lpc32xx_event_clear_all(void)
+{
+	/* Clear all latched event states */
+	writel(readl(CLKPWR_PIN_RS(CLKPWR_IOBASE)),
+		CLKPWR_PIN_RS(CLKPWR_IOBASE));
+	writel(readl(CLKPWR_INT_RS(CLKPWR_IOBASE)),
+		CLKPWR_INT_RS(CLKPWR_IOBASE));
+}
+
diff --git a/arch/arm/mach-lpc32xx/suspend.S b/arch/arm/mach-lpc32xx/suspend.S
new file mode 100644
index 0000000..075708b
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/suspend.S
@@ -0,0 +1,155 @@
+/*
+ * arch/arm/mach-lpc32xx/suspend.S
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ * Based in part on PNX4008 power management code
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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/linkage.h>
+#include <asm/assembler.h>
+#include <mach/platform.h>
+#include <mach/hardware.h>
+
+/* Using named register defines makes the code easier to follow */
+#define WORK1_REG		r0
+#define WORK2_REG		r1
+#define SAVED_HCLK_DIV_REG	r2
+#define SAVED_HCLK_PLL_REG	r3
+#define SAVED_DRAM_CLKCTRL_REG	r4
+#define SAVED_PWR_CTRL_REG	r5
+#define CLKPWRBASE_REG		r6
+#define EMCBASE_REG		r7
+
+#define EMC_STATUS_OFFS		0x04
+#define EMC_STATUS_BUSY		0x1
+#define EMC_STATUS_SELF_RFSH	0x4
+
+	.text
+
+ENTRY(lpc32xx_sys_suspend)
+	@ Save a copy of the used registers in IRAM, r0 is corrupted
+	adr	r0, tmp_stack_end
+	stmfd	r0!, {r1 - r7, sp, lr}
+
+	@ Load a few common register addresses
+	adr	WORK1_REG, reg_bases
+	ldr	CLKPWRBASE_REG, [WORK1_REG, #0]
+	ldr	EMCBASE_REG, [WORK1_REG, #4]
+
+	ldr	SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+	orr	WORK1_REG, SAVED_PWR_CTRL_REG, #CLKPWR_SDRAM_SELF_RFSH
+
+	@ Wait for SDRAM busy status to go busy and then idle
+	@ This guarantees a small windows where DRAM isn't busy
+1:
+	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
+	and	WORK2_REG, WORK2_REG, #EMC_STATUS_BUSY
+	cmp	WORK2_REG, #EMC_STATUS_BUSY
+	bne	1b @ Branch while idle
+2:
+	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
+	and	WORK2_REG, WORK2_REG, #EMC_STATUS_BUSY
+	cmp	WORK2_REG, #EMC_STATUS_BUSY
+	beq	2b @ Branch until idle
+
+	@ Setup self-refresh with support for manual exit of
+	@ self-refresh mode
+	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+	orr	WORK2_REG, WORK1_REG, #CLKPWR_UPD_SDRAM_SELF_RFSH
+	str	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+
+	@ Wait for self-refresh acknowledge, clocks to the DRAM device
+	@ will automatically stop on start of self-refresh
+3:
+	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
+	and	WORK2_REG, WORK2_REG, #EMC_STATUS_SELF_RFSH
+	cmp	WORK2_REG, #EMC_STATUS_SELF_RFSH
+	bne	3b @ Branch until self-refresh mode starts
+
+	@ Enter direct-run mode from run mode
+	bic	WORK1_REG, WORK1_REG, #CLKPWR_SELECT_RUN_MODE
+	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+
+	@ Safe disable of DRAM clock in EMC block, prevents DDR sync
+	@ issues on restart
+	ldr	SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG, #CLKPWR_HCLK_DIV(0)]
+	and	WORK2_REG, SAVED_HCLK_DIV_REG, #0xFFFFFE7F
+	str	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_HCLK_DIV(0)]
+
+	@ Save HCLK PLL state and disable HCLK PLL
+	ldr	SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
+	bic	WORK2_REG, SAVED_HCLK_PLL_REG, #CLKPWR_HCLKPLL_POWER_UP
+	str	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
+
+	@ Enter stop mode until an enabled event occurs
+	orr	WORK1_REG, WORK1_REG, #CLKPWR_STOP_MODE_CTRL
+	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+	nop
+
+	@ Clear stop status
+	bic	WORK1_REG, WORK1_REG, #CLKPWR_STOP_MODE_CTRL
+
+	@ Restore original HCLK PLL value and wait for PLL lock
+	str	SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
+4:
+	ldr	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
+	and	WORK2_REG, WORK2_REG, #CLKPWR_HCLKPLL_PLL_STS
+	bne	4b
+
+	@ Re-enter run mode with self-refresh flag cleared, but no DRAM
+	@ update yet. DRAM is still in self-refresh
+	str	SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+
+	@ Restore original DRAM clock mode to restore DRAM clocks
+	str	SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG, #CLKPWR_HCLK_DIV(0)]
+
+	@ Clear self-refresh mode
+	orr	WORK1_REG, SAVED_PWR_CTRL_REG, #CLKPWR_UPD_SDRAM_SELF_RFSH
+	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+	str	SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
+
+	@ Wait for EMC to clear self-refresh mode
+5:
+	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
+	and	WORK2_REG, WORK2_REG, #EMC_STATUS_SELF_RFSH
+	bne	5b @ Branch until self-refresh has exited
+
+	@ restore regs and return
+	adr	r0, tmp_stack
+	ldmfd	r0!, {r1 - r7, sp, pc}
+
+reg_bases:
+	.long	IO_ADDRESS(CLK_PM_BASE)
+	.long	IO_ADDRESS(EMC_BASE)
+
+tmp_stack:
+	.long	0, 0, 0, 0, 0, 0, 0, 0, 0
+tmp_stack_end:
+
+ENTRY(lpc32xx_sys_suspend_sz)
+	.word	. - lpc32xx_sys_suspend
+
-- 
1.6.6

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

* [PATCH 10/13] ARM: LPC32XX: Phytec PHY3250 platform support file
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (8 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 09/13] ARM: LPC32XX: power and event management wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-02-03 16:46   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions wellsk40 at gmail.com
                   ` (4 subsequent siblings)
  14 siblings, 1 reply; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

The is the board specific file for the PHY3250 platform.
(machine id: PHY3250)

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/phy3250.c |  424 +++++++++++++++++++++++++++++++++++++++
 1 files changed, 424 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/phy3250.c b/arch/arm/mach-lpc32xx/phy3250.c
new file mode 100644
index 0000000..aa29aa6
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/phy3250.c
@@ -0,0 +1,424 @@
+/*
+ * arch/arm/mach-lpc32xx/phy3250.c
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/dma-mapping.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/eeprom.h>
+#include <linux/leds.h>
+#include <linux/gpio.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+#include <linux/amba/pl022.h>
+
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+
+#include <mach/hardware.h>
+#include <mach/platform.h>
+#include <mach/board.h>
+#include "common.h"
+#include "pm.h"
+
+/*
+ * Mapped GPIOLIB GPIOs
+ */
+#define SPI0_CS_GPIO	LPC32XX_GPIO(GPIO_P3_GRP, 5)
+#define LCD_POWER_GPIO	LPC32XX_GPIO(GPO_P3_GRP, 0)
+#define BKL_POWER_GPIO	LPC32XX_GPIO(GPO_P3_GRP, 4)
+#define LED_GPIO	LPC32XX_GPIO(GPO_P3_GRP, 1)
+
+/*
+ * AMBA LCD controller
+ */
+static struct clcd_panel conn_lcd_panel = {
+	.mode		= {
+		.name		= "QVGA portrait",
+		.refresh	= 60,
+		.xres		= 240,
+		.yres		= 320,
+		.pixclock	= 191828,
+		.left_margin	= 22,
+		.right_margin	= 11,
+		.upper_margin	= 2,
+		.lower_margin	= 1,
+		.hsync_len	= 5,
+		.vsync_len	= 2,
+		.sync		= 0,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+	.width		= -1,
+	.height		= -1,
+	.tim2		= (TIM2_IVS | TIM2_IHS),
+	.cntl		= (CNTL_BGR | CNTL_LCDTFT | CNTL_LCDVCOMP(1) |
+				CNTL_LCDBPP16_565),
+	.bpp		= 16,
+};
+#define PANEL_SIZE (3 * SZ_64K)
+
+static int lpc32xx_clcd_setup(struct clcd_fb *fb)
+{
+	dma_addr_t dma;
+
+	fb->fb.screen_base = (void *) NULL;
+#ifdef CONFIG_MACH_LPC32XX_IRAM_FOR_CLCD
+	if (PANEL_SIZE <= LPC32XX_IRAM_SIZE) {
+		fb->fb.screen_base = (void *) io_p2v(IRAM_BASE);
+		fb->fb.fix.smem_start = (dma_addr_t) IRAM_BASE;
+	}
+#endif
+
+	if (fb->fb.screen_base == NULL) {
+		fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+			PANEL_SIZE, &dma, GFP_KERNEL);
+		fb->fb.fix.smem_start = dma;
+	}
+
+	if (!fb->fb.screen_base) {
+		printk(KERN_ERR "CLCD: unable to map framebuffer\n");
+		return -ENOMEM;
+	}
+
+	fb->fb.fix.smem_len = PANEL_SIZE;
+	fb->panel = &conn_lcd_panel;
+
+	gpio_request(LCD_POWER_GPIO, "LCD power");
+	gpio_direction_output(LCD_POWER_GPIO, 1);
+	gpio_request(BKL_POWER_GPIO, "LCD backlight power");
+	gpio_direction_output(BKL_POWER_GPIO, 1);
+
+	return 0;
+}
+
+static int lpc32xx_clcd_mmap(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+#ifdef CONFIG_MACH_LPC32XX_IRAM_FOR_CLCD
+	if (PANEL_SIZE <= LPC32XX_IRAM_SIZE) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		if (remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+			(vma->vm_end - vma->vm_start), vma->vm_page_prot)) {
+			return -EAGAIN;
+		}
+
+		return 0;
+	} else
+#endif
+
+	return dma_mmap_writecombine(&fb->dev->dev, vma,
+				     fb->fb.screen_base,
+				     fb->fb.fix.smem_start,
+				     fb->fb.fix.smem_len);
+}
+
+static void lpc32xx_clcd_remove(struct clcd_fb *fb)
+{
+#ifdef CONFIG_MACH_LPC32XX_IRAM_FOR_CLCD
+	if (PANEL_SIZE > LPC32XX_IRAM_SIZE)
+		dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+			fb->fb.screen_base, fb->fb.fix.smem_start);
+
+#else
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+		fb->fb.screen_base, fb->fb.fix.smem_start);
+#endif
+}
+
+#ifdef CONFIG_PHY3250_QVGA_PANEL_1307_0
+#define LCD_BKL_ON	0
+#define LCD_BKL_OFF	1
+#elif defined(CONFIG_PHY3250_QVGA_PANEL_1307_1)
+#define LCD_BKL_ON	1
+#define LCD_BKL_OFF	0
+#endif
+
+static void clcd_disable(struct clcd_fb *fb)
+{
+	gpio_set_value(BKL_POWER_GPIO, LCD_BKL_OFF);
+	gpio_set_value(LCD_POWER_GPIO, 0);
+}
+
+static void clcd_enable(struct clcd_fb *fb)
+{
+	gpio_set_value(BKL_POWER_GPIO, LCD_BKL_ON);
+	gpio_set_value(LCD_POWER_GPIO, 1);
+}
+
+static struct clcd_board lpc32xx_clcd_data = {
+	.name		= "Phytec LCD",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.disable	= clcd_disable,
+	.enable		= clcd_enable,
+	.setup		= lpc32xx_clcd_setup,
+	.mmap		= lpc32xx_clcd_mmap,
+	.remove		= lpc32xx_clcd_remove,
+};
+
+static struct amba_device clcd_device = {
+	.dev				= {
+		.coherent_dma_mask	= ~0,
+		.init_name		= "dev:clcd",
+		.platform_data		= &lpc32xx_clcd_data,
+	},
+	.res				= {
+		.start			= LCD_BASE,
+		.end			= (LCD_BASE + SZ_4K - 1),
+		.flags			= IORESOURCE_MEM,
+	},
+	.dma_mask			= ~0,
+	.irq				= {IRQ_LCD, NO_IRQ},
+};
+
+/*
+ * AMBA SSP (SPI)
+ */
+static void phy3250_spi_cs_set(u32 control)
+{
+	gpio_set_value(SPI0_CS_GPIO, (int) control);
+}
+
+static struct pl022_config_chip spi0_chip_info = {
+	.lbm			= LOOPBACK_DISABLED,
+	.com_mode		= INTERRUPT_TRANSFER,
+	.iface			= SSP_INTERFACE_MOTOROLA_SPI,
+	.hierarchy		= SSP_MASTER,
+	.slave_tx_disable	= 0,
+	.endian_tx		= SSP_TX_LSB,
+	.endian_rx		= SSP_RX_LSB,
+	.data_size		= SSP_DATA_BITS_8,
+	.rx_lev_trig		= SSP_RX_4_OR_MORE_ELEM,
+	.tx_lev_trig		= SSP_TX_4_OR_MORE_EMPTY_LOC,
+	.clk_phase		= SSP_CLK_FIRST_EDGE,
+	.clk_pol		= SSP_CLK_POL_IDLE_LOW,
+	.ctrl_len		= SSP_BITS_8,
+	.wait_state		= SSP_MWIRE_WAIT_ZERO,
+	.duplex			= SSP_MICROWIRE_CHANNEL_FULL_DUPLEX,
+	.cs_control		= phy3250_spi_cs_set,
+};
+
+static struct pl022_ssp_controller lpc32xx_ssp0_data = {
+	.bus_id			= 0,
+	.num_chipselect		= 1,
+	.enable_dma		= 0,
+};
+
+static struct amba_device ssp0_device = {
+	.dev				= {
+		.coherent_dma_mask	= ~0,
+		.init_name		= "dev:ssp0",
+		.platform_data		= &lpc32xx_ssp0_data,
+	},
+	.res				= {
+		.start			= SSP0_BASE,
+		.end			= (SSP0_BASE + SZ_4K - 1),
+		.flags			= IORESOURCE_MEM,
+	},
+	.dma_mask			= ~0,
+	.irq				= {IRQ_SSP0, NO_IRQ},
+};
+
+/* AT25 driver registration */
+static int __init phy3250_spi_board_register(void)
+{
+#if defined(CONFIG_SPI_SPIDEV) || defined(CONFIG_SPI_SPIDEV_MODULE)
+	static struct spi_board_info info[] = {
+		{
+			.modalias = "spidev",
+			.max_speed_hz = 5000000,
+			.bus_num = 0,
+			.chip_select = 0,
+			.controller_data = &spi0_chip_info,
+		},
+	};
+
+#else
+	static struct spi_eeprom eeprom = {
+		.name = "at25256a",
+		.byte_len = 0x8000,
+		.page_size = 64,
+		.flags = EE_ADDR2,
+	};
+
+	static struct spi_board_info info[] = {
+		{
+			.modalias = "at25",
+			.max_speed_hz = 5000000,
+			.bus_num = 0,
+			.chip_select = 0,
+			.platform_data = &eeprom,
+			.controller_data = &spi0_chip_info,
+		},
+	};
+#endif
+	return spi_register_board_info(info, ARRAY_SIZE(info));
+}
+arch_initcall(phy3250_spi_board_register);
+
+static struct i2c_board_info __initdata phy3250_i2c_board_info[] = {
+	{
+		I2C_BOARD_INFO("pcf8563", 0x51),
+	},
+};
+
+static struct gpio_led phy_leds[] = {
+	{
+		.name			= "led0",
+		.gpio			= LED_GPIO,
+		.active_low		= 1,
+		.default_trigger	= "heartbeat",
+	},
+};
+
+static struct gpio_led_platform_data led_data = {
+	.leds = phy_leds,
+	.num_leds = ARRAY_SIZE(phy_leds),
+};
+
+static struct platform_device lpc32xx_gpio_led_device = {
+	.name			= "leds-gpio",
+	.id			= -1,
+	.dev.platform_data	= &led_data,
+};
+
+static struct platform_device *phy3250_devs[] __initdata = {
+	&i2c0_device,
+	&i2c1_device,
+	&i2c2_device,
+	&watchdog_device,
+	&lpc32xx_gpio_led_device,
+};
+
+static struct amba_device *amba_devs[] __initdata = {
+	&clcd_device,
+	&ssp0_device,
+};
+
+/*
+ * Board specific functions
+ */
+static void __init phy3250_board_init(void)
+{
+	u32 tmp;
+	int i;
+
+	lpc32xx_gpio_init();
+
+	/* Register GPIOs used on this board */
+	gpio_request(SPI0_CS_GPIO, "spi0 cs");
+	gpio_direction_output(SPI0_CS_GPIO, 1);
+
+	/* Setup network interface for RMII mode */
+	tmp = readl(CLKPWR_MACCLK_CTRL(CLKPWR_IOBASE));
+	tmp &= ~CLKPWR_MACCTRL_PINS_MSK;
+	tmp |= CLKPWR_MACCTRL_USE_RMII_PINS;
+	writel(tmp, CLKPWR_MACCLK_CTRL(CLKPWR_IOBASE));
+
+	/* Setup SLC NAND controller muxing */
+	writel(CLKPWR_NANDCLK_SEL_SLC,
+		CLKPWR_NAND_CLK_CTRL(CLKPWR_IOBASE));
+
+	/* Setup LCD muxing to RGB565 */
+	tmp = readl(CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)) &
+		~(CLKPWR_LCDCTRL_LCDTYPE_MSK | CLKPWR_LCDCTRL_PSCALE_MSK);
+	tmp |= CLKPWR_LCDCTRL_LCDTYPE_TFT16;
+	writel(tmp, CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE));
+
+	/* Set up I2C pull levels */
+	tmp = readl(CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE));
+	tmp |= CLKPWR_I2CCLK_USBI2CHI_DRIVE | CLKPWR_I2CCLK_I2C2HI_DRIVE;
+	writel(tmp, CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE));
+
+	/* Enable DMA for I2S1 channel */
+	tmp = readl(CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE));
+	tmp = CLKPWR_I2SCTRL_I2S1_USE_DMA;
+	writel(tmp, CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE));
+
+	lpc32xx_serial_init();
+
+	/* AMBA peripheral clocks need to be enabled prior to AMBA device
+	   detection or a data fault will occur, so enable the clocks
+	   here. However, we don't want to enable them if the peripheral
+	   isn't included in the image */
+#ifdef CONFIG_FB_ARMCLCD
+	tmp = readl(CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE));
+	writel((tmp | CLKPWR_LCDCTRL_CLK_EN),
+		CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE));
+#endif
+#ifdef CONFIG_SPI_PL022
+	tmp = readl(CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE));
+	writel((tmp | CLKPWR_SSPCTRL_SSPCLK0_EN),
+		CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE));
+#endif
+
+	platform_add_devices(phy3250_devs, ARRAY_SIZE(phy3250_devs));
+	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+		struct amba_device *d = amba_devs[i];
+		amba_device_register(d, &iomem_resource);
+	}
+
+	/* Test clock needed for UDA1380 initial init */
+	writel((CLKPWR_TESTCLK2_SEL_MOSC | CLKPWR_TESTCLK_TESTCLK2_EN),
+		CLKPWR_TEST_CLK_SEL(CLKPWR_IOBASE));
+
+	i2c_register_board_info(0, phy3250_i2c_board_info,
+				ARRAY_SIZE(phy3250_i2c_board_info));
+
+	/* Initialize events and enable the internal RTC alarm interrupt
+	   as a system wakeup event */
+	lpc32xx_event_init();
+	lpc32xx_event_enable(LPC32XX_WKUP_RTC_INT);
+
+	/* BTN1 on the Phytec carrier board can be used to wakeup the board
+	   from suspend mode. It is connected to GPI3 and is active high */
+	lpc32xx_event_enable(LPC32XX_WKUP_GPI03);
+	lpc32xx_event_set(LPC32XX_WKUP_GPI03, 1);
+}
+
+static int __init lpc32xx_display_uid(void)
+{
+	u32 uid[4];
+
+	lpc32xx_get_uid(uid);
+
+	printk(KERN_INFO "LPC32XX unique ID: %08x%08x%08x%08x\n",
+		uid[3], uid[2], uid[1], uid[0]);
+
+	return 1;
+}
+arch_initcall(lpc32xx_display_uid);
+
+MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
+	/* Maintainer: Kevin Wells, NXP Semiconductors */
+	.phys_io	= UART5_BASE,
+	.io_pg_offst	= ((io_p2v(UART5_BASE))>>18) & 0xfffc,
+	.boot_params	= 0x80000100,
+	.map_io		= lpc32xx_map_io,
+	.init_irq	= lpc32xx_init_irq,
+	.timer		= &lpc32xx_timer,
+	.init_machine	= phy3250_board_init,
+MACHINE_END
-- 
1.6.6

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

* [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (9 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 10/13] ARM: LPC32XX: Phytec PHY3250 platform support file wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-02-03 16:50   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 12/13] ARM: LPC32XX: architecture header files wellsk40 at gmail.com
                   ` (3 subsequent siblings)
  14 siblings, 1 reply; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

Debug output support file for various UARTs and the LPC32XX irq
router support functions

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/include/mach/debug-macro.S |   72 +++++++++++++++++++
 arch/arm/mach-lpc32xx/include/mach/entry-macro.S |   81 ++++++++++++++++++++++
 2 files changed, 153 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/include/mach/debug-macro.S b/arch/arm/mach-lpc32xx/include/mach/debug-macro.S
new file mode 100644
index 0000000..641daba
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/debug-macro.S
@@ -0,0 +1,72 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/debug-macro.S
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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 <mach/hardware.h>
+#include <mach/platform.h>
+
+/*
+ * NOTE: The UART clock for the selected debug out should be enabled
+ * in the bootloader if this functionality is used.
+*/
+
+#ifdef CONFIG_ARCH_LPC32XX_DEBUGO_U3
+#define UARTDB_BASE UART3_BASE
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_DEBUGO_U4
+#define UARTDB_BASE UART4_BASE
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_DEBUGO_U5
+#define UARTDB_BASE UART5_BASE
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_DEBUGO_U6
+#define UARTDB_BASE UART6_BASE
+#endif
+
+	.macro	addruart,rx
+	mrc	p15, 0, \rx, c1, c0
+	tst	\rx, #1				@ MMU enabled?
+	ldr	\rx, =UARTDB_BASE		@ physical
+	beq	1003f
+	ldr	\rx, =io_p2v(UARTDB_BASE)	@ virtual
+1003:
+	.endm
+
+	.macro	senduart,rd,rx
+	str	\rd, [\rx, #0]
+	.endm
+
+	.macro	busyuart,rd,rx
+1002:
+	ldr	\rd, [\rx, #0x14]
+	tst	\rd, #(1 << 6)
+	beq	1002b
+	.endm
+
+	.macro	waituart,rd,rx
+1001:
+	ldr	\rd, [\rx, #0x14]
+	tst	\rd, #(1 << 5)
+	beq	1001b
+	.endm
diff --git a/arch/arm/mach-lpc32xx/include/mach/entry-macro.S b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S
new file mode 100644
index 0000000..c0313ae
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/entry-macro.S
@@ -0,0 +1,81 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/entry-macro.S
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * 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 <mach/hardware.h>
+#include <mach/platform.h>
+#include <mach/irqs.h>
+
+	.macro	disable_fiq
+	.endm
+
+	.macro  get_irqnr_preamble, base, tmp
+	.endm
+
+	.macro  arch_ret_to_user, tmp1, tmp2
+	.endm
+
+/*
+ * Return IRQ number in irqnr. Also return processor Z flag status in CPSR
+ * as set if an interrupt is pending.
+ */
+	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
+	/* Get MIC status first */
+	ldr	\base, =IO_ADDRESS(MIC_BASE)
+	ldr	\irqstat, [\base, #INTC_STAT]
+	and	\irqstat, \irqstat, #0xFFFFFFFC
+	mov	\tmp, #0
+
+	/* Drop through to SIC1 or SIC2 if MIC is not pending */
+	cmp	\irqstat, #0
+	bne	1000f
+
+	/* SIC1 interrupts start at offset 32 */
+	ldr	\base, =IO_ADDRESS(SIC1_BASE)
+	ldr	\irqstat, [\base, #INTC_STAT]
+	mov	\tmp, #32
+
+	/* Drop through to SIC2 if SIC1 is not pending */
+	cmp	\irqstat, #0
+	bne	1000f
+
+	/* SIC2 interrupts start at offset 64 */
+	ldr	\base, =IO_ADDRESS(SIC2_BASE)
+	ldr	\irqstat, [\base, #INTC_STAT]
+	mov	\tmp, #64
+
+	/* Safety check only, exit if no status on MIC, SIC1, SIC2 */
+	cmp	\irqstat, #0
+	beq	1001f
+
+1000:
+	/* Returns an pending interrupt between 0 and 95 */
+	clz	\irqnr, \irqstat
+	rsb	\irqnr, \irqnr, #31
+	add	\irqnr, \irqnr, \tmp
+
+1001:
+	teq	\irqstat, #0
+	.endm
+
+	.macro	irq_prio_table
+	.endm
+
-- 
1.6.6

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

* [PATCH 12/13] ARM: LPC32XX: architecture header files
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (10 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-02-03 17:07   ` Uwe Kleine-König
  2010-01-28  1:43 ` [PATCH 13/13] ARM: LPC32XX: Phytec PHY3250 default kernel config (ramdisk) wellsk40 at gmail.com
                   ` (2 subsequent siblings)
  14 siblings, 1 reply; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

Header files used for the LCP32XX arch and support platforms

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/mach-lpc32xx/include/mach/board.h      |   27 +
 arch/arm/mach-lpc32xx/include/mach/clkdev.h     |   29 +
 arch/arm/mach-lpc32xx/include/mach/gpio.h       |   78 +++
 arch/arm/mach-lpc32xx/include/mach/hardware.h   |   41 ++
 arch/arm/mach-lpc32xx/include/mach/i2c.h        |   63 ++
 arch/arm/mach-lpc32xx/include/mach/io.h         |   31 +
 arch/arm/mach-lpc32xx/include/mach/irqs.h       |  118 ++++
 arch/arm/mach-lpc32xx/include/mach/memory.h     |   32 +
 arch/arm/mach-lpc32xx/include/mach/platform.h   |  735 +++++++++++++++++++++++
 arch/arm/mach-lpc32xx/include/mach/system.h     |   56 ++
 arch/arm/mach-lpc32xx/include/mach/timex.h      |   33 +
 arch/arm/mach-lpc32xx/include/mach/uncompress.h |  114 ++++
 arch/arm/mach-lpc32xx/include/mach/vmalloc.h    |   28 +
 13 files changed, 1385 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-lpc32xx/include/mach/board.h b/arch/arm/mach-lpc32xx/include/mach/board.h
new file mode 100644
index 0000000..057774a
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/board.h
@@ -0,0 +1,27 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/board.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+
+#ifndef __ASM_ARCH_BOARD_H
+#define __ASM_ARCH_BOARD_H
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/clkdev.h b/arch/arm/mach-lpc32xx/include/mach/clkdev.h
new file mode 100644
index 0000000..3dd9d0d
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/clkdev.h
@@ -0,0 +1,29 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/clkdev.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_CLKDEV_H
+#define __ASM_ARCH_CLKDEV_H
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/gpio.h b/arch/arm/mach-lpc32xx/include/mach/gpio.h
new file mode 100644
index 0000000..8df2198
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/gpio.h
@@ -0,0 +1,78 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/gpio.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_GPIO_H
+#define __ASM_ARCH_GPIO_H
+
+#include <asm-generic/gpio.h>
+
+/*
+ * Note!
+ * Muxed GP pins need to be setup to the GP state in the board level
+ * code prior to using this driver.
+ * GPI pins : 28xP3 group
+ * GPO pins : 24xP3 group
+ * GPIO pins: 8xP0 group, 24xP1 group, 13xP2 group, 6xP3 group
+ */
+
+#define GPIO_P0_MAX 8
+#define GPIO_P1_MAX 24
+#define GPIO_P2_MAX 13
+#define GPIO_P3_MAX 6
+#define GPI_P3_MAX 28
+#define GPO_P3_MAX 24
+
+#define GPIO_P0_GRP 0
+#define GPIO_P1_GRP (GPIO_P0_GRP + GPIO_P0_MAX)
+#define GPIO_P2_GRP (GPIO_P1_GRP + GPIO_P1_MAX)
+#define GPIO_P3_GRP (GPIO_P2_GRP + GPIO_P2_MAX)
+#define GPI_P3_GRP (GPIO_P3_GRP + GPIO_P3_MAX)
+#define GPO_P3_GRP (GPI_P3_GRP + GPI_P3_MAX)
+
+/*
+ * A specific GPIO can be selected with this macro
+ * ie, GPIO_05 can be selected with LPC32XX_GPIO(GPIO_P3_GRP, 5)
+ * See the LPC32x0 User's guide for GPIO group numbers
+ */
+#define LPC32XX_GPIO(x, y) ((x) + (y))
+
+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);
+}
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/hardware.h b/arch/arm/mach-lpc32xx/include/mach/hardware.h
new file mode 100644
index 0000000..3f4bffa
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/hardware.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/hardware.h
+ *
+ * Copyright (c) 2005 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+/*
+ * Start of virtual addresses for IO devices
+ */
+#define IO_BASE		0xF0000000
+
+#define io_p2v(x)	(IO_BASE | (((x) & 0xff000000) >> 4) |\
+			 ((x) & 0x000fffff))
+#define io_v2p(x)	((((x) & 0x0ff00000) << 4) | ((x) & 0x000fffff))
+
+/*
+ * This macro relies on fact that for all HW i/o addresses bits 20-23 are 0
+ */
+#define IO_ADDRESS(x)	(((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\
+			 IO_BASE)
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/i2c.h b/arch/arm/mach-lpc32xx/include/mach/i2c.h
new file mode 100644
index 0000000..a2d810b
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/i2c.h
@@ -0,0 +1,63 @@
+/*
+ * PNX4008-specific tweaks for I2C IP3204 block
+ *
+ * Author: Vitaly Wool <vwool@ru.mvista.com>
+ *
+ * 2005 (c) MontaVista Software, Inc. 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.
+ */
+
+#ifndef __ASM_ARCH_I2C_H__
+#define __ASM_ARCH_I2C_H__
+
+enum {
+	mstatus_tdi = 0x00000001,
+	mstatus_afi = 0x00000002,
+	mstatus_nai = 0x00000004,
+	mstatus_drmi = 0x00000008,
+	mstatus_active = 0x00000020,
+	mstatus_scl = 0x00000040,
+	mstatus_sda = 0x00000080,
+	mstatus_rff = 0x00000100,
+	mstatus_rfe = 0x00000200,
+	mstatus_tff = 0x00000400,
+	mstatus_tfe = 0x00000800,
+};
+
+enum {
+	mcntrl_tdie = 0x00000001,
+	mcntrl_afie = 0x00000002,
+	mcntrl_naie = 0x00000004,
+	mcntrl_drmie = 0x00000008,
+	mcntrl_daie = 0x00000020,
+	mcntrl_rffie = 0x00000040,
+	mcntrl_tffie = 0x00000080,
+	mcntrl_reset = 0x00000100,
+	mcntrl_cdbmode = 0x00000400,
+};
+
+enum {
+	rw_bit = 1 << 0,
+	start_bit = 1 << 8,
+	stop_bit = 1 << 9,
+};
+
+#define I2C_REG_RX(a)	((a)->ioaddr)		/* Rx FIFO reg (RO) */
+#define I2C_REG_TX(a)	((a)->ioaddr)		/* Tx FIFO reg (WO) */
+#define I2C_REG_STS(a)	((a)->ioaddr + 0x04)	/* Status reg (RO) */
+#define I2C_REG_CTL(a)	((a)->ioaddr + 0x08)	/* Ctl reg */
+#define I2C_REG_CKL(a)	((a)->ioaddr + 0x0c)	/* Clock divider low */
+#define I2C_REG_CKH(a)	((a)->ioaddr + 0x10)	/* Clock divider high */
+#define I2C_REG_ADR(a)	((a)->ioaddr + 0x14)	/* I2C address */
+#define I2C_REG_RFL(a)	((a)->ioaddr + 0x18)	/* Rx FIFO level (RO) */
+#define I2C_REG_TFL(a)	((a)->ioaddr + 0x1c)	/* Tx FIFO level (RO) */
+#define I2C_REG_RXB(a)	((a)->ioaddr + 0x20)	/* Num of bytes Rx-ed (RO) */
+#define I2C_REG_TXB(a)	((a)->ioaddr + 0x24)	/* Num of bytes Tx-ed (RO) */
+#define I2C_REG_TXS(a)	((a)->ioaddr + 0x28)	/* Tx slave FIFO (RO) */
+#define I2C_REG_STFL(a)	((a)->ioaddr + 0x2c)	/* Tx slave FIFO level (RO) */
+
+#define I2C_CHIP_NAME		"PNX4008-I2C"
+
+#endif				/* __ASM_ARCH_I2C_H___ */
diff --git a/arch/arm/mach-lpc32xx/include/mach/io.h b/arch/arm/mach-lpc32xx/include/mach/io.h
new file mode 100644
index 0000000..0da8713
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/io.h
@@ -0,0 +1,31 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/io.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARM_ARCH_IO_H
+#define __ASM_ARM_ARCH_IO_H
+
+#define IO_SPACE_LIMIT	0xffffffff
+
+#define __io(a)		__typesafe_io(a)
+#define __mem_pci(a)	(a)
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/irqs.h b/arch/arm/mach-lpc32xx/include/mach/irqs.h
new file mode 100644
index 0000000..157a26c
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/irqs.h
@@ -0,0 +1,118 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/irqs.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARM_ARCH_IRQS_H
+#define __ASM_ARM_ARCH_IRQS_H
+
+/*
+ * MIC interrupts
+ */
+#define IRQ_SUB1IRQ		0
+#define IRQ_SUB2IRQ		1
+#define IRQ_PWM3		3
+#define IRQ_PWM4		4
+#define IRQ_HSTIMER		5
+#define IRQ_WATCH		6
+#define IRQ_UART_IIR3		7
+#define IRQ_UART_IIR4		8
+#define IRQ_UART_IIR5		9
+#define IRQ_UART_IIR6		10
+#define IRQ_FLASH		11
+#define IRQ_SD1			13
+#define IRQ_LCD			14
+#define IRQ_SD0			15
+#define IRQ_TIMER0		16
+#define IRQ_TIMER1		17
+#define IRQ_TIMER2		18
+#define IRQ_TIMER3		19
+#define IRQ_SSP0		20
+#define IRQ_SSP1		21
+#define IRQ_I2S0		22
+#define IRQ_I2S1		23
+#define IRQ_UART_IIR7		24
+#define IRQ_UART_IIR2		25
+#define IRQ_UART_IIR1		26
+#define IRQ_MSTIMER		27
+#define IRQ_DMA			28
+#define IRQ_ETHERNET		29
+#define IRQ_SUB1FIQ		30
+#define IRQ_SUB2FIQ		31
+
+/*
+ * SIC1 interrupts start at offset 32
+ */
+#define IRQ_JTAG_COMM_TX	(32 + 1)
+#define IRQ_JTAG_COMM_RX	(32 + 2)
+#define IRQ_GPI_11		(32 + 4)
+#define IRQ_TS_P		(32 + 6)
+#define IRQ_TS_IRQ		(32 + 7)
+#define IRQ_TS_AUX		(32 + 8)
+#define IRQ_SPI2		(32 + 12)
+#define IRQ_PLLUSB		(32 + 13)
+#define IRQ_PLLHCLK		(32 + 14)
+#define IRQ_PLL397		(32 + 17)
+#define IRQ_I2C_2		(32 + 18)
+#define IRQ_I2C_1		(32 + 19)
+#define IRQ_RTC			(32 + 20)
+#define IRQ_KEY			(32 + 22)
+#define IRQ_SPI1		(32 + 23)
+#define IRQ_SW			(32 + 24)
+#define IRQ_USB_OTG_TIMER	(32 + 25)
+#define IRQ_USB_OTG_ATX		(32 + 26)
+#define IRQ_USB_HOST		(32 + 27)
+#define IRQ_USB_DEV_DMA		(32 + 28)
+#define IRQ_USB_DEV_LP		(32 + 29)
+#define IRQ_USB_DEV_HP		(32 + 30)
+#define IRQ_USB_I2C		(32 + 31)
+
+/*
+ * SIC2 interrupts start at offset 64
+ */
+#define IRQ_GPIO_00		(64 + 0)
+#define IRQ_GPIO_01		(64 + 1)
+#define IRQ_GPIO_02		(64 + 2)
+#define IRQ_GPIO_03		(64 + 3)
+#define IRQ_GPIO_04		(64 + 4)
+#define IRQ_GPIO_05		(64 + 5)
+#define IRQ_SPI2_DATAIN		(64 + 6)
+#define IRQ_U2_HCTS		(64 + 7)
+#define IRQ_P0_P1_IRQ		(64 + 8)
+#define IRQ_GPI_08		(64 + 9)
+#define IRQ_GPI_09		(64 + 10)
+#define IRQ_GPI_10		(64 + 11)
+#define IRQ_U7_HCTS		(64 + 12)
+#define IRQ_GPI_07		(64 + 15)
+#define IRQ_SDIO		(64 + 18)
+#define IRQ_U5_RX		(64 + 19)
+#define IRQ_SPI1_DATAIN		(64 + 20)
+#define IRQ_GPI_00		(64 + 22)
+#define IRQ_GPI_01		(64 + 23)
+#define IRQ_GPI_02		(64 + 24)
+#define IRQ_GPI_03		(64 + 25)
+#define IRQ_GPI_04		(64 + 26)
+#define IRQ_GPI_05		(64 + 27)
+#define IRQ_GPI_06		(64 + 28)
+#define IRQ_SYSCLK		(64 + 31)
+
+#define NR_IRQS			96
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/memory.h b/arch/arm/mach-lpc32xx/include/mach/memory.h
new file mode 100644
index 0000000..b246973
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/memory.h
@@ -0,0 +1,32 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/memory.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_MEMORY_H
+#define __ASM_ARCH_MEMORY_H
+
+/*
+ * Physical DRAM offset of bank 0
+ */
+#define PHYS_OFFSET	UL(0x80000000)
+
+#endif
+
diff --git a/arch/arm/mach-lpc32xx/include/mach/platform.h b/arch/arm/mach-lpc32xx/include/mach/platform.h
new file mode 100644
index 0000000..48305a5
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/platform.h
@@ -0,0 +1,735 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/platform.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_PLATFORM_H
+#define __ASM_ARCH_PLATFORM_H
+
+#define _SBF(f, v)			(((v)) << (f))
+#define _BIT(n)				(1 << (n))
+
+/*
+ * AHB 0 physical base addresses
+ */
+#define SLC_BASE			0x20020000
+#define SSP0_BASE			0x20084000
+#define SPI1_BASE			0x20088000
+#define SSP1_BASE			0x2008C000
+#define SPI2_BASE			0x20090000
+#define I2S0_BASE			0x20094000
+#define SD_BASE				0x20098000
+#define I2S1_BASE			0x2009C000
+#define MLC_BASE			0x200A8000
+#define AHB0_START			SLC_BASE
+#define AHB0_SIZE			((MLC_BASE - SLC_BASE) + SZ_4K)
+
+/*
+ * AHB 1 physical base addresses
+ */
+#define DMA_BASE			0x31000000
+#define USB_BASE			0x31020000
+#define USBH_BASE			0x31020000
+#define USB_OTG_BASE			0x31020000
+#define OTG_I2C_BASE			0x31020300
+#define LCD_BASE			0x31040000
+#define ETHERNET_BASE			0x31060000
+#define EMC_BASE			0x31080000
+#define ETB_CFG_BASE			0x310C0000
+#define ETB_DATA_BASE			0x310E0000
+#define AHB1_START			DMA_BASE
+#define AHB1_SIZE			((EMC_BASE - DMA_BASE) + SZ_4K)
+
+/*
+ * FAB physical base addresses
+ */
+#define CLK_PM_BASE			0x40004000
+#define MIC_BASE			0x40008000
+#define SIC1_BASE			0x4000C000
+#define SIC2_BASE			0x40010000
+#define HS_UART1_BASE			0x40014000
+#define HS_UART2_BASE			0x40018000
+#define HS_UART7_BASE			0x4001C000
+#define RTC_BASE			0x40024000
+#define RTC_RAM_BASE			0x40024080
+#define GPIO_BASE			0x40028000
+#define PWM3_BASE			0x4002C000
+#define PWM4_BASE			0x40030000
+#define MSTIM_BASE			0x40034000
+#define HSTIM_BASE			0x40038000
+#define WDTIM_BASE			0x4003C000
+#define DEBUG_CTRL_BASE			0x40040000
+#define TIMER0_BASE			0x40044000
+#define ADC_BASE			0x40048000
+#define TIMER1_BASE			0x4004C000
+#define KSCAN_BASE			0x40050000
+#define UART_CTRL_BASE			0x40054000
+#define TIMER2_BASE			0x40058000
+#define PWM1_BASE			0x4005C000
+#define PWM2_BASE			0x4005C004
+#define TIMER3_BASE			0x40060000
+
+/*
+ * APB physical base addresses
+ */
+
+#define UART3_BASE			0x40080000
+#define UART4_BASE			0x40088000
+#define UART5_BASE			0x40090000
+#define UART6_BASE			0x40098000
+#define I2C1_BASE			0x400A0000
+#define I2C2_BASE			0x400A8000
+
+/*
+ * FAB and APB base and sizing
+ */
+#define FABAPB_START			CLK_PM_BASE
+#define FABAPB_SIZE			((I2C2_BASE - CLK_PM_BASE) + SZ_4K)
+
+/*
+ * Internal memory Bases
+ */
+#define IRAM_BASE			0x08000000
+#define IROM_BASE			0x0C000000
+
+/*
+ * External Static Memory Bank Address Space Bases
+ */
+#define EMC_CS0_BASE			0xE0000000
+#define EMC_CS1_BASE			0xE1000000
+#define EMC_CS2_BASE			0xE2000000
+#define EMC_CS3_BASE			0xE3000000
+
+/*
+ * External SDRAM Memory Bank Address Space Bases
+ */
+#define EMC_DYCS0_BASE			0x80000000
+#define EMC_DYCS1_BASE			0xA0000000
+
+/*
+ * Clock and crystal information
+ */
+#define MAIN_OSC_FREQ			13000000
+#define CLOCK_OSC_FREQ			32768
+
+/*
+ * IRAM size
+*/
+#define LPC32XX_IRAM_SIZE 		CONFIG_ARCH_LPC32XX_IRAM_SIZE
+
+/*
+ * Clock and Power control register offsets
+ */
+#define CLKPWR_DEBUG_CTRL(x)		((x) + 0x000)
+#define CLKPWR_BOOTMAP(x)		((x) + 0x014)
+#define CLKPWR_P01_ER(x)		((x) + 0x018)
+#define CLKPWR_USBCLK_PDIV(x)		((x) + 0x01C)
+#define CLKPWR_INT_ER(x)		((x) + 0x020)
+#define CLKPWR_INT_RS(x)		((x) + 0x024)
+#define CLKPWR_INT_SR(x)		((x) + 0x028)
+#define CLKPWR_INT_AP(x)		((x) + 0x02C)
+#define CLKPWR_PIN_ER(x)		((x) + 0x030)
+#define CLKPWR_PIN_RS(x)		((x) + 0x034)
+#define CLKPWR_PIN_SR(x)		((x) + 0x038)
+#define CLKPWR_PIN_AP(x)		((x) + 0x03C)
+#define CLKPWR_HCLK_DIV(x)		((x) + 0x040)
+#define CLKPWR_PWR_CTRL(x)		((x) + 0x044)
+#define CLKPWR_PLL397_CTRL(x)		((x) + 0x048)
+#define CLKPWR_MAIN_OSC_CTRL(x)		((x) + 0x04C)
+#define CLKPWR_SYSCLK_CTRL(x)		((x) + 0x050)
+#define CLKPWR_LCDCLK_CTRL(x)		((x) + 0x054)
+#define CLKPWR_HCLKPLL_CTRL(x)		((x) + 0x058)
+#define CLKPWR_ADC_CLK_CTRL_1(x)	((x) + 0x060)
+#define CLKPWR_USB_CTRL(x)		((x) + 0x064)
+#define CLKPWR_SDRAMCLK_CTRL(x)		((x) + 0x068)
+#define CLKPWR_DDR_LAP_NOM(x)		((x) + 0x06C)
+#define CLKPWR_DDR_LAP_COUNT(x)		((x) + 0x070)
+#define CLKPWR_DDR_LAP_DELAY(x)		((x) + 0x074)
+#define CLKPWR_SSP_CLK_CTRL(x)		((x) + 0x078)
+#define CLKPWR_I2S_CLK_CTRL(x)		((x) + 0x07C)
+#define CLKPWR_MS_CTRL(x)		((x) + 0x080)
+#define CLKPWR_MACCLK_CTRL(x)		((x) + 0x090)
+#define CLKPWR_TEST_CLK_SEL(x)		((x) + 0x0A4)
+#define CLKPWR_SFW_INT(x)		((x) + 0x0A8)
+#define CLKPWR_I2C_CLK_CTRL(x)		((x) + 0x0AC)
+#define CLKPWR_KEY_CLK_CTRL(x)		((x) + 0x0B0)
+#define CLKPWR_ADC_CLK_CTRL(x)		((x) + 0x0B4)
+#define CLKPWR_PWM_CLK_CTRL(x)		((x) + 0x0B8)
+#define CLKPWR_TIMER_CLK_CTRL(x)	((x) + 0x0BC)
+#define CLKPWR_TIMERS_PWMS_CLK_CTRL_1(x) ((x) + 0x0C0)
+#define CLKPWR_SPI_CLK_CTRL(x)		((x) + 0x0C4)
+#define CLKPWR_NAND_CLK_CTRL(x)		((x) + 0x0C8)
+#define CLKPWR_UART3_CLK_CTRL(x)	((x) + 0x0D0)
+#define CLKPWR_UART4_CLK_CTRL(x)	((x) + 0x0D4)
+#define CLKPWR_UART5_CLK_CTRL(x)	((x) + 0x0D8)
+#define CLKPWR_UART6_CLK_CTRL(x)	((x) + 0x0DC)
+#define CLKPWR_IRDA_CLK_CTRL(x)		((x) + 0x0E0)
+#define CLKPWR_UART_CLK_CTRL(x)		((x) + 0x0E4)
+#define CLKPWR_DMA_CLK_CTRL(x)		((x) + 0x0E8)
+#define CLKPWR_AUTOCLOCK(x)		((x) + 0x0EC)
+#define CLKPWR_DEVID(x, y)		((x) + 0x130 + (y))
+
+/*
+ * clkpwr_debug_ctrl register definitions
+*/
+#define CLKPWR_VFP_CLOCK_ENABLE_BIT	_BIT(4)
+
+/*
+ * clkpwr_bootmap register definitions
+ */
+#define CLKPWR_BOOTMAP_SEL_BIT		_BIT(1)
+
+/*
+ * clkpwr_start_gpio register bit definitions
+ */
+#define CLKPWR_GPIOSRC_P1IO23_BIT	_BIT(31)
+#define CLKPWR_GPIOSRC_P1IO22_BIT	_BIT(30)
+#define CLKPWR_GPIOSRC_P1IO21_BIT	_BIT(29)
+#define CLKPWR_GPIOSRC_P1IO20_BIT	_BIT(28)
+#define CLKPWR_GPIOSRC_P1IO19_BIT	_BIT(27)
+#define CLKPWR_GPIOSRC_P1IO18_BIT	_BIT(26)
+#define CLKPWR_GPIOSRC_P1IO17_BIT	_BIT(25)
+#define CLKPWR_GPIOSRC_P1IO16_BIT	_BIT(24)
+#define CLKPWR_GPIOSRC_P1IO15_BIT	_BIT(23)
+#define CLKPWR_GPIOSRC_P1IO14_BIT	_BIT(22)
+#define CLKPWR_GPIOSRC_P1IO13_BIT	_BIT(21)
+#define CLKPWR_GPIOSRC_P1IO12_BIT	_BIT(20)
+#define CLKPWR_GPIOSRC_P1IO11_BIT	_BIT(19)
+#define CLKPWR_GPIOSRC_P1IO10_BIT	_BIT(18)
+#define CLKPWR_GPIOSRC_P1IO9_BIT	_BIT(17)
+#define CLKPWR_GPIOSRC_P1IO8_BIT	_BIT(16)
+#define CLKPWR_GPIOSRC_P1IO7_BIT	_BIT(15)
+#define CLKPWR_GPIOSRC_P1IO6_BIT	_BIT(14)
+#define CLKPWR_GPIOSRC_P1IO5_BIT	_BIT(13)
+#define CLKPWR_GPIOSRC_P1IO4_BIT	_BIT(12)
+#define CLKPWR_GPIOSRC_P1IO3_BIT	_BIT(11)
+#define CLKPWR_GPIOSRC_P1IO2_BIT	_BIT(10)
+#define CLKPWR_GPIOSRC_P1IO1_BIT	_BIT(9)
+#define CLKPWR_GPIOSRC_P1IO0_BIT	_BIT(8)
+#define CLKPWR_GPIOSRC_P0IO7_BIT	_BIT(7)
+#define CLKPWR_GPIOSRC_P0IO6_BIT	_BIT(6)
+#define CLKPWR_GPIOSRC_P0IO5_BIT	_BIT(5)
+#define CLKPWR_GPIOSRC_P0IO4_BIT	_BIT(4)
+#define CLKPWR_GPIOSRC_P0IO3_BIT	_BIT(3)
+#define CLKPWR_GPIOSRC_P0IO2_BIT	_BIT(2)
+#define CLKPWR_GPIOSRC_P0IO1_BIT	_BIT(1)
+#define CLKPWR_GPIOSRC_P0IO0_BIT	_BIT(0)
+
+/*
+ * clkpwr_usbclk_pdiv register definitions
+ */
+#define CLKPWR_SET_PLL_USBPDIV(n)	((n) & 0xF)
+#define CLKPWR_USBPDIV_PLL_MASK		0xF
+
+/*
+ * clkpwr_start_int, clkpwr_start_raw_sts_int, clkpwr_start_sts_int,
+ * clkpwr_start_pol_int, register bit definitions
+ */
+#define CLKPWR_INTSRC_ADC_BIT		_BIT(31)
+#define CLKPWR_INTSRC_TS_P_BIT		_BIT(30)
+#define CLKPWR_INTSRC_TS_AUX_BIT	_BIT(29)
+#define CLKPWR_INTSRC_USBAHNEEDCLK_BIT	_BIT(26)
+#define CLKPWR_INTSRC_MSTIMER_BIT	_BIT(25)
+#define CLKPWR_INTSRC_RTC_BIT		_BIT(24)
+#define CLKPWR_INTSRC_USBNEEDCLK_BIT	_BIT(23)
+#define CLKPWR_INTSRC_USB_BIT		_BIT(22)
+#define CLKPWR_INTSRC_I2C_BIT		_BIT(21)
+#define CLKPWR_INTSRC_USBOTGTIMER_BIT	_BIT(20)
+#define CLKPWR_INTSRC_USBATXINT_BIT	_BIT(19)
+#define CLKPWR_INTSRC_KEY_BIT		_BIT(16)
+#define CLKPWR_INTSRC_MAC_BIT		_BIT(7)
+#define CLKPWR_INTSRC_P0P1_BIT		_BIT(6)
+#define CLKPWR_INTSRC_GPIO_05_BIT	_BIT(5)
+#define CLKPWR_INTSRC_GPIO_04_BIT	_BIT(4)
+#define CLKPWR_INTSRC_GPIO_03_BIT	_BIT(3)
+#define CLKPWR_INTSRC_GPIO_02_BIT	_BIT(2)
+#define CLKPWR_INTSRC_GPIO_01_BIT	_BIT(1)
+#define CLKPWR_INTSRC_GPIO_00_BIT	_BIT(0)
+
+/*
+ * clkpwr_start_pin, clkpwr_start_raw_sts_pin, clkpwr_start_sts_pin,
+ * clkpwr_start_pol_pin register bit definitions
+ */
+#define CLKPWR_EXTSRC_U7_RX_BIT		_BIT(31)
+#define CLKPWR_EXTSRC_U7_HCTS_BIT	_BIT(30)
+#define CLKPWR_EXTSRC_U6_IRRX_BIT	_BIT(28)
+#define CLKPWR_EXTSRC_U5_RX_BIT		_BIT(26)
+#define CLKPWR_EXTSRC_GPI_11_BIT	_BIT(25)
+#define CLKPWR_EXTSRC_U3_RX_BIT		_BIT(24)
+#define CLKPWR_EXTSRC_U2_HCTS_BIT	_BIT(23)
+#define CLKPWR_EXTSRC_U2_RX_BIT		_BIT(22)
+#define CLKPWR_EXTSRC_U1_RX_BIT		_BIT(21)
+#define CLKPWR_EXTSRC_MSDIO_INT_BIT	_BIT(18)
+#define CLKPWR_EXTSRC_MSDIO_SRT_BIT	_BIT(17)
+#define CLKPWR_EXTSRC_GPIO_O6_BIT	_BIT(16)
+#define CLKPWR_EXTSRC_GPIO_O5_BIT	_BIT(15)
+#define CLKPWR_EXTSRC_GPIO_O4_BIT	_BIT(14)
+#define CLKPWR_EXTSRC_GPIO_O3_BIT	_BIT(13)
+#define CLKPWR_EXTSRC_GPIO_O2_BIT	_BIT(12)
+#define CLKPWR_EXTSRC_GPIO_O1_BIT	_BIT(11)
+#define CLKPWR_EXTSRC_GPIO_O0_BIT	_BIT(10)
+#define CLKPWR_EXTSRC_SYSCLKEN_BIT	_BIT(9)
+#define CLKPWR_EXTSRC_SPI1_DATIN_BIT	_BIT(8)
+#define CLKPWR_EXTSRC_GPIO_O7_BIT	_BIT(7)
+#define CLKPWR_EXTSRC_SPI2_DATIN_BIT	_BIT(6)
+#define CLKPWR_EXTSRC_GPIO_19_BIT	_BIT(5)
+#define CLKPWR_EXTSRC_GPIO_O9_BIT	_BIT(4)
+#define CLKPWR_EXTSRC_GPIO_O8_BIT	_BIT(3)
+
+/*
+ * clkpwr_hclk_div register definitions
+ */
+#define CLKPWR_HCLKDIV_DDRCLK_STOP	(0x0 << 7)
+#define CLKPWR_HCLKDIV_DDRCLK_NORM	(0x1 << 7)
+#define CLKPWR_HCLKDIV_DDRCLK_HALF	(0x2 << 7)
+#define CLKPWR_HCLKDIV_PCLK_DIV(n)	(((n) & 0x1F) << 2)
+#define CLKPWR_HCLKDIV_DIV_2POW(n)	((n) & 0x3)
+
+/*
+ * clkpwr_pwr_ctrl register definitions
+ */
+#define CLKPWR_CTRL_FORCE_PCLK		_BIT(10)
+#define CLKPWR_SDRAM_SELF_RFSH		_BIT(9)
+#define CLKPWR_UPD_SDRAM_SELF_RFSH	_BIT(8)
+#define CLKPWR_AUTO_SDRAM_SELF_RFSH	_BIT(7)
+#define CLKPWR_HIGHCORE_STATE_BIT	_BIT(5)
+#define CLKPWR_SYSCLKEN_STATE_BIT	_BIT(4)
+#define CLKPWR_SYSCLKEN_GPIO_EN		_BIT(3)
+#define CLKPWR_SELECT_RUN_MODE		_BIT(2)
+#define CLKPWR_HIGHCORE_GPIO_EN		_BIT(1)
+#define CLKPWR_STOP_MODE_CTRL		_BIT(0)
+
+/*
+ * clkpwr_pll397_ctrl register definitions
+ */
+#define CLKPWR_PLL397_MSLOCK_STS	_BIT(10)
+#define CLKPWR_PLL397_BYPASS		_BIT(9)
+#define CLKPWR_PLL397_BIAS_NORM		0x000
+#define CLKPWR_PLL397_BIAS_N12_5	0x040
+#define CLKPWR_PLL397_BIAS_N25		0x080
+#define CLKPWR_PLL397_BIAS_N37_5	0x0C0
+#define CLKPWR_PLL397_BIAS_P12_5	0x100
+#define CLKPWR_PLL397_BIAS_P25		0x140
+#define CLKPWR_PLL397_BIAS_P37_5	0x180
+#define CLKPWR_PLL397_BIAS_P50		0x1C0
+#define CLKPWR_PLL397_BIAS_MASK		0x1C0
+#define CLKPWR_SYSCTRL_PLL397_DIS	_BIT(1)
+#define CLKPWR_SYSCTRL_PLL397_STS	_BIT(0)
+
+/*
+ * clkpwr_main_osc_ctrl register definitions
+ */
+#define CLKPWR_MOSC_ADD_CAP(n)		(((n) & 0x7F) << 2)
+#define CLKPWR_MOSC_CAP_MASK		(0x7F << 2)
+#define CLKPWR_TEST_MODE		_BIT(1)
+#define CLKPWR_MOSC_DISABLE		_BIT(0)
+
+/*
+ * clkpwr_sysclk_ctrl register definitions
+ */
+#define CLKPWR_SYSCTRL_BP_TRIG(n)	(((n) & 0x3FF) << 2)
+#define CLKPWR_SYSCTRL_BP_MASK		(0x3FF << 2)
+#define CLKPWR_SYSCTRL_USEPLL397	_BIT(1)
+#define CLKPWR_SYSCTRL_SYSCLKMUX	_BIT(0)
+
+/*
+ * clkpwr_lcdclk_ctrl register definitions
+ */
+#define CLKPWR_LCDCTRL_LCDTYPE_TFT12	0x000
+#define CLKPWR_LCDCTRL_LCDTYPE_TFT16	0x040
+#define CLKPWR_LCDCTRL_LCDTYPE_TFT15	0x080
+#define CLKPWR_LCDCTRL_LCDTYPE_TFT24	0x0C0
+#define CLKPWR_LCDCTRL_LCDTYPE_STN4M	0x100
+#define CLKPWR_LCDCTRL_LCDTYPE_STN8C	0x140
+#define CLKPWR_LCDCTRL_LCDTYPE_DSTN4M	0x180
+#define CLKPWR_LCDCTRL_LCDTYPE_DSTN8C	0x1C0
+#define CLKPWR_LCDCTRL_LCDTYPE_MSK	0x01C0
+#define CLKPWR_LCDCTRL_CLK_EN		0x020
+#define CLKPWR_LCDCTRL_SET_PSCALE(n)	((n - 1) & 0x1F)
+#define CLKPWR_LCDCTRL_PSCALE_MSK	0x001F
+
+/*
+ * clkpwr_hclkpll_ctrl register definitions
+ */
+#define CLKPWR_HCLKPLL_POWER_UP		_BIT(16)
+#define CLKPWR_HCLKPLL_CCO_BYPASS	_BIT(15)
+#define CLKPWR_HCLKPLL_POSTDIV_BYPASS	_BIT(14)
+#define CLKPWR_HCLKPLL_FDBK_SEL_FCLK	_BIT(13)
+#define CLKPWR_HCLKPLL_POSTDIV_2POW(n)	(((n) & 0x3) << 11)
+#define CLKPWR_HCLKPLL_PREDIV_PLUS1(n)	(((n) & 0x3) << 9)
+#define CLKPWR_HCLKPLL_PLLM(n)		(((n) & 0xFF) << 1)
+#define CLKPWR_HCLKPLL_PLL_STS		_BIT(0)
+
+/*
+ * clkpwr_adc_clk_ctrl_1 register definitions
+ */
+#define CLKPWR_ADCCTRL1_RTDIV(n)	(((n) & 0xFF) << 0)
+#define CLKPWR_ADCCTRL1_PCLK_SEL	_BIT(8)
+
+/*
+ * clkpwr_usb_ctrl register definitions
+ */
+#define CLKPWR_USBCTRL_HCLK_EN		_BIT(24)
+#define CLKPWR_USBCTRL_USBI2C_EN	_BIT(23)
+#define CLKPWR_USBCTRL_USBDVND_EN	_BIT(22)
+#define CLKPWR_USBCTRL_USBHSTND_EN	_BIT(21)
+#define CLKPWR_USBCTRL_PU_ADD		(0x0 << 19)
+#define CLKPWR_USBCTRL_BUS_KEEPER	(0x1 << 19)
+#define CLKPWR_USBCTRL_PD_ADD		(0x3 << 19)
+#define CLKPWR_USBCTRL_CLK_EN2		_BIT(18)
+#define CLKPWR_USBCTRL_CLK_EN1		_BIT(17)
+#define CLKPWR_USBCTRL_PLL_PWRUP	_BIT(16)
+#define CLKPWR_USBCTRL_CCO_BYPASS	_BIT(15)
+#define CLKPWR_USBCTRL_POSTDIV_BYPASS	_BIT(14)
+#define CLKPWR_USBCTRL_FDBK_SEL_FCLK	_BIT(13)
+#define CLKPWR_USBCTRL_POSTDIV_2POW(n)	(((n) & 0x3) << 11)
+#define CLKPWR_USBCTRL_PREDIV_PLUS1(n)	(((n) & 0x3) << 9)
+#define CLKPWR_USBCTRL_FDBK_PLUS1(n)	(((n) & 0xFF) << 1)
+#define CLKPWR_USBCTRL_PLL_STS		_BIT(0)
+
+/*
+ * clkpwr_sdramclk_ctrl register definitions
+ */
+#define CLKPWR_SDRCLK_FASTSLEW_CLK	_BIT(22)
+#define CLKPWR_SDRCLK_FASTSLEW		_BIT(21)
+#define CLKPWR_SDRCLK_FASTSLEW_DAT	_BIT(20)
+#define CLKPWR_SDRCLK_SW_DDR_RESET	_BIT(19)
+#define CLKPWR_SDRCLK_HCLK_DLY(n)	(((n) & 0x1F) << 14)
+#define CLKPWR_SDRCLK_DLY_ADDR_STS	_BIT(13)
+#define CLKPWR_SDRCLK_SENS_FACT(n)	(((n) & 0x7) << 10)
+#define CLKPWR_SDRCLK_USE_CAL		_BIT(9)
+#define CLKPWR_SDRCLK_DO_CAL		_BIT(8)
+#define CLKPWR_SDRCLK_CAL_ON_RTC	_BIT(7)
+#define CLKPWR_SDRCLK_DQS_DLY(n)	(((n) & 0x1F) << 2)
+#define CLKPWR_SDRCLK_USE_DDR		_BIT(1)
+#define CLKPWR_SDRCLK_CLK_DIS		_BIT(0)
+
+/*
+ * clkpwr_ssp_blk_ctrl register definitions
+ */
+#define CLKPWR_SSPCTRL_DMA_SSP1RX	_BIT(5)
+#define CLKPWR_SSPCTRL_DMA_SSP1TX	_BIT(4)
+#define CLKPWR_SSPCTRL_DMA_SSP0RX	_BIT(3)
+#define CLKPWR_SSPCTRL_DMA_SSP0TX	_BIT(2)
+#define CLKPWR_SSPCTRL_SSPCLK1_EN	_BIT(1)
+#define CLKPWR_SSPCTRL_SSPCLK0_EN	_BIT(0)
+
+/*
+ * clkpwr_i2s_clk_ctrl register definitions
+ */
+#define CLKPWR_I2SCTRL_I2S1_RX_FOR_TX	_BIT(6)
+#define CLKPWR_I2SCTRL_I2S1_TX_FOR_RX	_BIT(5)
+#define CLKPWR_I2SCTRL_I2S1_USE_DMA	_BIT(4)
+#define CLKPWR_I2SCTRL_I2S0_RX_FOR_TX	_BIT(3)
+#define CLKPWR_I2SCTRL_I2S0_TX_FOR_RX	_BIT(2)
+#define CLKPWR_I2SCTRL_I2SCLK1_EN	_BIT(1)
+#define CLKPWR_I2SCTRL_I2SCLK0_EN	_BIT(0)
+
+/*
+ * clkpwr_ms_ctrl register definitions
+ */
+#define CLKPWR_MSCARD_MSDIO_PIN_DIS	_BIT(10)
+#define CLKPWR_MSCARD_MSDIO_PU_EN	_BIT(9)
+#define CLKPWR_MSCARD_MSDIO23_DIS	_BIT(8)
+#define CLKPWR_MSCARD_MSDIO1_DIS	_BIT(7)
+#define CLKPWR_MSCARD_MSDIO0_DIS	_BIT(6)
+#define CLKPWR_MSCARD_SDCARD_EN		_BIT(5)
+#define CLKPWR_MSCARD_SDCARD_DIV(n)	((n) & 0xF)
+
+/*
+ * clkpwr_macclk_ctrl register definitions
+ */
+#define CLKPWR_MACCTRL_NO_ENET_PIS	0x00
+#define CLKPWR_MACCTRL_USE_MII_PINS	0x08
+#define CLKPWR_MACCTRL_USE_RMII_PINS	0x18
+#define CLKPWR_MACCTRL_PINS_MSK		0x18
+#define CLKPWR_MACCTRL_DMACLK_EN	_BIT(2)
+#define CLKPWR_MACCTRL_MMIOCLK_EN	_BIT(1)
+#define CLKPWR_MACCTRL_HRCCLK_EN	_BIT(0)
+
+/*
+ * clkpwr_test_clk_sel register definitions
+ */
+#define CLKPWR_TESTCLK1_SEL_PERCLK	(0x0 << 5)
+#define CLKPWR_TESTCLK1_SEL_RTC		(0x1 << 5)
+#define CLKPWR_TESTCLK1_SEL_MOSC	(0x2 << 5)
+#define CLKPWR_TESTCLK1_SEL_MASK	(0x3 << 5)
+#define CLKPWR_TESTCLK_TESTCLK1_EN	_BIT(4)
+#define CLKPWR_TESTCLK2_SEL_HCLK	(0x0 << 1)
+#define CLKPWR_TESTCLK2_SEL_PERCLK	(0x1 << 1)
+#define CLKPWR_TESTCLK2_SEL_USBCLK	(0x2 << 1)
+#define CLKPWR_TESTCLK2_SEL_MOSC	(0x5 << 1)
+#define CLKPWR_TESTCLK2_SEL_PLL397	(0x7 << 1)
+#define CLKPWR_TESTCLK2_SEL_MASK	(0x7 << 1)
+#define CLKPWR_TESTCLK_TESTCLK2_EN	_BIT(0)
+
+/*
+ * clkpwr_sw_int register definitions
+ */
+#define CLKPWR_SW_INT(n)		(_BIT(0) | (((n) & 0x7F) << 1))
+#define CLKPWR_SW_GET_ARG(n)		(((n) & 0xFE) >> 1)
+
+/*
+ * clkpwr_i2c_clk_ctrl register definitions
+ */
+#define CLKPWR_I2CCLK_USBI2CHI_DRIVE	_BIT(4)
+#define CLKPWR_I2CCLK_I2C2HI_DRIVE	_BIT(3)
+#define CLKPWR_I2CCLK_I2C1HI_DRIVE	_BIT(2)
+#define CLKPWR_I2CCLK_I2C2CLK_EN	_BIT(1)
+#define CLKPWR_I2CCLK_I2C1CLK_EN	_BIT(0)
+
+/*
+ * clkpwr_key_clk_ctrl register definitions
+ */
+#define CLKPWR_KEYCLKCTRL_CLK_EN	0x1
+
+/*
+ * clkpwr_adc_clk_ctrl register definitions
+ */
+#define CLKPWR_ADC32CLKCTRL_CLK_EN	0x1
+
+/*
+ * clkpwr_pwm_clk_ctrl register definitions
+ */
+#define CLKPWR_PWMCLK_PWM2_DIV(n)	(((n) & 0xF) << 8)
+#define CLKPWR_PWMCLK_PWM1_DIV(n)	(((n) & 0xF) << 4)
+#define CLKPWR_PWMCLK_PWM2SEL_PCLK	0x8
+#define CLKPWR_PWMCLK_PWM2CLK_EN	0x4
+#define CLKPWR_PWMCLK_PWM1SEL_PCLK	0x2
+#define CLKPWR_PWMCLK_PWM1CLK_EN	0x1
+
+/*
+ * clkpwr_timer_clk_ctrl register definitions
+ */
+#define CLKPWR_PWMCLK_HSTIMER_EN	0x2
+#define CLKPWR_PWMCLK_WDOG_EN		0x1
+
+/*
+ * clkpwr_timers_pwms_clk_ctrl_1 register definitions
+ */
+#define CLKPWR_TMRPWMCLK_TIMER3_EN	0x20
+#define CLKPWR_TMRPWMCLK_TIMER2_EN	0x10
+#define CLKPWR_TMRPWMCLK_TIMER1_EN	0x08
+#define CLKPWR_TMRPWMCLK_TIMER0_EN	0x04
+#define CLKPWR_TMRPWMCLK_PWM4_EN	0x02
+#define CLKPWR_TMRPWMCLK_PWM3_EN	0x01
+
+/*
+ * clkpwr_spi_clk_ctrl register definitions
+ */
+#define CLKPWR_SPICLK_SET_SPI2DATIO	0x80
+#define CLKPWR_SPICLK_SET_SPI2CLK	0x40
+#define CLKPWR_SPICLK_USE_SPI2		0x20
+#define CLKPWR_SPICLK_SPI2CLK_EN	0x10
+#define CLKPWR_SPICLK_SET_SPI1DATIO	0x08
+#define CLKPWR_SPICLK_SET_SPI1CLK	0x04
+#define CLKPWR_SPICLK_USE_SPI1		0x02
+#define CLKPWR_SPICLK_SPI1CLK_EN	0x01
+
+/*
+ * clkpwr_nand_clk_ctrl register definitions
+ */
+#define CLKPWR_NANDCLK_INTSEL_MLC	0x20
+#define CLKPWR_NANDCLK_DMA_RNB		0x10
+#define CLKPWR_NANDCLK_DMA_INT		0x08
+#define CLKPWR_NANDCLK_SEL_SLC		0x04
+#define CLKPWR_NANDCLK_MLCCLK_EN	0x02
+#define CLKPWR_NANDCLK_SLCCLK_EN	0x01
+
+/*
+ * clkpwr_uart3_clk_ctrl, clkpwr_uart4_clk_ctrl, clkpwr_uart5_clk_ctrl
+ * and clkpwr_uart6_clk_ctrl register definitions
+ */
+#define CLKPWR_UART_Y_DIV(y)		((y) & 0xFF)
+#define CLKPWR_UART_X_DIV(x)		(((x) & 0xFF) << 8)
+#define CLKPWR_UART_USE_HCLK		_BIT(16)
+
+/*
+ * clkpwr_irda_clk_ctrl register definitions
+ */
+#define CLKPWR_IRDA_Y_DIV(y)		((y) & 0xFF)
+#define CLKPWR_IRDA_X_DIV(x)		(((x) & 0xFF) << 8)
+
+/*
+ * clkpwr_uart_clk_ctrl register definitions
+ */
+#define CLKPWR_UARTCLKCTRL_UART6_EN	_BIT(3)
+#define CLKPWR_UARTCLKCTRL_UART5_EN	_BIT(2)
+#define CLKPWR_UARTCLKCTRL_UART4_EN	_BIT(1)
+#define CLKPWR_UARTCLKCTRL_UART3_EN	_BIT(0)
+
+/*
+ * clkpwr_dmaclk_ctrl register definitions
+ */
+#define CLKPWR_DMACLKCTRL_CLK_EN	0x1
+
+/*
+ * clkpwr_autoclock register definitions
+ */
+#define CLKPWR_AUTOCLK_USB_EN		0x40
+#define CLKPWR_AUTOCLK_IRAM_EN		0x02
+#define CLKPWR_AUTOCLK_IROM_EN		0x01
+
+/*
+ * Interrupt controller register offsets
+ */
+#define INTC_MASK		0x00
+#define INTC_RAW_STAT		0x04
+#define INTC_STAT		0x08
+#define INTC_POLAR		0x0C
+#define INTC_ACT_TYPE		0x10
+#define INTC_TYPE		0x14
+
+/*
+ *
+ * Timer/counter register offsets
+ *
+ */
+#define TIMER_IR(x)			((x) + 0x00)
+#define TIMER_TCR(x)			((x) + 0x04)
+#define TIMER_TC(x)			((x) + 0x08)
+#define TIMER_PR(x)			((x) + 0x0C)
+#define TIMER_PC(x)			((x) + 0x10)
+#define TIMER_MCR(x)			((x) + 0x14)
+#define TIMER_MR0(x)			((x) + 0x18)
+#define TIMER_MR1(x)			((x) + 0x1C)
+#define TIMER_MR2(x)			((x) + 0x20)
+#define TIMER_MR3(x)			((x) + 0x24)
+#define TIMER_CCR(x)			((x) + 0x28)
+#define TIMER_CR0(x)			((x) + 0x2C)
+#define TIMER_CR1(x)			((x) + 0x30)
+#define TIMER_CR2(x)			((x) + 0x34)
+#define TIMER_CR3(x)			((x) + 0x38)
+#define TIMER_EMR(x)			((x) + 0x3C)
+#define TIMER_CTCR(x)			((x) + 0x70)
+
+/*
+ * ir register definitions
+ */
+#define TIMER_CNTR_MTCH_BIT(n)		(1 << ((n) & 0x3))
+#define TIMER_CNTR_CAPT_BIT(n)		(1 << (4 + ((n) & 0x3)))
+
+/*
+ * tcr register definitions
+ */
+#define TIMER_CNTR_TCR_EN		0x1
+#define TIMER_CNTR_TCR_RESET		0x2
+
+/*
+ * mcr register definitions
+ */
+#define TIMER_CNTR_MCR_MTCH(n)		(0x1 << ((n) * 3))
+#define TIMER_CNTR_MCR_RESET(n)		(0x1 << (((n) * 3) + 1))
+#define TIMER_CNTR_MCR_STOP(n)		(0x1 << (((n) * 3) + 2))
+
+/*
+ *
+ * Standard UART register offsets
+ *
+ */
+#define UART_DLL_FIFO(x)		((x) + 0x00)
+#define UART_DLM_IER(x)			((x) + 0x04)
+#define UART_IIR_FCR(x)			((x) + 0x08)
+#define UART_LCR_(x)			((x) + 0x0C)
+#define UART_MODEM_CTRL(x)		((x) + 0x10)
+#define UART_LSR_(x)			((x) + 0x14)
+#define UART_MODEM_STATUS(x)		((x) + 0x18)
+#define UART_RXLEV(x)			((x) + 0x1C)
+
+/*
+ *
+ * UART control structure offsets
+ *
+ */
+#define UARTCTL_CTRL(x)			((x) + 0x00)
+#define UARTCTL_CLKMODE(x)		((x) + 0x04)
+#define UARTCTL_CLOOP(x)		((x) + 0x08)
+
+/*
+ * ctrl register definitions
+ */
+#define UART_U3_MD_CTRL_EN		_BIT(11)
+#define UART_IRRX6_INV_EN		_BIT(10)
+#define UART_HDPX_EN			_BIT(9)
+#define UART_UART6_IRDAMOD_BYPASS	_BIT(5)
+#define RT_IRTX6_INV_EN			_BIT(4)
+#define RT_IRTX6_INV_MIR_EN		_BIT(3)
+#define RT_RX_IRPULSE_3_16_115K		_BIT(2)
+#define RT_TX_IRPULSE_3_16_115K		_BIT(1)
+#define UART_U5_ROUTE_TO_USB		_BIT(0)
+
+/*
+ * clkmode register definitions
+ */
+#define UART_ENABLED_CLOCKS(n)		(((n) >> 16) & 0x7F)
+#define UART_ENABLED_CLOCK(n, u)	(((n) >> (16 + (u))) & 0x1)
+#define UART_ENABLED_CLKS_ANY		_BIT(14)
+#define UART_CLKMODE_OFF		0x0
+#define UART_CLKMODE_ON			0x1
+#define UART_CLKMODE_AUTO		0x2
+#define UART_CLKMODE_MASK(u)		(0x3 << ((((u) - 3) * 2) + 4))
+#define UART_CLKMODE_LOAD(m, u)		((m) << ((((u) - 3) * 2) + 4))
+
+/*
+ *
+ * GPIO Module Register offsets
+ *
+ */
+#define GPIO_P3_INP_STATE(x)		((x) + 0x000)
+#define GPIO_P3_OUTP_SET(x)		((x) + 0x004)
+#define GPIO_P3_OUTP_CLR(x)		((x) + 0x008)
+#define GPIO_P3_OUTP_STATE(x)		((x) + 0x00C)
+#define GPIO_P2_DIR_SET(x)		((x) + 0x010)
+#define GPIO_P2_DIR_CLR(x)		((x) + 0x014)
+#define GPIO_P2_DIR_STATE(x)		((x) + 0x018)
+#define GPIO_P2_INP_STATE(x)		((x) + 0x01C)
+#define GPIO_P2_OUTP_SET(x)		((x) + 0x020)
+#define GPIO_P2_OUTP_CLR(x)		((x) + 0x024)
+#define GPIO_P2_MUX_SET(x)		((x) + 0x028)
+#define GPIO_P2_MUX_CLR(x)		((x) + 0x02C)
+#define GPIO_P2_MUX_STATE(x)		((x) + 0x030)
+#define GPIO_P0_INP_STATE(x)		((x) + 0x040)
+#define GPIO_P0_OUTP_SET(x)		((x) + 0x044)
+#define GPIO_P0_OUTP_CLR(x)		((x) + 0x048)
+#define GPIO_P0_OUTP_STATE(x)		((x) + 0x04C)
+#define GPIO_P0_DIR_SET(x)		((x) + 0x050)
+#define GPIO_P0_DIR_CLR(x)		((x) + 0x054)
+#define GPIO_P0_DIR_STATE(x)		((x) + 0x058)
+#define GPIO_P1_INP_STATE(x)		((x) + 0x060)
+#define GPIO_P1_OUTP_SET(x)		((x) + 0x064)
+#define GPIO_P1_OUTP_CLR(x)		((x) + 0x068)
+#define GPIO_P1_OUTP_STATE(x)		((x) + 0x06C)
+#define GPIO_P1_DIR_SET(x)		((x) + 0x070)
+#define GPIO_P1_DIR_CLR(x)		((x) + 0x074)
+#define GPIO_P1_DIR_STATE(x)		((x) + 0x078)
+#define GPIO_P_MUX_SET(x)		((x) + 0x100)
+#define GPIO_P_MUX_CLR(x)		((x) + 0x104)
+#define GPIO_P_MUX_STATE(x)		((x) + 0x108)
+#define GPIO_P3_MUX_SET(x)		((x) + 0x110)
+#define GPIO_P3_MUX_CLR(x)		((x) + 0x114)
+#define GPIO_P3_MUX_STATE(x)		((x) + 0x118)
+#define GPIO_P0_MUX_SET(x)		((x) + 0x120)
+#define GPIO_P0_MUX_CLR(x)		((x) + 0x124)
+#define GPIO_P0_MUX_STATE(x)		((x) + 0x128)
+#define GPIO_P1_MUX_SET(x)		((x) + 0x130)
+#define GPIO_P1_MUX_CLR(x)		((x) + 0x134)
+#define GPIO_P1_MUX_STATE(x)		((x) + 0x138)
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/system.h b/arch/arm/mach-lpc32xx/include/mach/system.h
new file mode 100644
index 0000000..29bd2e4
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/system.h
@@ -0,0 +1,56 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/system.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_SYSTEM_H
+#define __ASM_ARCH_SYSTEM_H
+
+static void arch_idle(void)
+{
+	cpu_do_idle();
+}
+
+static inline void arch_reset(char mode, const char *cmd)
+{
+	extern void lpc32xx_watchdog_reset(void);
+
+	switch (mode) {
+	case 's':
+	case 'h':
+		printk(KERN_CRIT "RESET: Rebooting system\n");
+
+		/* Disable interrupts */
+		local_irq_disable();
+
+		lpc32xx_watchdog_reset();
+		break;
+
+	default:
+		/* Do nothing */
+		break;
+	}
+
+	/* Wait for watchdog to reset system */
+	while (1)
+		;
+}
+
+#endif
diff --git a/arch/arm/mach-lpc32xx/include/mach/timex.h b/arch/arm/mach-lpc32xx/include/mach/timex.h
new file mode 100644
index 0000000..1f872c5
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/timex.h
@@ -0,0 +1,33 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/timex.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_TIMEX_H
+#define __ASM_ARCH_TIMEX_H
+
+/*
+ * Rate in Hz of the main system oscillator. This value should match
+ * the value 'MAIN_OSC_FREQ' in platform.h
+ */
+#define CLOCK_TICK_RATE	13000000
+
+#endif
+
diff --git a/arch/arm/mach-lpc32xx/include/mach/uncompress.h b/arch/arm/mach-lpc32xx/include/mach/uncompress.h
new file mode 100644
index 0000000..a00ecc5
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/uncompress.h
@@ -0,0 +1,114 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/uncompress.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARM_ARCH_UNCOMPRESS_H
+#define __ASM_ARM_ARCH_UNCOMPRESS_H
+
+#include <linux/io.h>
+
+#include <mach/platform.h>
+
+#if defined(CONFIG_ARCH_LPC32XX_UNCOMP_HSU1) || \
+	defined(CONFIG_ARCH_LPC32XX_UNCOMP_HSU2) || \
+	defined(CONFIG_ARCH_LPC32XX_UNCOMP_HSU7)
+/*
+ * High speed UART uncompress output support
+*/
+#ifdef CONFIG_ARCH_LPC32XX_UNCOMP_HSU1
+#define HS_UARTX_BASE	(HS_UART1_BASE)
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_UNCOMP_HSU2
+#define HS_UARTX_BASE	(HS_UART2_BASE)
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_UNCOMP_HSU7
+#define HS_UARTX_BASE	(HS_UART7_BASE)
+#endif
+
+#define HSUART_FIFO	(HS_UARTX_BASE + 0x00)
+#define HSUART_LEVEL	(HS_UARTX_BASE + 0x04)
+
+static inline void putc(int ch)
+{
+	/* Wait for transmit FIFO to empty */
+	while ((readl(HSUART_LEVEL) & 0xFF00) != 0)
+		;
+	writel((u32) ch, HSUART_FIFO);
+}
+static inline void flush(void)
+{
+	/* Don't see a reset? */
+	/* Then just wait for transmition to complete */
+	while ((readl(HSUART_LEVEL) & 0xFF00) != 0)
+		;
+}
+
+#else
+/*
+ * Standard UART uncompress output support
+ */
+
+#define UART_FIFO_CTL_TX_RESET	(1 << 2)
+#define UART_STATUS_TX_MT	(1 << 6)
+
+#ifdef CONFIG_ARCH_LPC32XX_UNCOMP_U3
+#define UARTX_BASE	(UART3_BASE)
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_UNCOMP_U4
+#define UARTX_BASE	(UART4_BASE)
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_UNCOMP_U5
+#define UARTX_BASE	(UART5_BASE)
+#endif
+
+#ifdef CONFIG_ARCH_LPC32XX_UNCOMP_U6
+#define UARTX_BASE	(UART6_BASE)
+#endif
+
+#define UART_DATA	(UARTX_BASE + 0x00)
+#define UART_FIFO_CTL	(UARTX_BASE + 0x08)
+#define UART_STATUS	(UARTX_BASE + 0x14)
+
+static inline void putc(int ch)
+{
+	/* Wait for transmit FIFO to empty */
+	while ((readl(UART_STATUS) & UART_STATUS_TX_MT) == 0)
+		;
+
+	writel((u32) ch, UART_DATA);
+}
+
+static inline void flush(void)
+{
+	writel(readl(UART_FIFO_CTL) | UART_FIFO_CTL_TX_RESET, UART_FIFO_CTL);
+}
+#endif
+
+/* NULL functions; we don't presently need them */
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
+
+#endif
+
diff --git a/arch/arm/mach-lpc32xx/include/mach/vmalloc.h b/arch/arm/mach-lpc32xx/include/mach/vmalloc.h
new file mode 100644
index 0000000..5efcc96
--- /dev/null
+++ b/arch/arm/mach-lpc32xx/include/mach/vmalloc.h
@@ -0,0 +1,28 @@
+/*
+ * arch/arm/mach-lpc32xx/include/mach/vmalloc.h
+ *
+ * Author: Kevin Wells <kevin.wells@nxp.com>
+ *
+ * Copyright (C) 2010 NXP Semiconductors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_VMALLOC_H
+#define __ASM_ARCH_VMALLOC_H
+
+#define VMALLOC_END	(PAGE_OFFSET + 0x10000000)
+
+#endif
-- 
1.6.6

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

* [PATCH 13/13] ARM: LPC32XX: Phytec PHY3250 default kernel config (ramdisk)
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (11 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 12/13] ARM: LPC32XX: architecture header files wellsk40 at gmail.com
@ 2010-01-28  1:43 ` wellsk40 at gmail.com
  2010-01-28 11:16 ` LPC32XX architecture files (updated) Luotao Fu
  2010-01-28 19:06 ` Wolfram Sang
  14 siblings, 0 replies; 72+ messages in thread
From: wellsk40 at gmail.com @ 2010-01-28  1:43 UTC (permalink / raw)
  To: linux-arm-kernel

From: Kevin Wells <wellsk40@gmail.com>

Default kernel configuration for the Phytec PHY3250 platform with
ramdisk support.

Signed-off-by: Kevin Wells <wellsk40@gmail.com>
---
 arch/arm/configs/phy3250_defconfig | 1124 ++++++++++++++++++++++++++++++++++++
 1 files changed, 1124 insertions(+), 0 deletions(-)

diff --git a/arch/arm/configs/phy3250_defconfig b/arch/arm/configs/phy3250_defconfig
new file mode 100644
index 0000000..28bac0e
--- /dev/null
+++ b/arch/arm/configs/phy3250_defconfig
@@ -0,0 +1,1124 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.33-rc5
+# Mon Jan 25 17:45:35 2010
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_KERNEL_GZIP=y
+# CONFIG_KERNEL_BZIP2 is not set
+# CONFIG_KERNEL_LZMA is not set
+# CONFIG_KERNEL_LZO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+# CONFIG_RT_GROUP_SCHED is not set
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
+# CONFIG_RD_LZO is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+
+#
+# Kernel Performance Events And Counters
+#
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_SPIN_UNLOCK is not set
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_READ_UNLOCK is not set
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQ is not set
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+# CONFIG_INLINE_WRITE_UNLOCK is not set
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+CONFIG_MMU=y
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_GEMINI is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_STMP3XXX is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_NOMADIK is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_DOVE is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_MMP is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_W90X900 is not set
+CONFIG_ARCH_LPC32XX=y
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
+# CONFIG_ARCH_S5PC1XX is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_U300 is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_BCMRING is not set
+# CONFIG_ARCH_U8500 is not set
+
+#
+# LPC32XX chip options
+#
+CONFIG_ARCH_LPC32XX_IRAM_SIZE=262144
+# CONFIG_ARCH_LPC32XX_20 is not set
+# CONFIG_ARCH_LPC32XX_30 is not set
+# CONFIG_ARCH_LPC32XX_40 is not set
+CONFIG_ARCH_LPC32XX_50=y
+
+#
+# Serial port configuration
+#
+
+#
+# Individual UART enable selections
+#
+# CONFIG_ARCH_LPC32XX_HSUART1_ENABLE is not set
+# CONFIG_ARCH_LPC32XX_HSUART2_ENABLE is not set
+# CONFIG_ARCH_LPC32XX_UART3_ENABLE is not set
+# CONFIG_ARCH_LPC32XX_UART4_ENABLE is not set
+CONFIG_ARCH_LPC32XX_UART5_ENABLE=y
+# CONFIG_ARCH_LPC32XX_UART6_ENABLE is not set
+# CONFIG_ARCH_LPC32XX_HSUART7_ENABLE is not set
+# CONFIG_ARCH_LPC32XX_UNCOMP_HSU1 is not set
+# CONFIG_ARCH_LPC32XX_UNCOMP_HSU2 is not set
+# CONFIG_ARCH_LPC32XX_UNCOMP_U3 is not set
+# CONFIG_ARCH_LPC32XX_UNCOMP_U4 is not set
+CONFIG_ARCH_LPC32XX_UNCOMP_U5=y
+# CONFIG_ARCH_LPC32XX_UNCOMP_U6 is not set
+# CONFIG_ARCH_LPC32XX_UNCOMP_HSU7 is not set
+# CONFIG_ARCH_LPC32XX_DEBUGO_U3 is not set
+# CONFIG_ARCH_LPC32XX_DEBUGO_U4 is not set
+CONFIG_ARCH_LPC32XX_DEBUGO_U5=y
+# CONFIG_ARCH_LPC32XX_DEBUGO_U6 is not set
+
+#
+# LPC32XX platform choices
+#
+CONFIG_MACH_PHY3250=y
+# CONFIG_PHY3250_QVGA_PANEL_1307_0 is not set
+CONFIG_PHY3250_QVGA_PANEL_1307_1=y
+# CONFIG_PHY3250_CPU_MODULE_1304_0 is not set
+CONFIG_PHY3250_CPU_MODULE_1304_1=y
+# CONFIG_PHY3250_CARRIER_1305_01 is not set
+# CONFIG_PHY3250_CARRIER_1305_2 is not set
+CONFIG_PHY3250_CARRIER_1305_3=y
+CONFIG_MACH_LPC32XX_IRAM_RESERVED=y
+# CONFIG_MACH_LPC32XX_IRAM_FOR_CLCD is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_LEGACY=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+CONFIG_ARM_L1_CACHE_SHIFT=5
+CONFIG_COMMON_CLKDEV=y
+
+#
+# Bus support
+#
+CONFIG_ARM_AMBA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+# CONFIG_NO_HZ is not set
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_HIGHMEM is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=999999
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_UACCESS_WITH_MEMCPY is not set
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=tty0 console=ttyS0,115200n81 root=/dev/ram0 init=/sbin/init"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_MISC is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+# CONFIG_APM_EMULATION is not set
+# CONFIG_PM_RUNTIME is not set
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+# CONFIG_NET is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=y
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=16384
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_MG_DISK is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_TI_DAC7512 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+CONFIG_EEPROM_AT25=y
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_AMBA_PL010 is not set
+# CONFIG_SERIAL_AMBA_PL011 is not set
+# CONFIG_SERIAL_MAX3100 is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_GPIO is not set
+# CONFIG_I2C_OCORES is not set
+CONFIG_I2C_PNX=y
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
+CONFIG_SPI_PL022=y
+# CONFIG_SPI_XILINX is not set
+# CONFIG_SPI_DESIGNWARE is not set
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+# CONFIG_GPIO_PL061 is not set
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+# CONFIG_GPIO_ADP5588 is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# CONFIG_GPIO_MC33880 is not set
+
+#
+# AC97 GPIO expanders:
+#
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_PNX4008_WATCHDOG=y
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_MFD_MC13783 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_EZX_PCAP is not set
+# CONFIG_MFD_88PM8607 is not set
+# CONFIG_AB4500_CORE is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_MEDIA_SUPPORT is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_ARMCLCD=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+CONFIG_LEDS_GPIO_PLATFORM=y
+# CONFIG_LEDS_LP3944 is not set
+# CONFIG_LEDS_PCA955X is not set
+# CONFIG_LEDS_DAC124S085 is not set
+# CONFIG_LEDS_BD2802 is not set
+# CONFIG_LEDS_LT3593 is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+# CONFIG_LEDS_TRIGGER_TIMER is not set
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_GPIO is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+
+#
+# iptables trigger is under Netfilter config (LED target)
+#
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+# CONFIG_FILE_LOCKING is not set
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=y
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_CRAMFS=y
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_KMEMLEAK is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_DEBUG_CREDENTIALS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_DEBUG_FORCE_WEAK_PER_CPU is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+# CONFIG_PAGE_POISONING is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_ARM_UNWIND is not set
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+# CONFIG_OC_ETM is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+CONFIG_CRYPTO_ANSI_CPRNG=y
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
-- 
1.6.6

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

* LPC32XX architecture files (updated)
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (12 preceding siblings ...)
  2010-01-28  1:43 ` [PATCH 13/13] ARM: LPC32XX: Phytec PHY3250 default kernel config (ramdisk) wellsk40 at gmail.com
@ 2010-01-28 11:16 ` Luotao Fu
  2010-01-28 19:50   ` Kevin Wells
  2010-01-28 19:06 ` Wolfram Sang
  14 siblings, 1 reply; 72+ messages in thread
From: Luotao Fu @ 2010-01-28 11:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

wellsk40 at gmail.com wrote:
> The initial LCP32xx arch files are in these patches. Changes from
> yesterdays posting:
> 
> gpiolib.c updated from user review comments, thanks!
> 
> Files all send via git send-email now, thanks for pointing me in
> the right direction and sorry about the wraps. (if gmail wasn't
> available, I'd be stuck!)
> 
> These have been checked with checkpatch.
> 
> thanks,
> Kevin Wells
> NXP Semiconductors
> 
thx for the patches. I applied them together with the nxp patches by RMK on the
linus master tree. (since it otherwise won't compile, as you've mentioned
earlier). It compiles so far. For convenience I put this onto our public git server

git://git.pengutronix.de/git/lfu/linux-lfu lpc32xx_wells

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

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-01-28  1:43 ` [PATCH 08/13] ARM: LPC32XX: clock tree support wellsk40 at gmail.com
@ 2010-01-28 17:07   ` Rabin Vincent
  2010-01-28 19:51     ` Kevin Wells
  2010-02-03 16:32   ` Uwe Kleine-König
  1 sibling, 1 reply; 72+ messages in thread
From: Rabin Vincent @ 2010-01-28 17:07 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 27, 2010 at 05:43:26PM -0800, wellsk40 at gmail.com wrote:
> +static struct clk_lookup lookups[] __initdata = {

This shouldn't be __initdata, since it'll be needed when loading modules
which use clk_get().

Rabin

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-01-28  1:43 ` [PATCH 06/13] ARM: LPC32XX: Core architecture files wellsk40 at gmail.com
@ 2010-01-28 17:58   ` H Hartley Sweeten
  2010-01-28 19:54     ` Kevin Wells
  2010-02-03 10:54     ` Uwe Kleine-König
  2010-02-03 15:55   ` Uwe Kleine-König
  1 sibling, 2 replies; 72+ messages in thread
From: H Hartley Sweeten @ 2010-01-28 17:58 UTC (permalink / raw)
  To: linux-arm-kernel

On Wednesday, January 27, 2010 6:43 PM, wellsk40 wrote:
> From: Kevin Wells <wellsk40@gmail.com>
> 
> GPIO support functions for gpiolib, irq setup and handling, serial
> port support, and high resolution timer support used in the LPC32XX
> architecture.
> 
> Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> ---

[snip]

> +static struct gpio_regs gpio_grp_regs[] = {
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P0_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P0_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P0_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P0_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P0_DIR_CLR(GPIOBASE),
> +	},
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P1_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P1_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P1_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P1_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P1_DIR_CLR(GPIOBASE),
> +	},
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P2_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P2_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P2_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
> +	},
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P3_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P3_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P3_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
> +	},
> +};

All this casting is pretty ugly.

It appears these GPIO_P* macros are only used here.  Can the macros
be modified to create the (void __iomem *) directly?

BTW, you might need to add __force in order to keep sparse happy.

Also, a general comment on the global names in 
arch/arm/mach-lpc32xx/include/mach/platform.h.

You might consider adding something like LPC32XX_ to the front of
all the defines. Names like GPIO_BASE or UART3_BASE could very well
conflict with some other piece of code in the future.

Regards,
Hartley

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

* LPC32XX architecture files (updated)
  2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
                   ` (13 preceding siblings ...)
  2010-01-28 11:16 ` LPC32XX architecture files (updated) Luotao Fu
@ 2010-01-28 19:06 ` Wolfram Sang
  2010-01-28 19:58   ` Kevin Wells
  14 siblings, 1 reply; 72+ messages in thread
From: Wolfram Sang @ 2010-01-28 19:06 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

as I read it, the order of the patches could be improved. For example, patches
1-3 check for ARCH_LPC32XX which is only introduced in Patch 4 (which then
includes the Kconfig from the subdir which again is introduced in #5). This
makes bisecting troublesome.

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 197 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20100128/3ad14db1/attachment-0001.sig>

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

* LPC32XX architecture files (updated)
  2010-01-28 11:16 ` LPC32XX architecture files (updated) Luotao Fu
@ 2010-01-28 19:50   ` Kevin Wells
  0 siblings, 0 replies; 72+ messages in thread
From: Kevin Wells @ 2010-01-28 19:50 UTC (permalink / raw)
  To: linux-arm-kernel


> >
> thx for the patches. I applied them together with the nxp patches by RMK
> on the
> linus master tree. (since it otherwise won't compile, as you've mentioned
> earlier). It compiles so far. For convenience I put this onto our public
> git server
> 
> git://git.pengutronix.de/git/lfu/linux-lfu lpc32xx_wells

thanks for helping test compile and posting these Luotao!

Kevin

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-01-28 17:07   ` Rabin Vincent
@ 2010-01-28 19:51     ` Kevin Wells
  0 siblings, 0 replies; 72+ messages in thread
From: Kevin Wells @ 2010-01-28 19:51 UTC (permalink / raw)
  To: linux-arm-kernel


> > +static struct clk_lookup lookups[] __initdata = {
> 
> This shouldn't be __initdata, since it'll be needed when loading modules
> which use clk_get().
> 

Nice catch - I'll fix this.

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-01-28 17:58   ` H Hartley Sweeten
@ 2010-01-28 19:54     ` Kevin Wells
  2010-02-03 10:54     ` Uwe Kleine-König
  1 sibling, 0 replies; 72+ messages in thread
From: Kevin Wells @ 2010-01-28 19:54 UTC (permalink / raw)
  To: linux-arm-kernel

> > +	{
> > +		.inp_state	= (void __iomem *) GPIO_P3_INP_STATE(GPIOBASE),
> > +		.outp_set	= (void __iomem *) GPIO_P3_OUTP_SET(GPIOBASE),
> > +		.outp_clr	= (void __iomem *) GPIO_P3_OUTP_CLR(GPIOBASE),
> > +		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
> > +		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
> > +	},
> > +};
> 
> All this casting is pretty ugly.
> 
> It appears these GPIO_P* macros are only used here.  Can the macros
> be modified to create the (void __iomem *) directly?
> 
> BTW, you might need to add __force in order to keep sparse happy.
> 
> Also, a general comment on the global names in
> arch/arm/mach-lpc32xx/include/mach/platform.h.
> 
> You might consider adding something like LPC32XX_ to the front of
> all the defines. Names like GPIO_BASE or UART3_BASE could very well
> conflict with some other piece of code in the future.
> 

Thank you for helping review these. I'll look at the use of __force
and update the necessary arch files with your other review comments.

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

* LPC32XX architecture files (updated)
  2010-01-28 19:06 ` Wolfram Sang
@ 2010-01-28 19:58   ` Kevin Wells
  0 siblings, 0 replies; 72+ messages in thread
From: Kevin Wells @ 2010-01-28 19:58 UTC (permalink / raw)
  To: linux-arm-kernel

> Hi,
> 
> as I read it, the order of the patches could be improved. For example,
> patches
> 1-3 check for ARCH_LPC32XX which is only introduced in Patch 4 (which then
> includes the Kconfig from the subdir which again is introduced in #5).
> This makes bisecting troublesome.
> 

I see what you mean with git bisect. Once I get some of the other review
comments installed, I'll release a (hopeful) final round of patches with
a better organized patch order...

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

* [PATCH 04/13] ARM: LPC32XX arch support in Kconfig and Makefile
  2010-01-28  1:43 ` [PATCH 04/13] ARM: LPC32XX arch support in Kconfig and Makefile wellsk40 at gmail.com
@ 2010-02-03 10:31   ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 10:31 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Kevin,

On Wed, Jan 27, 2010 at 05:43:22PM -0800, wellsk40 at gmail.com wrote:
> From: Kevin Wells <wellsk40@gmail.com>
> 
> Added support and default config flags in Kconfig for the LCP32XX
> arch. Updated the Makefile to include the mach-lpc32xx dir when
> the ARCH_LCP32XX arch is selected.
> 
> Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> ---
>  arch/arm/Kconfig  |   16 ++++++++++++++++
>  arch/arm/Makefile |    1 +
This patch isn't self-contained.  This might hurt bisectability.
IMHO all intermediate states should be compilable.

>  2 files changed, 17 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 4c33ca8..cc2dbf9 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -550,6 +550,20 @@ config ARCH_W90X900
>  	  <http://www.nuvoton.com/hq/enu/ProductAndSales/ProductLines/
>  		ConsumerElectronicsIC/ARMMicrocontroller/ARMMicrocontroller>
>  
> +config ARCH_LPC32XX
> +	bool "NXP LPC32XX"
> +	select CPU_ARM926T
> +	select ARCH_REQUIRE_GPIOLIB
> +	select GENERIC_GPIO
no need to select GENERIC_GPIO if you have ARCH_REQUIRE_GPIOLIB

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles
  2010-01-28  1:43 ` [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles wellsk40 at gmail.com
@ 2010-02-03 10:51   ` Uwe Kleine-König
  2010-02-03 11:26     ` Russell King - ARM Linux
  2010-02-03 18:01     ` Kevin Wells
  0 siblings, 2 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 10:51 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Kevin,

On Wed, Jan 27, 2010 at 05:43:23PM -0800, wellsk40 at gmail.com wrote:
> From: Kevin Wells <wellsk40@gmail.com>
> 
> Added Kconfig for the LPC32XX arch, Kconfig.plat for platforms based
> on the LPC32XX, and the initial makefiles. Kconfig.plat currently
> supports the Phytec PHY3250 platform.
> 
> Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> ---
>  arch/arm/mach-lpc32xx/Kconfig       |  158 +++++++++++++++++++++++++++++++++++
>  arch/arm/mach-lpc32xx/Kconfig.plat  |   98 ++++++++++++++++++++++
>  arch/arm/mach-lpc32xx/Makefile      |    9 ++
>  arch/arm/mach-lpc32xx/Makefile.boot |    4 +
>  4 files changed, 269 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-lpc32xx/Kconfig b/arch/arm/mach-lpc32xx/Kconfig
> new file mode 100644
> index 0000000..a277885
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/Kconfig
> @@ -0,0 +1,158 @@
> +if ARCH_LPC32XX
> +
> +menu "LPC32XX chip options"
> +
> +config ARCH_LPC32XX_IRAM_SIZE
> +	int
> +	default 131072 if ARCH_LPC32XX_20
> +	default 262144 if ARCH_LPC32XX_30 || ARCH_LPC32XX_40 || ARCH_LPC32XX_50
> +
> +choice
> +    prompt "Select 32x0 device variation"
> +    default ARCH_LPC32XX_50
> +
> +	config ARCH_LPC32XX_20
> +		bool "LPC3220"
> +		help
> +		 128K IRAM, no ethernet or LCD
> +
> +	config ARCH_LPC32XX_30
> +		bool "LPC3230"
> +		help
> +		 256K IRAM and LCD, no ethernet
> +
> +	config ARCH_LPC32XX_40
> +		bool "LPC3240"
> +		help
> +		 256K IRAM and ethernet, no LCD
> +
> +	config ARCH_LPC32XX_50
> +		bool "LPC3250"
> +		help
> +		 256K IRAM and ethernet and LCD
> +
> +endchoice
It's sad this is a choice and only a single "device variation" is
selectable.  Maybe you can autodetect these?

> +menu "Serial port configuration"
> +
> +menu "Individual UART enable selections"
> +
> +config ARCH_LPC32XX_HSUART1_ENABLE
> +	bool "Enable high speed UART1"
> +	help
> +	 Also enable LPC32xx high speed serial support in drivers/serial
> +
> +config ARCH_LPC32XX_HSUART2_ENABLE
> +	bool "Enable high speed UART2"
> +	help
> +	 Also enable LPC32xx high speed serial support in drivers/serial
> +
> +config ARCH_LPC32XX_UART3_ENABLE
> +	bool "Enable standard UART3"
> +	help
> +	 Also enable 8250 serial support in drivers/serial
> +
> +config ARCH_LPC32XX_UART4_ENABLE
> +	bool "Enable standard UART4"
> +	help
> +	 Also enable 8250 serial support in drivers/serial
> +
> +config ARCH_LPC32XX_UART5_ENABLE
> +	bool "Enable standard UART5"
> +	default y
> +	help
> +	 Also enable 8250 serial support in drivers/serial
> +
> +config ARCH_LPC32XX_UART6_ENABLE
> +	bool "Enable standard UART6"
> +	help
> +	 Also enable 8250 serial support in drivers/serial
> +
> +config ARCH_LPC32XX_HSUART7_ENABLE
> +	bool "Enable high speed UART7"
> +	help
> +	 Also enable LPC32xx high speed serial support in drivers/serial
> +
> +endmenu
IMHO "enable" is a bit misleading here.  Depending on the selection here
the devices are defined or not.

> +config ARCH_LPC32XX_UART6_IRDAMODE
> +	bool "Use IRDA mode on UART6"
> +	depends on ARCH_LPC32XX_UART6_ENABLE
> +	help
> +		Enables the IrDA modulator for UART6
> +
> +choice
> +	prompt "Kernel uncompress status output UART selection"
> +	default ARCH_LPC32XX_UNCOMP_U5
> +
> +	config ARCH_LPC32XX_UNCOMP_HSU1
> +		bool "High speed UART 1"
> +		help
> +		 Kernel uncompress output is on high speed UART 1
> +
> +	config ARCH_LPC32XX_UNCOMP_HSU2
> +		bool "High speed UART 2"
> +		help
> +		 Kernel uncompress output is on high speed UART 2
> +
> +	config ARCH_LPC32XX_UNCOMP_U3
> +		bool "Standard UART 3"
> +		help
> +		 Kernel uncompress output is on standard UART 3
> +
> +	config ARCH_LPC32XX_UNCOMP_U4
> +		bool "Standard UART 4"
> +		help
> +		 Kernel uncompress output is on standard UART 4
> +
> +	config ARCH_LPC32XX_UNCOMP_U5
> +		bool "Standard UART 5"
> +		help
> +		 Kernel uncompress output is on standard UART 5
> +
> +	config ARCH_LPC32XX_UNCOMP_U6
> +		bool "Standard UART 6"
> +		help
> +		 Kernel uncompress output is on standard UART 6
> +
> +	config ARCH_LPC32XX_UNCOMP_HSU7
> +		bool "High speed UART 7"
> +		help
> +		 Kernel uncompress output is on high speed UART 7
> +
> +endchoice
Can you autodetect this?

> +choice
> +	prompt "debug output (printascii) UART selection"
> +	default ARCH_LPC32XX_DEBUGO_U5
> +
> +	config ARCH_LPC32XX_DEBUGO_U3
> +		bool "Standard UART 3"
> +		help
> +		 printascii messages are output on standard UART 3
> +
> +	config ARCH_LPC32XX_DEBUGO_U4
> +		bool "Standard UART 4"
> +		help
> +		 printascii messages are output on standard UART 4
> +
> +	config ARCH_LPC32XX_DEBUGO_U5
> +		bool "Standard UART 5"
> +		help
> +		 printascii messages are output on standard UART 5
> +
> +	config ARCH_LPC32XX_DEBUGO_U6
> +		bool "Standard UART 6"
> +		help
> +		 printascii messages are output on standard UART 6
> +
> +endchoice
IMHO this isn't something that needs configuration via Kconfig.  It's
enough to have this via #defines in debug-macro.S.

> +endmenu
> +
> +endmenu
> +
> +source "arch/arm/mach-lpc32xx/Kconfig.plat"
> +
> +endif
> +
> diff --git a/arch/arm/mach-lpc32xx/Kconfig.plat b/arch/arm/mach-lpc32xx/Kconfig.plat
> new file mode 100644
> index 0000000..a67d1ad
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/Kconfig.plat
> @@ -0,0 +1,98 @@
> +menu "LPC32XX platform choices"
> +
> +choice
> +    prompt "Choose your board"
> +    default MACH_PHY3250
> +    help
> +        This menu selects the LPC3250 board to support for this build
> +
> +    config MACH_PHY3250
> +        bool "Phytec 3250 development board"
> +	help
> +	    Support for the Phytec 3250 development board
> +
> +endchoice
Again, support more than one mach per kernel?

> +choice
> +	prompt "Phytec LCD module revisions"
> +	depends on MACH_PHY3250
> +	default PHY3250_QVGA_PANEL_1307_1
> +	help
> +	  Select one of the supported LCD panel revisions
> +
> +config PHY3250_QVGA_PANEL_1307_0
> +	bool "1307.0 QVGA panel (portrait mode RGB565)"
> +	help
> +	  Use LCD module version 1307.0
> +
> +config PHY3250_QVGA_PANEL_1307_1
> +	bool "1307.1 QVGA panel (portrait mode RGB565)"
> +	help
> +	  Use LCD module version 1307.1
> +
> +endchoice
autodetect?  kernel-parameter?

> +choice
> +	prompt "Phytec CPU module revisions"
> +	depends on MACH_PHY3250
> +	default PHY3250_CPU_MODULE_1304_1
> +	help
> +	  Select one of the supported CPU module revisions
> +
> +config PHY3250_CPU_MODULE_1304_0
> +	bool "1304.0 CPU module"
> +	help
> +	  Use CPU module version 1304.0
> +
> +config PHY3250_CPU_MODULE_1304_1
> +	bool "1304.1 CPU module"
> +	help
> +	  Use CPU module version 1304.1
> +
> +endchoice
ditto, autodetect?  kernel-parameter?

> +choice
> +	prompt "Phytec Carrier board revisions"
> +	depends on MACH_PHY3250
> +	default PHY3250_CARRIER_1305_3
> +	help
> +	  Select one of the supported carrier board revisions
> +
> +config PHY3250_CARRIER_1305_01
> +	bool "1305.0 or 1305.1 carrier board"
> +	help
> +	  Use carrier board version 1305.0 or 1305.1
> +
> +config PHY3250_CARRIER_1305_2
> +	bool "1305.2 carrier board"
> +	help
> +	  Use carrier board version 1305.2
> +
> +config PHY3250_CARRIER_1305_3
> +	bool "1305.3 carrier board"
> +	help
> +	  Use carrier board version 1305.3
> +
> +endchoice
ditto

> +choice
> +	prompt "Internal IRAM use"
> +	default MACH_LPC32XX_IRAM_RESERVED
> +	depends on MACH_PHY3250
> +
> +config MACH_LPC32XX_IRAM_RESERVED
> +	bool "IRAM is not used (reserved)"
> +	help
> +	  IRAM is not used for video or networking and can be used for
> +	  other purposes or drivers
> +
> +config MACH_LPC32XX_IRAM_FOR_CLCD
> +	bool "Use IRAM as a video frame buffer"
> +	help
> +	  IRAM will be used for the LCD frame buffer. If the required buffer
> +	  size is larger than the size of IRAM, then SDRAM will be used
> +	  instead.
> +
> +endchoice
A request API would be nice here!?

> +endmenu
> diff --git a/arch/arm/mach-lpc32xx/Makefile b/arch/arm/mach-lpc32xx/Makefile
> new file mode 100644
> index 0000000..9c76c70
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/Makefile
> @@ -0,0 +1,9 @@
> +#
> +# Makefile for the linux kernel.
> +#
> +
> +obj-y				:= timer.o irq.o common.o serial.o clock.o
> +obj-y				+= gpiolib.o pm.o pm_events.o suspend.o
wow, 4 tabs!

> +obj-$(CONFIG_MACH_PHY3250)	+= phy3250.o
> +
> diff --git a/arch/arm/mach-lpc32xx/Makefile.boot b/arch/arm/mach-lpc32xx/Makefile.boot
> new file mode 100644
> index 0000000..b796b41
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/Makefile.boot
> @@ -0,0 +1,4 @@
> +   zreladdr-y	:= 0x80008000
> +params_phys-y	:= 0x80000100
I hope your bootloader passes the atag list via r2.  If so there is no
need to define params_phys-y.

> +initrd_phys-y	:= 0x82000000
initrd_phys is only needed for bootp.  Do you need it?

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-01-28 17:58   ` H Hartley Sweeten
  2010-01-28 19:54     ` Kevin Wells
@ 2010-02-03 10:54     ` Uwe Kleine-König
  2010-02-03 18:05       ` Kevin Wells
  1 sibling, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 10:54 UTC (permalink / raw)
  To: linux-arm-kernel

Hello 
On Thu, Jan 28, 2010 at 12:58:40PM -0500, H Hartley Sweeten wrote:
> On Wednesday, January 27, 2010 6:43 PM, wellsk40 wrote:
> > From: Kevin Wells <wellsk40@gmail.com>
> > 
> > GPIO support functions for gpiolib, irq setup and handling, serial
> > port support, and high resolution timer support used in the LPC32XX
> > architecture.
> > 
> > Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> > ---
> 
> [snip]
> 
> > +static struct gpio_regs gpio_grp_regs[] = {
> > +	{
> > +		.inp_state	= (void __iomem *) GPIO_P0_INP_STATE(GPIOBASE),
> > +		.outp_set	= (void __iomem *) GPIO_P0_OUTP_SET(GPIOBASE),
> > +		.outp_clr	= (void __iomem *) GPIO_P0_OUTP_CLR(GPIOBASE),
> > +		.dir_set	= (void __iomem *) GPIO_P0_DIR_SET(GPIOBASE),
> > +		.dir_clr	= (void __iomem *) GPIO_P0_DIR_CLR(GPIOBASE),
> > +	},
> > +	{
> > +		.inp_state	= (void __iomem *) GPIO_P1_INP_STATE(GPIOBASE),
> > +		.outp_set	= (void __iomem *) GPIO_P1_OUTP_SET(GPIOBASE),
> > +		.outp_clr	= (void __iomem *) GPIO_P1_OUTP_CLR(GPIOBASE),
> > +		.dir_set	= (void __iomem *) GPIO_P1_DIR_SET(GPIOBASE),
> > +		.dir_clr	= (void __iomem *) GPIO_P1_DIR_CLR(GPIOBASE),
> > +	},
> > +	{
> > +		.inp_state	= (void __iomem *) GPIO_P2_INP_STATE(GPIOBASE),
> > +		.outp_set	= (void __iomem *) GPIO_P2_OUTP_SET(GPIOBASE),
> > +		.outp_clr	= (void __iomem *) GPIO_P2_OUTP_CLR(GPIOBASE),
> > +		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
> > +		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
> > +	},
> > +	{
> > +		.inp_state	= (void __iomem *) GPIO_P3_INP_STATE(GPIOBASE),
> > +		.outp_set	= (void __iomem *) GPIO_P3_OUTP_SET(GPIOBASE),
> > +		.outp_clr	= (void __iomem *) GPIO_P3_OUTP_CLR(GPIOBASE),
> > +		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
> > +		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
> > +	},
> > +};
> 
> All this casting is pretty ugly.
> 
> It appears these GPIO_P* macros are only used here.  Can the macros
> be modified to create the (void __iomem *) directly?
If GPIO_P* macros are only used here, maybe better define them in this
file?

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles
  2010-02-03 10:51   ` Uwe Kleine-König
@ 2010-02-03 11:26     ` Russell King - ARM Linux
  2010-02-03 13:57       ` Uwe Kleine-König
  2010-02-03 18:01     ` Kevin Wells
  1 sibling, 1 reply; 72+ messages in thread
From: Russell King - ARM Linux @ 2010-02-03 11:26 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 03, 2010 at 11:51:52AM +0100, Uwe Kleine-K?nig wrote:
> > diff --git a/arch/arm/mach-lpc32xx/Makefile.boot b/arch/arm/mach-lpc32xx/Makefile.boot
> > new file mode 100644
> > index 0000000..b796b41
> > --- /dev/null
> > +++ b/arch/arm/mach-lpc32xx/Makefile.boot
> > @@ -0,0 +1,4 @@
> > +   zreladdr-y	:= 0x80008000
> > +params_phys-y	:= 0x80000100
> I hope your bootloader passes the atag list via r2.  If so there is no
> need to define params_phys-y.

Wrong - that's your expectation that nothing uses this, rather than
reality.  While the decompressor doesn't use it, it's required for
the 'bootp' add-on, which allows an initrd/initramfs image and kernel
to be combined together, and the initrd/ramfs to be split away from
the kernel - without encountering the PC24 relocation error problem.

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

* [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles
  2010-02-03 11:26     ` Russell King - ARM Linux
@ 2010-02-03 13:57       ` Uwe Kleine-König
  2010-02-03 15:02         ` Russell King - ARM Linux
  0 siblings, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 13:57 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Russell,

On Wed, Feb 03, 2010 at 11:26:46AM +0000, Russell King - ARM Linux wrote:
> On Wed, Feb 03, 2010 at 11:51:52AM +0100, Uwe Kleine-K?nig wrote:
> > > diff --git a/arch/arm/mach-lpc32xx/Makefile.boot b/arch/arm/mach-lpc32xx/Makefile.boot
> > > new file mode 100644
> > > index 0000000..b796b41
> > > --- /dev/null
> > > +++ b/arch/arm/mach-lpc32xx/Makefile.boot
> > > @@ -0,0 +1,4 @@
> > > +   zreladdr-y	:= 0x80008000
> > > +params_phys-y	:= 0x80000100
> > I hope your bootloader passes the atag list via r2.  If so there is no
> > need to define params_phys-y.
> 
> Wrong - that's your expectation that nothing uses this, rather than
> reality.  While the decompressor doesn't use it, it's required for
> the 'bootp' add-on, which allows an initrd/initramfs image and kernel
> to be combined together, and the initrd/ramfs to be split away from
> the kernel - without encountering the PC24 relocation error problem.
Obviously you're right.  Is bootp still used?

If yes it should start looking for a taglist at the address specified by
r2, shouldn't it?

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles
  2010-02-03 13:57       ` Uwe Kleine-König
@ 2010-02-03 15:02         ` Russell King - ARM Linux
  0 siblings, 0 replies; 72+ messages in thread
From: Russell King - ARM Linux @ 2010-02-03 15:02 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 03, 2010 at 02:57:41PM +0100, Uwe Kleine-K?nig wrote:
> Hello Russell,
> 
> On Wed, Feb 03, 2010 at 11:26:46AM +0000, Russell King - ARM Linux wrote:
> > On Wed, Feb 03, 2010 at 11:51:52AM +0100, Uwe Kleine-K?nig wrote:
> > > > diff --git a/arch/arm/mach-lpc32xx/Makefile.boot b/arch/arm/mach-lpc32xx/Makefile.boot
> > > > new file mode 100644
> > > > index 0000000..b796b41
> > > > --- /dev/null
> > > > +++ b/arch/arm/mach-lpc32xx/Makefile.boot
> > > > @@ -0,0 +1,4 @@
> > > > +   zreladdr-y	:= 0x80008000
> > > > +params_phys-y	:= 0x80000100
> > > I hope your bootloader passes the atag list via r2.  If so there is no
> > > need to define params_phys-y.
> > 
> > Wrong - that's your expectation that nothing uses this, rather than
> > reality.  While the decompressor doesn't use it, it's required for
> > the 'bootp' add-on, which allows an initrd/initramfs image and kernel
> > to be combined together, and the initrd/ramfs to be split away from
> > the kernel - without encountering the PC24 relocation error problem.
> Obviously you're right.  Is bootp still used?

I've no idea - it's there for two reasons:

1. proof of concept for wrapping a zImage
2. to allow kernel+initrd to be loaded on systems which can only do
   bootp+tftp of a single file.

I know that my mini EBSA110 bootp loader (which is around 4K total) can
only accept an initrd this way, and I suspect there's some uclinux type
platforms which have similar restrictions.

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-01-28  1:43 ` [PATCH 06/13] ARM: LPC32XX: Core architecture files wellsk40 at gmail.com
  2010-01-28 17:58   ` H Hartley Sweeten
@ 2010-02-03 15:55   ` Uwe Kleine-König
  2010-02-03 18:43     ` Kevin Wells
                       ` (3 more replies)
  1 sibling, 4 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 15:55 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Kevin,

On Wed, Jan 27, 2010 at 05:43:24PM -0800, wellsk40 at gmail.com wrote:
> From: Kevin Wells <wellsk40@gmail.com>
> 
> GPIO support functions for gpiolib, irq setup and handling, serial
> port support, and high resolution timer support used in the LPC32XX
> architecture.
> 
> Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> ---
>  arch/arm/mach-lpc32xx/gpiolib.c |  418 +++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-lpc32xx/irq.c     |  237 ++++++++++++++++++++++
>  arch/arm/mach-lpc32xx/serial.c  |  200 +++++++++++++++++++
>  arch/arm/mach-lpc32xx/timer.c   |  187 +++++++++++++++++
>  4 files changed, 1042 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-lpc32xx/gpiolib.c b/arch/arm/mach-lpc32xx/gpiolib.c
> new file mode 100644
> index 0000000..30cf252
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/gpiolib.c
> @@ -0,0 +1,418 @@
> +/*
> + * arch/arm/mach-lpc32xx/gpiolib.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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
This is an old address of the FSF.  I'd recommend skipping the last
paragraph.  Ditto for the other files.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/errno.h>
> +#include <linux/gpio.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/platform.h>
> +
> +#define GPIOBASE io_p2v(GPIO_BASE)
> +
> +struct gpio_regs {
> +	void __iomem *inp_state;
> +	void __iomem *outp_set;
> +	void __iomem *outp_clr;
> +	void __iomem *dir_set;
> +	void __iomem *dir_clr;
> +};
> +
> +/*
> + * GPIO names
> + */
> +static char *gpio_p0_names[GPIO_P0_MAX] = {
> +	"p0.0", "p0.1", "p0.2", "p0.3",
> +	"p0.4", "p0.5", "p0.6", "p0.7"
> +};
> +
> +static char *gpio_p1_names[GPIO_P1_MAX] = {
> +	"p1.0", "p1.1", "p1.2", "p1.3",
> +	"p1.4", "p1.5", "p1.6", "p1.7",
> +	"p1.8", "p1.9", "p1.10", "p1.11",
> +	"p1.12", "p1.13", "p1.14", "p1.15",
> +	"p1.16", "p1.17", "p1.18", "p1.19",
> +	"p1.20", "p1.21", "p1.22", "p1.23",
> +};
> +
> +static char *gpio_p2_names[GPIO_P2_MAX] = {
> +	"p2.0", "p2.1", "p2.2", "p2.3",
> +	"p2.4", "p2.5", "p2.6", "p2.7",
> +	"p2.8", "p2.9", "p2.10", "p2.11",
> +	"p2.12"
> +};
> +
> +static char *gpio_p3_names[GPIO_P3_MAX] = {
> +	"gpi000", "gpio01", "gpio02", "gpio03",
> +	"gpio04", "gpio05"
> +};
> +
> +static char *gpi_p3_names[GPI_P3_MAX] = {
> +	"gpi00", "gpi01", "gpi02", "gpi03",
> +	"gpi04", "gpi05", "gpi06", "gpi07",
> +	"gpi08", "gpi09", "na",    "na",
Quoting include/asm-generic/gpio.h:
" [names] must be an array of strings to use as alternative names for
the GPIOs in this chip. Any entry in the array may be NULL if there is
no alias for the GPIO [...]".  So if I understand correctly use NULL
instead of "na".

IMHO there should be a few consts.  I will take a look into gpiolib
later to eventually add them there to not get a warning if the names
provided are const.

> +	"na",    "na",    "na",    "gpi15",
> +	"gpi16", "gpi17", "gpi18", "gpi19",
> +	"gpi20", "gpi21", "gpi22", "gpi23",
> +	"gpi24", "gpi25", "gpi26", "gpi27"
> +};
> +
> +static char *gpo_p3_names[GPO_P3_MAX] = {
> +	"gpo00", "gpo01", "gpo02", "gpo03",
> +	"gpo04", "gpo05", "gpo06", "gpo07",
> +	"gpo08", "gpo09", "gpo10", "gpo11",
> +	"gpo12", "gpo13", "gpo14", "gpo15",
> +	"gpo16", "gpo17", "gpo18", "gpo19",
> +	"gpo20", "gpo21", "gpo22", "gpo23"
> +};
> +
> +static struct gpio_regs gpio_grp_regs[] = {
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P0_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P0_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P0_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P0_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P0_DIR_CLR(GPIOBASE),
> +	},
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P1_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P1_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P1_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P1_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P1_DIR_CLR(GPIOBASE),
> +	},
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P2_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P2_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P2_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
> +	},
> +	{
> +		.inp_state	= (void __iomem *) GPIO_P3_INP_STATE(GPIOBASE),
> +		.outp_set	= (void __iomem *) GPIO_P3_OUTP_SET(GPIOBASE),
> +		.outp_clr	= (void __iomem *) GPIO_P3_OUTP_CLR(GPIOBASE),
> +		.dir_set	= (void __iomem *) GPIO_P2_DIR_SET(GPIOBASE),
> +		.dir_clr	= (void __iomem *) GPIO_P2_DIR_CLR(GPIOBASE),
> +	},
> +};
> +
> +struct lpc32xx_gpio_chip {
> +	struct gpio_chip	chip;
> +	struct gpio_regs	*gpio_grp;
> +};
> +
> +static inline struct lpc32xx_gpio_chip *to_lpc32xx_gpio(
> +	struct gpio_chip *gpc)
> +{
> +	return container_of(gpc, struct lpc32xx_gpio_chip, chip);
> +}
> +
> +static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
> +	unsigned pin, int input)
> +{
> +	if (input)
> +		writel(1 << pin, group->gpio_grp->dir_clr);
readl/writel are used to "perform PCI memory accesses via an ioremap
region" and "are defined to perform little endian accesses".  I think
most archs use __raw_readl/__raw_writel here.

> +	else
> +		writel(1 << pin, group->gpio_grp->dir_set);
> +}
> +
> +static void __set_gpio_dir_p3(struct lpc32xx_gpio_chip *group,
> +	unsigned pin, int input)
> +{
> +	u32 u;
> +
> +	/* P3 GPIO pins are offset in the register to pin mapping */
> +	u = (1 << (pin + 25));
Can you use a define for that?  e.g.

	#define pin_to_bit_p3(pin) (1 << (pin + 25))

and then for the p012 functions, too, for consistency.

> +
> +	if (input)
> +		writel(u, group->gpio_grp->dir_clr);
> +	else
> +		writel(u, group->gpio_grp->dir_set);
> +}
> +
> +static void __set_gpio_level_p012(struct lpc32xx_gpio_chip *group,
> +	unsigned pin, int high)
> +{
> +	if (high)
> +		writel(1 << pin, group->gpio_grp->outp_set);
> +	else
> +		writel(1 << pin, group->gpio_grp->outp_clr);
> +}
> +
> +static void __set_gpio_level_p3(struct lpc32xx_gpio_chip *group,
> +	unsigned pin, int high)
> +{
> +	u32 u;
> +
> +	/* P3 GPIO pins are offset in the register to pin mapping */
> +	u = (1 << (pin + 25));
> +
> +	if (high)
> +		writel(u, group->gpio_grp->outp_set);
> +	else
> +		writel(u, group->gpio_grp->outp_clr);
> +}
> +
> +static void __set_gpo_level_p3(struct lpc32xx_gpio_chip *group,
> +	unsigned pin, int high)
> +{
> +	if (high)
> +		writel(1 << pin, group->gpio_grp->outp_set);
> +	else
> +		writel(1 << pin, group->gpio_grp->outp_clr);
> +}
> +
> +static int __get_gpio_state_p012(struct lpc32xx_gpio_chip *group,
> +	unsigned pin)
> +{
> +	return (readl(group->gpio_grp->inp_state) >> pin) & 1;
> +}
> +
> +static int __get_gpio_state_p3(struct lpc32xx_gpio_chip *group,
> +	unsigned pin)
> +{
> +	int state;
> +
> +	state = readl(group->gpio_grp->inp_state);
> +
> +	/* P3 GPIO pin input mapping is not contiguous */
> +	if (pin == 5)
> +		state = (state >> 24) & 1;
> +	else
> +		state = (state >> (10 + pin)) & 1;
The mapping here is different from above in __set_gpio_dir_p3??  Please
someone kick the responsible hardware designer from me.

> +	return state;
> +}
> +
> +static int __get_gpi_state_p3(struct lpc32xx_gpio_chip *group,
> +	unsigned pin)
> +{
> +	return (readl(group->gpio_grp->inp_state) >> pin) & 1;
> +}
> +
> +/*
> + * GENERIC_GPIO primitives.
> + */
> +static int lpc32xx_gpio_dir_input_p012(struct gpio_chip *chip,
> +	unsigned pin)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	__set_gpio_dir_p012(group, pin, 1);
> +
> +	return 0;
> +}
> +
> +static int lpc32xx_gpio_dir_input_p3(struct gpio_chip *chip,
> +	unsigned pin)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	__set_gpio_dir_p3(group, pin, 1);
> +
> +	return 0;
> +}
> +
> +static int lpc32xx_gpio_dir_in_always(struct gpio_chip *chip,
> +	unsigned pin)
> +{
> +	return 0;
> +}
> +
> +static int lpc32xx_gpio_get_value_p012(struct gpio_chip *chip, unsigned pin)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	return __get_gpio_state_p012(group, pin);
> +}
> +
> +static int lpc32xx_gpio_get_value_p3(struct gpio_chip *chip, unsigned pin)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	return __get_gpio_state_p3(group, pin);
> +}
> +
> +static int lpc32xx_gpi_get_value(struct gpio_chip *chip, unsigned pin)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	return __get_gpi_state_p3(group, pin);
> +}
> +
> +static int lpc32xx_gpio_dir_output_p012(struct gpio_chip *chip, unsigned pin,
> +	int value)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	__set_gpio_dir_p012(group, pin, 0);
> +
> +	return 0;
> +}
> +
> +static int lpc32xx_gpio_dir_output_p3(struct gpio_chip *chip, unsigned pin,
> +	int value)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	__set_gpio_dir_p3(group, pin, 0);
> +
> +	return 0;
> +}
> +
> +static int lpc32xx_gpio_dir_out_always(struct gpio_chip *chip, unsigned pin,
> +	int value)
> +{
> +	return 0;
> +}
> +
> +static void lpc32xx_gpio_set_value_p012(struct gpio_chip *chip, unsigned pin,
> +	int value)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	__set_gpio_level_p012(group, pin, value);
> +}
> +
> +static void lpc32xx_gpio_set_value_p3(struct gpio_chip *chip, unsigned pin,
> +	int value)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	__set_gpio_level_p3(group, pin, value);
> +}
> +
> +static void lpc32xx_gpo_set_value(struct gpio_chip *chip, unsigned pin,
> +	int value)
> +{
> +	struct lpc32xx_gpio_chip *group = to_lpc32xx_gpio(chip);
> +
> +	__set_gpo_level_p3(group, pin, value);
> +}
> +
> +static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
> +{
> +	if (pin < chip->ngpio)
> +		return 0;
> +
> +	return -EINVAL;
> +}
> +
> +static struct lpc32xx_gpio_chip lpc32xx_gpiochip[] = {
> +	{
> +		.chip = {
> +			.label			= "gpio_p0",
> +			.direction_input	= lpc32xx_gpio_dir_input_p012,
> +			.get			= lpc32xx_gpio_get_value_p012,
> +			.direction_output	= lpc32xx_gpio_dir_output_p012,
> +			.set			= lpc32xx_gpio_set_value_p012,
> +			.request		= lpc32xx_gpio_request,
> +			.base			= GPIO_P0_GRP,
> +			.ngpio			= GPIO_P0_MAX,
> +			.names			= gpio_p0_names,
> +			.can_sleep		= 0,
> +		},
> +		.gpio_grp = &gpio_grp_regs[0],
These absolute array references tend to become wrong.  There is no need
to have them in an array, so why not call it gpio_grp_regs_p0 etc.?

> +	},
> +	{
> +		.chip = {
> +			.label			= "gpio_p1",
> +			.direction_input	= lpc32xx_gpio_dir_input_p012,
> +			.get			= lpc32xx_gpio_get_value_p012,
> +			.direction_output	= lpc32xx_gpio_dir_output_p012,
> +			.set			= lpc32xx_gpio_set_value_p012,
> +			.request		= lpc32xx_gpio_request,
> +			.base			= GPIO_P1_GRP,
> +			.ngpio			= GPIO_P1_MAX,
> +			.names			= gpio_p1_names,
> +			.can_sleep		= 0,
> +		},
> +		.gpio_grp = &gpio_grp_regs[1],
> +	},
> +	{
> +		.chip = {
> +			.label			= "gpio_p2",
> +			.direction_input	= lpc32xx_gpio_dir_input_p012,
> +			.get			= lpc32xx_gpio_get_value_p012,
> +			.direction_output	= lpc32xx_gpio_dir_output_p012,
> +			.set			= lpc32xx_gpio_set_value_p012,
> +			.request		= lpc32xx_gpio_request,
> +			.base			= GPIO_P2_GRP,
> +			.ngpio			= GPIO_P2_MAX,
> +			.names			= gpio_p2_names,
> +			.can_sleep		= 0,
> +		},
> +		.gpio_grp = &gpio_grp_regs[2],
> +	},
> +	{
> +		.chip = {
> +			.label			= "gpio_p3",
> +			.direction_input	= lpc32xx_gpio_dir_input_p3,
> +			.get			= lpc32xx_gpio_get_value_p3,
> +			.direction_output	= lpc32xx_gpio_dir_output_p3,
> +			.set			= lpc32xx_gpio_set_value_p3,
> +			.request		= lpc32xx_gpio_request,
> +			.base			= GPIO_P3_GRP,
> +			.ngpio			= GPIO_P3_MAX,
> +			.names			= gpio_p3_names,
> +			.can_sleep		= 0,
> +		},
> +		.gpio_grp = &gpio_grp_regs[3],
> +	},
> +	{
> +		.chip = {
> +			.label			= "gpi_p3",
> +			.direction_input	= lpc32xx_gpio_dir_in_always,
> +			.get			= lpc32xx_gpi_get_value,
> +			.request		= lpc32xx_gpio_request,
> +			.base			= GPI_P3_GRP,
> +			.ngpio			= GPI_P3_MAX,
> +			.names			= gpi_p3_names,
> +			.can_sleep		= 0,
> +		},
> +		.gpio_grp = &gpio_grp_regs[3],
> +	},
> +	{
> +		.chip = {
> +			.label			= "gpo_p3",
> +			.direction_output	= lpc32xx_gpio_dir_out_always,
> +			.set			= lpc32xx_gpo_set_value,
> +			.request		= lpc32xx_gpio_request,
> +			.base			= GPO_P3_GRP,
> +			.ngpio			= GPO_P3_MAX,
> +			.names			= gpo_p3_names,
> +			.can_sleep		= 0,
> +		},
> +		.gpio_grp = &gpio_grp_regs[3],
> +	},
> +};
> +
> +void __init lpc32xx_gpio_init(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(lpc32xx_gpiochip); i++)
> +		gpiochip_add(&lpc32xx_gpiochip[i].chip);
> +}
> diff --git a/arch/arm/mach-lpc32xx/irq.c b/arch/arm/mach-lpc32xx/irq.c
> new file mode 100644
> index 0000000..8a1b57d
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/irq.c
> @@ -0,0 +1,237 @@
> +/*
> + * arch/arm/mach-lpc32xx/irq.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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/kernel.h>
> +#include <linux/types.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +
> +#include <mach/irqs.h>
> +#include <mach/hardware.h>
> +#include <mach/platform.h>
> +
> +/*
> + * Default value represeting the Activation polarity of all internal
s/represeting/reprenseting/
> + * interrupt sources
> + */
> +#define MIC_APR_DEFAULT		0x3FF0EFE0
> +#define SIC1_APR_DEFAULT	0xFBD27186
> +#define SIC2_APR_DEFAULT	0x801810C0
> +
> +/*
> + * Default value represeting the Activation Type of all internal
> + * interrupt sources. All are level senesitive.
s/senesitive/sensitive/

> + */
> +#define MIC_ATR_DEFAULT		0x00000000
> +#define SIC1_ATR_DEFAULT	0x00026000
> +#define SIC2_ATR_DEFAULT	0x00000000
> +
> +static void get_controller(unsigned int irq, unsigned int *base,
> +	unsigned int *irqbit)
> +{
> +	if (irq < 32) {
> +		*base = io_p2v(MIC_BASE);
> +		*irqbit = 1 << irq;
> +	} else if (irq < 64) {
> +		*base = io_p2v(SIC1_BASE);
> +		*irqbit = 1 << (irq - 32);
> +	} else {
> +		*base = io_p2v(SIC2_BASE);
> +		*irqbit = 1 << (irq - 64);
> +	}
> +}
> +
> +static void lpc32xx_mask_irq(unsigned int irq)
> +{
> +	unsigned int reg, ctrl, mask;
> +
> +	get_controller(irq, &ctrl, &mask);
> +
> +	reg = readl(ctrl + INTC_MASK);
> +	reg &= ~mask;
> +	writel(reg, (ctrl + INTC_MASK));
as above s/readl/__raw_readl/; s/writel/__raw_writel/?
> +}
> +
> +static void lpc32xx_unmask_irq(unsigned int irq)
> +{
> +	unsigned int reg, ctrl, mask;
> +
> +	get_controller(irq, &ctrl, &mask);
> +
> +	reg = readl(ctrl + INTC_MASK);
> +	reg |= mask;
> +	writel(reg, (ctrl + INTC_MASK));
> +}
> +
> +static void lpc32xx_mask_ack_irq(unsigned int irq)
> +{
> +	unsigned int ctrl, mask;
> +
> +	get_controller(irq, &ctrl, &mask);
> +
> +	writel(mask, (ctrl + INTC_RAW_STAT));
> +}
> +
> +static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
> +{
> +	unsigned int reg, ctrl, mask;
> +
> +	get_controller(irq, &ctrl, &mask);
> +
> +	switch (type) {
> +	case IRQ_TYPE_EDGE_RISING:
> +		/* Rising edge sensitive */
> +		reg = readl(ctrl + INTC_POLAR);
> +		reg |= mask;
> +		writel(reg, (ctrl + INTC_POLAR));
> +		reg = readl(ctrl + INTC_ACT_TYPE);
> +		reg |= mask;
> +		writel(reg, (ctrl + INTC_ACT_TYPE));
> +		set_irq_handler(irq, handle_edge_irq);
> +		break;
> +
> +	case IRQ_TYPE_EDGE_FALLING:
> +		/* Falling edge sensitive */
> +		reg = readl(ctrl + INTC_POLAR);
> +		reg &= ~mask;
> +		writel(reg, (ctrl + INTC_POLAR));
> +		reg = readl(ctrl + INTC_ACT_TYPE);
> +		reg |= mask;
> +		writel(reg, (ctrl + INTC_ACT_TYPE));
> +		set_irq_handler(irq, handle_edge_irq);
> +		break;
did you test that you really need handle_edge_irq?  Sane irq controllers
can (and should) use handle_level_irq for both level and edge sensitive
irqs.  You only need handle_edge_irq if your controller doesn't remember
edge transitions while the irq is masked.

> +	case IRQ_TYPE_LEVEL_LOW:
> +		/* Low level sensitive */
> +		reg = readl(ctrl + INTC_POLAR);
> +		reg &= ~mask;
> +		writel(reg, (ctrl + INTC_POLAR));
> +		reg = readl(ctrl + INTC_ACT_TYPE);
> +		reg &= ~mask;
> +		writel(reg, (ctrl + INTC_ACT_TYPE));
> +		set_irq_handler(irq, handle_level_irq);
> +		break;
> +
> +	case IRQ_TYPE_LEVEL_HIGH:
> +		/* High level sensitive */
> +		reg = readl(ctrl + INTC_POLAR);
> +		reg |= mask;
> +		writel(reg, (ctrl + INTC_POLAR));
> +		reg = readl(ctrl + INTC_ACT_TYPE);
> +		reg &= ~mask;
> +		writel(reg, (ctrl + INTC_ACT_TYPE));
> +		set_irq_handler(irq, handle_level_irq);
> +		break;
You could increase code sharing here with something like:

	static inline __set_irq_type(unsigned int ctrl, unsigned mask, unsigned polar, unsigned acttype)
	{

		unsigned reg = __raw_readl(ctrl + INTC_POLAR);
		reg &= ~mask;
		reg |= polar;
		__raw_writel(reg, ctrl + INTC_POLAR);
		reg = __raw_readl(ctrl + INTC_ACT_TYPE);
		...
	}

and then the different cases would only be:

	...
	case IRQ_TYPE_LEVEL_HIGH:
		__set_irq_type(ctrl, mask, mask, 0);

> +
> +	/* Other modes are not supported */
> +	default:
> +		return -ENOTSUPP;
> +	}
I think you need to differenciate between unsupported an invalid types.
I.e.:

	case IRQ_TYPE_EDGE_BOTH:
		return -ENOTSUPP;

	default:
		return -EINVAL;

And I'm not sure if ENOTSUPP is the right value to return.  I grepped a
bit around and returning -EINVAL for both unsupported and wrong values
seems common.  (pnx4008_set_irq_type return -1 which looks worse than
-ENOTSUPP.)
> +
> +	return 0;
> +}
> +
> +static void __init lpc32xx_set_default_mappings(unsigned int base,
> +	unsigned int apr, unsigned int atr, unsigned int offset)
> +{
> +	unsigned int i, lvl, type;
> +
> +	/* Set activation levels for each interrupt */
> +	i = 0;
> +	while (i < 32) 	{
> +		lvl = ((apr >> i) & 0x1) | (((atr >> i) & 0x1) << 1);
> +		switch (lvl) {
> +		case 0x0: /* Low polarity and level operation */
> +			type = IRQ_TYPE_LEVEL_LOW;
> +			break;
> +
> +		case 0x1: /* High polarity and level operation */
> +			type = IRQ_TYPE_LEVEL_HIGH;
> +			break;
> +
> +		case 0x2: /* Low polarity and edge operation */
> +			type = IRQ_TYPE_EDGE_FALLING;
> +			break;
> +
> +		case 0x3: /* High polarity and edge operation */
> +		default:
> +			type = IRQ_TYPE_EDGE_RISING;
> +			break;
> +		}
> +
> +		lpc32xx_set_irq_type((offset + i), type);
you could reuse the function I suggested above, here.

> +		i++;
> +	}
> +}
> +
> +static struct irq_chip lpc32xx_irq_chip = {
> +	.ack = lpc32xx_mask_ack_irq,
.ack = ...mask_ack... ?

> +	.mask = lpc32xx_mask_irq,
> +	.unmask = lpc32xx_unmask_irq,
> +	.set_type = lpc32xx_set_irq_type,
> +};
> +
> +void __init lpc32xx_init_irq(void)
> +{
> +	unsigned int i, vloc;
> +
> +	/* Setup MIC */
> +	vloc = io_p2v(MIC_BASE);
> +	writel(0, (vloc + INTC_MASK));
> +	writel(MIC_APR_DEFAULT, (vloc + INTC_POLAR));
> +	writel(MIC_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
> +
> +	/* Setup SIC1 */
> +	vloc = io_p2v(SIC1_BASE);
> +	writel(0, (vloc + INTC_MASK));
> +	writel(SIC1_APR_DEFAULT, (vloc + INTC_POLAR));
> +	writel(SIC1_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
> +
> +	/* Setup SIC2 */
> +	vloc = io_p2v(SIC2_BASE);
> +	writel(0, (vloc + INTC_MASK));
> +	writel(SIC2_APR_DEFAULT, (vloc + INTC_POLAR));
> +	writel(SIC2_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
> +
> +	/* Configure supported IRQ's */
> +	for (i = 0; i < NR_IRQS; i++) {
> +		set_irq_flags(i, IRQF_VALID);
> +		set_irq_chip(i, &lpc32xx_irq_chip);
> +	}
> +
> +	/* Set default mappings */
> +	lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT,
> +		MIC_ATR_DEFAULT, 0);
> +	lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT,
> +		SIC1_ATR_DEFAULT, 32);
> +	lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT,
> +		SIC2_ATR_DEFAULT, 64);
> +
> +	/* mask all interrupts except SUBIRQA and SUBFIQ */
Why don't you mask all irqs?

> +	writel((1 << IRQ_SUB1IRQ) | (1 << IRQ_SUB2IRQ) |
> +			(1 << IRQ_SUB1FIQ) | (1 << IRQ_SUB2FIQ),
> +		(io_p2v(MIC_BASE) + INTC_MASK));
I wonder you want s/SUBIRQA/SUBIRQ/ ?

> +	writel(0, (io_p2v(SIC1_BASE) + INTC_MASK));
> +	writel(0, (io_p2v(SIC2_BASE) + INTC_MASK));
> +}
> diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-lpc32xx/serial.c
> new file mode 100644
> index 0000000..1c15121
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/serial.c
> @@ -0,0 +1,200 @@
> +/*
> + * arch/arm/mach-lpc32xx/serial.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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/kernel.h>
> +#include <linux/types.h>
> +#include <linux/serial.h>
> +#include <linux/serial_core.h>
> +#include <linux/serial_reg.h>
> +#include <linux/serial_8250.h>
> +#include <linux/clk.h>
> +#include <linux/io.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/platform.h>
> +#include <mach/io.h>
> +#include "common.h"
> +
> +/* Standard 8250/16550 compatible serial ports */
> +static struct plat_serial8250_port serial_std_platform_data[] = {
> +#ifdef CONFIG_ARCH_LPC32XX_UART5_ENABLE
> +	{
> +		.membase        = (void *) io_p2v(UART5_BASE),
> +		.mapbase        = UART5_BASE,
> +		.irq		= IRQ_UART_IIR5,
I'd prefix all lpc32xx specific constants with LPC32XX_.

> +		.uartclk	= MAIN_OSC_FREQ,
MAIN_OSC_FREQ isn't defined yet.

> +		.regshift	= 2,
> +		.iotype		= UPIO_MEM32,
> +		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> +					UPF_SKIP_TEST,
> +	},
> +#endif
> +#ifdef CONFIG_ARCH_LPC32XX_UART3_ENABLE
> +	{
> +		.membase	= (void *) io_p2v(UART3_BASE),
> +		.mapbase        = UART3_BASE,
> +		.irq		= IRQ_UART_IIR3,
> +		.uartclk	= MAIN_OSC_FREQ,
> +		.regshift	= 2,
> +		.iotype		= UPIO_MEM32,
> +		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> +					UPF_SKIP_TEST,
> +	},
> +#endif
> +#ifdef CONFIG_ARCH_LPC32XX_UART4_ENABLE
> +	{
> +		.membase	= (void *) io_p2v(UART4_BASE),
> +		.mapbase        = UART4_BASE,
> +		.irq		= IRQ_UART_IIR4,
> +		.uartclk	= MAIN_OSC_FREQ,
> +		.regshift	= 2,
> +		.iotype		= UPIO_MEM32,
> +		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> +					UPF_SKIP_TEST,
> +	},
> +#endif
> +#ifdef CONFIG_ARCH_LPC32XX_UART6_ENABLE
> +	{
> +		.membase	= (void *) io_p2v(UART6_BASE),
> +		.mapbase        = UART6_BASE,
> +		.irq		= IRQ_UART_IIR6,
> +		.uartclk	= MAIN_OSC_FREQ,
> +		.regshift	= 2,
> +		.iotype		= UPIO_MEM32,
> +		.flags		= UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> +					UPF_SKIP_TEST,
> +	},
> +#endif
> +	{ },
> +};
> +
> +struct uartinit {
> +	char *uart_ck_name;
> +	u32 ck_mode_mask;
> +	u32 pdiv_clk_reg;
> +};
> +
> +static struct uartinit uartinit_data[] __initdata = {
> +#ifdef CONFIG_ARCH_LPC32XX_UART5_ENABLE
> +	{
> +		.uart_ck_name = "uart5_ck",
> +		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 5),
> +		.pdiv_clk_reg = CLKPWR_UART5_CLK_CTRL(CLKPWR_IOBASE),
> +	},
> +#endif
> +#ifdef CONFIG_ARCH_LPC32XX_UART3_ENABLE
> +	{
> +		.uart_ck_name = "uart3_ck",
> +		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 3),
> +		.pdiv_clk_reg = CLKPWR_UART3_CLK_CTRL(CLKPWR_IOBASE),
> +	},
> +#endif
> +#ifdef CONFIG_ARCH_LPC32XX_UART4_ENABLE
> +	{
> +		.uart_ck_name = "uart4_ck",
> +		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 4),
> +		.pdiv_clk_reg = CLKPWR_UART4_CLK_CTRL(CLKPWR_IOBASE),
> +	},
> +#endif
> +#ifdef CONFIG_ARCH_LPC32XX_UART6_ENABLE
> +	{
> +		.uart_ck_name = "uart6_ck",
> +		.ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 6),
> +		.pdiv_clk_reg = CLKPWR_UART6_CLK_CTRL(CLKPWR_IOBASE),
> +	},
> +#endif
does the order matter here?  If not, why use 5,3,4,6?

> +};
> +
> +static struct platform_device serial_std_platform_device = {
> +	.name			= "serial8250",
> +	.id			= 0,
> +	.dev			= {
> +		.platform_data	= serial_std_platform_data,
> +	},
> +};
> +
> +static struct platform_device *lpc32xx_serial_devs[] __initdata = {
> +	&serial_std_platform_device,
> +};
> +
> +void __init lpc32xx_serial_init(void)
> +{
> +	u32 tmp, clkmodes = 0;
> +	struct clk *clk;
> +	void *puart;
> +	int i;
> +
> +	/* UART clocks are off, let clock driver manage them */
> +	__raw_writel(0, CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE));
> +
> +	for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
> +		clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
> +		if (IS_ERR(clk)) {
> +#ifdef CONFIG_DEBUG_LL
> +			/* A clock get failure can mean the console might
> +			   not work. It's possible this might not even
> +			   work. */
> +			printascii("Serial port clock get failure!\n");
> +#endif
> +		} else {
> +			clk_enable(clk);
> +			serial_std_platform_data[i].uartclk =
> +				clk_get_rate(clk);
IIRC clk_get_rate is only valid for enabled clocks, so you might want to
check if clk_enable returned 0.

> +		}
> +
> +		/* Setup UART clock modes for all UARTs, disable autoclock */
> +		clkmodes |= uartinit_data[i].ck_mode_mask;
Do you really want to do this if clk_enable or clk_get failed?
> +
> +		/* pre-UART clock divider set to 1 */
> +		writel(0x0101, uartinit_data[i].pdiv_clk_reg);
ditto.

> +	}
> +
> +	/* This needs to be done after all UART clocks are setup */
> +	writel(clkmodes, UARTCTL_CLKMODE(io_p2v(UART_CTRL_BASE)));
> +	for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) {
> +		/* Force a flush of the RX FIFOs to work around a HW bug */
> +		puart = serial_std_platform_data[i].membase;
> +		writel(0xC1, UART_IIR_FCR(puart));
> +		writel(0x00, UART_DLL_FIFO(puart));
> +		clkmodes = 64;
> +		while (clkmodes--)
> +			tmp = readl(UART_DLL_FIFO(puart));
The variable clkmodes seems to be misused here.  IMHO it should be named
something like j.  and can i have a 

	#define LPC32XX_UART_FIFO_SIZE	64

inclusive usage here?

> +		writel(0, UART_IIR_FCR(puart));
> +	}
> +
> +	/* IrDA pulsing support on UART6. This only enables the IrDA mux */
> +	tmp = readl(UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> +#ifdef CONFIG_ARCH_LPC32XX_UART6_IRDAMODE
> +	tmp &= ~UART_UART6_IRDAMOD_BYPASS;
> +#else
> +	tmp |= UART_UART6_IRDAMOD_BYPASS;
> +#endif
> +	writel(tmp, UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> +
> +	/* Disable UART5->USB transparent mode or USB won't work */
> +	tmp = readl(UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> +	tmp &= ~UART_U5_ROUTE_TO_USB;
> +	writel(tmp, UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> +
> +	platform_add_devices(lpc32xx_serial_devs,
> +		ARRAY_SIZE(lpc32xx_serial_devs));
> +}
> diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-lpc32xx/timer.c
> new file mode 100644
> index 0000000..9c06346
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/timer.c
> @@ -0,0 +1,187 @@
> +/*
> + * arch/arm/mach-lpc32xx/timer.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2009 - 2010 NXP Semiconductors
> + * Copyright (C) 2009 Fontys University of Applied Sciences, Eindhoven
> + *                    Ed Schouten <e.schouten@fontys.nl>
> + *                    Laurens Timmermans <l.timmermans@fontys.nl>
> + *
> + * 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/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/time.h>
> +#include <linux/err.h>
> +#include <linux/clockchips.h>
> +
> +#include <asm/mach/time.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/platform.h>
> +#include "common.h"
> +
> +#define TIMER0_IOBASE io_p2v(TIMER0_BASE)
> +#define TIMER1_IOBASE io_p2v(TIMER1_BASE)
I like the register constants already providing a virtual address.
Something like:

	#ifndef __REG
	#ifndef __ASSEMBLY__
	#define __REG(x) ((void __iomem __force *)io_p2v(x))
	#else
	#define __REG(x) io_p2v(x)
	#endif

	#define LPC32XX_TIMER0_IOBASE __REG(0x4004c000)

And for the few places where a physical address is needed you can define
__REG(x) to be just x.


> +static cycle_t lpc32xx_clksrc_read(struct clocksource *cs)
> +{
> +	return (cycle_t)readl(TIMER_TC(TIMER1_IOBASE));
> +}
> +
> +static struct clocksource lpc32xx_clksrc = {
> +	.name	= "lpc32xx_clksrc",
> +	.shift	= 24,
> +	.rating	= 300,
> +	.read	= lpc32xx_clksrc_read,
> +	.mask	= CLOCKSOURCE_MASK(32),
> +	.flags	= CLOCK_SOURCE_IS_CONTINUOUS,
> +};
> +
> +static int lpc32xx_clkevt_next_event(unsigned long delta,
> +    struct clock_event_device *dev)
> +{
> +	unsigned long flags;
> +
> +	if (delta < 1)
> +		return -ETIME;
As you set min_delta_ns below you don't need to test it here.

> +	local_irq_save(flags);
No.  irqs are already disabled by the clock framework.

> +	writel(TIMER_CNTR_TCR_RESET, TIMER_TCR(TIMER0_IOBASE));
> +	writel(delta, TIMER_PR(TIMER0_IOBASE));
> +	writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER0_IOBASE));
> +
> +	local_irq_restore(flags);
> +
> +	return 0;
> +}
> +
> +static void lpc32xx_clkevt_mode(enum clock_event_mode mode,
> +    struct clock_event_device *dev)
> +{
> +	switch (mode) {
> +	case CLOCK_EVT_MODE_PERIODIC:
> +		WARN_ON(1);
> +		break;
> +
> +	case CLOCK_EVT_MODE_ONESHOT:
> +	case CLOCK_EVT_MODE_SHUTDOWN:
> +		/*
> +		 * Disable the timer. When using oneshot, we must also
> +		 * disable the timer to wait for the first call to
> +		 * set_next_event().
> +		 */
> +		writel(0, TIMER_TCR(TIMER0_IOBASE));
> +		break;
> +
> +	case CLOCK_EVT_MODE_UNUSED:
> +	case CLOCK_EVT_MODE_RESUME:
> +		break;
> +	}
> +}
> +
> +static struct clock_event_device lpc32xx_clkevt = {
> +	.name		= "lpc32xx_clkevt",
> +	.features	= CLOCK_EVT_FEAT_ONESHOT,
> +	.shift		= 32,
> +	.rating		= 300,
> +	.set_next_event	= lpc32xx_clkevt_next_event,
> +	.set_mode	= lpc32xx_clkevt_mode,
> +};
> +
> +static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id)
> +{
> +	struct clock_event_device *evt = &lpc32xx_clkevt;
> +
> +	/* Clear match */
> +	writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE));
> +
> +	evt->event_handler(evt);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static struct irqaction lpc32xx_timer_irq = {
> +	.name		= "LPC32XX Timer Tick",
> +	.flags		= IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
> +	.handler	= lpc32xx_timer_interrupt,
> +};
> +
> +/*
> + * The clock management driver isn't initialized at this point, so the
> + * clocks need to be enabled here manually and then tagged as used in
> + * the clock driver initialization
> + */
> +static void __init lpc32xx_timer_init(void)
> +{
> +	u32 clkrate, pllreg;
> +
> +	/* Enable timer clock */
> +	writel(
> +		(CLKPWR_TMRPWMCLK_TIMER0_EN | CLKPWR_TMRPWMCLK_TIMER1_EN),
> +		CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE));
> +
> +	/* The clock driver isn't initialized at this point. So determine if
> +	   the SYSCLK is driven from the PLL397 or main oscillator and then use
> +	   it to compute the PLL frequency and the PCLK divider to get the base
> +	   timer rates. This rate is needed to compute the tick rate. */
the common format for multiline comments is

	/*
	 * ...
	 * ...
	 */

> +	if (clk_is_sysclk_mainosc() != 0)
> +		clkrate = MAIN_OSC_FREQ;
> +	else
> +		clkrate = 397 * CLOCK_OSC_FREQ;
> +
> +	/* Get ARM HCLKPLL register and convert it into a frequency*/
missing space -----------------------------------------------------^

> +	pllreg = readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & 0x1FFFF;
> +	clkrate = clk_get_pllrate_from_reg(clkrate, pllreg);
> +
> +	/* Get PCLK divider and divide ARM PLL clock by it to get timer rate */
> +	clkrate = clkrate / clk_get_pclk_div();
> +
> +	/* Initial timer setup */
> +	writel(0, TIMER_TCR(TIMER0_IOBASE));
> +	writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE));
> +	writel(1, TIMER_MR0(TIMER0_IOBASE));
> +	writel(TIMER_CNTR_MCR_MTCH(0) | TIMER_CNTR_MCR_STOP(0) |
> +	    TIMER_CNTR_MCR_RESET(0), TIMER_MCR(TIMER0_IOBASE));
> +
> +	/* Setup tick interrupt */
> +	setup_irq(IRQ_TIMER0, &lpc32xx_timer_irq);
> +
> +	/* Setup the clockevent structure. */
> +	lpc32xx_clkevt.mult = div_sc(clkrate, NSEC_PER_SEC,
> +		lpc32xx_clkevt.shift);
> +	lpc32xx_clkevt.max_delta_ns = clockevent_delta2ns(-1,
> +		&lpc32xx_clkevt);
> +	lpc32xx_clkevt.min_delta_ns = clockevent_delta2ns(1, &lpc32xx_clkevt);
For rounding reasons this might not be enough to assert delta being >= 1
for set_next event.  IIRC you need

	clockevent_delta2ns(1, &lpc32xx_clkevt) + 1

> +	lpc32xx_clkevt.cpumask = cpumask_of(0);
> +	clockevents_register_device(&lpc32xx_clkevt);
> +
> +	/* Use timer1 as clock source. */
> +	writel(TIMER_CNTR_TCR_RESET, TIMER_TCR(TIMER1_IOBASE));
> +	writel(0, TIMER_PR(TIMER1_IOBASE));
> +	writel(0, TIMER_MCR(TIMER1_IOBASE));
> +	writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER1_IOBASE));
> +	lpc32xx_clksrc.mult = clocksource_hz2mult(clkrate,
> +		lpc32xx_clksrc.shift);
> +	clocksource_register(&lpc32xx_clksrc);
> +}
> +
> +struct sys_timer lpc32xx_timer = {
> +	.init		= &lpc32xx_timer_init,
> +};
Does this work without NO_HZ?  I though you need to setup a periodic
mode with CONFIG_HZ irqs per second first?

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 07/13] ARM: LPC32XX: common architecture functions and structures
  2010-01-28  1:43 ` [PATCH 07/13] ARM: LPC32XX: common architecture functions and structures wellsk40 at gmail.com
@ 2010-02-03 16:01   ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 16:01 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Jan 27, 2010 at 05:43:25PM -0800, wellsk40 at gmail.com wrote:
> From: Kevin Wells <wellsk40@gmail.com>
> 
> LPC32XX arch specific functions and drivers that may be used
> in platforms based on the LCP32XX.
> 
> Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> ---
>  arch/arm/mach-lpc32xx/common.c |  269 ++++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-lpc32xx/common.h |   76 +++++++++++
>  2 files changed, 345 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-lpc32xx/common.c b/arch/arm/mach-lpc32xx/common.c
> new file mode 100644
> index 0000000..77c98b4
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/common.c
> @@ -0,0 +1,269 @@
> +/*
> + * arch/arm/mach-lpc32xx/common.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/err.h>
> +#include <linux/i2c.h>
> +#include <linux/i2c-pnx.h>
> +#include <linux/io.h>
> +
> +#include <asm/mach/map.h>
> +
> +#include <mach/i2c.h>
> +#include <mach/hardware.h>
> +#include <mach/platform.h>
> +#include "common.h"
> +
> +#define WDT_IOBASE io_p2v(WDTIM_BASE)
> +
> +/*
> + * Watchdog timer
> + */
> +static struct resource watchdog_resources[] = {
> +	[0] = {
> +		.start = WDTIM_BASE,
> +		.end = WDTIM_BASE + SZ_4K - 1,
> +		.flags = IORESOURCE_MEM,
> +	},
> +};
> +
> +struct platform_device watchdog_device = {
> +	.name = "pnx4008-watchdog",
> +	.id = -1,
> +	.num_resources = ARRAY_SIZE(watchdog_resources),
> +	.resource = watchdog_resources,
> +};
> +
> +/*
> + * I2C busses
> + */
> +static struct i2c_pnx_data i2c0_data = {
> +	.name = I2C_CHIP_NAME "0",
> +	.base = I2C1_BASE,
> +	.irq = IRQ_I2C_1,
Shouldn't that be I2C_CHIP_NAME "1" ?
> +};
> +
> +static struct i2c_pnx_data i2c1_data = {
> +	.name = I2C_CHIP_NAME "1",
> +	.base = I2C2_BASE,
> +	.irq = IRQ_I2C_2,
> +};
> +
> +static struct i2c_pnx_data i2c2_data = {
> +	.name = "USB-I2C",
> +	.base = OTG_I2C_BASE,
> +	.irq = IRQ_USB_I2C,
> +};
> +
> +struct platform_device i2c0_device = {
> +	.name = "pnx-i2c",
> +	.id = 0,
> +	.dev = {
> +		.platform_data = &i2c0_data,
> +	},
> +};
> +
> +struct platform_device i2c1_device = {
> +	.name = "pnx-i2c",
> +	.id = 1,
> +	.dev = {
> +		.platform_data = &i2c1_data,
> +	},
> +};
> +
> +struct platform_device i2c2_device = {
> +	.name = "pnx-i2c",
> +	.id = 2,
> +	.dev = {
> +		.platform_data = &i2c2_data,
> +	},
> +};
> +
> +/*
> + * Returns the unique ID for the device
> + */
> +void lpc32xx_get_uid(u32 devid[4])
> +{
> +	int i;
> +
> +	for (i = 0; i < 4; i++)
> +		devid[i] = readl(CLKPWR_DEVID(CLKPWR_IOBASE, i << 2));
> +}
> +
> +/*
> + * Returns SYSCLK source
> + * 0 = PLL397, 1 = main oscillator
> + */
> +int clk_is_sysclk_mainosc(void)
> +{
> +	if ((readl(CLKPWR_SYSCLK_CTRL(CLKPWR_IOBASE)) &
> +		CLKPWR_SYSCTRL_SYSCLKMUX) == 0)
> +		return 1;
> +
> +	return 0;
> +}
> +
> +/*
> + * System reset via the watchdog timer
> + */
> +void lpc32xx_watchdog_reset(void)
> +{
> +	/* Make sure WDT clocks are enabled */
> +	writel(CLKPWR_PWMCLK_WDOG_EN,
> +		CLKPWR_TIMER_CLK_CTRL(CLKPWR_IOBASE));
> +
> +	/* Instand assert of RESETOUT_N with pulse length 1mS */
s/Instand/Instant/
> +	writel(13000, WDT_IOBASE + 0x18);
> +	writel(0x70, WDT_IOBASE + 0xC);
> +}
> +
> +/*
> + * Computes PLL rate from PLL register and input clock
> + */
> +u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup)
> +{
> +	u32 ilfreq, p, m, n, fcco, fref, cfreq;
> +	int mode;
> +
> +	/* PLL requirements */
> +	/* ifreq must be >= 1MHz and <= 20MHz */
> +	/* FCCO must be >= 156MHz and <= 320MHz */
> +	/* FREF must be >= 1MHz and <= 27MHz. */
> +	/* Assume the passed input data is not valid */
> +
> +	ilfreq = ifreq;
> +	m = pllsetup->pll_m;
> +	n = pllsetup->pll_n;
> +	p = pllsetup->pll_p;
> +
> +	mode = (pllsetup->cco_bypass_b15 << 2) |
> +		(pllsetup->direct_output_b14 << 1) |
> +	pllsetup->fdbk_div_ctrl_b13;
> +
> +	switch (mode) {
> +	case 0x0: /* Non-integer mode */
> +		cfreq = (m * ilfreq) / (2 * p * n);
> +		fcco = (m * ilfreq) / n;
> +		fref = ilfreq / n;
> +		break;
> +
> +	case 0x1: /* integer mode */
> +		cfreq = (m * ilfreq) / n;
> +		fcco = (m * ilfreq) / (n * 2 * p);
> +		fref = ilfreq / n;
> +		break;
> +
> +	case 0x2:
> +	case 0x3: /* Direct mode */
> +		cfreq = (m * ilfreq) / n;
> +		fcco = cfreq;
> +		fref = ilfreq / n;
> +		break;
> +
> +	case 0x4:
> +	case 0x5: /* Bypass mode */
> +		cfreq = ilfreq / (2 * p);
> +		fcco = 156000000;
> +		fref = 1000000;
> +		break;
> +
> +	case 0x6:
> +	case 0x7: /* Direct bypass mode */
> +	default:
> +		cfreq = ilfreq;
> +		fcco = 156000000;
> +		fref = 1000000;
> +		break;
> +	}
> +
> +	if (fcco < 156000000 || fcco > 320000000)
> +		cfreq = 0;
> +
> +	if (fref < 1000000 || fref > 27000000)
> +		cfreq = 0;
> +
> +	return (u32) cfreq;
> +}
> +
> +/*
> + * Convert a PLL register value to a PLL output frequency
> + */
> +u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval)
> +{
> +	struct clk_pll_setup pllcfg;
> +
> +	pllcfg.cco_bypass_b15 = 0;
> +	pllcfg.direct_output_b14 = 0;
> +	pllcfg.fdbk_div_ctrl_b13 = 0;
> +	if ((regval & CLKPWR_HCLKPLL_CCO_BYPASS) != 0)
> +		pllcfg.cco_bypass_b15 = 1;
> +	if ((regval & CLKPWR_HCLKPLL_POSTDIV_BYPASS) != 0)
> +		pllcfg.direct_output_b14 = 1;
> +	if ((regval & CLKPWR_HCLKPLL_FDBK_SEL_FCLK) != 0)
> +		pllcfg.fdbk_div_ctrl_b13 = 1;
> +	pllcfg.pll_m = 1 + ((regval >> 1) & 0xFF);
> +	pllcfg.pll_n = 1 + ((regval >> 9) & 0x3);
> +	pllcfg.pll_p = pll_postdivs[((regval >> 11) & 0x3)];
> +
> +	return clk_check_pll_setup(inputclk, &pllcfg);
> +}
> +
> +u32 clk_get_pclk_div(void)
> +{
> +	return 1 + ((readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)) >> 2) &
> +		0x1F);
> +}
> +
> +static struct map_desc lpc32xx_io_desc[] __initdata = {
> +	{
> +		.virtual	= io_p2v(AHB0_START),
> +		.pfn		= __phys_to_pfn(AHB0_START),
> +		.length		= AHB0_SIZE,
> +		.type		= MT_DEVICE
> +	},
> +	{
> +		.virtual	= io_p2v(AHB1_START),
> +		.pfn		= __phys_to_pfn(AHB1_START),
> +		.length		= AHB1_SIZE,
> +		.type		= MT_DEVICE
> +	},
> +	{
> +		.virtual	= io_p2v(FABAPB_START),
> +		.pfn		= __phys_to_pfn(FABAPB_START),
> +		.length		= FABAPB_SIZE,
> +		.type		= MT_DEVICE
> +	},
> +	{
> +		.virtual	= io_p2v(IRAM_BASE),
> +		.pfn		= __phys_to_pfn(IRAM_BASE),
> +		.length		= CONFIG_ARCH_LPC32XX_IRAM_SIZE,
> +		.type		= MT_DEVICE
> +	},
> +};
> +
> +void __init lpc32xx_map_io(void)
> +{
> +	iotable_init(lpc32xx_io_desc, ARRAY_SIZE(lpc32xx_io_desc));
> +}
> diff --git a/arch/arm/mach-lpc32xx/common.h b/arch/arm/mach-lpc32xx/common.h
> new file mode 100644
> index 0000000..ab8d2b2
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/common.h
> @@ -0,0 +1,76 @@
> +/*
> + * arch/arm/mach-lpc32xx/common.h
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2009-2010 NXP Semiconductors
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef __LPC32XX_COMMON_H
> +#define __LPC32XX_COMMON_H
> +
> +#include <linux/platform_device.h>
> +
> +#define CLKPWR_IOBASE io_p2v(CLK_PM_BASE)
> +
> +/*
> + * Arch specific platform device structures
> + */
> +extern struct platform_device watchdog_device;
> +extern struct platform_device i2c0_device;
> +extern struct platform_device i2c1_device;
> +extern struct platform_device i2c2_device;
> +
> +/*
> + * Other arch specific structures and functions
> + */
> +extern struct sys_timer lpc32xx_timer;
> +extern void __init lpc32xx_init_irq(void);
> +extern void __init lpc32xx_map_io(void);
> +extern void __init lpc32xx_serial_init(void);
> +extern void __init lpc32xx_gpio_init(void);
> +
> +/*
> + * Structure used for setting up and querying the PLLS
> + */
> +struct clk_pll_setup {
> +	int analog_on;
> +	int cco_bypass_b15;
> +	int direct_output_b14;
> +	int fdbk_div_ctrl_b13;
> +	int pll_p;
> +	int pll_n;
> +	u32 pll_m;
> +};
> +
> +extern const u32 pll_postdivs[4];
> +
> +extern int clk_is_sysclk_mainosc(void);
> +extern u32 clk_check_pll_setup(u32 ifreq, struct clk_pll_setup *pllsetup);
> +extern u32 clk_get_pllrate_from_reg(u32 inputclk, u32 regval);
> +extern u32 clk_get_pclk_div(void);
> +
> +/*
> + * Returns the LPC32xx unique 128-bit chip ID
> + */
> +extern void lpc32xx_get_uid(u32 devid[4]);
> +
> +#ifdef CONFIG_DEBUG_LL
> +extern void printascii(const char *);
> +#endif
I'd not recomment using printascii while not debugging.  This cannot
work reliably for a mulit-machine kernel anyhow.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-01-28  1:43 ` [PATCH 08/13] ARM: LPC32XX: clock tree support wellsk40 at gmail.com
  2010-01-28 17:07   ` Rabin Vincent
@ 2010-02-03 16:32   ` Uwe Kleine-König
  2010-02-03 18:51     ` Kevin Wells
  1 sibling, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 16:32 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Wed, Jan 27, 2010 at 05:43:26PM -0800, wellsk40 at gmail.com wrote:
> From: Kevin Wells <wellsk40@gmail.com>
> 
> LPC32XX clock control and query functions
> 
> Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> ---
>  arch/arm/mach-lpc32xx/clock.c | 1042 +++++++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-lpc32xx/clock.h |   41 ++
>  2 files changed, 1083 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-lpc32xx/clock.c b/arch/arm/mach-lpc32xx/clock.c
> new file mode 100644
> index 0000000..615c091
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/clock.c
> @@ -0,0 +1,1042 @@
> +/*
> + * arch/arm/mach-lpc32xx/clock.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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
> + */
> +
> +/*
> + * LPC32xx clock mamagement driver overview
> + *
> + * The LPC32XX contains a number of high level system clocks that can be
> + * generated from different sources. These system clocks are used to
> + * generate the CPU and bus rates and the individual peripheral clocks in
> + * the system. When Linux is started by the boot loader, the system
> + * clocks are already running. Stopping a system clock during normal
> + * Linux operation should never be attempted, as peripherals that require
> + * those clocks will quit working (ie, DRAM).
> + *
> + * The LPC32xx high level clock tree looks as follows. Clocks marked with
> + * an asterisk are always on and cannot be disabled. Clocks marked with
> + * an ampersand can only be disabled in CPU suspend mode. Clocks marked
> + * with a carot are always on if it is the selected clock for the SYSCLK
> + * source. The clock that isn't used for SYSCLK can be enabled and
> + * disabled normally.
> + *                               32KHz oscillator*
> + *                               /      |      \
> + *                             RTC*   PLL397^ TOUCH
> + *                                     /
> + *               Main oscillator^     /
> + *                   |        \      /
> + *                   |         SYSCLK&
> + *                   |            \
> + *                   |             \
> + *                USB_PLL       HCLK_PLL&
> + *                   |           |    |
> + *            USB host/device  PCLK&  |
> + *                               |    |
> + *                             Peripherals
> + *
> + * The CPU and chip bus rates are derived from the HCLK PLL, which can
> + * generate various clock rates up to 266MHz and beyond. The internal bus
> + * rates (PCLK and HCLK) are generated from dividers based on the HCLK
> + * PLL rate. HCLK can be a ratio of 1:1, 1:2, or 1:4 or HCLK PLL rate,
> + * while PCLK can be 1:1 to 1:32 of HCLK PLL rate. Most peripherals high
> + * level clocks are based on either HCLK or PCLK, but have their own
> + * dividers as part of the IP itself. Because of this, the system clock
> + * rates should not be changed.
> + *
> + * The HCLK PLL is clocked from SYSCLK, which can be derived from the
> + * main oscillator or PLL397. PLL397 generates a rate that is 397 times
> + * the 32KHz oscillator rate. The main oscillator runs at the selected
> + * oscillator/crystal rate on the mosc_in pin of the LPC32xx. This rate
> + * is normally 13MHz, but depends on the selection of external crystals
> + * or oscillators. If USB operation is required, the main oscillator must
> + * be used in the system.
> + *
> + * Switching SYSCLK between sources during normal Linux operation is not
> + * supported. SYSCLK is preset in the bootloader. Because of the
> + * complexities of clock management during clock frequency changes,
> + * there are some limitations to the clock driver explained below:
> + * - The PLL397 and main oscillator can be enabled and disabled by the
> + *   clk_enable() and clk_disable() functions unless SYSCLK is based
> + *   on that clock. This allows the other oscillator that isn't driving
> + *   the HCLK PLL to be used as another system clock that can be routed
> + *   to an external pin.
> + * - The muxed SYSCLK input and HCLK_PLL rate cannot be changed with
> + *   this driver.
> + * - HCLK and PCLK rates cannot be changed as part of this driver.
> + * - Most peripherals have their own dividers are part of the peripheral
> + *   block. Changing SYSCLK, HCLK PLL, HCLK, or PCLK sources or rates
> + *   will also impact the individual peripheral rates.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/errno.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/clk.h>
> +#include <linux/amba/bus.h>
> +#include <linux/amba/clcd.h>
> +
> +#include <mach/hardware.h>
> +#include <asm/clkdev.h>
> +#include <mach/clkdev.h>
> +#include <mach/platform.h>
> +#include "clock.h"
> +#include "common.h"
> +
> +static struct clk clk_armpll;
> +static struct clk clk_usbpll;
> +
> +/*
> + * Post divider values for PLLs based on selected register value
> + */
> +const u32 pll_postdivs[4] = {1, 2, 4, 8};
> +
> +#define USB_OTG_IOBASE io_p2v(USB_BASE)
> +
> +/* 32KHz clock has a fixed rate and is not stoppable */
> +static struct clk osc_32KHz = {
> +	.rate		= CLOCK_OSC_FREQ,
> +};
> +
> +static int local_pll397_enable(struct clk *clk, int enable)
> +{
> +	u32 reg;
> +	unsigned long timeout = 1 + msecs_to_jiffies(10);
> +
> +	reg = readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE));
> +
> +	if (enable == 0) 	{
> +		reg |= CLKPWR_SYSCTRL_PLL397_DIS;
> +		writel(reg, CLKPWR_PLL397_CTRL(CLKPWR_IOBASE));
> +		clk->rate = 0;
> +	} else {
> +		/* Enable PLL397 */
> +		reg &= ~CLKPWR_SYSCTRL_PLL397_DIS;
> +		writel(reg, CLKPWR_PLL397_CTRL(CLKPWR_IOBASE));
> +		clk->rate = CLOCK_OSC_FREQ * 397;
> +
> +		/* Wait for PLL397 lock */
> +		while (((readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)) &
> +			CLKPWR_SYSCTRL_PLL397_STS) == 0) &&
> +			(timeout > jiffies))
> +			cpu_relax();
> +
> +		if ((readl(CLKPWR_PLL397_CTRL(CLKPWR_IOBASE)) &
> +			CLKPWR_SYSCTRL_PLL397_STS) == 0)
> +			return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
> +static int local_oscmain_enable(struct clk *clk, int enable)
> +{
> +	u32 reg;
> +	unsigned long timeout = 1 + msecs_to_jiffies(10);
> +
> +	reg = readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE));
> +
> +	if (enable == 0) {
> +		reg |= CLKPWR_MOSC_DISABLE;
> +		writel(reg, CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE));
> +		clk->rate = 0;
> +	} else {
> +		/* Enable main oscillator */
> +		reg &= ~CLKPWR_MOSC_DISABLE;
> +		writel(reg, CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE));
> +		clk->rate = MAIN_OSC_FREQ;
> +
> +		/* Wait for main oscillator to start */
> +		while (((readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)) &
> +			CLKPWR_MOSC_DISABLE) != 0) &&
> +			(timeout > jiffies))
> +			cpu_relax();
> +
> +		if ((readl(CLKPWR_MAIN_OSC_CTRL(CLKPWR_IOBASE)) &
> +			CLKPWR_MOSC_DISABLE) != 0)
> +			return -ENODEV;
> +	}
> +
> +	return 0;
> +}
> +
> +static struct clk osc_pll397 = {
> +	.parent		= &osc_32KHz,
> +	.enable		= &local_pll397_enable,
> +	.rate		= CLOCK_OSC_FREQ * 397,
> +};
> +
> +static struct clk osc_main = {
> +	.enable		= &local_oscmain_enable,
> +	.rate		= MAIN_OSC_FREQ,
> +};
> +
> +static struct clk clk_sys;
> +
> +/*
> + * Setup the HCLK PLL with a PLL structure
> + */
> +static u32 local_clk_pll_setup(struct clk_pll_setup *PllSetup)
> +{
> +	u32 tv, tmp = 0;
> +
> +	if (PllSetup->analog_on != 0)
> +		tmp |= CLKPWR_HCLKPLL_POWER_UP;
> +	if (PllSetup->cco_bypass_b15 != 0)
> +		tmp |= CLKPWR_HCLKPLL_CCO_BYPASS;
> +	if (PllSetup->direct_output_b14 != 0)
> +		tmp |= CLKPWR_HCLKPLL_POSTDIV_BYPASS;
> +	if (PllSetup->fdbk_div_ctrl_b13 != 0)
> +		tmp |= CLKPWR_HCLKPLL_FDBK_SEL_FCLK;
> +
> +	switch (PllSetup->pll_p) {
> +	case 1:
> +		tv = 0;
> +		break;
> +
> +	case 2:
> +		tv = 1;
> +		break;
> +
> +	case 4:
> +		tv = 2;
> +		break;
> +
> +	case 8:
> +		tv = 3;
> +		break;
> +
> +	default:
> +		return 0;
> +	}
> +
> +	tmp |= CLKPWR_HCLKPLL_POSTDIV_2POW(tv);
> +	tmp |= CLKPWR_HCLKPLL_PREDIV_PLUS1(PllSetup->pll_n - 1);
> +	tmp |= CLKPWR_HCLKPLL_PLLM(PllSetup->pll_m - 1);
> +
> +	return tmp;
> +}
> +
> +/*
> + * Update the ARM core PLL frequency rate variable from the actual PLL setting
> + */
> +static void local_update_armpll_rate(void)
> +{
> +	u32 clkin, pllreg;
> +
> +	clkin = clk_armpll.parent->rate;
> +	pllreg = readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & 0x1FFFF;
> +
> +	clk_armpll.rate = clk_get_pllrate_from_reg(clkin, pllreg);
> +}
> +
> +static int clkpwr_abs(int v1, int v2)
> +{
> +	if (v1 > v2)
> +		return v1 - v2;
> +
> +	return v2 - v1;
> +}
> +
> +/*
> + * Find a PLL configuration for the selected input frequency
> + */
> +static u32 local_clk_find_pll_cfg(u32 pllin_freq, u32 target_freq,
> +	struct clk_pll_setup *pllsetup)
> +{
> +	u32 ifreq, freqtol, m, n, p, fclkout = 0;
> +	u32 flag = 0, freqret = 0;
> +
> +	/* Determine frequency tolerance limits */
> +	freqtol = target_freq / 250;
> +	ifreq = pllin_freq;
> +
> +	/* Is direct bypass mode possible? */
> +	if (clkpwr_abs(pllin_freq, target_freq) <= freqtol) {
if (abs(pllin_freq - target_freq)) ...

> +		flag = 1;
> +		pllsetup->analog_on = 0;
> +		pllsetup->cco_bypass_b15 = 1;
> +		pllsetup->direct_output_b14 = 1;
> +		pllsetup->fdbk_div_ctrl_b13 = 1;
> +		pllsetup->pll_p = pll_postdivs[0];
> +		pllsetup->pll_n = 1;
> +		pllsetup->pll_m = 1;
> +		fclkout = clk_check_pll_setup(ifreq, pllsetup);
> +	} else if (target_freq <= ifreq) {
> +		pllsetup->analog_on = 0;
> +		pllsetup->cco_bypass_b15 = 1;
> +		pllsetup->direct_output_b14 = 0;
> +		pllsetup->fdbk_div_ctrl_b13 = 1;
> +		pllsetup->pll_n = 1;
> +		pllsetup->pll_m = 1;
> +		for (p = 0; ((p <= 3) && (flag == 0)); p++) {
> +			pllsetup->pll_p = pll_postdivs[p];
> +			fclkout = clk_check_pll_setup(ifreq, pllsetup);
> +			if (clkpwr_abs(target_freq, fclkout) <= freqtol)
> +				flag = 1;
> +		}
> +	}
> +
> +	/* Is direct mode possible? */
> +	if (flag == 0) {
> +		pllsetup->analog_on = 1;
> +		pllsetup->cco_bypass_b15 = 0;
> +		pllsetup->direct_output_b14 = 1;
> +		pllsetup->fdbk_div_ctrl_b13 = 0;
> +		pllsetup->pll_p = pll_postdivs[0];
> +		for (m = 1; ((m <= 256) && (flag == 0)); m++) {
> +			for (n = 1; ((n <= 4) && (flag == 0)); n++) {
> +				/* Compute output frequency for this value */
> +				pllsetup->pll_n = n;
> +				pllsetup->pll_m = m;
> +				fclkout = clk_check_pll_setup(ifreq,
> +					pllsetup);
> +				if (clkpwr_abs(target_freq, fclkout) <=
> +					freqtol)
> +					flag = 1;
> +			}
> +		}
> +	}
> +
> +	/* Is integer mode possible? */
> +	if (flag == 0) {
> +		pllsetup->analog_on = 1;
> +		pllsetup->cco_bypass_b15 = 0;
> +		pllsetup->direct_output_b14 = 0;
> +		pllsetup->fdbk_div_ctrl_b13 = 1;
> +		for (m = 1; ((m <= 256) && (flag == 0)); m++) {
> +			for (n = 1; ((n <= 4) && (flag == 0)); n++) {
> +				for (p = 0; ((p < 4) && (flag == 0)); p++) {
> +					/* Compute output frequency */
> +					pllsetup->pll_p = pll_postdivs[p];
> +					pllsetup->pll_n = n;
> +					pllsetup->pll_m = m;
> +					fclkout = clk_check_pll_setup(
> +						ifreq, pllsetup);
> +					if (clkpwr_abs(target_freq,
> +						fclkout) <= freqtol)
> +						flag = 1;
> +				}
> +			}
> +		}
> +	}
> +
> +	if (flag == 0)  {
> +		/* Try non-integer mode */
> +		pllsetup->analog_on = 1;
> +		pllsetup->cco_bypass_b15 = 0;
> +		pllsetup->direct_output_b14 = 0;
> +		pllsetup->fdbk_div_ctrl_b13 = 0;
> +		for (m = 1; ((m <= 256) && (flag == 0)); m++) {
> +			for (n = 1; ((n <= 4) && (flag == 0)); n++) {
> +				for (p = 0; ((p < 4) && (flag == 0)); p++) {
> +					/* Compute output frequency */
> +					pllsetup->pll_p = pll_postdivs[p];
> +					pllsetup->pll_n = n;
> +					pllsetup->pll_m = m;
> +					fclkout = clk_check_pll_setup(
> +						ifreq, pllsetup);
> +					if (clkpwr_abs(target_freq,
> +						fclkout) <= freqtol)
> +						flag = 1;
> +				}
> +			}
> +		}
> +	}
> +
> +	if (flag == 1)
> +		freqret = fclkout;
> +
This function could be a bit easier to understand without that flag
variable.  Just return fclkout instead of setting flag = 1.

> +	return freqret;
> +}
> +
> +static struct clk clk_armpll = {
> +	.parent		= &clk_sys,
> +};
> +
> +/*
> + * Update the USB PLL frequency rate variable from the actual PLL setting
> + */
> +static void local_update_usbpll_rate(void)
> +{
> +	u32 clkin, pllreg;
> +
> +	clkin = (u32) clk_get_rate(&clk_usbpll);
> +	pllreg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)) & 0x1FFFF;
> +
> +	if ((pllreg & CLKPWR_USBCTRL_PLL_PWRUP) == 0)
> +		clk_usbpll.rate = 0;
> +	else
> +		clk_usbpll.rate = clk_get_pllrate_from_reg(clkin,
> +			pllreg);
> +}
> +
> +/*
> + * Setup the USB PLL with a PLL structure
> + */
> +static u32 local_clk_usbpll_setup(struct clk_pll_setup *pHCLKPllSetup)
> +{
> +	u32 reg, tmp = local_clk_pll_setup(pHCLKPllSetup);
> +
> +	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE)) & ~0x1FFFF;
> +	reg |= tmp;
> +	writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +
> +	return clk_check_pll_setup(clk_usbpll.parent->rate,
> +		pHCLKPllSetup);
> +}
> +
> +static int local_usbpll_enable(struct clk *clk, int enable)
> +{
> +	u32 reg;
> +	int ret = -ENODEV, qj = (jiffies / 4);
> +
> +	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +
> +	if (enable == 0) {
> +		reg &= ~(CLKPWR_USBCTRL_CLK_EN1 | CLKPWR_USBCTRL_CLK_EN2);
> +		writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +	} else if (reg & CLKPWR_USBCTRL_PLL_PWRUP) {
> +		reg |= CLKPWR_USBCTRL_CLK_EN1;
> +		writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +
> +		/* Wait for PLL lock */
> +		while (qj < jiffies) {
> +			reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +			if (reg & CLKPWR_USBCTRL_PLL_STS)
> +				ret = 0;
> +		}
I wonder if you ever tested that code path.  How long exactly do you
want to wait here?

> +		if (ret == 0) {
> +			reg |= CLKPWR_USBCTRL_CLK_EN2;
> +			writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +static int local_usbpll_set_rate(struct clk *clk, u32 rate)
> +{
> +	u32 clkin, reg, usbdiv;
> +	struct clk_pll_setup pllsetup;
> +
> +	/* Unlike other clocks, this clock has a KHz input rate, so bump
> +	   it up to work with the PLL function */
> +	rate = rate * 1000;
> +
> +	local_usbpll_enable(clk, 0);
> +
> +	if (rate == 0)
> +		return 0;
> +
> +	clkin = clk->parent->rate;
> +	usbdiv = readl(CLKPWR_USBCLK_PDIV(CLKPWR_IOBASE)) + 1;
> +	clkin = clkin / usbdiv;
> +
> +	/* Try to find a good rate setup */
> +	if (local_clk_find_pll_cfg(clkin, rate, &pllsetup) == 0)
> +		return -EINVAL;
> +
> +	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +	reg |= CLKPWR_USBCTRL_CLK_EN1;
> +	writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +
> +	pllsetup.analog_on = 1;
> +	local_clk_usbpll_setup(&pllsetup);
> +
> +	clk->rate = clk_check_pll_setup(clkin, &pllsetup);
> +
> +	reg = readl(CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +	reg |= CLKPWR_USBCTRL_CLK_EN2;
> +	writel(reg, CLKPWR_USB_CTRL(CLKPWR_IOBASE));
> +
> +	return 0;
> +}
> +
> +static struct clk clk_usbpll = {
> +	.parent		= &osc_main,
> +	.set_rate	= &local_usbpll_set_rate,
> +	.enable		= &local_usbpll_enable,
> +};
> +
> +static u32 clk_get_hclk_div(void)
> +{
> +	static const u32 hclkdivs[4] = {1, 2, 4, 4};
> +	return hclkdivs[CLKPWR_HCLKDIV_DIV_2POW(
> +		readl(CLKPWR_HCLK_DIV(CLKPWR_IOBASE)))];
> +}
> +
> +static struct clk clk_hclk = {
> +	.parent		= &clk_armpll,
> +};
> +
> +static struct clk clk_pclk = {
> +	.parent		= &clk_armpll,
> +};
> +
> +static int local_onoff_enable(struct clk *clk, int enable)
> +{
> +	u32 tmp;
> +
> +	tmp = readl(clk->enable_reg);
> +
> +	if (enable == 0)
> +		tmp &= ~clk->enable_mask;
> +	else
> +		tmp |= clk->enable_mask;
> +
> +	writel(tmp, clk->enable_reg);
> +
> +	return 0;
> +}
> +
> +/* Peripheral clock sources */
> +static struct clk clk_timer0 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER0_EN,
> +};
> +static struct clk clk_timer1 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER1_EN,
> +};
> +static struct clk clk_timer2 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER2_EN,
> +};
> +static struct clk clk_timer3 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_TMRPWMCLK_TIMER3_EN,
> +};
> +static struct clk clk_wdt = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_TIMER_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_PWMCLK_WDOG_EN,
> +};
> +static struct clk clk_vfp9 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_DEBUG_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_VFP_CLOCK_ENABLE_BIT,
> +};
> +static struct clk clk_dma = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_DMA_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_DMACLKCTRL_CLK_EN,
> +};
> +
> +static struct clk clk_uart3 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_UARTCLKCTRL_UART3_EN,
> +};
> +
> +static struct clk clk_uart4 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_UARTCLKCTRL_UART4_EN,
> +};
> +
> +static struct clk clk_uart5 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_UARTCLKCTRL_UART5_EN,
> +};
> +
> +static struct clk clk_uart6 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_UARTCLKCTRL_UART6_EN,
> +};
> +
> +static struct clk clk_i2c0 = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_I2CCLK_I2C1CLK_EN,
> +};
> +
> +static struct clk clk_i2c1 = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_I2C_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_I2CCLK_I2C2CLK_EN,
> +};
> +
> +static struct clk clk_i2c2 = {
> +	.parent		= &clk_pclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= USB_OTG_IOBASE + 0xFF4,
> +	.enable_mask	= 0x4,
> +};
> +
> +static struct clk clk_ssp0 = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_SSPCTRL_SSPCLK0_EN,
> +};
> +static struct clk clk_ssp1 = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_SSP_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_SSPCTRL_SSPCLK1_EN,
> +};
> +
> +static struct clk clk_kscan = {
> +	.parent		= &osc_32KHz,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_KEY_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_KEYCLKCTRL_CLK_EN,
> +};
> +
> +static struct clk clk_nand = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_NAND_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_NANDCLK_SLCCLK_EN,
> +};
> +
> +static struct clk clk_i2s0 = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_I2SCTRL_I2SCLK0_EN,
> +};
> +static struct clk clk_i2s1 = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_I2S_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_I2SCTRL_I2SCLK1_EN,
> +};
> +
> +static struct clk clk_net = {
> +	.parent		= &clk_hclk,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_MACCLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= (CLKPWR_MACCTRL_DMACLK_EN |
> +		CLKPWR_MACCTRL_MMIOCLK_EN | CLKPWR_MACCTRL_HRCCLK_EN),
> +};
> +
> +static struct clk clk_rtc = {
> +	.parent		= &osc_32KHz,
> +	.rate		= 1, /* 1 Hz */
> +};
> +
> +static struct clk clk_usbd = {
> +	.parent		= &clk_usbpll,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_USB_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_USBCTRL_HCLK_EN,
> +};
> +
> +static int tsc_onoff_enable(struct clk *clk, int enable)
> +{
> +	u32 tmp;
> +
> +	/* Make sure 32KHz clock is the selected clock */
> +	tmp = readl(CLKPWR_ADC_CLK_CTRL_1(CLKPWR_IOBASE));
> +	tmp &= ~CLKPWR_ADCCTRL1_PCLK_SEL;
> +	writel(tmp, CLKPWR_ADC_CLK_CTRL_1(CLKPWR_IOBASE));
> +
> +	if (enable == 0)
> +		writel(0, clk->enable_reg);
> +	else
> +		writel(clk->enable_mask, clk->enable_reg);
> +
> +	return 0;
> +}
> +
> +static struct clk clk_tsc = {
> +	.parent		= &osc_32KHz,
> +	.enable		= &tsc_onoff_enable,
> +	.enable_reg	= CLKPWR_ADC_CLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_ADC32CLKCTRL_CLK_EN,
> +};
> +
> +static int mmc_onoff_enable(struct clk *clk, int enable)
> +{
> +	u32 tmp;
> +
> +	tmp = readl(CLKPWR_MS_CTRL(CLKPWR_IOBASE)) &
> +		~(CLKPWR_MSCARD_SDCARD_EN|CLKPWR_MSCARD_SDCARD_DIV(15));
> +
> +	/* If rate is 0, disable clock */
> +	if (enable != 0)
> +		tmp |= CLKPWR_MSCARD_SDCARD_EN | CLKPWR_MSCARD_SDCARD_DIV(1);
> +
> +	writel(tmp, CLKPWR_MS_CTRL(CLKPWR_IOBASE));
> +
> +	return 0;
> +}
> +
> +static u32 mmc_get_rate(struct clk *clk)
> +{
> +	u32 div, tmp, rate;
> +
> +	div = readl(CLKPWR_MS_CTRL(CLKPWR_IOBASE));
> +	tmp = div & CLKPWR_MSCARD_SDCARD_EN;
> +
> +	if (!tmp)
> +		return 0;
> +
> +	/* Get the parent clock rate */
> +	rate = clk_get_rate(clk->parent);
> +
> +	/* Get the LCD controller clock divider value */
> +	div = div & 0xF;
> +
> +	if (!div)
> +		return 0;
> +
> +	tmp = rate / div;
> +
> +	return tmp;
> +}
> +
> +static int mmc_set_rate(struct clk *clk, u32 rate)
> +{
> +	if (rate == 0)
> +		mmc_onoff_enable(clk, 0);
> +	else
> +		mmc_onoff_enable(clk, 1);
	mmc_onoff_enable(clk, !!rate);
> +
> +	return 0;
> +}
> +
> +static struct clk clk_mmc = {
> +	.parent		= &clk_armpll,
> +	.set_rate	= &mmc_set_rate,
> +	.get_rate	= &mmc_get_rate,
> +	.enable		= &mmc_onoff_enable,
> +	.enable_reg	= CLKPWR_MS_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_MSCARD_SDCARD_EN,
> +};
> +
> +static u32 clcd_get_rate(struct clk *clk)
> +{
> +	u32 tmp, div, rate;
> +
> +	tmp = readl(CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE)) &
> +		CLKPWR_LCDCTRL_CLK_EN;
> +
> +	if (!tmp)
> +		return 0;
> +
> +	rate = clk_get_rate(clk->parent);
> +	tmp = readl((io_p2v(LCD_BASE)) + CLCD_TIM2);
> +
> +	/* Only supports internal clocking */
> +	if (tmp & TIM2_BCD)
> +		return rate;
> +
> +	div = (tmp & 0x1F) | ((tmp & 0xF8) >> 22);
> +	tmp = rate / (2 + div);
> +
> +	return tmp;
> +}
> +
> +static int clcd_set_rate(struct clk *clk, u32 rate)
> +{
> +	u32 tmp, prate, div;
> +
> +	tmp = readl((io_p2v(LCD_BASE)) + CLCD_TIM2);
> +	prate = clk_get_rate(clk->parent);
> +
> +	if (rate == prate) {
> +		tmp |= TIM2_BCD;
> +		local_onoff_enable(clk, 1);
> +	} else {
> +		/* Find closest divider */
> +		div = prate / rate;
> +		if (div == 1)
> +			div = 0;
> +		else
> +			div -= 2;
> +
> +		tmp &= ~(0xF800001F);
> +		tmp &= ~TIM2_BCD;
> +		tmp |= (div & 0x1F);
> +		tmp |= (((div >> 5) & 0x1F) << 27);
> +		writel(tmp, ((io_p2v(LCD_BASE)) + CLCD_TIM2));
> +		local_onoff_enable(clk, 1);
> +	}
> +
> +	return 0;
> +}
> +static struct clk clk_lcd = {
> +	.parent		= &clk_hclk,
> +	.set_rate	= &clcd_set_rate,
> +	.get_rate	= &clcd_get_rate,
> +	.enable		= &local_onoff_enable,
> +	.enable_reg	= CLKPWR_LCDCLK_CTRL(CLKPWR_IOBASE),
> +	.enable_mask	= CLKPWR_LCDCTRL_CLK_EN,
> +};
> +
> +static inline void clk_lock(void)
> +{
> +	local_irq_disable();
> +}
> +
> +static inline void clk_unlock(void)
> +{
> +	local_irq_enable();
> +}
This means all code to enable and disable clocks must not sleep.  I
wouldn't count on this, better use a mutex here.  (The downside is that
you cannot call clk_enable from irq context, but that should be
manageable.)

> +static void local_clk_disable(struct clk *clk)
> +{
> +	/* Don't attempt to disable clock if it has no users */
> +	if (clk->usecount > 0) {
> +		clk->usecount--;
> +
> +		/* Only disable clock when it has no more users */
> +		if ((clk->usecount == 0) && (clk->enable))
> +			clk->enable(clk, 0);
> +
> +		/* Check parent clocks, they may need to be disabled too */
> +		if (clk->parent)
> +			local_clk_disable(clk->parent);
> +	}
> +}
> +
> +static int local_clk_enable(struct clk *clk)
> +{
> +	int ret = 0;
> +
> +	if (clk->usecount == 0) {
> +		/* Enable parent clocks first */
> +		if (clk->parent)
> +			ret = local_clk_enable(clk->parent);
> +
> +		/* Enable clock on first use */
> +		if ((ret == 0) && (clk->enable)) {
> +			ret = clk->enable(clk, 1);
> +			clk->usecount++;
> +		}
> +
> +		/* Back out use counters if enable fails */
> +		if (ret < 0)
> +			local_clk_disable(clk);
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * clk_enable - inform the system when the clock source should be running.
> + */
> +int clk_enable(struct clk *clk)
> +{
> +	int ret;
> +
> +	clk_lock();
> +	ret = local_clk_enable(clk);
> +	clk_unlock();
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(clk_enable);
> +
> +/*
> + * clk_disable - inform the system when the clock source is no longer required
> + */
> +void clk_disable(struct clk *clk)
> +{
> +	clk_lock();
> +	local_clk_disable(clk);
> +	clk_unlock();
> +}
> +EXPORT_SYMBOL(clk_disable);
> +
> +/*
> + * clk_get_rate - obtain the current clock rate (in Hz) for a clock source
> + */
> +unsigned long clk_get_rate(struct clk *clk)
> +{
> +	if (clk->get_rate)
> +		return (clk->get_rate)(clk);
> +
> +	/* If a clocks rate is 0, it uses the parent's rate instead. */
> +	while (clk->rate == 0)
> +		clk = clk->parent;
> +
> +	return clk->rate;
> +}
> +EXPORT_SYMBOL(clk_get_rate);
doesn't that need locking to protect against a race with clk_set_rate?
Hmmm, you never need to call get_rate for a parent clock?

> +
> +/*
> + * clk_set_rate - set the clock rate for a clock source
> + */
> +int clk_set_rate(struct clk *clk, unsigned long rate)
> +{
> +	int ret = -EINVAL;
> +
> +	/* Most system clocks can only be enabled or disabled, with
> +	   the actual rate set as part of the peripheral dividers
> +	   instead of high level clock control */
> +	if (clk->set_rate) {
> +		clk_lock();
> +		ret = (clk->set_rate)(clk, rate);
> +		clk_unlock();
> +	}
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(clk_set_rate);
> +
> +/*
> + * clk_round_rate - adjust a rate to the exact rate a clock can provide
> + */
> +long clk_round_rate(struct clk *clk, unsigned long rate)
> +{
> +	int ret;
> +
> +	/* Use set_rate to try to adjust the rate if it supports it */
> +	ret = clk_set_rate(clk, rate);
> +	if (ret < 0)
> +		return (long) ret;
AFAIK the cast isn't necessary.

> +	return clk->rate;
> +}
> +EXPORT_SYMBOL(clk_round_rate);
> +
> +/*
> + * clk_set_parent - set the parent clock source for this clock
> + */
> +int clk_set_parent(struct clk *clk, struct clk *parent)
> +{
> +	/* Clock re-parenting is not supported */
> +	return -EINVAL;
> +}
> +EXPORT_SYMBOL(clk_set_parent);
> +
> +/*
> + * clk_get_parent - get the parent clock source for this clock
> + */
> +struct clk *clk_get_parent(struct clk *clk)
> +{
> +	return clk->parent;
> +}
> +EXPORT_SYMBOL(clk_get_parent);
> +
> +#define _REGISTER_CLOCK(d, n, c) \
> +	{ \
> +		.dev_id = (d), \
> +		.con_id = (n), \
> +		.clk = &(c), \
> +	},
> +
> +static struct clk_lookup lookups[] __initdata = {
> +	_REGISTER_CLOCK(NULL, "osc_32KHz", osc_32KHz)
> +	_REGISTER_CLOCK(NULL, "osc_pll397", osc_pll397)
> +	_REGISTER_CLOCK(NULL, "osc_main", osc_main)
> +	_REGISTER_CLOCK(NULL, "sys_ck", clk_sys)
> +	_REGISTER_CLOCK(NULL, "arm_pll_ck", clk_armpll)
> +	_REGISTER_CLOCK(NULL, "ck_pll5", clk_usbpll)
> +	_REGISTER_CLOCK(NULL, "hclk_ck", clk_hclk)
> +	_REGISTER_CLOCK(NULL, "pclk_ck", clk_pclk)
> +	_REGISTER_CLOCK(NULL, "timer0_ck", clk_timer0)
> +	_REGISTER_CLOCK(NULL, "timer1_ck", clk_timer1)
> +	_REGISTER_CLOCK(NULL, "timer2_ck", clk_timer2)
> +	_REGISTER_CLOCK(NULL, "timer3_ck", clk_timer3)
> +	_REGISTER_CLOCK(NULL, "vfp9_ck", clk_vfp9)
> +	_REGISTER_CLOCK(NULL, "clk_dmac", clk_dma)
> +	_REGISTER_CLOCK("pnx4008-watchdog", NULL, clk_wdt)
> +	_REGISTER_CLOCK(NULL, "uart3_ck", clk_uart3)
> +	_REGISTER_CLOCK(NULL, "uart4_ck", clk_uart4)
> +	_REGISTER_CLOCK(NULL, "uart5_ck", clk_uart5)
> +	_REGISTER_CLOCK(NULL, "uart6_ck", clk_uart6)
> +	_REGISTER_CLOCK("pnx-i2c.0", NULL, clk_i2c0)
> +	_REGISTER_CLOCK("pnx-i2c.1", NULL, clk_i2c1)
> +	_REGISTER_CLOCK("pnx-i2c.2", NULL, clk_i2c2)
> +	_REGISTER_CLOCK("dev:ssp0", NULL, clk_ssp0)
> +	_REGISTER_CLOCK("dev:ssp1", NULL, clk_ssp1)
> +	_REGISTER_CLOCK("lpc32xx_keys.0", NULL, clk_kscan)
> +	_REGISTER_CLOCK("lpc32xx-nand.0", "nand_ck", clk_nand)
> +	_REGISTER_CLOCK("tbd", "i2s0_ck", clk_i2s0)
> +	_REGISTER_CLOCK("tbd", "i2s1_ck", clk_i2s1)
> +	_REGISTER_CLOCK("lpc32xx-ts", NULL, clk_tsc)
> +	_REGISTER_CLOCK("dev:mmc0", "MCLK", clk_mmc)
> +	_REGISTER_CLOCK("lpc-net.0", NULL, clk_net)
> +	_REGISTER_CLOCK("dev:clcd", NULL, clk_lcd)
> +	_REGISTER_CLOCK("lpc32xx_udc", "ck_usbd", clk_usbd)
> +	_REGISTER_CLOCK("lpc32xx_rtc", NULL, clk_rtc)
> +};
> +
> +int __init clk_init(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(lookups); i++)
> +		clkdev_add(&lookups[i]);
> +
> +	/* Setup muxed SYSCLK for HCLK PLL base -this selects the
> +	   parent clock used for the ARM PLL and is used to derive
> +	   the many system clock rates in the device. */
> +	if (clk_is_sysclk_mainosc() != 0)
> +		clk_sys.parent = &osc_main;
> +	else
> +		clk_sys.parent = &osc_pll397;
> +
> +	clk_sys.rate = clk_sys.parent->rate;
> +
> +	/* Compute the current ARM PLL and USB PLL frequencies */
> +	local_update_armpll_rate();
> +	local_update_usbpll_rate();
> +
> +	/* Compute HCLK and PCLK bus rates */
> +	clk_hclk.rate = clk_hclk.parent->rate / clk_get_hclk_div();
> +	clk_pclk.rate = clk_pclk.parent->rate / clk_get_pclk_div();
> +
> +	/* Enable system clocks - this step is somewhat formal, as the
> +	   clocks are already running, but it does get the clock data
> +	   inline with the actual system state. Never disable these
> +	   clocks as they will only stop if the system is going to sleep.
> +	   In that case, the chip/system power management functions will
> +	   handle clock gating. */
> +	clk_enable(&clk_hclk);
> +	clk_enable(&clk_pclk);
> +
> +	/* Timers 0 and 1 were enabled and are being used by the high
> +	   resolution tick function prior to this driver being initialized.
> +	   Tag them now as used */
> +	clk_enable(&clk_timer0);
> +	clk_enable(&clk_timer1);
> +
> +	return 0;
> +}
> +core_initcall(clk_init);
> +
> diff --git a/arch/arm/mach-lpc32xx/clock.h b/arch/arm/mach-lpc32xx/clock.h
> new file mode 100644
> index 0000000..f37f245
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/clock.h
> @@ -0,0 +1,41 @@
> +/*
> + * arch/arm/mach-lpc32xx/clock.h
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef __LPC32XX_CLOCK_H
> +#define __LPC32XX_CLOCK_H
> +
> +struct clk {
> +	struct list_head node;
> +	struct clk *parent;
> +	u32 rate;
> +	s8 usecount;
> +
> +	int (*set_rate) (struct clk *, u32);
> +	int (*enable) (struct clk *clk, int);
> +	u32 (*get_rate) (struct clk *clk);
> +
> +	/* Register address and bit mask for simple clocks */
> +	u32 enable_reg;
> +	u32 enable_mask;
> +};
> +
> +#endif
> -- 
> 1.6.6
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 09/13] ARM: LPC32XX: power and event management
  2010-01-28  1:43 ` [PATCH 09/13] ARM: LPC32XX: power and event management wellsk40 at gmail.com
@ 2010-02-03 16:44   ` Uwe Kleine-König
  2010-02-03 19:03     ` Kevin Wells
  0 siblings, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 16:44 UTC (permalink / raw)
  To: linux-arm-kernel

Hello Kevin,

On Wed, Jan 27, 2010 at 05:43:27PM -0800, wellsk40 at gmail.com wrote:
> From: Kevin Wells <wellsk40@gmail.com>
> 
> Power mode suspend code and event management code used for device,
> system, and memory sleep/wakeup
> 
> Signed-off-by: Kevin Wells <wellsk40@gmail.com>
> ---
>  arch/arm/mach-lpc32xx/pm.c        |  170 +++++++++++++++
>  arch/arm/mach-lpc32xx/pm.h        |  140 ++++++++++++
>  arch/arm/mach-lpc32xx/pm_events.c |  426 +++++++++++++++++++++++++++++++++++++
>  arch/arm/mach-lpc32xx/suspend.S   |  155 ++++++++++++++
>  4 files changed, 891 insertions(+), 0 deletions(-)
> 
> diff --git a/arch/arm/mach-lpc32xx/pm.c b/arch/arm/mach-lpc32xx/pm.c
> new file mode 100644
> index 0000000..8535e99
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/pm.c
> @@ -0,0 +1,170 @@
> +/*
> + * arch/arm/mach-lpc32xx/pm.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + * Based in part on PNX4008 power management code
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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
> + */
> +
> +/*
> + * LPC32XX CPU and system power management
> + *
> + * The LCP32XX has three CPU modes for controlling system power: run,
> + * direct-run, and halt modes. When switching between halt and run modes,
> + * the CPU transistions through direct-run mode. For Linux, direct-run
> + * mode is not used in normal operation. Halt mode is used when the
> + * system is fully suspended.
> + *
> + * Run mode:
> + * The ARM CPU clock (HCLK_PLL), HCLK bus clock, and PCLK bus clocks are
> + * derived from the HCLK PLL. The HCLK and PCLK bus rates are divided from
> + * the HCLK_PLL rate. Linux runs in this mode.
> + *
> + * Direct-run mode:
> + * The ARM CPU clock, HCLK bus clock, and PCLK bus clocks are driven from
> + * SYSCLK. SYSCLK is usually around 13MHz, but may vary based on SYSCLK
> + * source or the frequency of the main oscillator. In this mode, the
> + * HCLK_PLL can be safely enabled, changed, or disabled.
> + *
> + * Halt mode:
> + * SYSCLK is gated off and the CPU and system clocks are halted.
> + * Peripherals based on the 32KHz oscillator clock (ie, RTC, touch,
> + * key scanner, etc.) still operate if enabled. In this state, an enabled
> + * system event (ie, GPIO state change, RTC match, key press, etc.) will
> + * wake the system up back into direct-run mode.
> + *
> + * DRAM refresh
> + * DRAM clocking and refresh are slightly different for systems with DDR
> + * DRAM or regular SDRAM devices. If SDRAM is used in the system, the
> + * SDRAM will still be accessible in direct-run mode. In DDR based systems,
> + * a transistion to direct-run mode will stop all DDR accesses (no clocks).
> + * Because of this, the code to switch power modes and the code to enter
> + * and exit DRAM self-refresh modes must not be executed in DRAM. A small
> + * section of IRAM is used instead for this.
> + *
> + * Suspend is handled with the following logic:
> + *  Backup a small area of IRAM used for the suspend code
> + *  Copy suspend code to IRAM
> + *  Transfer control to code in IRAM
> + *  Places DRAMs in self-refresh mode
> + *  Enter direct-run mode
> + *  Save state of HCLK_PLL PLL
> + *  Disable HCLK_PLL PLL
> + *  Enter halt mode - CPU and buses will stop
> + *  System enters direct-run mode when an enabled event occurs
> + *  HCLK PLL state is restored
> + *  Run mode is entered
> + *  DRAMS are placed back into normal mode
> + *  Code execution returns from IRAM
> + *  IRAM code are used for suspend is restored
> + *  Suspend mode is exited
> + */
> +
> +#include <linux/suspend.h>
> +#include <linux/io.h>
> +
> +#include <asm/irq.h>
> +#include <asm/atomic.h>
> +#include <asm/mach/time.h>
> +#include <asm/mach/irq.h>
> +#include <asm/cacheflush.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/platform.h>
> +#include "common.h"
> +#include "clock.h"
> +#include "pm.h"
> +
> +#define TEMP_IRAM_AREA  io_p2v(IRAM_BASE)
> +
> +static void *iram_swap_area;
> +
> +static int lpc32xx_pm_valid_state(suspend_state_t state)
> +{
> +	return (state == PM_SUSPEND_STANDBY) ||
> +	       (state == PM_SUSPEND_MEM);
> +}
Why support both standby and mem and let both do the same?

> +/*
> + * Both STANDBY and MEM suspend states are handled the same with no
> + * loss of CPU or memory state
> + */
> +static int lpc32xx_pm_enter(suspend_state_t state)
> +{
> +	int (*lpc32xx_suspend_ptr) (void);
> +
> +	if (state == PM_SUSPEND_MEM || state == PM_SUSPEND_STANDBY) {
> +		/* The CPU and MEM suspend code do the same thing. Wakeup
> +		   from both states is very quick. */
> +
> +		/* Backup a small area of IRAM used for the suspend code */
> +		memcpy(iram_swap_area, (void *) TEMP_IRAM_AREA,
> +			lpc32xx_sys_suspend_sz);
> +		flush_cache_all();
> +
> +		/* Copy code to suspend system into IRAM. The suspend code
> +		   needs to run from IRAM as DRAM may no longer be available
> +		   when the PLL is stopped. */
> +		memcpy((void *) TEMP_IRAM_AREA, &lpc32xx_sys_suspend,
> +			lpc32xx_sys_suspend_sz);
> +
> +		/* Transfer to suspend code in IRAM */
> +		lpc32xx_suspend_ptr = (void *) TEMP_IRAM_AREA;
> +		(void) lpc32xx_suspend_ptr();
> +
> +		/* Restore original IRAM contents */
> +		memcpy((void *) TEMP_IRAM_AREA, iram_swap_area,
> +			lpc32xx_sys_suspend_sz);
> +	} else
> +		return -ENOTSUPP;
I don't know much about PM, but I think it's not necessary to test state
if valid only accepts PM_SUSPEND_MEM and PM_SUSPEND_STANDBY.

> +	/* Clear any pending wakeup events */
> +	lpc32xx_event_clear_all();
> +
> +	return 0;
> +}
> +
> +static struct platform_suspend_ops lpc32xx_pm_ops = {
> +	.valid	= lpc32xx_pm_valid_state,
> +	.enter	= lpc32xx_pm_enter,
> +};
> +
> +#define EMC_DYN_MEM_CTRL_OFS 0x20
> +#define EMC_SRMMC           (1 << 3)
> +
> +static int __init lpc32xx_pm_init(void)
> +{
> +	/* Setup SDRAM self-refresh clock to automatically
> +	   disable on start of self-refresh */
> +	writel(readl(io_p2v(EMC_BASE) + EMC_DYN_MEM_CTRL_OFS) | EMC_SRMMC,
> +		io_p2v(EMC_BASE) + EMC_DYN_MEM_CTRL_OFS);
> +
> +	/* Allocate some space for temporary IRAM storage */
> +	iram_swap_area = kmalloc(lpc32xx_sys_suspend_sz, GFP_ATOMIC);
Why atomic memory?  Why don't you allocate the needed memory only when
you're going down?

> +	if (!iram_swap_area) {
> +		printk(KERN_ERR
> +		       "PM Suspend: cannot allocate memory to save portion "
> +			"of SRAM\n");
> +		return -ENOMEM;
> +	}
> +
> +	suspend_set_ops(&lpc32xx_pm_ops);
> +
> +	return 0;
> +}
> +arch_initcall(lpc32xx_pm_init);
> diff --git a/arch/arm/mach-lpc32xx/pm.h b/arch/arm/mach-lpc32xx/pm.h
> new file mode 100644
> index 0000000..9d7d548
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/pm.h
> @@ -0,0 +1,140 @@
> +/*
> + * arch/arm/mach-lpc32xx/pm.h
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef __LPC32XX__PM_H
> +#define __LPC32XX__PM_H
> +
> +/*
> + * This file allows the enable and disable of events that can wake up
> + * the system when in sleep mode. Events fire on either the low or
> + * high edge transistion and can be configured in hardware.
> + */
> +
> +enum lpc32xx_events {
> +	/* For the following group, an active transistion on the pin
s/transistion/transition/

> +	   associated with the event will wakeup the chip if the
> +	   event is enabled. */
> +	LPC32XX_WKUP_GPI_08,
> +	LPC32XX_WKUP_GPI_09,
> +	LPC32XX_WKUP_GPI_19,
> +	LPC32XX_WKUP_SPI2_DATIN,
> +	LPC32XX_WKUP_GPI_07,
> +	LPC32XX_WKUP_SPI1_DATIN,
> +	LPC32XX_WKUP_SYSCLKEN,
> +	LPC32XX_WKUP_GPI00, /* Input mode only */
> +	LPC32XX_WKUP_GPI01, /* Input mode only */
> +	LPC32XX_WKUP_GPI02, /* Input mode only */
> +	LPC32XX_WKUP_GPI03, /* Input mode only */
> +	LPC32XX_WKUP_GPI04, /* Input mode only */
> +	LPC32XX_WKUP_GPI05, /* Input mode only */
> +	LPC32XX_WKUP_GPI06, /* Input mode only */
> +	LPC32XX_WKUP_MSDIO_START, /* All SD data signals Or'ed */
> +	LPC32XX_WKUP_SDIO_INT_N, /* SDIO D1 only */
> +	LPC32XX_WKUP_U1_RX,
> +	LPC32XX_WKUP_U2_RX,
> +	LPC32XX_WKUP_U2_HCTS,
> +	LPC32XX_WKUP_U3_RX,
> +	LPC32XX_WKUP_GPI_28,
> +	LPC32XX_WKUP_U5_RX,
> +	LPC32XX_WKUP_U6_IRRX,
> +	LPC32XX_WKUP_U7_HCTS,
> +	LPC32XX_WKUP_U7_RX,
> +
> +	/* For the following group, an interrupt for the peripheral
> +	   will wakeup the chip if the event is enabled. */
> +	LPC32XX_WKUP_GPIO_00,
> +	LPC32XX_WKUP_GPIO_01,
> +	LPC32XX_WKUP_GPIO_02,
> +	LPC32XX_WKUP_GPIO_03,
> +	LPC32XX_WKUP_GPIO_04,
> +	LPC32XX_WKUP_GPIO_05,
> +	LPC32XX_WKUP_P0_P1_ALL, /* One or more sources in P0/P1 */
> +	LPC32XX_WKUP_MAC_START,
> +	LPC32XX_WKUP_KEY_IRQ,
> +	LPC32XX_WKUP_USB_OTG_ATX_INT_N,
> +	LPC32XX_WKUP_USB_OTG_TIMER,
> +	LPC32XX_WKUP_USB_I2C_INT,
> +	LPC32XX_WKUP_USB_INT,
> +	LPC32XX_WKUP_USB_NEED_CLK,
> +	LPC32XX_WKUP_RTC_INT,
> +	LPC32XX_WKUP_MSTIMER_INT,
> +	LPC32XX_WKUP_USB_AHC_NEED_CLK,
> +	LPC32XX_WKUP_TS_AUX_INT,
> +	LPC32XX_WKUP_TS_P_INT,
> +	LPC32XX_WKUP_TS_INT,
> +
> +	/* P0/P1 group signals. These signals are all routed through the
> +	   LPC32XX_WKUP_P0_P1_ALL event in the previous group, so be sure
> +	   to enable LPC32XX_WKUP_P0_P1_ALL if any of these are used. Any
> +	   one enabled and active event will generate the
> +	   LPC32XX_WKUP_P0_P1_ALL event */
> +	LPC32XX_WKUP_P0_0,
> +	LPC32XX_WKUP_P0_1,
> +	LPC32XX_WKUP_P0_2,
> +	LPC32XX_WKUP_P0_3,
> +	LPC32XX_WKUP_P0_4,
> +	LPC32XX_WKUP_P0_5,
> +	LPC32XX_WKUP_P0_6,
> +	LPC32XX_WKUP_P0_7,
> +	LPC32XX_WKUP_P1_3,
> +	LPC32XX_WKUP_P1_4,
> +	LPC32XX_WKUP_P1_5,
> +	LPC32XX_WKUP_P1_6,
> +	LPC32XX_WKUP_P1_7,
> +	LPC32XX_WKUP_P1_8,
> +	LPC32XX_WKUP_P1_9,
> +	LPC32XX_WKUP_P1_10,
> +	LPC32XX_WKUP_P1_11,
> +	LPC32XX_WKUP_P1_12,
> +	LPC32XX_WKUP_P1_13,
> +	LPC32XX_WKUP_P1_14,
> +	LPC32XX_WKUP_P1_15,
> +	LPC32XX_WKUP_P1_16,
> +	LPC32XX_WKUP_P1_17,
> +	LPC32XX_WKUP_P1_18,
> +	LPC32XX_WKUP_P1_19,
> +	LPC32XX_WKUP_P1_20,
> +	LPC32XX_WKUP_P1_21,
> +	LPC32XX_WKUP_P1_22,
> +	LPC32XX_WKUP_P1_23,
> +	LPC32XX_LAST_EVENT = LPC32XX_WKUP_P1_23
> +};
> +
> +/*
> + * Wakeup event support
> + */
> +extern void lpc32xx_event_init(void);
> +extern void lpc32xx_event_enable(enum lpc32xx_events event_id);
> +extern void lpc32xx_event_disable(enum lpc32xx_events event_id);
> +extern int lpc32xx_event_set(enum lpc32xx_events event_id,
> +	int high_edge);
> +extern int lpc32xx_event_enabled(enum lpc32xx_events event_id);
> +extern void lpc32xx_event_clear(enum lpc32xx_events event_id);
> +extern void lpc32xx_event_clear_all(void);
This is usually plugged into set_irq_wake.  Isn't that generic enough
for you?

> +
> +/*
> + * Pointers used for sizing and copying suspend function data
> + */
> +extern int lpc32xx_sys_suspend(void);
> +extern int lpc32xx_sys_suspend_sz;
> +
> +#endif
> diff --git a/arch/arm/mach-lpc32xx/pm_events.c b/arch/arm/mach-lpc32xx/pm_events.c
> new file mode 100644
> index 0000000..d3b1b54
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/pm_events.c
> @@ -0,0 +1,426 @@
> +/*
> + * arch/arm/mach-lpc32xx/pm_events.c
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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/types.h>
> +#include <linux/io.h>
> +#include <linux/err.h>
> +
> +#include <mach/hardware.h>
> +#include <mach/platform.h>
> +#include "common.h"
> +#include "pm.h"
> +
> +struct lpc32xx_event_info {
> +	u32 offs;
> +	u32 mask;
> +};
> +
> +static const struct lpc32xx_event_info events[LPC32XX_LAST_EVENT + 1] = {
> +	[LPC32XX_WKUP_GPI_08] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O8_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI_09] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O9_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI_19] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_19_BIT,
> +	},
> +	[LPC32XX_WKUP_SPI2_DATIN] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_SPI2_DATIN_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI_07] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O7_BIT,
> +	},
> +	[LPC32XX_WKUP_SPI1_DATIN] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_SPI1_DATIN_BIT,
> +	},
> +	[LPC32XX_WKUP_SYSCLKEN] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_SYSCLKEN_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI00] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O0_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI01] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O1_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI02] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O2_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI03] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O3_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI04] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O4_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI05] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O5_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI06] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPIO_O6_BIT,
> +	},
> +	[LPC32XX_WKUP_MSDIO_START] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_MSDIO_SRT_BIT,
> +	},
> +	[LPC32XX_WKUP_SDIO_INT_N] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_MSDIO_INT_BIT,
> +	},
> +	[LPC32XX_WKUP_U1_RX] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U1_RX_BIT,
> +	},
> +	[LPC32XX_WKUP_U2_RX] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U2_RX_BIT,
> +	},
> +	[LPC32XX_WKUP_U2_HCTS] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U2_HCTS_BIT,
> +	},
> +	[LPC32XX_WKUP_U3_RX] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U3_RX_BIT,
> +	},
> +	[LPC32XX_WKUP_GPI_28] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_GPI_11_BIT,
> +	},
> +	[LPC32XX_WKUP_U5_RX] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U5_RX_BIT,
> +	},
> +	[LPC32XX_WKUP_U6_IRRX] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U6_IRRX_BIT,
> +	},
> +	[LPC32XX_WKUP_U7_HCTS] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U7_HCTS_BIT,
> +	},
> +	[LPC32XX_WKUP_U7_RX] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_EXTSRC_U7_RX_BIT,
> +	},
> +
> +	[LPC32XX_WKUP_GPIO_00] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_GPIO_00_BIT,
> +	},
> +	[LPC32XX_WKUP_GPIO_01] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_GPIO_01_BIT,
> +	},
> +	[LPC32XX_WKUP_GPIO_02] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_GPIO_02_BIT,
> +	},
> +	[LPC32XX_WKUP_GPIO_03] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_GPIO_03_BIT,
> +	},
> +	[LPC32XX_WKUP_GPIO_04] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_GPIO_04_BIT,
> +	},
> +	[LPC32XX_WKUP_GPIO_05] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_GPIO_05_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_P1_ALL] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_P0P1_BIT,
> +	},
> +	[LPC32XX_WKUP_MAC_START] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_MAC_BIT,
> +	},
> +	[LPC32XX_WKUP_KEY_IRQ] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_KEY_BIT,
> +	},
> +	[LPC32XX_WKUP_USB_OTG_ATX_INT_N] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_USBATXINT_BIT,
> +	},
> +	[LPC32XX_WKUP_USB_OTG_TIMER] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_USBOTGTIMER_BIT,
> +	},
> +	[LPC32XX_WKUP_USB_I2C_INT] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_I2C_BIT,
> +	},
> +	[LPC32XX_WKUP_USB_INT] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_USB_BIT,
> +	},
> +	[LPC32XX_WKUP_USB_NEED_CLK] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_USBNEEDCLK_BIT,
> +	},
> +	[LPC32XX_WKUP_RTC_INT] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_RTC_BIT,
> +	},
> +	[LPC32XX_WKUP_MSTIMER_INT] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_MSTIMER_BIT,
> +	},
> +	[LPC32XX_WKUP_USB_AHC_NEED_CLK] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_USBAHNEEDCLK_BIT,
> +	},
> +	[LPC32XX_WKUP_TS_AUX_INT] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_TS_AUX_BIT,
> +	},
> +	[LPC32XX_WKUP_TS_P_INT] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_TS_P_BIT,
> +	},
> +	[LPC32XX_WKUP_TS_INT] = {
> +		.offs = CLKPWR_INT_ER(0),
> +		.mask = CLKPWR_INTSRC_ADC_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_0] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO0_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_1] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO1_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_2] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO2_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_3] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO3_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_4] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO4_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_5] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO5_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_6] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO6_BIT,
> +	},
> +	[LPC32XX_WKUP_P0_7] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P0IO7_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_3] = {
> +		.offs = CLKPWR_PIN_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO3_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_4] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO4_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_5] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO5_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_6] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO6_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_7] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO7_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_8] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO8_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_9] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO9_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_10] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO10_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_11] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO11_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_12] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO12_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_13] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO13_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_14] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO14_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_15] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO15_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_16] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO16_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_17] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO17_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_18] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO18_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_19] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO19_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_20] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO20_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_21] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO21_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_22] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO22_BIT,
> +	},
> +	[LPC32XX_WKUP_P1_23] = {
> +		.offs = CLKPWR_P01_ER(0),
> +		.mask = CLKPWR_GPIOSRC_P1IO23_BIT,
> +	},
> +};
> +
> +void lpc32xx_event_init(void)
> +{
> +	/* Initially disable all events, set all events to default
> +	   type and polarity per chip User guide, and clear any
> +	   pending event statuses */
> +	writel(0, CLKPWR_P01_ER(CLKPWR_IOBASE));
> +	writel(0, CLKPWR_INT_ER(CLKPWR_IOBASE));
> +	writel(0, CLKPWR_PIN_ER(CLKPWR_IOBASE));
> +
> +	/* Default activation polarities, all pin sources are low edge
> +	   triggered */
> +	writel(CLKPWR_INTSRC_TS_P_BIT | CLKPWR_INTSRC_MSTIMER_BIT |
> +		CLKPWR_INTSRC_RTC_BIT, CLKPWR_INT_AP(CLKPWR_IOBASE));
> +	writel(0, CLKPWR_PIN_AP(CLKPWR_IOBASE));
> +
> +	/* Clear latched event states */
> +	writel(readl(CLKPWR_PIN_RS(CLKPWR_IOBASE)),
> +		CLKPWR_PIN_RS(CLKPWR_IOBASE));
> +	writel(readl(CLKPWR_INT_RS(CLKPWR_IOBASE)),
> +		CLKPWR_INT_RS(CLKPWR_IOBASE));
> +}
> +
> +void lpc32xx_event_enable(enum lpc32xx_events event_id)
> +{
> +	writel(readl(CLKPWR_IOBASE + events[event_id].offs) |
> +		events[event_id].mask, CLKPWR_IOBASE + events[event_id].offs);
> +}
> +
> +void lpc32xx_event_disable(enum lpc32xx_events event_id)
> +{
> +	writel(readl(CLKPWR_IOBASE + events[event_id].offs) &
> +		~events[event_id].mask, CLKPWR_IOBASE + events[event_id].offs);
> +}
> +
> +extern int lpc32xx_event_set(enum lpc32xx_events event_id,
> +	int high_edge)
> +{
> +	u32 tmp;
> +
> +	if (event_id <= LPC32XX_WKUP_U7_RX) {
> +		tmp = readl(CLKPWR_PIN_AP(CLKPWR_IOBASE));
> +
> +		if (high_edge)
> +			tmp |= events[event_id].mask;
> +		else
> +			tmp &= ~events[event_id].mask;
> +
> +		writel(tmp, CLKPWR_PIN_AP(CLKPWR_IOBASE));
> +	} else if (event_id <= LPC32XX_WKUP_TS_INT) {
> +		tmp = readl(CLKPWR_INT_AP(CLKPWR_IOBASE));
> +
> +		if (high_edge)
> +			tmp |= events[event_id].mask;
> +		else
> +			tmp &= ~events[event_id].mask;
> +
> +		writel(tmp, CLKPWR_INT_AP(CLKPWR_IOBASE));
> +	} else
> +		return -EINVAL;
> +
> +	return 0;
> +}
> +
> +int lpc32xx_event_enabled(enum lpc32xx_events event_id)
> +{
> +	u32 tmp;
> +
> +	tmp = readl(CLKPWR_IOBASE + events[event_id].offs) &
> +		events[event_id].mask;
> +
> +	return (tmp != 0);
> +}
> +
> +void lpc32xx_event_clear(enum lpc32xx_events event_id)
> +{
> +	if (event_id <= LPC32XX_WKUP_U7_RX)
> +		writel(events[event_id].mask, CLKPWR_PIN_RS(CLKPWR_IOBASE));
> +	else if (event_id <= LPC32XX_WKUP_TS_INT)
> +		writel(events[event_id].mask, CLKPWR_INT_RS(CLKPWR_IOBASE));
> +}
> +
> +void lpc32xx_event_clear_all(void)
> +{
> +	/* Clear all latched event states */
> +	writel(readl(CLKPWR_PIN_RS(CLKPWR_IOBASE)),
> +		CLKPWR_PIN_RS(CLKPWR_IOBASE));
> +	writel(readl(CLKPWR_INT_RS(CLKPWR_IOBASE)),
> +		CLKPWR_INT_RS(CLKPWR_IOBASE));
> +}
> +
> diff --git a/arch/arm/mach-lpc32xx/suspend.S b/arch/arm/mach-lpc32xx/suspend.S
> new file mode 100644
> index 0000000..075708b
> --- /dev/null
> +++ b/arch/arm/mach-lpc32xx/suspend.S
> @@ -0,0 +1,155 @@
> +/*
> + * arch/arm/mach-lpc32xx/suspend.S
> + *
> + * Author: Kevin Wells <kevin.wells@nxp.com>
> + * Based in part on PNX4008 power management code
> + *
> + * Copyright (C) 2010 NXP Semiconductors
> + *
> + * 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/linkage.h>
> +#include <asm/assembler.h>
> +#include <mach/platform.h>
> +#include <mach/hardware.h>
> +
> +/* Using named register defines makes the code easier to follow */
> +#define WORK1_REG		r0
> +#define WORK2_REG		r1
> +#define SAVED_HCLK_DIV_REG	r2
> +#define SAVED_HCLK_PLL_REG	r3
> +#define SAVED_DRAM_CLKCTRL_REG	r4
> +#define SAVED_PWR_CTRL_REG	r5
> +#define CLKPWRBASE_REG		r6
> +#define EMCBASE_REG		r7
> +
> +#define EMC_STATUS_OFFS		0x04
> +#define EMC_STATUS_BUSY		0x1
> +#define EMC_STATUS_SELF_RFSH	0x4
> +
> +	.text
> +
> +ENTRY(lpc32xx_sys_suspend)
> +	@ Save a copy of the used registers in IRAM, r0 is corrupted
> +	adr	r0, tmp_stack_end
> +	stmfd	r0!, {r1 - r7, sp, lr}
> +
> +	@ Load a few common register addresses
> +	adr	WORK1_REG, reg_bases
> +	ldr	CLKPWRBASE_REG, [WORK1_REG, #0]
> +	ldr	EMCBASE_REG, [WORK1_REG, #4]
> +
> +	ldr	SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +	orr	WORK1_REG, SAVED_PWR_CTRL_REG, #CLKPWR_SDRAM_SELF_RFSH
> +
> +	@ Wait for SDRAM busy status to go busy and then idle
> +	@ This guarantees a small windows where DRAM isn't busy
> +1:
> +	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
> +	and	WORK2_REG, WORK2_REG, #EMC_STATUS_BUSY
> +	cmp	WORK2_REG, #EMC_STATUS_BUSY
> +	bne	1b @ Branch while idle
> +2:
> +	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
> +	and	WORK2_REG, WORK2_REG, #EMC_STATUS_BUSY
> +	cmp	WORK2_REG, #EMC_STATUS_BUSY
> +	beq	2b @ Branch until idle
> +
> +	@ Setup self-refresh with support for manual exit of
> +	@ self-refresh mode
> +	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +	orr	WORK2_REG, WORK1_REG, #CLKPWR_UPD_SDRAM_SELF_RFSH
> +	str	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +
> +	@ Wait for self-refresh acknowledge, clocks to the DRAM device
> +	@ will automatically stop on start of self-refresh
> +3:
> +	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
> +	and	WORK2_REG, WORK2_REG, #EMC_STATUS_SELF_RFSH
> +	cmp	WORK2_REG, #EMC_STATUS_SELF_RFSH
> +	bne	3b @ Branch until self-refresh mode starts
> +
> +	@ Enter direct-run mode from run mode
> +	bic	WORK1_REG, WORK1_REG, #CLKPWR_SELECT_RUN_MODE
> +	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +
> +	@ Safe disable of DRAM clock in EMC block, prevents DDR sync
> +	@ issues on restart
> +	ldr	SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG, #CLKPWR_HCLK_DIV(0)]
> +	and	WORK2_REG, SAVED_HCLK_DIV_REG, #0xFFFFFE7F
> +	str	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_HCLK_DIV(0)]
> +
> +	@ Save HCLK PLL state and disable HCLK PLL
> +	ldr	SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
> +	bic	WORK2_REG, SAVED_HCLK_PLL_REG, #CLKPWR_HCLKPLL_POWER_UP
> +	str	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
> +
> +	@ Enter stop mode until an enabled event occurs
> +	orr	WORK1_REG, WORK1_REG, #CLKPWR_STOP_MODE_CTRL
> +	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +	nop
> +	nop
> +	nop
> +	nop
> +	nop
> +	nop
> +	nop
> +	nop
> +	nop
> +
> +	@ Clear stop status
> +	bic	WORK1_REG, WORK1_REG, #CLKPWR_STOP_MODE_CTRL
> +
> +	@ Restore original HCLK PLL value and wait for PLL lock
> +	str	SAVED_HCLK_PLL_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
> +4:
> +	ldr	WORK2_REG, [CLKPWRBASE_REG, #CLKPWR_HCLKPLL_CTRL(0)]
> +	and	WORK2_REG, WORK2_REG, #CLKPWR_HCLKPLL_PLL_STS
> +	bne	4b
> +
> +	@ Re-enter run mode with self-refresh flag cleared, but no DRAM
> +	@ update yet. DRAM is still in self-refresh
> +	str	SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +
> +	@ Restore original DRAM clock mode to restore DRAM clocks
> +	str	SAVED_HCLK_DIV_REG, [CLKPWRBASE_REG, #CLKPWR_HCLK_DIV(0)]
> +
> +	@ Clear self-refresh mode
> +	orr	WORK1_REG, SAVED_PWR_CTRL_REG, #CLKPWR_UPD_SDRAM_SELF_RFSH
> +	str	WORK1_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +	str	SAVED_PWR_CTRL_REG, [CLKPWRBASE_REG, #CLKPWR_PWR_CTRL(0)]
> +
> +	@ Wait for EMC to clear self-refresh mode
> +5:
> +	ldr	WORK2_REG, [EMCBASE_REG, #EMC_STATUS_OFFS]
> +	and	WORK2_REG, WORK2_REG, #EMC_STATUS_SELF_RFSH
> +	bne	5b @ Branch until self-refresh has exited
> +
> +	@ restore regs and return
> +	adr	r0, tmp_stack
> +	ldmfd	r0!, {r1 - r7, sp, pc}
> +
> +reg_bases:
> +	.long	IO_ADDRESS(CLK_PM_BASE)
> +	.long	IO_ADDRESS(EMC_BASE)
> +
> +tmp_stack:
> +	.long	0, 0, 0, 0, 0, 0, 0, 0, 0
> +tmp_stack_end:
> +
> +ENTRY(lpc32xx_sys_suspend_sz)
> +	.word	. - lpc32xx_sys_suspend
> +
> -- 
> 1.6.6
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
> 

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 10/13] ARM: LPC32XX: Phytec PHY3250 platform support file
  2010-01-28  1:43 ` [PATCH 10/13] ARM: LPC32XX: Phytec PHY3250 platform support file wellsk40 at gmail.com
@ 2010-02-03 16:46   ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 16:46 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

> +MACHINE_START(PHY3250, "Phytec 3250 board with the LPC3250 Microcontroller")
> +	/* Maintainer: Kevin Wells, NXP Semiconductors */
> +	.phys_io	= UART5_BASE,
> +	.io_pg_offst	= ((io_p2v(UART5_BASE))>>18) & 0xfffc,
> +	.boot_params	= 0x80000100,
Assuming a recent boot loader you don't need boot_params.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions
  2010-01-28  1:43 ` [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions wellsk40 at gmail.com
@ 2010-02-03 16:50   ` Uwe Kleine-König
  2010-02-03 18:57     ` Kevin Wells
  0 siblings, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 16:50 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Kevin,

> +	.macro	disable_fiq
> +	.endm
> +
> +	.macro  get_irqnr_preamble, base, tmp
> +	.endm
> +
> +	.macro  arch_ret_to_user, tmp1, tmp2
> +	.endm
> +
> +/*
> + * Return IRQ number in irqnr. Also return processor Z flag status in CPSR
> + * as set if an interrupt is pending.
> + */
> +	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
> +	/* Get MIC status first */
> +	ldr	\base, =IO_ADDRESS(MIC_BASE)
> +	ldr	\irqstat, [\base, #INTC_STAT]
> +	and	\irqstat, \irqstat, #0xFFFFFFFC
> +	mov	\tmp, #0
> +
> +	/* Drop through to SIC1 or SIC2 if MIC is not pending */
> +	cmp	\irqstat, #0
> +	bne	1000f
> +
> +	/* SIC1 interrupts start at offset 32 */
> +	ldr	\base, =IO_ADDRESS(SIC1_BASE)
> +	ldr	\irqstat, [\base, #INTC_STAT]
> +	mov	\tmp, #32
> +
> +	/* Drop through to SIC2 if SIC1 is not pending */
> +	cmp	\irqstat, #0
> +	bne	1000f
> +
> +	/* SIC2 interrupts start at offset 64 */
> +	ldr	\base, =IO_ADDRESS(SIC2_BASE)
> +	ldr	\irqstat, [\base, #INTC_STAT]
> +	mov	\tmp, #64
> +
> +	/* Safety check only, exit if no status on MIC, SIC1, SIC2 */
> +	cmp	\irqstat, #0
> +	beq	1001f
> +
> +1000:
> +	/* Returns an pending interrupt between 0 and 95 */
> +	clz	\irqnr, \irqstat
> +	rsb	\irqnr, \irqnr, #31
> +	add	\irqnr, \irqnr, \tmp
> +
> +1001:
> +	teq	\irqstat, #0
> +	.endm
> +
> +	.macro	irq_prio_table
> +	.endm

You could make this easier by only handling MIC(?) interrupts and make
SIC1 and SIC2 use a chained handler.  Then you can use
get_irqnr_preamble for microoptimisation.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 12/13] ARM: LPC32XX: architecture header files
  2010-01-28  1:43 ` [PATCH 12/13] ARM: LPC32XX: architecture header files wellsk40 at gmail.com
@ 2010-02-03 17:07   ` Uwe Kleine-König
  2010-02-03 19:20     ` Kevin Wells
  0 siblings, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 17:07 UTC (permalink / raw)
  To: linux-arm-kernel

Halle Kevin,

> +++ b/arch/arm/mach-lpc32xx/include/mach/hardware.h
> @@ -0,0 +1,41 @@
> +/*
> + * arch/arm/mach-lpc32xx/include/mach/hardware.h
> + *
> + * Copyright (c) 2005 MontaVista Software, Inc. <source@mvista.com>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
> + */
> +
> +#ifndef __ASM_ARCH_HARDWARE_H
> +#define __ASM_ARCH_HARDWARE_H
> +
> +#include <asm/sizes.h>
Where is that needed?
> +
> +/*
> + * Start of virtual addresses for IO devices
> + */
> +#define IO_BASE		0xF0000000
> +
> +#define io_p2v(x)	(IO_BASE | (((x) & 0xff000000) >> 4) |\
> +			 ((x) & 0x000fffff))
> +#define io_v2p(x)	((((x) & 0x0ff00000) << 4) | ((x) & 0x000fffff))
> +
> +/*
> + * This macro relies on fact that for all HW i/o addresses bits 20-23 are 0
> + */
> +#define IO_ADDRESS(x)	(((((x) & 0xff000000) >> 4) | ((x) & 0xfffff)) |\
> +			 IO_BASE)
#define IO_ADDRESS(x) io_p2v(x)

> +#define _SBF(f, v)			(((v)) << (f))
> +#define _BIT(n)				(1 << (n))
What about:

#define _SBF(f, v)	((v) << (f))
#define _BIT(n)		_SBF(n, 1)

?

> +#define VMALLOC_END	(PAGE_OFFSET + 0x10000000)
grepping shows that defining VMALLOC_END based on PAGE_OFFSET is usual,
but I wonder why you don't just

	#define VMALLOC_END 0xF0000000

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles
  2010-02-03 10:51   ` Uwe Kleine-König
  2010-02-03 11:26     ` Russell King - ARM Linux
@ 2010-02-03 18:01     ` Kevin Wells
  2010-02-03 18:56       ` Uwe Kleine-König
  1 sibling, 1 reply; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 18:01 UTC (permalink / raw)
  To: linux-arm-kernel

> lpc32xx/Kconfig
> > new file mode 100644
> > index 0000000..a277885
> > --- /dev/null
> > +++ b/arch/arm/mach-lpc32xx/Kconfig
> > @@ -0,0 +1,158 @@
> > +if ARCH_LPC32XX
> > +
> > +menu "LPC32XX chip options"
> > +
> > +config ARCH_LPC32XX_IRAM_SIZE
> > +	int
> > +	default 131072 if ARCH_LPC32XX_20
> > +	default 262144 if ARCH_LPC32XX_30 || ARCH_LPC32XX_40 ||
> ARCH_LPC32XX_50
> > +
> > +choice
> > +    prompt "Select 32x0 device variation"
> > +    default ARCH_LPC32XX_50
> > +
> > +	config ARCH_LPC32XX_20
> > +		bool "LPC3220"
> > +		help
> > +		 128K IRAM, no ethernet or LCD
> > +
> > +	config ARCH_LPC32XX_30
> > +		bool "LPC3230"
> > +		help
> > +		 256K IRAM and LCD, no ethernet
> > +
> > +	config ARCH_LPC32XX_40
> > +		bool "LPC3240"
> > +		help
> > +		 256K IRAM and ethernet, no LCD
> > +
> > +	config ARCH_LPC32XX_50
> > +		bool "LPC3250"
> > +		help
> > +		 256K IRAM and ethernet and LCD
> > +
> > +endchoice
> It's sad this is a choice and only a single "device variation" is
> selectable.  Maybe you can autodetect these?

Hi Uwe, thank your for your comments and thorough review.
Most systems can simply disable support for unused options by disabling
the driver. I can reduce this.

> 
> > +menu "Serial port configuration"
> > +
> > +menu "Individual UART enable selections"
> > +
> > +config ARCH_LPC32XX_HSUART1_ENABLE
> > +	bool "Enable high speed UART1"
> > +	help
> > +	 Also enable LPC32xx high speed serial support in drivers/serial
> > +
> > +config ARCH_LPC32XX_HSUART2_ENABLE
> > +	bool "Enable high speed UART2"
> > +	help
> > +	 Also enable LPC32xx high speed serial support in drivers/serial
> > +
> > +config ARCH_LPC32XX_UART3_ENABLE
> > +	bool "Enable standard UART3"
> > +	help
> > +	 Also enable 8250 serial support in drivers/serial
> > +
> > +config ARCH_LPC32XX_UART4_ENABLE
> > +	bool "Enable standard UART4"
> > +	help
> > +	 Also enable 8250 serial support in drivers/serial
> > +
> > +config ARCH_LPC32XX_UART5_ENABLE
> > +	bool "Enable standard UART5"
> > +	default y
> > +	help
> > +	 Also enable 8250 serial support in drivers/serial
> > +
> > +config ARCH_LPC32XX_UART6_ENABLE
> > +	bool "Enable standard UART6"
> > +	help
> > +	 Also enable 8250 serial support in drivers/serial
> > +
> > +config ARCH_LPC32XX_HSUART7_ENABLE
> > +	bool "Enable high speed UART7"
> > +	help
> > +	 Also enable LPC32xx high speed serial support in drivers/serial
> > +
> > +endmenu
> IMHO "enable" is a bit misleading here.  Depending on the selection here
> the devices are defined or not.

I'm not sure what what you mean here. I'll look at the wording and try to
fix.

> > +choice
> > +	prompt "Kernel uncompress status output UART selection"
> > +	default ARCH_LPC32XX_UNCOMP_U5
> > +
> > +	config ARCH_LPC32XX_UNCOMP_HSU1
> > +		bool "High speed UART 1"
> > +		help
> > +		 Kernel uncompress output is on high speed UART 1
> > +
> > +	config ARCH_LPC32XX_UNCOMP_HSU2
> > +		bool "High speed UART 2"
> > +		help
> > +		 Kernel uncompress output is on high speed UART 2
> > +
> > +	config ARCH_LPC32XX_UNCOMP_U3
> > +		bool "Standard UART 3"
> > +		help
> > +		 Kernel uncompress output is on standard UART 3
> > +
> > +	config ARCH_LPC32XX_UNCOMP_U4
> > +		bool "Standard UART 4"
> > +		help
> > +		 Kernel uncompress output is on standard UART 4
> > +
> > +	config ARCH_LPC32XX_UNCOMP_U5
> > +		bool "Standard UART 5"
> > +		help
> > +		 Kernel uncompress output is on standard UART 5
> > +
> > +	config ARCH_LPC32XX_UNCOMP_U6
> > +		bool "Standard UART 6"
> > +		help
> > +		 Kernel uncompress output is on standard UART 6
> > +
> > +	config ARCH_LPC32XX_UNCOMP_HSU7
> > +		bool "High speed UART 7"
> > +		help
> > +		 Kernel uncompress output is on high speed UART 7
> > +
> > +endchoice
> Can you autodetect this?

This is the uncompress output prior to kernel startup. There are
7 UARTs on the device and different board manufacturers don't
always use the same UART. For the currently supported boards
(PHY3250, EA3250, and FDI3250 mach ids), this was the only way
I could get the UART selection into the config without changing
code. I suppose it's possible to put specific board checks in
the uncompress macros, but it would require changes to that file
for new boards. This seemed the best way to go.

> 
> > +choice
> > +	prompt "debug output (printascii) UART selection"
> > +	default ARCH_LPC32XX_DEBUGO_U5
> > +
> > +	config ARCH_LPC32XX_DEBUGO_U3
> > +		bool "Standard UART 3"
> > +		help
> > +		 printascii messages are output on standard UART 3
> > +
> > +	config ARCH_LPC32XX_DEBUGO_U4
> > +		bool "Standard UART 4"
> > +		help
> > +		 printascii messages are output on standard UART 4
> > +
> > +	config ARCH_LPC32XX_DEBUGO_U5
> > +		bool "Standard UART 5"
> > +		help
> > +		 printascii messages are output on standard UART 5
> > +
> > +	config ARCH_LPC32XX_DEBUGO_U6
> > +		bool "Standard UART 6"
> > +		help
> > +		 printascii messages are output on standard UART 6
> > +
> > +endchoice
> IMHO this isn't something that needs configuration via Kconfig.  It's
> enough to have this via #defines in debug-macro.S.

See comment about uncompress output above. Some developers prefer
printascii messages on a specific UART output (seperated from main
serial or console output). This handles that.

> 
> > +endmenu
> > +
> > +endmenu
> > +
> > +source "arch/arm/mach-lpc32xx/Kconfig.plat"
> > +
> > +endif
> > +
> > diff --git a/arch/arm/mach-lpc32xx/Kconfig.plat b/arch/arm/mach-
> lpc32xx/Kconfig.plat
> > new file mode 100644
> > index 0000000..a67d1ad
> > --- /dev/null
> > +++ b/arch/arm/mach-lpc32xx/Kconfig.plat
> > @@ -0,0 +1,98 @@
> > +menu "LPC32XX platform choices"
> > +
> > +choice
> > +    prompt "Choose your board"
> > +    default MACH_PHY3250
> > +    help
> > +        This menu selects the LPC3250 board to support for this build
> > +
> > +    config MACH_PHY3250
> > +        bool "Phytec 3250 development board"
> > +	help
> > +	    Support for the Phytec 3250 development board
> > +
> > +endchoice
> Again, support more than one mach per kernel?

There are a minimum of 3 supported machs for this arch. To keep thing
simple, I wanted to release initially with just 1 mach. What is a good
approach for this? Should I break up the arch and plat areas into different
subdirectories under arch/arm similar to other platforms and remove
Kconfig.plat?

> 
> > +choice
> > +	prompt "Phytec LCD module revisions"
> > +	depends on MACH_PHY3250
> > +	default PHY3250_QVGA_PANEL_1307_1
> > +	help
> > +	  Select one of the supported LCD panel revisions
> > +
> > +config PHY3250_QVGA_PANEL_1307_0
> > +	bool "1307.0 QVGA panel (portrait mode RGB565)"
> > +	help
> > +	  Use LCD module version 1307.0
> > +
> > +config PHY3250_QVGA_PANEL_1307_1
> > +	bool "1307.1 QVGA panel (portrait mode RGB565)"
> > +	help
> > +	  Use LCD module version 1307.1
> > +
> > +endchoice
> autodetect?  kernel-parameter?
> 
> > +choice
> > +	prompt "Phytec CPU module revisions"
> > +	depends on MACH_PHY3250
> > +	default PHY3250_CPU_MODULE_1304_1
> > +	help
> > +	  Select one of the supported CPU module revisions
> > +
> > +config PHY3250_CPU_MODULE_1304_0
> > +	bool "1304.0 CPU module"
> > +	help
> > +	  Use CPU module version 1304.0
> > +
> > +config PHY3250_CPU_MODULE_1304_1
> > +	bool "1304.1 CPU module"
> > +	help
> > +	  Use CPU module version 1304.1
> > +
> > +endchoice
> ditto, autodetect?  kernel-parameter?
> 
> > +choice
> > +	prompt "Phytec Carrier board revisions"
> > +	depends on MACH_PHY3250
> > +	default PHY3250_CARRIER_1305_3
> > +	help
> > +	  Select one of the supported carrier board revisions
> > +
> > +config PHY3250_CARRIER_1305_01
> > +	bool "1305.0 or 1305.1 carrier board"
> > +	help
> > +	  Use carrier board version 1305.0 or 1305.1
> > +
> > +config PHY3250_CARRIER_1305_2
> > +	bool "1305.2 carrier board"
> > +	help
> > +	  Use carrier board version 1305.2
> > +
> > +config PHY3250_CARRIER_1305_3
> > +	bool "1305.3 carrier board"
> > +	help
> > +	  Use carrier board version 1305.3
> > +
> > +endchoice
> ditto

I can make these 3 kernel parameters, but not all of them are
autodetectable. Is this approach wrong?

> 
> > +choice
> > +	prompt "Internal IRAM use"
> > +	default MACH_LPC32XX_IRAM_RESERVED
> > +	depends on MACH_PHY3250
> > +
> > +config MACH_LPC32XX_IRAM_RESERVED
> > +	bool "IRAM is not used (reserved)"
> > +	help
> > +	  IRAM is not used for video or networking and can be used for
> > +	  other purposes or drivers
> > +
> > +config MACH_LPC32XX_IRAM_FOR_CLCD
> > +	bool "Use IRAM as a video frame buffer"
> > +	help
> > +	  IRAM will be used for the LCD frame buffer. If the required
> buffer
> > +	  size is larger than the size of IRAM, then SDRAM will be used
> > +	  instead.
> > +
> > +endchoice
> A request API would be nice here!?

I'm not sure what you mean here by a request API?. The IRAM also can
be used for network buffer storage (the option was purposely removed
for initial release). Can you please post an example?

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-02-03 10:54     ` Uwe Kleine-König
@ 2010-02-03 18:05       ` Kevin Wells
  0 siblings, 0 replies; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 18:05 UTC (permalink / raw)
  To: linux-arm-kernel

> >
> > It appears these GPIO_P* macros are only used here.  Can the macros
> > be modified to create the (void __iomem *) directly?
> If GPIO_P* macros are only used here, maybe better define them in this
> file?

Some of the macros of the GPIO and muxing block are used in board/plat
files. It seemed logical to keep all those defines in the same area
(platform.h) instead of having some there and some in gpiolib.c.

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-02-03 15:55   ` Uwe Kleine-König
@ 2010-02-03 18:43     ` Kevin Wells
  2010-02-03 20:40       ` Uwe Kleine-König
  2010-02-08  9:09       ` Uwe Kleine-König
                       ` (2 subsequent siblings)
  3 siblings, 1 reply; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 18:43 UTC (permalink / raw)
  To: linux-arm-kernel

> > +
> > +static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
> > +   unsigned pin, int input)
> > +{
> > +   if (input)
> > +           writel(1 << pin, group->gpio_grp->dir_clr);
> readl/writel are used to "perform PCI memory accesses via an ioremap
> region" and "are defined to perform little endian accesses".  I think
> most archs use __raw_readl/__raw_writel here.

There seems to be a lot of intermixing elsewhere in arch/arm where
readl()/writel() is used instead of the __raw() functions. I actually
switched to the non-__raw functions previously. Are the __raw variants
the correct way to go then?


> > +   int state;
> > +
> > +   state = readl(group->gpio_grp->inp_state);
> > +
> > +   /* P3 GPIO pin input mapping is not contiguous */
> > +   if (pin == 5)
> > +           state = (state >> 24) & 1;
> > +   else
> > +           state = (state >> (10 + pin)) & 1;
> The mapping here is different from above in __set_gpio_dir_p3??  Please
> someone kick the responsible hardware designer from me.
>

I've already kicked the ones involved. It's not wrong though, its
designed like that.

> > +                   .request                = lpc32xx_gpio_request,
> > +                   .base                   = GPIO_P0_GRP,
> > +                   .ngpio                  = GPIO_P0_MAX,
> > +                   .names                  = gpio_p0_names,
> > +                   .can_sleep              = 0,
> > +           },
> > +           .gpio_grp = &gpio_grp_regs[0],
> These absolute array references tend to become wrong.  There is no need
> to have them in an array, so why not call it gpio_grp_regs_p0 etc.?
>

Ok

> > +   case IRQ_TYPE_EDGE_FALLING:
> > +           /* Falling edge sensitive */
> > +           reg = readl(ctrl + INTC_POLAR);
> > +           reg &= ~mask;
> > +           writel(reg, (ctrl + INTC_POLAR));
> > +           reg = readl(ctrl + INTC_ACT_TYPE);
> > +           reg |= mask;
> > +           writel(reg, (ctrl + INTC_ACT_TYPE));
> > +           set_irq_handler(irq, handle_edge_irq);
> > +           break;
> did you test that you really need handle_edge_irq?  Sane irq controllers
> can (and should) use handle_level_irq for both level and edge sensitive
> irqs.  You only need handle_edge_irq if your controller doesn't remember
> edge transitions while the irq is masked.

This is supported and intended. It's important for slow moving external
GPIO events where you can't clear the active level state or pulse
duration (ie, switches).

>
> > +   case IRQ_TYPE_LEVEL_LOW:
> > +           /* Low level sensitive */
> > +           reg = readl(ctrl + INTC_POLAR);
> > +           reg &= ~mask;
> > +           writel(reg, (ctrl + INTC_POLAR));
> > +           reg = readl(ctrl + INTC_ACT_TYPE);
> > +           reg &= ~mask;
> > +           writel(reg, (ctrl + INTC_ACT_TYPE));
> > +           set_irq_handler(irq, handle_level_irq);
> > +           break;
> > +
> > +   case IRQ_TYPE_LEVEL_HIGH:
> > +           /* High level sensitive */
> > +           reg = readl(ctrl + INTC_POLAR);
> > +           reg |= mask;
> > +           writel(reg, (ctrl + INTC_POLAR));
> > +           reg = readl(ctrl + INTC_ACT_TYPE);
> > +           reg &= ~mask;
> > +           writel(reg, (ctrl + INTC_ACT_TYPE));
> > +           set_irq_handler(irq, handle_level_irq);
> > +           break;
> You could increase code sharing here with something like:
>
>       static inline __set_irq_type(unsigned int ctrl, unsigned mask,
> unsigned polar, unsigned acttype)
>       {
>
>               unsigned reg = __raw_readl(ctrl + INTC_POLAR);
>               reg &= ~mask;
>               reg |= polar;
>               __raw_writel(reg, ctrl + INTC_POLAR);
>               reg = __raw_readl(ctrl + INTC_ACT_TYPE);
>               ...
>       }
>
> and then the different cases would only be:
>
>       ...
>       case IRQ_TYPE_LEVEL_HIGH:
>               __set_irq_type(ctrl, mask, mask, 0);
>

Again, some great suggestions. I'm all for making this more readable.

> > +
> > +   /* Other modes are not supported */
> > +   default:
> > +           return -ENOTSUPP;
> > +   }
> I think you need to differenciate between unsupported an invalid types.
> I.e.:
>
>       case IRQ_TYPE_EDGE_BOTH:
>               return -ENOTSUPP;
>
>       default:
>               return -EINVAL;
>
> And I'm not sure if ENOTSUPP is the right value to return.  I grepped a
> bit around and returning -EINVAL for both unsupported and wrong values
> seems common.  (pnx4008_set_irq_type return -1 which looks worse than
> -ENOTSUPP.)
> > +
> > +   return 0;
> > +}
> > +
> > +static void __init lpc32xx_set_default_mappings(unsigned int base,
> > +   unsigned int apr, unsigned int atr, unsigned int offset)
> > +{
> > +   unsigned int i, lvl, type;
> > +
> > +   /* Set activation levels for each interrupt */
> > +   i = 0;
> > +   while (i < 32)  {
> > +           lvl = ((apr >> i) & 0x1) | (((atr >> i) & 0x1) << 1);
> > +           switch (lvl) {
> > +           case 0x0: /* Low polarity and level operation */
> > +                   type = IRQ_TYPE_LEVEL_LOW;
> > +                   break;
> > +
> > +           case 0x1: /* High polarity and level operation */
> > +                   type = IRQ_TYPE_LEVEL_HIGH;
> > +                   break;
> > +
> > +           case 0x2: /* Low polarity and edge operation */
> > +                   type = IRQ_TYPE_EDGE_FALLING;
> > +                   break;
> > +
> > +           case 0x3: /* High polarity and edge operation */
> > +           default:
> > +                   type = IRQ_TYPE_EDGE_RISING;
> > +                   break;
> > +           }
> > +
> > +           lpc32xx_set_irq_type((offset + i), type);
> you could reuse the function I suggested above, here.
>
> > +           i++;
> > +   }
> > +}
> > +
> > +static struct irq_chip lpc32xx_irq_chip = {
> > +   .ack = lpc32xx_mask_ack_irq,
> .ack = ...mask_ack... ?
>
> > +   .mask = lpc32xx_mask_irq,
> > +   .unmask = lpc32xx_unmask_irq,
> > +   .set_type = lpc32xx_set_irq_type,
> > +};
> > +
> > +void __init lpc32xx_init_irq(void)
> > +{
> > +   unsigned int i, vloc;
> > +
> > +   /* Setup MIC */
> > +   vloc = io_p2v(MIC_BASE);
> > +   writel(0, (vloc + INTC_MASK));
> > +   writel(MIC_APR_DEFAULT, (vloc + INTC_POLAR));
> > +   writel(MIC_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
> > +
> > +   /* Setup SIC1 */
> > +   vloc = io_p2v(SIC1_BASE);
> > +   writel(0, (vloc + INTC_MASK));
> > +   writel(SIC1_APR_DEFAULT, (vloc + INTC_POLAR));
> > +   writel(SIC1_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
> > +
> > +   /* Setup SIC2 */
> > +   vloc = io_p2v(SIC2_BASE);
> > +   writel(0, (vloc + INTC_MASK));
> > +   writel(SIC2_APR_DEFAULT, (vloc + INTC_POLAR));
> > +   writel(SIC2_ATR_DEFAULT, (vloc + INTC_ACT_TYPE));
> > +
> > +   /* Configure supported IRQ's */
> > +   for (i = 0; i < NR_IRQS; i++) {
> > +           set_irq_flags(i, IRQF_VALID);
> > +           set_irq_chip(i, &lpc32xx_irq_chip);
> > +   }
> > +
> > +   /* Set default mappings */
> > +   lpc32xx_set_default_mappings(io_p2v(MIC_BASE), MIC_APR_DEFAULT,
> > +           MIC_ATR_DEFAULT, 0);
> > +   lpc32xx_set_default_mappings(io_p2v(SIC1_BASE), SIC1_APR_DEFAULT,
> > +           SIC1_ATR_DEFAULT, 32);
> > +   lpc32xx_set_default_mappings(io_p2v(SIC2_BASE), SIC2_APR_DEFAULT,
> > +           SIC2_ATR_DEFAULT, 64);
> > +
> > +   /* mask all interrupts except SUBIRQA and SUBFIQ */
> Why don't you mask all irqs?
>
> > +   writel((1 << IRQ_SUB1IRQ) | (1 << IRQ_SUB2IRQ) |
> > +                   (1 << IRQ_SUB1FIQ) | (1 << IRQ_SUB2FIQ),
> > +           (io_p2v(MIC_BASE) + INTC_MASK));
> I wonder you want s/SUBIRQA/SUBIRQ/ ?

Interrupt banks SIC1 and SIC2 will work, but won't signal events to the
MIC if they are masked. These are globally unmasked and never changed.
The MIC is the only device that can generate an ARM IRQ or FIQ.

>
> > +   writel(0, (io_p2v(SIC1_BASE) + INTC_MASK));
> > +   writel(0, (io_p2v(SIC2_BASE) + INTC_MASK));
> > +}
> > diff --git a/arch/arm/mach-lpc32xx/serial.c b/arch/arm/mach-
> lpc32xx/serial.c
> > new file mode 100644
> > index 0000000..1c15121
> > --- /dev/null
> > +++ b/arch/arm/mach-lpc32xx/serial.c
> > @@ -0,0 +1,200 @@
> > +/*
> > + * arch/arm/mach-lpc32xx/serial.c
> > + *
> > + * Author: Kevin Wells <kevin.wells@nxp.com>
> > + *
> > + * Copyright (C) 2010 NXP Semiconductors
> > + *
> > + * 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/kernel.h>
> > +#include <linux/types.h>
> > +#include <linux/serial.h>
> > +#include <linux/serial_core.h>
> > +#include <linux/serial_reg.h>
> > +#include <linux/serial_8250.h>
> > +#include <linux/clk.h>
> > +#include <linux/io.h>
> > +
> > +#include <mach/hardware.h>
> > +#include <mach/platform.h>
> > +#include <mach/io.h>
> > +#include "common.h"
> > +
> > +/* Standard 8250/16550 compatible serial ports */
> > +static struct plat_serial8250_port serial_std_platform_data[] = {
> > +#ifdef CONFIG_ARCH_LPC32XX_UART5_ENABLE
> > +   {
> > +           .membase        = (void *) io_p2v(UART5_BASE),
> > +           .mapbase        = UART5_BASE,
> > +           .irq            = IRQ_UART_IIR5,
> I'd prefix all lpc32xx specific constants with LPC32XX_.
>
> > +           .uartclk        = MAIN_OSC_FREQ,
> MAIN_OSC_FREQ isn't defined yet.
>
> > +           .regshift       = 2,
> > +           .iotype         = UPIO_MEM32,
> > +           .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> > +                                   UPF_SKIP_TEST,
> > +   },
> > +#endif
> > +#ifdef CONFIG_ARCH_LPC32XX_UART3_ENABLE
> > +   {
> > +           .membase        = (void *) io_p2v(UART3_BASE),
> > +           .mapbase        = UART3_BASE,
> > +           .irq            = IRQ_UART_IIR3,
> > +           .uartclk        = MAIN_OSC_FREQ,
> > +           .regshift       = 2,
> > +           .iotype         = UPIO_MEM32,
> > +           .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> > +                                   UPF_SKIP_TEST,
> > +   },
> > +#endif
> > +#ifdef CONFIG_ARCH_LPC32XX_UART4_ENABLE
> > +   {
> > +           .membase        = (void *) io_p2v(UART4_BASE),
> > +           .mapbase        = UART4_BASE,
> > +           .irq            = IRQ_UART_IIR4,
> > +           .uartclk        = MAIN_OSC_FREQ,
> > +           .regshift       = 2,
> > +           .iotype         = UPIO_MEM32,
> > +           .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> > +                                   UPF_SKIP_TEST,
> > +   },
> > +#endif
> > +#ifdef CONFIG_ARCH_LPC32XX_UART6_ENABLE
> > +   {
> > +           .membase        = (void *) io_p2v(UART6_BASE),
> > +           .mapbase        = UART6_BASE,
> > +           .irq            = IRQ_UART_IIR6,
> > +           .uartclk        = MAIN_OSC_FREQ,
> > +           .regshift       = 2,
> > +           .iotype         = UPIO_MEM32,
> > +           .flags          = UPF_BOOT_AUTOCONF | UPF_BUGGY_UART |
> > +                                   UPF_SKIP_TEST,
> > +   },
> > +#endif
> > +   { },
> > +};
> > +
> > +struct uartinit {
> > +   char *uart_ck_name;
> > +   u32 ck_mode_mask;
> > +   u32 pdiv_clk_reg;
> > +};
> > +
> > +static struct uartinit uartinit_data[] __initdata = {
> > +#ifdef CONFIG_ARCH_LPC32XX_UART5_ENABLE
> > +   {
> > +           .uart_ck_name = "uart5_ck",
> > +           .ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 5),
> > +           .pdiv_clk_reg = CLKPWR_UART5_CLK_CTRL(CLKPWR_IOBASE),
> > +   },
> > +#endif
> > +#ifdef CONFIG_ARCH_LPC32XX_UART3_ENABLE
> > +   {
> > +           .uart_ck_name = "uart3_ck",
> > +           .ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 3),
> > +           .pdiv_clk_reg = CLKPWR_UART3_CLK_CTRL(CLKPWR_IOBASE),
> > +   },
> > +#endif
> > +#ifdef CONFIG_ARCH_LPC32XX_UART4_ENABLE
> > +   {
> > +           .uart_ck_name = "uart4_ck",
> > +           .ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 4),
> > +           .pdiv_clk_reg = CLKPWR_UART4_CLK_CTRL(CLKPWR_IOBASE),
> > +   },
> > +#endif
> > +#ifdef CONFIG_ARCH_LPC32XX_UART6_ENABLE
> > +   {
> > +           .uart_ck_name = "uart6_ck",
> > +           .ck_mode_mask = UART_CLKMODE_LOAD(UART_CLKMODE_ON, 6),
> > +           .pdiv_clk_reg = CLKPWR_UART6_CLK_CTRL(CLKPWR_IOBASE),
> > +   },
> > +#endif
> does the order matter here?  If not, why use 5,3,4,6?
>
> > +};
> > +
> > +static struct platform_device serial_std_platform_device = {
> > +   .name                   = "serial8250",
> > +   .id                     = 0,
> > +   .dev                    = {
> > +           .platform_data  = serial_std_platform_data,
> > +   },
> > +};
> > +
> > +static struct platform_device *lpc32xx_serial_devs[] __initdata = {
> > +   &serial_std_platform_device,
> > +};
> > +
> > +void __init lpc32xx_serial_init(void)
> > +{
> > +   u32 tmp, clkmodes = 0;
> > +   struct clk *clk;
> > +   void *puart;
> > +   int i;
> > +
> > +   /* UART clocks are off, let clock driver manage them */
> > +   __raw_writel(0, CLKPWR_UART_CLK_CTRL(CLKPWR_IOBASE));
> > +
> > +   for (i = 0; i < ARRAY_SIZE(uartinit_data); i++) {
> > +           clk = clk_get(NULL, uartinit_data[i].uart_ck_name);
> > +           if (IS_ERR(clk)) {
> > +#ifdef CONFIG_DEBUG_LL
> > +                   /* A clock get failure can mean the console might
> > +                      not work. It's possible this might not even
> > +                      work. */
> > +                   printascii("Serial port clock get failure!\n");
> > +#endif
> > +           } else {
> > +                   clk_enable(clk);
> > +                   serial_std_platform_data[i].uartclk =
> > +                           clk_get_rate(clk);
> IIRC clk_get_rate is only valid for enabled clocks, so you might want to
> check if clk_enable returned 0.
>
> > +           }
> > +
> > +           /* Setup UART clock modes for all UARTs, disable autoclock */
> > +           clkmodes |= uartinit_data[i].ck_mode_mask;
> Do you really want to do this if clk_enable or clk_get failed?
> > +
> > +           /* pre-UART clock divider set to 1 */
> > +           writel(0x0101, uartinit_data[i].pdiv_clk_reg);
> ditto.
>
> > +   }
> > +
> > +   /* This needs to be done after all UART clocks are setup */
> > +   writel(clkmodes, UARTCTL_CLKMODE(io_p2v(UART_CTRL_BASE)));
> > +   for (i = 0; i < ARRAY_SIZE(uartinit_data) - 1; i++) {
> > +           /* Force a flush of the RX FIFOs to work around a HW bug */
> > +           puart = serial_std_platform_data[i].membase;
> > +           writel(0xC1, UART_IIR_FCR(puart));
> > +           writel(0x00, UART_DLL_FIFO(puart));
> > +           clkmodes = 64;
> > +           while (clkmodes--)
> > +                   tmp = readl(UART_DLL_FIFO(puart));
> The variable clkmodes seems to be misused here.  IMHO it should be named
> something like j.  and can i have a
>
>       #define LPC32XX_UART_FIFO_SIZE  64
>
> inclusive usage here?
>
> > +           writel(0, UART_IIR_FCR(puart));
> > +   }
> > +
> > +   /* IrDA pulsing support on UART6. This only enables the IrDA mux */
> > +   tmp = readl(UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> > +#ifdef CONFIG_ARCH_LPC32XX_UART6_IRDAMODE
> > +   tmp &= ~UART_UART6_IRDAMOD_BYPASS;
> > +#else
> > +   tmp |= UART_UART6_IRDAMOD_BYPASS;
> > +#endif
> > +   writel(tmp, UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> > +
> > +   /* Disable UART5->USB transparent mode or USB won't work */
> > +   tmp = readl(UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> > +   tmp &= ~UART_U5_ROUTE_TO_USB;
> > +   writel(tmp, UARTCTL_CTRL(io_p2v(UART_CTRL_BASE)));
> > +
> > +   platform_add_devices(lpc32xx_serial_devs,
> > +           ARRAY_SIZE(lpc32xx_serial_devs));
> > +}
> > diff --git a/arch/arm/mach-lpc32xx/timer.c b/arch/arm/mach-
> lpc32xx/timer.c
> > new file mode 100644
> > index 0000000..9c06346
> > --- /dev/null
> > +++ b/arch/arm/mach-lpc32xx/timer.c
> > @@ -0,0 +1,187 @@
> > +/*
> > + * arch/arm/mach-lpc32xx/timer.c
> > + *
> > + * Author: Kevin Wells <kevin.wells@nxp.com>
> > + *
> > + * Copyright (C) 2009 - 2010 NXP Semiconductors
> > + * Copyright (C) 2009 Fontys University of Applied Sciences, Eindhoven
> > + *                    Ed Schouten <e.schouten@fontys.nl>
> > + *                    Laurens Timmermans <l.timmermans@fontys.nl>
> > + *
> > + * 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/interrupt.h>
> > +#include <linux/irq.h>
> > +#include <linux/time.h>
> > +#include <linux/err.h>
> > +#include <linux/clockchips.h>
> > +
> > +#include <asm/mach/time.h>
> > +
> > +#include <mach/hardware.h>
> > +#include <mach/platform.h>
> > +#include "common.h"
> > +
> > +#define TIMER0_IOBASE io_p2v(TIMER0_BASE)
> > +#define TIMER1_IOBASE io_p2v(TIMER1_BASE)
> I like the register constants already providing a virtual address.
> Something like:
>
>       #ifndef __REG
>       #ifndef __ASSEMBLY__
>       #define __REG(x) ((void __iomem __force *)io_p2v(x))
>       #else
>       #define __REG(x) io_p2v(x)
>       #endif
>
>       #define LPC32XX_TIMER0_IOBASE __REG(0x4004c000)
>
> And for the few places where a physical address is needed you can define
> __REG(x) to be just x.
>
>
> > +static cycle_t lpc32xx_clksrc_read(struct clocksource *cs)
> > +{
> > +   return (cycle_t)readl(TIMER_TC(TIMER1_IOBASE));
> > +}
> > +
> > +static struct clocksource lpc32xx_clksrc = {
> > +   .name   = "lpc32xx_clksrc",
> > +   .shift  = 24,
> > +   .rating = 300,
> > +   .read   = lpc32xx_clksrc_read,
> > +   .mask   = CLOCKSOURCE_MASK(32),
> > +   .flags  = CLOCK_SOURCE_IS_CONTINUOUS,
> > +};
> > +
> > +static int lpc32xx_clkevt_next_event(unsigned long delta,
> > +    struct clock_event_device *dev)
> > +{
> > +   unsigned long flags;
> > +
> > +   if (delta < 1)
> > +           return -ETIME;
> As you set min_delta_ns below you don't need to test it here.
>
> > +   local_irq_save(flags);
> No.  irqs are already disabled by the clock framework.
>
> > +   writel(TIMER_CNTR_TCR_RESET, TIMER_TCR(TIMER0_IOBASE));
> > +   writel(delta, TIMER_PR(TIMER0_IOBASE));
> > +   writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER0_IOBASE));
> > +
> > +   local_irq_restore(flags);
> > +
> > +   return 0;
> > +}
> > +
> > +static void lpc32xx_clkevt_mode(enum clock_event_mode mode,
> > +    struct clock_event_device *dev)
> > +{
> > +   switch (mode) {
> > +   case CLOCK_EVT_MODE_PERIODIC:
> > +           WARN_ON(1);
> > +           break;
> > +
> > +   case CLOCK_EVT_MODE_ONESHOT:
> > +   case CLOCK_EVT_MODE_SHUTDOWN:
> > +           /*
> > +            * Disable the timer. When using oneshot, we must also
> > +            * disable the timer to wait for the first call to
> > +            * set_next_event().
> > +            */
> > +           writel(0, TIMER_TCR(TIMER0_IOBASE));
> > +           break;
> > +
> > +   case CLOCK_EVT_MODE_UNUSED:
> > +   case CLOCK_EVT_MODE_RESUME:
> > +           break;
> > +   }
> > +}
> > +
> > +static struct clock_event_device lpc32xx_clkevt = {
> > +   .name           = "lpc32xx_clkevt",
> > +   .features       = CLOCK_EVT_FEAT_ONESHOT,
> > +   .shift          = 32,
> > +   .rating         = 300,
> > +   .set_next_event = lpc32xx_clkevt_next_event,
> > +   .set_mode       = lpc32xx_clkevt_mode,
> > +};
> > +
> > +static irqreturn_t lpc32xx_timer_interrupt(int irq, void *dev_id)
> > +{
> > +   struct clock_event_device *evt = &lpc32xx_clkevt;
> > +
> > +   /* Clear match */
> > +   writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE));
> > +
> > +   evt->event_handler(evt);
> > +
> > +   return IRQ_HANDLED;
> > +}
> > +
> > +static struct irqaction lpc32xx_timer_irq = {
> > +   .name           = "LPC32XX Timer Tick",
> > +   .flags          = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL,
> > +   .handler        = lpc32xx_timer_interrupt,
> > +};
> > +
> > +/*
> > + * The clock management driver isn't initialized at this point, so the
> > + * clocks need to be enabled here manually and then tagged as used in
> > + * the clock driver initialization
> > + */
> > +static void __init lpc32xx_timer_init(void)
> > +{
> > +   u32 clkrate, pllreg;
> > +
> > +   /* Enable timer clock */
> > +   writel(
> > +           (CLKPWR_TMRPWMCLK_TIMER0_EN | CLKPWR_TMRPWMCLK_TIMER1_EN),
> > +           CLKPWR_TIMERS_PWMS_CLK_CTRL_1(CLKPWR_IOBASE));
> > +
> > +   /* The clock driver isn't initialized at this point. So determine
> if
> > +      the SYSCLK is driven from the PLL397 or main oscillator and then
> use
> > +      it to compute the PLL frequency and the PCLK divider to get the
> base
> > +      timer rates. This rate is needed to compute the tick rate. */
> the common format for multiline comments is
>
>       /*
>        * ...
>        * ...
>        */
>
> > +   if (clk_is_sysclk_mainosc() != 0)
> > +           clkrate = MAIN_OSC_FREQ;
> > +   else
> > +           clkrate = 397 * CLOCK_OSC_FREQ;
> > +
> > +   /* Get ARM HCLKPLL register and convert it into a frequency*/
> missing space -----------------------------------------------------^
>
> > +   pllreg = readl(CLKPWR_HCLKPLL_CTRL(CLKPWR_IOBASE)) & 0x1FFFF;
> > +   clkrate = clk_get_pllrate_from_reg(clkrate, pllreg);
> > +
> > +   /* Get PCLK divider and divide ARM PLL clock by it to get timer
> rate */
> > +   clkrate = clkrate / clk_get_pclk_div();
> > +
> > +   /* Initial timer setup */
> > +   writel(0, TIMER_TCR(TIMER0_IOBASE));
> > +   writel(TIMER_CNTR_MTCH_BIT(0), TIMER_IR(TIMER0_IOBASE));
> > +   writel(1, TIMER_MR0(TIMER0_IOBASE));
> > +   writel(TIMER_CNTR_MCR_MTCH(0) | TIMER_CNTR_MCR_STOP(0) |
> > +       TIMER_CNTR_MCR_RESET(0), TIMER_MCR(TIMER0_IOBASE));
> > +
> > +   /* Setup tick interrupt */
> > +   setup_irq(IRQ_TIMER0, &lpc32xx_timer_irq);
> > +
> > +   /* Setup the clockevent structure. */
> > +   lpc32xx_clkevt.mult = div_sc(clkrate, NSEC_PER_SEC,
> > +           lpc32xx_clkevt.shift);
> > +   lpc32xx_clkevt.max_delta_ns = clockevent_delta2ns(-1,
> > +           &lpc32xx_clkevt);
> > +   lpc32xx_clkevt.min_delta_ns = clockevent_delta2ns(1,
> &lpc32xx_clkevt);
> For rounding reasons this might not be enough to assert delta being >= 1
> for set_next event.  IIRC you need
>
>       clockevent_delta2ns(1, &lpc32xx_clkevt) + 1
>
> > +   lpc32xx_clkevt.cpumask = cpumask_of(0);
> > +   clockevents_register_device(&lpc32xx_clkevt);
> > +
> > +   /* Use timer1 as clock source. */
> > +   writel(TIMER_CNTR_TCR_RESET, TIMER_TCR(TIMER1_IOBASE));
> > +   writel(0, TIMER_PR(TIMER1_IOBASE));
> > +   writel(0, TIMER_MCR(TIMER1_IOBASE));
> > +   writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER1_IOBASE));
> > +   lpc32xx_clksrc.mult = clocksource_hz2mult(clkrate,
> > +           lpc32xx_clksrc.shift);
> > +   clocksource_register(&lpc32xx_clksrc);
> > +}
> > +
> > +struct sys_timer lpc32xx_timer = {
> > +   .init           = &lpc32xx_timer_init,
> > +};
> Does this work without NO_HZ?  I though you need to setup a periodic
> mode with CONFIG_HZ irqs per second first?

This is handled in the clockevents handler. It will setup the driver
for the next event in the set_next_event callback. I believe the
current CONFIG_HZ rate is set to 100.

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-02-03 16:32   ` Uwe Kleine-König
@ 2010-02-03 18:51     ` Kevin Wells
  2010-02-03 20:20       ` Uwe Kleine-König
  0 siblings, 1 reply; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 18:51 UTC (permalink / raw)
  To: linux-arm-kernel

> > +/*
> > + * clk_get_rate - obtain the current clock rate (in Hz) for a clock
> source
> > + */
> > +unsigned long clk_get_rate(struct clk *clk)
> > +{
> > +	if (clk->get_rate)
> > +		return (clk->get_rate)(clk);
> > +
> > +	/* If a clocks rate is 0, it uses the parent's rate instead. */
> > +	while (clk->rate == 0)
> > +		clk = clk->parent;
> > +
> > +	return clk->rate;
> > +}
> > +EXPORT_SYMBOL(clk_get_rate);
> doesn't that need locking to protect against a race with clk_set_rate?
> Hmmm, you never need to call get_rate for a parent clock?
> 

I'll add a lock for this, its needed. The get_rate() function will just
continue to fall back to the first non-0Hz parent clock (all clocks
eventually go to a non-0Hz parent clock). Most clocks don't even have
a get_rate() function.

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

* [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles
  2010-02-03 18:01     ` Kevin Wells
@ 2010-02-03 18:56       ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 18:56 UTC (permalink / raw)
  To: linux-arm-kernel

Hey Kevin,

> > > +config ARCH_LPC32XX_HSUART7_ENABLE
> > > +	bool "Enable high speed UART7"
> > > +	help
> > > +	 Also enable LPC32xx high speed serial support in drivers/serial
> > > +
> > > +endmenu
> > IMHO "enable" is a bit misleading here.  Depending on the selection here
> > the devices are defined or not.
> 
> I'm not sure what what you mean here. I'll look at the wording and try to
> fix.
For me enable is something like

	clk_enable(...)

but not

	platform_device_register(...)

.  Does this make it clearer?

> > > +choice
> > > +	prompt "Kernel uncompress status output UART selection"
> > > +	default ARCH_LPC32XX_UNCOMP_U5
> > > +
> > > +	config ARCH_LPC32XX_UNCOMP_HSU1
> > > +		bool "High speed UART 1"
> > > +		help
> > > +		 Kernel uncompress output is on high speed UART 1
> > > +
> > > +	config ARCH_LPC32XX_UNCOMP_HSU2
> > > +		bool "High speed UART 2"
> > > +		help
> > > +		 Kernel uncompress output is on high speed UART 2
> > > +
> > > +	config ARCH_LPC32XX_UNCOMP_U3
> > > +		bool "Standard UART 3"
> > > +		help
> > > +		 Kernel uncompress output is on standard UART 3
> > > +
> > > +	config ARCH_LPC32XX_UNCOMP_U4
> > > +		bool "Standard UART 4"
> > > +		help
> > > +		 Kernel uncompress output is on standard UART 4
> > > +
> > > +	config ARCH_LPC32XX_UNCOMP_U5
> > > +		bool "Standard UART 5"
> > > +		help
> > > +		 Kernel uncompress output is on standard UART 5
> > > +
> > > +	config ARCH_LPC32XX_UNCOMP_U6
> > > +		bool "Standard UART 6"
> > > +		help
> > > +		 Kernel uncompress output is on standard UART 6
> > > +
> > > +	config ARCH_LPC32XX_UNCOMP_HSU7
> > > +		bool "High speed UART 7"
> > > +		help
> > > +		 Kernel uncompress output is on high speed UART 7
> > > +
> > > +endchoice
> > Can you autodetect this?
> 
> This is the uncompress output prior to kernel startup. There are
> 7 UARTs on the device and different board manufacturers don't
> always use the same UART. For the currently supported boards
> (PHY3250, EA3250, and FDI3250 mach ids), this was the only way
> I could get the UART selection into the config without changing
> code. I suppose it's possible to put specific board checks in
> the uncompress macros, but it would require changes to that file
> for new boards. This seemed the best way to go.
IMHO the best way is to do something like
arch/arm/plat-mxc/include/mach/uncompress.h or
arch/arm/mach-ns9xxx/include/mach/uncompress.h.  That is either (mxc)
make it depend on mach_id or (ns9xxx) check all available ports and use
the first that is enabled.
 
> > > +choice
> > > +	prompt "debug output (printascii) UART selection"
> > > +	default ARCH_LPC32XX_DEBUGO_U5
> > > +
> > > +	config ARCH_LPC32XX_DEBUGO_U3
> > > +		bool "Standard UART 3"
> > > +		help
> > > +		 printascii messages are output on standard UART 3
> > > +
> > > +	config ARCH_LPC32XX_DEBUGO_U4
> > > +		bool "Standard UART 4"
> > > +		help
> > > +		 printascii messages are output on standard UART 4
> > > +
> > > +	config ARCH_LPC32XX_DEBUGO_U5
> > > +		bool "Standard UART 5"
> > > +		help
> > > +		 printascii messages are output on standard UART 5
> > > +
> > > +	config ARCH_LPC32XX_DEBUGO_U6
> > > +		bool "Standard UART 6"
> > > +		help
> > > +		 printascii messages are output on standard UART 6
> > > +
> > > +endchoice
> > IMHO this isn't something that needs configuration via Kconfig.  It's
> > enough to have this via #defines in debug-macro.S.
> 
> See comment about uncompress output above. Some developers prefer
> printascii messages on a specific UART output (seperated from main
> serial or console output). This handles that.
No, printascii shouldn't be used but for debugging.  (So IMHO the
printascii that I saw somewhere in the series should go away.)
So if I want to debug something in early boot code then I check that
the cpp symbols are set up correctly for the board I'm currently using
and then I start adding printasciis and printhex8s.  When I found my
problem all these are removed again.  So don't expose it to your users.

> > > --- /dev/null
> > > +++ b/arch/arm/mach-lpc32xx/Kconfig.plat
> > > @@ -0,0 +1,98 @@
> > > +menu "LPC32XX platform choices"
> > > +
> > > +choice
> > > +    prompt "Choose your board"
> > > +    default MACH_PHY3250
> > > +    help
> > > +        This menu selects the LPC3250 board to support for this build
> > > +
> > > +    config MACH_PHY3250
> > > +        bool "Phytec 3250 development board"
> > > +	help
> > > +	    Support for the Phytec 3250 development board
> > > +
> > > +endchoice
> > Again, support more than one mach per kernel?
> 
> There are a minimum of 3 supported machs for this arch. To keep thing
> simple, I wanted to release initially with just 1 mach. What is a good
> approach for this? Should I break up the arch and plat areas into different
> subdirectories under arch/arm similar to other platforms and remove
> Kconfig.plat?
My comment was more about the "choice" than on the existance of only a
single board.  For now it doesn't matter, but later it would be nice if
you could have a kernel with

	[X] PHY3250
	[X] EA3250
	[X] FDI3250

and therefor you must not use

	choice
	    prompt ...

but e.g.

	comment "LPC32XX platforms:"
	config MACH_PHY3250
		bool ...
		...

	config MACH_EA3250
		bool ...
		...
	
> > > +choice
> > > +	prompt "Phytec Carrier board revisions"
> > > +	depends on MACH_PHY3250
> > > +	default PHY3250_CARRIER_1305_3
> > > +	help
> > > +	  Select one of the supported carrier board revisions
> > > +
> > > +config PHY3250_CARRIER_1305_01
> > > +	bool "1305.0 or 1305.1 carrier board"
> > > +	help
> > > +	  Use carrier board version 1305.0 or 1305.1
> > > +
> > > +config PHY3250_CARRIER_1305_2
> > > +	bool "1305.2 carrier board"
> > > +	help
> > > +	  Use carrier board version 1305.2
> > > +
> > > +config PHY3250_CARRIER_1305_3
> > > +	bool "1305.3 carrier board"
> > > +	help
> > > +	  Use carrier board version 1305.3
> > > +
> > > +endchoice
> > ditto
> 
> I can make these 3 kernel parameters, but not all of them are
> autodetectable. Is this approach wrong?
It's all about having one image for more than one machine.  Then the
autobuilder needs only build a single image for you and you don't have
to care about the exact revisions of all your hardware (assuming you can
autodetect it).
 
> > 
> > > +choice
> > > +	prompt "Internal IRAM use"
> > > +	default MACH_LPC32XX_IRAM_RESERVED
> > > +	depends on MACH_PHY3250
> > > +
> > > +config MACH_LPC32XX_IRAM_RESERVED
> > > +	bool "IRAM is not used (reserved)"
> > > +	help
> > > +	  IRAM is not used for video or networking and can be used for
> > > +	  other purposes or drivers
> > > +
> > > +config MACH_LPC32XX_IRAM_FOR_CLCD
> > > +	bool "Use IRAM as a video frame buffer"
> > > +	help
> > > +	  IRAM will be used for the LCD frame buffer. If the required
> > buffer
> > > +	  size is larger than the size of IRAM, then SDRAM will be used
> > > +	  instead.
> > > +
> > > +endchoice
> > A request API would be nice here!?
> 
> I'm not sure what you mean here by a request API?. The IRAM also can
> be used for network buffer storage (the option was purposely removed
> for initial release). Can you please post an example?
Something like request_mem_region.  This way the first driver who wants
to can use the IRAM, no need to fix it at compile time.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions
  2010-02-03 16:50   ` Uwe Kleine-König
@ 2010-02-03 18:57     ` Kevin Wells
  2010-02-03 20:49       ` Uwe Kleine-König
  0 siblings, 1 reply; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 18:57 UTC (permalink / raw)
  To: linux-arm-kernel

> 
> > +	.macro	disable_fiq
> > +	.endm
> > +
> > +	.macro  get_irqnr_preamble, base, tmp
> > +	.endm
> > +
> > +	.macro  arch_ret_to_user, tmp1, tmp2
> > +	.endm
> > +
> > +/*
> > + * Return IRQ number in irqnr. Also return processor Z flag status in
> CPSR
> > + * as set if an interrupt is pending.
> > + */
> > +	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
> > +	/* Get MIC status first */
> > +	ldr	\base, =IO_ADDRESS(MIC_BASE)
> > +	ldr	\irqstat, [\base, #INTC_STAT]
> > +	and	\irqstat, \irqstat, #0xFFFFFFFC
> > +	mov	\tmp, #0
> > +
> > +	/* Drop through to SIC1 or SIC2 if MIC is not pending */
> > +	cmp	\irqstat, #0
> > +	bne	1000f
> > +
> > +	/* SIC1 interrupts start at offset 32 */
> > +	ldr	\base, =IO_ADDRESS(SIC1_BASE)
> > +	ldr	\irqstat, [\base, #INTC_STAT]
> > +	mov	\tmp, #32
> > +
> > +	/* Drop through to SIC2 if SIC1 is not pending */
> > +	cmp	\irqstat, #0
> > +	bne	1000f
> > +
> > +	/* SIC2 interrupts start at offset 64 */
> > +	ldr	\base, =IO_ADDRESS(SIC2_BASE)
> > +	ldr	\irqstat, [\base, #INTC_STAT]
> > +	mov	\tmp, #64
> > +
> > +	/* Safety check only, exit if no status on MIC, SIC1, SIC2 */
> > +	cmp	\irqstat, #0
> > +	beq	1001f
> > +
> > +1000:
> > +	/* Returns an pending interrupt between 0 and 95 */
> > +	clz	\irqnr, \irqstat
> > +	rsb	\irqnr, \irqnr, #31
> > +	add	\irqnr, \irqnr, \tmp
> > +
> > +1001:
> > +	teq	\irqstat, #0
> > +	.endm
> > +
> > +	.macro	irq_prio_table
> > +	.endm
> 
> You could make this easier by only handling MIC(?) interrupts and make
> SIC1 and SIC2 use a chained handler.  Then you can use
> get_irqnr_preamble for microoptimisation.
> 

I'll take a look at this. I'm not entirely sure it can be made more
optimal than how it's implemented now. Even SIC1 and SIC2 interrupts
need to be routed via the MIC (The MIC interrupt will always fire
when a SIC1 or SIC2 interrupt occur.) This code is very tight right
now.

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

* [PATCH 09/13] ARM: LPC32XX: power and event management
  2010-02-03 16:44   ` Uwe Kleine-König
@ 2010-02-03 19:03     ` Kevin Wells
  0 siblings, 0 replies; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 19:03 UTC (permalink / raw)
  To: linux-arm-kernel

> > +/*
> > + * Wakeup event support
> > + */
> > +extern void lpc32xx_event_init(void);
> > +extern void lpc32xx_event_enable(enum lpc32xx_events event_id);
> > +extern void lpc32xx_event_disable(enum lpc32xx_events event_id);
> > +extern int lpc32xx_event_set(enum lpc32xx_events event_id,
> > +	int high_edge);
> > +extern int lpc32xx_event_enabled(enum lpc32xx_events event_id);
> > +extern void lpc32xx_event_clear(enum lpc32xx_events event_id);
> > +extern void lpc32xx_event_clear_all(void);
> This is usually plugged into set_irq_wake.  Isn't that generic enough
> for you?
> 

I'm not familiar with that yet. I'll look into it and rewrite the
handling if necessary. IRQ events and wakeup events are different
things on this device, although you can set an alarm wakeup event
with an alarm irq...or something like that..

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

* [PATCH 12/13] ARM: LPC32XX: architecture header files
  2010-02-03 17:07   ` Uwe Kleine-König
@ 2010-02-03 19:20     ` Kevin Wells
  2010-02-03 20:44       ` Uwe Kleine-König
  2010-02-03 21:34       ` Russell King - ARM Linux
  0 siblings, 2 replies; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 19:20 UTC (permalink / raw)
  To: linux-arm-kernel

> 
> > +#define VMALLOC_END	(PAGE_OFFSET + 0x10000000)
> grepping shows that defining VMALLOC_END based on PAGE_OFFSET is usual,
> but I wonder why you don't just

The maximum addressable DRAM sizing is 256MB when fully populated. It seemed
the right size. 0xF0000000 works too though, I have no problems changing it.

> 
> 	#define VMALLOC_END 0xF0000000
> 

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-02-03 18:51     ` Kevin Wells
@ 2010-02-03 20:20       ` Uwe Kleine-König
  2010-02-05 16:48         ` Kevin Wells
  0 siblings, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 20:20 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 03, 2010 at 07:51:36PM +0100, Kevin Wells wrote:
> > > +/*
> > > + * clk_get_rate - obtain the current clock rate (in Hz) for a clock
> > source
> > > + */
> > > +unsigned long clk_get_rate(struct clk *clk)
> > > +{
> > > +	if (clk->get_rate)
> > > +		return (clk->get_rate)(clk);
> > > +
> > > +	/* If a clocks rate is 0, it uses the parent's rate instead. */
> > > +	while (clk->rate == 0)
> > > +		clk = clk->parent;
> > > +
> > > +	return clk->rate;
> > > +}
> > > +EXPORT_SYMBOL(clk_get_rate);
> > doesn't that need locking to protect against a race with clk_set_rate?
> > Hmmm, you never need to call get_rate for a parent clock?
> > 
> 
> I'll add a lock for this, its needed. The get_rate() function will just
> continue to fall back to the first non-0Hz parent clock (all clocks
> eventually go to a non-0Hz parent clock). Most clocks don't even have
> a get_rate() function.
still, if a clock with a get_rate function has a child, clk_get_rate for
the child might return a wrong result.

Actually you need something like:

	while (!(rate = clk->rate) && !(clk->get_rate && (rate = clk->get_rate(clk)))) {
		clk = clk->parent;
		if (!clk)
			break;
	}	
	return rate;

Maybe with a nicer coding style by not using an assignment in the while
condition.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-02-03 18:43     ` Kevin Wells
@ 2010-02-03 20:40       ` Uwe Kleine-König
  2010-02-03 21:58         ` Kevin Wells
  0 siblings, 1 reply; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 20:40 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Wed, Feb 03, 2010 at 07:43:59PM +0100, Kevin Wells wrote:
> > > +
> > > +static void __set_gpio_dir_p012(struct lpc32xx_gpio_chip *group,
> > > +   unsigned pin, int input)
> > > +{
> > > +   if (input)
> > > +           writel(1 << pin, group->gpio_grp->dir_clr);
> > readl/writel are used to "perform PCI memory accesses via an ioremap
> > region" and "are defined to perform little endian accesses".  I think
> > most archs use __raw_readl/__raw_writel here.
> 
> There seems to be a lot of intermixing elsewhere in arch/arm where
> readl()/writel() is used instead of the __raw() functions. I actually
> switched to the non-__raw functions previously. Are the __raw variants
> the correct way to go then?
I think __raw_... is the right variant.  But I'm sure there are people
thinking different.
 
> > > +   case IRQ_TYPE_EDGE_FALLING:
> > > +           /* Falling edge sensitive */
> > > +           reg = readl(ctrl + INTC_POLAR);
> > > +           reg &= ~mask;
> > > +           writel(reg, (ctrl + INTC_POLAR));
> > > +           reg = readl(ctrl + INTC_ACT_TYPE);
> > > +           reg |= mask;
> > > +           writel(reg, (ctrl + INTC_ACT_TYPE));
> > > +           set_irq_handler(irq, handle_edge_irq);
> > > +           break;
> > did you test that you really need handle_edge_irq?  Sane irq controllers
> > can (and should) use handle_level_irq for both level and edge sensitive
> > irqs.  You only need handle_edge_irq if your controller doesn't remember
> > edge transitions while the irq is masked.
> 
> This is supported and intended. It's important for slow moving external
> GPIO events where you can't clear the active level state or pulse
> duration (ie, switches).
I didn't understand your answer here.  What is supported and intended?
This has something to do with your controller, not with slow external
things.
 
> > > +   /* mask all interrupts except SUBIRQA and SUBFIQ */
> > Why don't you mask all irqs?
> >
> > > +   writel((1 << IRQ_SUB1IRQ) | (1 << IRQ_SUB2IRQ) |
> > > +                   (1 << IRQ_SUB1FIQ) | (1 << IRQ_SUB2FIQ),
> > > +           (io_p2v(MIC_BASE) + INTC_MASK));
> > I wonder you want s/SUBIRQA/SUBIRQ/ ?
> 
> Interrupt banks SIC1 and SIC2 will work, but won't signal events to the
> MIC if they are masked. These are globally unmasked and never changed.
> The MIC is the only device that can generate an ARM IRQ or FIQ.
See my other mail about a chained handler.
 
> > > +   lpc32xx_clkevt.cpumask = cpumask_of(0);
> > > +   clockevents_register_device(&lpc32xx_clkevt);
> > > +
> > > +   /* Use timer1 as clock source. */
> > > +   writel(TIMER_CNTR_TCR_RESET, TIMER_TCR(TIMER1_IOBASE));
> > > +   writel(0, TIMER_PR(TIMER1_IOBASE));
> > > +   writel(0, TIMER_MCR(TIMER1_IOBASE));
> > > +   writel(TIMER_CNTR_TCR_EN, TIMER_TCR(TIMER1_IOBASE));
> > > +   lpc32xx_clksrc.mult = clocksource_hz2mult(clkrate,
> > > +           lpc32xx_clksrc.shift);
> > > +   clocksource_register(&lpc32xx_clksrc);
> > > +}
> > > +
> > > +struct sys_timer lpc32xx_timer = {
> > > +   .init           = &lpc32xx_timer_init,
> > > +};
> > Does this work without NO_HZ?  I though you need to setup a periodic
> > mode with CONFIG_HZ irqs per second first?
> 
> This is handled in the clockevents handler. It will setup the driver
> for the next event in the set_next_event callback. I believe the
> current CONFIG_HZ rate is set to 100.
Hmmm:

	~/gsrc/linux-2.6/arch/arm/mach-lpc32xx$ grep HZ *
	~/gsrc/linux-2.6/arch/arm/mach-lpc32xx$ 

Best regards
Uwe
-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 12/13] ARM: LPC32XX: architecture header files
  2010-02-03 19:20     ` Kevin Wells
@ 2010-02-03 20:44       ` Uwe Kleine-König
  2010-02-03 21:34       ` Russell King - ARM Linux
  1 sibling, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 20:44 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 03, 2010 at 08:20:01PM +0100, Kevin Wells wrote:
> > 
> > > +#define VMALLOC_END	(PAGE_OFFSET + 0x10000000)
> > grepping shows that defining VMALLOC_END based on PAGE_OFFSET is usual,
> > but I wonder why you don't just
> 
> The maximum addressable DRAM sizing is 256MB when fully populated. It seemed
> the right size. 0xF0000000 works too though, I have no problems changing it.
> 
> > 
> > 	#define VMALLOC_END 0xF0000000
> > 
The size of the vmalloc area has nothing to do with RAM.  See
http://www.arm.linux.org.uk/developer/memory.txt

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions
  2010-02-03 18:57     ` Kevin Wells
@ 2010-02-03 20:49       ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-03 20:49 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

> > 
> > You could make this easier by only handling MIC(?) interrupts and make
> > SIC1 and SIC2 use a chained handler.  Then you can use
> > get_irqnr_preamble for microoptimisation.
> > 
> 
> I'll take a look at this. I'm not entirely sure it can be made more
> optimal than how it's implemented now. Even SIC1 and SIC2 interrupts
> need to be routed via the MIC (The MIC interrupt will always fire
> when a SIC1 or SIC2 interrupt occur.) This code is very tight right
> now.
Yes, I got that.  You can look at
board_a9m9750dev_init_irq() (arch/arm/mach-ns9xxx/board-a9m9750dev.c)
for an example.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 12/13] ARM: LPC32XX: architecture header files
  2010-02-03 19:20     ` Kevin Wells
  2010-02-03 20:44       ` Uwe Kleine-König
@ 2010-02-03 21:34       ` Russell King - ARM Linux
  2010-02-03 22:06         ` Kevin Wells
  1 sibling, 1 reply; 72+ messages in thread
From: Russell King - ARM Linux @ 2010-02-03 21:34 UTC (permalink / raw)
  To: linux-arm-kernel

On Wed, Feb 03, 2010 at 08:20:01PM +0100, Kevin Wells wrote:
> > 
> > > +#define VMALLOC_END	(PAGE_OFFSET + 0x10000000)
> > grepping shows that defining VMALLOC_END based on PAGE_OFFSET is usual,
> > but I wonder why you don't just
> 
> The maximum addressable DRAM sizing is 256MB when fully populated. It seemed
> the right size. 0xF0000000 works too though, I have no problems changing it.

Well, what you have is:

VMALLOC_END
	...
VMALLOC_START
	8MB hole
high_memory
	Direct mapped RAM
PAGE_OFFSET

So, if your maximal DRAM size is 256MB, then if you install that amount
(ignoring things like highmem support, which you should have disabled)
high_memory = PAGE_OFFSET + 256MB, or PAGE_OFFSET + 0x10000000.

That makes VMALLOC_START = PAGE_OFFSET + 0x10800000, which will be
above VMALLOC_END !

What actually happens is that the kernel (by default) enforces a 128MB
VMALLOC area, which, given your VMALLOC_END value will give you a
maximum of 120MB of SDRAM - if you check your boot log, you probably
have some message like:

"Truncating RAM at ..."

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-02-03 20:40       ` Uwe Kleine-König
@ 2010-02-03 21:58         ` Kevin Wells
  2010-02-04  8:17           ` Uwe Kleine-König
  0 siblings, 1 reply; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 21:58 UTC (permalink / raw)
  To: linux-arm-kernel

> > > > +   case IRQ_TYPE_EDGE_FALLING:
> > > > +           /* Falling edge sensitive */
> > > > +           reg = readl(ctrl + INTC_POLAR);
> > > > +           reg &= ~mask;
> > > > +           writel(reg, (ctrl + INTC_POLAR));
> > > > +           reg = readl(ctrl + INTC_ACT_TYPE);
> > > > +           reg |= mask;
> > > > +           writel(reg, (ctrl + INTC_ACT_TYPE));
> > > > +           set_irq_handler(irq, handle_edge_irq);
> > > > +           break;
> > > did you test that you really need handle_edge_irq?  Sane irq
> controllers
> > > can (and should) use handle_level_irq for both level and edge
> sensitive
> > > irqs.  You only need handle_edge_irq if your controller doesn't
> remember
> > > edge transitions while the irq is masked.
> >
> > This is supported and intended. It's important for slow moving external
> > GPIO events where you can't clear the active level state or pulse
> > duration (ie, switches).
> I didn't understand your answer here.  What is supported and intended?
> This has something to do with your controller, not with slow external
> things.
> 

The controller supports level and edge sensitive modes. There are cases
when using external events that you want an edge based interrupt. For
example, an event connected to a monetary switch will stay asserted
(level-wise) as long as the switch is closed. The interrupt controller
latches the event and can clear the latch, but the latch would never
clear if the interrupt was level sensitive. In cases like this, you just
want to handle the edges. This has been tested.

> > > Does this work without NO_HZ?  I though you need to setup a periodic
> > > mode with CONFIG_HZ irqs per second first?
> >
> > This is handled in the clockevents handler. It will setup the driver
> > for the next event in the set_next_event callback. I believe the
> > current CONFIG_HZ rate is set to 100.
> Hmmm:
> 
> 	~/gsrc/linux-2.6/arch/arm/mach-lpc32xx$ grep HZ *
> 	~/gsrc/linux-2.6/arch/arm/mach-lpc32xx$
> 

CONFIG_HZ is defined in the phy3250_defconfig file in arch/arms/configs.
It's actually used in the clock events driver and passes the next tick delta
to the timer driver callback. The timer driver itself doesn't know the tick
rate or even the value of HZ - it's in the higher layers. Note this timer
driver also works fine with NO_HZ. Sorry about the confusion on this.

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

* [PATCH 12/13] ARM: LPC32XX: architecture header files
  2010-02-03 21:34       ` Russell King - ARM Linux
@ 2010-02-03 22:06         ` Kevin Wells
  0 siblings, 0 replies; 72+ messages in thread
From: Kevin Wells @ 2010-02-03 22:06 UTC (permalink / raw)
  To: linux-arm-kernel

> 
> On Wed, Feb 03, 2010 at 08:20:01PM +0100, Kevin Wells wrote:
> > >
> > > > +#define VMALLOC_END	(PAGE_OFFSET + 0x10000000)
> > > grepping shows that defining VMALLOC_END based on PAGE_OFFSET is
> usual,
> > > but I wonder why you don't just
> >
> > The maximum addressable DRAM sizing is 256MB when fully populated. It
> seemed
> > the right size. 0xF0000000 works too though, I have no problems changing
> it.
> 
> Well, what you have is:
> 
> VMALLOC_END
> 	...
> VMALLOC_START
> 	8MB hole
> high_memory
> 	Direct mapped RAM
> PAGE_OFFSET
> 
> So, if your maximal DRAM size is 256MB, then if you install that amount
> (ignoring things like highmem support, which you should have disabled)
> high_memory = PAGE_OFFSET + 256MB, or PAGE_OFFSET + 0x10000000.
> 
> That makes VMALLOC_START = PAGE_OFFSET + 0x10800000, which will be
> above VMALLOC_END !
> 
> What actually happens is that the kernel (by default) enforces a 128MB
> VMALLOC area, which, given your VMALLOC_END value will give you a
> maximum of 120MB of SDRAM - if you check your boot log, you probably
> have some message like:
> 
> "Truncating RAM at ..."

We only have 64M boards right now so this is untested.

Previously with an older kernel where I had to support discontiguous
mem and 128M/256M x2 bank boards (I no longer have these), I did have
to change this value to make it work.

Thanks for the the quick explanation and thanks Uwe for the link. I'll
review and fix this in the next patch series.

Kevin

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

* [PATCH 06/13] ARM: LPC32XX: Core architecture files
  2010-02-03 21:58         ` Kevin Wells
@ 2010-02-04  8:17           ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-04  8:17 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Wed, Feb 03, 2010 at 10:58:55PM +0100, Kevin Wells wrote:
> > > > > +   case IRQ_TYPE_EDGE_FALLING:
> > > > > +           /* Falling edge sensitive */
> > > > > +           reg = readl(ctrl + INTC_POLAR);
> > > > > +           reg &= ~mask;
> > > > > +           writel(reg, (ctrl + INTC_POLAR));
> > > > > +           reg = readl(ctrl + INTC_ACT_TYPE);
> > > > > +           reg |= mask;
> > > > > +           writel(reg, (ctrl + INTC_ACT_TYPE));
> > > > > +           set_irq_handler(irq, handle_edge_irq);
> > > > > +           break;
> > > > did you test that you really need handle_edge_irq?  Sane irq
> > controllers
> > > > can (and should) use handle_level_irq for both level and edge
> > sensitive
> > > > irqs.  You only need handle_edge_irq if your controller doesn't
> > remember
> > > > edge transitions while the irq is masked.
> > >
> > > This is supported and intended. It's important for slow moving external
> > > GPIO events where you can't clear the active level state or pulse
> > > duration (ie, switches).
> > I didn't understand your answer here.  What is supported and intended?
> > This has something to do with your controller, not with slow external
> > things.
> > 
> 
> The controller supports level and edge sensitive modes. There are cases
> when using external events that you want an edge based interrupt. For
> example, an event connected to a monetary switch will stay asserted
> (level-wise) as long as the switch is closed. The interrupt controller
> latches the event and can clear the latch, but the latch would never
> clear if the interrupt was level sensitive. In cases like this, you just
> want to handle the edges. This has been tested.
Oh yes.  Of course.  I'll retry to make my point more explicit using some
code.

Did you verify the following is broken? :

	static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type)
	{
		unsigned int reg, ctrl, mask;

		get_controller(irq, &ctrl, &mask);

		switch (type) {
		case IRQ_TYPE_EDGE_RISING:
			/* Rising edge sensitive */
			__set_irq_type(ctrl, mask, mask, mask);
			/*
			 * don't set irq_handler to handle_edge_irq here
		         * as handle_level_irq can handle edge sensitive
		         * irqs just fine.  Of course the controller
		         * needs to be setup for edge irqs to get any
		         * difference to IRQ_TYPE_LEVEL_HIGH.
			 * See
			 * http://mid.gmane.org/20091007102836.GA27860 at flint.arm.linux.org.uk
			 * for some details
			 */
			break;

		case IRQ_TYPE_EDGE_FALLING:
			/* Falling edge sensitive */
			__set_irq_type(ctrl, mask, 0, mask);
			/* don't set irq_handler to handle_edge_irq here */
			break;

		case IRQ_TYPE_LEVEL_LOW:
			/* Low level sensitive */
			__set_irq_type(ctrl, mask, 0, 0);
			...

	}

	...

	void __init lpc32xx_init_irq(void)
	{
		...
		for (i = 0; i < NR_IRQS; i++) {
			set_irq_flags(i, IRQF_VALID);
			set_irq_chip(i, &lpc32xx_irq_chip);
			/*
			 * use handle_level_irq for edge and level
 			 * triggered irqs
			 */
			set_irq_handler(irq, handle_level_irq);
		}
		...
	}
	

> > > > Does this work without NO_HZ?  I though you need to setup a periodic
> > > > mode with CONFIG_HZ irqs per second first?
> > >
> > > This is handled in the clockevents handler. It will setup the driver
> > > for the next event in the set_next_event callback. I believe the
> > > current CONFIG_HZ rate is set to 100.
> > Hmmm:
> > 
> > 	~/gsrc/linux-2.6/arch/arm/mach-lpc32xx$ grep HZ *
> > 	~/gsrc/linux-2.6/arch/arm/mach-lpc32xx$
> > 
> 
> CONFIG_HZ is defined in the phy3250_defconfig file in arch/arms/configs.
> It's actually used in the clock events driver and passes the next tick delta
> to the timer driver callback. The timer driver itself doesn't know the tick
> rate or even the value of HZ - it's in the higher layers. Note this timer
> driver also works fine with NO_HZ. Sorry about the confusion on this.
Probably it's really just me who is confused, but I wondered if this
works *without* NO_HZ as I thought the timer init function is supposed
to set up a HZ tick.

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-02-03 20:20       ` Uwe Kleine-König
@ 2010-02-05 16:48         ` Kevin Wells
  2010-02-05 19:45           ` Russell King - ARM Linux
  0 siblings, 1 reply; 72+ messages in thread
From: Kevin Wells @ 2010-02-05 16:48 UTC (permalink / raw)
  To: linux-arm-kernel

03, 2010 at 07:51:36PM +0100, Kevin Wells wrote:
> > > > +/*
> > > > + * clk_get_rate - obtain the current clock rate (in Hz) for a clock
> > > source
> > > > + */
> > > > +unsigned long clk_get_rate(struct clk *clk)
> > > > +{
> > > > +	if (clk->get_rate)
> > > > +		return (clk->get_rate)(clk);
> > > > +
> > > > +	/* If a clocks rate is 0, it uses the parent's rate instead.
> */
> > > > +	while (clk->rate == 0)
> > > > +		clk = clk->parent;
> > > > +
> > > > +	return clk->rate;
> > > > +}
> > > > +EXPORT_SYMBOL(clk_get_rate);
> > > doesn't that need locking to protect against a race with clk_set_rate?
> > > Hmmm, you never need to call get_rate for a parent clock?
> > >
> >
> > I'll add a lock for this, its needed. The get_rate() function will just
> > continue to fall back to the first non-0Hz parent clock (all clocks
> > eventually go to a non-0Hz parent clock). Most clocks don't even have
> > a get_rate() function.
> still, if a clock with a get_rate function has a child, clk_get_rate for
> the child might return a wrong result.
> 
> Actually you need something like:
> 
> 	while (!(rate = clk->rate) && !(clk->get_rate && (rate = clk-
> >get_rate(clk)))) {
> 		clk = clk->parent;
> 		if (!clk)
> 			break;
> 	}
> 	return rate;
> 
> Maybe with a nicer coding style by not using an assignment in the while
> condition.
> 

This approach always returned a non-0 clock rate for the clock, regardless
of whether the clock was enabled or not. Does the clk_get_rate() function
need to return a rate of 0 if the clock is disabled?

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

* [PATCH 08/13] ARM: LPC32XX: clock tree support
  2010-02-05 16:48         ` Kevin Wells
@ 2010-02-05 19:45           ` Russell King - ARM Linux
  0 siblings, 0 replies; 72+ messages in thread
From: Russell King - ARM Linux @ 2010-02-05 19:45 UTC (permalink / raw)
  To: linux-arm-kernel

On Fri, Feb 05, 2010 at 05:48:36PM +0100, Kevin Wells wrote:
> This approach always returned a non-0 clock rate for the clock, regardless
> of whether the clock was enabled or not. Does the clk_get_rate() function
> need to return a rate of 0 if the clock is disabled?

No - there's no requirement for that to be the case.

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

* [PATCH 1/3] gpiolib: make names array and its values const
  2010-02-03 15:55   ` Uwe Kleine-König
@ 2010-02-08  9:09       ` Uwe Kleine-König
  2010-02-08  9:09       ` Uwe Kleine-König
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:09 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arm-kernel, Andrew Morton, David Brownell, Jani Nikula,
	Daniel Glöckner, Nate Case, H Hartley Sweeten,
	Daniel Silverstone, Arnd Bergmann, Mike Frysinger, Kevin Wells

gpiolib doesn't need to modify the names and I assume most initializers
use sting constants that shouldn't be modified anyhow.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Cc: Kevin Wells <kevin.wells@nxp.com>
---
 drivers/gpio/gpiolib.c      |    2 +-
 drivers/gpio/pca953x.c      |    2 +-
 include/asm-generic/gpio.h  |    2 +-
 include/linux/i2c/pca953x.h |    2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a25ad28..8543685 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -716,7 +716,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
 	unsigned long		flags;
 	struct gpio_desc	*desc;
 	int			status = -EINVAL;
-	char			*ioname = NULL;
+	const char		*ioname = NULL;
 
 	/* can't export until sysfs is available ... */
 	if (!gpio_class.p) {
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 6a2fb3f..4faeca4 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -56,7 +56,7 @@ struct pca953x_chip {
 	struct i2c_client *client;
 	struct pca953x_platform_data *dyn_pdata;
 	struct gpio_chip gpio_chip;
-	char **names;
+	const char *const *names;
 };
 
 static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 485eeb6..37af893 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -98,7 +98,7 @@ struct gpio_chip {
 						struct gpio_chip *chip);
 	int			base;
 	u16			ngpio;
-	char			**names;
+	const char		*const *names;
 	unsigned		can_sleep:1;
 	unsigned		exported:1;
 };
diff --git a/include/linux/i2c/pca953x.h b/include/linux/i2c/pca953x.h
index 81736d6..4630fab 100644
--- a/include/linux/i2c/pca953x.h
+++ b/include/linux/i2c/pca953x.h
@@ -15,5 +15,5 @@ struct pca953x_platform_data {
 	int		(*teardown)(struct i2c_client *client,
 				unsigned gpio, unsigned ngpio,
 				void *context);
-	char		**names;
+	const char	*const *names;
 };
-- 
1.6.6


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

* [PATCH 1/3] gpiolib: make names array and its values const
@ 2010-02-08  9:09       ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

gpiolib doesn't need to modify the names and I assume most initializers
use sting constants that shouldn't be modified anyhow.

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
Cc: Kevin Wells <kevin.wells@nxp.com>
---
 drivers/gpio/gpiolib.c      |    2 +-
 drivers/gpio/pca953x.c      |    2 +-
 include/asm-generic/gpio.h  |    2 +-
 include/linux/i2c/pca953x.h |    2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index a25ad28..8543685 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -716,7 +716,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
 	unsigned long		flags;
 	struct gpio_desc	*desc;
 	int			status = -EINVAL;
-	char			*ioname = NULL;
+	const char		*ioname = NULL;
 
 	/* can't export until sysfs is available ... */
 	if (!gpio_class.p) {
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index 6a2fb3f..4faeca4 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -56,7 +56,7 @@ struct pca953x_chip {
 	struct i2c_client *client;
 	struct pca953x_platform_data *dyn_pdata;
 	struct gpio_chip gpio_chip;
-	char **names;
+	const char *const *names;
 };
 
 static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 485eeb6..37af893 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -98,7 +98,7 @@ struct gpio_chip {
 						struct gpio_chip *chip);
 	int			base;
 	u16			ngpio;
-	char			**names;
+	const char		*const *names;
 	unsigned		can_sleep:1;
 	unsigned		exported:1;
 };
diff --git a/include/linux/i2c/pca953x.h b/include/linux/i2c/pca953x.h
index 81736d6..4630fab 100644
--- a/include/linux/i2c/pca953x.h
+++ b/include/linux/i2c/pca953x.h
@@ -15,5 +15,5 @@ struct pca953x_platform_data {
 	int		(*teardown)(struct i2c_client *client,
 				unsigned gpio, unsigned ngpio,
 				void *context);
-	char		**names;
+	const char	*const *names;
 };
-- 
1.6.6

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

* [PATCH 2/3] gpiolib: a gpio is unsigned, so use %u to print it
  2010-02-03 15:55   ` Uwe Kleine-König
@ 2010-02-08  9:09       ` Uwe Kleine-König
  2010-02-08  9:09       ` Uwe Kleine-König
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:09 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arm-kernel, Andrew Morton, David Brownell, Jani Nikula,
	Daniel Glöckner, Nate Case, H Hartley Sweeten,
	Daniel Silverstone, Arnd Bergmann, Mike Frysinger

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/gpio/gpiolib.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 8543685..20988c8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -747,7 +747,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
 		struct device	*dev;
 
 		dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-				desc, ioname ? ioname : "gpio%d", gpio);
+				desc, ioname ? ioname : "gpio%u", gpio);
 		if (!IS_ERR(dev)) {
 			status = sysfs_create_group(&dev->kobj,
 						&gpio_attr_group);
-- 
1.6.6


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

* [PATCH 2/3] gpiolib: a gpio is unsigned, so use %u to print it
@ 2010-02-08  9:09       ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
 drivers/gpio/gpiolib.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 8543685..20988c8 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -747,7 +747,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
 		struct device	*dev;
 
 		dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-				desc, ioname ? ioname : "gpio%d", gpio);
+				desc, ioname ? ioname : "gpio%u", gpio);
 		if (!IS_ERR(dev)) {
 			status = sysfs_create_group(&dev->kobj,
 						&gpio_attr_group);
-- 
1.6.6

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

* [PATCH 3/3] gpiolib: document that names can contain printk format specifiers
  2010-02-03 15:55   ` Uwe Kleine-König
@ 2010-02-08  9:09       ` Uwe Kleine-König
  2010-02-08  9:09       ` Uwe Kleine-König
                         ` (2 subsequent siblings)
  3 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:09 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arm-kernel, Andrew Morton, David Brownell, Jani Nikula,
	Daniel Glöckner, Nate Case, H Hartley Sweeten,
	Daniel Silverstone, Arnd Bergmann, Mike Frysinger

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 include/asm-generic/gpio.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 37af893..abdb5d3 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -60,7 +60,8 @@ struct module;
  * @names: if set, must be an array of strings to use as alternative
  *      names for the GPIOs in this chip. Any entry in the array
  *      may be NULL if there is no alias for the GPIO, however the
- *      array must be @ngpio entries long.
+ *      array must be @ngpio entries long.  A name can include a single printk
+ *      format specifier for an unsigned int.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
-- 
1.6.6


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

* [PATCH 3/3] gpiolib: document that names can contain printk format specifiers
@ 2010-02-08  9:09       ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:09 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
---
 include/asm-generic/gpio.h |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 37af893..abdb5d3 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -60,7 +60,8 @@ struct module;
  * @names: if set, must be an array of strings to use as alternative
  *      names for the GPIOs in this chip. Any entry in the array
  *      may be NULL if there is no alias for the GPIO, however the
- *      array must be @ngpio entries long.
+ *      array must be @ngpio entries long.  A name can include a single printk
+ *      format specifier for an unsigned int.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
-- 
1.6.6

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

* Re: [PATCH 3/3] gpiolib: document that names can contain printk format specifiers
  2010-02-08  9:09       ` Uwe Kleine-König
@ 2010-02-08  9:16         ` Uwe Kleine-König
  -1 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:16 UTC (permalink / raw)
  To: linux-kernel
  Cc: linux-arm-kernel, Andrew Morton, David Brownell, Jani Nikula,
	Daniel Glöckner, Nate Case, H Hartley Sweeten,
	Daniel Silverstone, Arnd Bergmann, Mike Frysinger

Hello,

On Mon, Feb 08, 2010 at 10:09:40AM +0100, Uwe Kleine-König wrote:
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> ---
>  include/asm-generic/gpio.h |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
> index 37af893..abdb5d3 100644
> --- a/include/asm-generic/gpio.h
> +++ b/include/asm-generic/gpio.h
> @@ -60,7 +60,8 @@ struct module;
>   * @names: if set, must be an array of strings to use as alternative
>   *      names for the GPIOs in this chip. Any entry in the array
>   *      may be NULL if there is no alias for the GPIO, however the
> - *      array must be @ngpio entries long.
> + *      array must be @ngpio entries long.  A name can include a single printk
> + *      format specifier for an unsigned int.
probably add: "It is substituted by the actual number of the gpio."

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-König            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 3/3] gpiolib: document that names can contain printk format specifiers
@ 2010-02-08  9:16         ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:16 UTC (permalink / raw)
  To: linux-arm-kernel

Hello,

On Mon, Feb 08, 2010 at 10:09:40AM +0100, Uwe Kleine-K?nig wrote:
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
> ---
>  include/asm-generic/gpio.h |    3 ++-
>  1 files changed, 2 insertions(+), 1 deletions(-)
> 
> diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
> index 37af893..abdb5d3 100644
> --- a/include/asm-generic/gpio.h
> +++ b/include/asm-generic/gpio.h
> @@ -60,7 +60,8 @@ struct module;
>   * @names: if set, must be an array of strings to use as alternative
>   *      names for the GPIOs in this chip. Any entry in the array
>   *      may be NULL if there is no alias for the GPIO, however the
> - *      array must be @ngpio entries long.
> + *      array must be @ngpio entries long.  A name can include a single printk
> + *      format specifier for an unsigned int.
probably add: "It is substituted by the actual number of the gpio."

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/3] gpiolib: make names array and its values const
  2010-02-08  9:09       ` Uwe Kleine-König
@ 2010-02-08  9:37         ` Baruch Siach
  -1 siblings, 0 replies; 72+ messages in thread
From: Baruch Siach @ 2010-02-08  9:37 UTC (permalink / raw)
  To: Uwe Kleine-König
  Cc: linux-kernel, David Brownell, Mike Frysinger, Nate Case,
	Daniel Silverstone, Kevin Wells, Daniel Glöckner,
	H Hartley Sweeten, Arnd Bergmann, Jani Nikula, Andrew Morton,
	linux-arm-kernel

Hi Uwe,

On Mon, Feb 08, 2010 at 10:09:38AM +0100, Uwe Kleine-König wrote:
> gpiolib doesn't need to modify the names and I assume most initializers
> use sting constants that shouldn't be modified anyhow.

s/sting/string/

> 
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> Cc: Kevin Wells <kevin.wells@nxp.com>
> ---

[snip]

baruch

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

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

* [PATCH 1/3] gpiolib: make names array and its values const
@ 2010-02-08  9:37         ` Baruch Siach
  0 siblings, 0 replies; 72+ messages in thread
From: Baruch Siach @ 2010-02-08  9:37 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Uwe,

On Mon, Feb 08, 2010 at 10:09:38AM +0100, Uwe Kleine-K?nig wrote:
> gpiolib doesn't need to modify the names and I assume most initializers
> use sting constants that shouldn't be modified anyhow.

s/sting/string/

> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
> Cc: Kevin Wells <kevin.wells@nxp.com>
> ---

[snip]

baruch

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

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

* Re: [PATCH 1/3] gpiolib: make names array and its values const
  2010-02-08  9:37         ` Baruch Siach
@ 2010-02-08  9:43           ` Uwe Kleine-König
  -1 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:43 UTC (permalink / raw)
  To: Baruch Siach
  Cc: linux-kernel, David Brownell, Mike Frysinger, Nate Case,
	Daniel Silverstone, Kevin Wells, Daniel Glöckner,
	H Hartley Sweeten, Arnd Bergmann, Jani Nikula, Andrew Morton,
	linux-arm-kernel

Hi Baruch,

On Mon, Feb 08, 2010 at 11:37:24AM +0200, Baruch Siach wrote:
> Hi Uwe,
> 
> On Mon, Feb 08, 2010 at 10:09:38AM +0100, Uwe Kleine-König wrote:
> > gpiolib doesn't need to modify the names and I assume most initializers
> > use sting constants that shouldn't be modified anyhow.
> 
> s/sting/string/
Thanks, fixed in my tree.

BTW, you can get the updated series at

	git://git.pengutronix.de/git/ukl/linux-2.6.git gpiolib/names

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-König            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* [PATCH 1/3] gpiolib: make names array and its values const
@ 2010-02-08  9:43           ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-08  9:43 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Baruch,

On Mon, Feb 08, 2010 at 11:37:24AM +0200, Baruch Siach wrote:
> Hi Uwe,
> 
> On Mon, Feb 08, 2010 at 10:09:38AM +0100, Uwe Kleine-K?nig wrote:
> > gpiolib doesn't need to modify the names and I assume most initializers
> > use sting constants that shouldn't be modified anyhow.
> 
> s/sting/string/
Thanks, fixed in my tree.

BTW, you can get the updated series at

	git://git.pengutronix.de/git/ukl/linux-2.6.git gpiolib/names

Best regards
Uwe

-- 
Pengutronix e.K.                              | Uwe Kleine-K?nig            |
Industrial Linux Solutions                    | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/3] gpiolib: make names array and its values const
  2010-02-08  9:09       ` Uwe Kleine-König
@ 2010-02-24 10:35         ` Uwe Kleine-König
  -1 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-24 10:35 UTC (permalink / raw)
  To: David Brownell
  Cc: linux-arm-kernel, Andrew Morton, Jani Nikula,
	Daniel Glöckner, Nate Case, H Hartley Sweeten,
	Daniel Silverstone, Arnd Bergmann, Mike Frysinger, Kevin Wells,
	linux-kernel

Hi David,

what do you think about these three patches?  Should I resend?

Best regards
Uwe

The following changes since commit 6339204ecc2aa2067a99595522de0403f0854bb8:
  Linus Torvalds (1):
        Merge branch 'for-linus' of git://git.kernel.org/.../viro/vfs-2.6

are available in the git repository at:

  git://git.pengutronix.de/git/ukl/linux-2.6.git gpiolib/names

Uwe Kleine-König (3):
      gpiolib: make names array and its values const
      gpiolib: a gpio is unsigned, so use %u to print it
      gpiolib: document that names can contain printk format specifiers

 drivers/gpio/gpiolib.c      |    4 ++--
 drivers/gpio/pca953x.c      |    2 +-
 include/asm-generic/gpio.h  |    6 ++++--
 include/linux/i2c/pca953x.h |    2 +-
 4 files changed, 8 insertions(+), 6 deletions(-)
-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/3] gpiolib: make names array and its values const
@ 2010-02-24 10:35         ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-02-24 10:35 UTC (permalink / raw)
  To: linux-arm-kernel

Hi David,

what do you think about these three patches?  Should I resend?

Best regards
Uwe

The following changes since commit 6339204ecc2aa2067a99595522de0403f0854bb8:
  Linus Torvalds (1):
        Merge branch 'for-linus' of git://git.kernel.org/.../viro/vfs-2.6

are available in the git repository at:

  git://git.pengutronix.de/git/ukl/linux-2.6.git gpiolib/names

Uwe Kleine-K?nig (3):
      gpiolib: make names array and its values const
      gpiolib: a gpio is unsigned, so use %u to print it
      gpiolib: document that names can contain printk format specifiers

 drivers/gpio/gpiolib.c      |    4 ++--
 drivers/gpio/pca953x.c      |    2 +-
 include/asm-generic/gpio.h  |    6 ++++--
 include/linux/i2c/pca953x.h |    2 +-
 4 files changed, 8 insertions(+), 6 deletions(-)
-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* Re: [PATCH 1/3] gpiolib: make names array and its values const
  2010-02-08  9:09       ` Uwe Kleine-König
@ 2010-03-22 20:47         ` Uwe Kleine-König
  -1 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-03-22 20:47 UTC (permalink / raw)
  To: Andrew Morton
  Cc: linux-arm-kernel, David Brownell, Jani Nikula,
	Daniel Glöckner, Nate Case, H Hartley Sweeten,
	Daniel Silverstone, Arnd Bergmann, Mike Frysinger, Kevin Wells,
	linux-kernel

Hi Andrew,

On Mon, Feb 08, 2010 at 10:09:38AM +0100, Uwe Kleine-König wrote:
> gpiolib doesn't need to modify the names and I assume most initializers
> use sting constants that shouldn't be modified anyhow.
> 
> Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
> Cc: Kevin Wells <kevin.wells@nxp.com>
> ---
>  drivers/gpio/gpiolib.c      |    2 +-
>  drivers/gpio/pca953x.c      |    2 +-
>  include/asm-generic/gpio.h  |    2 +-
>  include/linux/i2c/pca953x.h |    2 +-
>  4 files changed, 4 insertions(+), 4 deletions(-)

I haven't received feed back for these patches.  Would you care to take
them?  If yes, should I resend?  Alternatively you can get them from 

	git://git.pengutronix.de/git/ukl/linux-2.6.git gpiolib/names

whatever is easiest for you ...

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-König            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/3] gpiolib: make names array and its values const
@ 2010-03-22 20:47         ` Uwe Kleine-König
  0 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-03-22 20:47 UTC (permalink / raw)
  To: linux-arm-kernel

Hi Andrew,

On Mon, Feb 08, 2010 at 10:09:38AM +0100, Uwe Kleine-K?nig wrote:
> gpiolib doesn't need to modify the names and I assume most initializers
> use sting constants that shouldn't be modified anyhow.
> 
> Signed-off-by: Uwe Kleine-K?nig <u.kleine-koenig@pengutronix.de>
> Cc: Kevin Wells <kevin.wells@nxp.com>
> ---
>  drivers/gpio/gpiolib.c      |    2 +-
>  drivers/gpio/pca953x.c      |    2 +-
>  include/asm-generic/gpio.h  |    2 +-
>  include/linux/i2c/pca953x.h |    2 +-
>  4 files changed, 4 insertions(+), 4 deletions(-)

I haven't received feed back for these patches.  Would you care to take
them?  If yes, should I resend?  Alternatively you can get them from 

	git://git.pengutronix.de/git/ukl/linux-2.6.git gpiolib/names

whatever is easiest for you ...

Best regards
Uwe

-- 
Pengutronix e.K.                           | Uwe Kleine-K?nig            |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

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

* [PATCH 1/3] gpiolib: make names array and its values const
  2010-03-22 20:47         ` Uwe Kleine-König
  (?)
@ 2010-03-23 10:24         ` Uwe Kleine-König
  -1 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-03-23 10:24 UTC (permalink / raw)
  To: linux-kernel, Andrew Morton; +Cc: Kevin Wells

gpiolib doesn't need to modify the names and I assume most initializers
use string constants that shouldn't be modified anyhow.

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Cc: Kevin Wells <kevin.wells@nxp.com>
---
 drivers/gpio/gpiolib.c      |    2 +-
 drivers/gpio/pca953x.c      |    2 +-
 include/asm-generic/gpio.h  |    2 +-
 include/linux/i2c/pca953x.h |    2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 6d1b866..03e82d5 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -720,7 +720,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
 	unsigned long		flags;
 	struct gpio_desc	*desc;
 	int			status = -EINVAL;
-	char			*ioname = NULL;
+	const char		*ioname = NULL;
 
 	/* can't export until sysfs is available ... */
 	if (!gpio_class.p) {
diff --git a/drivers/gpio/pca953x.c b/drivers/gpio/pca953x.c
index ab5daab..60553d0 100644
--- a/drivers/gpio/pca953x.c
+++ b/drivers/gpio/pca953x.c
@@ -72,7 +72,7 @@ struct pca953x_chip {
 	struct i2c_client *client;
 	struct pca953x_platform_data *dyn_pdata;
 	struct gpio_chip gpio_chip;
-	char **names;
+	const char *const *names;
 };
 
 static int pca953x_write_reg(struct pca953x_chip *chip, int reg, uint16_t val)
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 979c6a5..bc0c14d 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -98,7 +98,7 @@ struct gpio_chip {
 						struct gpio_chip *chip);
 	int			base;
 	u16			ngpio;
-	char			**names;
+	const char		*const *names;
 	unsigned		can_sleep:1;
 	unsigned		exported:1;
 };
diff --git a/include/linux/i2c/pca953x.h b/include/linux/i2c/pca953x.h
index d5c5a60..139ba52 100644
--- a/include/linux/i2c/pca953x.h
+++ b/include/linux/i2c/pca953x.h
@@ -24,7 +24,7 @@ struct pca953x_platform_data {
 	int		(*teardown)(struct i2c_client *client,
 				unsigned gpio, unsigned ngpio,
 				void *context);
-	char		**names;
+	const char	*const *names;
 };
 
 #endif /* _LINUX_PCA953X_H */
-- 
1.7.0


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

* [PATCH 2/3] gpiolib: a gpio is unsigned, so use %u to print it
  2010-03-22 20:47         ` Uwe Kleine-König
  (?)
  (?)
@ 2010-03-23 10:24         ` Uwe Kleine-König
  -1 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-03-23 10:24 UTC (permalink / raw)
  To: linux-kernel, Andrew Morton

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 drivers/gpio/gpiolib.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 03e82d5..548b71e 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -751,7 +751,7 @@ int gpio_export(unsigned gpio, bool direction_may_change)
 		struct device	*dev;
 
 		dev = device_create(&gpio_class, desc->chip->dev, MKDEV(0, 0),
-				desc, ioname ? ioname : "gpio%d", gpio);
+				desc, ioname ? ioname : "gpio%u", gpio);
 		if (!IS_ERR(dev)) {
 			status = sysfs_create_group(&dev->kobj,
 						&gpio_attr_group);
-- 
1.7.0


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

* [PATCH 3/3] gpiolib: document that names can contain printk format specifiers
  2010-03-22 20:47         ` Uwe Kleine-König
                           ` (2 preceding siblings ...)
  (?)
@ 2010-03-23 10:24         ` Uwe Kleine-König
  -1 siblings, 0 replies; 72+ messages in thread
From: Uwe Kleine-König @ 2010-03-23 10:24 UTC (permalink / raw)
  To: linux-kernel, Andrew Morton

Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
---
 include/asm-generic/gpio.h |    4 +++-
 1 files changed, 3 insertions(+), 1 deletions(-)

diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index bc0c14d..fb1ecf8 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -60,7 +60,9 @@ struct module;
  * @names: if set, must be an array of strings to use as alternative
  *      names for the GPIOs in this chip. Any entry in the array
  *      may be NULL if there is no alias for the GPIO, however the
- *      array must be @ngpio entries long.
+ *      array must be @ngpio entries long.  A name can include a single printk
+ *      format specifier for an unsigned int.  It is substituted by the actual
+ *      number of the gpio.
  *
  * A gpio_chip can help platforms abstract various sources of GPIOs so
  * they can all be accessed through a common programing interface.
-- 
1.7.0


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

end of thread, other threads:[~2010-03-23 10:25 UTC | newest]

Thread overview: 72+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-01-28  1:43 LPC32XX architecture files (updated) wellsk40 at gmail.com
2010-01-28  1:43 ` [PATCH 01/13] i2c_pnx: Added Kconfig support for the LCP32XX wellsk40 at gmail.com
2010-01-28  1:43 ` [PATCH 02/13] pnx4008_wdt: Added Kconfig support for the LPC32XX wellsk40 at gmail.com
2010-01-28  1:43 ` [PATCH 03/13] amba clcd: Swapped CTRL/IENB registers for LCP32XX wellsk40 at gmail.com
2010-01-28  1:43 ` [PATCH 04/13] ARM: LPC32XX arch support in Kconfig and Makefile wellsk40 at gmail.com
2010-02-03 10:31   ` Uwe Kleine-König
2010-01-28  1:43 ` [PATCH 05/13] ARM: LPC32XX: arch Kconfig, plat Kconfig, and makefiles wellsk40 at gmail.com
2010-02-03 10:51   ` Uwe Kleine-König
2010-02-03 11:26     ` Russell King - ARM Linux
2010-02-03 13:57       ` Uwe Kleine-König
2010-02-03 15:02         ` Russell King - ARM Linux
2010-02-03 18:01     ` Kevin Wells
2010-02-03 18:56       ` Uwe Kleine-König
2010-01-28  1:43 ` [PATCH 06/13] ARM: LPC32XX: Core architecture files wellsk40 at gmail.com
2010-01-28 17:58   ` H Hartley Sweeten
2010-01-28 19:54     ` Kevin Wells
2010-02-03 10:54     ` Uwe Kleine-König
2010-02-03 18:05       ` Kevin Wells
2010-02-03 15:55   ` Uwe Kleine-König
2010-02-03 18:43     ` Kevin Wells
2010-02-03 20:40       ` Uwe Kleine-König
2010-02-03 21:58         ` Kevin Wells
2010-02-04  8:17           ` Uwe Kleine-König
2010-02-08  9:09     ` [PATCH 1/3] gpiolib: make names array and its values const Uwe Kleine-König
2010-02-08  9:09       ` Uwe Kleine-König
2010-02-08  9:37       ` Baruch Siach
2010-02-08  9:37         ` Baruch Siach
2010-02-08  9:43         ` Uwe Kleine-König
2010-02-08  9:43           ` Uwe Kleine-König
2010-02-24 10:35       ` Uwe Kleine-König
2010-02-24 10:35         ` Uwe Kleine-König
2010-03-22 20:47       ` Uwe Kleine-König
2010-03-22 20:47         ` Uwe Kleine-König
2010-03-23 10:24         ` Uwe Kleine-König
2010-03-23 10:24         ` [PATCH 2/3] gpiolib: a gpio is unsigned, so use %u to print it Uwe Kleine-König
2010-03-23 10:24         ` [PATCH 3/3] gpiolib: document that names can contain printk format specifiers Uwe Kleine-König
2010-02-08  9:09     ` [PATCH 2/3] gpiolib: a gpio is unsigned, so use %u to print it Uwe Kleine-König
2010-02-08  9:09       ` Uwe Kleine-König
2010-02-08  9:09     ` [PATCH 3/3] gpiolib: document that names can contain printk format specifiers Uwe Kleine-König
2010-02-08  9:09       ` Uwe Kleine-König
2010-02-08  9:16       ` Uwe Kleine-König
2010-02-08  9:16         ` Uwe Kleine-König
2010-01-28  1:43 ` [PATCH 07/13] ARM: LPC32XX: common architecture functions and structures wellsk40 at gmail.com
2010-02-03 16:01   ` Uwe Kleine-König
2010-01-28  1:43 ` [PATCH 08/13] ARM: LPC32XX: clock tree support wellsk40 at gmail.com
2010-01-28 17:07   ` Rabin Vincent
2010-01-28 19:51     ` Kevin Wells
2010-02-03 16:32   ` Uwe Kleine-König
2010-02-03 18:51     ` Kevin Wells
2010-02-03 20:20       ` Uwe Kleine-König
2010-02-05 16:48         ` Kevin Wells
2010-02-05 19:45           ` Russell King - ARM Linux
2010-01-28  1:43 ` [PATCH 09/13] ARM: LPC32XX: power and event management wellsk40 at gmail.com
2010-02-03 16:44   ` Uwe Kleine-König
2010-02-03 19:03     ` Kevin Wells
2010-01-28  1:43 ` [PATCH 10/13] ARM: LPC32XX: Phytec PHY3250 platform support file wellsk40 at gmail.com
2010-02-03 16:46   ` Uwe Kleine-König
2010-01-28  1:43 ` [PATCH 11/13] ARM: LPC32XX: printascii() output and irq support functions wellsk40 at gmail.com
2010-02-03 16:50   ` Uwe Kleine-König
2010-02-03 18:57     ` Kevin Wells
2010-02-03 20:49       ` Uwe Kleine-König
2010-01-28  1:43 ` [PATCH 12/13] ARM: LPC32XX: architecture header files wellsk40 at gmail.com
2010-02-03 17:07   ` Uwe Kleine-König
2010-02-03 19:20     ` Kevin Wells
2010-02-03 20:44       ` Uwe Kleine-König
2010-02-03 21:34       ` Russell King - ARM Linux
2010-02-03 22:06         ` Kevin Wells
2010-01-28  1:43 ` [PATCH 13/13] ARM: LPC32XX: Phytec PHY3250 default kernel config (ramdisk) wellsk40 at gmail.com
2010-01-28 11:16 ` LPC32XX architecture files (updated) Luotao Fu
2010-01-28 19:50   ` Kevin Wells
2010-01-28 19:06 ` Wolfram Sang
2010-01-28 19:58   ` Kevin Wells

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.