linux/drivers/irqchip/irq-ls1x.c
<<
>>
Prefs
   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_irq(irq_find_mapping(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);
 194