xref: /linux/drivers/comedi/drivers/addi_apci_3xxx.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1e184e2beSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+
25c70cbfbSH Hartley Sweeten /*
35c70cbfbSH Hartley Sweeten  * addi_apci_3xxx.c
45c70cbfbSH Hartley Sweeten  * Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
55c70cbfbSH Hartley Sweeten  * Project manager: S. Weber
65c70cbfbSH Hartley Sweeten  *
75c70cbfbSH Hartley Sweeten  *	ADDI-DATA GmbH
85c70cbfbSH Hartley Sweeten  *	Dieselstrasse 3
95c70cbfbSH Hartley Sweeten  *	D-77833 Ottersweier
105c70cbfbSH Hartley Sweeten  *	Tel: +19(0)7223/9493-0
115c70cbfbSH Hartley Sweeten  *	Fax: +49(0)7223/9493-92
125c70cbfbSH Hartley Sweeten  *	http://www.addi-data.com
135c70cbfbSH Hartley Sweeten  *	info@addi-data.com
145c70cbfbSH Hartley Sweeten  */
155c70cbfbSH Hartley Sweeten 
16ce157f80SH Hartley Sweeten #include <linux/module.h>
171867add9SH Hartley Sweeten #include <linux/interrupt.h>
18*df0e68c1SIan Abbott #include <linux/comedi/comedi_pci.h>
193d41c443SH Hartley Sweeten 
20dcfd3494SH Hartley Sweeten #define CONV_UNIT_NS		BIT(0)
21dcfd3494SH Hartley Sweeten #define CONV_UNIT_US		BIT(1)
22dcfd3494SH Hartley Sweeten #define CONV_UNIT_MS		BIT(2)
23a67e0cc7SH Hartley Sweeten 
2498a85621SH Hartley Sweeten static const struct comedi_lrange apci3xxx_ai_range = {
2598a85621SH Hartley Sweeten 	8, {
2698a85621SH Hartley Sweeten 		BIP_RANGE(10),
2798a85621SH Hartley Sweeten 		BIP_RANGE(5),
2898a85621SH Hartley Sweeten 		BIP_RANGE(2),
2998a85621SH Hartley Sweeten 		BIP_RANGE(1),
3098a85621SH Hartley Sweeten 		UNI_RANGE(10),
3198a85621SH Hartley Sweeten 		UNI_RANGE(5),
3298a85621SH Hartley Sweeten 		UNI_RANGE(2),
3398a85621SH Hartley Sweeten 		UNI_RANGE(1)
3498a85621SH Hartley Sweeten 	}
3598a85621SH Hartley Sweeten };
3698a85621SH Hartley Sweeten 
3798a85621SH Hartley Sweeten static const struct comedi_lrange apci3xxx_ao_range = {
3898a85621SH Hartley Sweeten 	2, {
3998a85621SH Hartley Sweeten 		BIP_RANGE(10),
4098a85621SH Hartley Sweeten 		UNI_RANGE(10)
4198a85621SH Hartley Sweeten 	}
4298a85621SH Hartley Sweeten };
4398a85621SH Hartley Sweeten 
44dbae4575SH Hartley Sweeten enum apci3xxx_boardid {
45dbae4575SH Hartley Sweeten 	BOARD_APCI3000_16,
46dbae4575SH Hartley Sweeten 	BOARD_APCI3000_8,
47dbae4575SH Hartley Sweeten 	BOARD_APCI3000_4,
48dbae4575SH Hartley Sweeten 	BOARD_APCI3006_16,
49dbae4575SH Hartley Sweeten 	BOARD_APCI3006_8,
50dbae4575SH Hartley Sweeten 	BOARD_APCI3006_4,
51dbae4575SH Hartley Sweeten 	BOARD_APCI3010_16,
52dbae4575SH Hartley Sweeten 	BOARD_APCI3010_8,
53dbae4575SH Hartley Sweeten 	BOARD_APCI3010_4,
54dbae4575SH Hartley Sweeten 	BOARD_APCI3016_16,
55dbae4575SH Hartley Sweeten 	BOARD_APCI3016_8,
56dbae4575SH Hartley Sweeten 	BOARD_APCI3016_4,
57dbae4575SH Hartley Sweeten 	BOARD_APCI3100_16_4,
58dbae4575SH Hartley Sweeten 	BOARD_APCI3100_8_4,
59dbae4575SH Hartley Sweeten 	BOARD_APCI3106_16_4,
60dbae4575SH Hartley Sweeten 	BOARD_APCI3106_8_4,
61dbae4575SH Hartley Sweeten 	BOARD_APCI3110_16_4,
62dbae4575SH Hartley Sweeten 	BOARD_APCI3110_8_4,
63dbae4575SH Hartley Sweeten 	BOARD_APCI3116_16_4,
64dbae4575SH Hartley Sweeten 	BOARD_APCI3116_8_4,
65dbae4575SH Hartley Sweeten 	BOARD_APCI3003,
66dbae4575SH Hartley Sweeten 	BOARD_APCI3002_16,
67dbae4575SH Hartley Sweeten 	BOARD_APCI3002_8,
68dbae4575SH Hartley Sweeten 	BOARD_APCI3002_4,
69dbae4575SH Hartley Sweeten 	BOARD_APCI3500,
70dbae4575SH Hartley Sweeten };
71dbae4575SH Hartley Sweeten 
72e053b241SH Hartley Sweeten struct apci3xxx_boardinfo {
736abeba09SH Hartley Sweeten 	const char *name;
748a1ec30dSH Hartley Sweeten 	int ai_subdev_flags;
7547bd1ad8SH Hartley Sweeten 	int ai_n_chan;
765469d929SH Hartley Sweeten 	unsigned int ai_maxdata;
77a67e0cc7SH Hartley Sweeten 	unsigned char ai_conv_units;
788edd4425SH Hartley Sweeten 	unsigned int ai_min_acq_ns;
79fa81e2f1SH Hartley Sweeten 	unsigned int has_ao:1;
804aab8bfdSH Hartley Sweeten 	unsigned int has_dig_in:1;
814aab8bfdSH Hartley Sweeten 	unsigned int has_dig_out:1;
820ed9f25fSH Hartley Sweeten 	unsigned int has_ttl_io:1;
83e053b241SH Hartley Sweeten };
84e053b241SH Hartley Sweeten 
85e053b241SH Hartley Sweeten static const struct apci3xxx_boardinfo apci3xxx_boardtypes[] = {
86dbae4575SH Hartley Sweeten 	[BOARD_APCI3000_16] = {
876abeba09SH Hartley Sweeten 		.name			= "apci3000-16",
888a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
8947bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
905469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
91a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
928edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
930ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
94dbae4575SH Hartley Sweeten 	},
95dbae4575SH Hartley Sweeten 	[BOARD_APCI3000_8] = {
966abeba09SH Hartley Sweeten 		.name			= "apci3000-8",
978a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
9847bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
995469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
100a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1018edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
1020ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
103dbae4575SH Hartley Sweeten 	},
104dbae4575SH Hartley Sweeten 	[BOARD_APCI3000_4] = {
1056abeba09SH Hartley Sweeten 		.name			= "apci3000-4",
1068a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
10747bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 4,
1085469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
109a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1108edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
1110ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
112dbae4575SH Hartley Sweeten 	},
113dbae4575SH Hartley Sweeten 	[BOARD_APCI3006_16] = {
1146abeba09SH Hartley Sweeten 		.name			= "apci3006-16",
1158a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
11647bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
1175469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
118a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1198edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
1200ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
121dbae4575SH Hartley Sweeten 	},
122dbae4575SH Hartley Sweeten 	[BOARD_APCI3006_8] = {
1236abeba09SH Hartley Sweeten 		.name			= "apci3006-8",
1248a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
12547bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
1265469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
127a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1288edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
1290ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
130dbae4575SH Hartley Sweeten 	},
131dbae4575SH Hartley Sweeten 	[BOARD_APCI3006_4] = {
1326abeba09SH Hartley Sweeten 		.name			= "apci3006-4",
1338a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
13447bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 4,
1355469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
136a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1378edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
1380ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
139dbae4575SH Hartley Sweeten 	},
140dbae4575SH Hartley Sweeten 	[BOARD_APCI3010_16] = {
1416abeba09SH Hartley Sweeten 		.name			= "apci3010-16",
1428a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
14347bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
1445469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
145a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1468edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
1474aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
1484aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
1490ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
150dbae4575SH Hartley Sweeten 	},
151dbae4575SH Hartley Sweeten 	[BOARD_APCI3010_8] = {
1526abeba09SH Hartley Sweeten 		.name			= "apci3010-8",
1538a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
15447bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
1555469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
156a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1578edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
1584aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
1594aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
1600ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
161dbae4575SH Hartley Sweeten 	},
162dbae4575SH Hartley Sweeten 	[BOARD_APCI3010_4] = {
1636abeba09SH Hartley Sweeten 		.name			= "apci3010-4",
1648a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
16547bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 4,
1665469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
167a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1688edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
1694aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
1704aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
1710ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
172dbae4575SH Hartley Sweeten 	},
173dbae4575SH Hartley Sweeten 	[BOARD_APCI3016_16] = {
1746abeba09SH Hartley Sweeten 		.name			= "apci3016-16",
1758a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
17647bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
1775469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
178a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1798edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
1804aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
1814aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
1820ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
183dbae4575SH Hartley Sweeten 	},
184dbae4575SH Hartley Sweeten 	[BOARD_APCI3016_8] = {
1856abeba09SH Hartley Sweeten 		.name			= "apci3016-8",
1868a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
18747bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
1885469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
189a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
1908edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
1914aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
1924aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
1930ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
194dbae4575SH Hartley Sweeten 	},
195dbae4575SH Hartley Sweeten 	[BOARD_APCI3016_4] = {
1966abeba09SH Hartley Sweeten 		.name			= "apci3016-4",
1978a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
19847bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 4,
1995469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
200a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2018edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
2024aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
2034aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
2040ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
205dbae4575SH Hartley Sweeten 	},
206dbae4575SH Hartley Sweeten 	[BOARD_APCI3100_16_4] = {
2076abeba09SH Hartley Sweeten 		.name			= "apci3100-16-4",
2088a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
20947bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
2105469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
211a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2128edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
213fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2140ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
215dbae4575SH Hartley Sweeten 	},
216dbae4575SH Hartley Sweeten 	[BOARD_APCI3100_8_4] = {
2176abeba09SH Hartley Sweeten 		.name			= "apci3100-8-4",
2188a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
21947bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
2205469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
221a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2228edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
223fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2240ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
225dbae4575SH Hartley Sweeten 	},
226dbae4575SH Hartley Sweeten 	[BOARD_APCI3106_16_4] = {
2276abeba09SH Hartley Sweeten 		.name			= "apci3106-16-4",
2288a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
22947bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
2305469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
231a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2328edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
233fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2340ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
235dbae4575SH Hartley Sweeten 	},
236dbae4575SH Hartley Sweeten 	[BOARD_APCI3106_8_4] = {
2376abeba09SH Hartley Sweeten 		.name			= "apci3106-8-4",
2388a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
23947bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
2405469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
241a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2428edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 10000,
243fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2440ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
245dbae4575SH Hartley Sweeten 	},
246dbae4575SH Hartley Sweeten 	[BOARD_APCI3110_16_4] = {
2476abeba09SH Hartley Sweeten 		.name			= "apci3110-16-4",
2488a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
24947bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
2505469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
251a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2528edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
253fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2544aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
2554aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
2560ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
257dbae4575SH Hartley Sweeten 	},
258dbae4575SH Hartley Sweeten 	[BOARD_APCI3110_8_4] = {
2596abeba09SH Hartley Sweeten 		.name			= "apci3110-8-4",
2608a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
26147bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
2625469d929SH Hartley Sweeten 		.ai_maxdata		= 0x0fff,
263a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2648edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
265fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2664aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
2674aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
2680ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
269dbae4575SH Hartley Sweeten 	},
270dbae4575SH Hartley Sweeten 	[BOARD_APCI3116_16_4] = {
2716abeba09SH Hartley Sweeten 		.name			= "apci3116-16-4",
2728a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
27347bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 16,
2745469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
275a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2768edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
277fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2784aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
2794aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
2800ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
281dbae4575SH Hartley Sweeten 	},
282dbae4575SH Hartley Sweeten 	[BOARD_APCI3116_8_4] = {
2836abeba09SH Hartley Sweeten 		.name			= "apci3116-8-4",
2848a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_COMMON | SDF_GROUND | SDF_DIFF,
28547bd1ad8SH Hartley Sweeten 		.ai_n_chan		= 8,
2865469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
287a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
2888edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
289fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
2904aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
2914aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
2920ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
293dbae4575SH Hartley Sweeten 	},
294dbae4575SH Hartley Sweeten 	[BOARD_APCI3003] = {
2956abeba09SH Hartley Sweeten 		.name			= "apci3003",
2968a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_DIFF,
2978d472906SH Hartley Sweeten 		.ai_n_chan		= 4,
2985469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
299a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US |
300a67e0cc7SH Hartley Sweeten 					  CONV_UNIT_NS,
3018edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 2500,
3024aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
3034aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
304dbae4575SH Hartley Sweeten 	},
305dbae4575SH Hartley Sweeten 	[BOARD_APCI3002_16] = {
3066abeba09SH Hartley Sweeten 		.name			= "apci3002-16",
3078a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_DIFF,
3088d472906SH Hartley Sweeten 		.ai_n_chan		= 16,
3095469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
310a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
3118edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
3124aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
3134aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
314dbae4575SH Hartley Sweeten 	},
315dbae4575SH Hartley Sweeten 	[BOARD_APCI3002_8] = {
3166abeba09SH Hartley Sweeten 		.name			= "apci3002-8",
3178a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_DIFF,
3188d472906SH Hartley Sweeten 		.ai_n_chan		= 8,
3195469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
320a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
3218edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
3224aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
3234aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
324dbae4575SH Hartley Sweeten 	},
325dbae4575SH Hartley Sweeten 	[BOARD_APCI3002_4] = {
3266abeba09SH Hartley Sweeten 		.name			= "apci3002-4",
3278a1ec30dSH Hartley Sweeten 		.ai_subdev_flags	= SDF_DIFF,
3288d472906SH Hartley Sweeten 		.ai_n_chan		= 4,
3295469d929SH Hartley Sweeten 		.ai_maxdata		= 0xffff,
330a67e0cc7SH Hartley Sweeten 		.ai_conv_units		= CONV_UNIT_MS | CONV_UNIT_US,
3318edd4425SH Hartley Sweeten 		.ai_min_acq_ns		= 5000,
3324aab8bfdSH Hartley Sweeten 		.has_dig_in		= 1,
3334aab8bfdSH Hartley Sweeten 		.has_dig_out		= 1,
334dbae4575SH Hartley Sweeten 	},
335dbae4575SH Hartley Sweeten 	[BOARD_APCI3500] = {
3366abeba09SH Hartley Sweeten 		.name			= "apci3500",
337fa81e2f1SH Hartley Sweeten 		.has_ao			= 1,
3380ed9f25fSH Hartley Sweeten 		.has_ttl_io		= 1,
339c0a053b8SH Hartley Sweeten 	},
340c0a053b8SH Hartley Sweeten };
341c0a053b8SH Hartley Sweeten 
3421867add9SH Hartley Sweeten struct apci3xxx_private {
343f32376e9SH Hartley Sweeten 	unsigned int ai_timer;
344f32376e9SH Hartley Sweeten 	unsigned char ai_time_base;
3451867add9SH Hartley Sweeten };
3461867add9SH Hartley Sweeten 
apci3xxx_irq_handler(int irq,void * d)3476c5b0fffSH Hartley Sweeten static irqreturn_t apci3xxx_irq_handler(int irq, void *d)
3486c5b0fffSH Hartley Sweeten {
3496c5b0fffSH Hartley Sweeten 	struct comedi_device *dev = d;
350f32376e9SH Hartley Sweeten 	struct comedi_subdevice *s = dev->read_subdev;
3516c5b0fffSH Hartley Sweeten 	unsigned int status;
352f32376e9SH Hartley Sweeten 	unsigned int val;
3536c5b0fffSH Hartley Sweeten 
3546c5b0fffSH Hartley Sweeten 	/* Test if interrupt occur */
35524a44612SH Hartley Sweeten 	status = readl(dev->mmio + 16);
3566c5b0fffSH Hartley Sweeten 	if ((status & 0x2) == 0x2) {
3576c5b0fffSH Hartley Sweeten 		/* Reset the interrupt */
35824a44612SH Hartley Sweeten 		writel(status, dev->mmio + 16);
3596c5b0fffSH Hartley Sweeten 
36024a44612SH Hartley Sweeten 		val = readl(dev->mmio + 28);
3616aec0f9aSH Hartley Sweeten 		comedi_buf_write_samples(s, &val, 1);
362f32376e9SH Hartley Sweeten 
363f32376e9SH Hartley Sweeten 		s->async->events |= COMEDI_CB_EOA;
364f47906a3SH Hartley Sweeten 		comedi_handle_events(dev, s);
365f32376e9SH Hartley Sweeten 
366f32376e9SH Hartley Sweeten 		return IRQ_HANDLED;
367f32376e9SH Hartley Sweeten 	}
368f32376e9SH Hartley Sweeten 	return IRQ_NONE;
369f32376e9SH Hartley Sweeten }
370f32376e9SH Hartley Sweeten 
apci3xxx_ai_started(struct comedi_device * dev)371f32376e9SH Hartley Sweeten static int apci3xxx_ai_started(struct comedi_device *dev)
372f32376e9SH Hartley Sweeten {
37324a44612SH Hartley Sweeten 	if ((readl(dev->mmio + 8) & 0x80000) == 0x80000)
374f32376e9SH Hartley Sweeten 		return 1;
375f32376e9SH Hartley Sweeten 
3769ed221faSH Hartley Sweeten 	return 0;
377f32376e9SH Hartley Sweeten }
378f32376e9SH Hartley Sweeten 
apci3xxx_ai_setup(struct comedi_device * dev,unsigned int chanspec)379f32376e9SH Hartley Sweeten static int apci3xxx_ai_setup(struct comedi_device *dev, unsigned int chanspec)
380f32376e9SH Hartley Sweeten {
381f32376e9SH Hartley Sweeten 	unsigned int chan = CR_CHAN(chanspec);
382f32376e9SH Hartley Sweeten 	unsigned int range = CR_RANGE(chanspec);
383f32376e9SH Hartley Sweeten 	unsigned int aref = CR_AREF(chanspec);
384f32376e9SH Hartley Sweeten 	unsigned int delay_mode;
3856c5b0fffSH Hartley Sweeten 	unsigned int val;
3866c5b0fffSH Hartley Sweeten 
387f32376e9SH Hartley Sweeten 	if (apci3xxx_ai_started(dev))
388f32376e9SH Hartley Sweeten 		return -EBUSY;
389f32376e9SH Hartley Sweeten 
390f32376e9SH Hartley Sweeten 	/* Clear the FIFO */
39124a44612SH Hartley Sweeten 	writel(0x10000, dev->mmio + 12);
392f32376e9SH Hartley Sweeten 
393f32376e9SH Hartley Sweeten 	/* Get and save the delay mode */
39424a44612SH Hartley Sweeten 	delay_mode = readl(dev->mmio + 4);
395f32376e9SH Hartley Sweeten 	delay_mode &= 0xfffffef0;
396f32376e9SH Hartley Sweeten 
397f32376e9SH Hartley Sweeten 	/* Channel configuration selection */
39824a44612SH Hartley Sweeten 	writel(delay_mode, dev->mmio + 4);
399f32376e9SH Hartley Sweeten 
400f32376e9SH Hartley Sweeten 	/* Make the configuration */
401f32376e9SH Hartley Sweeten 	val = (range & 3) | ((range >> 2) << 6) |
402f32376e9SH Hartley Sweeten 	      ((aref == AREF_DIFF) << 7);
40324a44612SH Hartley Sweeten 	writel(val, dev->mmio + 0);
404f32376e9SH Hartley Sweeten 
405f32376e9SH Hartley Sweeten 	/* Channel selection */
40624a44612SH Hartley Sweeten 	writel(delay_mode | 0x100, dev->mmio + 4);
40724a44612SH Hartley Sweeten 	writel(chan, dev->mmio + 0);
408f32376e9SH Hartley Sweeten 
409f32376e9SH Hartley Sweeten 	/* Restore delay mode */
41024a44612SH Hartley Sweeten 	writel(delay_mode, dev->mmio + 4);
411f32376e9SH Hartley Sweeten 
412f32376e9SH Hartley Sweeten 	/* Set the number of sequence to 1 */
41324a44612SH Hartley Sweeten 	writel(1, dev->mmio + 48);
414f32376e9SH Hartley Sweeten 
415f32376e9SH Hartley Sweeten 	return 0;
4166c5b0fffSH Hartley Sweeten }
4176c5b0fffSH Hartley Sweeten 
apci3xxx_ai_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)41867562be5SH Hartley Sweeten static int apci3xxx_ai_eoc(struct comedi_device *dev,
41967562be5SH Hartley Sweeten 			   struct comedi_subdevice *s,
42067562be5SH Hartley Sweeten 			   struct comedi_insn *insn,
42167562be5SH Hartley Sweeten 			   unsigned long context)
42267562be5SH Hartley Sweeten {
42367562be5SH Hartley Sweeten 	unsigned int status;
42467562be5SH Hartley Sweeten 
42524a44612SH Hartley Sweeten 	status = readl(dev->mmio + 20);
42667562be5SH Hartley Sweeten 	if (status & 0x1)
42767562be5SH Hartley Sweeten 		return 0;
42867562be5SH Hartley Sweeten 	return -EBUSY;
42967562be5SH Hartley Sweeten }
43067562be5SH Hartley Sweeten 
apci3xxx_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)431f32376e9SH Hartley Sweeten static int apci3xxx_ai_insn_read(struct comedi_device *dev,
432f32376e9SH Hartley Sweeten 				 struct comedi_subdevice *s,
433f32376e9SH Hartley Sweeten 				 struct comedi_insn *insn,
434f32376e9SH Hartley Sweeten 				 unsigned int *data)
435f32376e9SH Hartley Sweeten {
436f32376e9SH Hartley Sweeten 	int ret;
437f32376e9SH Hartley Sweeten 	int i;
4386c5b0fffSH Hartley Sweeten 
439f32376e9SH Hartley Sweeten 	ret = apci3xxx_ai_setup(dev, insn->chanspec);
440f32376e9SH Hartley Sweeten 	if (ret)
441f32376e9SH Hartley Sweeten 		return ret;
442f32376e9SH Hartley Sweeten 
443f32376e9SH Hartley Sweeten 	for (i = 0; i < insn->n; i++) {
444f32376e9SH Hartley Sweeten 		/* Start the conversion */
44524a44612SH Hartley Sweeten 		writel(0x80000, dev->mmio + 8);
446f32376e9SH Hartley Sweeten 
447f32376e9SH Hartley Sweeten 		/* Wait the EOS */
44867562be5SH Hartley Sweeten 		ret = comedi_timeout(dev, s, insn, apci3xxx_ai_eoc, 0);
44967562be5SH Hartley Sweeten 		if (ret)
45067562be5SH Hartley Sweeten 			return ret;
451f32376e9SH Hartley Sweeten 
452f32376e9SH Hartley Sweeten 		/* Read the analog value */
45324a44612SH Hartley Sweeten 		data[i] = readl(dev->mmio + 28);
454f32376e9SH Hartley Sweeten 	}
455f32376e9SH Hartley Sweeten 
456f32376e9SH Hartley Sweeten 	return insn->n;
457f32376e9SH Hartley Sweeten }
458f32376e9SH Hartley Sweeten 
apci3xxx_ai_ns_to_timer(struct comedi_device * dev,unsigned int * ns,unsigned int flags)459f32376e9SH Hartley Sweeten static int apci3xxx_ai_ns_to_timer(struct comedi_device *dev,
460a207c12fSH Hartley Sweeten 				   unsigned int *ns, unsigned int flags)
461f32376e9SH Hartley Sweeten {
462ef97126fSIan Abbott 	const struct apci3xxx_boardinfo *board = dev->board_ptr;
463f32376e9SH Hartley Sweeten 	struct apci3xxx_private *devpriv = dev->private;
464f32376e9SH Hartley Sweeten 	unsigned int base;
465f32376e9SH Hartley Sweeten 	unsigned int timer;
466f32376e9SH Hartley Sweeten 	int time_base;
467f32376e9SH Hartley Sweeten 
468f32376e9SH Hartley Sweeten 	/* time_base: 0 = ns, 1 = us, 2 = ms */
469f32376e9SH Hartley Sweeten 	for (time_base = 0; time_base < 3; time_base++) {
470f32376e9SH Hartley Sweeten 		/* skip unsupported time bases */
471f32376e9SH Hartley Sweeten 		if (!(board->ai_conv_units & (1 << time_base)))
472f32376e9SH Hartley Sweeten 			continue;
473f32376e9SH Hartley Sweeten 
474f32376e9SH Hartley Sweeten 		switch (time_base) {
475f32376e9SH Hartley Sweeten 		case 0:
476f32376e9SH Hartley Sweeten 			base = 1;
477f32376e9SH Hartley Sweeten 			break;
478f32376e9SH Hartley Sweeten 		case 1:
479f32376e9SH Hartley Sweeten 			base = 1000;
480f32376e9SH Hartley Sweeten 			break;
481f32376e9SH Hartley Sweeten 		case 2:
482f32376e9SH Hartley Sweeten 			base = 1000000;
483f32376e9SH Hartley Sweeten 			break;
484f32376e9SH Hartley Sweeten 		}
485f32376e9SH Hartley Sweeten 
48674eede61SIan Abbott 		switch (flags & CMDF_ROUND_MASK) {
48774eede61SIan Abbott 		case CMDF_ROUND_NEAREST:
488f32376e9SH Hartley Sweeten 		default:
4892ead7b32SAmitoj Kaur Chawla 			timer = DIV_ROUND_CLOSEST(*ns, base);
490f32376e9SH Hartley Sweeten 			break;
49174eede61SIan Abbott 		case CMDF_ROUND_DOWN:
492f32376e9SH Hartley Sweeten 			timer = *ns / base;
493f32376e9SH Hartley Sweeten 			break;
49474eede61SIan Abbott 		case CMDF_ROUND_UP:
4957dfc6971Ssimran singhal 			timer = DIV_ROUND_UP(*ns, base);
496f32376e9SH Hartley Sweeten 			break;
497f32376e9SH Hartley Sweeten 		}
498f32376e9SH Hartley Sweeten 
499f32376e9SH Hartley Sweeten 		if (timer < 0x10000) {
500f32376e9SH Hartley Sweeten 			devpriv->ai_time_base = time_base;
501f32376e9SH Hartley Sweeten 			devpriv->ai_timer = timer;
502f32376e9SH Hartley Sweeten 			*ns = timer * time_base;
503f32376e9SH Hartley Sweeten 			return 0;
5046c5b0fffSH Hartley Sweeten 		}
5056c5b0fffSH Hartley Sweeten 	}
506f32376e9SH Hartley Sweeten 	return -EINVAL;
5076c5b0fffSH Hartley Sweeten }
5086c5b0fffSH Hartley Sweeten 
apci3xxx_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)50966573991SH Hartley Sweeten static int apci3xxx_ai_cmdtest(struct comedi_device *dev,
51066573991SH Hartley Sweeten 			       struct comedi_subdevice *s,
51166573991SH Hartley Sweeten 			       struct comedi_cmd *cmd)
51266573991SH Hartley Sweeten {
513ef97126fSIan Abbott 	const struct apci3xxx_boardinfo *board = dev->board_ptr;
514f32376e9SH Hartley Sweeten 	int err = 0;
51566e3015fSH Hartley Sweeten 	unsigned int arg;
516f32376e9SH Hartley Sweeten 
517f32376e9SH Hartley Sweeten 	/* Step 1 : check if triggers are trivially valid */
518f32376e9SH Hartley Sweeten 
519c0618689SIan Abbott 	err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
520c0618689SIan Abbott 	err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
521c0618689SIan Abbott 	err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
522c0618689SIan Abbott 	err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
523c0618689SIan Abbott 	err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
524f32376e9SH Hartley Sweeten 
525f32376e9SH Hartley Sweeten 	if (err)
526f32376e9SH Hartley Sweeten 		return 1;
527f32376e9SH Hartley Sweeten 
528f32376e9SH Hartley Sweeten 	/* Step 2a : make sure trigger sources are unique */
529f32376e9SH Hartley Sweeten 
530c0618689SIan Abbott 	err |= comedi_check_trigger_is_unique(cmd->stop_src);
531f32376e9SH Hartley Sweeten 
532f32376e9SH Hartley Sweeten 	/* Step 2b : and mutually compatible */
533f32376e9SH Hartley Sweeten 
534f32376e9SH Hartley Sweeten 	if (err)
535f32376e9SH Hartley Sweeten 		return 2;
536f32376e9SH Hartley Sweeten 
537f32376e9SH Hartley Sweeten 	/* Step 3: check if arguments are trivially valid */
538f32376e9SH Hartley Sweeten 
539c0618689SIan Abbott 	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
540c0618689SIan Abbott 	err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
541c0618689SIan Abbott 	err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
542f32376e9SH Hartley Sweeten 					    board->ai_min_acq_ns);
543c0618689SIan Abbott 	err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
544c0618689SIan Abbott 					   cmd->chanlist_len);
545f32376e9SH Hartley Sweeten 
546f32376e9SH Hartley Sweeten 	if (cmd->stop_src == TRIG_COUNT)
547c0618689SIan Abbott 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
548f32376e9SH Hartley Sweeten 	else	/* TRIG_NONE */
549c0618689SIan Abbott 		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
550f32376e9SH Hartley Sweeten 
551f32376e9SH Hartley Sweeten 	if (err)
552f32376e9SH Hartley Sweeten 		return 3;
553f32376e9SH Hartley Sweeten 
554f32376e9SH Hartley Sweeten 	/* step 4: fix up any arguments */
555f32376e9SH Hartley Sweeten 
55666e3015fSH Hartley Sweeten 	arg = cmd->convert_arg;
557a207c12fSH Hartley Sweeten 	err |= apci3xxx_ai_ns_to_timer(dev, &arg, cmd->flags);
558c0618689SIan Abbott 	err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
559f32376e9SH Hartley Sweeten 
560f32376e9SH Hartley Sweeten 	if (err)
561f32376e9SH Hartley Sweeten 		return 4;
562f32376e9SH Hartley Sweeten 
56366573991SH Hartley Sweeten 	return 0;
56466573991SH Hartley Sweeten }
56566573991SH Hartley Sweeten 
apci3xxx_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)56666573991SH Hartley Sweeten static int apci3xxx_ai_cmd(struct comedi_device *dev,
56766573991SH Hartley Sweeten 			   struct comedi_subdevice *s)
56866573991SH Hartley Sweeten {
569f32376e9SH Hartley Sweeten 	struct apci3xxx_private *devpriv = dev->private;
570f32376e9SH Hartley Sweeten 	struct comedi_cmd *cmd = &s->async->cmd;
571f32376e9SH Hartley Sweeten 	int ret;
572f32376e9SH Hartley Sweeten 
573f32376e9SH Hartley Sweeten 	ret = apci3xxx_ai_setup(dev, cmd->chanlist[0]);
574f32376e9SH Hartley Sweeten 	if (ret)
575f32376e9SH Hartley Sweeten 		return ret;
576f32376e9SH Hartley Sweeten 
577f32376e9SH Hartley Sweeten 	/* Set the convert timing unit */
57824a44612SH Hartley Sweeten 	writel(devpriv->ai_time_base, dev->mmio + 36);
579f32376e9SH Hartley Sweeten 
580f32376e9SH Hartley Sweeten 	/* Set the convert timing */
58124a44612SH Hartley Sweeten 	writel(devpriv->ai_timer, dev->mmio + 32);
582f32376e9SH Hartley Sweeten 
583f32376e9SH Hartley Sweeten 	/* Start the conversion */
58424a44612SH Hartley Sweeten 	writel(0x180000, dev->mmio + 8);
585f32376e9SH Hartley Sweeten 
58666573991SH Hartley Sweeten 	return 0;
58766573991SH Hartley Sweeten }
58866573991SH Hartley Sweeten 
apci3xxx_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)58966573991SH Hartley Sweeten static int apci3xxx_ai_cancel(struct comedi_device *dev,
59066573991SH Hartley Sweeten 			      struct comedi_subdevice *s)
59166573991SH Hartley Sweeten {
59266573991SH Hartley Sweeten 	return 0;
59366573991SH Hartley Sweeten }
59466573991SH Hartley Sweeten 
apci3xxx_ao_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)59567562be5SH Hartley Sweeten static int apci3xxx_ao_eoc(struct comedi_device *dev,
59667562be5SH Hartley Sweeten 			   struct comedi_subdevice *s,
59767562be5SH Hartley Sweeten 			   struct comedi_insn *insn,
59867562be5SH Hartley Sweeten 			   unsigned long context)
59967562be5SH Hartley Sweeten {
60067562be5SH Hartley Sweeten 	unsigned int status;
60167562be5SH Hartley Sweeten 
60224a44612SH Hartley Sweeten 	status = readl(dev->mmio + 96);
60367562be5SH Hartley Sweeten 	if (status & 0x100)
60467562be5SH Hartley Sweeten 		return 0;
60567562be5SH Hartley Sweeten 	return -EBUSY;
60667562be5SH Hartley Sweeten }
60767562be5SH Hartley Sweeten 
apci3xxx_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)6080e771e49SH Hartley Sweeten static int apci3xxx_ao_insn_write(struct comedi_device *dev,
6090e771e49SH Hartley Sweeten 				  struct comedi_subdevice *s,
6100e771e49SH Hartley Sweeten 				  struct comedi_insn *insn,
6110e771e49SH Hartley Sweeten 				  unsigned int *data)
6120e771e49SH Hartley Sweeten {
6130e771e49SH Hartley Sweeten 	unsigned int chan = CR_CHAN(insn->chanspec);
6140e771e49SH Hartley Sweeten 	unsigned int range = CR_RANGE(insn->chanspec);
61567562be5SH Hartley Sweeten 	int ret;
6160e771e49SH Hartley Sweeten 	int i;
6170e771e49SH Hartley Sweeten 
6180e771e49SH Hartley Sweeten 	for (i = 0; i < insn->n; i++) {
619b38d6494SH Hartley Sweeten 		unsigned int val = data[i];
620b38d6494SH Hartley Sweeten 
6210e771e49SH Hartley Sweeten 		/* Set the range selection */
62224a44612SH Hartley Sweeten 		writel(range, dev->mmio + 96);
6230e771e49SH Hartley Sweeten 
6240e771e49SH Hartley Sweeten 		/* Write the analog value to the selected channel */
625b38d6494SH Hartley Sweeten 		writel((val << 8) | chan, dev->mmio + 100);
6260e771e49SH Hartley Sweeten 
6270e771e49SH Hartley Sweeten 		/* Wait the end of transfer */
62867562be5SH Hartley Sweeten 		ret = comedi_timeout(dev, s, insn, apci3xxx_ao_eoc, 0);
62967562be5SH Hartley Sweeten 		if (ret)
63067562be5SH Hartley Sweeten 			return ret;
631b38d6494SH Hartley Sweeten 
632b38d6494SH Hartley Sweeten 		s->readback[chan] = val;
6330e771e49SH Hartley Sweeten 	}
6340e771e49SH Hartley Sweeten 
6350e771e49SH Hartley Sweeten 	return insn->n;
6360e771e49SH Hartley Sweeten }
6370e771e49SH Hartley Sweeten 
apci3xxx_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)638ae57b696SH Hartley Sweeten static int apci3xxx_di_insn_bits(struct comedi_device *dev,
639ae57b696SH Hartley Sweeten 				 struct comedi_subdevice *s,
640ae57b696SH Hartley Sweeten 				 struct comedi_insn *insn,
641ae57b696SH Hartley Sweeten 				 unsigned int *data)
642ae57b696SH Hartley Sweeten {
643dc633646SH Hartley Sweeten 	data[1] = inl(dev->iobase + 32) & 0xf;
644ae57b696SH Hartley Sweeten 
645ae57b696SH Hartley Sweeten 	return insn->n;
646ae57b696SH Hartley Sweeten }
647ae57b696SH Hartley Sweeten 
apci3xxx_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)648c3d8605fSH Hartley Sweeten static int apci3xxx_do_insn_bits(struct comedi_device *dev,
649c3d8605fSH Hartley Sweeten 				 struct comedi_subdevice *s,
650c3d8605fSH Hartley Sweeten 				 struct comedi_insn *insn,
651c3d8605fSH Hartley Sweeten 				 unsigned int *data)
652c3d8605fSH Hartley Sweeten {
653dc633646SH Hartley Sweeten 	s->state = inl(dev->iobase + 48) & 0xf;
654c3d8605fSH Hartley Sweeten 
65597f4289aSH Hartley Sweeten 	if (comedi_dio_update_state(s, data))
656dc633646SH Hartley Sweeten 		outl(s->state, dev->iobase + 48);
657c3d8605fSH Hartley Sweeten 
658c3d8605fSH Hartley Sweeten 	data[1] = s->state;
659c3d8605fSH Hartley Sweeten 
660c3d8605fSH Hartley Sweeten 	return insn->n;
661c3d8605fSH Hartley Sweeten }
662c3d8605fSH Hartley Sweeten 
apci3xxx_dio_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)663da6578abSH Hartley Sweeten static int apci3xxx_dio_insn_config(struct comedi_device *dev,
664da6578abSH Hartley Sweeten 				    struct comedi_subdevice *s,
665da6578abSH Hartley Sweeten 				    struct comedi_insn *insn,
666da6578abSH Hartley Sweeten 				    unsigned int *data)
667da6578abSH Hartley Sweeten {
668da6578abSH Hartley Sweeten 	unsigned int chan = CR_CHAN(insn->chanspec);
669b0377d4bSChase Southwood 	unsigned int mask = 0;
6705dacadccSH Hartley Sweeten 	int ret;
671da6578abSH Hartley Sweeten 
672da6578abSH Hartley Sweeten 	/*
673da6578abSH Hartley Sweeten 	 * Port 0 (channels 0-7) are always inputs
674da6578abSH Hartley Sweeten 	 * Port 1 (channels 8-15) are always outputs
675da6578abSH Hartley Sweeten 	 * Port 2 (channels 16-23) are programmable i/o
676da6578abSH Hartley Sweeten 	 */
677b0377d4bSChase Southwood 	if (data[0] != INSN_CONFIG_DIO_QUERY) {
678b0377d4bSChase Southwood 		/* ignore all other instructions for ports 0 and 1 */
679b0377d4bSChase Southwood 		if (chan < 16)
680da6578abSH Hartley Sweeten 			return -EINVAL;
6819ed221faSH Hartley Sweeten 
6829ed221faSH Hartley Sweeten 		/* changing any channel in port 2 changes the entire port */
6835dacadccSH Hartley Sweeten 		mask = 0xff0000;
684da6578abSH Hartley Sweeten 	}
685da6578abSH Hartley Sweeten 
6865dacadccSH Hartley Sweeten 	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
6875dacadccSH Hartley Sweeten 	if (ret)
6885dacadccSH Hartley Sweeten 		return ret;
6895dacadccSH Hartley Sweeten 
690da6578abSH Hartley Sweeten 	/* update port 2 configuration */
691dc633646SH Hartley Sweeten 	outl((s->io_bits >> 24) & 0xff, dev->iobase + 224);
692da6578abSH Hartley Sweeten 
693da6578abSH Hartley Sweeten 	return insn->n;
694da6578abSH Hartley Sweeten }
695da6578abSH Hartley Sweeten 
apci3xxx_dio_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)696da6578abSH Hartley Sweeten static int apci3xxx_dio_insn_bits(struct comedi_device *dev,
697da6578abSH Hartley Sweeten 				  struct comedi_subdevice *s,
698da6578abSH Hartley Sweeten 				  struct comedi_insn *insn,
699da6578abSH Hartley Sweeten 				  unsigned int *data)
700da6578abSH Hartley Sweeten {
701ca5d4a20SH Hartley Sweeten 	unsigned int mask;
702da6578abSH Hartley Sweeten 	unsigned int val;
703da6578abSH Hartley Sweeten 
704ca5d4a20SH Hartley Sweeten 	mask = comedi_dio_update_state(s, data);
705da6578abSH Hartley Sweeten 	if (mask) {
706da6578abSH Hartley Sweeten 		if (mask & 0xff)
707dc633646SH Hartley Sweeten 			outl(s->state & 0xff, dev->iobase + 80);
708da6578abSH Hartley Sweeten 		if (mask & 0xff0000)
709dc633646SH Hartley Sweeten 			outl((s->state >> 16) & 0xff, dev->iobase + 112);
710da6578abSH Hartley Sweeten 	}
711da6578abSH Hartley Sweeten 
712dc633646SH Hartley Sweeten 	val = inl(dev->iobase + 80);
713dc633646SH Hartley Sweeten 	val |= (inl(dev->iobase + 64) << 8);
714da6578abSH Hartley Sweeten 	if (s->io_bits & 0xff0000)
715dc633646SH Hartley Sweeten 		val |= (inl(dev->iobase + 112) << 16);
716da6578abSH Hartley Sweeten 	else
717dc633646SH Hartley Sweeten 		val |= (inl(dev->iobase + 96) << 16);
718da6578abSH Hartley Sweeten 
719da6578abSH Hartley Sweeten 	data[1] = val;
720da6578abSH Hartley Sweeten 
721da6578abSH Hartley Sweeten 	return insn->n;
722da6578abSH Hartley Sweeten }
723da6578abSH Hartley Sweeten 
apci3xxx_reset(struct comedi_device * dev)7245e72c7a5SH Hartley Sweeten static int apci3xxx_reset(struct comedi_device *dev)
72598d3385dSH Hartley Sweeten {
7265e72c7a5SH Hartley Sweeten 	unsigned int val;
7275e72c7a5SH Hartley Sweeten 	int i;
72898d3385dSH Hartley Sweeten 
7295e72c7a5SH Hartley Sweeten 	/* Disable the interrupt */
7305e72c7a5SH Hartley Sweeten 	disable_irq(dev->irq);
7315e72c7a5SH Hartley Sweeten 
7325e72c7a5SH Hartley Sweeten 	/* Clear the start command */
73324a44612SH Hartley Sweeten 	writel(0, dev->mmio + 8);
7345e72c7a5SH Hartley Sweeten 
7355e72c7a5SH Hartley Sweeten 	/* Reset the interrupt flags */
73624a44612SH Hartley Sweeten 	val = readl(dev->mmio + 16);
73724a44612SH Hartley Sweeten 	writel(val, dev->mmio + 16);
7385e72c7a5SH Hartley Sweeten 
7395e72c7a5SH Hartley Sweeten 	/* clear the EOS */
74024a44612SH Hartley Sweeten 	readl(dev->mmio + 20);
7415e72c7a5SH Hartley Sweeten 
7425e72c7a5SH Hartley Sweeten 	/* Clear the FIFO */
7435e72c7a5SH Hartley Sweeten 	for (i = 0; i < 16; i++)
74424a44612SH Hartley Sweeten 		val = readl(dev->mmio + 28);
7455e72c7a5SH Hartley Sweeten 
7465e72c7a5SH Hartley Sweeten 	/* Enable the interrupt */
7475e72c7a5SH Hartley Sweeten 	enable_irq(dev->irq);
7485e72c7a5SH Hartley Sweeten 
74998d3385dSH Hartley Sweeten 	return 0;
75098d3385dSH Hartley Sweeten }
75198d3385dSH Hartley Sweeten 
apci3xxx_auto_attach(struct comedi_device * dev,unsigned long context)752dbae4575SH Hartley Sweeten static int apci3xxx_auto_attach(struct comedi_device *dev,
753dbae4575SH Hartley Sweeten 				unsigned long context)
754dbae4575SH Hartley Sweeten {
75598d3385dSH Hartley Sweeten 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
756e053b241SH Hartley Sweeten 	const struct apci3xxx_boardinfo *board = NULL;
7571867add9SH Hartley Sweeten 	struct apci3xxx_private *devpriv;
75898d3385dSH Hartley Sweeten 	struct comedi_subdevice *s;
759656e39feSH Hartley Sweeten 	int n_subdevices;
760656e39feSH Hartley Sweeten 	int subdev;
761656e39feSH Hartley Sweeten 	int ret;
762dbae4575SH Hartley Sweeten 
763dbae4575SH Hartley Sweeten 	if (context < ARRAY_SIZE(apci3xxx_boardtypes))
764dbae4575SH Hartley Sweeten 		board = &apci3xxx_boardtypes[context];
765dbae4575SH Hartley Sweeten 	if (!board)
766dbae4575SH Hartley Sweeten 		return -ENODEV;
767dbae4575SH Hartley Sweeten 	dev->board_ptr = board;
7686abeba09SH Hartley Sweeten 	dev->board_name = board->name;
769dbae4575SH Hartley Sweeten 
7700bdab509SH Hartley Sweeten 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
77198d3385dSH Hartley Sweeten 	if (!devpriv)
77298d3385dSH Hartley Sweeten 		return -ENOMEM;
77398d3385dSH Hartley Sweeten 
77498d3385dSH Hartley Sweeten 	ret = comedi_pci_enable(dev);
77598d3385dSH Hartley Sweeten 	if (ret)
77698d3385dSH Hartley Sweeten 		return ret;
77798d3385dSH Hartley Sweeten 
77898d3385dSH Hartley Sweeten 	dev->iobase = pci_resource_start(pcidev, 2);
77924a44612SH Hartley Sweeten 	dev->mmio = pci_ioremap_bar(pcidev, 3);
780a455178eSPan Bian 	if (!dev->mmio)
781a455178eSPan Bian 		return -ENOMEM;
78298d3385dSH Hartley Sweeten 
78398d3385dSH Hartley Sweeten 	if (pcidev->irq > 0) {
7846c5b0fffSH Hartley Sweeten 		ret = request_irq(pcidev->irq, apci3xxx_irq_handler,
7856c5b0fffSH Hartley Sweeten 				  IRQF_SHARED, dev->board_name, dev);
78698d3385dSH Hartley Sweeten 		if (ret == 0)
78798d3385dSH Hartley Sweeten 			dev->irq = pcidev->irq;
78898d3385dSH Hartley Sweeten 	}
78998d3385dSH Hartley Sweeten 
790656e39feSH Hartley Sweeten 	n_subdevices = (board->ai_n_chan ? 0 : 1) + board->has_ao +
791656e39feSH Hartley Sweeten 		       board->has_dig_in + board->has_dig_out +
792656e39feSH Hartley Sweeten 		       board->has_ttl_io;
79398d3385dSH Hartley Sweeten 	ret = comedi_alloc_subdevices(dev, n_subdevices);
79498d3385dSH Hartley Sweeten 	if (ret)
79598d3385dSH Hartley Sweeten 		return ret;
79698d3385dSH Hartley Sweeten 
797656e39feSH Hartley Sweeten 	subdev = 0;
798656e39feSH Hartley Sweeten 
799308380e6SH Hartley Sweeten 	/* Analog Input subdevice */
8008d472906SH Hartley Sweeten 	if (board->ai_n_chan) {
801656e39feSH Hartley Sweeten 		s = &dev->subdevices[subdev];
80298d3385dSH Hartley Sweeten 		s->type		= COMEDI_SUBD_AI;
8038a1ec30dSH Hartley Sweeten 		s->subdev_flags	= SDF_READABLE | board->ai_subdev_flags;
80447bd1ad8SH Hartley Sweeten 		s->n_chan	= board->ai_n_chan;
8055469d929SH Hartley Sweeten 		s->maxdata	= board->ai_maxdata;
80698a85621SH Hartley Sweeten 		s->range_table	= &apci3xxx_ai_range;
807088e2e05SH Hartley Sweeten 		s->insn_read	= apci3xxx_ai_insn_read;
80866573991SH Hartley Sweeten 		if (dev->irq) {
8097c9fc34eSH Hartley Sweeten 			/*
8107c9fc34eSH Hartley Sweeten 			 * FIXME: The hardware supports multiple scan modes
8117c9fc34eSH Hartley Sweeten 			 * but the original addi-data driver only supported
8127c9fc34eSH Hartley Sweeten 			 * reading a single channel with interrupts. Need a
8137c9fc34eSH Hartley Sweeten 			 * proper datasheet to fix this.
8147c9fc34eSH Hartley Sweeten 			 *
8157c9fc34eSH Hartley Sweeten 			 * The following scan modes are supported by the
8167c9fc34eSH Hartley Sweeten 			 * hardware:
8177c9fc34eSH Hartley Sweeten 			 *   1) Single software scan
8187c9fc34eSH Hartley Sweeten 			 *   2) Single hardware triggered scan
8197c9fc34eSH Hartley Sweeten 			 *   3) Continuous software scan
8207c9fc34eSH Hartley Sweeten 			 *   4) Continuous software scan with timer delay
8217c9fc34eSH Hartley Sweeten 			 *   5) Continuous hardware triggered scan
8227c9fc34eSH Hartley Sweeten 			 *   6) Continuous hardware triggered scan with timer
8237c9fc34eSH Hartley Sweeten 			 *      delay
8247c9fc34eSH Hartley Sweeten 			 *
8257c9fc34eSH Hartley Sweeten 			 * For now, limit the chanlist to a single channel.
8267c9fc34eSH Hartley Sweeten 			 */
82766573991SH Hartley Sweeten 			dev->read_subdev = s;
82866573991SH Hartley Sweeten 			s->subdev_flags	|= SDF_CMD_READ;
8297c9fc34eSH Hartley Sweeten 			s->len_chanlist	= 1;
83066573991SH Hartley Sweeten 			s->do_cmdtest	= apci3xxx_ai_cmdtest;
83166573991SH Hartley Sweeten 			s->do_cmd	= apci3xxx_ai_cmd;
83266573991SH Hartley Sweeten 			s->cancel	= apci3xxx_ai_cancel;
83366573991SH Hartley Sweeten 		}
834656e39feSH Hartley Sweeten 
835656e39feSH Hartley Sweeten 		subdev++;
83698d3385dSH Hartley Sweeten 	}
83798d3385dSH Hartley Sweeten 
8380e771e49SH Hartley Sweeten 	/* Analog Output subdevice */
839fa81e2f1SH Hartley Sweeten 	if (board->has_ao) {
840656e39feSH Hartley Sweeten 		s = &dev->subdevices[subdev];
84198d3385dSH Hartley Sweeten 		s->type		= COMEDI_SUBD_AO;
842ef49d832SH Hartley Sweeten 		s->subdev_flags	= SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
843fa81e2f1SH Hartley Sweeten 		s->n_chan	= 4;
844f1861cb0SH Hartley Sweeten 		s->maxdata	= 0x0fff;
84598a85621SH Hartley Sweeten 		s->range_table	= &apci3xxx_ao_range;
8460e771e49SH Hartley Sweeten 		s->insn_write	= apci3xxx_ao_insn_write;
847b38d6494SH Hartley Sweeten 
848b38d6494SH Hartley Sweeten 		ret = comedi_alloc_subdev_readback(s);
849b38d6494SH Hartley Sweeten 		if (ret)
850b38d6494SH Hartley Sweeten 			return ret;
851656e39feSH Hartley Sweeten 
852656e39feSH Hartley Sweeten 		subdev++;
85398d3385dSH Hartley Sweeten 	}
854ca1cc85bSH Hartley Sweeten 
855ca1cc85bSH Hartley Sweeten 	/* Digital Input subdevice */
8564aab8bfdSH Hartley Sweeten 	if (board->has_dig_in) {
857656e39feSH Hartley Sweeten 		s = &dev->subdevices[subdev];
85898d3385dSH Hartley Sweeten 		s->type		= COMEDI_SUBD_DI;
859ca1cc85bSH Hartley Sweeten 		s->subdev_flags	= SDF_READABLE;
8604aab8bfdSH Hartley Sweeten 		s->n_chan	= 4;
86198d3385dSH Hartley Sweeten 		s->maxdata	= 1;
86298d3385dSH Hartley Sweeten 		s->range_table	= &range_digital;
863ae57b696SH Hartley Sweeten 		s->insn_bits	= apci3xxx_di_insn_bits;
864656e39feSH Hartley Sweeten 
865656e39feSH Hartley Sweeten 		subdev++;
86698d3385dSH Hartley Sweeten 	}
867ca1cc85bSH Hartley Sweeten 
868ca1cc85bSH Hartley Sweeten 	/* Digital Output subdevice */
8694aab8bfdSH Hartley Sweeten 	if (board->has_dig_out) {
870656e39feSH Hartley Sweeten 		s = &dev->subdevices[subdev];
87198d3385dSH Hartley Sweeten 		s->type		= COMEDI_SUBD_DO;
872ef49d832SH Hartley Sweeten 		s->subdev_flags	= SDF_WRITABLE;
8734aab8bfdSH Hartley Sweeten 		s->n_chan	= 4;
87456e18770SH Hartley Sweeten 		s->maxdata	= 1;
87598d3385dSH Hartley Sweeten 		s->range_table	= &range_digital;
876c3d8605fSH Hartley Sweeten 		s->insn_bits	= apci3xxx_do_insn_bits;
877656e39feSH Hartley Sweeten 
878656e39feSH Hartley Sweeten 		subdev++;
87998d3385dSH Hartley Sweeten 	}
88098d3385dSH Hartley Sweeten 
881383390cfSH Hartley Sweeten 	/* TTL Digital I/O subdevice */
8820ed9f25fSH Hartley Sweeten 	if (board->has_ttl_io) {
883656e39feSH Hartley Sweeten 		s = &dev->subdevices[subdev];
884641abdacSH Hartley Sweeten 		s->type		= COMEDI_SUBD_DIO;
885ef49d832SH Hartley Sweeten 		s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
8860ed9f25fSH Hartley Sweeten 		s->n_chan	= 24;
88798d3385dSH Hartley Sweeten 		s->maxdata	= 1;
888383390cfSH Hartley Sweeten 		s->io_bits	= 0xff;	/* channels 0-7 are always outputs */
88998d3385dSH Hartley Sweeten 		s->range_table	= &range_digital;
890da6578abSH Hartley Sweeten 		s->insn_config	= apci3xxx_dio_insn_config;
891da6578abSH Hartley Sweeten 		s->insn_bits	= apci3xxx_dio_insn_bits;
89298d3385dSH Hartley Sweeten 
893656e39feSH Hartley Sweeten 		subdev++;
894656e39feSH Hartley Sweeten 	}
89598d3385dSH Hartley Sweeten 
8965e72c7a5SH Hartley Sweeten 	apci3xxx_reset(dev);
89798d3385dSH Hartley Sweeten 	return 0;
89898d3385dSH Hartley Sweeten }
89998d3385dSH Hartley Sweeten 
apci3xxx_detach(struct comedi_device * dev)90098d3385dSH Hartley Sweeten static void apci3xxx_detach(struct comedi_device *dev)
90198d3385dSH Hartley Sweeten {
90298d3385dSH Hartley Sweeten 	if (dev->iobase)
9035e72c7a5SH Hartley Sweeten 		apci3xxx_reset(dev);
904aac307f9SH Hartley Sweeten 	comedi_pci_detach(dev);
905dbae4575SH Hartley Sweeten }
906dbae4575SH Hartley Sweeten 
90720a22b70SH Hartley Sweeten static struct comedi_driver apci3xxx_driver = {
90820a22b70SH Hartley Sweeten 	.driver_name	= "addi_apci_3xxx",
90920a22b70SH Hartley Sweeten 	.module		= THIS_MODULE,
910dbae4575SH Hartley Sweeten 	.auto_attach	= apci3xxx_auto_attach,
91198d3385dSH Hartley Sweeten 	.detach		= apci3xxx_detach,
91220a22b70SH Hartley Sweeten };
91320a22b70SH Hartley Sweeten 
apci3xxx_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)914a690b7e5SBill Pemberton static int apci3xxx_pci_probe(struct pci_dev *dev,
915b8f4ac23SH Hartley Sweeten 			      const struct pci_device_id *id)
91620a22b70SH Hartley Sweeten {
917b8f4ac23SH Hartley Sweeten 	return comedi_pci_auto_config(dev, &apci3xxx_driver, id->driver_data);
91820a22b70SH Hartley Sweeten }
91920a22b70SH Hartley Sweeten 
92041e043fcSJingoo Han static const struct pci_device_id apci3xxx_pci_table[] = {
921dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3010), BOARD_APCI3000_16 },
922dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x300f), BOARD_APCI3000_8 },
923dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x300e), BOARD_APCI3000_4 },
924dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3013), BOARD_APCI3006_16 },
925dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3014), BOARD_APCI3006_8 },
926dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3015), BOARD_APCI3006_4 },
927dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3016), BOARD_APCI3010_16 },
928dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3017), BOARD_APCI3010_8 },
929dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3018), BOARD_APCI3010_4 },
930dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3019), BOARD_APCI3016_16 },
931dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x301a), BOARD_APCI3016_8 },
932dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x301b), BOARD_APCI3016_4 },
933dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x301c), BOARD_APCI3100_16_4 },
934dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x301d), BOARD_APCI3100_8_4 },
935dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x301e), BOARD_APCI3106_16_4 },
936dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x301f), BOARD_APCI3106_8_4 },
937dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3020), BOARD_APCI3110_16_4 },
938dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3021), BOARD_APCI3110_8_4 },
939dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3022), BOARD_APCI3116_16_4 },
940dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3023), BOARD_APCI3116_8_4 },
941dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x300B), BOARD_APCI3003 },
942dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3002), BOARD_APCI3002_16 },
943dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3003), BOARD_APCI3002_8 },
944dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3004), BOARD_APCI3002_4 },
945dbae4575SH Hartley Sweeten 	{ PCI_VDEVICE(ADDIDATA, 0x3024), BOARD_APCI3500 },
946317285d7SH Hartley Sweeten 	{ 0 }
947317285d7SH Hartley Sweeten };
94820a22b70SH Hartley Sweeten MODULE_DEVICE_TABLE(pci, apci3xxx_pci_table);
949317285d7SH Hartley Sweeten 
95020a22b70SH Hartley Sweeten static struct pci_driver apci3xxx_pci_driver = {
95120a22b70SH Hartley Sweeten 	.name		= "addi_apci_3xxx",
95220a22b70SH Hartley Sweeten 	.id_table	= apci3xxx_pci_table,
95320a22b70SH Hartley Sweeten 	.probe		= apci3xxx_pci_probe,
9549901a4d7SPeter Huewe 	.remove		= comedi_pci_auto_unconfig,
95520a22b70SH Hartley Sweeten };
95620a22b70SH Hartley Sweeten module_comedi_pci_driver(apci3xxx_driver, apci3xxx_pci_driver);
95790f703d3SArun Thomas 
95858b1d3f8SAlexander A. Klimov MODULE_AUTHOR("Comedi https://www.comedi.org");
95990f703d3SArun Thomas MODULE_DESCRIPTION("Comedi low-level driver");
96090f703d3SArun Thomas MODULE_LICENSE("GPL");
961