| /* | 
 |  * arch/arm/mach-lpc32xx/irq.c | 
 |  * | 
 |  * Author: Kevin Wells <kevin.wells@nxp.com> | 
 |  * | 
 |  * Copyright (C) 2010 NXP Semiconductors | 
 |  * | 
 |  * This program is free software; you can redistribute it and/or modify | 
 |  * it under the terms of the GNU General Public License as published by | 
 |  * the Free Software Foundation; either version 2 of the License, or | 
 |  * (at your option) any later version. | 
 |  * | 
 |  * This program is distributed in the hope that it will be useful, | 
 |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
 |  * GNU General Public License for more details. | 
 |  */ | 
 |  | 
 | #include <linux/kernel.h> | 
 | #include <linux/types.h> | 
 | #include <linux/interrupt.h> | 
 | #include <linux/irq.h> | 
 | #include <linux/err.h> | 
 | #include <linux/io.h> | 
 |  | 
 | #include <mach/irqs.h> | 
 | #include <mach/hardware.h> | 
 | #include <mach/platform.h> | 
 | #include "common.h" | 
 |  | 
 | /* | 
 |  * Default value representing the Activation polarity of all internal | 
 |  * interrupt sources | 
 |  */ | 
 | #define MIC_APR_DEFAULT		0x3FF0EFE0 | 
 | #define SIC1_APR_DEFAULT	0xFBD27186 | 
 | #define SIC2_APR_DEFAULT	0x801810C0 | 
 |  | 
 | /* | 
 |  * Default value representing the Activation Type of all internal | 
 |  * interrupt sources. All are level sensitive. | 
 |  */ | 
 | #define MIC_ATR_DEFAULT		0x00000000 | 
 | #define SIC1_ATR_DEFAULT	0x00026000 | 
 | #define SIC2_ATR_DEFAULT	0x00000000 | 
 |  | 
 | struct lpc32xx_event_group_regs { | 
 | 	void __iomem *enab_reg; | 
 | 	void __iomem *edge_reg; | 
 | 	void __iomem *maskstat_reg; | 
 | 	void __iomem *rawstat_reg; | 
 | }; | 
 |  | 
 | static const struct lpc32xx_event_group_regs lpc32xx_event_int_regs = { | 
 | 	.enab_reg = LPC32XX_CLKPWR_INT_ER, | 
 | 	.edge_reg = LPC32XX_CLKPWR_INT_AP, | 
 | 	.maskstat_reg = LPC32XX_CLKPWR_INT_SR, | 
 | 	.rawstat_reg = LPC32XX_CLKPWR_INT_RS, | 
 | }; | 
 |  | 
 | static const struct lpc32xx_event_group_regs lpc32xx_event_pin_regs = { | 
 | 	.enab_reg = LPC32XX_CLKPWR_PIN_ER, | 
 | 	.edge_reg = LPC32XX_CLKPWR_PIN_AP, | 
 | 	.maskstat_reg = LPC32XX_CLKPWR_PIN_SR, | 
 | 	.rawstat_reg = LPC32XX_CLKPWR_PIN_RS, | 
 | }; | 
 |  | 
 | struct lpc32xx_event_info { | 
 | 	const struct lpc32xx_event_group_regs *event_group; | 
 | 	u32 mask; | 
 | }; | 
 |  | 
 | /* | 
 |  * Maps an IRQ number to and event mask and register | 
 |  */ | 
 | static const struct lpc32xx_event_info lpc32xx_events[NR_IRQS] = { | 
 | 	[IRQ_LPC32XX_GPI_08] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_08_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_09] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_09_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_19] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_19_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_07] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_07_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_00] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_00_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_01] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_01_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_02] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_02_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_03] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_03_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_04] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_04_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_05] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_05_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPI_06] = { | 
 | 		.event_group = &lpc32xx_event_pin_regs, | 
 | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_06_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPIO_00] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_GPIO_00_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPIO_01] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_GPIO_01_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPIO_02] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_GPIO_02_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPIO_03] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_GPIO_03_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPIO_04] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_GPIO_04_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_GPIO_05] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_GPIO_05_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_KEY] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_KEY_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_USB_OTG_ATX] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_USBATXINT_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_USB_HOST] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_USB_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_RTC] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_RTC_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_MSTIMER] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_TS_AUX] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_TS_AUX_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_TS_P] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_TS_P_BIT, | 
 | 	}, | 
 | 	[IRQ_LPC32XX_TS_IRQ] = { | 
 | 		.event_group = &lpc32xx_event_int_regs, | 
 | 		.mask = LPC32XX_CLKPWR_INTSRC_ADC_BIT, | 
 | 	}, | 
 | }; | 
 |  | 
 | static void get_controller(unsigned int irq, unsigned int *base, | 
 | 	unsigned int *irqbit) | 
 | { | 
 | 	if (irq < 32) { | 
 | 		*base = LPC32XX_MIC_BASE; | 
 | 		*irqbit = 1 << irq; | 
 | 	} else if (irq < 64) { | 
 | 		*base = LPC32XX_SIC1_BASE; | 
 | 		*irqbit = 1 << (irq - 32); | 
 | 	} else { | 
 | 		*base = LPC32XX_SIC2_BASE; | 
 | 		*irqbit = 1 << (irq - 64); | 
 | 	} | 
 | } | 
 |  | 
 | static void lpc32xx_mask_irq(unsigned int irq) | 
 | { | 
 | 	unsigned int reg, ctrl, mask; | 
 |  | 
 | 	get_controller(irq, &ctrl, &mask); | 
 |  | 
 | 	reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask; | 
 | 	__raw_writel(reg, LPC32XX_INTC_MASK(ctrl)); | 
 | } | 
 |  | 
 | static void lpc32xx_unmask_irq(unsigned int irq) | 
 | { | 
 | 	unsigned int reg, ctrl, mask; | 
 |  | 
 | 	get_controller(irq, &ctrl, &mask); | 
 |  | 
 | 	reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask; | 
 | 	__raw_writel(reg, LPC32XX_INTC_MASK(ctrl)); | 
 | } | 
 |  | 
 | static void lpc32xx_ack_irq(unsigned int irq) | 
 | { | 
 | 	unsigned int ctrl, mask; | 
 |  | 
 | 	get_controller(irq, &ctrl, &mask); | 
 |  | 
 | 	__raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl)); | 
 |  | 
 | 	/* Also need to clear pending wake event */ | 
 | 	if (lpc32xx_events[irq].mask != 0) | 
 | 		__raw_writel(lpc32xx_events[irq].mask, | 
 | 			lpc32xx_events[irq].event_group->rawstat_reg); | 
 | } | 
 |  | 
 | static void __lpc32xx_set_irq_type(unsigned int irq, int use_high_level, | 
 | 	int use_edge) | 
 | { | 
 | 	unsigned int reg, ctrl, mask; | 
 |  | 
 | 	get_controller(irq, &ctrl, &mask); | 
 |  | 
 | 	/* Activation level, high or low */ | 
 | 	reg = __raw_readl(LPC32XX_INTC_POLAR(ctrl)); | 
 | 	if (use_high_level) | 
 | 		reg |= mask; | 
 | 	else | 
 | 		reg &= ~mask; | 
 | 	__raw_writel(reg, LPC32XX_INTC_POLAR(ctrl)); | 
 |  | 
 | 	/* Activation type, edge or level */ | 
 | 	reg = __raw_readl(LPC32XX_INTC_ACT_TYPE(ctrl)); | 
 | 	if (use_edge) | 
 | 		reg |= mask; | 
 | 	else | 
 | 		reg &= ~mask; | 
 | 	__raw_writel(reg, LPC32XX_INTC_ACT_TYPE(ctrl)); | 
 |  | 
 | 	/* Use same polarity for the wake events */ | 
 | 	if (lpc32xx_events[irq].mask != 0) { | 
 | 		reg = __raw_readl(lpc32xx_events[irq].event_group->edge_reg); | 
 |  | 
 | 		if (use_high_level) | 
 | 			reg |= lpc32xx_events[irq].mask; | 
 | 		else | 
 | 			reg &= ~lpc32xx_events[irq].mask; | 
 |  | 
 | 		__raw_writel(reg, lpc32xx_events[irq].event_group->edge_reg); | 
 | 	} | 
 | } | 
 |  | 
 | static int lpc32xx_set_irq_type(unsigned int irq, unsigned int type) | 
 | { | 
 | 	switch (type) { | 
 | 	case IRQ_TYPE_EDGE_RISING: | 
 | 		/* Rising edge sensitive */ | 
 | 		__lpc32xx_set_irq_type(irq, 1, 1); | 
 | 		break; | 
 |  | 
 | 	case IRQ_TYPE_EDGE_FALLING: | 
 | 		/* Falling edge sensitive */ | 
 | 		__lpc32xx_set_irq_type(irq, 0, 1); | 
 | 		break; | 
 |  | 
 | 	case IRQ_TYPE_LEVEL_LOW: | 
 | 		/* Low level sensitive */ | 
 | 		__lpc32xx_set_irq_type(irq, 0, 0); | 
 | 		break; | 
 |  | 
 | 	case IRQ_TYPE_LEVEL_HIGH: | 
 | 		/* High level sensitive */ | 
 | 		__lpc32xx_set_irq_type(irq, 1, 0); | 
 | 		break; | 
 |  | 
 | 	/* Other modes are not supported */ | 
 | 	default: | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	/* Ok to use the level handler for all types */ | 
 | 	set_irq_handler(irq, handle_level_irq); | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int lpc32xx_irq_wake(unsigned int irqno, unsigned int state) | 
 | { | 
 | 	unsigned long eventreg; | 
 |  | 
 | 	if (lpc32xx_events[irqno].mask != 0) { | 
 | 		eventreg = __raw_readl(lpc32xx_events[irqno]. | 
 | 			event_group->enab_reg); | 
 |  | 
 | 		if (state) | 
 | 			eventreg |= lpc32xx_events[irqno].mask; | 
 | 		else | 
 | 			eventreg &= ~lpc32xx_events[irqno].mask; | 
 |  | 
 | 		__raw_writel(eventreg, | 
 | 			lpc32xx_events[irqno].event_group->enab_reg); | 
 |  | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	/* Clear event */ | 
 | 	__raw_writel(lpc32xx_events[irqno].mask, | 
 | 		lpc32xx_events[irqno].event_group->rawstat_reg); | 
 |  | 
 | 	return -ENODEV; | 
 | } | 
 |  | 
 | static void __init lpc32xx_set_default_mappings(unsigned int apr, | 
 | 	unsigned int atr, unsigned int offset) | 
 | { | 
 | 	unsigned int i; | 
 |  | 
 | 	/* Set activation levels for each interrupt */ | 
 | 	i = 0; | 
 | 	while (i < 32) { | 
 | 		__lpc32xx_set_irq_type(offset + i, ((apr >> i) & 0x1), | 
 | 			((atr >> i) & 0x1)); | 
 | 		i++; | 
 | 	} | 
 | } | 
 |  | 
 | static struct irq_chip lpc32xx_irq_chip = { | 
 | 	.ack = lpc32xx_ack_irq, | 
 | 	.mask = lpc32xx_mask_irq, | 
 | 	.unmask = lpc32xx_unmask_irq, | 
 | 	.set_type = lpc32xx_set_irq_type, | 
 | 	.set_wake = lpc32xx_irq_wake | 
 | }; | 
 |  | 
 | static void lpc32xx_sic1_handler(unsigned int irq, struct irq_desc *desc) | 
 | { | 
 | 	unsigned long ints = __raw_readl(LPC32XX_INTC_STAT(LPC32XX_SIC1_BASE)); | 
 |  | 
 | 	while (ints != 0) { | 
 | 		int irqno = fls(ints) - 1; | 
 |  | 
 | 		ints &= ~(1 << irqno); | 
 |  | 
 | 		generic_handle_irq(LPC32XX_SIC1_IRQ(irqno)); | 
 | 	} | 
 | } | 
 |  | 
 | static void lpc32xx_sic2_handler(unsigned int irq, struct irq_desc *desc) | 
 | { | 
 | 	unsigned long ints = __raw_readl(LPC32XX_INTC_STAT(LPC32XX_SIC2_BASE)); | 
 |  | 
 | 	while (ints != 0) { | 
 | 		int irqno = fls(ints) - 1; | 
 |  | 
 | 		ints &= ~(1 << irqno); | 
 |  | 
 | 		generic_handle_irq(LPC32XX_SIC2_IRQ(irqno)); | 
 | 	} | 
 | } | 
 |  | 
 | void __init lpc32xx_init_irq(void) | 
 | { | 
 | 	unsigned int i; | 
 |  | 
 | 	/* Setup MIC */ | 
 | 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE)); | 
 | 	__raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_MIC_BASE)); | 
 | 	__raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_MIC_BASE)); | 
 |  | 
 | 	/* Setup SIC1 */ | 
 | 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE)); | 
 | 	__raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE)); | 
 | 	__raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE)); | 
 |  | 
 | 	/* Setup SIC2 */ | 
 | 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE)); | 
 | 	__raw_writel(MIC_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE)); | 
 | 	__raw_writel(MIC_ATR_DEFAULT, LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE)); | 
 |  | 
 | 	/* Configure supported IRQ's */ | 
 | 	for (i = 0; i < NR_IRQS; i++) { | 
 | 		set_irq_chip(i, &lpc32xx_irq_chip); | 
 | 		set_irq_handler(i, handle_level_irq); | 
 | 		set_irq_flags(i, IRQF_VALID); | 
 | 	} | 
 |  | 
 | 	/* Set default mappings */ | 
 | 	lpc32xx_set_default_mappings(MIC_APR_DEFAULT, MIC_ATR_DEFAULT, 0); | 
 | 	lpc32xx_set_default_mappings(SIC1_APR_DEFAULT, SIC1_ATR_DEFAULT, 32); | 
 | 	lpc32xx_set_default_mappings(SIC2_APR_DEFAULT, SIC2_ATR_DEFAULT, 64); | 
 |  | 
 | 	/* mask all interrupts except SUBIRQ */ | 
 | 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_MIC_BASE)); | 
 | 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC1_BASE)); | 
 | 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE)); | 
 |  | 
 | 	/* MIC SUBIRQx interrupts will route handling to the chain handlers */ | 
 | 	set_irq_chained_handler(IRQ_LPC32XX_SUB1IRQ, lpc32xx_sic1_handler); | 
 | 	set_irq_chained_handler(IRQ_LPC32XX_SUB2IRQ, lpc32xx_sic2_handler); | 
 |  | 
 | 	/* Initially disable all wake events */ | 
 | 	__raw_writel(0, LPC32XX_CLKPWR_P01_ER); | 
 | 	__raw_writel(0, LPC32XX_CLKPWR_INT_ER); | 
 | 	__raw_writel(0, LPC32XX_CLKPWR_PIN_ER); | 
 |  | 
 | 	/* | 
 | 	 * Default wake activation polarities, all pin sources are low edge | 
 | 	 * triggered | 
 | 	 */ | 
 | 	__raw_writel(LPC32XX_CLKPWR_INTSRC_TS_P_BIT | | 
 | 		LPC32XX_CLKPWR_INTSRC_MSTIMER_BIT | | 
 | 		LPC32XX_CLKPWR_INTSRC_RTC_BIT, | 
 | 		LPC32XX_CLKPWR_INT_AP); | 
 | 	__raw_writel(0, LPC32XX_CLKPWR_PIN_AP); | 
 |  | 
 | 	/* Clear latched wake event states */ | 
 | 	__raw_writel(__raw_readl(LPC32XX_CLKPWR_PIN_RS), | 
 | 		LPC32XX_CLKPWR_PIN_RS); | 
 | 	__raw_writel(__raw_readl(LPC32XX_CLKPWR_INT_RS), | 
 | 		LPC32XX_CLKPWR_INT_RS); | 
 | } |