Commit a019f4a9 authored by Ben Dooks's avatar Ben Dooks Committed by Russell King

[ARM] 3645/1: S3C2412: irq support for external interrupts

Patch from Ben Dooks

Move the decoding of the IRQ_EXT4 and above out of
the entry macro, and into an chained irq handler
as the EXTINT registers move depending on the CPU
being used.
Signed-off-by: default avatarBen Dooks <ben-linux@fluff.org>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 22346aea
...@@ -191,13 +191,9 @@ static struct irqchip s3c_irq_chip = { ...@@ -191,13 +191,9 @@ static struct irqchip s3c_irq_chip = {
.ack = s3c_irq_ack, .ack = s3c_irq_ack,
.mask = s3c_irq_mask, .mask = s3c_irq_mask,
.unmask = s3c_irq_unmask, .unmask = s3c_irq_unmask,
.set_wake = s3c_irq_wake .set_wake = s3c_irq_wake
}; };
/* S3C2410_EINTMASK
* S3C2410_EINTPEND
*/
static void static void
s3c_irqext_mask(unsigned int irqno) s3c_irqext_mask(unsigned int irqno)
{ {
...@@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno) ...@@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno)
irqno -= EXTINT_OFF; irqno -= EXTINT_OFF;
mask = __raw_readl(S3C2410_EINTMASK); mask = __raw_readl(S3C24XX_EINTMASK);
mask |= ( 1UL << irqno); mask |= ( 1UL << irqno);
__raw_writel(mask, S3C2410_EINTMASK); __raw_writel(mask, S3C24XX_EINTMASK);
if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) { if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) {
/* check to see if all need masking */ /* check to see if all need masking */
...@@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno) ...@@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno)
bit = 1UL << (irqno - EXTINT_OFF); bit = 1UL << (irqno - EXTINT_OFF);
mask = __raw_readl(S3C2410_EINTMASK); mask = __raw_readl(S3C24XX_EINTMASK);
__raw_writel(bit, S3C2410_EINTPEND); __raw_writel(bit, S3C24XX_EINTPEND);
req = __raw_readl(S3C2410_EINTPEND); req = __raw_readl(S3C24XX_EINTPEND);
req &= ~mask; req &= ~mask;
/* not sure if we should be acking the parent irq... */ /* not sure if we should be acking the parent irq... */
...@@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno) ...@@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno)
irqno -= EXTINT_OFF; irqno -= EXTINT_OFF;
mask = __raw_readl(S3C2410_EINTMASK); mask = __raw_readl(S3C24XX_EINTMASK);
mask &= ~( 1UL << irqno); mask &= ~( 1UL << irqno);
__raw_writel(mask, S3C2410_EINTMASK); __raw_writel(mask, S3C24XX_EINTMASK);
s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23); s3c_irq_unmask((irqno <= (IRQ_EINT7 - EXTINT_OFF)) ? IRQ_EINT4t7 : IRQ_EINT8t23);
} }
...@@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq, ...@@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq,
s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs); s3c_irq_demux_uart(IRQ_S3CUART_RX2, regs);
} }
static void
s3c_irq_demux_extint(unsigned int irq,
struct irqdesc *desc,
struct pt_regs *regs)
{
unsigned long eintpnd = __raw_readl(S3C24XX_EINTPEND);
unsigned long eintmsk = __raw_readl(S3C24XX_EINTMASK);
eintpnd &= ~eintmsk;
if (eintpnd) {
irq = fls(eintpnd);
irq += (IRQ_EINT4 - (4 + 1));
desc_handle_irq(irq, irq_desc + irq, regs);
}
}
/* s3c24xx_init_irq /* s3c24xx_init_irq
* *
...@@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void) ...@@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void)
last = 0; last = 0;
for (i = 0; i < 4; i++) { for (i = 0; i < 4; i++) {
pend = __raw_readl(S3C2410_EINTPEND); pend = __raw_readl(S3C24XX_EINTPEND);
if (pend == 0 || pend == last) if (pend == 0 || pend == last)
break; break;
__raw_writel(pend, S3C2410_EINTPEND); __raw_writel(pend, S3C24XX_EINTPEND);
printk("irq: clearing pending ext status %08x\n", (int)pend); printk("irq: clearing pending ext status %08x\n", (int)pend);
last = pend; last = pend;
} }
...@@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void) ...@@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void)
irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n"); irqdbf("s3c2410_init_irq: registering s3c2410 interrupt handlers\n");
for (irqno = IRQ_BATT_FLT; irqno <= IRQ_ADCPARENT; irqno++) { for (irqno = IRQ_EINT4t7; irqno <= IRQ_ADCPARENT; irqno++) {
/* set all the s3c2410 internal irqs */ /* set all the s3c2410 internal irqs */
switch (irqno) { switch (irqno) {
/* deal with the special IRQs (cascaded) */ /* deal with the special IRQs (cascaded) */
case IRQ_EINT4t7:
case IRQ_EINT8t23:
case IRQ_UART0: case IRQ_UART0:
case IRQ_UART1: case IRQ_UART1:
case IRQ_UART2: case IRQ_UART2:
...@@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void) ...@@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void)
/* setup the cascade irq handlers */ /* setup the cascade irq handlers */
set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint);
set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0); set_irq_chained_handler(IRQ_UART0, s3c_irq_demux_uart0);
set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1); set_irq_chained_handler(IRQ_UART1, s3c_irq_demux_uart1);
set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2); set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc); set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);
/* external interrupts */ /* external interrupts */
for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
......
...@@ -18,8 +18,6 @@ ...@@ -18,8 +18,6 @@
#define INTPND (0x10) #define INTPND (0x10)
#define INTOFFSET (0x14) #define INTOFFSET (0x14)
#define EXTINTPEND (0xa8)
#define EXTINTMASK (0xa4)
#include <asm/hardware.h> #include <asm/hardware.h>
#include <asm/arch/irqs.h> #include <asm/arch/irqs.h>
...@@ -28,37 +26,23 @@ ...@@ -28,37 +26,23 @@
mov \base, #S3C24XX_VA_IRQ mov \base, #S3C24XX_VA_IRQ
ldr \irqstat, [ \base, #INTPND]
bics \irqnr, \irqstat, #3<<4 @@ only an GPIO IRQ
beq 2000f
@@ try the interrupt offset register, since it is there @@ try the interrupt offset register, since it is there
ldr \irqstat, [ \base, #INTPND ]
teq \irqstat, #0
beq 1002f
ldr \irqnr, [ \base, #INTOFFSET ] ldr \irqnr, [ \base, #INTOFFSET ]
mov \tmp, #1 mov \tmp, #1
tst \irqstat, \tmp, lsl \irqnr tst \irqstat, \tmp, lsl \irqnr
addne \irqnr, \irqnr, #IRQ_EINT0
bne 1001f bne 1001f
@@ the number specified is not a valid irq, so try @@ the number specified is not a valid irq, so try
@@ and work it out for ourselves @@ and work it out for ourselves
mov \irqnr, #IRQ_EINT0 @@ start here mov \irqnr, #0 @@ start here
b 3000f
2000:
@@ load the GPIO interrupt register, and check it
add \tmp, \base, #S3C24XX_VA_GPIO - S3C24XX_VA_IRQ
ldr \irqstat, [ \tmp, # EXTINTPEND ]
ldr \irqnr, [ \tmp, # EXTINTMASK ]
bics \irqstat, \irqstat, \irqnr
beq 1001f
mov \irqnr, #(IRQ_EINT4 - 4)
@@ work out which irq (if any) we got @@ work out which irq (if any) we got
3000:
movs \tmp, \irqstat, lsl#16 movs \tmp, \irqstat, lsl#16
addeq \irqnr, \irqnr, #16 addeq \irqnr, \irqnr, #16
moveq \irqstat, \irqstat, lsr#16 moveq \irqstat, \irqstat, lsr#16
...@@ -75,9 +59,9 @@ ...@@ -75,9 +59,9 @@
addeq \irqnr, \irqnr, #1 addeq \irqnr, \irqnr, #1
@@ we have the value @@ we have the value
movs \irqnr, \irqnr
1001: 1001:
adds \irqnr, \irqnr, #IRQ_EINT0
1002:
@@ exit here, Z flag unset if IRQ @@ exit here, Z flag unset if IRQ
.endm .endm
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#define S3C2410_IRQREG(x) ((x) + S3C24XX_VA_IRQ) #define S3C2410_IRQREG(x) ((x) + S3C24XX_VA_IRQ)
#define S3C2410_EINTREG(x) ((x) + S3C24XX_VA_GPIO) #define S3C2410_EINTREG(x) ((x) + S3C24XX_VA_GPIO)
#define S3C24XX_EINTREG(x) ((x) + S3C24XX_VA_GPIO2)
#define S3C2410_SRCPND S3C2410_IRQREG(0x000) #define S3C2410_SRCPND S3C2410_IRQREG(0x000)
#define S3C2410_INTMOD S3C2410_IRQREG(0x004) #define S3C2410_INTMOD S3C2410_IRQREG(0x004)
...@@ -40,5 +41,10 @@ ...@@ -40,5 +41,10 @@
#define S3C2410_EINTMASK S3C2410_EINTREG(0x0A4) #define S3C2410_EINTMASK S3C2410_EINTREG(0x0A4)
#define S3C2410_EINTPEND S3C2410_EINTREG(0X0A8) #define S3C2410_EINTPEND S3C2410_EINTREG(0X0A8)
#define S3C2412_EINTMASK S3C2410_EINTREG(0x0B4)
#define S3C2412_EINTPEND S3C2410_EINTREG(0X0B8)
#define S3C24XX_EINTMASK S3C24XX_EINTREG(0x0A4)
#define S3C24XX_EINTPEND S3C24XX_EINTREG(0X0A8)
#endif /* ___ASM_ARCH_REGS_IRQ_H */ #endif /* ___ASM_ARCH_REGS_IRQ_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment