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/slab.h>
27 static DEFINE_RAW_SPINLOCK(pci_pic_lock
);
29 struct pq2ads_pci_pic
{
30 struct device_node
*node
;
31 struct irq_domain
*host
;
41 static void pq2ads_pci_mask_irq(struct irq_data
*d
)
43 struct pq2ads_pci_pic
*priv
= irq_data_get_irq_chip_data(d
);
44 int irq
= NUM_IRQS
- irqd_to_hwirq(d
) - 1;
48 raw_spin_lock_irqsave(&pci_pic_lock
, flags
);
50 setbits32(&priv
->regs
->mask
, 1 << irq
);
53 raw_spin_unlock_irqrestore(&pci_pic_lock
, flags
);
57 static void pq2ads_pci_unmask_irq(struct irq_data
*d
)
59 struct pq2ads_pci_pic
*priv
= irq_data_get_irq_chip_data(d
);
60 int irq
= NUM_IRQS
- irqd_to_hwirq(d
) - 1;
65 raw_spin_lock_irqsave(&pci_pic_lock
, flags
);
66 clrbits32(&priv
->regs
->mask
, 1 << irq
);
67 raw_spin_unlock_irqrestore(&pci_pic_lock
, flags
);
71 static struct irq_chip pq2ads_pci_ic
= {
72 .name
= "PQ2 ADS PCI",
73 .irq_mask
= pq2ads_pci_mask_irq
,
74 .irq_mask_ack
= pq2ads_pci_mask_irq
,
75 .irq_ack
= pq2ads_pci_mask_irq
,
76 .irq_unmask
= pq2ads_pci_unmask_irq
,
77 .irq_enable
= pq2ads_pci_unmask_irq
,
78 .irq_disable
= pq2ads_pci_mask_irq
81 static void pq2ads_pci_irq_demux(unsigned int irq
, struct irq_desc
*desc
)
83 struct pq2ads_pci_pic
*priv
= irq_desc_get_handler_data(desc
);
88 stat
= in_be32(&priv
->regs
->stat
);
89 mask
= in_be32(&priv
->regs
->mask
);
96 for (bit
= 0; pend
!= 0; ++bit
, pend
<<= 1) {
97 if (pend
& 0x80000000) {
98 int virq
= irq_linear_revmap(priv
->host
, bit
);
99 generic_handle_irq(virq
);
105 static int pci_pic_host_map(struct irq_domain
*h
, unsigned int virq
,
108 irq_set_status_flags(virq
, IRQ_LEVEL
);
109 irq_set_chip_data(virq
, h
->host_data
);
110 irq_set_chip_and_handler(virq
, &pq2ads_pci_ic
, handle_level_irq
);
114 static const struct irq_domain_ops pci_pic_host_ops
= {
115 .map
= pci_pic_host_map
,
118 int __init
pq2ads_pci_init_irq(void)
120 struct pq2ads_pci_pic
*priv
;
121 struct irq_domain
*host
;
122 struct device_node
*np
;
126 np
= of_find_compatible_node(NULL
, NULL
, "fsl,pq2ads-pci-pic");
128 printk(KERN_ERR
"No pci pic node in device tree.\n");
133 irq
= irq_of_parse_and_map(np
, 0);
135 printk(KERN_ERR
"No interrupt in pci pic node.\n");
140 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
147 /* PCI interrupt controller registers: status and mask */
148 priv
->regs
= of_iomap(np
, 0);
150 printk(KERN_ERR
"Cannot map PCI PIC registers.\n");
151 goto out_free_kmalloc
;
154 /* mask all PCI interrupts */
155 out_be32(&priv
->regs
->mask
, ~0);
158 host
= irq_domain_add_linear(np
, NUM_IRQS
, &pci_pic_host_ops
, priv
);
165 irq_set_handler_data(irq
, priv
);
166 irq_set_chained_handler(irq
, pq2ads_pci_irq_demux
);
177 irq_dispose_mapping(irq
);