linux/arch/arm/mach-sa1100/irq.c
<<
>>
Prefs
   1/*
   2 * linux/arch/arm/mach-sa1100/irq.c
   3 *
   4 * Copyright (C) 1999-2001 Nicolas Pitre
   5 *
   6 * Generic IRQ handling for the SA11x0, GPIO 11-27 IRQ demultiplexing.
   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 version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12#include <linux/init.h>
  13#include <linux/module.h>
  14#include <linux/interrupt.h>
  15#include <linux/io.h>
  16#include <linux/irq.h>
  17#include <linux/irqdomain.h>
  18#include <linux/ioport.h>
  19#include <linux/syscore_ops.h>
  20
  21#include <mach/hardware.h>
  22#include <mach/irqs.h>
  23#include <asm/mach/irq.h>
  24#include <asm/exception.h>
  25
  26#include "generic.h"
  27
  28
  29/*
  30 * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
  31 * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm.
  32 */
  33static void sa1100_mask_irq(struct irq_data *d)
  34{
  35        ICMR &= ~BIT(d->hwirq);
  36}
  37
  38static void sa1100_unmask_irq(struct irq_data *d)
  39{
  40        ICMR |= BIT(d->hwirq);
  41}
  42
  43/*
  44 * Apart form GPIOs, only the RTC alarm can be a wakeup event.
  45 */
  46static int sa1100_set_wake(struct irq_data *d, unsigned int on)
  47{
  48        if (BIT(d->hwirq) == IC_RTCAlrm) {
  49                if (on)
  50                        PWER |= PWER_RTC;
  51                else
  52                        PWER &= ~PWER_RTC;
  53                return 0;
  54        }
  55        return -EINVAL;
  56}
  57
  58static struct irq_chip sa1100_normal_chip = {
  59        .name           = "SC",
  60        .irq_ack        = sa1100_mask_irq,
  61        .irq_mask       = sa1100_mask_irq,
  62        .irq_unmask     = sa1100_unmask_irq,
  63        .irq_set_wake   = sa1100_set_wake,
  64};
  65
  66static int sa1100_normal_irqdomain_map(struct irq_domain *d,
  67                unsigned int irq, irq_hw_number_t hwirq)
  68{
  69        irq_set_chip_and_handler(irq, &sa1100_normal_chip,
  70                                 handle_level_irq);
  71        set_irq_flags(irq, IRQF_VALID);
  72
  73        return 0;
  74}
  75
  76static struct irq_domain_ops sa1100_normal_irqdomain_ops = {
  77        .map = sa1100_normal_irqdomain_map,
  78        .xlate = irq_domain_xlate_onetwocell,
  79};
  80
  81static struct irq_domain *sa1100_normal_irqdomain;
  82
  83static struct resource irq_resource =
  84        DEFINE_RES_MEM_NAMED(0x90050000, SZ_64K, "irqs");
  85
  86static struct sa1100irq_state {
  87        unsigned int    saved;
  88        unsigned int    icmr;
  89        unsigned int    iclr;
  90        unsigned int    iccr;
  91} sa1100irq_state;
  92
  93static int sa1100irq_suspend(void)
  94{
  95        struct sa1100irq_state *st = &sa1100irq_state;
  96
  97        st->saved = 1;
  98        st->icmr = ICMR;
  99        st->iclr = ICLR;
 100        st->iccr = ICCR;
 101
 102        /*
 103         * Disable all GPIO-based interrupts.
 104         */
 105        ICMR &= ~(IC_GPIO11_27|IC_GPIO10|IC_GPIO9|IC_GPIO8|IC_GPIO7|
 106                  IC_GPIO6|IC_GPIO5|IC_GPIO4|IC_GPIO3|IC_GPIO2|
 107                  IC_GPIO1|IC_GPIO0);
 108
 109        return 0;
 110}
 111
 112static void sa1100irq_resume(void)
 113{
 114        struct sa1100irq_state *st = &sa1100irq_state;
 115
 116        if (st->saved) {
 117                ICCR = st->iccr;
 118                ICLR = st->iclr;
 119
 120                ICMR = st->icmr;
 121        }
 122}
 123
 124static struct syscore_ops sa1100irq_syscore_ops = {
 125        .suspend        = sa1100irq_suspend,
 126        .resume         = sa1100irq_resume,
 127};
 128
 129static int __init sa1100irq_init_devicefs(void)
 130{
 131        register_syscore_ops(&sa1100irq_syscore_ops);
 132        return 0;
 133}
 134
 135device_initcall(sa1100irq_init_devicefs);
 136
 137static asmlinkage void __exception_irq_entry
 138sa1100_handle_irq(struct pt_regs *regs)
 139{
 140        uint32_t icip, icmr, mask;
 141
 142        do {
 143                icip = (ICIP);
 144                icmr = (ICMR);
 145                mask = icip & icmr;
 146
 147                if (mask == 0)
 148                        break;
 149
 150                handle_domain_irq(sa1100_normal_irqdomain,
 151                                ffs(mask) - 1, regs);
 152        } while (1);
 153}
 154
 155void __init sa1100_init_irq(void)
 156{
 157        request_resource(&iomem_resource, &irq_resource);
 158
 159        /* disable all IRQs */
 160        ICMR = 0;
 161
 162        /* all IRQs are IRQ, not FIQ */
 163        ICLR = 0;
 164
 165        /*
 166         * Whatever the doc says, this has to be set for the wait-on-irq
 167         * instruction to work... on a SA1100 rev 9 at least.
 168         */
 169        ICCR = 1;
 170
 171        sa1100_normal_irqdomain = irq_domain_add_simple(NULL,
 172                        32, IRQ_GPIO0_SC,
 173                        &sa1100_normal_irqdomain_ops, NULL);
 174
 175        set_handle_irq(sa1100_handle_irq);
 176
 177        sa1100_init_gpio();
 178}
 179