diff --git a/arch/arm/mach-s3c2410/Makefile b/arch/arm/mach-s3c2410/Makefile index 273e05f2b8d..0eadec91621 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 6822dc7f779..cd6139b3599 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 4abf0ca14e0..f7cc4c983de 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 00000000000..c80ec93dfea --- /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 + * + * 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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#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);