aboutsummaryrefslogtreecommitdiffstats
path: root/arch/avr32/mach-at32ap/extint.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/avr32/mach-at32ap/extint.c')
-rw-r--r--arch/avr32/mach-at32ap/extint.c59
1 files changed, 40 insertions, 19 deletions
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c
index f5bfd4c81fe7..c36a6d59d6f0 100644
--- a/arch/avr32/mach-at32ap/extint.c
+++ b/arch/avr32/mach-at32ap/extint.c
@@ -26,16 +26,10 @@
26#define EIC_MODE 0x0014 26#define EIC_MODE 0x0014
27#define EIC_EDGE 0x0018 27#define EIC_EDGE 0x0018
28#define EIC_LEVEL 0x001c 28#define EIC_LEVEL 0x001c
29#define EIC_TEST 0x0020
30#define EIC_NMIC 0x0024 29#define EIC_NMIC 0x0024
31 30
32/* Bitfields in TEST */
33#define EIC_TESTEN_OFFSET 31
34#define EIC_TESTEN_SIZE 1
35
36/* Bitfields in NMIC */ 31/* Bitfields in NMIC */
37#define EIC_EN_OFFSET 0 32#define EIC_NMIC_ENABLE (1 << 0)
38#define EIC_EN_SIZE 1
39 33
40/* Bit manipulation macros */ 34/* Bit manipulation macros */
41#define EIC_BIT(name) \ 35#define EIC_BIT(name) \
@@ -63,6 +57,9 @@ struct eic {
63 unsigned int first_irq; 57 unsigned int first_irq;
64}; 58};
65 59
60static struct eic *nmi_eic;
61static bool nmi_enabled;
62
66static void eic_ack_irq(unsigned int irq) 63static void eic_ack_irq(unsigned int irq)
67{ 64{
68 struct eic *eic = get_irq_chip_data(irq); 65 struct eic *eic = get_irq_chip_data(irq);
@@ -133,8 +130,11 @@ static int eic_set_irq_type(unsigned int irq, unsigned int flow_type)
133 eic_writel(eic, EDGE, edge); 130 eic_writel(eic, EDGE, edge);
134 eic_writel(eic, LEVEL, level); 131 eic_writel(eic, LEVEL, level);
135 132
136 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) 133 if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) {
137 flow_type |= IRQ_LEVEL; 134 flow_type |= IRQ_LEVEL;
135 __set_irq_handler_unlocked(irq, handle_level_irq);
136 } else
137 __set_irq_handler_unlocked(irq, handle_edge_irq);
138 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL); 138 desc->status &= ~(IRQ_TYPE_SENSE_MASK | IRQ_LEVEL);
139 desc->status |= flow_type; 139 desc->status |= flow_type;
140 } 140 }
@@ -154,9 +154,8 @@ static struct irq_chip eic_chip = {
154static void demux_eic_irq(unsigned int irq, struct irq_desc *desc) 154static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
155{ 155{
156 struct eic *eic = desc->handler_data; 156 struct eic *eic = desc->handler_data;
157 struct irq_desc *ext_desc;
158 unsigned long status, pending; 157 unsigned long status, pending;
159 unsigned int i, ext_irq; 158 unsigned int i;
160 159
161 status = eic_readl(eic, ISR); 160 status = eic_readl(eic, ISR);
162 pending = status & eic_readl(eic, IMR); 161 pending = status & eic_readl(eic, IMR);
@@ -165,15 +164,28 @@ static void demux_eic_irq(unsigned int irq, struct irq_desc *desc)
165 i = fls(pending) - 1; 164 i = fls(pending) - 1;
166 pending &= ~(1 << i); 165 pending &= ~(1 << i);
167 166
168 ext_irq = i + eic->first_irq; 167 generic_handle_irq(i + eic->first_irq);
169 ext_desc = irq_desc + ext_irq;
170 if (ext_desc->status & IRQ_LEVEL)
171 handle_level_irq(ext_irq, ext_desc);
172 else
173 handle_edge_irq(ext_irq, ext_desc);
174 } 168 }
175} 169}
176 170
171int nmi_enable(void)
172{
173 nmi_enabled = true;
174
175 if (nmi_eic)
176 eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
177
178 return 0;
179}
180
181void nmi_disable(void)
182{
183 if (nmi_eic)
184 eic_writel(nmi_eic, NMIC, 0);
185
186 nmi_enabled = false;
187}
188
177static int __init eic_probe(struct platform_device *pdev) 189static int __init eic_probe(struct platform_device *pdev)
178{ 190{
179 struct eic *eic; 191 struct eic *eic;
@@ -214,14 +226,13 @@ static int __init eic_probe(struct platform_device *pdev)
214 pattern = eic_readl(eic, MODE); 226 pattern = eic_readl(eic, MODE);
215 nr_irqs = fls(pattern); 227 nr_irqs = fls(pattern);
216 228
217 /* Trigger on falling edge unless overridden by driver */ 229 /* Trigger on low level unless overridden by driver */
218 eic_writel(eic, MODE, 0UL);
219 eic_writel(eic, EDGE, 0UL); 230 eic_writel(eic, EDGE, 0UL);
231 eic_writel(eic, LEVEL, 0UL);
220 232
221 eic->chip = &eic_chip; 233 eic->chip = &eic_chip;
222 234
223 for (i = 0; i < nr_irqs; i++) { 235 for (i = 0; i < nr_irqs; i++) {
224 /* NOTE the handler we set here is ignored by the demux */
225 set_irq_chip_and_handler(eic->first_irq + i, &eic_chip, 236 set_irq_chip_and_handler(eic->first_irq + i, &eic_chip,
226 handle_level_irq); 237 handle_level_irq);
227 set_irq_chip_data(eic->first_irq + i, eic); 238 set_irq_chip_data(eic->first_irq + i, eic);
@@ -230,6 +241,16 @@ static int __init eic_probe(struct platform_device *pdev)
230 set_irq_chained_handler(int_irq, demux_eic_irq); 241 set_irq_chained_handler(int_irq, demux_eic_irq);
231 set_irq_data(int_irq, eic); 242 set_irq_data(int_irq, eic);
232 243
244 if (pdev->id == 0) {
245 nmi_eic = eic;
246 if (nmi_enabled)
247 /*
248 * Someone tried to enable NMI before we were
249 * ready. Do it now.
250 */
251 nmi_enable();
252 }
253
233 dev_info(&pdev->dev, 254 dev_info(&pdev->dev,
234 "External Interrupt Controller at 0x%p, IRQ %u\n", 255 "External Interrupt Controller at 0x%p, IRQ %u\n",
235 eic->regs, int_irq); 256 eic->regs, int_irq);