[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: Ben Dooks <ben-linux@fluff.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
This commit is contained in:
parent
22346aea8d
commit
a019f4a9a7
3 changed files with 46 additions and 39 deletions
|
@ -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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
/* 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 @@
|
||||||
|
|
||||||
#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 @@
|
||||||
|
|
||||||
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 @@
|
||||||
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 @@
|
||||||
|
|
||||||
#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 @@
|
||||||
|
|
||||||
#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 */
|
||||||
|
|
Loading…
Reference in a new issue