linux/arch/arm/mach-imx/irq.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-imx/irq.c
   3 *
   4 *  Copyright (C) 1999 ARM Limited
   5 *  Copyright (C) 2002 Shane Nay (shane@minirl.com)
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  20 *
  21 *  03/03/2004   Sascha Hauer <sascha@saschahauer.de>
  22 *               Copied from the motorola bsp package and added gpio demux
  23 *               interrupt handler
  24 */
  25
  26#include <linux/init.h>
  27#include <linux/list.h>
  28#include <linux/timer.h>
  29
  30#include <asm/hardware.h>
  31#include <asm/irq.h>
  32#include <asm/io.h>
  33
  34#include <asm/mach/irq.h>
  35
  36/*
  37 *
  38 * We simply use the ENABLE DISABLE registers inside of the IMX
  39 * to turn on/off specific interrupts.  FIXME- We should
  40 * also add support for the accelerated interrupt controller
  41 * by putting offets to irq jump code in the appropriate
  42 * places.
  43 *
  44 */
  45
  46#define INTENNUM_OFF              0x8
  47#define INTDISNUM_OFF             0xC
  48
  49#define VA_AITC_BASE              IO_ADDRESS(IMX_AITC_BASE)
  50#define IMX_AITC_INTDISNUM       (VA_AITC_BASE + INTDISNUM_OFF)
  51#define IMX_AITC_INTENNUM        (VA_AITC_BASE + INTENNUM_OFF)
  52
  53#if 0
  54#define DEBUG_IRQ(fmt...)       printk(fmt)
  55#else
  56#define DEBUG_IRQ(fmt...)       do { } while (0)
  57#endif
  58
  59static void
  60imx_mask_irq(unsigned int irq)
  61{
  62        __raw_writel(irq, IMX_AITC_INTDISNUM);
  63}
  64
  65static void
  66imx_unmask_irq(unsigned int irq)
  67{
  68        __raw_writel(irq, IMX_AITC_INTENNUM);
  69}
  70
  71static int
  72imx_gpio_irq_type(unsigned int _irq, unsigned int type)
  73{
  74        unsigned int irq_type = 0, irq, reg, bit;
  75
  76        irq = _irq - IRQ_GPIOA(0);
  77        reg = irq >> 5;
  78        bit = 1 << (irq % 32);
  79
  80        if (type == IRQT_PROBE) {
  81                /* Don't mess with enabled GPIOs using preconfigured edges or
  82                   GPIOs set to alternate function during probe */
  83                /* TODO: support probe */
  84//              if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) &
  85//                  GPIO_bit(gpio))
  86//                      return 0;
  87//              if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2)))
  88//                      return 0;
  89//              type = __IRQT_RISEDGE | __IRQT_FALEDGE;
  90        }
  91
  92        GIUS(reg) |= bit;
  93        DDIR(reg) &= ~(bit);
  94
  95        DEBUG_IRQ("setting type of irq %d to ", _irq);
  96
  97        if (type & __IRQT_RISEDGE) {
  98                DEBUG_IRQ("rising edges\n");
  99                irq_type = 0x0;
 100        }
 101        if (type & __IRQT_FALEDGE) {
 102                DEBUG_IRQ("falling edges\n");
 103                irq_type = 0x1;
 104        }
 105        if (type & __IRQT_LOWLVL) {
 106                DEBUG_IRQ("low level\n");
 107                irq_type = 0x3;
 108        }
 109        if (type & __IRQT_HIGHLVL) {
 110                DEBUG_IRQ("high level\n");
 111                irq_type = 0x2;
 112        }
 113
 114        if (irq % 32 < 16) {
 115                ICR1(reg) = (ICR1(reg) & ~(0x3 << ((irq % 16) * 2))) |
 116                    (irq_type << ((irq % 16) * 2));
 117        } else {
 118                ICR2(reg) = (ICR2(reg) & ~(0x3 << ((irq % 16) * 2))) |
 119                    (irq_type << ((irq % 16) * 2));
 120        }
 121
 122        return 0;
 123
 124}
 125
 126static void
 127imx_gpio_ack_irq(unsigned int irq)
 128{
 129        DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
 130        ISR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
 131}
 132
 133static void
 134imx_gpio_mask_irq(unsigned int irq)
 135{
 136        DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
 137        IMR(IRQ_TO_REG(irq)) &= ~( 1 << ((irq - IRQ_GPIOA(0)) % 32));
 138}
 139
 140static void
 141imx_gpio_unmask_irq(unsigned int irq)
 142{
 143        DEBUG_IRQ("%s: irq %d\n", __FUNCTION__, irq);
 144        IMR(IRQ_TO_REG(irq)) |= 1 << ((irq - IRQ_GPIOA(0)) % 32);
 145}
 146
 147static void
 148imx_gpio_handler(unsigned int mask, unsigned int irq,
 149                 struct irqdesc *desc, struct pt_regs *regs)
 150{
 151        desc = irq_desc + irq;
 152        while (mask) {
 153                if (mask & 1) {
 154                        DEBUG_IRQ("handling irq %d\n", irq);
 155                        desc->handle(irq, desc, regs);
 156                }
 157                irq++;
 158                desc++;
 159                mask >>= 1;
 160        }
 161}
 162
 163static void
 164imx_gpioa_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
 165                        struct pt_regs *regs)
 166{
 167        unsigned int mask, irq;
 168
 169        mask = ISR(0);
 170        irq = IRQ_GPIOA(0);
 171        imx_gpio_handler(mask, irq, desc, regs);
 172}
 173
 174static void
 175imx_gpiob_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
 176                        struct pt_regs *regs)
 177{
 178        unsigned int mask, irq;
 179
 180        mask = ISR(1);
 181        irq = IRQ_GPIOB(0);
 182        imx_gpio_handler(mask, irq, desc, regs);
 183}
 184
 185static void
 186imx_gpioc_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
 187                        struct pt_regs *regs)
 188{
 189        unsigned int mask, irq;
 190
 191        mask = ISR(2);
 192        irq = IRQ_GPIOC(0);
 193        imx_gpio_handler(mask, irq, desc, regs);
 194}
 195
 196static void
 197imx_gpiod_demux_handler(unsigned int irq_unused, struct irqdesc *desc,
 198                        struct pt_regs *regs)
 199{
 200        unsigned int mask, irq;
 201
 202        mask = ISR(3);
 203        irq = IRQ_GPIOD(0);
 204        imx_gpio_handler(mask, irq, desc, regs);
 205}
 206
 207static struct irqchip imx_internal_chip = {
 208        .ack = imx_mask_irq,
 209        .mask = imx_mask_irq,
 210        .unmask = imx_unmask_irq,
 211};
 212
 213static struct irqchip imx_gpio_chip = {
 214        .ack = imx_gpio_ack_irq,
 215        .mask = imx_gpio_mask_irq,
 216        .unmask = imx_gpio_unmask_irq,
 217        .type = imx_gpio_irq_type,
 218};
 219
 220void __init
 221imx_init_irq(void)
 222{
 223        unsigned int irq;
 224
 225        DEBUG_IRQ("Initializing imx interrupts\n");
 226
 227        /* Mask all interrupts initially */
 228        IMR(0) = 0;
 229        IMR(1) = 0;
 230        IMR(2) = 0;
 231        IMR(3) = 0;
 232
 233        for (irq = 0; irq < IMX_IRQS; irq++) {
 234                set_irq_chip(irq, &imx_internal_chip);
 235                set_irq_handler(irq, do_level_IRQ);
 236                set_irq_flags(irq, IRQF_VALID);
 237        }
 238
 239        for (irq = IRQ_GPIOA(0); irq < IRQ_GPIOD(32); irq++) {
 240                set_irq_chip(irq, &imx_gpio_chip);
 241                set_irq_handler(irq, do_edge_IRQ);
 242                set_irq_flags(irq, IRQF_VALID);
 243        }
 244
 245        set_irq_chained_handler(GPIO_INT_PORTA, imx_gpioa_demux_handler);
 246        set_irq_chained_handler(GPIO_INT_PORTB, imx_gpiob_demux_handler);
 247        set_irq_chained_handler(GPIO_INT_PORTC, imx_gpioc_demux_handler);
 248        set_irq_chained_handler(GPIO_INT_PORTD, imx_gpiod_demux_handler);
 249
 250        /* Disable all interrupts initially. */
 251        /* In IMX this is done in the bootloader. */
 252}
 253
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.