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 <asm/irq.h>
  21#include <asm/io.h>
  22#include <mach-se/mach/se7724.h>
  23
  24struct fpga_irq {
  25        unsigned long  sraddr;
  26        unsigned long  mraddr;
  27        unsigned short mask;
  28        unsigned int   base;
  29};
  30
  31static unsigned int fpga2irq(unsigned int irq)
  32{
  33        if (irq >= IRQ0_BASE &&
  34            irq <= IRQ0_END)
  35                return IRQ0_IRQ;
  36        else if (irq >= IRQ1_BASE &&
  37                 irq <= IRQ1_END)
  38                return IRQ1_IRQ;
  39        else
  40                return IRQ2_IRQ;
  41}
  42
  43static struct fpga_irq get_fpga_irq(unsigned int irq)
  44{
  45        struct fpga_irq set;
  46
  47        switch (irq) {
  48        case IRQ0_IRQ:
  49                set.sraddr = IRQ0_SR;
  50                set.mraddr = IRQ0_MR;
  51                set.mask   = IRQ0_MASK;
  52                set.base   = IRQ0_BASE;
  53                break;
  54        case IRQ1_IRQ:
  55                set.sraddr = IRQ1_SR;
  56                set.mraddr = IRQ1_MR;
  57                set.mask   = IRQ1_MASK;
  58                set.base   = IRQ1_BASE;
  59                break;
  60        default:
  61                set.sraddr = IRQ2_SR;
  62                set.mraddr = IRQ2_MR;
  63                set.mask   = IRQ2_MASK;
  64                set.base   = IRQ2_BASE;
  65                break;
  66        }
  67
  68        return set;
  69}
  70
  71static void disable_se7724_irq(struct irq_data *data)
  72{
  73        unsigned int irq = data->irq;
  74        struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
  75        unsigned int bit = irq - set.base;
  76        __raw_writew(__raw_readw(set.mraddr) | 0x0001 << bit, set.mraddr);
  77}
  78
  79static void enable_se7724_irq(struct irq_data *data)
  80{
  81        unsigned int irq = data->irq;
  82        struct fpga_irq set = get_fpga_irq(fpga2irq(irq));
  83        unsigned int bit = irq - set.base;
  84        __raw_writew(__raw_readw(set.mraddr) & ~(0x0001 << bit), set.mraddr);
  85}
  86
  87static struct irq_chip se7724_irq_chip __read_mostly = {
  88        .name           = "SE7724-FPGA",
  89        .irq_mask       = disable_se7724_irq,
  90        .irq_unmask     = enable_se7724_irq,
  91};
  92
  93static void se7724_irq_demux(unsigned int irq, struct irq_desc *desc)
  94{
  95        struct fpga_irq set = get_fpga_irq(irq);
  96        unsigned short intv = __raw_readw(set.sraddr);
  97        unsigned int ext_irq = set.base;
  98
  99        intv &= set.mask;
 100
 101        for (; intv; intv >>= 1, ext_irq++) {
 102                if (!(intv & 1))
 103                        continue;
 104
 105                generic_handle_irq(ext_irq);
 106        }
 107}
 108
 109/*
 110 * Initialize IRQ setting
 111 */
 112void __init init_se7724_IRQ(void)
 113{
 114        int i, nid = cpu_to_node(boot_cpu_data);
 115
 116        __raw_writew(0xffff, IRQ0_MR);  /* mask all */
 117        __raw_writew(0xffff, IRQ1_MR);  /* mask all */
 118        __raw_writew(0xffff, IRQ2_MR);  /* mask all */
 119        __raw_writew(0x0000, IRQ0_SR);  /* clear irq */
 120        __raw_writew(0x0000, IRQ1_SR);  /* clear irq */
 121        __raw_writew(0x0000, IRQ2_SR);  /* clear irq */
 122        __raw_writew(0x002a, IRQ_MODE); /* set irq type */
 123
 124        for (i = 0; i < SE7724_FPGA_IRQ_NR; i++) {
 125                int irq, wanted;
 126
 127                wanted = SE7724_FPGA_IRQ_BASE + i;
 128
 129                irq = create_irq_nr(wanted, nid);
 130                if (unlikely(irq == 0)) {
 131                        pr_err("%s: failed hooking irq %d for FPGA\n",
 132                               __func__, wanted);
 133                        return;
 134                }
 135
 136                if (unlikely(irq != wanted)) {
 137                        pr_err("%s: got irq %d but wanted %d, bailing.\n",
 138                               __func__, irq, wanted);
 139                        destroy_irq(irq);
 140                        return;
 141                }
 142
 143                irq_set_chip_and_handler_name(irq, &se7724_irq_chip,
 144                                              handle_level_irq, "level");
 145        }
 146
 147        irq_set_chained_handler(IRQ0_IRQ, se7724_irq_demux);
 148        irq_set_irq_type(IRQ0_IRQ, IRQ_TYPE_LEVEL_LOW);
 149
 150        irq_set_chained_handler(IRQ1_IRQ, se7724_irq_demux);
 151        irq_set_irq_type(IRQ1_IRQ, IRQ_TYPE_LEVEL_LOW);
 152
 153        irq_set_chained_handler(IRQ2_IRQ, se7724_irq_demux);
 154        irq_set_irq_type(IRQ2_IRQ, IRQ_TYPE_LEVEL_LOW);
 155}
 156