1/* linux/arch/arm/mach-s3c2412/irq.c 2 * 3 * Copyright (c) 2006 Simtec Electronics 4 * Ben Dooks <ben@simtec.co.uk> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 * 20*/ 21 22#include <linux/init.h> 23#include <linux/module.h> 24#include <linux/interrupt.h> 25#include <linux/ioport.h> 26#include <linux/sysdev.h> 27 28#include <asm/hardware.h> 29#include <asm/irq.h> 30#include <asm/io.h> 31 32#include <asm/mach/irq.h> 33 34#include <asm/arch/regs-irq.h> 35#include <asm/arch/regs-gpio.h> 36 37#include <asm/plat-s3c24xx/cpu.h> 38#include <asm/plat-s3c24xx/irq.h> 39#include <asm/plat-s3c24xx/pm.h> 40 41/* the s3c2412 changes the behaviour of IRQ_EINT0 through IRQ_EINT3 by 42 * having them turn up in both the INT* and the EINT* registers. Whilst 43 * both show the status, they both now need to be acked when the IRQs 44 * go off. 45*/ 46 47static void 48s3c2412_irq_mask(unsigned int irqno) 49{ 50 unsigned long bitval = 1UL << (irqno - IRQ_EINT0); 51 unsigned long mask; 52 53 mask = __raw_readl(S3C2410_INTMSK); 54 __raw_writel(mask | bitval, S3C2410_INTMSK); 55 56 mask = __raw_readl(S3C2412_EINTMASK); 57 __raw_writel(mask | bitval, S3C2412_EINTMASK); 58} 59 60static inline void 61s3c2412_irq_ack(unsigned int irqno) 62{ 63 unsigned long bitval = 1UL << (irqno - IRQ_EINT0); 64 65 __raw_writel(bitval, S3C2412_EINTPEND); 66 __raw_writel(bitval, S3C2410_SRCPND); 67 __raw_writel(bitval, S3C2410_INTPND); 68} 69 70static inline void 71s3c2412_irq_maskack(unsigned int irqno) 72{ 73 unsigned long bitval = 1UL << (irqno - IRQ_EINT0); 74 unsigned long mask; 75 76 mask = __raw_readl(S3C2410_INTMSK); 77 __raw_writel(mask|bitval, S3C2410_INTMSK); 78 79 mask = __raw_readl(S3C2412_EINTMASK); 80 __raw_writel(mask | bitval, S3C2412_EINTMASK); 81 82 __raw_writel(bitval, S3C2412_EINTPEND); 83 __raw_writel(bitval, S3C2410_SRCPND); 84 __raw_writel(bitval, S3C2410_INTPND); 85} 86 87static void 88s3c2412_irq_unmask(unsigned int irqno) 89{ 90 unsigned long bitval = 1UL << (irqno - IRQ_EINT0); 91 unsigned long mask; 92 93 mask = __raw_readl(S3C2412_EINTMASK); 94 __raw_writel(mask & ~bitval, S3C2412_EINTMASK); 95 96 mask = __raw_readl(S3C2410_INTMSK); 97 __raw_writel(mask & ~bitval, S3C2410_INTMSK); 98} 99 100static struct irq_chip s3c2412_irq_eint0t4 = { 101 .ack = s3c2412_irq_ack, 102 .mask = s3c2412_irq_mask, 103 .unmask = s3c2412_irq_unmask, 104 .set_wake = s3c_irq_wake, 105 .set_type = s3c_irqext_type, 106}; 107 108static int s3c2412_irq_add(struct sys_device *sysdev) 109{ 110 unsigned int irqno; 111 112 for (irqno = IRQ_EINT0; irqno <= IRQ_EINT3; irqno++) { 113 set_irq_chip(irqno, &s3c2412_irq_eint0t4); 114 set_irq_handler(irqno, handle_edge_irq); 115 set_irq_flags(irqno, IRQF_VALID); 116 } 117 118 return 0; 119} 120 121static struct sysdev_driver s3c2412_irq_driver = { 122 .add = s3c2412_irq_add, 123 .suspend = s3c24xx_irq_suspend, 124 .resume = s3c24xx_irq_resume, 125}; 126 127static int s3c2412_irq_init(void) 128{ 129 return sysdev_driver_register(&s3c2412_sysclass, &s3c2412_irq_driver); 130} 131 132arch_initcall(s3c2412_irq_init); 133