linux/arch/frv/kernel/irq-mb93493.c
<<
>>
Prefs
   1/* irq-mb93493.c: MB93493 companion chip interrupt handler
   2 *
   3 * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/ptrace.h>
  13#include <linux/errno.h>
  14#include <linux/signal.h>
  15#include <linux/sched.h>
  16#include <linux/ioport.h>
  17#include <linux/interrupt.h>
  18#include <linux/init.h>
  19#include <linux/irq.h>
  20#include <linux/bitops.h>
  21
  22#include <asm/io.h>
  23#include <asm/system.h>
  24#include <asm/delay.h>
  25#include <asm/irq.h>
  26#include <asm/irc-regs.h>
  27#include <asm/mb93493-irqs.h>
  28#include <asm/mb93493-regs.h>
  29
  30#define IRQ_ROUTE_ONE(X) (X##_ROUTE << (X - IRQ_BASE_MB93493))
  31
  32#define IRQ_ROUTING                                     \
  33        (IRQ_ROUTE_ONE(IRQ_MB93493_VDC)         |       \
  34         IRQ_ROUTE_ONE(IRQ_MB93493_VCC)         |       \
  35         IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_OUT)   |       \
  36         IRQ_ROUTE_ONE(IRQ_MB93493_I2C_0)       |       \
  37         IRQ_ROUTE_ONE(IRQ_MB93493_I2C_1)       |       \
  38         IRQ_ROUTE_ONE(IRQ_MB93493_USB)         |       \
  39         IRQ_ROUTE_ONE(IRQ_MB93493_LOCAL_BUS)   |       \
  40         IRQ_ROUTE_ONE(IRQ_MB93493_PCMCIA)      |       \
  41         IRQ_ROUTE_ONE(IRQ_MB93493_GPIO)        |       \
  42         IRQ_ROUTE_ONE(IRQ_MB93493_AUDIO_IN))
  43
  44/*
  45 * daughter board PIC operations
  46 * - there is no way to ACK interrupts in the MB93493 chip
  47 */
  48static void frv_mb93493_mask(unsigned int irq)
  49{
  50        uint32_t iqsr;
  51        volatile void *piqsr;
  52
  53        if (IRQ_ROUTING & (1 << (irq - IRQ_BASE_MB93493)))
  54                piqsr = __addr_MB93493_IQSR(1);
  55        else
  56                piqsr = __addr_MB93493_IQSR(0);
  57
  58        iqsr = readl(piqsr);
  59        iqsr &= ~(1 << (irq - IRQ_BASE_MB93493 + 16));
  60        writel(iqsr, piqsr);
  61}
  62
  63static void frv_mb93493_ack(unsigned int irq)
  64{
  65}
  66
  67static void frv_mb93493_unmask(unsigned int irq)
  68{
  69        uint32_t iqsr;
  70        volatile void *piqsr;
  71
  72        if (IRQ_ROUTING & (1 << (irq - IRQ_BASE_MB93493)))
  73                piqsr = __addr_MB93493_IQSR(1);
  74        else
  75                piqsr = __addr_MB93493_IQSR(0);
  76
  77        iqsr = readl(piqsr);
  78        iqsr |= 1 << (irq - IRQ_BASE_MB93493 + 16);
  79        writel(iqsr, piqsr);
  80}
  81
  82static struct irq_chip frv_mb93493_pic = {
  83        .name           = "mb93093",
  84        .ack            = frv_mb93493_ack,
  85        .mask           = frv_mb93493_mask,
  86        .mask_ack       = frv_mb93493_mask,
  87        .unmask         = frv_mb93493_unmask,
  88};
  89
  90/*
  91 * MB93493 PIC interrupt handler
  92 */
  93static irqreturn_t mb93493_interrupt(int irq, void *_piqsr)
  94{
  95        volatile void *piqsr = _piqsr;
  96        uint32_t iqsr;
  97
  98        iqsr = readl(piqsr);
  99        iqsr = iqsr & (iqsr >> 16) & 0xffff;
 100
 101        /* poll all the triggered IRQs */
 102        while (iqsr) {
 103                int irq;
 104
 105                asm("scan %1,gr0,%0" : "=r"(irq) : "r"(iqsr));
 106                irq = 31 - irq;
 107                iqsr &= ~(1 << irq);
 108
 109                generic_handle_irq(IRQ_BASE_MB93493 + irq);
 110        }
 111
 112        return IRQ_HANDLED;
 113}
 114
 115/*
 116 * define an interrupt action for each MB93493 PIC output
 117 * - use dev_id to indicate the MB93493 PIC input to output mappings
 118 */
 119static struct irqaction mb93493_irq[2]  = {
 120        [0] = {
 121                .handler        = mb93493_interrupt,
 122                .flags          = IRQF_DISABLED | IRQF_SHARED,
 123                .name           = "mb93493.0",
 124                .dev_id         = (void *) __addr_MB93493_IQSR(0),
 125        },
 126        [1] = {
 127                .handler        = mb93493_interrupt,
 128                .flags          = IRQF_DISABLED | IRQF_SHARED,
 129                .name           = "mb93493.1",
 130                .dev_id         = (void *) __addr_MB93493_IQSR(1),
 131        }
 132};
 133
 134/*
 135 * initialise the motherboard MB93493's PIC
 136 */
 137void __init mb93493_init(void)
 138{
 139        int irq;
 140
 141        for (irq = IRQ_BASE_MB93493 + 0; irq <= IRQ_BASE_MB93493 + 10; irq++)
 142                set_irq_chip_and_handler(irq, &frv_mb93493_pic, handle_edge_irq);
 143
 144        /* the MB93493 drives external IRQ inputs on the CPU PIC */
 145        setup_irq(IRQ_CPU_MB93493_0, &mb93493_irq[0]);
 146        setup_irq(IRQ_CPU_MB93493_1, &mb93493_irq[1]);
 147}
 148