| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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>
 | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | #include <linux/of.h>
 | 
					
						
							|  |  |  | #include <linux/of_address.h>
 | 
					
						
							|  |  |  | #include <linux/of_irq.h>
 | 
					
						
							|  |  |  | #include <linux/irqdomain.h>
 | 
					
						
							|  |  |  | #include <linux/module.h>
 | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | #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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | static struct irq_domain *lpc32xx_mic_domain; | 
					
						
							|  |  |  | static struct device_node *lpc32xx_mic_np; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 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, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-02-27 17:28:02 +01:00
										 |  |  | 	[IRQ_LPC32XX_GPI_28] = { | 
					
						
							|  |  |  | 		.event_group = &lpc32xx_event_pin_regs, | 
					
						
							|  |  |  | 		.mask = LPC32XX_CLKPWR_EXTSRC_GPI_28_BIT, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 	[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, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-03-12 22:27:28 +01:00
										 |  |  | 	[IRQ_LPC32XX_ETHERNET] = { | 
					
						
							|  |  |  | 		.event_group = &lpc32xx_event_int_regs, | 
					
						
							|  |  |  | 		.mask = LPC32XX_CLKPWR_INTSRC_MAC_BIT, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 	[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); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-29 10:35:20 +01:00
										 |  |  | static void lpc32xx_mask_irq(struct irq_data *d) | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int reg, ctrl, mask; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 	get_controller(d->hwirq, &ctrl, &mask); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) & ~mask; | 
					
						
							|  |  |  | 	__raw_writel(reg, LPC32XX_INTC_MASK(ctrl)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-29 10:35:20 +01:00
										 |  |  | static void lpc32xx_unmask_irq(struct irq_data *d) | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int reg, ctrl, mask; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 	get_controller(d->hwirq, &ctrl, &mask); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	reg = __raw_readl(LPC32XX_INTC_MASK(ctrl)) | mask; | 
					
						
							|  |  |  | 	__raw_writel(reg, LPC32XX_INTC_MASK(ctrl)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-29 10:35:20 +01:00
										 |  |  | static void lpc32xx_ack_irq(struct irq_data *d) | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned int ctrl, mask; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 	get_controller(d->hwirq, &ctrl, &mask); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	__raw_writel(mask, LPC32XX_INTC_RAW_STAT(ctrl)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Also need to clear pending wake event */ | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 	if (lpc32xx_events[d->hwirq].mask != 0) | 
					
						
							|  |  |  | 		__raw_writel(lpc32xx_events[d->hwirq].mask, | 
					
						
							|  |  |  | 			lpc32xx_events[d->hwirq].event_group->rawstat_reg); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-29 10:35:20 +01:00
										 |  |  | static int lpc32xx_set_irq_type(struct irq_data *d, unsigned int type) | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	switch (type) { | 
					
						
							|  |  |  | 	case IRQ_TYPE_EDGE_RISING: | 
					
						
							|  |  |  | 		/* Rising edge sensitive */ | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 		__lpc32xx_set_irq_type(d->hwirq, 1, 1); | 
					
						
							| 
									
										
										
										
											2012-09-06 11:39:10 +02:00
										 |  |  | 		__irq_set_handler_locked(d->hwirq, handle_edge_irq); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case IRQ_TYPE_EDGE_FALLING: | 
					
						
							|  |  |  | 		/* Falling edge sensitive */ | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 		__lpc32xx_set_irq_type(d->hwirq, 0, 1); | 
					
						
							| 
									
										
										
										
											2012-09-06 11:39:10 +02:00
										 |  |  | 		__irq_set_handler_locked(d->hwirq, handle_edge_irq); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case IRQ_TYPE_LEVEL_LOW: | 
					
						
							|  |  |  | 		/* Low level sensitive */ | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 		__lpc32xx_set_irq_type(d->hwirq, 0, 0); | 
					
						
							| 
									
										
										
										
											2012-09-06 11:39:10 +02:00
										 |  |  | 		__irq_set_handler_locked(d->hwirq, handle_level_irq); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case IRQ_TYPE_LEVEL_HIGH: | 
					
						
							|  |  |  | 		/* High level sensitive */ | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 		__lpc32xx_set_irq_type(d->hwirq, 1, 0); | 
					
						
							| 
									
										
										
										
											2012-09-06 11:39:10 +02:00
										 |  |  | 		__irq_set_handler_locked(d->hwirq, handle_level_irq); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 		break; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Other modes are not supported */ | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-29 10:35:20 +01:00
										 |  |  | static int lpc32xx_irq_wake(struct irq_data *d, unsigned int state) | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | { | 
					
						
							|  |  |  | 	unsigned long eventreg; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 	if (lpc32xx_events[d->hwirq].mask != 0) { | 
					
						
							|  |  |  | 		eventreg = __raw_readl(lpc32xx_events[d->hwirq]. | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 			event_group->enab_reg); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (state) | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 			eventreg |= lpc32xx_events[d->hwirq].mask; | 
					
						
							| 
									
										
										
										
											2012-02-27 17:28:02 +01:00
										 |  |  | 		else { | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 			eventreg &= ~lpc32xx_events[d->hwirq].mask; | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-27 17:28:02 +01:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * When disabling the wakeup, clear the latched | 
					
						
							|  |  |  | 			 * event | 
					
						
							|  |  |  | 			 */ | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 			__raw_writel(lpc32xx_events[d->hwirq].mask, | 
					
						
							|  |  |  | 				lpc32xx_events[d->hwirq]. | 
					
						
							| 
									
										
										
										
											2012-02-27 17:28:02 +01:00
										 |  |  | 				event_group->rawstat_reg); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 		__raw_writel(eventreg, | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 			lpc32xx_events[d->hwirq].event_group->enab_reg); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Clear event */ | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 	__raw_writel(lpc32xx_events[d->hwirq].mask, | 
					
						
							|  |  |  | 		lpc32xx_events[d->hwirq].event_group->rawstat_reg); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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 = { | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 	.name = "MIC", | 
					
						
							| 
									
										
										
										
											2010-11-29 10:35:20 +01:00
										 |  |  | 	.irq_ack = lpc32xx_ack_irq, | 
					
						
							|  |  |  | 	.irq_mask = lpc32xx_mask_irq, | 
					
						
							|  |  |  | 	.irq_unmask = lpc32xx_unmask_irq, | 
					
						
							|  |  |  | 	.irq_set_type = lpc32xx_set_irq_type, | 
					
						
							|  |  |  | 	.irq_set_wake = lpc32xx_irq_wake | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | static int __init __lpc32xx_mic_of_init(struct device_node *node, | 
					
						
							|  |  |  | 					struct device_node *parent) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	lpc32xx_mic_np = node; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const struct of_device_id mic_of_match[] __initconst = { | 
					
						
							|  |  |  | 	{ .compatible = "nxp,lpc3220-mic", .data = __lpc32xx_mic_of_init }, | 
					
						
							|  |  |  | 	{ } | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 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)); | 
					
						
							| 
									
										
										
										
											2012-02-27 17:28:02 +01:00
										 |  |  | 	__raw_writel(SIC1_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC1_BASE)); | 
					
						
							|  |  |  | 	__raw_writel(SIC1_ATR_DEFAULT, | 
					
						
							|  |  |  | 				LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC1_BASE)); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Setup SIC2 */ | 
					
						
							|  |  |  | 	__raw_writel(0, LPC32XX_INTC_MASK(LPC32XX_SIC2_BASE)); | 
					
						
							| 
									
										
										
										
											2012-02-27 17:28:02 +01:00
										 |  |  | 	__raw_writel(SIC2_APR_DEFAULT, LPC32XX_INTC_POLAR(LPC32XX_SIC2_BASE)); | 
					
						
							|  |  |  | 	__raw_writel(SIC2_ATR_DEFAULT, | 
					
						
							|  |  |  | 				LPC32XX_INTC_ACT_TYPE(LPC32XX_SIC2_BASE)); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* Configure supported IRQ's */ | 
					
						
							|  |  |  | 	for (i = 0; i < NR_IRQS; i++) { | 
					
						
							| 
									
										
										
										
											2011-03-24 13:35:09 +01:00
										 |  |  | 		irq_set_chip_and_handler(i, &lpc32xx_irq_chip, | 
					
						
							|  |  |  | 					 handle_level_irq); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | 		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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 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); | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	of_irq_init(mic_of_match); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	lpc32xx_mic_domain = irq_domain_add_legacy(lpc32xx_mic_np, NR_IRQS, | 
					
						
							| 
									
										
										
										
											2012-11-07 13:30:50 +01:00
										 |  |  | 						   0, 0, &irq_domain_simple_ops, | 
					
						
							| 
									
										
										
										
											2012-04-22 12:01:19 +02:00
										 |  |  | 						   NULL); | 
					
						
							|  |  |  | 	if (!lpc32xx_mic_domain) | 
					
						
							|  |  |  | 		panic("Unable to add MIC irq domain\n"); | 
					
						
							| 
									
										
										
										
											2012-11-07 13:30:50 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/* MIC SUBIRQx interrupts will route handling to the chain handlers */ | 
					
						
							|  |  |  | 	irq_set_chained_handler(IRQ_LPC32XX_SUB1IRQ, lpc32xx_sic1_handler); | 
					
						
							|  |  |  | 	irq_set_chained_handler(IRQ_LPC32XX_SUB2IRQ, lpc32xx_sic2_handler); | 
					
						
							| 
									
										
										
										
											2010-02-26 15:53:41 -08:00
										 |  |  | } |