uio_mf624.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * UIO driver fo Humusoft MF624 DAQ card.
  3. * Copyright (C) 2011 Rostislav Lisovy <lisovy@gmail.com>,
  4. * Czech Technical University in Prague
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19. */
  20. #include <linux/init.h>
  21. #include <linux/module.h>
  22. #include <linux/device.h>
  23. #include <linux/pci.h>
  24. #include <linux/slab.h>
  25. #include <linux/io.h>
  26. #include <linux/kernel.h>
  27. #include <linux/uio_driver.h>
  28. #define PCI_VENDOR_ID_HUMUSOFT 0x186c
  29. #define PCI_DEVICE_ID_MF624 0x0624
  30. #define PCI_SUBVENDOR_ID_HUMUSOFT 0x186c
  31. #define PCI_SUBDEVICE_DEVICE 0x0624
  32. /* BAR0 Interrupt control/status register */
  33. #define INTCSR 0x4C
  34. #define INTCSR_ADINT_ENABLE (1 << 0)
  35. #define INTCSR_CTR4INT_ENABLE (1 << 3)
  36. #define INTCSR_PCIINT_ENABLE (1 << 6)
  37. #define INTCSR_ADINT_STATUS (1 << 2)
  38. #define INTCSR_CTR4INT_STATUS (1 << 5)
  39. enum mf624_interrupt_source {ADC, CTR4, ALL};
  40. static void mf624_disable_interrupt(enum mf624_interrupt_source source,
  41. struct uio_info *info)
  42. {
  43. void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
  44. switch (source) {
  45. case ADC:
  46. iowrite32(ioread32(INTCSR_reg)
  47. & ~(INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE),
  48. INTCSR_reg);
  49. break;
  50. case CTR4:
  51. iowrite32(ioread32(INTCSR_reg)
  52. & ~(INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE),
  53. INTCSR_reg);
  54. break;
  55. case ALL:
  56. default:
  57. iowrite32(ioread32(INTCSR_reg)
  58. & ~(INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
  59. | INTCSR_PCIINT_ENABLE),
  60. INTCSR_reg);
  61. break;
  62. }
  63. }
  64. static void mf624_enable_interrupt(enum mf624_interrupt_source source,
  65. struct uio_info *info)
  66. {
  67. void __iomem *INTCSR_reg = info->mem[0].internal_addr + INTCSR;
  68. switch (source) {
  69. case ADC:
  70. iowrite32(ioread32(INTCSR_reg)
  71. | INTCSR_ADINT_ENABLE | INTCSR_PCIINT_ENABLE,
  72. INTCSR_reg);
  73. break;
  74. case CTR4:
  75. iowrite32(ioread32(INTCSR_reg)
  76. | INTCSR_CTR4INT_ENABLE | INTCSR_PCIINT_ENABLE,
  77. INTCSR_reg);
  78. break;
  79. case ALL:
  80. default:
  81. iowrite32(ioread32(INTCSR_reg)
  82. | INTCSR_ADINT_ENABLE | INTCSR_CTR4INT_ENABLE
  83. | INTCSR_PCIINT_ENABLE,
  84. INTCSR_reg);
  85. break;
  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. if ((ioread32(INTCSR_reg) & INTCSR_ADINT_ENABLE)
  92. && (ioread32(INTCSR_reg) & INTCSR_ADINT_STATUS)) {
  93. mf624_disable_interrupt(ADC, info);
  94. return IRQ_HANDLED;
  95. }
  96. if ((ioread32(INTCSR_reg) & INTCSR_CTR4INT_ENABLE)
  97. && (ioread32(INTCSR_reg) & INTCSR_CTR4INT_STATUS)) {
  98. mf624_disable_interrupt(CTR4, info);
  99. return IRQ_HANDLED;
  100. }
  101. return IRQ_NONE;
  102. }
  103. static int mf624_irqcontrol(struct uio_info *info, s32 irq_on)
  104. {
  105. if (irq_on == 0)
  106. mf624_disable_interrupt(ALL, info);
  107. else if (irq_on == 1)
  108. mf624_enable_interrupt(ALL, info);
  109. return 0;
  110. }
  111. static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
  112. {
  113. struct uio_info *info;
  114. info = kzalloc(sizeof(struct uio_info), GFP_KERNEL);
  115. if (!info)
  116. return -ENOMEM;
  117. if (pci_enable_device(dev))
  118. goto out_free;
  119. if (pci_request_regions(dev, "mf624"))
  120. goto out_disable;
  121. info->name = "mf624";
  122. info->version = "0.0.1";
  123. /* Note: Datasheet says device uses BAR0, BAR1, BAR2 -- do not trust it */
  124. /* BAR0 */
  125. info->mem[0].name = "PCI chipset, interrupts, status "
  126. "bits, special functions";
  127. info->mem[0].addr = pci_resource_start(dev, 0);
  128. if (!info->mem[0].addr)
  129. goto out_release;
  130. info->mem[0].size = pci_resource_len(dev, 0);
  131. info->mem[0].memtype = UIO_MEM_PHYS;
  132. info->mem[0].internal_addr = pci_ioremap_bar(dev, 0);
  133. if (!info->mem[0].internal_addr)
  134. goto out_release;
  135. /* BAR2 */
  136. info->mem[1].name = "ADC, DAC, DIO";
  137. info->mem[1].addr = pci_resource_start(dev, 2);
  138. if (!info->mem[1].addr)
  139. goto out_unmap0;
  140. info->mem[1].size = pci_resource_len(dev, 2);
  141. info->mem[1].memtype = UIO_MEM_PHYS;
  142. info->mem[1].internal_addr = pci_ioremap_bar(dev, 2);
  143. if (!info->mem[1].internal_addr)
  144. goto out_unmap0;
  145. /* BAR4 */
  146. info->mem[2].name = "Counter/timer chip";
  147. info->mem[2].addr = pci_resource_start(dev, 4);
  148. if (!info->mem[2].addr)
  149. goto out_unmap1;
  150. info->mem[2].size = pci_resource_len(dev, 4);
  151. info->mem[2].memtype = UIO_MEM_PHYS;
  152. info->mem[2].internal_addr = pci_ioremap_bar(dev, 4);
  153. if (!info->mem[2].internal_addr)
  154. goto out_unmap1;
  155. info->irq = dev->irq;
  156. info->irq_flags = IRQF_SHARED;
  157. info->handler = mf624_irq_handler;
  158. info->irqcontrol = mf624_irqcontrol;
  159. if (uio_register_device(&dev->dev, info))
  160. goto out_unmap2;
  161. pci_set_drvdata(dev, info);
  162. return 0;
  163. out_unmap2:
  164. iounmap(info->mem[2].internal_addr);
  165. out_unmap1:
  166. iounmap(info->mem[1].internal_addr);
  167. out_unmap0:
  168. iounmap(info->mem[0].internal_addr);
  169. out_release:
  170. pci_release_regions(dev);
  171. out_disable:
  172. pci_disable_device(dev);
  173. out_free:
  174. kfree(info);
  175. return -ENODEV;
  176. }
  177. static void mf624_pci_remove(struct pci_dev *dev)
  178. {
  179. struct uio_info *info = pci_get_drvdata(dev);
  180. mf624_disable_interrupt(ALL, info);
  181. uio_unregister_device(info);
  182. pci_release_regions(dev);
  183. pci_disable_device(dev);
  184. iounmap(info->mem[0].internal_addr);
  185. iounmap(info->mem[1].internal_addr);
  186. iounmap(info->mem[2].internal_addr);
  187. kfree(info);
  188. }
  189. static const struct pci_device_id mf624_pci_id[] = {
  190. { PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
  191. { 0, }
  192. };
  193. static struct pci_driver mf624_pci_driver = {
  194. .name = "mf624",
  195. .id_table = mf624_pci_id,
  196. .probe = mf624_pci_probe,
  197. .remove = mf624_pci_remove,
  198. };
  199. MODULE_DEVICE_TABLE(pci, mf624_pci_id);
  200. module_pci_driver(mf624_pci_driver);
  201. MODULE_LICENSE("GPL v2");
  202. MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");