linux/arch/sh/boards/mach-se/7724/irq.c
<<
>>
Prefs
   1/*
   2 * linux/arch/sh/boards/se/7724/irq.c
   3 *
   4 * Copyright (C) 2009 Renesas Solutions Corp.
   5 *
   6 * Kuninori Morimoto <morimoto.kuninori@renesas.com>
   7 *
   8 * Based on  linux/arch/sh/boards/se/7722/irq.c
   9 * Copyright (C) 2007  Nobuhiro Iwamatsu
  10 *
  11 * Hitachi UL SolutionEngine 7724 Support.
  12 *
  13 * This file is subject to the terms and conditions of the GNU General Public
  14 * License.  See the file "COPYING" in the main directory of this archive
  15 * for more details.
  16 */
  17#include <linux/init.h>
  18#include <linux/irq.h>
  19#include <linux/interrupt.h>
  20#include <linux/export.h>
  21#include <linux/topology.h>
  22#include <linux/io.h>
  23#include <linux/err.h>
  24#include <mach-se/mach/se7724.h>
  25
  26struct fpga_irq {
  27        unsigned long  sraddr;
  28        unsigned long  mraddr;
  29        unsigned short mask;
  30        unsigned int   base;
  31};
  32
  33static unsigned int fpga2irq(unsigned int irq)
  34{
  35        if (irq >= IRQ0_BASE &&
  36            irq <= IRQ0_END)
  37                return IRQ0_IRQ;
  38        else if (irq >= IRQ1_BASE &&
  39                 irq <= IRQ1_END)
  40                return IRQ1_IRQ;
  41        else
  42                return IRQ2_IRQ;
  43}
  44
  45static struct fpga_irq get_fpga_irq(unsigned int irq)
  46{
  47        struct fpga_irq set;
  48
  49        switch (irq) {
  50        case IRQ0_IRQ:
  51                set.sraddr = IRQ0_SR;
  52                set.mraddr = IRQ0_MR;
  53                set.mask   = IRQ0_MASK;
  54                set.base   = IRQ0_BASE;
  55                break;
  56        case IRQ1_IRQ:
  57                set.sraddr = IRQ1_SR;
  58                set.mraddr = IRQ1_MR;
  59                set.mask   = IRQ1_MASK;
  60                set.base   = IRQ1_BASE;
  61                break;
  62        default:
  63                set.sraddr = IRQ2_SR;
  64                set.mraddr = IRQ2_MR;
  65                set.mask   = IRQ2_MASK;
  66                set.base   = IRQ2_BASE;
  67                break;
  68        }
  69
  70        return set;
  71}
  72
  73static void disable_se7724_irq(struct irq_data *data)
  74{
  75        unsigned int irq = data->irq;
  76        struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
  77        unsigned int bit = irq - set.base;
  78        __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
  79}
  80
  81static void enable_se7724_irq(struct irq_data *data)
  82{
  83        unsigned int irq = data->irq;
  84        struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
  85        unsigned int bit = irq - set.base;
  86        __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
  87}
  88
  89static struct irq_chip se7724_irq_chip __read_mostly = {
  90        .name           = "SE7724-FPGA",
  91        .irq_mask       = disable_se7724_irq,
  92        .irq_unmask     = enable_se7724_irq,
  93};
  94
  95static void se7724_irq_demux(struct irq_desc *desc)
  96{
  97        unsigned int irq = irq_desc_get_irq(desc);
  98        struct fpga_irq set = get_fpga_irq(irq);
  99        unsigned short intv = __raw_readw(set.sraddr);
 100        unsigned int ext_irq = set.base;
 101
 102        intv &= set.mask;
 103
 104        for (; intv; intv >>= 1, ext_irq++) {
 105                if (!(intv & 1))
 106                        continue;
 107
 108                generic_handle_irq(ext_irq);
 109        }
 110}
 111
 112/*
 113 * Initialize IRQ setting
 114 */
 115void __init init_se7724_IRQ(void)
 116{
 117        int irq_base, i;
 118
 119        __raw_writew(0xffff, IRQ0_MR);  /* mask all */
 120        __raw_writew(0xffff, IRQ1_MR);  /* mask all */
 121        __raw_writew(0xffff, IRQ2_MR);  /* mask all */
 122        __raw_writew(0x0000, IRQ0_SR);  /* clear irq */
 123        __raw_writew(0x0000, IRQ1_SR);  /* clear irq */
 124        __raw_writew(0x0000, IRQ2_SR);  /* clear irq */
 125        __raw_writew(0x002a, IRQ_MODE); /* set irq type */
 126
 127        irq_base = irq_alloc_descs(SE7724_FPGA_IRQ_BASE, SE7724_FPGA_IRQ_BASE,
 128                                   SE7724_FPGA_IRQ_NR, numa_node_id());
 129        if (IS_ERR_VALUE(irq_base)) {
 130                pr_err("%s: failed hooking irqs for FPGA\n", __func__);
 131                return;
 132        }
 133
 134        for (i = 0; i < SE7724_FPGA_IRQ_NR; i++)
 135                irq_set_chip_and_handler_name(irq_base + i, &se7724_irq_chip,
 136                                              handle_level_irq, "level");
 137
 138        irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux);
 139        irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
 140
 141        irq_set_chained_handler(IRQ1_IRQ, se7724_irq_demux);
 142        irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
 143
 144        irq_set_chained_handler(IRQ2_IRQ, se7724_irq_demux);
 145        irq_set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW);
 146}
 147