~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/avr32/mach-at32ap/extint.c

Version: ~ [ linux-5.4-rc7 ] ~ [ linux-5.3.11 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.84 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.154 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.201 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.201 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.77 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * External interrupt handling for AT32AP CPUs
  3  *
  4  * Copyright (C) 2006 Atmel Corporation
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License version 2 as
  8  * published by the Free Software Foundation.
  9  */
 10 
 11 #include <linux/errno.h>
 12 #include <linux/init.h>
 13 #include <linux/interrupt.h>
 14 #include <linux/irq.h>
 15 #include <linux/platform_device.h>
 16 #include <linux/random.h>
 17 #include <linux/slab.h>
 18 
 19 #include <asm/io.h>
 20 
 21 /* EIC register offsets */
 22 #define EIC_IER                                 0x0000
 23 #define EIC_IDR                                 0x0004
 24 #define EIC_IMR                                 0x0008
 25 #define EIC_ISR                                 0x000c
 26 #define EIC_ICR                                 0x0010
 27 #define EIC_MODE                                0x0014
 28 #define EIC_EDGE                                0x0018
 29 #define EIC_LEVEL                               0x001c
 30 #define EIC_NMIC                                0x0024
 31 
 32 /* Bitfields in NMIC */
 33 #define EIC_NMIC_ENABLE                         (1 << 0)
 34 
 35 /* Bit manipulation macros */
 36 #define EIC_BIT(name)                                   \
 37         (1 << EIC_##name##_OFFSET)
 38 #define EIC_BF(name,value)                              \
 39         (((value) & ((1 << EIC_##name##_SIZE) - 1))     \
 40          << EIC_##name##_OFFSET)
 41 #define EIC_BFEXT(name,value)                           \
 42         (((value) >> EIC_##name##_OFFSET)               \
 43          & ((1 << EIC_##name##_SIZE) - 1))
 44 #define EIC_BFINS(name,value,old)                       \
 45         (((old) & ~(((1 << EIC_##name##_SIZE) - 1)      \
 46                     << EIC_##name##_OFFSET))            \
 47          | EIC_BF(name,value))
 48 
 49 /* Register access macros */
 50 #define eic_readl(port,reg)                             \
 51         __raw_readl((port)->regs + EIC_##reg)
 52 #define eic_writel(port,reg,value)                      \
 53         __raw_writel((value), (port)->regs + EIC_##reg)
 54 
 55 struct eic {
 56         void __iomem *regs;
 57         struct irq_chip *chip;
 58         unsigned int first_irq;
 59 };
 60 
 61 static struct eic *nmi_eic;
 62 static bool nmi_enabled;
 63 
 64 static void eic_ack_irq(struct irq_data *d)
 65 {
 66         struct eic *eic = irq_data_get_irq_chip_data(d);
 67         eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq));
 68 }
 69 
 70 static void eic_mask_irq(struct irq_data *d)
 71 {
 72         struct eic *eic = irq_data_get_irq_chip_data(d);
 73         eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq));
 74 }
 75 
 76 static void eic_mask_ack_irq(struct irq_data *d)
 77 {
 78         struct eic *eic = irq_data_get_irq_chip_data(d);
 79         eic_writel(eic, ICR, 1 << (d->irq - eic->first_irq));
 80         eic_writel(eic, IDR, 1 << (d->irq - eic->first_irq));
 81 }
 82 
 83 static void eic_unmask_irq(struct irq_data *d)
 84 {
 85         struct eic *eic = irq_data_get_irq_chip_data(d);
 86         eic_writel(eic, IER, 1 << (d->irq - eic->first_irq));
 87 }
 88 
 89 static int eic_set_irq_type(struct irq_data *d, unsigned int flow_type)
 90 {
 91         struct eic *eic = irq_data_get_irq_chip_data(d);
 92         unsigned int irq = d->irq;
 93         unsigned int i = irq - eic->first_irq;
 94         u32 mode, edge, level;
 95 
 96         flow_type &= IRQ_TYPE_SENSE_MASK;
 97         if (flow_type == IRQ_TYPE_NONE)
 98                 flow_type = IRQ_TYPE_LEVEL_LOW;
 99 
100         mode = eic_readl(eic, MODE);
101         edge = eic_readl(eic, EDGE);
102         level = eic_readl(eic, LEVEL);
103 
104         switch (flow_type) {
105         case IRQ_TYPE_LEVEL_LOW:
106                 mode |= 1 << i;
107                 level &= ~(1 << i);
108                 break;
109         case IRQ_TYPE_LEVEL_HIGH:
110                 mode |= 1 << i;
111                 level |= 1 << i;
112                 break;
113         case IRQ_TYPE_EDGE_RISING:
114                 mode &= ~(1 << i);
115                 edge |= 1 << i;
116                 break;
117         case IRQ_TYPE_EDGE_FALLING:
118                 mode &= ~(1 << i);
119                 edge &= ~(1 << i);
120                 break;
121         default:
122                 return -EINVAL;
123         }
124 
125         eic_writel(eic, MODE, mode);
126         eic_writel(eic, EDGE, edge);
127         eic_writel(eic, LEVEL, level);
128 
129         irqd_set_trigger_type(d, flow_type);
130         if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
131                 irq_set_handler_locked(d, handle_level_irq);
132         else
133                 irq_set_handler_locked(d, handle_edge_irq);
134 
135         return IRQ_SET_MASK_OK_NOCOPY;
136 }
137 
138 static struct irq_chip eic_chip = {
139         .name           = "eic",
140         .irq_ack        = eic_ack_irq,
141         .irq_mask       = eic_mask_irq,
142         .irq_mask_ack   = eic_mask_ack_irq,
143         .irq_unmask     = eic_unmask_irq,
144         .irq_set_type   = eic_set_irq_type,
145 };
146 
147 static void demux_eic_irq(struct irq_desc *desc)
148 {
149         struct eic *eic = irq_desc_get_handler_data(desc);
150         unsigned long status, pending;
151         unsigned int i;
152 
153         status = eic_readl(eic, ISR);
154         pending = status & eic_readl(eic, IMR);
155 
156         while (pending) {
157                 i = fls(pending) - 1;
158                 pending &= ~(1 << i);
159 
160                 generic_handle_irq(i + eic->first_irq);
161         }
162 }
163 
164 int nmi_enable(void)
165 {
166         nmi_enabled = true;
167 
168         if (nmi_eic)
169                 eic_writel(nmi_eic, NMIC, EIC_NMIC_ENABLE);
170 
171         return 0;
172 }
173 
174 void nmi_disable(void)
175 {
176         if (nmi_eic)
177                 eic_writel(nmi_eic, NMIC, 0);
178 
179         nmi_enabled = false;
180 }
181 
182 static int __init eic_probe(struct platform_device *pdev)
183 {
184         struct eic *eic;
185         struct resource *regs;
186         unsigned int i;
187         unsigned int nr_of_irqs;
188         unsigned int int_irq;
189         int ret;
190         u32 pattern;
191 
192         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
193         int_irq = platform_get_irq(pdev, 0);
194         if (!regs || (int)int_irq <= 0) {
195                 dev_dbg(&pdev->dev, "missing regs and/or irq resource\n");
196                 return -ENXIO;
197         }
198 
199         ret = -ENOMEM;
200         eic = kzalloc(sizeof(struct eic), GFP_KERNEL);
201         if (!eic) {
202                 dev_dbg(&pdev->dev, "no memory for eic structure\n");
203                 goto err_kzalloc;
204         }
205 
206         eic->first_irq = EIM_IRQ_BASE + 32 * pdev->id;
207         eic->regs = ioremap(regs->start, resource_size(regs));
208         if (!eic->regs) {
209                 dev_dbg(&pdev->dev, "failed to map regs\n");
210                 goto err_ioremap;
211         }
212 
213         /*
214          * Find out how many interrupt lines that are actually
215          * implemented in hardware.
216          */
217         eic_writel(eic, IDR, ~0UL);
218         eic_writel(eic, MODE, ~0UL);
219         pattern = eic_readl(eic, MODE);
220         nr_of_irqs = fls(pattern);
221 
222         /* Trigger on low level unless overridden by driver */
223         eic_writel(eic, EDGE, 0UL);
224         eic_writel(eic, LEVEL, 0UL);
225 
226         eic->chip = &eic_chip;
227 
228         for (i = 0; i < nr_of_irqs; i++) {
229                 irq_set_chip_and_handler(eic->first_irq + i, &eic_chip,
230                                          handle_level_irq);
231                 irq_set_chip_data(eic->first_irq + i, eic);
232         }
233 
234         irq_set_chained_handler_and_data(int_irq, demux_eic_irq, eic);
235 
236         if (pdev->id == 0) {
237                 nmi_eic = eic;
238                 if (nmi_enabled)
239                         /*
240                          * Someone tried to enable NMI before we were
241                          * ready. Do it now.
242                          */
243                         nmi_enable();
244         }
245 
246         dev_info(&pdev->dev,
247                  "External Interrupt Controller at 0x%p, IRQ %u\n",
248                  eic->regs, int_irq);
249         dev_info(&pdev->dev,
250                  "Handling %u external IRQs, starting with IRQ %u\n",
251                  nr_of_irqs, eic->first_irq);
252 
253         return 0;
254 
255 err_ioremap:
256         kfree(eic);
257 err_kzalloc:
258         return ret;
259 }
260 
261 static struct platform_driver eic_driver = {
262         .driver = {
263                 .name = "at32_eic",
264         },
265 };
266 
267 static int __init eic_init(void)
268 {
269         return platform_driver_probe(&eic_driver, eic_probe);
270 }
271 arch_initcall(eic_init);
272 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp