diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/extint.c')
-rw-r--r-- | arch/avr32/mach-at32ap/extint.c | 59 |
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 | ||
60 | static struct eic *nmi_eic; | ||
61 | static bool nmi_enabled; | ||
62 | |||
66 | static void eic_ack_irq(unsigned int irq) | 63 | static 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 = { | |||
154 | static void demux_eic_irq(unsigned int irq, struct irq_desc *desc) | 154 | static 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 | ||
171 | int 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 | |||
181 | void nmi_disable(void) | ||
182 | { | ||
183 | if (nmi_eic) | ||
184 | eic_writel(nmi_eic, NMIC, 0); | ||
185 | |||
186 | nmi_enabled = false; | ||
187 | } | ||
188 | |||
177 | static int __init eic_probe(struct platform_device *pdev) | 189 | static 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); |