summaryrefslogtreecommitdiff
path: root/arch/arm/plat-s3c24xx/irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-s3c24xx/irq.c')
-rw-r--r--arch/arm/plat-s3c24xx/irq.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/arch/arm/plat-s3c24xx/irq.c b/arch/arm/plat-s3c24xx/irq.c
index 963f7a4f26f2..a5040b163c18 100644
--- a/arch/arm/plat-s3c24xx/irq.c
+++ b/arch/arm/plat-s3c24xx/irq.c
@@ -253,6 +253,9 @@ s3c_irqext_type(unsigned int irq, unsigned int type)
void __iomem *gpcon_reg;
unsigned long gpcon_offset, extint_offset;
unsigned long newvalue = 0, value;
+#if defined(CONFIG_CPU_S3C2443)
+ unsigned int t;
+#endif
if ((irq >= IRQ_EINT0) && (irq <= IRQ_EINT3))
{
@@ -322,6 +325,49 @@ s3c_irqext_type(unsigned int irq, unsigned int type)
}
value = __raw_readl(extint_reg);
+
+ /* According to Samsung's document 'S3C2443 guide to extra gpio'
+ * several registers (including EXTINT0-2) must use a precompiled
+ * function for read access. We don't have the original code but
+ * we have seen the following behavior in U-Boot:
+ * EXTINT0:
+ * 1. Read values are given in big endian (at nibble level):
+ * a read value of 0x00001234 is really 0x43210000.
+ * 2. The read value does not return the LSB:
+ * after writing 0xffffffff value read is 0x7fffffff.
+ * EXTINT1/2:
+ * 1. Read values are given in big endian (at nibble level)
+ * and bits at nibble level suffer a 1 bit rotation to the left:
+ * after writing 0x12488822 value read is 0x44111842
+ */
+#if defined(CONFIG_CPU_S3C2443)
+ t = (value & 0x0000000f) << 28;
+ t |= (value & 0x000000f0) << 20;
+ t |= (value & 0x00000f00) << 12;
+ t |= (value & 0x0000f000) << 4;
+ t |= (value & 0x000f0000) >> 4;
+ t |= (value & 0x00f00000) >> 12;
+ t |= (value & 0x0f000000) >> 20;
+ t |= (value & 0xf0000000) >> 28;
+ value = t;
+
+ if (S3C24XX_EXTINT1 == extint_reg ||
+ S3C24XX_EXTINT2 == extint_reg) {
+ /* Swap bits in nibbles */
+ unsigned char old_n, new_n;
+ int i;
+
+ t = 0;
+ for (i=0; i < 8; i++) {
+ old_n = (value & (0xf << (4*i))) >> (4*i);
+ new_n = ((old_n & 0xe) >> 1);
+ if (old_n & 0x1)
+ new_n |= 0x8;
+ t |= new_n << (4*i);
+ }
+ value = t;
+ }
+#endif /* CONFIG_CPU_S3C2443 */
value = (value & ~(7 << extint_offset)) | (newvalue << extint_offset);
__raw_writel(value, extint_reg);
@@ -729,7 +775,6 @@ void __init s3c24xx_init_irq(void)
}
/* setup the cascade irq handlers */
-
set_irq_chained_handler(IRQ_EINT4t7, s3c_irq_demux_extint4t7);
set_irq_chained_handler(IRQ_EINT8t23, s3c_irq_demux_extint8);
@@ -786,5 +831,10 @@ void __init s3c24xx_init_irq(void)
set_irq_flags(irqno, IRQF_VALID);
}
+ /* Register CF/ATA interrupt */
+ set_irq_chip(IRQ_S3C2443_CFCON, &s3c_irq_level_chip);
+ set_irq_handler(IRQ_S3C2443_CFCON, handle_level_irq);
+ set_irq_flags(IRQ_S3C2443_CFCON, IRQF_VALID);
+
irqdbf("s3c2410: registered interrupt handlers\n");
}