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>
20 #include <linux/slab.h>
28 static DEFINE_RAW_SPINLOCK(pci_pic_lock
);
30 struct pq2ads_pci_pic
{
31 struct device_node
*node
;
32 struct irq_host
*host
;
42 static void pq2ads_pci_mask_irq(struct irq_data
*d
)
44 struct pq2ads_pci_pic
*priv
= irq_data_get_irq_chip_data(d
);
45 int irq
= NUM_IRQS
- irqd_to_hwirq(d
) - 1;
49 raw_spin_lock_irqsave(&pci_pic_lock
, flags
);
51 setbits32(&priv
->regs
->mask
, 1 << irq
);
54 raw_spin_unlock_irqrestore(&pci_pic_lock
, flags
);
58 static void pq2ads_pci_unmask_irq(struct irq_data
*d
)
60 struct pq2ads_pci_pic
*priv
= irq_data_get_irq_chip_data(d
);
61 int irq
= NUM_IRQS
- irqd_to_hwirq(d
) - 1;
66 raw_spin_lock_irqsave(&pci_pic_lock
, flags
);
67 clrbits32(&priv
->regs
->mask
, 1 << irq
);
68 raw_spin_unlock_irqrestore(&pci_pic_lock
, flags
);
72 static struct irq_chip pq2ads_pci_ic
= {
73 .name
= "PQ2 ADS PCI",
74 .irq_mask
= pq2ads_pci_mask_irq
,
75 .irq_mask_ack
= pq2ads_pci_mask_irq
,
76 .irq_ack
= pq2ads_pci_mask_irq
,
77 .irq_unmask
= pq2ads_pci_unmask_irq
,
78 .irq_enable
= pq2ads_pci_unmask_irq
,
79 .irq_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
= irq_desc_get_handler_data(desc
);
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_set_status_flags(virq
, IRQ_LEVEL
);
110 irq_set_chip_data(virq
, h
->host_data
);
111 irq_set_chip_and_handler(virq
, &pq2ads_pci_ic
, handle_level_irq
);
115 static struct irq_host_ops pci_pic_host_ops
= {
116 .map
= pci_pic_host_map
,
119 int __init
pq2ads_pci_init_irq(void)
121 struct pq2ads_pci_pic
*priv
;
122 struct irq_host
*host
;
123 struct device_node
*np
;
127 np
= of_find_compatible_node(NULL
, NULL
, "fsl,pq2ads-pci-pic");
129 printk(KERN_ERR
"No pci pic node in device tree.\n");
134 irq
= irq_of_parse_and_map(np
, 0);
136 printk(KERN_ERR
"No interrupt in pci pic node.\n");
141 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
148 /* PCI interrupt controller registers: status and mask */
149 priv
->regs
= of_iomap(np
, 0);
151 printk(KERN_ERR
"Cannot map PCI PIC registers.\n");
152 goto out_free_bootmem
;
155 /* mask all PCI interrupts */
156 out_be32(&priv
->regs
->mask
, ~0);
159 host
= irq_alloc_host(np
, IRQ_HOST_MAP_LINEAR
, NUM_IRQS
,
160 &pci_pic_host_ops
, NUM_IRQS
);
166 host
->host_data
= priv
;
169 host
->host_data
= priv
;
170 irq_set_handler_data(irq
, priv
);
171 irq_set_chained_handler(irq
, pq2ads_pci_irq_demux
);
179 free_bootmem((unsigned long)priv
,
180 sizeof(struct pq2ads_pci_pic
));
183 irq_dispose_mapping(irq
);