linux/arch/arm/mach-s3c2416/irq.c
<<
>>
Prefs
   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(struct irq_data *data)
  81{
  82        s3c_irqsub_mask(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
  83}
  84
  85static void s3c2416_irq_wdtac97_unmask(struct irq_data *data)
  86{
  87        s3c_irqsub_unmask(data->irq, INTMSK_WDTAC97);
  88}
  89
  90static void s3c2416_irq_wdtac97_ack(struct irq_data *data)
  91{
  92        s3c_irqsub_maskack(data->irq, INTMSK_WDTAC97, SUBMSK_WDTAC97);
  93}
  94
  95static struct irq_chip s3c2416_irq_wdtac97 = {
  96        .irq_mask       = s3c2416_irq_wdtac97_mask,
  97        .irq_unmask     = s3c2416_irq_wdtac97_unmask,
  98        .irq_ack        = s3c2416_irq_wdtac97_ack,
  99};
 100
 101/* LCD sub interrupts */
 102
 103static void s3c2416_irq_demux_lcd(unsigned int irq, struct irq_desc *desc)
 104{
 105        s3c2416_irq_demux(IRQ_S3C2443_LCD1, 4);
 106}
 107
 108#define INTMSK_LCD      (1UL << (IRQ_LCD - IRQ_EINT0))
 109#define SUBMSK_LCD      INTMSK(IRQ_S3C2443_LCD1, IRQ_S3C2443_LCD4)
 110
 111static void s3c2416_irq_lcd_mask(struct irq_data *data)
 112{
 113        s3c_irqsub_mask(data->irq, INTMSK_LCD, SUBMSK_LCD);
 114}
 115
 116static void s3c2416_irq_lcd_unmask(struct irq_data *data)
 117{
 118        s3c_irqsub_unmask(data->irq, INTMSK_LCD);
 119}
 120
 121static void s3c2416_irq_lcd_ack(struct irq_data *data)
 122{
 123        s3c_irqsub_maskack(data->irq, INTMSK_LCD, SUBMSK_LCD);
 124}
 125
 126static struct irq_chip s3c2416_irq_lcd = {
 127        .irq_mask       = s3c2416_irq_lcd_mask,
 128        .irq_unmask     = s3c2416_irq_lcd_unmask,
 129        .irq_ack        = s3c2416_irq_lcd_ack,
 130};
 131
 132/* DMA sub interrupts */
 133
 134static void s3c2416_irq_demux_dma(unsigned int irq, struct irq_desc *desc)
 135{
 136        s3c2416_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 s3c2416_irq_dma_mask(struct irq_data *data)
 144{
 145        s3c_irqsub_mask(data->irq, INTMSK_DMA, SUBMSK_DMA);
 146}
 147
 148static void s3c2416_irq_dma_unmask(struct irq_data *data)
 149{
 150        s3c_irqsub_unmask(data->irq, INTMSK_DMA);
 151}
 152
 153static void s3c2416_irq_dma_ack(struct irq_data *data)
 154{
 155        s3c_irqsub_maskack(data->irq, INTMSK_DMA, SUBMSK_DMA);
 156}
 157
 158static struct irq_chip s3c2416_irq_dma = {
 159        .irq_mask       = s3c2416_irq_dma_mask,
 160        .irq_unmask     = s3c2416_irq_dma_unmask,
 161        .irq_ack        = s3c2416_irq_dma_ack,
 162};
 163
 164/* UART3 sub interrupts */
 165
 166static void s3c2416_irq_demux_uart3(unsigned int irq, struct irq_desc *desc)
 167{
 168        s3c2416_irq_demux(IRQ_S3C2443_RX3, 3);
 169}
 170
 171#define INTMSK_UART3    (1UL << (IRQ_S3C2443_UART3 - IRQ_EINT0))
 172#define SUBMSK_UART3    (0x7 << (IRQ_S3C2443_RX3 - S3C2410_IRQSUB(0)))
 173
 174static void s3c2416_irq_uart3_mask(struct irq_data *data)
 175{
 176        s3c_irqsub_mask(data->irq, INTMSK_UART3, SUBMSK_UART3);
 177}
 178
 179static void s3c2416_irq_uart3_unmask(struct irq_data *data)
 180{
 181        s3c_irqsub_unmask(data->irq, INTMSK_UART3);
 182}
 183
 184static void s3c2416_irq_uart3_ack(struct irq_data *data)
 185{
 186        s3c_irqsub_maskack(data->irq, INTMSK_UART3, SUBMSK_UART3);
 187}
 188
 189static struct irq_chip s3c2416_irq_uart3 = {
 190        .irq_mask       = s3c2416_irq_uart3_mask,
 191        .irq_unmask     = s3c2416_irq_uart3_unmask,
 192        .irq_ack        = s3c2416_irq_uart3_ack,
 193};
 194
 195/* IRQ initialisation code */
 196
 197static int __init s3c2416_add_sub(unsigned int base,
 198                                   void (*demux)(unsigned int,
 199                                                 struct irq_desc *),
 200                                   struct irq_chip *chip,
 201                                   unsigned int start, unsigned int end)
 202{
 203        unsigned int irqno;
 204
 205        set_irq_chip(base, &s3c_irq_level_chip);
 206        set_irq_handler(base, handle_level_irq);
 207        set_irq_chained_handler(base, demux);
 208
 209        for (irqno = start; irqno <= end; irqno++) {
 210                set_irq_chip(irqno, chip);
 211                set_irq_handler(irqno, handle_level_irq);
 212                set_irq_flags(irqno, IRQF_VALID);
 213        }
 214
 215        return 0;
 216}
 217
 218static int __init s3c2416_irq_add(struct sys_device *sysdev)
 219{
 220        printk(KERN_INFO "S3C2416: IRQ Support\n");
 221
 222        s3c2416_add_sub(IRQ_LCD, s3c2416_irq_demux_lcd, &s3c2416_irq_lcd,
 223                        IRQ_S3C2443_LCD2, IRQ_S3C2443_LCD4);
 224
 225        s3c2416_add_sub(IRQ_S3C2443_DMA, s3c2416_irq_demux_dma,
 226                        &s3c2416_irq_dma, IRQ_S3C2443_DMA0, IRQ_S3C2443_DMA5);
 227
 228        s3c2416_add_sub(IRQ_S3C2443_UART3, s3c2416_irq_demux_uart3,
 229                        &s3c2416_irq_uart3,
 230                        IRQ_S3C2443_RX3, IRQ_S3C2443_ERR3);
 231
 232        s3c2416_add_sub(IRQ_WDT, s3c2416_irq_demux_wdtac97,
 233                        &s3c2416_irq_wdtac97,
 234                        IRQ_S3C2443_WDT, IRQ_S3C2443_AC97);
 235
 236        return 0;
 237}
 238
 239static struct sysdev_driver s3c2416_irq_driver = {
 240        .add            = s3c2416_irq_add,
 241        .suspend        = s3c24xx_irq_suspend,
 242        .resume         = s3c24xx_irq_resume,
 243};
 244
 245static int __init s3c2416_irq_init(void)
 246{
 247        return sysdev_driver_register(&s3c2416_sysclass, &s3c2416_irq_driver);
 248}
 249
 250arch_initcall(s3c2416_irq_init);
 251
 252