diff options
Diffstat (limited to 'arch/avr32/mach-at32ap/extint.c')
-rw-r--r-- | arch/avr32/mach-at32ap/extint.c | 200 |
1 files changed, 136 insertions, 64 deletions
diff --git a/arch/avr32/mach-at32ap/extint.c b/arch/avr32/mach-at32ap/extint.c index 4a60eccfebd2..8acd01090031 100644 --- a/arch/avr32/mach-at32ap/extint.c +++ b/arch/avr32/mach-at32ap/extint.c | |||
@@ -17,42 +17,83 @@ | |||
17 | 17 | ||
18 | #include <asm/io.h> | 18 | #include <asm/io.h> |
19 | 19 | ||
20 | #include <asm/arch/sm.h> | 20 | /* EIC register offsets */ |
21 | 21 | #define EIC_IER 0x0000 | |
22 | #include "sm.h" | 22 | #define EIC_IDR 0x0004 |
23 | #define EIC_IMR 0x0008 | ||
24 | #define EIC_ISR 0x000c | ||
25 | #define EIC_ICR 0x0010 | ||
26 | #define EIC_MODE 0x0014 | ||
27 | #define EIC_EDGE 0x0018 | ||
28 | #define EIC_LEVEL 0x001c | ||
29 | #define EIC_TEST 0x0020 | ||
30 | #define EIC_NMIC 0x0024 | ||
31 | |||
32 | /* Bitfields in TEST */ | ||
33 | #define EIC_TESTEN_OFFSET 31 | ||
34 | #define EIC_TESTEN_SIZE 1 | ||
35 | |||
36 | /* Bitfields in NMIC */ | ||
37 | #define EIC_EN_OFFSET 0 | ||
38 | #define EIC_EN_SIZE 1 | ||
39 | |||
40 | /* Bit manipulation macros */ | ||
41 | #define EIC_BIT(name) \ | ||
42 | (1 << EIC_##name##_OFFSET) | ||
43 | #define EIC_BF(name,value) \ | ||
44 | (((value) & ((1 << EIC_##name##_SIZE) - 1)) \ | ||
45 | << EIC_##name##_OFFSET) | ||
46 | #define EIC_BFEXT(name,value) \ | ||
47 | (((value) >> EIC_##name##_OFFSET) \ | ||
48 | & ((1 << EIC_##name##_SIZE) - 1)) | ||
49 | #define EIC_BFINS(name,value,old) \ | ||
50 | (((old) & ~(((1 << EIC_##name##_SIZE) - 1) \ | ||
51 | << EIC_##name##_OFFSET)) \ | ||
52 | | EIC_BF(name,value)) | ||
53 | |||
54 | /* Register access macros */ | ||
55 | #define eic_readl(port,reg) \ | ||
56 | __raw_readl((port)->regs + EIC_##reg) | ||
57 | #define eic_writel(port,reg,value) \ | ||
58 | __raw_writel((value), (port)->regs + EIC_##reg) | ||
59 | |||
60 | struct eic { | ||
61 | void __iomem *regs; | ||
62 | struct irq_chip *chip; | ||
63 | unsigned int first_irq; | ||
64 | }; | ||
23 | 65 | ||
24 | static void eim_ack_irq(unsigned int irq) | 66 | static void eic_ack_irq(unsigned int irq) |
25 | { | 67 | { |
26 | struct at32_sm *sm = get_irq_chip_data(irq); | 68 | struct eic *eic = get_irq_chip_data(irq); |
27 | sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq)); | 69 | eic_writel(eic, ICR, 1 << (irq - eic->first_irq)); |
28 | } | 70 | } |
29 | 71 | ||
30 | static void eim_mask_irq(unsigned int irq) | 72 | static void eic_mask_irq(unsigned int irq) |
31 | { | 73 | { |
32 | struct at32_sm *sm = get_irq_chip_data(irq); | 74 | struct eic *eic = get_irq_chip_data(irq); |
33 | sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq)); | 75 | eic_writel(eic, IDR, 1 << (irq - eic->first_irq)); |
34 | } | 76 | } |
35 | 77 | ||
36 | static void eim_mask_ack_irq(unsigned int irq) | 78 | static void eic_mask_ack_irq(unsigned int irq) |
37 | { | 79 | { |
38 | struct at32_sm *sm = get_irq_chip_data(irq); | 80 | struct eic *eic = get_irq_chip_data(irq); |
39 | sm_writel(sm, EIM_ICR, 1 << (irq - sm->eim_first_irq)); | 81 | eic_writel(eic, ICR, 1 << (irq - eic->first_irq)); |
40 | sm_writel(sm, EIM_IDR, 1 << (irq - sm->eim_first_irq)); | 82 | eic_writel(eic, IDR, 1 << (irq - eic->first_irq)); |
41 | } | 83 | } |
42 | 84 | ||
43 | static void eim_unmask_irq(unsigned int irq) | 85 | static void eic_unmask_irq(unsigned int irq) |
44 | { | 86 | { |
45 | struct at32_sm *sm = get_irq_chip_data(irq); | 87 | struct eic *eic = get_irq_chip_data(irq); |
46 | sm_writel(sm, EIM_IER, 1 << (irq - sm->eim_first_irq)); | 88 | eic_writel(eic, IER, 1 << (irq - eic->first_irq)); |
47 | } | 89 | } |
48 | 90 | ||
49 | static int eim_set_irq_type(unsigned int irq, unsigned int flow_type) | 91 | static int eic_set_irq_type(unsigned int irq, unsigned int flow_type) |
50 | { | 92 | { |
51 | struct at32_sm *sm = get_irq_chip_data(irq); | 93 | struct eic *eic = get_irq_chip_data(irq); |
52 | struct irq_desc *desc; | 94 | struct irq_desc *desc; |
53 | unsigned int i = irq - sm->eim_first_irq; | 95 | unsigned int i = irq - eic->first_irq; |
54 | u32 mode, edge, level; | 96 | u32 mode, edge, level; |
55 | unsigned long flags; | ||
56 | int ret = 0; | 97 | int ret = 0; |
57 | 98 | ||
58 | flow_type &= IRQ_TYPE_SENSE_MASK; | 99 | flow_type &= IRQ_TYPE_SENSE_MASK; |
@@ -60,11 +101,10 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type) | |||
60 | flow_type = IRQ_TYPE_LEVEL_LOW; | 101 | flow_type = IRQ_TYPE_LEVEL_LOW; |
61 | 102 | ||
62 | desc = &irq_desc[irq]; | 103 | desc = &irq_desc[irq]; |
63 | spin_lock_irqsave(&sm->lock, flags); | ||
64 | 104 | ||
65 | mode = sm_readl(sm, EIM_MODE); | 105 | mode = eic_readl(eic, MODE); |
66 | edge = sm_readl(sm, EIM_EDGE); | 106 | edge = eic_readl(eic, EDGE); |
67 | level = sm_readl(sm, EIM_LEVEL); | 107 | level = eic_readl(eic, LEVEL); |
68 | 108 | ||
69 | switch (flow_type) { | 109 | switch (flow_type) { |
70 | case IRQ_TYPE_LEVEL_LOW: | 110 | case IRQ_TYPE_LEVEL_LOW: |
@@ -89,9 +129,9 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type) | |||
89 | } | 129 | } |
90 | 130 | ||
91 | if (ret == 0) { | 131 | if (ret == 0) { |
92 | sm_writel(sm, EIM_MODE, mode); | 132 | eic_writel(eic, MODE, mode); |
93 | sm_writel(sm, EIM_EDGE, edge); | 133 | eic_writel(eic, EDGE, edge); |
94 | sm_writel(sm, EIM_LEVEL, level); | 134 | eic_writel(eic, LEVEL, level); |
95 | 135 | ||
96 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) | 136 | if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH)) |
97 | flow_type |= IRQ_LEVEL; | 137 | flow_type |= IRQ_LEVEL; |
@@ -99,35 +139,33 @@ static int eim_set_irq_type(unsigned int irq, unsigned int flow_type) | |||
99 | desc->status |= flow_type; | 139 | desc->status |= flow_type; |
100 | } | 140 | } |
101 | 141 | ||
102 | spin_unlock_irqrestore(&sm->lock, flags); | ||
103 | |||
104 | return ret; | 142 | return ret; |
105 | } | 143 | } |
106 | 144 | ||
107 | struct irq_chip eim_chip = { | 145 | struct irq_chip eic_chip = { |
108 | .name = "eim", | 146 | .name = "eic", |
109 | .ack = eim_ack_irq, | 147 | .ack = eic_ack_irq, |
110 | .mask = eim_mask_irq, | 148 | .mask = eic_mask_irq, |
111 | .mask_ack = eim_mask_ack_irq, | 149 | .mask_ack = eic_mask_ack_irq, |
112 | .unmask = eim_unmask_irq, | 150 | .unmask = eic_unmask_irq, |
113 | .set_type = eim_set_irq_type, | 151 | .set_type = eic_set_irq_type, |
114 | }; | 152 | }; |
115 | 153 | ||
116 | static void demux_eim_irq(unsigned int irq, struct irq_desc *desc) | 154 | static void demux_eic_irq(unsigned int irq, struct irq_desc *desc) |
117 | { | 155 | { |
118 | struct at32_sm *sm = desc->handler_data; | 156 | struct eic *eic = desc->handler_data; |
119 | struct irq_desc *ext_desc; | 157 | struct irq_desc *ext_desc; |
120 | unsigned long status, pending; | 158 | unsigned long status, pending; |
121 | unsigned int i, ext_irq; | 159 | unsigned int i, ext_irq; |
122 | 160 | ||
123 | status = sm_readl(sm, EIM_ISR); | 161 | status = eic_readl(eic, ISR); |
124 | pending = status & sm_readl(sm, EIM_IMR); | 162 | pending = status & eic_readl(eic, IMR); |
125 | 163 | ||
126 | while (pending) { | 164 | while (pending) { |
127 | i = fls(pending) - 1; | 165 | i = fls(pending) - 1; |
128 | pending &= ~(1 << i); | 166 | pending &= ~(1 << i); |
129 | 167 | ||
130 | ext_irq = i + sm->eim_first_irq; | 168 | ext_irq = i + eic->first_irq; |
131 | ext_desc = irq_desc + ext_irq; | 169 | ext_desc = irq_desc + ext_irq; |
132 | if (ext_desc->status & IRQ_LEVEL) | 170 | if (ext_desc->status & IRQ_LEVEL) |
133 | handle_level_irq(ext_irq, ext_desc); | 171 | handle_level_irq(ext_irq, ext_desc); |
@@ -136,51 +174,85 @@ static void demux_eim_irq(unsigned int irq, struct irq_desc *desc) | |||
136 | } | 174 | } |
137 | } | 175 | } |
138 | 176 | ||
139 | static int __init eim_init(void) | 177 | static int __init eic_probe(struct platform_device *pdev) |
140 | { | 178 | { |
141 | struct at32_sm *sm = &system_manager; | 179 | struct eic *eic; |
180 | struct resource *regs; | ||
142 | unsigned int i; | 181 | unsigned int i; |
143 | unsigned int nr_irqs; | 182 | unsigned int nr_irqs; |
144 | unsigned int int_irq; | 183 | unsigned int int_irq; |
184 | int ret; | ||
145 | u32 pattern; | 185 | u32 pattern; |
146 | 186 | ||
147 | /* | 187 | regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
148 | * The EIM is really the same module as SM, so register | 188 | int_irq = platform_get_irq(pdev, 0); |
149 | * mapping, etc. has been taken care of already. | 189 | if (!regs || !int_irq) { |
150 | */ | 190 | dev_dbg(&pdev->dev, "missing regs and/or irq resource\n"); |
191 | return -ENXIO; | ||
192 | } | ||
193 | |||
194 | ret = -ENOMEM; | ||
195 | eic = kzalloc(sizeof(struct eic), GFP_KERNEL); | ||
196 | if (!eic) { | ||
197 | dev_dbg(&pdev->dev, "no memory for eic structure\n"); | ||
198 | goto err_kzalloc; | ||
199 | } | ||
200 | |||
201 | eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id; | ||
202 | eic->regs = ioremap(regs->start, regs->end - regs->start + 1); | ||
203 | if (!eic->regs) { | ||
204 | dev_dbg(&pdev->dev, "failed to map regs\n"); | ||
205 | goto err_ioremap; | ||
206 | } | ||
151 | 207 | ||
152 | /* | 208 | /* |
153 | * Find out how many interrupt lines that are actually | 209 | * Find out how many interrupt lines that are actually |
154 | * implemented in hardware. | 210 | * implemented in hardware. |
155 | */ | 211 | */ |
156 | sm_writel(sm, EIM_IDR, ~0UL); | 212 | eic_writel(eic, IDR, ~0UL); |
157 | sm_writel(sm, EIM_MODE, ~0UL); | 213 | eic_writel(eic, MODE, ~0UL); |
158 | pattern = sm_readl(sm, EIM_MODE); | 214 | pattern = eic_readl(eic, MODE); |
159 | nr_irqs = fls(pattern); | 215 | nr_irqs = fls(pattern); |
160 | 216 | ||
161 | /* Trigger on falling edge unless overridden by driver */ | 217 | /* Trigger on falling edge unless overridden by driver */ |
162 | sm_writel(sm, EIM_MODE, 0UL); | 218 | eic_writel(eic, MODE, 0UL); |
163 | sm_writel(sm, EIM_EDGE, 0UL); | 219 | eic_writel(eic, EDGE, 0UL); |
164 | 220 | ||
165 | sm->eim_chip = &eim_chip; | 221 | eic->chip = &eic_chip; |
166 | 222 | ||
167 | for (i = 0; i < nr_irqs; i++) { | 223 | for (i = 0; i < nr_irqs; i++) { |
168 | /* NOTE the handler we set here is ignored by the demux */ | 224 | /* NOTE the handler we set here is ignored by the demux */ |
169 | set_irq_chip_and_handler(sm->eim_first_irq + i, &eim_chip, | 225 | set_irq_chip_and_handler(eic->first_irq + i, &eic_chip, |
170 | handle_level_irq); | 226 | handle_level_irq); |
171 | set_irq_chip_data(sm->eim_first_irq + i, sm); | 227 | set_irq_chip_data(eic->first_irq + i, eic); |
172 | } | 228 | } |
173 | 229 | ||
174 | int_irq = platform_get_irq_byname(sm->pdev, "eim"); | 230 | set_irq_chained_handler(int_irq, demux_eic_irq); |
175 | 231 | set_irq_data(int_irq, eic); | |
176 | set_irq_chained_handler(int_irq, demux_eim_irq); | ||
177 | set_irq_data(int_irq, sm); | ||
178 | 232 | ||
179 | printk("EIM: External Interrupt Module at 0x%p, IRQ %u\n", | 233 | dev_info(&pdev->dev, |
180 | sm->regs, int_irq); | 234 | "External Interrupt Controller at 0x%p, IRQ %u\n", |
181 | printk("EIM: Handling %u external IRQs, starting with IRQ %u\n", | 235 | eic->regs, int_irq); |
182 | nr_irqs, sm->eim_first_irq); | 236 | dev_info(&pdev->dev, |
237 | "Handling %u external IRQs, starting with IRQ %u\n", | ||
238 | nr_irqs, eic->first_irq); | ||
183 | 239 | ||
184 | return 0; | 240 | return 0; |
241 | |||
242 | err_ioremap: | ||
243 | kfree(eic); | ||
244 | err_kzalloc: | ||
245 | return ret; | ||
246 | } | ||
247 | |||
248 | static struct platform_driver eic_driver = { | ||
249 | .driver = { | ||
250 | .name = "at32_eic", | ||
251 | }, | ||
252 | }; | ||
253 | |||
254 | static int __init eic_init(void) | ||
255 | { | ||
256 | return platform_driver_probe(&eic_driver, eic_probe); | ||
185 | } | 257 | } |
186 | arch_initcall(eim_init); | 258 | arch_initcall(eic_init); |