root/drivers/uio/uio_mf624.c

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

DEFINITIONS

This source file includes following definitions.
  1. mf624_disable_interrupt
  2. mf624_enable_interrupt
  3. mf624_irq_handler
  4. mf624_irqcontrol
  5. mf624_setup_mem
  6. mf624_pci_probe
  7. mf624_pci_remove

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * UIO driver fo Humusoft MF624 DAQ card.
   4  * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
   5  *                    Czech Technical University in Prague
   6  */
   7 
   8 #include <linux/init.h>
   9 #include <linux/module.h>
  10 #include <linux/device.h>
  11 #include <linux/pci.h>
  12 #include <linux/slab.h>
  13 #include <linux/io.h>
  14 #include <linux/kernel.h>
  15 #include <linux/uio_driver.h>
  16 
  17 #define PCI_VENDOR_ID_HUMUSOFT          0x186c
  18 #define PCI_DEVICE_ID_MF624             0x0624
  19 #define PCI_SUBVENDOR_ID_HUMUSOFT       0x186c
  20 #define PCI_SUBDEVICE_DEVICE            0x0624
  21 
  22 /* BAR0 Interrupt control/status register */
  23 #define INTCSR                          0x4C
  24 #define INTCSR_ADINT_ENABLE             (1 << 0)
  25 #define INTCSR_CTR4INT_ENABLE           (1 << 3)
  26 #define INTCSR_PCIINT_ENABLE            (1 << 6)
  27 #define INTCSR_ADINT_STATUS             (1 << 2)
  28 #define INTCSR_CTR4INT_STATUS           (1 << 5)
  29 
  30 enum mf624_interrupt_source {ADC, CTR4, ALL};
  31 
  32 static void mf624_disable_interrupt(enum mf624_interrupt_source source,
  33                              struct uio_info *info)
  34 {
  35         void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
  36 
  37         switch (source) {
  38         case ADC:
  39                 iowrite32(ioread32(INTCSR_reg)
  40                         & ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE),
  41                         INTCSR_reg);
  42                 break;
  43 
  44         case CTR4:
  45                 iowrite32(ioread32(INTCSR_reg)
  46                         & ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE),
  47                         INTCSR_reg);
  48                 break;
  49 
  50         case ALL:
  51         default:
  52                 iowrite32(ioread32(INTCSR_reg)
  53                         & ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
  54                             | INTCSR_PCIINT_ENABLE),
  55                         INTCSR_reg);
  56                 break;
  57         }
  58 }
  59 
  60 static void mf624_enable_interrupt(enum mf624_interrupt_source source,
  61                             struct uio_info *info)
  62 {
  63         void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
  64 
  65         switch (source) {
  66         case ADC:
  67                 iowrite32(ioread32(INTCSR_reg)
  68                         | INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE,
  69                         INTCSR_reg);
  70                 break;
  71 
  72         case CTR4:
  73                 iowrite32(ioread32(INTCSR_reg)
  74                         | INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE,
  75                         INTCSR_reg);
  76                 break;
  77 
  78         case ALL:
  79         default:
  80                 iowrite32(ioread32(INTCSR_reg)
  81                         | INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
  82                         | INTCSR_PCIINT_ENABLE,
  83                         INTCSR_reg);
  84                 break;
  85         }
  86 }
  87 
  88 static irqreturn_t mf624_irq_handler(int irq, struct uio_info *info)
  89 {
  90         void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
  91 
  92         if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE)
  93             && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) {
  94                 mf624_disable_interrupt(ADC, info);
  95                 return IRQ_HANDLED;
  96         }
  97 
  98         if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE)
  99             && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) {
 100                 mf624_disable_interrupt(CTR4, info);
 101                 return IRQ_HANDLED;
 102         }
 103 
 104         return IRQ_NONE;
 105 }
 106 
 107 static int mf624_irqcontrol(struct uio_info *info, s32 irq_on)
 108 {
 109         if (irq_on == 0)
 110                 mf624_disable_interrupt(ALL, info);
 111         else if (irq_on == 1)
 112                 mf624_enable_interrupt(ALL, info);
 113 
 114         return 0;
 115 }
 116 
 117 static int mf624_setup_mem(struct pci_dev *dev, int bar, struct uio_mem *mem, const char *name)
 118 {
 119         resource_size_t start = pci_resource_start(dev, bar);
 120         resource_size_t len = pci_resource_len(dev, bar);
 121 
 122         mem->name = name;
 123         mem->addr = start & PAGE_MASK;
 124         mem->offs = start & ~PAGE_MASK;
 125         if (!mem->addr)
 126                 return -ENODEV;
 127         mem->size = ((start & ~PAGE_MASK) + len + PAGE_SIZE - 1) & PAGE_MASK;
 128         mem->memtype = UIO_MEM_PHYS;
 129         mem->internal_addr = pci_ioremap_bar(dev, bar);
 130         if (!mem->internal_addr)
 131                 return -ENODEV;
 132         return 0;
 133 }
 134 
 135 static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 136 {
 137         struct uio_info *info;
 138 
 139         info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
 140         if (!info)
 141                 return -ENOMEM;
 142 
 143         if (pci_enable_device(dev))
 144                 goto out_free;
 145 
 146         if (pci_request_regions(dev, "mf624"))
 147                 goto out_disable;
 148 
 149         info->name = "mf624";
 150         info->version = "0.0.1";
 151 
 152         /* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */
 153 
 154         /* BAR0 */
 155         if (mf624_setup_mem(dev, 0, &info->mem[0], "PCI chipset, interrupts, status "
 156                             "bits, special functions"))
 157                 goto out_release;
 158         /* BAR2 */
 159         if (mf624_setup_mem(dev, 2, &info->mem[1], "ADC, DAC, DIO"))
 160                 goto out_unmap0;
 161 
 162         /* BAR4 */
 163         if (mf624_setup_mem(dev, 4, &info->mem[2], "Counter/timer chip"))
 164                 goto out_unmap1;
 165 
 166         info->irq = dev->irq;
 167         info->irq_flags = IRQF_SHARED;
 168         info->handler = mf624_irq_handler;
 169 
 170         info->irqcontrol = mf624_irqcontrol;
 171 
 172         if (uio_register_device(&dev->dev, info))
 173                 goto out_unmap2;
 174 
 175         pci_set_drvdata(dev, info);
 176 
 177         return 0;
 178 
 179 out_unmap2:
 180         iounmap(info->mem[2].internal_addr);
 181 out_unmap1:
 182         iounmap(info->mem[1].internal_addr);
 183 out_unmap0:
 184         iounmap(info->mem[0].internal_addr);
 185 
 186 out_release:
 187         pci_release_regions(dev);
 188 
 189 out_disable:
 190         pci_disable_device(dev);
 191 
 192 out_free:
 193         kfree(info);
 194         return -ENODEV;
 195 }
 196 
 197 static void mf624_pci_remove(struct pci_dev *dev)
 198 {
 199         struct uio_info *info = pci_get_drvdata(dev);
 200 
 201         mf624_disable_interrupt(ALL, info);
 202 
 203         uio_unregister_device(info);
 204         pci_release_regions(dev);
 205         pci_disable_device(dev);
 206 
 207         iounmap(info->mem[0].internal_addr);
 208         iounmap(info->mem[1].internal_addr);
 209         iounmap(info->mem[2].internal_addr);
 210 
 211         kfree(info);
 212 }
 213 
 214 static const struct pci_device_id mf624_pci_id[] = {
 215         { PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
 216         { 0, }
 217 };
 218 
 219 static struct pci_driver mf624_pci_driver = {
 220         .name = "mf624",
 221         .id_table = mf624_pci_id,
 222         .probe = mf624_pci_probe,
 223         .remove = mf624_pci_remove,
 224 };
 225 MODULE_DEVICE_TABLE(pci, mf624_pci_id);
 226 
 227 module_pci_driver(mf624_pci_driver);
 228 MODULE_LICENSE("GPL v2");
 229 MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");

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