2 * PQ2 ADS-style PCI interrupt controller
4 * Copyright 2007 Freescale Semiconductor, Inc.
5 * Author: Scott Wood <scottwood@freescale.com>
7 * Loosely based on mpc82xx ADS support by Vitaly Bordug <vbordug@ru.mvista.com>
8 * Copyright (c) 2006 MontaVista Software, Inc.
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License version 2 as published
12 * by the Free Software Foundation.
15 #include <linux/init.h>
16 #include <linux/spinlock.h>
17 #include <linux/irq.h>
18 #include <linux/types.h>
19 #include <linux/bootmem.h>
27 static DEFINE_SPINLOCK(pci_pic_lock
);
29 struct pq2ads_pci_pic
{
30 struct device_node
*node
;
31 struct irq_host
*host
;
41 static void pq2ads_pci_mask_irq(unsigned int virq
)
43 struct pq2ads_pci_pic
*priv
= get_irq_chip_data(virq
);
44 int irq
= NUM_IRQS
- virq_to_hw(virq
) - 1;
48 spin_lock_irqsave(&pci_pic_lock
, flags
);
50 setbits32(&priv
->regs
->mask
, 1 << irq
);
53 spin_unlock_irqrestore(&pci_pic_lock
, flags
);
57 static void pq2ads_pci_unmask_irq(unsigned int virq
)
59 struct pq2ads_pci_pic
*priv
= get_irq_chip_data(virq
);
60 int irq
= NUM_IRQS
- virq_to_hw(virq
) - 1;
65 spin_lock_irqsave(&pci_pic_lock
, flags
);
66 clrbits32(&priv
->regs
->mask
, 1 << irq
);
67 spin_unlock_irqrestore(&pci_pic_lock
, flags
);
71 static struct irq_chip pq2ads_pci_ic
= {
72 .typename
= "PQ2 ADS PCI",
73 .name
= "PQ2 ADS PCI",
74 .end
= pq2ads_pci_unmask_irq
,
75 .mask
= pq2ads_pci_mask_irq
,
76 .mask_ack
= pq2ads_pci_mask_irq
,
77 .ack
= pq2ads_pci_mask_irq
,
78 .unmask
= pq2ads_pci_unmask_irq
,
79 .enable
= pq2ads_pci_unmask_irq
,
80 .disable
= pq2ads_pci_mask_irq
83 static void pq2ads_pci_irq_demux(unsigned int irq
, struct irq_desc
*desc
)
85 struct pq2ads_pci_pic
*priv
= desc
->handler_data
;
90 stat
= in_be32(&priv
->regs
->stat
);
91 mask
= in_be32(&priv
->regs
->mask
);
98 for (bit
= 0; pend
!= 0; ++bit
, pend
<<= 1) {
99 if (pend
& 0x80000000) {
100 int virq
= irq_linear_revmap(priv
->host
, bit
);
101 generic_handle_irq(virq
);
107 static int pci_pic_host_map(struct irq_host
*h
, unsigned int virq
,
110 get_irq_desc(virq
)->status
|= IRQ_LEVEL
;
111 set_irq_chip_data(virq
, h
->host_data
);
112 set_irq_chip(virq
, &pq2ads_pci_ic
);
116 static void pci_host_unmap(struct irq_host
*h
, unsigned int virq
)
118 /* remove chip and handler */
119 set_irq_chip_data(virq
, NULL
);
120 set_irq_chip(virq
, NULL
);
123 static struct irq_host_ops pci_pic_host_ops
= {
124 .map
= pci_pic_host_map
,
125 .unmap
= pci_host_unmap
,
128 int __init
pq2ads_pci_init_irq(void)
130 struct pq2ads_pci_pic
*priv
;
131 struct irq_host
*host
;
132 struct device_node
*np
;
136 np
= of_find_compatible_node(NULL
, NULL
, "fsl,pq2ads-pci-pic");
138 printk(KERN_ERR
"No pci pic node in device tree.\n");
143 irq
= irq_of_parse_and_map(np
, 0);
145 printk(KERN_ERR
"No interrupt in pci pic node.\n");
150 priv
= alloc_bootmem(sizeof(struct pq2ads_pci_pic
));
157 /* PCI interrupt controller registers: status and mask */
158 priv
->regs
= of_iomap(np
, 0);
160 printk(KERN_ERR
"Cannot map PCI PIC registers.\n");
161 goto out_free_bootmem
;
164 /* mask all PCI interrupts */
165 out_be32(&priv
->regs
->mask
, ~0);
168 host
= irq_alloc_host(np
, IRQ_HOST_MAP_LINEAR
, NUM_IRQS
,
169 &pci_pic_host_ops
, NUM_IRQS
);
175 host
->host_data
= priv
;
178 host
->host_data
= priv
;
179 set_irq_data(irq
, priv
);
180 set_irq_chained_handler(irq
, pq2ads_pci_irq_demux
);
188 free_bootmem((unsigned long)priv
,
189 sizeof(sizeof(struct pq2ads_pci_pic
)));
192 irq_dispose_mapping(irq
);