linux/arch/avr32/mach-at32ap/extint.c
<<
>>
Prefs
   1/*
   2 * External interrupt handling for AT32AP CPUs
   3 *
   4 * Copyright (C) 2006 Atmel Corporation
   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 version 2 as
   8 * published by the Free Software Foundation.
   9 */
  10
  11#include <linux/errno.h>
  12#include <linux/init.h>
  13#include <linux/interrupt.h>
  14#include <linux/irq.h>
  15#include <linux/platform_device.h>
  16#include <linux/random.h>
  17
  18#include <asm/io.h>
  19
  20/* EIC register offsets */
  21#define EIC_IER                                 0x0000
  22#define EIC_IDR                                 0x0004
  23#define EIC_IMR                                 0x0008
  24#define EIC_ISR                                 0x000c
  25#define EIC_ICR                                 0x0010
  26#define EIC_MODE                                0x0014
  27#define EIC_EDGE                                0x0018
  28#define EIC_LEVEL                               0x001c
  29#define EIC_NMIC                                0x0024
  30
  31/* Bitfields in NMIC */
  32#define EIC_NMIC_ENABLE                         (1 << 0)
  33
  34/* Bit manipulation macros */
  35#define EIC_BIT(name)                                   \
  36        (1 << EIC_##name##_OFFSET)
  37#define EIC_BF(name,value)                              \
  38        (((value) & ((1 << EIC_##name##_SIZE) - 1))     \
  39         << EIC_##name##_OFFSET)
  40#define EIC_BFEXT(name,value)                           \
  41        (((value) >> EIC_##name##_OFFSET)               \
  42         & ((1 << EIC_##name##_SIZE) - 1))
  43#define EIC_BFINS(name,value,old)                       \
  44        (((old) & ~(((1 << EIC_##name##_SIZE) - 1)      \
  45                    << EIC_##name##_OFFSET))            \
  46         | EIC_BF(name,value))
  47
  48/* Register access macros */
  49#define eic_readl(port,reg)                             \
  50        __raw_readl((port)->regs + EIC_##reg)
  51#define eic_writel(port,reg,value)                      \
  52        __raw_writel((value), (port)->regs + EIC_##reg)
  53
  54struct eic {
  55        void __iomem *regs;
  56        struct irq_chip *chip;
  57        unsigned int first_irq;
  58};
  59
  60static struct eic *nmi_eic;
  61static bool nmi_enabled;
  62
  63static void eic_ack_irq(unsigned int irq)
  64{
  65        struct eic *eic = get_irq_chip_data(irq);
  66        eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
  67}
  68
  69static void eic_mask_irq(unsigned int irq)
  70{
  71        struct eic *eic = get_irq_chip_data(irq);
  72        eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
  73}
  74
  75static void eic_mask_ack_irq(unsigned int irq)
  76{
  77        struct eic *eic = get_irq_chip_data(irq);
  78        eic_writel(eic, ICR, 1 << (irq - eic->first_irq));
  79        eic_writel(eic, IDR, 1 << (irq - eic->first_irq));
  80}
  81
  82static void eic_unmask_irq(unsigned int irq)
  83{
  84        struct eic *eic = get_irq_chip_data(irq);
  85        eic_writel(eic, IER, 1 << (irq - eic->first_irq));
  86}
  87
  88static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
  89{
  90        struct eic *eic = get_irq_chip_data(irq);
  91        struct irq_desc *desc;
  92        unsigned int i = irq - eic->first_irq;
  93        u32 mode, edge, level;
  94        int ret = 0;
  95
  96        flow_type &= IRQ_TYPE_SENSE_MASK;
  97        if (flow_type == IRQ_TYPE_NONE)
  98                flow_type = IRQ_TYPE_LEVEL_LOW;
  99
 100        desc = &irq_desc[irq];
 101
 102        mode = eic_readl(eic, MODE);
 103        edge = eic_readl(eic, EDGE);
 104        level = eic_readl(eic, LEVEL);
 105
 106        switch (flow_type) {
 107        case IRQ_TYPE_LEVEL_LOW:
 108                mode |= 1 << i;
 109                level &= ~(1 << i);
 110                break;
 111        case IRQ_TYPE_LEVEL_HIGH:
 112                mode |= 1 << i;
 113                level |= 1 << i;
 114                break;
 115        case IRQ_TYPE_EDGE_RISING:
 116                mode &= ~(1 << i);
 117                edge |= 1 << i;
 118                break;
 119        case IRQ_TYPE_EDGE_FALLING:
 120                mode &= ~(1 << i);
 121                edge &= ~(1 << i);
 122                break;
 123        default:
 124                ret = -EINVAL;
 125                break;
 126        }
 127
 128        if (ret == 0) {
 129                eic_writel(eic, MODE, mode);
 130                eic_writel(eic, EDGE, edge);
 131                eic_writel(eic, LEVEL, level);
 132
 133                if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
 134                        flow_type |= IRQ_LEVEL;
 135                        __set_irq_handler_unlocked(irq, handle_level_irq);
 136                } else
 137                        __set_irq_handler_unlocked(irq, handle_edge_irq);
 138                desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
 139                desc->status |= flow_type;
 140        }
 141
 142        return ret;
 143}
 144
 145static struct irq_chip eic_chip = {
 146        .name           = "eic",
 147        .ack            = eic_ack_irq,
 148        .mask           = eic_mask_irq,
 149        .mask_ack       = eic_mask_ack_irq,
 150        .unmask         = eic_unmask_irq,
 151        .set_type       = eic_set_irq_type,
 152};
 153
 154static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
 155{
 156        struct eic *eic = desc->handler_data;
 157        unsigned long status, pending;
 158        unsigned int i;
 159
 160        status = eic_readl(eic, ISR);
 161        pending = status & eic_readl(eic, IMR);
 162
 163        while (pending) {
 164                i = fls(pending) - 1;
 165                pending &= ~(1 << i);
 166
 167                generic_handle_irq(i + eic->first_irq);
 168        }
 169}
 170
 171int nmi_enable(void)
 172{
 173        nmi_enabled = true;
 174
 175        if (nmi_eic)
 176                eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
 177
 178        return 0;
 179}
 180
 181void nmi_disable(void)
 182{
 183        if (nmi_eic)
 184                eic_writel(nmi_eic, NMIC, 0);
 185
 186        nmi_enabled = false;
 187}
 188
 189static int __init eic_probe(struct platform_device *pdev)
 190{
 191        struct eic *eic;
 192        struct resource *regs;
 193        unsigned int i;
 194        unsigned int nr_irqs;
 195        unsigned int int_irq;
 196        int ret;
 197        u32 pattern;
 198
 199        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 200        int_irq = platform_get_irq(pdev, 0);
 201        if (!regs || !int_irq) {
 202                dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
 203                return -ENXIO;
 204        }
 205
 206        ret = -ENOMEM;
 207        eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
 208        if (!eic) {
 209                dev_dbg(&pdev->dev, "no memory for eic structure\n");
 210                goto err_kzalloc;
 211        }
 212
 213        eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
 214        eic->regs = ioremap(regs->start, regs->end - regs->start + 1);
 215        if (!eic->regs) {
 216                dev_dbg(&pdev->dev, "failed to map regs\n");
 217                goto err_ioremap;
 218        }
 219
 220        /*
 221         * Find out how many interrupt lines that are actually
 222         * implemented in hardware.
 223         */
 224        eic_writel(eic, IDR, ~0UL);
 225        eic_writel(eic, MODE, ~0UL);
 226        pattern = eic_readl(eic, MODE);
 227        nr_irqs = fls(pattern);
 228
 229        /* Trigger on low level unless overridden by driver */
 230        eic_writel(eic, EDGE, 0UL);
 231        eic_writel(eic, LEVEL, 0UL);
 232
 233        eic->chip = &eic_chip;
 234
 235        for (i = 0; i < nr_irqs; i++) {
 236                set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
 237                                         handle_level_irq);
 238                set_irq_chip_data(eic->first_irq + i, eic);
 239        }
 240
 241        set_irq_chained_handler(int_irq, demux_eic_irq);
 242        set_irq_data(int_irq, eic);
 243
 244        if (pdev->id == 0) {
 245                nmi_eic = eic;
 246                if (nmi_enabled)
 247                        /*
 248                         * Someone tried to enable NMI before we were
 249                         * ready. Do it now.
 250                         */
 251                        nmi_enable();
 252        }
 253
 254        dev_info(&pdev->dev,
 255                 "External Interrupt Controller at 0x%p, IRQ %u\n",
 256                 eic->regs, int_irq);
 257        dev_info(&pdev->dev,
 258                 "Handling %u external IRQs, starting with IRQ %u\n",
 259                 nr_irqs, eic->first_irq);
 260
 261        return 0;
 262
 263err_ioremap:
 264        kfree(eic);
 265err_kzalloc:
 266        return ret;
 267}
 268
 269static struct platform_driver eic_driver = {
 270        .driver = {
 271                .name = "at32_eic",
 272        },
 273};
 274
 275static int __init eic_init(void)
 276{
 277        return platform_driver_probe(&eic_driver, eic_probe);
 278}
 279arch_initcall(eic_init);
 280