| /* | 
 |  *  linux/arch/arm/mach-pxa/irq.c | 
 |  * | 
 |  *  Generic PXA IRQ handling, GPIO IRQ demultiplexing, etc. | 
 |  * | 
 |  *  Author:	Nicolas Pitre | 
 |  *  Created:	Jun 15, 2001 | 
 |  *  Copyright:	MontaVista Software Inc. | 
 |  * | 
 |  *  This program is free software; you can redistribute it and/or modify | 
 |  *  it under the terms of the GNU General Public License version 2 as | 
 |  *  published by the Free Software Foundation. | 
 |  */ | 
 |  | 
 | #include <linux/init.h> | 
 | #include <linux/module.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/ptrace.h> | 
 |  | 
 | #include <asm/hardware.h> | 
 | #include <asm/irq.h> | 
 | #include <asm/mach/irq.h> | 
 | #include <asm/arch/pxa-regs.h> | 
 |  | 
 | #include "generic.h" | 
 |  | 
 |  | 
 | /* | 
 |  * This is for peripheral IRQs internal to the PXA chip. | 
 |  */ | 
 |  | 
 | static void pxa_mask_low_irq(unsigned int irq) | 
 | { | 
 | 	ICMR &= ~(1 << (irq + PXA_IRQ_SKIP)); | 
 | } | 
 |  | 
 | static void pxa_unmask_low_irq(unsigned int irq) | 
 | { | 
 | 	ICMR |= (1 << (irq + PXA_IRQ_SKIP)); | 
 | } | 
 |  | 
 | static struct irqchip pxa_internal_chip_low = { | 
 | 	.ack		= pxa_mask_low_irq, | 
 | 	.mask		= pxa_mask_low_irq, | 
 | 	.unmask		= pxa_unmask_low_irq, | 
 | }; | 
 |  | 
 | #if PXA_INTERNAL_IRQS > 32 | 
 |  | 
 | /* | 
 |  * This is for the second set of internal IRQs as found on the PXA27x. | 
 |  */ | 
 |  | 
 | static void pxa_mask_high_irq(unsigned int irq) | 
 | { | 
 | 	ICMR2 &= ~(1 << (irq - 32 + PXA_IRQ_SKIP)); | 
 | } | 
 |  | 
 | static void pxa_unmask_high_irq(unsigned int irq) | 
 | { | 
 | 	ICMR2 |= (1 << (irq - 32 + PXA_IRQ_SKIP)); | 
 | } | 
 |  | 
 | static struct irqchip pxa_internal_chip_high = { | 
 | 	.ack		= pxa_mask_high_irq, | 
 | 	.mask		= pxa_mask_high_irq, | 
 | 	.unmask		= pxa_unmask_high_irq, | 
 | }; | 
 |  | 
 | #endif | 
 |  | 
 | /* | 
 |  * PXA GPIO edge detection for IRQs: | 
 |  * IRQs are generated on Falling-Edge, Rising-Edge, or both. | 
 |  * Use this instead of directly setting GRER/GFER. | 
 |  */ | 
 |  | 
 | static long GPIO_IRQ_rising_edge[4]; | 
 | static long GPIO_IRQ_falling_edge[4]; | 
 | static long GPIO_IRQ_mask[4]; | 
 |  | 
 | static int pxa_gpio_irq_type(unsigned int irq, unsigned int type) | 
 | { | 
 | 	int gpio, idx; | 
 |  | 
 | 	gpio = IRQ_TO_GPIO(irq); | 
 | 	idx = gpio >> 5; | 
 |  | 
 | 	if (type == IRQT_PROBE) { | 
 | 	    /* Don't mess with enabled GPIOs using preconfigured edges or | 
 | 	       GPIOs set to alternate function during probe */ | 
 | 		if ((GPIO_IRQ_rising_edge[idx] | GPIO_IRQ_falling_edge[idx]) & | 
 | 		    GPIO_bit(gpio)) | 
 | 			return 0; | 
 | 		if (GAFR(gpio) & (0x3 << (((gpio) & 0xf)*2))) | 
 | 			return 0; | 
 | 		type = __IRQT_RISEDGE | __IRQT_FALEDGE; | 
 | 	} | 
 |  | 
 | 	/* printk(KERN_DEBUG "IRQ%d (GPIO%d): ", irq, gpio); */ | 
 |  | 
 | 	pxa_gpio_mode(gpio | GPIO_IN); | 
 |  | 
 | 	if (type & __IRQT_RISEDGE) { | 
 | 		/* printk("rising "); */ | 
 | 		__set_bit (gpio, GPIO_IRQ_rising_edge); | 
 | 	} else | 
 | 		__clear_bit (gpio, GPIO_IRQ_rising_edge); | 
 |  | 
 | 	if (type & __IRQT_FALEDGE) { | 
 | 		/* printk("falling "); */ | 
 | 		__set_bit (gpio, GPIO_IRQ_falling_edge); | 
 | 	} else | 
 | 		__clear_bit (gpio, GPIO_IRQ_falling_edge); | 
 |  | 
 | 	/* printk("edges\n"); */ | 
 |  | 
 | 	GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | 
 | 	GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * GPIO IRQs must be acknowledged.  This is for GPIO 0 and 1. | 
 |  */ | 
 |  | 
 | static void pxa_ack_low_gpio(unsigned int irq) | 
 | { | 
 | 	GEDR0 = (1 << (irq - IRQ_GPIO0)); | 
 | } | 
 |  | 
 | static struct irqchip pxa_low_gpio_chip = { | 
 | 	.ack		= pxa_ack_low_gpio, | 
 | 	.mask		= pxa_mask_low_irq, | 
 | 	.unmask		= pxa_unmask_low_irq, | 
 | 	.set_type	= pxa_gpio_irq_type, | 
 | }; | 
 |  | 
 | /* | 
 |  * Demux handler for GPIO>=2 edge detect interrupts | 
 |  */ | 
 |  | 
 | static void pxa_gpio_demux_handler(unsigned int irq, struct irqdesc *desc, | 
 | 				   struct pt_regs *regs) | 
 | { | 
 | 	unsigned int mask; | 
 | 	int loop; | 
 |  | 
 | 	do { | 
 | 		loop = 0; | 
 |  | 
 | 		mask = GEDR0 & ~3; | 
 | 		if (mask) { | 
 | 			GEDR0 = mask; | 
 | 			irq = IRQ_GPIO(2); | 
 | 			desc = irq_desc + irq; | 
 | 			mask >>= 2; | 
 | 			do { | 
 | 				if (mask & 1) | 
 | 					desc_handle_irq(irq, desc, regs); | 
 | 				irq++; | 
 | 				desc++; | 
 | 				mask >>= 1; | 
 | 			} while (mask); | 
 | 			loop = 1; | 
 | 		} | 
 |  | 
 | 		mask = GEDR1; | 
 | 		if (mask) { | 
 | 			GEDR1 = mask; | 
 | 			irq = IRQ_GPIO(32); | 
 | 			desc = irq_desc + irq; | 
 | 			do { | 
 | 				if (mask & 1) | 
 | 					desc_handle_irq(irq, desc, regs); | 
 | 				irq++; | 
 | 				desc++; | 
 | 				mask >>= 1; | 
 | 			} while (mask); | 
 | 			loop = 1; | 
 | 		} | 
 |  | 
 | 		mask = GEDR2; | 
 | 		if (mask) { | 
 | 			GEDR2 = mask; | 
 | 			irq = IRQ_GPIO(64); | 
 | 			desc = irq_desc + irq; | 
 | 			do { | 
 | 				if (mask & 1) | 
 | 					desc_handle_irq(irq, desc, regs); | 
 | 				irq++; | 
 | 				desc++; | 
 | 				mask >>= 1; | 
 | 			} while (mask); | 
 | 			loop = 1; | 
 | 		} | 
 |  | 
 | #if PXA_LAST_GPIO >= 96 | 
 | 		mask = GEDR3; | 
 | 		if (mask) { | 
 | 			GEDR3 = mask; | 
 | 			irq = IRQ_GPIO(96); | 
 | 			desc = irq_desc + irq; | 
 | 			do { | 
 | 				if (mask & 1) | 
 | 					desc_handle_irq(irq, desc, regs); | 
 | 				irq++; | 
 | 				desc++; | 
 | 				mask >>= 1; | 
 | 			} while (mask); | 
 | 			loop = 1; | 
 | 		} | 
 | #endif | 
 | 	} while (loop); | 
 | } | 
 |  | 
 | static void pxa_ack_muxed_gpio(unsigned int irq) | 
 | { | 
 | 	int gpio = irq - IRQ_GPIO(2) + 2; | 
 | 	GEDR(gpio) = GPIO_bit(gpio); | 
 | } | 
 |  | 
 | static void pxa_mask_muxed_gpio(unsigned int irq) | 
 | { | 
 | 	int gpio = irq - IRQ_GPIO(2) + 2; | 
 | 	__clear_bit(gpio, GPIO_IRQ_mask); | 
 | 	GRER(gpio) &= ~GPIO_bit(gpio); | 
 | 	GFER(gpio) &= ~GPIO_bit(gpio); | 
 | } | 
 |  | 
 | static void pxa_unmask_muxed_gpio(unsigned int irq) | 
 | { | 
 | 	int gpio = irq - IRQ_GPIO(2) + 2; | 
 | 	int idx = gpio >> 5; | 
 | 	__set_bit(gpio, GPIO_IRQ_mask); | 
 | 	GRER(gpio) = GPIO_IRQ_rising_edge[idx] & GPIO_IRQ_mask[idx]; | 
 | 	GFER(gpio) = GPIO_IRQ_falling_edge[idx] & GPIO_IRQ_mask[idx]; | 
 | } | 
 |  | 
 | static struct irqchip pxa_muxed_gpio_chip = { | 
 | 	.ack		= pxa_ack_muxed_gpio, | 
 | 	.mask		= pxa_mask_muxed_gpio, | 
 | 	.unmask		= pxa_unmask_muxed_gpio, | 
 | 	.set_type	= pxa_gpio_irq_type, | 
 | }; | 
 |  | 
 |  | 
 | void __init pxa_init_irq(void) | 
 | { | 
 | 	int irq; | 
 |  | 
 | 	/* disable all IRQs */ | 
 | 	ICMR = 0; | 
 |  | 
 | 	/* all IRQs are IRQ, not FIQ */ | 
 | 	ICLR = 0; | 
 |  | 
 | 	/* clear all GPIO edge detects */ | 
 | 	GFER0 = 0; | 
 | 	GFER1 = 0; | 
 | 	GFER2 = 0; | 
 | 	GRER0 = 0; | 
 | 	GRER1 = 0; | 
 | 	GRER2 = 0; | 
 | 	GEDR0 = GEDR0; | 
 | 	GEDR1 = GEDR1; | 
 | 	GEDR2 = GEDR2; | 
 |  | 
 | #ifdef CONFIG_PXA27x | 
 | 	/* And similarly for the extra regs on the PXA27x */ | 
 | 	ICMR2 = 0; | 
 | 	ICLR2 = 0; | 
 | 	GFER3 = 0; | 
 | 	GRER3 = 0; | 
 | 	GEDR3 = GEDR3; | 
 | #endif | 
 |  | 
 | 	/* only unmasked interrupts kick us out of idle */ | 
 | 	ICCR = 1; | 
 |  | 
 | 	/* GPIO 0 and 1 must have their mask bit always set */ | 
 | 	GPIO_IRQ_mask[0] = 3; | 
 |  | 
 | 	for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) { | 
 | 		set_irq_chip(irq, &pxa_internal_chip_low); | 
 | 		set_irq_handler(irq, do_level_IRQ); | 
 | 		set_irq_flags(irq, IRQF_VALID); | 
 | 	} | 
 |  | 
 | #if PXA_INTERNAL_IRQS > 32 | 
 | 	for (irq = PXA_IRQ(32); irq < PXA_IRQ(PXA_INTERNAL_IRQS); irq++) { | 
 | 		set_irq_chip(irq, &pxa_internal_chip_high); | 
 | 		set_irq_handler(irq, do_level_IRQ); | 
 | 		set_irq_flags(irq, IRQF_VALID); | 
 | 	} | 
 | #endif | 
 |  | 
 | 	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) { | 
 | 		set_irq_chip(irq, &pxa_low_gpio_chip); | 
 | 		set_irq_handler(irq, do_edge_IRQ); | 
 | 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 
 | 	} | 
 |  | 
 | 	for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(PXA_LAST_GPIO); irq++) { | 
 | 		set_irq_chip(irq, &pxa_muxed_gpio_chip); | 
 | 		set_irq_handler(irq, do_edge_IRQ); | 
 | 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); | 
 | 	} | 
 |  | 
 | 	/* Install handler for GPIO>=2 edge detect interrupts */ | 
 | 	set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low); | 
 | 	set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler); | 
 | } |