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.c200
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
60struct eic {
61 void __iomem *regs;
62 struct irq_chip *chip;
63 unsigned int first_irq;
64};
23 65
24static void eim_ack_irq(unsigned int irq) 66static 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
30static void eim_mask_irq(unsigned int irq) 72static 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
36static void eim_mask_ack_irq(unsigned int irq) 78static 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
43static void eim_unmask_irq(unsigned int irq) 85static 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
49static int eim_set_irq_type(unsigned int irq, unsigned int flow_type) 91static 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
107struct irq_chip eim_chip = { 145struct 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
116static void demux_eim_irq(unsigned int irq, struct irq_desc *desc) 154static 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
139static int __init eim_init(void) 177static 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
242err_ioremap:
243 kfree(eic);
244err_kzalloc:
245 return ret;
246}
247
248static struct platform_driver eic_driver = {
249 .driver = {
250 .name = "at32_eic",
251 },
252};
253
254static int __init eic_init(void)
255{
256 return platform_driver_probe(&eic_driver, eic_probe);
185} 257}
186arch_initcall(eim_init); 258arch_initcall(eic_init);