1/* linux/arch/arm/mach-s3c2416/irq.c 2 * 3 * Copyright (c) 2009 Yauhen Kharuzhy <jekhor@gmail.com>, 4 * as part of OpenInkpot project 5 * Copyright (c) 2009 Promwad Innovation Company 6 * Yauhen Kharuzhy <yauhen.kharuzhy@promwad.com> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22*/ 23 24#include <linux/init.h> 25#include <linux/module.h> 26#include <linux/interrupt.h> 27#include <linux/ioport.h> 28#include <linux/sysdev.h> 29#include <linux/io.h> 30 31#include <mach/hardware.h> 32#include <asm/irq.h> 33 34#include <asm/mach/irq.h> 35 36#include <mach/regs-irq.h> 37#include <mach/regs-gpio.h> 38 39#include <plat/cpu.h> 40#include <plat/pm.h> 41#include <plat/irq.h> 42 43#define INTMSK(start, end) ((1 << ((end) + 1 - (start))) - 1) 44 45static inline void s3c2416_irq_demux(unsigned int irq, unsigned int len) 46{ 47 unsigned int subsrc, submsk; 48 unsigned int end; 49 50 /* read the current pending interrupts, and the mask 51 * for what it is available */ 52 53 subsrc = __raw_readl(S3C2410_SUBSRCPND); 54 submsk = __raw_readl(S3C2410_INTSUBMSK); 55 56 subsrc &= ~submsk; 57 subsrc >>= (irq - S3C2410_IRQSUB(0)); 58 subsrc &= (1 << len)-1; 59 60 end = len + irq; 61 62 for (; irq < end && subsrc; irq++) { 63 if (subsrc & 1) 64 generic_handle_irq(irq); 65 66 subsrc >>= 1; 67 } 68} 69 70/* WDT/AC97 sub interrupts */ 71 72static void s3c2416_irq_demux_wdtac97(unsigned int irq, struct irq_desc *desc) 73{ 74 s3c2416_irq_demux(IRQ_S3C2443_WDT, 4); 75} 76 77#define INTMSK_WDTAC97 (1UL << (IRQ_WDT - IRQ_EINT0)) 78#define SUBMSK_WDTAC97 INTMSK(IRQ_S3C2443_WDT, IRQ_S3C2443_AC97) 79 80static void s3c2416_irq_wdtac97_mask(unsigned int irqno) 81{ 82 s3c_irqsub_mask(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); 83} 84 85static void s3c2416_irq_wdtac97_unmask(unsigned int irqno) 86{ 87 s3c_irqsub_unmask(irqno, INTMSK_WDTAC97); 88} 89 90static void s3c2416_irq_wdtac97_ack(unsigned int irqno) 91{ 92 s3c_irqsub_maskack(irqno, INTMSK_WDTAC97, SUBMSK_WDTAC97); 93} 94 95static struct irq_chip s3c2416_irq_wdtac97 = { 96 .mask = s3c2416_irq_wdtac97_mask, 97 .unmask = s3c2416_irq_wdtac97_unmask, 98 .ack = s3c2416_irq_wdtac97_ack, 99}; 100 101 102/* LCD sub interrupts */ 103 104static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc) 105{ 106 s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4); 107} 108 109#define INTMSK_LCD (1UL << (IRQ_LCD - IRQ_EINT0)) 110#define SUBMSK_LCD INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4) 111 112static void s3c2416_irq_lcd_mask(unsigned int irqno) 113{ 114 s3c_irqsub_mask(irqno, INTMSK_LCD, SUBMSK_LCD); 115} 116 117static void s3c2416_irq_lcd_unmask(unsigned int irqno) 118{ 119 s3c_irqsub_unmask(irqno, INTMSK_LCD); 120} 121 122static void s3c2416_irq_lcd_ack(unsigned int irqno) 123{ 124 s3c_irqsub_maskack(irqno, INTMSK_LCD, SUBMSK_LCD); 125} 126 127static struct irq_chip s3c2416_irq_lcd = { 128 .mask = s3c2416_irq_lcd_mask, 129 .unmask = s3c2416_irq_lcd_unmask, 130 .ack = s3c2416_irq_lcd_ack, 131}; 132 133 134/* DMA sub interrupts */ 135 136static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc) 137{ 138 s3c2416_irq_demux(IRQ_S3C2443_DMA0, 6); 139} 140 141#define INTMSK_DMA (1UL << (IRQ_S3C2443_DMA - IRQ_EINT0)) 142#define SUBMSK_DMA INTMSK(IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5) 143 144 145static void s3c2416_irq_dma_mask(unsigned int irqno) 146{ 147 s3c_irqsub_mask(irqno, INTMSK_DMA, SUBMSK_DMA); 148} 149 150static void s3c2416_irq_dma_unmask(unsigned int irqno) 151{ 152 s3c_irqsub_unmask(irqno, INTMSK_DMA); 153} 154 155static void s3c2416_irq_dma_ack(unsigned int irqno) 156{ 157 s3c_irqsub_maskack(irqno, INTMSK_DMA, SUBMSK_DMA); 158} 159 160static struct irq_chip s3c2416_irq_dma = { 161 .mask = s3c2416_irq_dma_mask, 162 .unmask = s3c2416_irq_dma_unmask, 163 .ack = s3c2416_irq_dma_ack, 164}; 165 166 167/* UART3 sub interrupts */ 168 169static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc) 170{ 171 s3c2416_irq_demux(IRQ_S3C2443_UART3, 3); 172} 173 174#define INTMSK_UART3 (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0)) 175#define SUBMSK_UART3 (0xf << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0))) 176 177 178static void s3c2416_irq_uart3_mask(unsigned int irqno) 179{ 180 s3c_irqsub_mask(irqno, INTMSK_UART3, SUBMSK_UART3); 181} 182 183static void s3c2416_irq_uart3_unmask(unsigned int irqno) 184{ 185 s3c_irqsub_unmask(irqno, INTMSK_UART3); 186} 187 188static void s3c2416_irq_uart3_ack(unsigned int irqno) 189{ 190 s3c_irqsub_maskack(irqno, INTMSK_UART3, SUBMSK_UART3); 191} 192 193static struct irq_chip s3c2416_irq_uart3 = { 194 .mask = s3c2416_irq_uart3_mask, 195 .unmask = s3c2416_irq_uart3_unmask, 196 .ack = s3c2416_irq_uart3_ack, 197}; 198 199 200/* IRQ initialisation code */ 201 202static int __init s3c2416_add_sub(unsigned int base, 203 void (*demux)(unsigned int, 204 struct irq_desc *), 205 struct irq_chip *chip, 206 unsigned int start, unsigned int end) 207{ 208 unsigned int irqno; 209 210 set_irq_chip(base, &s3c_irq_level_chip); 211 set_irq_handler(base, handle_level_irq); 212 set_irq_chained_handler(base, demux); 213 214 for (irqno = start; irqno <= end; irqno++) { 215 set_irq_chip(irqno, chip); 216 set_irq_handler(irqno, handle_level_irq); 217 set_irq_flags(irqno, IRQF_VALID); 218 } 219 220 return 0; 221} 222 223static int __init s3c2416_irq_add(struct sys_device *sysdev) 224{ 225 printk(KERN_INFO "S3C2416: IRQ Support\n"); 226 227 s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd, 228 IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4); 229 230 s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma, 231 &s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5); 232 233 s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3, 234 &s3c2416_irq_uart3, 235 IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3); 236 237 s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97, 238 &s3c2416_irq_wdtac97, 239 IRQ_S3C2443_WDT, IRQ_S3C2443_AC97); 240 241 return 0; 242} 243 244static struct sysdev_driver s3c2416_irq_driver = { 245 .add = s3c2416_irq_add, 246}; 247 248static int __init s3c2416_irq_init(void) 249{ 250 return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_irq_driver); 251} 252 253arch_initcall(s3c2416_irq_init); 254