Linux Audio

Check our new training course

Loading...
v6.8
  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
 30enum mf624_interrupt_source {ADC, CTR4, ALL};
 31
 32static 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
 60static 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
 88static 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
107static 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
117static 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
135static int mf624_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
136{
137	struct uio_info *info;
138
139	info = devm_kzalloc(&dev->dev, sizeof(struct uio_info), GFP_KERNEL);
140	if (!info)
141		return -ENOMEM;
142
143	if (pci_enable_device(dev))
144		return -ENODEV;
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
179out_unmap2:
180	iounmap(info->mem[2].internal_addr);
181out_unmap1:
182	iounmap(info->mem[1].internal_addr);
183out_unmap0:
184	iounmap(info->mem[0].internal_addr);
185
186out_release:
187	pci_release_regions(dev);
188
189out_disable:
190	pci_disable_device(dev);
191
 
 
192	return -ENODEV;
193}
194
195static void mf624_pci_remove(struct pci_dev *dev)
196{
197	struct uio_info *info = pci_get_drvdata(dev);
198
199	mf624_disable_interrupt(ALL, info);
200
201	uio_unregister_device(info);
202	pci_release_regions(dev);
203	pci_disable_device(dev);
204
205	iounmap(info->mem[0].internal_addr);
206	iounmap(info->mem[1].internal_addr);
207	iounmap(info->mem[2].internal_addr);
 
 
208}
209
210static const struct pci_device_id mf624_pci_id[] = {
211	{ PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
212	{ 0, }
213};
214
215static struct pci_driver mf624_pci_driver = {
216	.name = "mf624",
217	.id_table = mf624_pci_id,
218	.probe = mf624_pci_probe,
219	.remove = mf624_pci_remove,
220};
221MODULE_DEVICE_TABLE(pci, mf624_pci_id);
222
223module_pci_driver(mf624_pci_driver);
224MODULE_LICENSE("GPL v2");
225MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");
v5.9
  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
 30enum mf624_interrupt_source {ADC, CTR4, ALL};
 31
 32static 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
 60static 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
 88static 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
107static 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
117static 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
135static 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
179out_unmap2:
180	iounmap(info->mem[2].internal_addr);
181out_unmap1:
182	iounmap(info->mem[1].internal_addr);
183out_unmap0:
184	iounmap(info->mem[0].internal_addr);
185
186out_release:
187	pci_release_regions(dev);
188
189out_disable:
190	pci_disable_device(dev);
191
192out_free:
193	kfree(info);
194	return -ENODEV;
195}
196
197static 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
214static const struct pci_device_id mf624_pci_id[] = {
215	{ PCI_DEVICE(PCI_VENDOR_ID_HUMUSOFT, PCI_DEVICE_ID_MF624) },
216	{ 0, }
217};
218
219static 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};
225MODULE_DEVICE_TABLE(pci, mf624_pci_id);
226
227module_pci_driver(mf624_pci_driver);
228MODULE_LICENSE("GPL v2");
229MODULE_AUTHOR("Rostislav Lisovy <lisovy@gmail.com>");