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