linux/arch/mips/pmcs-msp71xx/msp_irq_slp.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * This file define the irq handler for MSP SLM subsystem interrupts.
   4 *
   5 * Copyright 2005-2006 PMC-Sierra, Inc, derived from irq_cpu.c
   6 * Author: Andrew Hughes, Andrew_Hughes@pmc-sierra.com
   7 */
   8
   9#include <linux/init.h>
  10#include <linux/interrupt.h>
  11#include <linux/kernel.h>
  12#include <linux/bitops.h>
  13
  14#include <asm/mipsregs.h>
  15
  16#include <msp_slp_int.h>
  17#include <msp_regs.h>
  18
  19static inline void unmask_msp_slp_irq(struct irq_data *d)
  20{
  21        unsigned int irq = d->irq;
  22
  23        /* check for PER interrupt range */
  24        if (irq < MSP_PER_INTBASE)
  25                *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE));
  26        else
  27                *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE));
  28}
  29
  30static inline void mask_msp_slp_irq(struct irq_data *d)
  31{
  32        unsigned int irq = d->irq;
  33
  34        /* check for PER interrupt range */
  35        if (irq < MSP_PER_INTBASE)
  36                *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE));
  37        else
  38                *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE));
  39}
  40
  41/*
  42 * While we ack the interrupt interrupts are disabled and thus we don't need
  43 * to deal with concurrency issues.  Same for msp_slp_irq_end.
  44 */
  45static inline void ack_msp_slp_irq(struct irq_data *d)
  46{
  47        unsigned int irq = d->irq;
  48
  49        /* check for PER interrupt range */
  50        if (irq < MSP_PER_INTBASE)
  51                *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE));
  52        else
  53                *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE));
  54}
  55
  56static struct irq_chip msp_slp_irq_controller = {
  57        .name = "MSP_SLP",
  58        .irq_ack = ack_msp_slp_irq,
  59        .irq_mask = mask_msp_slp_irq,
  60        .irq_unmask = unmask_msp_slp_irq,
  61};
  62
  63void __init msp_slp_irq_init(void)
  64{
  65        int i;
  66
  67        /* Mask/clear interrupts. */
  68        *SLP_INT_MSK_REG = 0x00000000;
  69        *PER_INT_MSK_REG = 0x00000000;
  70        *SLP_INT_STS_REG = 0xFFFFFFFF;
  71        *PER_INT_STS_REG = 0xFFFFFFFF;
  72
  73        /* initialize all the IRQ descriptors */
  74        for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++)
  75                irq_set_chip_and_handler(i, &msp_slp_irq_controller,
  76                                         handle_level_irq);
  77}
  78
  79void msp_slp_irq_dispatch(void)
  80{
  81        u32 pending;
  82        int intbase;
  83
  84        intbase = MSP_SLP_INTBASE;
  85        pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG;
  86
  87        /* check for PER interrupt */
  88        if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) {
  89                intbase = MSP_PER_INTBASE;
  90                pending = *PER_INT_STS_REG & *PER_INT_MSK_REG;
  91        }
  92
  93        /* check for spurious interrupt */
  94        if (pending == 0x00000000) {
  95                printk(KERN_ERR "Spurious %s interrupt?\n",
  96                        (intbase == MSP_SLP_INTBASE) ? "SLP" : "PER");
  97                return;
  98        }
  99
 100        /* dispatch the irq */
 101        do_IRQ(ffs(pending) + intbase - 1);
 102}
 103