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#include <asm/system.h> 20 21#include <msp_slp_int.h> 22#include <msp_regs.h> 23 24static inline void unmask_msp_slp_irq(unsigned int irq) 25{ 26 /* check for PER interrupt range */ 27 if (irq < MSP_PER_INTBASE) 28 *SLP_INT_MSK_REG |= (1 << (irq - MSP_SLP_INTBASE)); 29 else 30 *PER_INT_MSK_REG |= (1 << (irq - MSP_PER_INTBASE)); 31} 32 33static inline void mask_msp_slp_irq(unsigned int irq) 34{ 35 /* check for PER interrupt range */ 36 if (irq < MSP_PER_INTBASE) 37 *SLP_INT_MSK_REG &= ~(1 << (irq - MSP_SLP_INTBASE)); 38 else 39 *PER_INT_MSK_REG &= ~(1 << (irq - MSP_PER_INTBASE)); 40} 41 42/* 43 * While we ack the interrupt interrupts are disabled and thus we don't need 44 * to deal with concurrency issues. Same for msp_slp_irq_end. 45 */ 46static inline void ack_msp_slp_irq(unsigned int irq) 47{ 48 /* check for PER interrupt range */ 49 if (irq < MSP_PER_INTBASE) 50 *SLP_INT_STS_REG = (1 << (irq - MSP_SLP_INTBASE)); 51 else 52 *PER_INT_STS_REG = (1 << (irq - MSP_PER_INTBASE)); 53} 54 55static struct irq_chip msp_slp_irq_controller = { 56 .name = "MSP_SLP", 57 .ack = ack_msp_slp_irq, 58 .mask = mask_msp_slp_irq, 59 .unmask = unmask_msp_slp_irq, 60}; 61 62void __init msp_slp_irq_init(void) 63{ 64 int i; 65 66 /* Mask/clear interrupts. */ 67 *SLP_INT_MSK_REG = 0x00000000; 68 *PER_INT_MSK_REG = 0x00000000; 69 *SLP_INT_STS_REG = 0xFFFFFFFF; 70 *PER_INT_STS_REG = 0xFFFFFFFF; 71 72 /* initialize all the IRQ descriptors */ 73 for (i = MSP_SLP_INTBASE; i < MSP_PER_INTBASE + 32; i++) 74 set_irq_chip_and_handler(i, &msp_slp_irq_controller, 75 handle_level_irq); 76} 77 78void msp_slp_irq_dispatch(void) 79{ 80 u32 pending; 81 int intbase; 82 83 intbase = MSP_SLP_INTBASE; 84 pending = *SLP_INT_STS_REG & *SLP_INT_MSK_REG; 85 86 /* check for PER interrupt */ 87 if (pending == (1 << (MSP_INT_PER - MSP_SLP_INTBASE))) { 88 intbase = MSP_PER_INTBASE; 89 pending = *PER_INT_STS_REG & *PER_INT_MSK_REG; 90 } 91 92 /* check for spurious interrupt */ 93 if (pending == 0x00000000) { 94 printk(KERN_ERR "Spurious %s interrupt?\n", 95 (intbase == MSP_SLP_INTBASE) ? "SLP" : "PER"); 96 return; 97 } 98 99 /* dispatch the irq */ 100 do_IRQ(ffs(pending) + intbase - 1); 101} 102