1/* 2 * arch/arm/mach-pnx4008/irq.c 3 * 4 * PNX4008 IRQ controller driver 5 * 6 * Author: Dmitry Chigirev <source@mvista.com> 7 * 8 * Based on reference code received from Philips: 9 * Copyright (C) 2003 Philips Semiconductors 10 * 11 * 2005 (c) MontaVista Software, Inc. This file is licensed under 12 * the terms of the GNU General Public License version 2. This program 13 * is licensed "as is" without any warranty of any kind, whether express 14 * or implied. 15 */ 16 17#include <linux/kernel.h> 18#include <linux/types.h> 19#include <linux/mm.h> 20#include <linux/interrupt.h> 21#include <linux/list.h> 22#include <linux/init.h> 23#include <linux/ioport.h> 24#include <linux/device.h> 25#include <linux/irq.h> 26#include <linux/io.h> 27#include <mach/hardware.h> 28#include <asm/setup.h> 29#include <asm/pgtable.h> 30#include <asm/page.h> 31#include <asm/system.h> 32#include <asm/mach/arch.h> 33#include <asm/mach/irq.h> 34#include <asm/mach/map.h> 35#include <mach/irq.h> 36 37static u8 pnx4008_irq_type[NR_IRQS] = PNX4008_IRQ_TYPES; 38 39static void pnx4008_mask_irq(unsigned int irq) 40{ 41 __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */ 42} 43 44static void pnx4008_unmask_irq(unsigned int irq) 45{ 46 __raw_writel(__raw_readl(INTC_ER(irq)) | INTC_BIT(irq), INTC_ER(irq)); /* unmask interrupt */ 47} 48 49static void pnx4008_mask_ack_irq(unsigned int irq) 50{ 51 __raw_writel(__raw_readl(INTC_ER(irq)) & ~INTC_BIT(irq), INTC_ER(irq)); /* mask interrupt */ 52 __raw_writel(INTC_BIT(irq), INTC_SR(irq)); /* clear interrupt status */ 53} 54 55static int pnx4008_set_irq_type(unsigned int irq, unsigned int type) 56{ 57 switch (type) { 58 case IRQ_TYPE_EDGE_RISING: 59 __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq)); /*edge sensitive */ 60 __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq)); /*rising edge */ 61 set_irq_handler(irq, handle_edge_irq); 62 break; 63 case IRQ_TYPE_EDGE_FALLING: 64 __raw_writel(__raw_readl(INTC_ATR(irq)) | INTC_BIT(irq), INTC_ATR(irq)); /*edge sensitive */ 65 __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq)); /*falling edge */ 66 set_irq_handler(irq, handle_edge_irq); 67 break; 68 case IRQ_TYPE_LEVEL_LOW: 69 __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq)); /*level sensitive */ 70 __raw_writel(__raw_readl(INTC_APR(irq)) & ~INTC_BIT(irq), INTC_APR(irq)); /*low level */ 71 set_irq_handler(irq, handle_level_irq); 72 break; 73 case IRQ_TYPE_LEVEL_HIGH: 74 __raw_writel(__raw_readl(INTC_ATR(irq)) & ~INTC_BIT(irq), INTC_ATR(irq)); /*level sensitive */ 75 __raw_writel(__raw_readl(INTC_APR(irq)) | INTC_BIT(irq), INTC_APR(irq)); /* high level */ 76 set_irq_handler(irq, handle_level_irq); 77 break; 78 79 /* IRQ_TYPE_EDGE_BOTH is not supported */ 80 default: 81 printk(KERN_ERR "PNX4008 IRQ: Unsupported irq type %d\n", type); 82 return -1; 83 } 84 return 0; 85} 86 87static struct irq_chip pnx4008_irq_chip = { 88 .ack = pnx4008_mask_ack_irq, 89 .mask = pnx4008_mask_irq, 90 .unmask = pnx4008_unmask_irq, 91 .set_type = pnx4008_set_irq_type, 92}; 93 94void __init pnx4008_init_irq(void) 95{ 96 unsigned int i; 97 98 /* configure IRQ's */ 99 for (i = 0; i < NR_IRQS; i++) { 100 set_irq_flags(i, IRQF_VALID); 101 set_irq_chip(i, &pnx4008_irq_chip); 102 pnx4008_set_irq_type(i, pnx4008_irq_type[i]); 103 } 104 105 /* configure and enable IRQ 0,1,30,31 (cascade interrupts) */ 106 pnx4008_set_irq_type(SUB1_IRQ_N, pnx4008_irq_type[SUB1_IRQ_N]); 107 pnx4008_set_irq_type(SUB2_IRQ_N, pnx4008_irq_type[SUB2_IRQ_N]); 108 pnx4008_set_irq_type(SUB1_FIQ_N, pnx4008_irq_type[SUB1_FIQ_N]); 109 pnx4008_set_irq_type(SUB2_FIQ_N, pnx4008_irq_type[SUB2_FIQ_N]); 110 111 /* mask all others */ 112 __raw_writel((1 << SUB2_FIQ_N) | (1 << SUB1_FIQ_N) | 113 (1 << SUB2_IRQ_N) | (1 << SUB1_IRQ_N), 114 INTC_ER(MAIN_BASE_INT)); 115 __raw_writel(0, INTC_ER(SIC1_BASE_INT)); 116 __raw_writel(0, INTC_ER(SIC2_BASE_INT)); 117} 118