Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

m68knommu: external interrupt support to ColdFire intc-2 controller

The EDGE Port module of some ColdFire parts using the intc-2 interrupt
controller provides support for 7 external interrupts. These interrupts
go off-chip (that is they are not for internal peripherals). They need
some special handling and have some extra setup registers. Add code to
support them.

Signed-off-by: Greg Ungerer <gerg@uclinux.org>

+97 -4
+3
arch/m68k/include/asm/m523xsim.h
··· 139 139 /* 140 140 * EPort 141 141 */ 142 + #define MCFEPORT_EPPAR (MCF_IPSBAR + 0x130000) 142 143 #define MCFEPORT_EPDDR (MCF_IPSBAR + 0x130002) 144 + #define MCFEPORT_EPIER (MCF_IPSBAR + 0x130003) 143 145 #define MCFEPORT_EPDR (MCF_IPSBAR + 0x130004) 144 146 #define MCFEPORT_EPPDR (MCF_IPSBAR + 0x130005) 147 + #define MCFEPORT_EPFR (MCF_IPSBAR + 0x130006) 145 148 146 149 /* 147 150 * Generic GPIO support
+3
arch/m68k/include/asm/m527xsim.h
··· 259 259 /* 260 260 * EPort 261 261 */ 262 + #define MCFEPORT_EPPAR (MCF_IPSBAR + 0x130000) 262 263 #define MCFEPORT_EPDDR (MCF_IPSBAR + 0x130002) 264 + #define MCFEPORT_EPIER (MCF_IPSBAR + 0x130003) 263 265 #define MCFEPORT_EPDR (MCF_IPSBAR + 0x130004) 264 266 #define MCFEPORT_EPPDR (MCF_IPSBAR + 0x130005) 267 + #define MCFEPORT_EPFR (MCF_IPSBAR + 0x130006) 265 268 266 269 /* 267 270 * GPIO pins setups to enable the UARTs.
+10
arch/m68k/include/asm/m54xxsim.h
··· 50 50 #define MCFGPIO_IRQ_VECBASE -1 51 51 52 52 /* 53 + * EDGE Port support. 54 + */ 55 + #define MCFEPORT_EPPAR (MCF_MBAR + 0xf00) /* Pin assignment */ 56 + #define MCFEPORT_EPDDR (MCF_MBAR + 0xf04) /* Data direction */ 57 + #define MCFEPORT_EPIER (MCF_MBAR + 0xf05) /* Interrupt enable */ 58 + #define MCFEPORT_EPDR (MCF_MBAR + 0xf08) /* Port data (w) */ 59 + #define MCFEPORT_EPPDR (MCF_MBAR + 0xf09) /* Port data (r) */ 60 + #define MCFEPORT_EPFR (MCF_MBAR + 0xf0c) /* Flags */ 61 + 62 + /* 53 63 * Some PSC related definitions 54 64 */ 55 65 #define MCF_PAR_PSC(x) (0x000A4F-((x)&0x3))
+81 -4
arch/m68knommu/platform/coldfire/intc-2.c
··· 7 7 * family, the 5270, 5271, 5274, 5275, and the 528x family which have two such 8 8 * controllers, and the 547x and 548x families which have only one of them. 9 9 * 10 - * (C) Copyright 2009, Greg Ungerer <gerg@snapgear.com> 10 + * The external 7 fixed interrupts are part the the Edge Port unit of these 11 + * ColdFire parts. They can be configured as level or edge triggered. 12 + * 13 + * (C) Copyright 2009-2011, Greg Ungerer <gerg@snapgear.com> 11 14 * 12 15 * This file is subject to the terms and conditions of the GNU General Public 13 16 * License. See the file COPYING in the main directory of this archive ··· 32 29 */ 33 30 #define MCFSIM_ICR_LEVEL(l) ((l)<<3) /* Level l intr */ 34 31 #define MCFSIM_ICR_PRI(p) (p) /* Priority p intr */ 32 + 33 + /* 34 + * The EDGE Port interrupts are the fixed 7 external interrupts. 35 + * They need some special treatment, for example they need to be acked. 36 + */ 37 + #define EINT0 64 /* Is not actually used, but spot reserved for it */ 38 + #define EINT1 65 /* EDGE Port interrupt 1 */ 39 + #define EINT7 71 /* EDGE Port interrupt 7 */ 35 40 36 41 #ifdef MCFICM_INTC1 37 42 #define NR_VECS 128 ··· 87 76 __raw_writel(val & ~imrbit, imraddr); 88 77 } 89 78 90 - static int intc_irq_set_type(struct irq_data *d, unsigned int type) 79 + /* 80 + * Only the external (or EDGE Port) interrupts need to be acknowledged 81 + * here, as part of the IRQ handler. They only really need to be ack'ed 82 + * if they are in edge triggered mode, but there is no harm in doing it 83 + * for all types. 84 + */ 85 + static void intc_irq_ack(struct irq_data *d) 91 86 { 92 - return 0; 87 + unsigned int irq = d->irq; 88 + 89 + __raw_writeb(0x1 << (irq - EINT0), MCFEPORT_EPFR); 93 90 } 94 91 95 92 /* ··· 123 104 if (__raw_readb(icraddr) == 0) 124 105 __raw_writeb(intc_intpri--, icraddr); 125 106 107 + irq = d->irq; 108 + if ((irq >= EINT1) && (irq <= EINT7)) { 109 + u8 v; 110 + 111 + irq -= EINT0; 112 + 113 + /* Set EPORT line as input */ 114 + v = __raw_readb(MCFEPORT_EPDDR); 115 + __raw_writeb(v & ~(0x1 << irq), MCFEPORT_EPDDR); 116 + 117 + /* Set EPORT line as interrupt source */ 118 + v = __raw_readb(MCFEPORT_EPIER); 119 + __raw_writeb(v | (0x1 << irq), MCFEPORT_EPIER); 120 + } 121 + 126 122 intc_irq_unmask(d); 123 + return 0; 124 + } 125 + 126 + static int intc_irq_set_type(struct irq_data *d, unsigned int type) 127 + { 128 + unsigned int irq = d->irq; 129 + u16 pa, tb; 130 + 131 + switch (type) { 132 + case IRQ_TYPE_EDGE_RISING: 133 + tb = 0x1; 134 + break; 135 + case IRQ_TYPE_EDGE_FALLING: 136 + tb = 0x2; 137 + break; 138 + case IRQ_TYPE_EDGE_BOTH: 139 + tb = 0x3; 140 + break; 141 + default: 142 + /* Level triggered */ 143 + tb = 0; 144 + break; 145 + } 146 + 147 + if (tb) 148 + set_irq_handler(irq, handle_edge_irq); 149 + 150 + irq -= EINT0; 151 + pa = __raw_readw(MCFEPORT_EPPAR); 152 + pa = (pa & ~(0x3 << (irq * 2))) | (tb << (irq * 2)); 153 + __raw_writew(pa, MCFEPORT_EPPAR); 154 + 127 155 return 0; 128 156 } 129 157 ··· 179 113 .irq_startup = intc_irq_startup, 180 114 .irq_mask = intc_irq_mask, 181 115 .irq_unmask = intc_irq_unmask, 116 + }; 117 + 118 + static struct irq_chip intc_irq_chip_edge_port = { 119 + .name = "CF-INTC-EP", 120 + .irq_startup = intc_irq_startup, 121 + .irq_mask = intc_irq_mask, 122 + .irq_unmask = intc_irq_unmask, 123 + .irq_ack = intc_irq_ack, 182 124 .irq_set_type = intc_irq_set_type, 183 125 }; 184 126 ··· 203 129 #endif 204 130 205 131 for (irq = MCFINT_VECBASE; (irq < MCFINT_VECBASE + NR_VECS); irq++) { 206 - set_irq_chip(irq, &intc_irq_chip); 132 + if ((irq >= EINT1) && (irq <=EINT7)) 133 + set_irq_chip(irq, &intc_irq_chip_edge_port); 134 + else 135 + set_irq_chip(irq, &intc_irq_chip); 207 136 set_irq_type(irq, IRQ_TYPE_LEVEL_HIGH); 208 137 set_irq_handler(irq, handle_level_irq); 209 138 }