Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+33 −16
Original line number Diff line number Diff line
@@ -194,10 +194,6 @@ static struct irqchip s3c_irq_chip = {
	.set_wake  = s3c_irq_wake
};

/* S3C2410_EINTMASK
 * S3C2410_EINTPEND
 */

static void
s3c_irqext_mask(unsigned int irqno)
{
@@ -205,9 +201,9 @@ s3c_irqext_mask(unsigned int irqno)

	irqno -= EXTINT_OFF;

	mask = __raw_readl(S3C2410_EINTMASK);
	mask = __raw_readl(S3C24XX_EINTMASK);
	mask |= ( 1UL << irqno);
	__raw_writel(mask, S3C2410_EINTMASK);
	__raw_writel(mask, S3C24XX_EINTMASK);

	if (irqno <= (IRQ_EINT7 - EXTINT_OFF)) {
		/* check to see if all need masking */
@@ -232,11 +228,11 @@ s3c_irqext_ack(unsigned int irqno)
	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;

	/* not sure if we should be acking the parent irq... */
@@ -257,9 +253,9 @@ s3c_irqext_unmask(unsigned int irqno)

	irqno -= EXTINT_OFF;

	mask = __raw_readl(S3C2410_EINTMASK);
	mask = __raw_readl(S3C24XX_EINTMASK);
	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);
}
@@ -572,6 +568,23 @@ s3c_irq_demux_uart2(unsigned int irq,
	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
 *
@@ -591,12 +604,12 @@ void __init s3c24xx_init_irq(void)

	last = 0;
	for (i = 0; i < 4; i++) {
		pend = __raw_readl(S3C2410_EINTPEND);
		pend = __raw_readl(S3C24XX_EINTPEND);

		if (pend == 0 || pend == last)
			break;

		__raw_writel(pend, S3C2410_EINTPEND);
		__raw_writel(pend, S3C24XX_EINTPEND);
		printk("irq: clearing pending ext status %08x\n", (int)pend);
		last = pend;
	}
@@ -630,12 +643,14 @@ void __init s3c24xx_init_irq(void)

	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 */

		switch (irqno) {
			/* deal with the special IRQs (cascaded) */

		case IRQ_EINT4t7:
		case IRQ_EINT8t23:
		case IRQ_UART0:
		case IRQ_UART1:
		case IRQ_UART2:
@@ -659,12 +674,14 @@ void __init s3c24xx_init_irq(void)

	/* 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_UART1, s3c_irq_demux_uart1);
	set_irq_chained_handler(IRQ_UART2, s3c_irq_demux_uart2);
	set_irq_chained_handler(IRQ_ADCPARENT, s3c_irq_demux_adc);


	/* external interrupts */

	for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) {
+7 −23
Original line number Diff line number Diff line
@@ -18,8 +18,6 @@

#define INTPND		(0x10)
#define INTOFFSET	(0x14)
#define EXTINTPEND	(0xa8)
#define EXTINTMASK	(0xa4)

#include <asm/hardware.h>
#include <asm/arch/irqs.h>
@@ -28,37 +26,23 @@

		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

		ldr	\irqstat, [ \base, #INTPND ]
		teq	\irqstat, #0
		beq	1002f
		ldr	\irqnr, [ \base, #INTOFFSET ]
		mov	\tmp, #1
		tst	\irqstat, \tmp, lsl \irqnr
		addne	\irqnr, \irqnr, #IRQ_EINT0
		bne	1001f

		@@ the number specified is not a valid irq, so try
		@@ and work it out for ourselves

		mov	\irqnr, #IRQ_EINT0		@@ 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)
		mov	\irqnr, #0		@@ start here

		@@ work out which irq (if any) we got
3000:

		movs	\tmp, \irqstat, lsl#16
		addeq	\irqnr, \irqnr, #16
		moveq	\irqstat, \irqstat, lsr#16
@@ -75,9 +59,9 @@
		addeq	\irqnr, \irqnr, #1

		@@ we have the value
		movs	\irqnr, \irqnr

1001:
		adds	\irqnr, \irqnr, #IRQ_EINT0
1002:
		@@ exit here, Z flag unset if IRQ

	.endm
+6 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@

#define S3C2410_IRQREG(x)   ((x) + S3C24XX_VA_IRQ)
#define S3C2410_EINTREG(x)  ((x) + S3C24XX_VA_GPIO)
#define S3C24XX_EINTREG(x)  ((x) + S3C24XX_VA_GPIO2)

#define S3C2410_SRCPND	       S3C2410_IRQREG(0x000)
#define S3C2410_INTMOD	       S3C2410_IRQREG(0x004)
@@ -40,5 +41,10 @@

#define S3C2410_EINTMASK       S3C2410_EINTREG(0x0A4)
#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 */