]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/arm/mach-s3c2412/irq.c
Merge branch 's3c-move' into devel
[linux-2.6-omap-h63xx.git] / arch / arm / mach-s3c2412 / irq.c
index f0d66828f96576768c4f6ab7d0bb696c31489858..6000ca9d18156d6d0c48736e0c3e82bc1905b3a3 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/sysdev.h>
+#include <linux/io.h>
 
-#include <asm/hardware.h>
+#include <mach/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 <mach/regs-irq.h>
+#include <mach/regs-gpio.h>
+#include <mach/regs-power.h>
 
-#include <asm/plat-s3c24xx/cpu.h>
-#include <asm/plat-s3c24xx/irq.h>
-#include <asm/plat-s3c24xx/pm.h>
+#include <plat/cpu.h>
+#include <plat/irq.h>
+#include <plat/pm.h>
+
+#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1)
+#define INTMSK_SUB(start, end) (INTMSK(start, end) << ((start - S3C2410_IRQSUB(0))))
 
 /* 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
@@ -105,6 +109,67 @@ static struct irq_chip s3c2412_irq_eint0t4 = {
        .set_type  = s3c_irqext_type,
 };
 
+#define INTBIT(x)      (1 << ((x) - S3C2410_IRQSUB(0)))
+
+/* CF and SDI sub interrupts */
+
+static void s3c2412_irq_demux_cfsdi(unsigned int irq, struct irq_desc *desc)
+{
+       unsigned int subsrc, submsk;
+
+       subsrc = __raw_readl(S3C2410_SUBSRCPND);
+       submsk = __raw_readl(S3C2410_INTSUBMSK);
+
+       subsrc  &= ~submsk;
+
+       if (subsrc & INTBIT(IRQ_S3C2412_SDI))
+               generic_handle_irq(IRQ_S3C2412_SDI);
+
+       if (subsrc & INTBIT(IRQ_S3C2412_CF))
+               generic_handle_irq(IRQ_S3C2412_CF);
+}
+
+#define INTMSK_CFSDI   (1UL << (IRQ_S3C2412_CFSDI - IRQ_EINT0))
+#define SUBMSK_CFSDI   INTMSK_SUB(IRQ_S3C2412_SDI, IRQ_S3C2412_CF)
+
+static void s3c2412_irq_cfsdi_mask(unsigned int irqno)
+{
+       s3c_irqsub_mask(irqno, INTMSK_CFSDI, SUBMSK_CFSDI);
+}
+
+static void s3c2412_irq_cfsdi_unmask(unsigned int irqno)
+{
+       s3c_irqsub_unmask(irqno, INTMSK_CFSDI);
+}
+
+static void s3c2412_irq_cfsdi_ack(unsigned int irqno)
+{
+       s3c_irqsub_maskack(irqno, INTMSK_CFSDI, SUBMSK_CFSDI);
+}
+
+static struct irq_chip s3c2412_irq_cfsdi = {
+       .name           = "s3c2412-cfsdi",
+       .ack            = s3c2412_irq_cfsdi_ack,
+       .mask           = s3c2412_irq_cfsdi_mask,
+       .unmask         = s3c2412_irq_cfsdi_unmask,
+};
+
+static int s3c2412_irq_rtc_wake(unsigned int irqno, unsigned int state)
+{
+       unsigned long pwrcfg;
+
+       pwrcfg = __raw_readl(S3C2412_PWRCFG);
+       if (state)
+               pwrcfg &= ~S3C2412_PWRCFG_RTC_MASKIRQ;
+       else
+               pwrcfg |= S3C2412_PWRCFG_RTC_MASKIRQ;
+       __raw_writel(pwrcfg, S3C2412_PWRCFG);
+
+       return s3c_irq_chip.set_wake(irqno, state);
+}
+
+static struct irq_chip s3c2412_irq_rtc_chip;
+
 static int s3c2412_irq_add(struct sys_device *sysdev)
 {
        unsigned int irqno;
@@ -115,6 +180,23 @@ static int s3c2412_irq_add(struct sys_device *sysdev)
                set_irq_flags(irqno, IRQF_VALID);
        }
 
+       /* add demux support for CF/SDI */
+
+       set_irq_chained_handler(IRQ_S3C2412_CFSDI, s3c2412_irq_demux_cfsdi);
+
+       for (irqno = IRQ_S3C2412_SDI; irqno <= IRQ_S3C2412_CF; irqno++) {
+               set_irq_chip(irqno, &s3c2412_irq_cfsdi);
+               set_irq_handler(irqno, handle_level_irq);
+               set_irq_flags(irqno, IRQF_VALID);
+       }
+
+       /* change RTC IRQ's set wake method */
+
+       s3c2412_irq_rtc_chip = s3c_irq_chip;
+       s3c2412_irq_rtc_chip.set_wake = s3c2412_irq_rtc_wake;
+
+       set_irq_chip(IRQ_RTC, &s3c2412_irq_rtc_chip);
+
        return 0;
 }