diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile
index 273e05f2b8de3adf508d56a8184145f7508813ee..0eadec916214ecde32fa0ed66532d4ee33732276 100644
--- a/arch/arm/mach-s3c2410/Makefile
+++ b/arch/arm/mach-s3c2410/Makefile
@@ -28,6 +28,7 @@ obj-$(CONFIG_PM_SIMTEC)		+= pm-simtec.o
 
 # S3C2412 support
 obj-$(CONFIG_CPU_S3C2412)	+= s3c2412.o
+obj-$(CONFIG_CPU_S3C2412)	+= s3c2412-irq.o
 obj-$(CONFIG_CPU_S3C2412)	+= s3c2412-clock.o
 
 #
diff --git a/arch/arm/mach-s3c2410/irq.c b/arch/arm/mach-s3c2410/irq.c
index 6822dc7f779953f072ab8873fd770bcfcc5e2da3..cd6139b359996ed3dd37528201023b7ed65a3157 100644
--- a/arch/arm/mach-s3c2410/irq.c
+++ b/arch/arm/mach-s3c2410/irq.c
@@ -86,7 +86,7 @@ unsigned long s3c_irqwake_intmask	= 0xffffffffL;
 unsigned long s3c_irqwake_eintallow	= 0x0000fff0L;
 unsigned long s3c_irqwake_eintmask	= 0xffffffffL;
 
-static int
+int
 s3c_irq_wake(unsigned int irqno, unsigned int state)
 {
 	unsigned long irqbit = 1 << (irqno - IRQ_EINT0);
@@ -260,7 +260,7 @@ s3c_irqext_unmask(unsigned int irqno)
 	s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23);
 }
 
-static int
+int
 s3c_irqext_type(unsigned int irq, unsigned int type)
 {
 	void __iomem *extint_reg;
diff --git a/arch/arm/mach-s3c2410/irq.h b/arch/arm/mach-s3c2410/irq.h
index 4abf0ca14e0074b2a6b0b69457b39c8236e61f4a..f7cc4c983de53a9c995794d950940fd60bffdb0c 100644
--- a/arch/arm/mach-s3c2410/irq.h
+++ b/arch/arm/mach-s3c2410/irq.h
@@ -97,3 +97,8 @@ s3c_irqsub_ack(unsigned int irqno, unsigned int parentmask, unsigned int group)
 		__raw_writel(parentmask, S3C2410_INTPND);
 	}
 }
+
+/* exported for use in arch/arm/mach-s3c2410 */
+
+extern int s3c_irq_wake(unsigned int irqno, unsigned int state);
+extern int s3c_irqext_type(unsigned int irq, unsigned int type);
diff --git a/arch/arm/mach-s3c2410/s3c2412-irq.c b/arch/arm/mach-s3c2410/s3c2412-irq.c
new file mode 100644
index 0000000000000000000000000000000000000000..c80ec93dfea968104d1c3ce254c8ae589fd09700
--- /dev/null
+++ b/arch/arm/mach-s3c2410/s3c2412-irq.c
@@ -0,0 +1,130 @@
+/* linux/arch/arm/mach-s3c2412/s3c2412-irq.c
+ *
+ * Copyright (c) 2006 Simtec Electronics
+ *	Ben Dooks <ben@simtec.co.uk>
+ *
+ * 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/module.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/ptrace.h>
+#include <linux/sysdev.h>
+
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include <asm/mach/irq.h>
+
+#include <asm/arch/regs-irq.h>
+#include <asm/arch/regs-gpio.h>
+
+#include "cpu.h"
+#include "irq.h"
+
+/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by
+ * having them turn up in both the INT* and the EINT* registers. Whilst
+ * both show the status, they both now need to be acked when the IRQs
+ * go off.
+*/
+
+static void
+s3c2412_irq_mask(unsigned int irqno)
+{
+	unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+	unsigned long mask;
+
+	mask = __raw_readl(S3C2410_INTMSK);
+	__raw_writel(mask | bitval, S3C2410_INTMSK);
+
+	mask = __raw_readl(S3C2412_EINTMASK);
+	__raw_writel(mask | bitval, S3C2412_EINTMASK);
+}
+
+static inline void
+s3c2412_irq_ack(unsigned int irqno)
+{
+	unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+
+	__raw_writel(bitval, S3C2412_EINTPEND);
+	__raw_writel(bitval, S3C2410_SRCPND);
+	__raw_writel(bitval, S3C2410_INTPND);
+}
+
+static inline void
+s3c2412_irq_maskack(unsigned int irqno)
+{
+	unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+	unsigned long mask;
+
+	mask = __raw_readl(S3C2410_INTMSK);
+	__raw_writel(mask|bitval, S3C2410_INTMSK);
+
+	mask = __raw_readl(S3C2412_EINTMASK);
+	__raw_writel(mask | bitval, S3C2412_EINTMASK);
+
+	__raw_writel(bitval, S3C2412_EINTPEND);
+	__raw_writel(bitval, S3C2410_SRCPND);
+	__raw_writel(bitval, S3C2410_INTPND);
+}
+
+static void
+s3c2412_irq_unmask(unsigned int irqno)
+{
+	unsigned long bitval = 1UL << (irqno - IRQ_EINT0);
+	unsigned long mask;
+
+	mask = __raw_readl(S3C2412_EINTMASK);
+	__raw_writel(mask & ~bitval, S3C2412_EINTMASK);
+
+	mask = __raw_readl(S3C2410_INTMSK);
+	__raw_writel(mask & ~bitval, S3C2410_INTMSK);
+}
+
+static struct irqchip s3c2412_irq_eint0t4 = {
+	.ack	   = s3c2412_irq_ack,
+	.mask	   = s3c2412_irq_mask,
+	.unmask	   = s3c2412_irq_unmask,
+	.set_wake  = s3c_irq_wake,
+	.set_type  = s3c_irqext_type,
+};
+
+static int s3c2412_irq_add(struct sys_device *sysdev)
+{
+	unsigned int irqno;
+
+	for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
+		set_irq_chip(irqno, &s3c2412_irq_eint0t4);
+		set_irq_handler(irqno, do_edge_IRQ);
+		set_irq_flags(irqno, IRQF_VALID);
+	}
+
+	return 0;
+}
+
+static struct sysdev_driver s3c2412_irq_driver = {
+	.add		= s3c2412_irq_add,
+};
+
+static int s3c2412_irq_init(void)
+{
+	return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_irq_driver);
+}
+
+arch_initcall(s3c2412_irq_init);