diff options
Diffstat (limited to 'arch/arm/mach-s3c2412/irq.c')
-rw-r--r-- | arch/arm/mach-s3c2412/irq.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/arch/arm/mach-s3c2412/irq.c b/arch/arm/mach-s3c2412/irq.c index f0d66828f96..e9d0c769f5d 100644 --- a/arch/arm/mach-s3c2412/irq.c +++ b/arch/arm/mach-s3c2412/irq.c @@ -38,6 +38,9 @@ #include <asm/plat-s3c24xx/irq.h> #include <asm/plat-s3c24xx/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 * both show the status, they both now need to be acked when the IRQs @@ -105,6 +108,51 @@ 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)) + desc_handle_irq(IRQ_S3C2412_SDI, irq_desc + IRQ_S3C2412_SDI); + + if (subsrc & INTBIT(IRQ_S3C2412_CF)) + desc_handle_irq(IRQ_S3C2412_CF, irq_desc + 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_add(struct sys_device *sysdev) { unsigned int irqno; @@ -115,6 +163,16 @@ 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); + } + return 0; } |