0001
0002
0003
0004
0005
0006 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0007
0008 #include <linux/interrupt.h>
0009 #include <linux/irq.h>
0010 #include <linux/irqchip.h>
0011 #include <linux/irqchip/chained_irq.h>
0012 #include <linux/irqdomain.h>
0013 #include <linux/of_address.h>
0014 #include <linux/of_irq.h>
0015
0016 #define IDT_PIC_NR_IRQS 32
0017
0018 #define IDT_PIC_IRQ_PEND 0x00
0019 #define IDT_PIC_IRQ_MASK 0x08
0020
0021 struct idt_pic_data {
0022 void __iomem *base;
0023 struct irq_domain *irq_domain;
0024 struct irq_chip_generic *gc;
0025 };
0026
0027 static void idt_irq_dispatch(struct irq_desc *desc)
0028 {
0029 struct idt_pic_data *idtpic = irq_desc_get_handler_data(desc);
0030 struct irq_chip *host_chip = irq_desc_get_chip(desc);
0031 u32 pending, hwirq;
0032
0033 chained_irq_enter(host_chip, desc);
0034
0035 pending = irq_reg_readl(idtpic->gc, IDT_PIC_IRQ_PEND);
0036 pending &= ~idtpic->gc->mask_cache;
0037 while (pending) {
0038 hwirq = __fls(pending);
0039 generic_handle_domain_irq(idtpic->irq_domain, hwirq);
0040 pending &= ~(1 << hwirq);
0041 }
0042
0043 chained_irq_exit(host_chip, desc);
0044 }
0045
0046 static int idt_pic_init(struct device_node *of_node, struct device_node *parent)
0047 {
0048 struct irq_domain *domain;
0049 struct idt_pic_data *idtpic;
0050 struct irq_chip_generic *gc;
0051 struct irq_chip_type *ct;
0052 unsigned int parent_irq;
0053 int ret = 0;
0054
0055 idtpic = kzalloc(sizeof(*idtpic), GFP_KERNEL);
0056 if (!idtpic) {
0057 ret = -ENOMEM;
0058 goto out_err;
0059 }
0060
0061 parent_irq = irq_of_parse_and_map(of_node, 0);
0062 if (!parent_irq) {
0063 pr_err("Failed to map parent IRQ!\n");
0064 ret = -EINVAL;
0065 goto out_free;
0066 }
0067
0068 idtpic->base = of_iomap(of_node, 0);
0069 if (!idtpic->base) {
0070 pr_err("Failed to map base address!\n");
0071 ret = -ENOMEM;
0072 goto out_unmap_irq;
0073 }
0074
0075 domain = irq_domain_add_linear(of_node, IDT_PIC_NR_IRQS,
0076 &irq_generic_chip_ops, NULL);
0077 if (!domain) {
0078 pr_err("Failed to add irqdomain!\n");
0079 ret = -ENOMEM;
0080 goto out_iounmap;
0081 }
0082 idtpic->irq_domain = domain;
0083
0084 ret = irq_alloc_domain_generic_chips(domain, 32, 1, "IDTPIC",
0085 handle_level_irq, 0,
0086 IRQ_NOPROBE | IRQ_LEVEL, 0);
0087 if (ret)
0088 goto out_domain_remove;
0089
0090 gc = irq_get_domain_generic_chip(domain, 0);
0091 gc->reg_base = idtpic->base;
0092 gc->private = idtpic;
0093
0094 ct = gc->chip_types;
0095 ct->regs.mask = IDT_PIC_IRQ_MASK;
0096 ct->chip.irq_mask = irq_gc_mask_set_bit;
0097 ct->chip.irq_unmask = irq_gc_mask_clr_bit;
0098 idtpic->gc = gc;
0099
0100
0101 writel(0xffffffff, idtpic->base + IDT_PIC_IRQ_MASK);
0102 gc->mask_cache = 0xffffffff;
0103
0104 irq_set_chained_handler_and_data(parent_irq,
0105 idt_irq_dispatch, idtpic);
0106
0107 return 0;
0108
0109 out_domain_remove:
0110 irq_domain_remove(domain);
0111 out_iounmap:
0112 iounmap(idtpic->base);
0113 out_unmap_irq:
0114 irq_dispose_mapping(parent_irq);
0115 out_free:
0116 kfree(idtpic);
0117 out_err:
0118 pr_err("Failed to initialize! (errno = %d)\n", ret);
0119 return ret;
0120 }
0121
0122 IRQCHIP_DECLARE(idt_pic, "idt,32434-pic", idt_pic_init);