11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * linux/arch/arm/mach-pxa/irq.c 31da177e4SLinus Torvalds * 4e3630db1Seric miao * Generic PXA IRQ handling 51da177e4SLinus Torvalds * 61da177e4SLinus Torvalds * Author: Nicolas Pitre 71da177e4SLinus Torvalds * Created: Jun 15, 2001 81da177e4SLinus Torvalds * Copyright: MontaVista Software Inc. 91da177e4SLinus Torvalds * 101da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or modify 111da177e4SLinus Torvalds * it under the terms of the GNU General Public License version 2 as 121da177e4SLinus Torvalds * published by the Free Software Foundation. 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <linux/init.h> 161da177e4SLinus Torvalds #include <linux/module.h> 171da177e4SLinus Torvalds #include <linux/interrupt.h> 18c0165504Seric miao #include <linux/sysdev.h> 191da177e4SLinus Torvalds 20a09e64fbSRussell King #include <mach/hardware.h> 211da177e4SLinus Torvalds #include <asm/irq.h> 221da177e4SLinus Torvalds #include <asm/mach/irq.h> 23a09e64fbSRussell King #include <mach/pxa-regs.h> 241da177e4SLinus Torvalds 251da177e4SLinus Torvalds #include "generic.h" 261da177e4SLinus Torvalds 27f6fb7af4Seric miao #define IRQ_BIT(n) (((n) - PXA_IRQ(0)) & 0x1f) 28f6fb7af4Seric miao #define _ICMR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR)) 29f6fb7af4Seric miao #define _ICLR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR)) 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds /* 321da177e4SLinus Torvalds * This is for peripheral IRQs internal to the PXA chip. 331da177e4SLinus Torvalds */ 341da177e4SLinus Torvalds 35f6fb7af4Seric miao static int pxa_internal_irq_nr; 36f6fb7af4Seric miao 37f6fb7af4Seric miao static void pxa_mask_irq(unsigned int irq) 381da177e4SLinus Torvalds { 39f6fb7af4Seric miao _ICMR(irq) &= ~(1 << IRQ_BIT(irq)); 401da177e4SLinus Torvalds } 411da177e4SLinus Torvalds 42f6fb7af4Seric miao static void pxa_unmask_irq(unsigned int irq) 431da177e4SLinus Torvalds { 44f6fb7af4Seric miao _ICMR(irq) |= 1 << IRQ_BIT(irq); 451da177e4SLinus Torvalds } 461da177e4SLinus Torvalds 47f6fb7af4Seric miao static struct irq_chip pxa_internal_irq_chip = { 4838c677cbSDavid Brownell .name = "SC", 49f6fb7af4Seric miao .ack = pxa_mask_irq, 50f6fb7af4Seric miao .mask = pxa_mask_irq, 51f6fb7af4Seric miao .unmask = pxa_unmask_irq, 521da177e4SLinus Torvalds }; 531da177e4SLinus Torvalds 54b9e25aceSeric miao void __init pxa_init_irq(int irq_nr, set_wake_t fn) 5553665a50SEric Miao { 5653665a50SEric Miao int irq; 5753665a50SEric Miao 58f6fb7af4Seric miao pxa_internal_irq_nr = irq_nr; 5953665a50SEric Miao 60f6fb7af4Seric miao for (irq = 0; irq < irq_nr; irq += 32) { 61f6fb7af4Seric miao _ICMR(irq) = 0; /* disable all IRQs */ 62f6fb7af4Seric miao _ICLR(irq) = 0; /* all IRQs are IRQ, not FIQ */ 63f6fb7af4Seric miao } 6453665a50SEric Miao 6553665a50SEric Miao /* only unmasked interrupts kick us out of idle */ 6653665a50SEric Miao ICCR = 1; 6753665a50SEric Miao 68f6fb7af4Seric miao for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) { 69f6fb7af4Seric miao set_irq_chip(irq, &pxa_internal_irq_chip); 7053665a50SEric Miao set_irq_handler(irq, handle_level_irq); 7153665a50SEric Miao set_irq_flags(irq, IRQF_VALID); 7253665a50SEric Miao } 7353665a50SEric Miao 74b9e25aceSeric miao pxa_internal_irq_chip.set_wake = fn; 75c95530c7Seric miao } 76c0165504Seric miao 77c0165504Seric miao #ifdef CONFIG_PM 78c0165504Seric miao static unsigned long saved_icmr[2]; 79c0165504Seric miao 80c0165504Seric miao static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) 81c0165504Seric miao { 82f6fb7af4Seric miao int i, irq = PXA_IRQ(0); 83f6fb7af4Seric miao 84f6fb7af4Seric miao for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { 85f6fb7af4Seric miao saved_icmr[i] = _ICMR(irq); 86f6fb7af4Seric miao _ICMR(irq) = 0; 87c0165504Seric miao } 88c0165504Seric miao 89c0165504Seric miao return 0; 90c0165504Seric miao } 91c0165504Seric miao 92c0165504Seric miao static int pxa_irq_resume(struct sys_device *dev) 93c0165504Seric miao { 94f6fb7af4Seric miao int i, irq = PXA_IRQ(0); 95f6fb7af4Seric miao 96f6fb7af4Seric miao for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { 97f6fb7af4Seric miao _ICMR(irq) = saved_icmr[i]; 98f6fb7af4Seric miao _ICLR(irq) = 0; 99c0165504Seric miao } 100c0165504Seric miao 101f6fb7af4Seric miao ICCR = 1; 102c0165504Seric miao return 0; 103c0165504Seric miao } 104c0165504Seric miao #else 105c0165504Seric miao #define pxa_irq_suspend NULL 106c0165504Seric miao #define pxa_irq_resume NULL 107c0165504Seric miao #endif 108c0165504Seric miao 109c0165504Seric miao struct sysdev_class pxa_irq_sysclass = { 110c0165504Seric miao .name = "irq", 111c0165504Seric miao .suspend = pxa_irq_suspend, 112c0165504Seric miao .resume = pxa_irq_resume, 113c0165504Seric miao }; 114c0165504Seric miao 115c0165504Seric miao static int __init pxa_irq_init(void) 116c0165504Seric miao { 117c0165504Seric miao return sysdev_class_register(&pxa_irq_sysclass); 118c0165504Seric miao } 119c0165504Seric miao 120c0165504Seric miao core_initcall(pxa_irq_init); 121