root/drivers/irqchip/irq-clps711x.c

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

DEFINITIONS

This source file includes following definitions.
  1. clps711x_irqh
  2. clps711x_intc_eoi
  3. clps711x_intc_mask
  4. clps711x_intc_unmask
  5. clps711x_intc_irq_map
  6. _clps711x_intc_init
  7. clps711x_intc_init
  8. clps711x_intc_init_dt

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *  CLPS711X IRQ driver
   4  *
   5  *  Copyright (C) 2013 Alexander Shiyan <shc_work@mail.ru>
   6  */
   7 
   8 #include <linux/io.h>
   9 #include <linux/irq.h>
  10 #include <linux/irqchip.h>
  11 #include <linux/irqdomain.h>
  12 #include <linux/of_address.h>
  13 #include <linux/of_irq.h>
  14 #include <linux/slab.h>
  15 
  16 #include <asm/exception.h>
  17 #include <asm/mach/irq.h>
  18 
  19 #define CLPS711X_INTSR1 (0x0240)
  20 #define CLPS711X_INTMR1 (0x0280)
  21 #define CLPS711X_BLEOI  (0x0600)
  22 #define CLPS711X_MCEOI  (0x0640)
  23 #define CLPS711X_TEOI   (0x0680)
  24 #define CLPS711X_TC1EOI (0x06c0)
  25 #define CLPS711X_TC2EOI (0x0700)
  26 #define CLPS711X_RTCEOI (0x0740)
  27 #define CLPS711X_UMSEOI (0x0780)
  28 #define CLPS711X_COEOI  (0x07c0)
  29 #define CLPS711X_INTSR2 (0x1240)
  30 #define CLPS711X_INTMR2 (0x1280)
  31 #define CLPS711X_SRXEOF (0x1600)
  32 #define CLPS711X_KBDEOI (0x1700)
  33 #define CLPS711X_INTSR3 (0x2240)
  34 #define CLPS711X_INTMR3 (0x2280)
  35 
  36 static const struct {
  37 #define CLPS711X_FLAG_EN        (1 << 0)
  38 #define CLPS711X_FLAG_FIQ       (1 << 1)
  39         unsigned int    flags;
  40         phys_addr_t     eoi;
  41 } clps711x_irqs[] = {
  42         [1]     = { CLPS711X_FLAG_FIQ, CLPS711X_BLEOI, },
  43         [3]     = { CLPS711X_FLAG_FIQ, CLPS711X_MCEOI, },
  44         [4]     = { CLPS711X_FLAG_EN, CLPS711X_COEOI, },
  45         [5]     = { CLPS711X_FLAG_EN, },
  46         [6]     = { CLPS711X_FLAG_EN, },
  47         [7]     = { CLPS711X_FLAG_EN, },
  48         [8]     = { CLPS711X_FLAG_EN, CLPS711X_TC1EOI, },
  49         [9]     = { CLPS711X_FLAG_EN, CLPS711X_TC2EOI, },
  50         [10]    = { CLPS711X_FLAG_EN, CLPS711X_RTCEOI, },
  51         [11]    = { CLPS711X_FLAG_EN, CLPS711X_TEOI, },
  52         [12]    = { CLPS711X_FLAG_EN, },
  53         [13]    = { CLPS711X_FLAG_EN, },
  54         [14]    = { CLPS711X_FLAG_EN, CLPS711X_UMSEOI, },
  55         [15]    = { CLPS711X_FLAG_EN, CLPS711X_SRXEOF, },
  56         [16]    = { CLPS711X_FLAG_EN, CLPS711X_KBDEOI, },
  57         [17]    = { CLPS711X_FLAG_EN, },
  58         [18]    = { CLPS711X_FLAG_EN, },
  59         [28]    = { CLPS711X_FLAG_EN, },
  60         [29]    = { CLPS711X_FLAG_EN, },
  61         [32]    = { CLPS711X_FLAG_FIQ, },
  62 };
  63 
  64 static struct {
  65         void __iomem            *base;
  66         void __iomem            *intmr[3];
  67         void __iomem            *intsr[3];
  68         struct irq_domain       *domain;
  69         struct irq_domain_ops   ops;
  70 } *clps711x_intc;
  71 
  72 static asmlinkage void __exception_irq_entry clps711x_irqh(struct pt_regs *regs)
  73 {
  74         u32 irqstat;
  75 
  76         do {
  77                 irqstat = readw_relaxed(clps711x_intc->intmr[0]) &
  78                           readw_relaxed(clps711x_intc->intsr[0]);
  79                 if (irqstat)
  80                         handle_domain_irq(clps711x_intc->domain,
  81                                           fls(irqstat) - 1, regs);
  82 
  83                 irqstat = readw_relaxed(clps711x_intc->intmr[1]) &
  84                           readw_relaxed(clps711x_intc->intsr[1]);
  85                 if (irqstat)
  86                         handle_domain_irq(clps711x_intc->domain,
  87                                           fls(irqstat) - 1 + 16, regs);
  88         } while (irqstat);
  89 }
  90 
  91 static void clps711x_intc_eoi(struct irq_data *d)
  92 {
  93         irq_hw_number_t hwirq = irqd_to_hwirq(d);
  94 
  95         writel_relaxed(0, clps711x_intc->base + clps711x_irqs[hwirq].eoi);
  96 }
  97 
  98 static void clps711x_intc_mask(struct irq_data *d)
  99 {
 100         irq_hw_number_t hwirq = irqd_to_hwirq(d);
 101         void __iomem *intmr = clps711x_intc->intmr[hwirq / 16];
 102         u32 tmp;
 103 
 104         tmp = readl_relaxed(intmr);
 105         tmp &= ~(1 << (hwirq % 16));
 106         writel_relaxed(tmp, intmr);
 107 }
 108 
 109 static void clps711x_intc_unmask(struct irq_data *d)
 110 {
 111         irq_hw_number_t hwirq = irqd_to_hwirq(d);
 112         void __iomem *intmr = clps711x_intc->intmr[hwirq / 16];
 113         u32 tmp;
 114 
 115         tmp = readl_relaxed(intmr);
 116         tmp |= 1 << (hwirq % 16);
 117         writel_relaxed(tmp, intmr);
 118 }
 119 
 120 static struct irq_chip clps711x_intc_chip = {
 121         .name           = "clps711x-intc",
 122         .irq_eoi        = clps711x_intc_eoi,
 123         .irq_mask       = clps711x_intc_mask,
 124         .irq_unmask     = clps711x_intc_unmask,
 125 };
 126 
 127 static int __init clps711x_intc_irq_map(struct irq_domain *h, unsigned int virq,
 128                                         irq_hw_number_t hw)
 129 {
 130         irq_flow_handler_t handler = handle_level_irq;
 131         unsigned int flags = 0;
 132 
 133         if (!clps711x_irqs[hw].flags)
 134                 return 0;
 135 
 136         if (clps711x_irqs[hw].flags & CLPS711X_FLAG_FIQ) {
 137                 handler = handle_bad_irq;
 138                 flags |= IRQ_NOAUTOEN;
 139         } else if (clps711x_irqs[hw].eoi) {
 140                 handler = handle_fasteoi_irq;
 141         }
 142 
 143         /* Clear down pending interrupt */
 144         if (clps711x_irqs[hw].eoi)
 145                 writel_relaxed(0, clps711x_intc->base + clps711x_irqs[hw].eoi);
 146 
 147         irq_set_chip_and_handler(virq, &clps711x_intc_chip, handler);
 148         irq_modify_status(virq, IRQ_NOPROBE, flags);
 149 
 150         return 0;
 151 }
 152 
 153 static int __init _clps711x_intc_init(struct device_node *np,
 154                                       phys_addr_t base, resource_size_t size)
 155 {
 156         int err;
 157 
 158         clps711x_intc = kzalloc(sizeof(*clps711x_intc), GFP_KERNEL);
 159         if (!clps711x_intc)
 160                 return -ENOMEM;
 161 
 162         clps711x_intc->base = ioremap(base, size);
 163         if (!clps711x_intc->base) {
 164                 err = -ENOMEM;
 165                 goto out_kfree;
 166         }
 167 
 168         clps711x_intc->intsr[0] = clps711x_intc->base + CLPS711X_INTSR1;
 169         clps711x_intc->intmr[0] = clps711x_intc->base + CLPS711X_INTMR1;
 170         clps711x_intc->intsr[1] = clps711x_intc->base + CLPS711X_INTSR2;
 171         clps711x_intc->intmr[1] = clps711x_intc->base + CLPS711X_INTMR2;
 172         clps711x_intc->intsr[2] = clps711x_intc->base + CLPS711X_INTSR3;
 173         clps711x_intc->intmr[2] = clps711x_intc->base + CLPS711X_INTMR3;
 174 
 175         /* Mask all interrupts */
 176         writel_relaxed(0, clps711x_intc->intmr[0]);
 177         writel_relaxed(0, clps711x_intc->intmr[1]);
 178         writel_relaxed(0, clps711x_intc->intmr[2]);
 179 
 180         err = irq_alloc_descs(-1, 0, ARRAY_SIZE(clps711x_irqs), numa_node_id());
 181         if (err < 0)
 182                 goto out_iounmap;
 183 
 184         clps711x_intc->ops.map = clps711x_intc_irq_map;
 185         clps711x_intc->ops.xlate = irq_domain_xlate_onecell;
 186         clps711x_intc->domain =
 187                 irq_domain_add_legacy(np, ARRAY_SIZE(clps711x_irqs),
 188                                       0, 0, &clps711x_intc->ops, NULL);
 189         if (!clps711x_intc->domain) {
 190                 err = -ENOMEM;
 191                 goto out_irqfree;
 192         }
 193 
 194         irq_set_default_host(clps711x_intc->domain);
 195         set_handle_irq(clps711x_irqh);
 196 
 197 #ifdef CONFIG_FIQ
 198         init_FIQ(0);
 199 #endif
 200 
 201         return 0;
 202 
 203 out_irqfree:
 204         irq_free_descs(0, ARRAY_SIZE(clps711x_irqs));
 205 
 206 out_iounmap:
 207         iounmap(clps711x_intc->base);
 208 
 209 out_kfree:
 210         kfree(clps711x_intc);
 211 
 212         return err;
 213 }
 214 
 215 void __init clps711x_intc_init(phys_addr_t base, resource_size_t size)
 216 {
 217         BUG_ON(_clps711x_intc_init(NULL, base, size));
 218 }
 219 
 220 #ifdef CONFIG_IRQCHIP
 221 static int __init clps711x_intc_init_dt(struct device_node *np,
 222                                         struct device_node *parent)
 223 {
 224         struct resource res;
 225         int err;
 226 
 227         err = of_address_to_resource(np, 0, &res);
 228         if (err)
 229                 return err;
 230 
 231         return _clps711x_intc_init(np, res.start, resource_size(&res));
 232 }
 233 IRQCHIP_DECLARE(clps711x, "cirrus,ep7209-intc", clps711x_intc_init_dt);
 234 #endif

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