linux/drivers/irqchip/irq-sa11x0.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2015 Dmitry Eremin-Solenikov
   3 * Copyright (C) 1999-2001 Nicolas Pitre
   4 *
   5 * Generic IRQ handling for the SA11x0.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License version 2 as
   9 * published by the Free Software Foundation.
  10 */
  11#include <linux/init.h>
  12#include <linux/module.h>
  13#include <linux/interrupt.h>
  14#include <linux/io.h>
  15#include <linux/irq.h>
  16#include <linux/irqdomain.h>
  17#include <linux/syscore_ops.h>
  18#include <linux/irqchip/irq-sa11x0.h>
  19
  20#include <soc/sa1100/pwer.h>
  21
  22#include <asm/exception.h>
  23
  24#define ICIP    0x00  /* IC IRQ Pending reg. */
  25#define ICMR    0x04  /* IC Mask Reg.        */
  26#define ICLR    0x08  /* IC Level Reg.       */
  27#define ICCR    0x0C  /* IC Control Reg.     */
  28#define ICFP    0x10  /* IC FIQ Pending reg. */
  29#define ICPR    0x20  /* IC Pending Reg.     */
  30
  31static void __iomem *iobase;
  32
  33/*
  34 * We don't need to ACK IRQs on the SA1100 unless they're GPIOs
  35 * this is for internal IRQs i.e. from IRQ LCD to RTCAlrm.
  36 */
  37static void sa1100_mask_irq(struct irq_data *d)
  38{
  39        u32 reg;
  40
  41        reg = readl_relaxed(iobase + ICMR);
  42        reg &= ~BIT(d->hwirq);
  43        writel_relaxed(reg, iobase + ICMR);
  44}
  45
  46static void sa1100_unmask_irq(struct irq_data *d)
  47{
  48        u32 reg;
  49
  50        reg = readl_relaxed(iobase + ICMR);
  51        reg |= BIT(d->hwirq);
  52        writel_relaxed(reg, iobase + ICMR);
  53}
  54
  55static int sa1100_set_wake(struct irq_data *d, unsigned int on)
  56{
  57        return sa11x0_sc_set_wake(d->hwirq, on);
  58}
  59
  60static struct irq_chip sa1100_normal_chip = {
  61        .name           = "SC",
  62        .irq_ack        = sa1100_mask_irq,
  63        .irq_mask       = sa1100_mask_irq,
  64        .irq_unmask     = sa1100_unmask_irq,
  65        .irq_set_wake   = sa1100_set_wake,
  66};
  67
  68static int sa1100_normal_irqdomain_map(struct irq_domain *d,
  69                unsigned int irq, irq_hw_number_t hwirq)
  70{
  71        irq_set_chip_and_handler(irq, &sa1100_normal_chip,
  72                                 handle_level_irq);
  73
  74        return 0;
  75}
  76
  77static const struct irq_domain_ops sa1100_normal_irqdomain_ops = {
  78        .map = sa1100_normal_irqdomain_map,
  79        .xlate = irq_domain_xlate_onetwocell,
  80};
  81
  82static struct irq_domain *sa1100_normal_irqdomain;
  83
  84static struct sa1100irq_state {
  85        unsigned int    saved;
  86        unsigned int    icmr;
  87        unsigned int    iclr;
  88        unsigned int    iccr;
  89} sa1100irq_state;
  90
  91static int sa1100irq_suspend(void)
  92{
  93        struct sa1100irq_state *st = &sa1100irq_state;
  94
  95        st->saved = 1;
  96        st->icmr = readl_relaxed(iobase + ICMR);
  97        st->iclr = readl_relaxed(iobase + ICLR);
  98        st->iccr = readl_relaxed(iobase + ICCR);
  99
 100        /*
 101         * Disable all GPIO-based interrupts.
 102         */
 103        writel_relaxed(st->icmr & 0xfffff000, iobase + ICMR);
 104
 105        return 0;
 106}
 107
 108static void sa1100irq_resume(void)
 109{
 110        struct sa1100irq_state *st = &sa1100irq_state;
 111
 112        if (st->saved) {
 113                writel_relaxed(st->iccr, iobase + ICCR);
 114                writel_relaxed(st->iclr, iobase + ICLR);
 115
 116                writel_relaxed(st->icmr, iobase + ICMR);
 117        }
 118}
 119
 120static struct syscore_ops sa1100irq_syscore_ops = {
 121        .suspend        = sa1100irq_suspend,
 122        .resume         = sa1100irq_resume,
 123};
 124
 125static int __init sa1100irq_init_devicefs(void)
 126{
 127        register_syscore_ops(&sa1100irq_syscore_ops);
 128        return 0;
 129}
 130
 131device_initcall(sa1100irq_init_devicefs);
 132
 133static asmlinkage void __exception_irq_entry
 134sa1100_handle_irq(struct pt_regs *regs)
 135{
 136        uint32_t icip, icmr, mask;
 137
 138        do {
 139                icip = readl_relaxed(iobase + ICIP);
 140                icmr = readl_relaxed(iobase + ICMR);
 141                mask = icip & icmr;
 142
 143                if (mask == 0)
 144                        break;
 145
 146                handle_domain_irq(sa1100_normal_irqdomain,
 147                                ffs(mask) - 1, regs);
 148        } while (1);
 149}
 150
 151void __init sa11x0_init_irq_nodt(int irq_start, resource_size_t io_start)
 152{
 153        iobase = ioremap(io_start, SZ_64K);
 154        if (WARN_ON(!iobase))
 155                return;
 156
 157        /* disable all IRQs */
 158        writel_relaxed(0, iobase + ICMR);
 159
 160        /* all IRQs are IRQ, not FIQ */
 161        writel_relaxed(0, iobase + ICLR);
 162
 163        /*
 164         * Whatever the doc says, this has to be set for the wait-on-irq
 165         * instruction to work... on a SA1100 rev 9 at least.
 166         */
 167        writel_relaxed(1, iobase + ICCR);
 168
 169        sa1100_normal_irqdomain = irq_domain_add_simple(NULL,
 170                        32, irq_start,
 171                        &sa1100_normal_irqdomain_ops, NULL);
 172
 173        set_handle_irq(sa1100_handle_irq);
 174}
 175