1/* linux/arch/arm/mach-s3c2443/irq.c 2 * 3 * Copyright (c) 2007 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/pm.h> 39#include <asm/plat-s3c24xx/irq.h> 40 41#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) 42 43static inline void s3c2443_irq_demux(unsigned int irq, unsigned int len) 44{ 45 unsigned int subsrc, submsk; 46 unsigned int end; 47 struct irq_desc *mydesc; 48 49 /* read the current pending interrupts, and the mask 50 * for what it is available */ 51 52 subsrc = __raw_readl(S3C2410_SUBSRCPND); 53 submsk = __raw_readl(S3C2410_INTSUBMSK); 54 55 subsrc &= ~submsk; 56 subsrc >>= (irq - S3C2410_IRQSUB(0)); 57 subsrc &= (1 << len)-1; 58 59 end = len + irq; 60 mydesc = irq_desc + irq; 61 62 for (; irq < end && subsrc; irq++) { 63 if (subsrc & 1) 64 desc_handle_irq(irq, mydesc); 65 66 mydesc++; 67 subsrc >>= 1; 68 } 69} 70 71/* WDT/AC97 sub interrupts */ 72 73static void s3c2443_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc) 74{ 75 s3c2443_irq_demux(IRQ_S3C2443_WDT, 4); 76} 77 78#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0)) 79#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97) 80 81static void s3c2443_irq_wdtac97_mask(unsigned int irqno) 82{ 83 s3c_irqsub_mask(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); 84} 85 86static void s3c2443_irq_wdtac97_unmask(unsigned int irqno) 87{ 88 s3c_irqsub_unmask(irqno, INTMSK_WDTAC97); 89} 90 91static void s3c2443_irq_wdtac97_ack(unsigned int irqno) 92{ 93 s3c_irqsub_maskack(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); 94} 95 96static struct irq_chip s3c2443_irq_wdtac97 = { 97 .mask = s3c2443_irq_wdtac97_mask, 98 .unmask = s3c2443_irq_wdtac97_unmask, 99 .ack = s3c2443_irq_wdtac97_ack, 100}; 101 102 103/* LCD sub interrupts */ 104 105static void s3c2443_irq_demux_lcd(unsigned int irq, struct irq_desc *desc) 106{ 107 s3c2443_irq_demux(IRQ_S3C2443_LCD1, 4); 108} 109 110#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) 111#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4) 112 113static void s3c2443_irq_lcd_mask(unsigned int irqno) 114{ 115 s3c_irqsub_mask(irqno, INTMSK_LCD, SUBMSK_LCD); 116} 117 118static void s3c2443_irq_lcd_unmask(unsigned int irqno) 119{ 120 s3c_irqsub_unmask(irqno, INTMSK_LCD); 121} 122 123static void s3c2443_irq_lcd_ack(unsigned int irqno) 124{ 125 s3c_irqsub_maskack(irqno, INTMSK_LCD, SUBMSK_LCD); 126} 127 128static struct irq_chip s3c2443_irq_lcd = { 129 .mask = s3c2443_irq_lcd_mask, 130 .unmask = s3c2443_irq_lcd_unmask, 131 .ack = s3c2443_irq_lcd_ack, 132}; 133 134 135/* DMA sub interrupts */ 136 137static void s3c2443_irq_demux_dma(unsigned int irq, struct irq_desc *desc) 138{ 139 s3c2443_irq_demux(IRQ_S3C2443_DMA0, 6); 140} 141 142#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0)) 143#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5) 144 145 146static void s3c2443_irq_dma_mask(unsigned int irqno) 147{ 148 s3c_irqsub_mask(irqno, INTMSK_DMA, SUBMSK_DMA); 149} 150 151static void s3c2443_irq_dma_unmask(unsigned int irqno) 152{ 153 s3c_irqsub_unmask(irqno, INTMSK_DMA); 154} 155 156static void s3c2443_irq_dma_ack(unsigned int irqno) 157{ 158 s3c_irqsub_maskack(irqno, INTMSK_DMA, SUBMSK_DMA); 159} 160 161static struct irq_chip s3c2443_irq_dma = { 162 .mask = s3c2443_irq_dma_mask, 163 .unmask = s3c2443_irq_dma_unmask, 164 .ack = s3c2443_irq_dma_ack, 165}; 166 167 168/* UART3 sub interrupts */ 169 170static void s3c2443_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) 171{ 172 s3c2443_irq_demux(IRQ_S3C2443_UART3, 3); 173} 174 175#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) 176#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) 177 178 179static void s3c2443_irq_uart3_mask(unsigned int irqno) 180{ 181 s3c_irqsub_mask(irqno, INTMSK_UART3, SUBMSK_UART3); 182} 183 184static void s3c2443_irq_uart3_unmask(unsigned int irqno) 185{ 186 s3c_irqsub_unmask(irqno, INTMSK_UART3); 187} 188 189static void s3c2443_irq_uart3_ack(unsigned int irqno) 190{ 191 s3c_irqsub_maskack(irqno, INTMSK_UART3, SUBMSK_UART3); 192} 193 194static struct irq_chip s3c2443_irq_uart3 = { 195 .mask = s3c2443_irq_uart3_mask, 196 .unmask = s3c2443_irq_uart3_unmask, 197 .ack = s3c2443_irq_uart3_ack, 198}; 199 200 201/* CAM sub interrupts */ 202 203static void s3c2443_irq_demux_cam(unsigned int irq, struct irq_desc *desc) 204{ 205 s3c2443_irq_demux(IRQ_S3C2440_CAM_C, 4); 206} 207 208#define INTMSK_CAM (1UL << (IRQ_CAM - IRQ_EINT0)) 209#define SUBMSK_CAM INTMSK(IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P) 210 211static void s3c2443_irq_cam_mask(unsigned int irqno) 212{ 213 s3c_irqsub_mask(irqno, INTMSK_CAM, SUBMSK_CAM); 214} 215 216static void s3c2443_irq_cam_unmask(unsigned int irqno) 217{ 218 s3c_irqsub_unmask(irqno, INTMSK_CAM); 219} 220 221static void s3c2443_irq_cam_ack(unsigned int irqno) 222{ 223 s3c_irqsub_maskack(irqno, INTMSK_CAM, SUBMSK_CAM); 224} 225 226static struct irq_chip s3c2443_irq_cam = { 227 .mask = s3c2443_irq_cam_mask, 228 .unmask = s3c2443_irq_cam_unmask, 229 .ack = s3c2443_irq_cam_ack, 230}; 231 232/* IRQ initialisation code */ 233 234static int __init s3c2443_add_sub(unsigned int base, 235 void (*demux)(unsigned int, 236 struct irq_desc *), 237 struct irq_chip *chip, 238 unsigned int start, unsigned int end) 239{ 240 unsigned int irqno; 241 242 set_irq_chip(base, &s3c_irq_level_chip); 243 set_irq_handler(base, handle_level_irq); 244 set_irq_chained_handler(base, demux); 245 246 for (irqno = start; irqno <= end; irqno++) { 247 set_irq_chip(irqno, chip); 248 set_irq_handler(irqno, handle_level_irq); 249 set_irq_flags(irqno, IRQF_VALID); 250 } 251 252 return 0; 253} 254 255static int s3c2443_irq_add(struct sys_device *sysdev) 256{ 257 printk("S3C2443: IRQ Support\n"); 258 259 s3c2443_add_sub(IRQ_CAM, s3c2443_irq_demux_cam, &s3c2443_irq_cam, 260 IRQ_S3C2440_CAM_C, IRQ_S3C2440_CAM_P); 261 262 s3c2443_add_sub(IRQ_LCD, s3c2443_irq_demux_lcd, &s3c2443_irq_lcd, 263 IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4); 264 265 s3c2443_add_sub(IRQ_S3C2443_DMA, s3c2443_irq_demux_dma, 266 &s3c2443_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5); 267 268 s3c2443_add_sub(IRQ_S3C2443_UART3, s3c2443_irq_demux_uart3, 269 &s3c2443_irq_uart3, 270 IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3); 271 272 s3c2443_add_sub(IRQ_WDT, s3c2443_irq_demux_wdtac97, 273 &s3c2443_irq_wdtac97, 274 IRQ_S3C2443_WDT, IRQ_S3C2443_AC97); 275 276 return 0; 277} 278 279static struct sysdev_driver s3c2443_irq_driver = { 280 .add = s3c2443_irq_add, 281}; 282 283static int s3c2443_irq_init(void) 284{ 285 return sysdev_driver_register(&s3c2443_sysclass, &s3c2443_irq_driver); 286} 287 288arch_initcall(s3c2443_irq_init); 289