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> 23a58fbcd8SEric Miao #include <mach/gpio.h> 245bf3df3fSEric Miao #include <mach/regs-intc.h> 251da177e4SLinus Torvalds 261da177e4SLinus Torvalds #include "generic.h" 271da177e4SLinus Torvalds 28c482ae4dSHaojian Zhuang #define MAX_INTERNAL_IRQS 128 29c482ae4dSHaojian Zhuang 30f6fb7af4Seric miao #define IRQ_BIT(n) (((n) - PXA_IRQ(0)) & 0x1f) 31f6fb7af4Seric miao #define _ICMR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICMR2 : &ICMR)) 32f6fb7af4Seric miao #define _ICLR(n) (*((((n) - PXA_IRQ(0)) & ~0x1f) ? &ICLR2 : &ICLR)) 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds /* 351da177e4SLinus Torvalds * This is for peripheral IRQs internal to the PXA chip. 361da177e4SLinus Torvalds */ 371da177e4SLinus Torvalds 38f6fb7af4Seric miao static int pxa_internal_irq_nr; 39f6fb7af4Seric miao 40bb71bdd3SHaojian Zhuang static inline int cpu_has_ipr(void) 41bb71bdd3SHaojian Zhuang { 42bb71bdd3SHaojian Zhuang return !cpu_is_pxa25x(); 43bb71bdd3SHaojian Zhuang } 44bb71bdd3SHaojian Zhuang 45f6fb7af4Seric miao static void pxa_mask_irq(unsigned int irq) 461da177e4SLinus Torvalds { 47f6fb7af4Seric miao _ICMR(irq) &= ~(1 << IRQ_BIT(irq)); 481da177e4SLinus Torvalds } 491da177e4SLinus Torvalds 50f6fb7af4Seric miao static void pxa_unmask_irq(unsigned int irq) 511da177e4SLinus Torvalds { 52f6fb7af4Seric miao _ICMR(irq) |= 1 << IRQ_BIT(irq); 531da177e4SLinus Torvalds } 541da177e4SLinus Torvalds 55f6fb7af4Seric miao static struct irq_chip pxa_internal_irq_chip = { 5638c677cbSDavid Brownell .name = "SC", 57f6fb7af4Seric miao .ack = pxa_mask_irq, 58f6fb7af4Seric miao .mask = pxa_mask_irq, 59f6fb7af4Seric miao .unmask = pxa_unmask_irq, 601da177e4SLinus Torvalds }; 611da177e4SLinus Torvalds 62a58fbcd8SEric Miao /* 63a58fbcd8SEric Miao * GPIO IRQs for GPIO 0 and 1 64a58fbcd8SEric Miao */ 65a58fbcd8SEric Miao static int pxa_set_low_gpio_type(unsigned int irq, unsigned int type) 66a58fbcd8SEric Miao { 67a58fbcd8SEric Miao int gpio = irq - IRQ_GPIO0; 68a58fbcd8SEric Miao 69a58fbcd8SEric Miao if (__gpio_is_occupied(gpio)) { 70a58fbcd8SEric Miao pr_err("%s failed: GPIO is configured\n", __func__); 71a58fbcd8SEric Miao return -EINVAL; 72a58fbcd8SEric Miao } 73a58fbcd8SEric Miao 74a58fbcd8SEric Miao if (type & IRQ_TYPE_EDGE_RISING) 75a58fbcd8SEric Miao GRER0 |= GPIO_bit(gpio); 76a58fbcd8SEric Miao else 77a58fbcd8SEric Miao GRER0 &= ~GPIO_bit(gpio); 78a58fbcd8SEric Miao 79a58fbcd8SEric Miao if (type & IRQ_TYPE_EDGE_FALLING) 80a58fbcd8SEric Miao GFER0 |= GPIO_bit(gpio); 81a58fbcd8SEric Miao else 82a58fbcd8SEric Miao GFER0 &= ~GPIO_bit(gpio); 83a58fbcd8SEric Miao 84a58fbcd8SEric Miao return 0; 85a58fbcd8SEric Miao } 86a58fbcd8SEric Miao 87a58fbcd8SEric Miao static void pxa_ack_low_gpio(unsigned int irq) 88a58fbcd8SEric Miao { 89a58fbcd8SEric Miao GEDR0 = (1 << (irq - IRQ_GPIO0)); 90a58fbcd8SEric Miao } 91a58fbcd8SEric Miao 92a58fbcd8SEric Miao static void pxa_mask_low_gpio(unsigned int irq) 93a58fbcd8SEric Miao { 94a58fbcd8SEric Miao ICMR &= ~(1 << (irq - PXA_IRQ(0))); 95a58fbcd8SEric Miao } 96a58fbcd8SEric Miao 97a58fbcd8SEric Miao static void pxa_unmask_low_gpio(unsigned int irq) 98a58fbcd8SEric Miao { 99a58fbcd8SEric Miao ICMR |= 1 << (irq - PXA_IRQ(0)); 100a58fbcd8SEric Miao } 101a58fbcd8SEric Miao 102a58fbcd8SEric Miao static struct irq_chip pxa_low_gpio_chip = { 103a58fbcd8SEric Miao .name = "GPIO-l", 104a58fbcd8SEric Miao .ack = pxa_ack_low_gpio, 105a58fbcd8SEric Miao .mask = pxa_mask_low_gpio, 106a58fbcd8SEric Miao .unmask = pxa_unmask_low_gpio, 107a58fbcd8SEric Miao .set_type = pxa_set_low_gpio_type, 108a58fbcd8SEric Miao }; 109a58fbcd8SEric Miao 110a58fbcd8SEric Miao static void __init pxa_init_low_gpio_irq(set_wake_t fn) 111a58fbcd8SEric Miao { 112a58fbcd8SEric Miao int irq; 113a58fbcd8SEric Miao 114a58fbcd8SEric Miao /* clear edge detection on GPIO 0 and 1 */ 115a58fbcd8SEric Miao GFER0 &= ~0x3; 116a58fbcd8SEric Miao GRER0 &= ~0x3; 117a58fbcd8SEric Miao GEDR0 = 0x3; 118a58fbcd8SEric Miao 119a58fbcd8SEric Miao for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { 120a58fbcd8SEric Miao set_irq_chip(irq, &pxa_low_gpio_chip); 121a58fbcd8SEric Miao set_irq_handler(irq, handle_edge_irq); 122a58fbcd8SEric Miao set_irq_flags(irq, IRQF_VALID); 123a58fbcd8SEric Miao } 124a58fbcd8SEric Miao 125a58fbcd8SEric Miao pxa_low_gpio_chip.set_wake = fn; 126a58fbcd8SEric Miao } 127a58fbcd8SEric Miao 128b9e25aceSeric miao void __init pxa_init_irq(int irq_nr, set_wake_t fn) 12953665a50SEric Miao { 130d2c37068SHaojian Zhuang int irq, i; 13153665a50SEric Miao 132c482ae4dSHaojian Zhuang BUG_ON(irq_nr > MAX_INTERNAL_IRQS); 133c482ae4dSHaojian Zhuang 134f6fb7af4Seric miao pxa_internal_irq_nr = irq_nr; 13553665a50SEric Miao 13657a7a62eSMarc Zyngier for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq += 32) { 137f6fb7af4Seric miao _ICMR(irq) = 0; /* disable all IRQs */ 138f6fb7af4Seric miao _ICLR(irq) = 0; /* all IRQs are IRQ, not FIQ */ 139f6fb7af4Seric miao } 14053665a50SEric Miao 141d2c37068SHaojian Zhuang /* initialize interrupt priority */ 142bb71bdd3SHaojian Zhuang if (cpu_has_ipr()) { 143d2c37068SHaojian Zhuang for (i = 0; i < irq_nr; i++) 144d2c37068SHaojian Zhuang IPR(i) = i | (1 << 31); 145d2c37068SHaojian Zhuang } 146d2c37068SHaojian Zhuang 14753665a50SEric Miao /* only unmasked interrupts kick us out of idle */ 14853665a50SEric Miao ICCR = 1; 14953665a50SEric Miao 150f6fb7af4Seric miao for (irq = PXA_IRQ(0); irq < PXA_IRQ(irq_nr); irq++) { 151f6fb7af4Seric miao set_irq_chip(irq, &pxa_internal_irq_chip); 15253665a50SEric Miao set_irq_handler(irq, handle_level_irq); 15353665a50SEric Miao set_irq_flags(irq, IRQF_VALID); 15453665a50SEric Miao } 15553665a50SEric Miao 156b9e25aceSeric miao pxa_internal_irq_chip.set_wake = fn; 157a58fbcd8SEric Miao pxa_init_low_gpio_irq(fn); 158c95530c7Seric miao } 159c0165504Seric miao 160c0165504Seric miao #ifdef CONFIG_PM 161c482ae4dSHaojian Zhuang static unsigned long saved_icmr[MAX_INTERNAL_IRQS/32]; 162c482ae4dSHaojian Zhuang static unsigned long saved_ipr[MAX_INTERNAL_IRQS]; 163c0165504Seric miao 164c0165504Seric miao static int pxa_irq_suspend(struct sys_device *dev, pm_message_t state) 165c0165504Seric miao { 166f6fb7af4Seric miao int i, irq = PXA_IRQ(0); 167f6fb7af4Seric miao 168f6fb7af4Seric miao for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { 169f6fb7af4Seric miao saved_icmr[i] = _ICMR(irq); 170f6fb7af4Seric miao _ICMR(irq) = 0; 171c0165504Seric miao } 172c70f5a60SEric Miao 173bb71bdd3SHaojian Zhuang if (cpu_has_ipr()) { 174c482ae4dSHaojian Zhuang for (i = 0; i < pxa_internal_irq_nr; i++) 175c482ae4dSHaojian Zhuang saved_ipr[i] = IPR(i); 176c70f5a60SEric Miao } 177c0165504Seric miao 178c0165504Seric miao return 0; 179c0165504Seric miao } 180c0165504Seric miao 181c0165504Seric miao static int pxa_irq_resume(struct sys_device *dev) 182c0165504Seric miao { 183f6fb7af4Seric miao int i, irq = PXA_IRQ(0); 184f6fb7af4Seric miao 185bb71bdd3SHaojian Zhuang if (cpu_has_ipr()) { 186c70f5a60SEric Miao for (i = 0; i < pxa_internal_irq_nr; i++) 187c70f5a60SEric Miao IPR(i) = saved_ipr[i]; 188c70f5a60SEric Miao } 189c70f5a60SEric Miao 190f6fb7af4Seric miao for (i = 0; irq < PXA_IRQ(pxa_internal_irq_nr); i++, irq += 32) { 191f6fb7af4Seric miao _ICMR(irq) = saved_icmr[i]; 192f6fb7af4Seric miao _ICLR(irq) = 0; 193c0165504Seric miao } 194c0165504Seric miao 195f6fb7af4Seric miao ICCR = 1; 196c0165504Seric miao return 0; 197c0165504Seric miao } 198c0165504Seric miao #else 199c0165504Seric miao #define pxa_irq_suspend NULL 200c0165504Seric miao #define pxa_irq_resume NULL 201c0165504Seric miao #endif 202c0165504Seric miao 203c0165504Seric miao struct sysdev_class pxa_irq_sysclass = { 204c0165504Seric miao .name = "irq", 205c0165504Seric miao .suspend = pxa_irq_suspend, 206c0165504Seric miao .resume = pxa_irq_resume, 207c0165504Seric miao }; 208c0165504Seric miao 209c0165504Seric miao static int __init pxa_irq_init(void) 210c0165504Seric miao { 211c0165504Seric miao return sysdev_class_register(&pxa_irq_sysclass); 212c0165504Seric miao } 213c0165504Seric miao 214c0165504Seric miao core_initcall(pxa_irq_init); 215