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