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