1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Comedi driver for NI PCMCIA MIO E series cards
4 *
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
7 */
8
9/*
10 * Driver: ni_mio_cs
11 * Description: National Instruments DAQCard E series
12 * Author: ds
13 * Status: works
14 * Devices: [National Instruments] DAQCard-AI-16XE-50 (ni_mio_cs),
15 *   DAQCard-AI-16E-4, DAQCard-6062E, DAQCard-6024E, DAQCard-6036E
16 * Updated: Thu Oct 23 19:43:17 CDT 2003
17 *
18 * See the notes in the ni_atmio.o driver.
19 */
20
21/*
22 * The real guts of the driver is in ni_mio_common.c, which is
23 * included by all the E series drivers.
24 *
25 * References for specifications:
26 *	341080a.pdf  DAQCard E Series Register Level Programmer Manual
27 */
28
29#include <linux/module.h>
30#include <linux/delay.h>
31#include <linux/comedi/comedi_pcmcia.h>
32#include <linux/comedi/comedi_8255.h>
33
34#include "ni_stc.h"
35
36/*
37 *  AT specific setup
38 */
39
40static const struct ni_board_struct ni_boards[] = {
41	{
42		.name		= "DAQCard-ai-16xe-50",
43		.device_id	= 0x010d,
44		.n_adchan	= 16,
45		.ai_maxdata	= 0xffff,
46		.ai_fifo_depth	= 1024,
47		.gainlkup	= ai_gain_8,
48		.ai_speed	= 5000,
49		.caldac		= { dac8800, dac8043 },
50	}, {
51		.name		= "DAQCard-ai-16e-4",
52		.device_id	= 0x010c,
53		.n_adchan	= 16,
54		.ai_maxdata	= 0x0fff,
55		.ai_fifo_depth	= 1024,
56		.gainlkup	= ai_gain_16,
57		.ai_speed	= 4000,
58		.caldac		= { mb88341 },		/* verified */
59	}, {
60		.name		= "DAQCard-6062E",
61		.device_id	= 0x02c4,
62		.n_adchan	= 16,
63		.ai_maxdata	= 0x0fff,
64		.ai_fifo_depth	= 8192,
65		.gainlkup	= ai_gain_16,
66		.ai_speed	= 2000,
67		.n_aochan	= 2,
68		.ao_maxdata	= 0x0fff,
69		.ao_fifo_depth	= 2048,
70		.ao_range_table	= &range_bipolar10,
71		.ao_speed	= 1176,
72		.caldac		= { ad8804_debug },	/* verified */
73	 }, {
74		/* specs incorrect! */
75		.name		= "DAQCard-6024E",
76		.device_id	= 0x075e,
77		.n_adchan	= 16,
78		.ai_maxdata	= 0x0fff,
79		.ai_fifo_depth	= 1024,
80		.gainlkup	= ai_gain_4,
81		.ai_speed	= 5000,
82		.n_aochan	= 2,
83		.ao_maxdata	= 0x0fff,
84		.ao_range_table	= &range_bipolar10,
85		.ao_speed	= 1000000,
86		.caldac		= { ad8804_debug },
87	}, {
88		/* specs incorrect! */
89		.name		= "DAQCard-6036E",
90		.device_id	= 0x0245,
91		.n_adchan	= 16,
92		.ai_maxdata	= 0xffff,
93		.ai_fifo_depth	= 1024,
94		.alwaysdither	= 1,
95		.gainlkup	= ai_gain_4,
96		.ai_speed	= 5000,
97		.n_aochan	= 2,
98		.ao_maxdata	= 0xffff,
99		.ao_range_table	= &range_bipolar10,
100		.ao_speed	= 1000000,
101		.caldac		= { ad8804_debug },
102	 },
103#if 0
104	{
105		.name		= "DAQCard-6715",
106		.device_id	= 0x0000,	/* unknown */
107		.n_aochan	= 8,
108		.ao_maxdata	= 0x0fff,
109		.ao_671x	= 8192,
110		.caldac		= { mb88341, mb88341 },
111	},
112#endif
113};
114
115#include "ni_mio_common.c"
116
117static const void *ni_getboardtype(struct comedi_device *dev,
118				   struct pcmcia_device *link)
119{
120	static const struct ni_board_struct *board;
121	int i;
122
123	for (i = 0; i < ARRAY_SIZE(ni_boards); i++) {
124		board = &ni_boards[i];
125		if (board->device_id == link->card_id)
126			return board;
127	}
128	return NULL;
129}
130
131static int mio_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data)
132{
133	int base, ret;
134
135	p_dev->resource[0]->flags &= ~IO_DATA_PATH_WIDTH;
136	p_dev->resource[0]->flags |= IO_DATA_PATH_WIDTH_16;
137
138	for (base = 0x000; base < 0x400; base += 0x20) {
139		p_dev->resource[0]->start = base;
140		ret = pcmcia_request_io(p_dev);
141		if (!ret)
142			return 0;
143	}
144	return -ENODEV;
145}
146
147static int mio_cs_auto_attach(struct comedi_device *dev,
148			      unsigned long context)
149{
150	struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
151	static const struct ni_board_struct *board;
152	int ret;
153
154	board = ni_getboardtype(dev, link);
155	if (!board)
156		return -ENODEV;
157	dev->board_ptr = board;
158	dev->board_name = board->name;
159
160	link->config_flags |= CONF_AUTO_SET_IO | CONF_ENABLE_IRQ;
161	ret = comedi_pcmcia_enable(dev, mio_pcmcia_config_loop);
162	if (ret)
163		return ret;
164	dev->iobase = link->resource[0]->start;
165
166	link->priv = dev;
167	ret = pcmcia_request_irq(link, ni_E_interrupt);
168	if (ret)
169		return ret;
170	dev->irq = link->irq;
171
172	ret = ni_alloc_private(dev);
173	if (ret)
174		return ret;
175
176	return ni_E_init(dev, 0, 1);
177}
178
179static void mio_cs_detach(struct comedi_device *dev)
180{
181	mio_common_detach(dev);
182	comedi_pcmcia_disable(dev);
183}
184
185static struct comedi_driver driver_ni_mio_cs = {
186	.driver_name	= "ni_mio_cs",
187	.module		= THIS_MODULE,
188	.auto_attach	= mio_cs_auto_attach,
189	.detach		= mio_cs_detach,
190};
191
192static int cs_attach(struct pcmcia_device *link)
193{
194	return comedi_pcmcia_auto_config(link, &driver_ni_mio_cs);
195}
196
197static const struct pcmcia_device_id ni_mio_cs_ids[] = {
198	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010d),	/* DAQCard-ai-16xe-50 */
199	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x010c),	/* DAQCard-ai-16e-4 */
200	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x02c4),	/* DAQCard-6062E */
201	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x075e),	/* DAQCard-6024E */
202	PCMCIA_DEVICE_MANF_CARD(0x010b, 0x0245),	/* DAQCard-6036E */
203	PCMCIA_DEVICE_NULL
204};
205MODULE_DEVICE_TABLE(pcmcia, ni_mio_cs_ids);
206
207static struct pcmcia_driver ni_mio_cs_driver = {
208	.name		= "ni_mio_cs",
209	.owner		= THIS_MODULE,
210	.id_table	= ni_mio_cs_ids,
211	.probe		= cs_attach,
212	.remove		= comedi_pcmcia_auto_unconfig,
213};
214module_comedi_pcmcia_driver(driver_ni_mio_cs, ni_mio_cs_driver);
215
216MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series");
217MODULE_AUTHOR("David A. Schleef <ds@schleef.org>");
218MODULE_LICENSE("GPL");
219