root/drivers/irqchip/irq-ingenic-tcu.c

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

DEFINITIONS

This source file includes following definitions.
  1. ingenic_tcu_intc_cascade
  2. ingenic_tcu_gc_unmask_enable_reg
  3. ingenic_tcu_gc_mask_disable_reg
  4. ingenic_tcu_gc_mask_disable_reg_and_ack
  5. ingenic_tcu_irq_init

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * JZ47xx SoCs TCU IRQ driver
   4  * Copyright (C) 2019 Paul Cercueil <paul@crapouillou.net>
   5  */
   6 
   7 #include <linux/clk.h>
   8 #include <linux/interrupt.h>
   9 #include <linux/irqchip.h>
  10 #include <linux/irqchip/chained_irq.h>
  11 #include <linux/mfd/ingenic-tcu.h>
  12 #include <linux/mfd/syscon.h>
  13 #include <linux/of_irq.h>
  14 #include <linux/regmap.h>
  15 
  16 struct ingenic_tcu {
  17         struct regmap *map;
  18         struct clk *clk;
  19         struct irq_domain *domain;
  20         unsigned int nb_parent_irqs;
  21         u32 parent_irqs[3];
  22 };
  23 
  24 static void ingenic_tcu_intc_cascade(struct irq_desc *desc)
  25 {
  26         struct irq_chip *irq_chip = irq_data_get_irq_chip(&desc->irq_data);
  27         struct irq_domain *domain = irq_desc_get_handler_data(desc);
  28         struct irq_chip_generic *gc = irq_get_domain_generic_chip(domain, 0);
  29         struct regmap *map = gc->private;
  30         uint32_t irq_reg, irq_mask;
  31         unsigned int i;
  32 
  33         regmap_read(map, TCU_REG_TFR, &irq_reg);
  34         regmap_read(map, TCU_REG_TMR, &irq_mask);
  35 
  36         chained_irq_enter(irq_chip, desc);
  37 
  38         irq_reg &= ~irq_mask;
  39 
  40         for_each_set_bit(i, (unsigned long *)&irq_reg, 32)
  41                 generic_handle_irq(irq_linear_revmap(domain, i));
  42 
  43         chained_irq_exit(irq_chip, desc);
  44 }
  45 
  46 static void ingenic_tcu_gc_unmask_enable_reg(struct irq_data *d)
  47 {
  48         struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  49         struct irq_chip_type *ct = irq_data_get_chip_type(d);
  50         struct regmap *map = gc->private;
  51         u32 mask = d->mask;
  52 
  53         irq_gc_lock(gc);
  54         regmap_write(map, ct->regs.ack, mask);
  55         regmap_write(map, ct->regs.enable, mask);
  56         *ct->mask_cache |= mask;
  57         irq_gc_unlock(gc);
  58 }
  59 
  60 static void ingenic_tcu_gc_mask_disable_reg(struct irq_data *d)
  61 {
  62         struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  63         struct irq_chip_type *ct = irq_data_get_chip_type(d);
  64         struct regmap *map = gc->private;
  65         u32 mask = d->mask;
  66 
  67         irq_gc_lock(gc);
  68         regmap_write(map, ct->regs.disable, mask);
  69         *ct->mask_cache &= ~mask;
  70         irq_gc_unlock(gc);
  71 }
  72 
  73 static void ingenic_tcu_gc_mask_disable_reg_and_ack(struct irq_data *d)
  74 {
  75         struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
  76         struct irq_chip_type *ct = irq_data_get_chip_type(d);
  77         struct regmap *map = gc->private;
  78         u32 mask = d->mask;
  79 
  80         irq_gc_lock(gc);
  81         regmap_write(map, ct->regs.ack, mask);
  82         regmap_write(map, ct->regs.disable, mask);
  83         irq_gc_unlock(gc);
  84 }
  85 
  86 static int __init ingenic_tcu_irq_init(struct device_node *np,
  87                                        struct device_node *parent)
  88 {
  89         struct irq_chip_generic *gc;
  90         struct irq_chip_type *ct;
  91         struct ingenic_tcu *tcu;
  92         struct regmap *map;
  93         unsigned int i;
  94         int ret, irqs;
  95 
  96         map = device_node_to_regmap(np);
  97         if (IS_ERR(map))
  98                 return PTR_ERR(map);
  99 
 100         tcu = kzalloc(sizeof(*tcu), GFP_KERNEL);
 101         if (!tcu)
 102                 return -ENOMEM;
 103 
 104         tcu->map = map;
 105 
 106         irqs = of_property_count_elems_of_size(np, "interrupts", sizeof(u32));
 107         if (irqs < 0 || irqs > ARRAY_SIZE(tcu->parent_irqs)) {
 108                 pr_crit("%s: Invalid 'interrupts' property\n", __func__);
 109                 ret = -EINVAL;
 110                 goto err_free_tcu;
 111         }
 112 
 113         tcu->nb_parent_irqs = irqs;
 114 
 115         tcu->domain = irq_domain_add_linear(np, 32, &irq_generic_chip_ops,
 116                                             NULL);
 117         if (!tcu->domain) {
 118                 ret = -ENOMEM;
 119                 goto err_free_tcu;
 120         }
 121 
 122         ret = irq_alloc_domain_generic_chips(tcu->domain, 32, 1, "TCU",
 123                                              handle_level_irq, 0,
 124                                              IRQ_NOPROBE | IRQ_LEVEL, 0);
 125         if (ret) {
 126                 pr_crit("%s: Invalid 'interrupts' property\n", __func__);
 127                 goto out_domain_remove;
 128         }
 129 
 130         gc = irq_get_domain_generic_chip(tcu->domain, 0);
 131         ct = gc->chip_types;
 132 
 133         gc->wake_enabled = IRQ_MSK(32);
 134         gc->private = tcu->map;
 135 
 136         ct->regs.disable = TCU_REG_TMSR;
 137         ct->regs.enable = TCU_REG_TMCR;
 138         ct->regs.ack = TCU_REG_TFCR;
 139         ct->chip.irq_unmask = ingenic_tcu_gc_unmask_enable_reg;
 140         ct->chip.irq_mask = ingenic_tcu_gc_mask_disable_reg;
 141         ct->chip.irq_mask_ack = ingenic_tcu_gc_mask_disable_reg_and_ack;
 142         ct->chip.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE;
 143 
 144         /* Mask all IRQs by default */
 145         regmap_write(tcu->map, TCU_REG_TMSR, IRQ_MSK(32));
 146 
 147         /*
 148          * On JZ4740, timer 0 and timer 1 have their own interrupt line;
 149          * timers 2-7 share one interrupt.
 150          * On SoCs >= JZ4770, timer 5 has its own interrupt line;
 151          * timers 0-4 and 6-7 share one single interrupt.
 152          *
 153          * To keep things simple, we just register the same handler to
 154          * all parent interrupts. The handler will properly detect which
 155          * channel fired the interrupt.
 156          */
 157         for (i = 0; i < irqs; i++) {
 158                 tcu->parent_irqs[i] = irq_of_parse_and_map(np, i);
 159                 if (!tcu->parent_irqs[i]) {
 160                         ret = -EINVAL;
 161                         goto out_unmap_irqs;
 162                 }
 163 
 164                 irq_set_chained_handler_and_data(tcu->parent_irqs[i],
 165                                                  ingenic_tcu_intc_cascade,
 166                                                  tcu->domain);
 167         }
 168 
 169         return 0;
 170 
 171 out_unmap_irqs:
 172         for (; i > 0; i--)
 173                 irq_dispose_mapping(tcu->parent_irqs[i - 1]);
 174 out_domain_remove:
 175         irq_domain_remove(tcu->domain);
 176 err_free_tcu:
 177         kfree(tcu);
 178         return ret;
 179 }
 180 IRQCHIP_DECLARE(jz4740_tcu_irq, "ingenic,jz4740-tcu", ingenic_tcu_irq_init);
 181 IRQCHIP_DECLARE(jz4725b_tcu_irq, "ingenic,jz4725b-tcu", ingenic_tcu_irq_init);
 182 IRQCHIP_DECLARE(jz4770_tcu_irq, "ingenic,jz4770-tcu", ingenic_tcu_irq_init);

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