root/arch/arm/mach-pxa/pxa_cplds_irqs.c

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

DEFINITIONS

This source file includes following definitions.
  1. cplds_irq_handler
  2. cplds_irq_mask
  3. cplds_irq_unmask
  4. cplds_irq_domain_map
  5. cplds_resume
  6. cplds_probe
  7. cplds_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Intel Reference Systems cplds
   4  *
   5  * Copyright (C) 2014 Robert Jarzmik
   6  *
   7  * Cplds motherboard driver, supporting lubbock and mainstone SoC board.
   8  */
   9 
  10 #include <linux/bitops.h>
  11 #include <linux/gpio.h>
  12 #include <linux/gpio/consumer.h>
  13 #include <linux/interrupt.h>
  14 #include <linux/io.h>
  15 #include <linux/irq.h>
  16 #include <linux/irqdomain.h>
  17 #include <linux/mfd/core.h>
  18 #include <linux/module.h>
  19 #include <linux/of_platform.h>
  20 
  21 #define FPGA_IRQ_MASK_EN 0x0
  22 #define FPGA_IRQ_SET_CLR 0x10
  23 
  24 #define CPLDS_NB_IRQ    32
  25 
  26 struct cplds {
  27         void __iomem *base;
  28         int irq;
  29         unsigned int irq_mask;
  30         struct gpio_desc *gpio0;
  31         struct irq_domain *irqdomain;
  32 };
  33 
  34 static irqreturn_t cplds_irq_handler(int in_irq, void *d)
  35 {
  36         struct cplds *fpga = d;
  37         unsigned long pending;
  38         unsigned int bit;
  39 
  40         do {
  41                 pending = readl(fpga->base + FPGA_IRQ_SET_CLR) & fpga->irq_mask;
  42                 for_each_set_bit(bit, &pending, CPLDS_NB_IRQ) {
  43                         generic_handle_irq(irq_find_mapping(fpga->irqdomain,
  44                                                             bit));
  45                 }
  46         } while (pending);
  47 
  48         return IRQ_HANDLED;
  49 }
  50 
  51 static void cplds_irq_mask(struct irq_data *d)
  52 {
  53         struct cplds *fpga = irq_data_get_irq_chip_data(d);
  54         unsigned int cplds_irq = irqd_to_hwirq(d);
  55         unsigned int bit = BIT(cplds_irq);
  56 
  57         fpga->irq_mask &= ~bit;
  58         writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
  59 }
  60 
  61 static void cplds_irq_unmask(struct irq_data *d)
  62 {
  63         struct cplds *fpga = irq_data_get_irq_chip_data(d);
  64         unsigned int cplds_irq = irqd_to_hwirq(d);
  65         unsigned int set, bit = BIT(cplds_irq);
  66 
  67         set = readl(fpga->base + FPGA_IRQ_SET_CLR);
  68         writel(set & ~bit, fpga->base + FPGA_IRQ_SET_CLR);
  69 
  70         fpga->irq_mask |= bit;
  71         writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
  72 }
  73 
  74 static struct irq_chip cplds_irq_chip = {
  75         .name           = "pxa_cplds",
  76         .irq_ack        = cplds_irq_mask,
  77         .irq_mask       = cplds_irq_mask,
  78         .irq_unmask     = cplds_irq_unmask,
  79         .flags          = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_SKIP_SET_WAKE,
  80 };
  81 
  82 static int cplds_irq_domain_map(struct irq_domain *d, unsigned int irq,
  83                                    irq_hw_number_t hwirq)
  84 {
  85         struct cplds *fpga = d->host_data;
  86 
  87         irq_set_chip_and_handler(irq, &cplds_irq_chip, handle_level_irq);
  88         irq_set_chip_data(irq, fpga);
  89 
  90         return 0;
  91 }
  92 
  93 static const struct irq_domain_ops cplds_irq_domain_ops = {
  94         .xlate = irq_domain_xlate_twocell,
  95         .map = cplds_irq_domain_map,
  96 };
  97 
  98 static int cplds_resume(struct platform_device *pdev)
  99 {
 100         struct cplds *fpga = platform_get_drvdata(pdev);
 101 
 102         writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
 103 
 104         return 0;
 105 }
 106 
 107 static int cplds_probe(struct platform_device *pdev)
 108 {
 109         struct resource *res;
 110         struct cplds *fpga;
 111         int ret;
 112         int base_irq;
 113         unsigned long irqflags = 0;
 114 
 115         fpga = devm_kzalloc(&pdev->dev, sizeof(*fpga), GFP_KERNEL);
 116         if (!fpga)
 117                 return -ENOMEM;
 118 
 119         fpga->irq = platform_get_irq(pdev, 0);
 120         if (fpga->irq <= 0)
 121                 return fpga->irq;
 122 
 123         base_irq = platform_get_irq(pdev, 1);
 124         if (base_irq < 0)
 125                 base_irq = 0;
 126 
 127         res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 128         fpga->base = devm_ioremap_resource(&pdev->dev, res);
 129         if (IS_ERR(fpga->base))
 130                 return PTR_ERR(fpga->base);
 131 
 132         platform_set_drvdata(pdev, fpga);
 133 
 134         writel(fpga->irq_mask, fpga->base + FPGA_IRQ_MASK_EN);
 135         writel(0, fpga->base + FPGA_IRQ_SET_CLR);
 136 
 137         irqflags = irq_get_trigger_type(fpga->irq);
 138         ret = devm_request_irq(&pdev->dev, fpga->irq, cplds_irq_handler,
 139                                irqflags, dev_name(&pdev->dev), fpga);
 140         if (ret == -ENOSYS)
 141                 return -EPROBE_DEFER;
 142 
 143         if (ret) {
 144                 dev_err(&pdev->dev, "couldn't request main irq%d: %d\n",
 145                         fpga->irq, ret);
 146                 return ret;
 147         }
 148 
 149         irq_set_irq_wake(fpga->irq, 1);
 150         fpga->irqdomain = irq_domain_add_linear(pdev->dev.of_node,
 151                                                CPLDS_NB_IRQ,
 152                                                &cplds_irq_domain_ops, fpga);
 153         if (!fpga->irqdomain)
 154                 return -ENODEV;
 155 
 156         if (base_irq) {
 157                 ret = irq_create_strict_mappings(fpga->irqdomain, base_irq, 0,
 158                                                  CPLDS_NB_IRQ);
 159                 if (ret) {
 160                         dev_err(&pdev->dev, "couldn't create the irq mapping %d..%d\n",
 161                                 base_irq, base_irq + CPLDS_NB_IRQ);
 162                         return ret;
 163                 }
 164         }
 165 
 166         return 0;
 167 }
 168 
 169 static int cplds_remove(struct platform_device *pdev)
 170 {
 171         struct cplds *fpga = platform_get_drvdata(pdev);
 172 
 173         irq_set_chip_and_handler(fpga->irq, NULL, NULL);
 174 
 175         return 0;
 176 }
 177 
 178 static const struct of_device_id cplds_id_table[] = {
 179         { .compatible = "intel,lubbock-cplds-irqs", },
 180         { .compatible = "intel,mainstone-cplds-irqs", },
 181         { }
 182 };
 183 MODULE_DEVICE_TABLE(of, cplds_id_table);
 184 
 185 static struct platform_driver cplds_driver = {
 186         .driver         = {
 187                 .name   = "pxa_cplds_irqs",
 188                 .of_match_table = of_match_ptr(cplds_id_table),
 189         },
 190         .probe          = cplds_probe,
 191         .remove         = cplds_remove,
 192         .resume         = cplds_resume,
 193 };
 194 
 195 module_platform_driver(cplds_driver);
 196 
 197 MODULE_DESCRIPTION("PXA Cplds interrupts driver");
 198 MODULE_AUTHOR("Robert Jarzmik <robert.jarzmik@free.fr>");
 199 MODULE_LICENSE("GPL");

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