irq-ls1x.c (4804B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2019, Jiaxun Yang <jiaxun.yang@flygoat.com> 4 * Loongson-1 platform IRQ support 5 */ 6 7#include <linux/errno.h> 8#include <linux/init.h> 9#include <linux/types.h> 10#include <linux/interrupt.h> 11#include <linux/ioport.h> 12#include <linux/irqchip.h> 13#include <linux/of_address.h> 14#include <linux/of_irq.h> 15#include <linux/io.h> 16#include <linux/irqchip/chained_irq.h> 17 18#define LS_REG_INTC_STATUS 0x00 19#define LS_REG_INTC_EN 0x04 20#define LS_REG_INTC_SET 0x08 21#define LS_REG_INTC_CLR 0x0c 22#define LS_REG_INTC_POL 0x10 23#define LS_REG_INTC_EDGE 0x14 24 25/** 26 * struct ls1x_intc_priv - private ls1x-intc data. 27 * @domain: IRQ domain. 28 * @intc_base: IO Base of intc registers. 29 */ 30 31struct ls1x_intc_priv { 32 struct irq_domain *domain; 33 void __iomem *intc_base; 34}; 35 36 37static void ls1x_chained_handle_irq(struct irq_desc *desc) 38{ 39 struct ls1x_intc_priv *priv = irq_desc_get_handler_data(desc); 40 struct irq_chip *chip = irq_desc_get_chip(desc); 41 u32 pending; 42 43 chained_irq_enter(chip, desc); 44 pending = readl(priv->intc_base + LS_REG_INTC_STATUS) & 45 readl(priv->intc_base + LS_REG_INTC_EN); 46 47 if (!pending) 48 spurious_interrupt(); 49 50 while (pending) { 51 int bit = __ffs(pending); 52 53 generic_handle_domain_irq(priv->domain, bit); 54 pending &= ~BIT(bit); 55 } 56 57 chained_irq_exit(chip, desc); 58} 59 60static void ls_intc_set_bit(struct irq_chip_generic *gc, 61 unsigned int offset, 62 u32 mask, bool set) 63{ 64 if (set) 65 writel(readl(gc->reg_base + offset) | mask, 66 gc->reg_base + offset); 67 else 68 writel(readl(gc->reg_base + offset) & ~mask, 69 gc->reg_base + offset); 70} 71 72static int ls_intc_set_type(struct irq_data *data, unsigned int type) 73{ 74 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(data); 75 u32 mask = data->mask; 76 77 switch (type) { 78 case IRQ_TYPE_LEVEL_HIGH: 79 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, false); 80 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, true); 81 break; 82 case IRQ_TYPE_LEVEL_LOW: 83 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, false); 84 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, false); 85 break; 86 case IRQ_TYPE_EDGE_RISING: 87 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, true); 88 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, true); 89 break; 90 case IRQ_TYPE_EDGE_FALLING: 91 ls_intc_set_bit(gc, LS_REG_INTC_EDGE, mask, true); 92 ls_intc_set_bit(gc, LS_REG_INTC_POL, mask, false); 93 break; 94 default: 95 return -EINVAL; 96 } 97 98 irqd_set_trigger_type(data, type); 99 return irq_setup_alt_chip(data, type); 100} 101 102 103static int __init ls1x_intc_of_init(struct device_node *node, 104 struct device_node *parent) 105{ 106 struct irq_chip_generic *gc; 107 struct irq_chip_type *ct; 108 struct ls1x_intc_priv *priv; 109 int parent_irq, err = 0; 110 111 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 112 if (!priv) 113 return -ENOMEM; 114 115 priv->intc_base = of_iomap(node, 0); 116 if (!priv->intc_base) { 117 err = -ENODEV; 118 goto out_free_priv; 119 } 120 121 parent_irq = irq_of_parse_and_map(node, 0); 122 if (!parent_irq) { 123 pr_err("ls1x-irq: unable to get parent irq\n"); 124 err = -ENODEV; 125 goto out_iounmap; 126 } 127 128 /* Set up an IRQ domain */ 129 priv->domain = irq_domain_add_linear(node, 32, &irq_generic_chip_ops, 130 NULL); 131 if (!priv->domain) { 132 pr_err("ls1x-irq: cannot add IRQ domain\n"); 133 err = -ENOMEM; 134 goto out_iounmap; 135 } 136 137 err = irq_alloc_domain_generic_chips(priv->domain, 32, 2, 138 node->full_name, handle_level_irq, 139 IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN, 0, 140 IRQ_GC_INIT_MASK_CACHE); 141 if (err) { 142 pr_err("ls1x-irq: unable to register IRQ domain\n"); 143 goto out_free_domain; 144 } 145 146 /* Mask all irqs */ 147 writel(0x0, priv->intc_base + LS_REG_INTC_EN); 148 149 /* Ack all irqs */ 150 writel(0xffffffff, priv->intc_base + LS_REG_INTC_CLR); 151 152 /* Set all irqs to high level triggered */ 153 writel(0xffffffff, priv->intc_base + LS_REG_INTC_POL); 154 155 gc = irq_get_domain_generic_chip(priv->domain, 0); 156 157 gc->reg_base = priv->intc_base; 158 159 ct = gc->chip_types; 160 ct[0].type = IRQ_TYPE_LEVEL_MASK; 161 ct[0].regs.mask = LS_REG_INTC_EN; 162 ct[0].regs.ack = LS_REG_INTC_CLR; 163 ct[0].chip.irq_unmask = irq_gc_mask_set_bit; 164 ct[0].chip.irq_mask = irq_gc_mask_clr_bit; 165 ct[0].chip.irq_ack = irq_gc_ack_set_bit; 166 ct[0].chip.irq_set_type = ls_intc_set_type; 167 ct[0].handler = handle_level_irq; 168 169 ct[1].type = IRQ_TYPE_EDGE_BOTH; 170 ct[1].regs.mask = LS_REG_INTC_EN; 171 ct[1].regs.ack = LS_REG_INTC_CLR; 172 ct[1].chip.irq_unmask = irq_gc_mask_set_bit; 173 ct[1].chip.irq_mask = irq_gc_mask_clr_bit; 174 ct[1].chip.irq_ack = irq_gc_ack_set_bit; 175 ct[1].chip.irq_set_type = ls_intc_set_type; 176 ct[1].handler = handle_edge_irq; 177 178 irq_set_chained_handler_and_data(parent_irq, 179 ls1x_chained_handle_irq, priv); 180 181 return 0; 182 183out_free_domain: 184 irq_domain_remove(priv->domain); 185out_iounmap: 186 iounmap(priv->intc_base); 187out_free_priv: 188 kfree(priv); 189 190 return err; 191} 192 193IRQCHIP_DECLARE(ls1x_intc, "loongson,ls1x-intc", ls1x_intc_of_init);