Commit | Line | Data |
---|---|---|
8f567c37 HS |
1 | /* |
2 | * COMEDI driver for the ADLINK PCI-723x/743x series boards. | |
3 | * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> | |
4 | * | |
5 | * Based on the adl_pci7230 driver written by: | |
6 | * David Fernandez <dfcastelao@gmail.com> | |
7 | * and the adl_pci7432 driver written by: | |
8 | * Michel Lachaine <mike@mikelachaine.ca> | |
9 | * | |
10 | * COMEDI - Linux Control and Measurement Device Interface | |
11 | * Copyright (C) 2000 David A. Schleef <ds@schleef.org> | |
12 | * | |
13 | * This program is free software; you can redistribute it and/or modify | |
14 | * it under the terms of the GNU General Public License as published by | |
15 | * the Free Software Foundation; either version 2 of the License, or | |
16 | * (at your option) any later version. | |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | * GNU General Public License for more details. | |
8f567c37 HS |
22 | */ |
23 | ||
24 | /* | |
cd44161e IA |
25 | * Driver: adl_pci7x3x |
26 | * Description: 32/64-Channel Isolated Digital I/O Boards | |
27 | * Devices: [ADLink] PCI-7230 (adl_pci7230), PCI-7233 (adl_pci7233), | |
28 | * PCI-7234 (adl_pci7234), PCI-7432 (adl_pci7432), PCI-7433 (adl_pci7433), | |
29 | * PCI-7434 (adl_pci7434) | |
30 | * Author: H Hartley Sweeten <hsweeten@visionengravers.com> | |
31 | * Updated: Thu, 02 Aug 2012 14:27:46 -0700 | |
32 | * Status: untested | |
33 | * | |
34 | * One or two subdevices are setup by this driver depending on | |
35 | * the number of digital inputs and/or outputs provided by the | |
36 | * board. Each subdevice has a maximum of 32 channels. | |
37 | * | |
38 | * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output | |
39 | * PCI-7233 - 1 subdevice: 0 - 32 input | |
40 | * PCI-7234 - 1 subdevice: 0 - 32 output | |
41 | * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output | |
42 | * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input | |
43 | * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output | |
44 | * | |
45 | * The PCI-7230, PCI-7432 and PCI-7433 boards also support external | |
46 | * interrupt signals on digital input channels 0 and 1. The PCI-7233 | |
47 | * has dual-interrupt sources for change-of-state (COS) on any 16 | |
48 | * digital input channels of LSB and for COS on any 16 digital input | |
49 | * lines of MSB. Interrupts are not currently supported by this | |
50 | * driver. | |
51 | * | |
52 | * Configuration Options: not applicable, uses comedi PCI auto config | |
53 | */ | |
8f567c37 | 54 | |
ce157f80 | 55 | #include <linux/module.h> |
33782dd5 | 56 | |
28b57484 | 57 | #include "../comedi_pci.h" |
8f567c37 | 58 | |
8f567c37 HS |
59 | /* |
60 | * Register I/O map (32-bit access only) | |
61 | */ | |
62 | #define PCI7X3X_DIO_REG 0x00 | |
63 | #define PCI743X_DIO_REG 0x04 | |
64 | ||
b5357e61 HS |
65 | enum apci1516_boardid { |
66 | BOARD_PCI7230, | |
67 | BOARD_PCI7233, | |
68 | BOARD_PCI7234, | |
69 | BOARD_PCI7432, | |
70 | BOARD_PCI7433, | |
71 | BOARD_PCI7434, | |
72 | }; | |
73 | ||
8f567c37 HS |
74 | struct adl_pci7x3x_boardinfo { |
75 | const char *name; | |
8f567c37 HS |
76 | int nsubdevs; |
77 | int di_nchan; | |
78 | int do_nchan; | |
79 | }; | |
80 | ||
81 | static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = { | |
b5357e61 | 82 | [BOARD_PCI7230] = { |
8f567c37 | 83 | .name = "adl_pci7230", |
8f567c37 HS |
84 | .nsubdevs = 2, |
85 | .di_nchan = 16, | |
86 | .do_nchan = 16, | |
b5357e61 HS |
87 | }, |
88 | [BOARD_PCI7233] = { | |
8f567c37 | 89 | .name = "adl_pci7233", |
8f567c37 HS |
90 | .nsubdevs = 1, |
91 | .di_nchan = 32, | |
b5357e61 HS |
92 | }, |
93 | [BOARD_PCI7234] = { | |
8f567c37 | 94 | .name = "adl_pci7234", |
8f567c37 HS |
95 | .nsubdevs = 1, |
96 | .do_nchan = 32, | |
b5357e61 HS |
97 | }, |
98 | [BOARD_PCI7432] = { | |
8f567c37 | 99 | .name = "adl_pci7432", |
8f567c37 HS |
100 | .nsubdevs = 2, |
101 | .di_nchan = 32, | |
102 | .do_nchan = 32, | |
b5357e61 HS |
103 | }, |
104 | [BOARD_PCI7433] = { | |
8f567c37 | 105 | .name = "adl_pci7433", |
8f567c37 HS |
106 | .nsubdevs = 2, |
107 | .di_nchan = 64, | |
b5357e61 HS |
108 | }, |
109 | [BOARD_PCI7434] = { | |
8f567c37 | 110 | .name = "adl_pci7434", |
8f567c37 HS |
111 | .nsubdevs = 2, |
112 | .do_nchan = 64, | |
113 | } | |
114 | }; | |
115 | ||
116 | static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev, | |
117 | struct comedi_subdevice *s, | |
118 | struct comedi_insn *insn, | |
119 | unsigned int *data) | |
120 | { | |
69af5997 | 121 | unsigned long reg = (unsigned long)s->private; |
8f567c37 | 122 | |
ad83dbd9 IA |
123 | if (comedi_dio_update_state(s, data)) { |
124 | unsigned int val = s->state; | |
125 | ||
126 | if (s->n_chan == 16) { | |
127 | /* | |
128 | * It seems the PCI-7230 needs the 16-bit DO state | |
129 | * to be shifted left by 16 bits before being written | |
130 | * to the 32-bit register. Set the value in both | |
131 | * halves of the register to be sure. | |
132 | */ | |
133 | val |= val << 16; | |
134 | } | |
135 | outl(val, dev->iobase + reg); | |
136 | } | |
8f567c37 | 137 | |
8f567c37 HS |
138 | data[1] = s->state; |
139 | ||
140 | return insn->n; | |
141 | } | |
142 | ||
143 | static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev, | |
144 | struct comedi_subdevice *s, | |
145 | struct comedi_insn *insn, | |
146 | unsigned int *data) | |
147 | { | |
69af5997 | 148 | unsigned long reg = (unsigned long)s->private; |
8f567c37 HS |
149 | |
150 | data[1] = inl(dev->iobase + reg); | |
151 | ||
152 | return insn->n; | |
153 | } | |
154 | ||
a690b7e5 | 155 | static int adl_pci7x3x_auto_attach(struct comedi_device *dev, |
b5357e61 | 156 | unsigned long context) |
8f567c37 | 157 | { |
750af5e5 | 158 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
b5357e61 | 159 | const struct adl_pci7x3x_boardinfo *board = NULL; |
8f567c37 HS |
160 | struct comedi_subdevice *s; |
161 | int subdev; | |
162 | int nchan; | |
163 | int ret; | |
164 | ||
b5357e61 HS |
165 | if (context < ARRAY_SIZE(adl_pci7x3x_boards)) |
166 | board = &adl_pci7x3x_boards[context]; | |
8f567c37 HS |
167 | if (!board) |
168 | return -ENODEV; | |
169 | dev->board_ptr = board; | |
170 | dev->board_name = board->name; | |
171 | ||
818f569f | 172 | ret = comedi_pci_enable(dev); |
8f567c37 HS |
173 | if (ret) |
174 | return ret; | |
175 | dev->iobase = pci_resource_start(pcidev, 2); | |
176 | ||
8f567c37 HS |
177 | ret = comedi_alloc_subdevices(dev, board->nsubdevs); |
178 | if (ret) | |
179 | return ret; | |
180 | ||
181 | subdev = 0; | |
182 | ||
183 | if (board->di_nchan) { | |
184 | nchan = min(board->di_nchan, 32); | |
185 | ||
2bac8ab3 | 186 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
187 | /* Isolated digital inputs 0 to 15/31 */ |
188 | s->type = COMEDI_SUBD_DI; | |
189 | s->subdev_flags = SDF_READABLE; | |
190 | s->n_chan = nchan; | |
191 | s->maxdata = 1; | |
192 | s->insn_bits = adl_pci7x3x_di_insn_bits; | |
193 | s->range_table = &range_digital; | |
194 | ||
195 | s->private = (void *)PCI7X3X_DIO_REG; | |
196 | ||
197 | subdev++; | |
198 | ||
199 | nchan = board->di_nchan - nchan; | |
200 | if (nchan) { | |
2bac8ab3 | 201 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
202 | /* Isolated digital inputs 32 to 63 */ |
203 | s->type = COMEDI_SUBD_DI; | |
204 | s->subdev_flags = SDF_READABLE; | |
205 | s->n_chan = nchan; | |
206 | s->maxdata = 1; | |
207 | s->insn_bits = adl_pci7x3x_di_insn_bits; | |
208 | s->range_table = &range_digital; | |
209 | ||
210 | s->private = (void *)PCI743X_DIO_REG; | |
211 | ||
212 | subdev++; | |
213 | } | |
214 | } | |
215 | ||
216 | if (board->do_nchan) { | |
217 | nchan = min(board->do_nchan, 32); | |
218 | ||
2bac8ab3 | 219 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
220 | /* Isolated digital outputs 0 to 15/31 */ |
221 | s->type = COMEDI_SUBD_DO; | |
222 | s->subdev_flags = SDF_WRITABLE; | |
223 | s->n_chan = nchan; | |
224 | s->maxdata = 1; | |
225 | s->insn_bits = adl_pci7x3x_do_insn_bits; | |
226 | s->range_table = &range_digital; | |
227 | ||
228 | s->private = (void *)PCI7X3X_DIO_REG; | |
229 | ||
230 | subdev++; | |
231 | ||
232 | nchan = board->do_nchan - nchan; | |
233 | if (nchan) { | |
2bac8ab3 | 234 | s = &dev->subdevices[subdev]; |
8f567c37 HS |
235 | /* Isolated digital outputs 32 to 63 */ |
236 | s->type = COMEDI_SUBD_DO; | |
237 | s->subdev_flags = SDF_WRITABLE; | |
238 | s->n_chan = nchan; | |
239 | s->maxdata = 1; | |
240 | s->insn_bits = adl_pci7x3x_do_insn_bits; | |
241 | s->range_table = &range_digital; | |
242 | ||
243 | s->private = (void *)PCI743X_DIO_REG; | |
244 | ||
245 | subdev++; | |
246 | } | |
247 | } | |
248 | ||
8f567c37 HS |
249 | return 0; |
250 | } | |
251 | ||
8f567c37 HS |
252 | static struct comedi_driver adl_pci7x3x_driver = { |
253 | .driver_name = "adl_pci7x3x", | |
254 | .module = THIS_MODULE, | |
750af5e5 | 255 | .auto_attach = adl_pci7x3x_auto_attach, |
aac307f9 | 256 | .detach = comedi_pci_detach, |
8f567c37 HS |
257 | }; |
258 | ||
a690b7e5 | 259 | static int adl_pci7x3x_pci_probe(struct pci_dev *dev, |
b8f4ac23 | 260 | const struct pci_device_id *id) |
8f567c37 | 261 | { |
b8f4ac23 HS |
262 | return comedi_pci_auto_config(dev, &adl_pci7x3x_driver, |
263 | id->driver_data); | |
8f567c37 HS |
264 | } |
265 | ||
41e043fc | 266 | static const struct pci_device_id adl_pci7x3x_pci_table[] = { |
b5357e61 HS |
267 | { PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 }, |
268 | { PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 }, | |
269 | { PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 }, | |
270 | { PCI_VDEVICE(ADLINK, 0x7432), BOARD_PCI7432 }, | |
271 | { PCI_VDEVICE(ADLINK, 0x7433), BOARD_PCI7433 }, | |
272 | { PCI_VDEVICE(ADLINK, 0x7434), BOARD_PCI7434 }, | |
8f567c37 HS |
273 | { 0 } |
274 | }; | |
275 | MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table); | |
276 | ||
277 | static struct pci_driver adl_pci7x3x_pci_driver = { | |
278 | .name = "adl_pci7x3x", | |
279 | .id_table = adl_pci7x3x_pci_table, | |
280 | .probe = adl_pci7x3x_pci_probe, | |
9901a4d7 | 281 | .remove = comedi_pci_auto_unconfig, |
8f567c37 HS |
282 | }; |
283 | module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver); | |
284 | ||
285 | MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards"); | |
286 | MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); | |
287 | MODULE_LICENSE("GPL"); |