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 .name
= "PQ2 ADS PCI",
73 .end
= pq2ads_pci_unmask_irq
,
74 .mask
= pq2ads_pci_mask_irq
,
75 .mask_ack
= pq2ads_pci_mask_irq
,
76 .ack
= pq2ads_pci_mask_irq
,
77 .unmask
= pq2ads_pci_unmask_irq
,
78 .enable
= pq2ads_pci_unmask_irq
,
79 .disable
= pq2ads_pci_mask_irq
82 static void pq2ads_pci_irq_demux(unsigned int irq
, struct irq_desc
*desc
)
84 struct pq2ads_pci_pic
*priv
= desc
->handler_data
;
89 stat
= in_be32(&priv
->regs
->stat
);
90 mask
= in_be32(&priv
->regs
->mask
);
97 for (bit
= 0; pend
!= 0; ++bit
, pend
<<= 1) {
98 if (pend
& 0x80000000) {
99 int virq
= irq_linear_revmap(priv
->host
, bit
);
100 generic_handle_irq(virq
);
106 static int pci_pic_host_map(struct irq_host
*h
, unsigned int virq
,
109 irq_to_desc(virq
)->status
|= IRQ_LEVEL
;
110 set_irq_chip_data(virq
, h
->host_data
);
111 set_irq_chip_and_handler(virq
, &pq2ads_pci_ic
, handle_level_irq
);
115 static void pci_host_unmap(struct irq_host
*h
, unsigned int virq
)
117 /* remove chip and handler */
118 set_irq_chip_data(virq
, NULL
);
119 set_irq_chip(virq
, NULL
);
122 static struct irq_host_ops pci_pic_host_ops
= {
123 .map
= pci_pic_host_map
,
124 .unmap
= pci_host_unmap
,
127 int __init
pq2ads_pci_init_irq(void)
129 struct pq2ads_pci_pic
*priv
;
130 struct irq_host
*host
;
131 struct device_node
*np
;
135 np
= of_find_compatible_node(NULL
, NULL
, "fsl,pq2ads-pci-pic");
137 printk(KERN_ERR
"No pci pic node in device tree.\n");
142 irq
= irq_of_parse_and_map(np
, 0);
144 printk(KERN_ERR
"No interrupt in pci pic node.\n");
149 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
156 /* PCI interrupt controller registers: status and mask */
157 priv
->regs
= of_iomap(np
, 0);
159 printk(KERN_ERR
"Cannot map PCI PIC registers.\n");
160 goto out_free_bootmem
;
163 /* mask all PCI interrupts */
164 out_be32(&priv
->regs
->mask
, ~0);
167 host
= irq_alloc_host(np
, IRQ_HOST_MAP_LINEAR
, NUM_IRQS
,
168 &pci_pic_host_ops
, NUM_IRQS
);
174 host
->host_data
= priv
;
177 host
->host_data
= priv
;
178 set_irq_data(irq
, priv
);
179 set_irq_chained_handler(irq
, pq2ads_pci_irq_demux
);
187 free_bootmem((unsigned long)priv
,
188 sizeof(struct pq2ads_pci_pic
));
191 irq_dispose_mapping(irq
);