root/drivers/irqchip/irq-ftintc010.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ft010_irq_mask
  2. ft010_irq_unmask
  3. ft010_irq_ack
  4. ft010_irq_set_type
  5. ft010_irqchip_handle_irq
  6. ft010_irqdomain_map
  7. ft010_irqdomain_unmap
  8. ft010_of_init_irq

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * irqchip for the Faraday Technology FTINTC010 Copyright (C) 2017 Linus
   4  * Walleij <linus.walleij@linaro.org>
   5  *
   6  * Based on arch/arm/mach-gemini/irq.c
   7  * Copyright (C) 2001-2006 Storlink, Corp.
   8  * Copyright (C) 2008-2009 Paulius Zaleckas <paulius.zaleckas@gmail.com>
   9  */
  10 #include <linux/bitops.h>
  11 #include <linux/irq.h>
  12 #include <linux/io.h>
  13 #include <linux/irqchip.h>
  14 #include <linux/irqchip/versatile-fpga.h>
  15 #include <linux/irqdomain.h>
  16 #include <linux/module.h>
  17 #include <linux/of.h>
  18 #include <linux/of_address.h>
  19 #include <linux/of_irq.h>
  20 #include <linux/cpu.h>
  21 
  22 #include <asm/exception.h>
  23 #include <asm/mach/irq.h>
  24 
  25 #define FT010_NUM_IRQS 32
  26 
  27 #define FT010_IRQ_SOURCE(base_addr)     (base_addr + 0x00)
  28 #define FT010_IRQ_MASK(base_addr)       (base_addr + 0x04)
  29 #define FT010_IRQ_CLEAR(base_addr)      (base_addr + 0x08)
  30 /* Selects level- or edge-triggered */
  31 #define FT010_IRQ_MODE(base_addr)       (base_addr + 0x0C)
  32 /* Selects active low/high or falling/rising edge */
  33 #define FT010_IRQ_POLARITY(base_addr)   (base_addr + 0x10)
  34 #define FT010_IRQ_STATUS(base_addr)     (base_addr + 0x14)
  35 #define FT010_FIQ_SOURCE(base_addr)     (base_addr + 0x20)
  36 #define FT010_FIQ_MASK(base_addr)       (base_addr + 0x24)
  37 #define FT010_FIQ_CLEAR(base_addr)      (base_addr + 0x28)
  38 #define FT010_FIQ_MODE(base_addr)       (base_addr + 0x2C)
  39 #define FT010_FIQ_POLARITY(base_addr)   (base_addr + 0x30)
  40 #define FT010_FIQ_STATUS(base_addr)     (base_addr + 0x34)
  41 
  42 /**
  43  * struct ft010_irq_data - irq data container for the Faraday IRQ controller
  44  * @base: memory offset in virtual memory
  45  * @chip: chip container for this instance
  46  * @domain: IRQ domain for this instance
  47  */
  48 struct ft010_irq_data {
  49         void __iomem *base;
  50         struct irq_chip chip;
  51         struct irq_domain *domain;
  52 };
  53 
  54 static void ft010_irq_mask(struct irq_data *d)
  55 {
  56         struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
  57         unsigned int mask;
  58 
  59         mask = readl(FT010_IRQ_MASK(f->base));
  60         mask &= ~BIT(irqd_to_hwirq(d));
  61         writel(mask, FT010_IRQ_MASK(f->base));
  62 }
  63 
  64 static void ft010_irq_unmask(struct irq_data *d)
  65 {
  66         struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
  67         unsigned int mask;
  68 
  69         mask = readl(FT010_IRQ_MASK(f->base));
  70         mask |= BIT(irqd_to_hwirq(d));
  71         writel(mask, FT010_IRQ_MASK(f->base));
  72 }
  73 
  74 static void ft010_irq_ack(struct irq_data *d)
  75 {
  76         struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
  77 
  78         writel(BIT(irqd_to_hwirq(d)), FT010_IRQ_CLEAR(f->base));
  79 }
  80 
  81 static int ft010_irq_set_type(struct irq_data *d, unsigned int trigger)
  82 {
  83         struct ft010_irq_data *f = irq_data_get_irq_chip_data(d);
  84         int offset = irqd_to_hwirq(d);
  85         u32 mode, polarity;
  86 
  87         mode = readl(FT010_IRQ_MODE(f->base));
  88         polarity = readl(FT010_IRQ_POLARITY(f->base));
  89 
  90         if (trigger & (IRQ_TYPE_LEVEL_LOW)) {
  91                 irq_set_handler_locked(d, handle_level_irq);
  92                 mode &= ~BIT(offset);
  93                 polarity |= BIT(offset);
  94         } else if (trigger & (IRQ_TYPE_LEVEL_HIGH)) {
  95                 irq_set_handler_locked(d, handle_level_irq);
  96                 mode &= ~BIT(offset);
  97                 polarity &= ~BIT(offset);
  98         } else if (trigger & IRQ_TYPE_EDGE_FALLING) {
  99                 irq_set_handler_locked(d, handle_edge_irq);
 100                 mode |= BIT(offset);
 101                 polarity |= BIT(offset);
 102         } else if (trigger & IRQ_TYPE_EDGE_RISING) {
 103                 irq_set_handler_locked(d, handle_edge_irq);
 104                 mode |= BIT(offset);
 105                 polarity &= ~BIT(offset);
 106         } else {
 107                 irq_set_handler_locked(d, handle_bad_irq);
 108                 pr_warn("Faraday IRQ: no supported trigger selected for line %d\n",
 109                         offset);
 110         }
 111 
 112         writel(mode, FT010_IRQ_MODE(f->base));
 113         writel(polarity, FT010_IRQ_POLARITY(f->base));
 114 
 115         return 0;
 116 }
 117 
 118 static struct irq_chip ft010_irq_chip = {
 119         .name           = "FTINTC010",
 120         .irq_ack        = ft010_irq_ack,
 121         .irq_mask       = ft010_irq_mask,
 122         .irq_unmask     = ft010_irq_unmask,
 123         .irq_set_type   = ft010_irq_set_type,
 124 };
 125 
 126 /* Local static for the IRQ entry call */
 127 static struct ft010_irq_data firq;
 128 
 129 asmlinkage void __exception_irq_entry ft010_irqchip_handle_irq(struct pt_regs *regs)
 130 {
 131         struct ft010_irq_data *f = &firq;
 132         int irq;
 133         u32 status;
 134 
 135         while ((status = readl(FT010_IRQ_STATUS(f->base)))) {
 136                 irq = ffs(status) - 1;
 137                 handle_domain_irq(f->domain, irq, regs);
 138         }
 139 }
 140 
 141 static int ft010_irqdomain_map(struct irq_domain *d, unsigned int irq,
 142                                 irq_hw_number_t hwirq)
 143 {
 144         struct ft010_irq_data *f = d->host_data;
 145 
 146         irq_set_chip_data(irq, f);
 147         /* All IRQs should set up their type, flags as bad by default */
 148         irq_set_chip_and_handler(irq, &ft010_irq_chip, handle_bad_irq);
 149         irq_set_probe(irq);
 150 
 151         return 0;
 152 }
 153 
 154 static void ft010_irqdomain_unmap(struct irq_domain *d, unsigned int irq)
 155 {
 156         irq_set_chip_and_handler(irq, NULL, NULL);
 157         irq_set_chip_data(irq, NULL);
 158 }
 159 
 160 static const struct irq_domain_ops ft010_irqdomain_ops = {
 161         .map = ft010_irqdomain_map,
 162         .unmap = ft010_irqdomain_unmap,
 163         .xlate = irq_domain_xlate_onetwocell,
 164 };
 165 
 166 int __init ft010_of_init_irq(struct device_node *node,
 167                               struct device_node *parent)
 168 {
 169         struct ft010_irq_data *f = &firq;
 170 
 171         /*
 172          * Disable the idle handler by default since it is buggy
 173          * For more info see arch/arm/mach-gemini/idle.c
 174          */
 175         cpu_idle_poll_ctrl(true);
 176 
 177         f->base = of_iomap(node, 0);
 178         WARN(!f->base, "unable to map gemini irq registers\n");
 179 
 180         /* Disable all interrupts */
 181         writel(0, FT010_IRQ_MASK(f->base));
 182         writel(0, FT010_FIQ_MASK(f->base));
 183 
 184         f->domain = irq_domain_add_simple(node, FT010_NUM_IRQS, 0,
 185                                           &ft010_irqdomain_ops, f);
 186         set_handle_irq(ft010_irqchip_handle_irq);
 187 
 188         return 0;
 189 }
 190 IRQCHIP_DECLARE(faraday, "faraday,ftintc010",
 191                 ft010_of_init_irq);
 192 IRQCHIP_DECLARE(gemini, "cortina,gemini-interrupt-controller",
 193                 ft010_of_init_irq);
 194 IRQCHIP_DECLARE(moxa, "moxa,moxart-ic",
 195                 ft010_of_init_irq);

/* [<][>][^][v][top][bottom][index][help] */