1/* arch/arm/mach-lh7a40x/irq-lpd7a40x.c 2 * 3 * Copyright (C) 2004 Coastal Environmental Systems 4 * Copyright (C) 2004 Logic Product Development 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public License 8 * version 2 as published by the Free Software Foundation. 9 * 10 */ 11 12#include <linux/init.h> 13#include <linux/module.h> 14#include <linux/interrupt.h> 15 16#include <mach/hardware.h> 17#include <asm/irq.h> 18#include <asm/mach/irq.h> 19#include <mach/irqs.h> 20 21#include "common.h" 22 23static void lh7a40x_ack_cpld_irq (u32 irq) 24{ 25 /* CPLD doesn't have ack capability */ 26} 27 28static void lh7a40x_mask_cpld_irq (u32 irq) 29{ 30 switch (irq) { 31 case IRQ_LPD7A40X_ETH_INT: 32 CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x4; 33 break; 34 case IRQ_LPD7A400_TS: 35 CPLD_INTERRUPTS = CPLD_INTERRUPTS | 0x8; 36 break; 37 } 38} 39 40static void lh7a40x_unmask_cpld_irq (u32 irq) 41{ 42 switch (irq) { 43 case IRQ_LPD7A40X_ETH_INT: 44 CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x4; 45 break; 46 case IRQ_LPD7A400_TS: 47 CPLD_INTERRUPTS = CPLD_INTERRUPTS & ~ 0x8; 48 break; 49 } 50} 51 52static struct irq_chip lh7a40x_cpld_chip = { 53 .name = "CPLD", 54 .ack = lh7a40x_ack_cpld_irq, 55 .mask = lh7a40x_mask_cpld_irq, 56 .unmask = lh7a40x_unmask_cpld_irq, 57}; 58 59static void lh7a40x_cpld_handler (unsigned int irq, struct irq_desc *desc) 60{ 61 unsigned int mask = CPLD_INTERRUPTS; 62 63 desc->chip->ack (irq); 64 65 if ((mask & 0x1) == 0) /* WLAN */ 66 generic_handle_irq(IRQ_LPD7A40X_ETH_INT); 67 68 if ((mask & 0x2) == 0) /* Touch */ 69 generic_handle_irq(IRQ_LPD7A400_TS); 70 71 desc->chip->unmask (irq); /* Level-triggered need this */ 72} 73 74 75 /* IRQ initialization */ 76 77void __init lh7a40x_init_board_irq (void) 78{ 79 int irq; 80 81 /* Rev A (v2.8): PF0, PF1, PF2, and PF3 are available IRQs. 82 PF7 supports the CPLD. 83 Rev B (v3.4): PF0, PF1, and PF2 are available IRQs. 84 PF3 supports the CPLD. 85 (Some) LPD7A404 prerelease boards report a version 86 number of 0x16, but we force an override since the 87 hardware is of the newer variety. 88 */ 89 90 unsigned char cpld_version = CPLD_REVISION; 91 int pinCPLD; 92 93#if defined CONFIG_MACH_LPD7A404 94 cpld_version = 0x34; /* Override, for now */ 95#endif 96 pinCPLD = (cpld_version == 0x28) ? 7 : 3; 97 98 /* First, configure user controlled GPIOF interrupts */ 99 100 GPIO_PFDD &= ~0x0f; /* PF0-3 are inputs */ 101 GPIO_INTTYPE1 &= ~0x0f; /* PF0-3 are level triggered */ 102 GPIO_INTTYPE2 &= ~0x0f; /* PF0-3 are active low */ 103 barrier (); 104 GPIO_GPIOFINTEN |= 0x0f; /* Enable PF0, PF1, PF2, and PF3 IRQs */ 105 106 /* Then, configure CPLD interrupt */ 107 108 CPLD_INTERRUPTS = 0x0c; /* Disable all CPLD interrupts */ 109 GPIO_PFDD &= ~(1 << pinCPLD); /* Make input */ 110 GPIO_INTTYPE1 |= (1 << pinCPLD); /* Edge triggered */ 111 GPIO_INTTYPE2 &= ~(1 << pinCPLD); /* Active low */ 112 barrier (); 113 GPIO_GPIOFINTEN |= (1 << pinCPLD); /* Enable */ 114 115 /* Cascade CPLD interrupts */ 116 117 for (irq = IRQ_BOARD_START; 118 irq < IRQ_BOARD_START + NR_IRQ_BOARD; ++irq) { 119 set_irq_chip (irq, &lh7a40x_cpld_chip); 120 set_irq_handler (irq, handle_edge_irq); 121 set_irq_flags (irq, IRQF_VALID); 122 } 123 124 set_irq_chained_handler ((cpld_version == 0x28) 125 ? IRQ_CPLD_V28 126 : IRQ_CPLD_V34, 127 lh7a40x_cpld_handler); 128} 129