root/drivers/irqchip/irq-keystone.c

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

DEFINITIONS

This source file includes following definitions.
  1. keystone_irq_readl
  2. keystone_irq_writel
  3. keystone_irq_setmask
  4. keystone_irq_unmask
  5. keystone_irq_ack
  6. keystone_irq_handler
  7. keystone_irq_map
  8. keystone_irq_probe
  9. keystone_irq_remove

   1 /*
   2  * Texas Instruments Keystone IRQ controller IP driver
   3  *
   4  * Copyright (C) 2014 Texas Instruments, Inc.
   5  * Author: Sajesh Kumar Saran <sajesh@ti.com>
   6  *         Grygorii Strashko <grygorii.strashko@ti.com>
   7  *
   8  * This program is free software; you can redistribute it and/or
   9  * modify it under the terms of the GNU General Public License as
  10  * published by the Free Software Foundation version 2.
  11  *
  12  * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  13  * kind, whether express or implied; without even the implied warranty
  14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15  * GNU General Public License for more details.
  16  */
  17 
  18 #include <linux/irq.h>
  19 #include <linux/bitops.h>
  20 #include <linux/module.h>
  21 #include <linux/moduleparam.h>
  22 #include <linux/interrupt.h>
  23 #include <linux/irqdomain.h>
  24 #include <linux/irqchip.h>
  25 #include <linux/of.h>
  26 #include <linux/of_platform.h>
  27 #include <linux/mfd/syscon.h>
  28 #include <linux/regmap.h>
  29 
  30 /* The source ID bits start from 4 to 31 (total 28 bits)*/
  31 #define BIT_OFS                 4
  32 #define KEYSTONE_N_IRQ          (32 - BIT_OFS)
  33 
  34 struct keystone_irq_device {
  35         struct device           *dev;
  36         struct irq_chip          chip;
  37         u32                      mask;
  38         int                      irq;
  39         struct irq_domain       *irqd;
  40         struct regmap           *devctrl_regs;
  41         u32                     devctrl_offset;
  42         raw_spinlock_t          wa_lock;
  43 };
  44 
  45 static inline u32 keystone_irq_readl(struct keystone_irq_device *kirq)
  46 {
  47         int ret;
  48         u32 val = 0;
  49 
  50         ret = regmap_read(kirq->devctrl_regs, kirq->devctrl_offset, &val);
  51         if (ret < 0)
  52                 dev_dbg(kirq->dev, "irq read failed ret(%d)\n", ret);
  53         return val;
  54 }
  55 
  56 static inline void
  57 keystone_irq_writel(struct keystone_irq_device *kirq, u32 value)
  58 {
  59         int ret;
  60 
  61         ret = regmap_write(kirq->devctrl_regs, kirq->devctrl_offset, value);
  62         if (ret < 0)
  63                 dev_dbg(kirq->dev, "irq write failed ret(%d)\n", ret);
  64 }
  65 
  66 static void keystone_irq_setmask(struct irq_data *d)
  67 {
  68         struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d);
  69 
  70         kirq->mask |= BIT(d->hwirq);
  71         dev_dbg(kirq->dev, "mask %lu [%x]\n", d->hwirq, kirq->mask);
  72 }
  73 
  74 static void keystone_irq_unmask(struct irq_data *d)
  75 {
  76         struct keystone_irq_device *kirq = irq_data_get_irq_chip_data(d);
  77 
  78         kirq->mask &= ~BIT(d->hwirq);
  79         dev_dbg(kirq->dev, "unmask %lu [%x]\n", d->hwirq, kirq->mask);
  80 }
  81 
  82 static void keystone_irq_ack(struct irq_data *d)
  83 {
  84         /* nothing to do here */
  85 }
  86 
  87 static irqreturn_t keystone_irq_handler(int irq, void *keystone_irq)
  88 {
  89         struct keystone_irq_device *kirq = keystone_irq;
  90         unsigned long wa_lock_flags;
  91         unsigned long pending;
  92         int src, virq;
  93 
  94         dev_dbg(kirq->dev, "start irq %d\n", irq);
  95 
  96         pending = keystone_irq_readl(kirq);
  97         keystone_irq_writel(kirq, pending);
  98 
  99         dev_dbg(kirq->dev, "pending 0x%lx, mask 0x%x\n", pending, kirq->mask);
 100 
 101         pending = (pending >> BIT_OFS) & ~kirq->mask;
 102 
 103         dev_dbg(kirq->dev, "pending after mask 0x%lx\n", pending);
 104 
 105         for (src = 0; src < KEYSTONE_N_IRQ; src++) {
 106                 if (BIT(src) & pending) {
 107                         virq = irq_find_mapping(kirq->irqd, src);
 108                         dev_dbg(kirq->dev, "dispatch bit %d, virq %d\n",
 109                                 src, virq);
 110                         if (!virq)
 111                                 dev_warn(kirq->dev, "spurious irq detected hwirq %d, virq %d\n",
 112                                          src, virq);
 113                         raw_spin_lock_irqsave(&kirq->wa_lock, wa_lock_flags);
 114                         generic_handle_irq(virq);
 115                         raw_spin_unlock_irqrestore(&kirq->wa_lock,
 116                                                    wa_lock_flags);
 117                 }
 118         }
 119 
 120         dev_dbg(kirq->dev, "end irq %d\n", irq);
 121         return IRQ_HANDLED;
 122 }
 123 
 124 static int keystone_irq_map(struct irq_domain *h, unsigned int virq,
 125                                 irq_hw_number_t hw)
 126 {
 127         struct keystone_irq_device *kirq = h->host_data;
 128 
 129         irq_set_chip_data(virq, kirq);
 130         irq_set_chip_and_handler(virq, &kirq->chip, handle_level_irq);
 131         irq_set_probe(virq);
 132         return 0;
 133 }
 134 
 135 static const struct irq_domain_ops keystone_irq_ops = {
 136         .map    = keystone_irq_map,
 137         .xlate  = irq_domain_xlate_onecell,
 138 };
 139 
 140 static int keystone_irq_probe(struct platform_device *pdev)
 141 {
 142         struct device *dev = &pdev->dev;
 143         struct device_node *np = dev->of_node;
 144         struct keystone_irq_device *kirq;
 145         int ret;
 146 
 147         if (np == NULL)
 148                 return -EINVAL;
 149 
 150         kirq = devm_kzalloc(dev, sizeof(*kirq), GFP_KERNEL);
 151         if (!kirq)
 152                 return -ENOMEM;
 153 
 154         kirq->devctrl_regs =
 155                 syscon_regmap_lookup_by_phandle(np, "ti,syscon-dev");
 156         if (IS_ERR(kirq->devctrl_regs))
 157                 return PTR_ERR(kirq->devctrl_regs);
 158 
 159         ret = of_property_read_u32_index(np, "ti,syscon-dev", 1,
 160                                          &kirq->devctrl_offset);
 161         if (ret) {
 162                 dev_err(dev, "couldn't read the devctrl_offset offset!\n");
 163                 return ret;
 164         }
 165 
 166         kirq->irq = platform_get_irq(pdev, 0);
 167         if (kirq->irq < 0)
 168                 return kirq->irq;
 169 
 170         kirq->dev = dev;
 171         kirq->mask = ~0x0;
 172         kirq->chip.name         = "keystone-irq";
 173         kirq->chip.irq_ack      = keystone_irq_ack;
 174         kirq->chip.irq_mask     = keystone_irq_setmask;
 175         kirq->chip.irq_unmask   = keystone_irq_unmask;
 176 
 177         kirq->irqd = irq_domain_add_linear(np, KEYSTONE_N_IRQ,
 178                                            &keystone_irq_ops, kirq);
 179         if (!kirq->irqd) {
 180                 dev_err(dev, "IRQ domain registration failed\n");
 181                 return -ENODEV;
 182         }
 183 
 184         raw_spin_lock_init(&kirq->wa_lock);
 185 
 186         platform_set_drvdata(pdev, kirq);
 187 
 188         ret = request_irq(kirq->irq, keystone_irq_handler,
 189                           0, dev_name(dev), kirq);
 190         if (ret) {
 191                 irq_domain_remove(kirq->irqd);
 192                 return ret;
 193         }
 194 
 195         /* clear all source bits */
 196         keystone_irq_writel(kirq, ~0x0);
 197 
 198         dev_info(dev, "irqchip registered, nr_irqs %u\n", KEYSTONE_N_IRQ);
 199 
 200         return 0;
 201 }
 202 
 203 static int keystone_irq_remove(struct platform_device *pdev)
 204 {
 205         struct keystone_irq_device *kirq = platform_get_drvdata(pdev);
 206         int hwirq;
 207 
 208         free_irq(kirq->irq, kirq);
 209 
 210         for (hwirq = 0; hwirq < KEYSTONE_N_IRQ; hwirq++)
 211                 irq_dispose_mapping(irq_find_mapping(kirq->irqd, hwirq));
 212 
 213         irq_domain_remove(kirq->irqd);
 214         return 0;
 215 }
 216 
 217 static const struct of_device_id keystone_irq_dt_ids[] = {
 218         { .compatible = "ti,keystone-irq", },
 219         {},
 220 };
 221 MODULE_DEVICE_TABLE(of, keystone_irq_dt_ids);
 222 
 223 static struct platform_driver keystone_irq_device_driver = {
 224         .probe          = keystone_irq_probe,
 225         .remove         = keystone_irq_remove,
 226         .driver         = {
 227                 .name   = "keystone_irq",
 228                 .of_match_table = of_match_ptr(keystone_irq_dt_ids),
 229         }
 230 };
 231 
 232 module_platform_driver(keystone_irq_device_driver);
 233 
 234 MODULE_AUTHOR("Texas Instruments");
 235 MODULE_AUTHOR("Sajesh Kumar Saran");
 236 MODULE_AUTHOR("Grygorii Strashko");
 237 MODULE_DESCRIPTION("Keystone IRQ chip");
 238 MODULE_LICENSE("GPL v2");

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