blob: 5617f5ca384a0bd8fd463c85dca28357bb025a2a [file] [log] [blame]
H Hartley Sweeten8f567c32012-08-03 10:28:18 -07001/*
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.
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070022 */
23
24/*
25Driver: adl_pci7x3x
26Description: 32/64-Channel Isolated Digital I/O Boards
27Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output
28 (ADLink) PCI-7233 [adl_pci7233] - 32 input
29 (ADLink) PCI-7234 [adl_pci7234] - 32 output
30 (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output
31 (ADLink) PCI-7433 [adl_pci7433] - 64 input
32 (ADLink) PCI-7434 [adl_pci7434] - 64 output
33Author: H Hartley Sweeten <hsweeten@visionengravers.com>
34Updated: Thu, 02 Aug 2012 14:27:46 -0700
35Status: untested
36
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070037The PCI-7230, PCI-7432 and PCI-7433 boards also support external
38interrupt signals on digital input channels 0 and 1. The PCI-7233
39has dual-interrupt sources for change-of-state (COS) on any 16
40digital input channels of LSB and for COS on any 16 digital input
41lines of MSB. Interrupts are not currently supported by this
42driver.
43
H Hartley Sweeten4a79f732013-02-04 17:13:01 -070044Configuration Options: not applicable, uses comedi PCI auto config
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070045*/
46
H Hartley Sweetence157f82013-06-24 17:04:43 -070047#include <linux/module.h>
H Hartley Sweeten33782dd2013-01-30 15:22:21 -070048#include <linux/pci.h>
49
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070050#include "../comedidev.h"
51
52/*
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070053 * Register I/O map (32-bit access only)
54 */
55#define PCI7X3X_DIO_REG 0x00
56#define PCI743X_DIO_REG 0x04
57
H Hartley Sweetenb5357e62013-03-05 09:59:07 -070058enum apci1516_boardid {
59 BOARD_PCI7230,
60 BOARD_PCI7233,
61 BOARD_PCI7234,
62 BOARD_PCI7432,
63 BOARD_PCI7433,
64 BOARD_PCI7434,
65};
66
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070067struct adl_pci7x3x_boardinfo {
68 const char *name;
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070069 int nsubdevs;
70 int di_nchan;
71 int do_nchan;
72};
73
74static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = {
H Hartley Sweetenb5357e62013-03-05 09:59:07 -070075 [BOARD_PCI7230] = {
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070076 .name = "adl_pci7230",
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070077 .nsubdevs = 2,
78 .di_nchan = 16,
79 .do_nchan = 16,
H Hartley Sweetenb5357e62013-03-05 09:59:07 -070080 },
81 [BOARD_PCI7233] = {
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070082 .name = "adl_pci7233",
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070083 .nsubdevs = 1,
84 .di_nchan = 32,
H Hartley Sweetenb5357e62013-03-05 09:59:07 -070085 },
86 [BOARD_PCI7234] = {
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070087 .name = "adl_pci7234",
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070088 .nsubdevs = 1,
89 .do_nchan = 32,
H Hartley Sweetenb5357e62013-03-05 09:59:07 -070090 },
91 [BOARD_PCI7432] = {
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070092 .name = "adl_pci7432",
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070093 .nsubdevs = 2,
94 .di_nchan = 32,
95 .do_nchan = 32,
H Hartley Sweetenb5357e62013-03-05 09:59:07 -070096 },
97 [BOARD_PCI7433] = {
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070098 .name = "adl_pci7433",
H Hartley Sweeten8f567c32012-08-03 10:28:18 -070099 .nsubdevs = 2,
100 .di_nchan = 64,
H Hartley Sweetenb5357e62013-03-05 09:59:07 -0700101 },
102 [BOARD_PCI7434] = {
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700103 .name = "adl_pci7434",
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700104 .nsubdevs = 2,
105 .do_nchan = 64,
106 }
107};
108
109static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev,
110 struct comedi_subdevice *s,
111 struct comedi_insn *insn,
112 unsigned int *data)
113{
H Hartley Sweeten69af5992012-08-14 13:45:53 -0700114 unsigned long reg = (unsigned long)s->private;
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700115
H Hartley Sweeten97f42892013-08-30 11:05:58 -0700116 if (comedi_dio_update_state(s, data))
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700117 outl(s->state, dev->iobase + reg);
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700118
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700119 data[1] = s->state;
120
121 return insn->n;
122}
123
124static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev,
125 struct comedi_subdevice *s,
126 struct comedi_insn *insn,
127 unsigned int *data)
128{
H Hartley Sweeten69af5992012-08-14 13:45:53 -0700129 unsigned long reg = (unsigned long)s->private;
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700130
131 data[1] = inl(dev->iobase + reg);
132
133 return insn->n;
134}
135
Bill Pembertona690b7e2012-11-19 13:21:58 -0500136static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
H Hartley Sweetenb5357e62013-03-05 09:59:07 -0700137 unsigned long context)
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700138{
Ian Abbott750af5e2012-10-30 13:30:04 +0000139 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
H Hartley Sweetenb5357e62013-03-05 09:59:07 -0700140 const struct adl_pci7x3x_boardinfo *board = NULL;
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700141 struct comedi_subdevice *s;
142 int subdev;
143 int nchan;
144 int ret;
145
H Hartley Sweetenb5357e62013-03-05 09:59:07 -0700146 if (context < ARRAY_SIZE(adl_pci7x3x_boards))
147 board = &adl_pci7x3x_boards[context];
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700148 if (!board)
149 return -ENODEV;
150 dev->board_ptr = board;
151 dev->board_name = board->name;
152
H Hartley Sweeten818f5692013-03-13 10:36:31 -0700153 ret = comedi_pci_enable(dev);
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700154 if (ret)
155 return ret;
156 dev->iobase = pci_resource_start(pcidev, 2);
157
158 /*
159 * One or two subdevices are setup by this driver depending on
160 * the number of digital inputs and/or outputs provided by the
161 * board. Each subdevice has a maximum of 32 channels.
162 *
163 * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output
164 * PCI-7233 - 1 subdevice: 0 - 32 input
165 * PCI-7234 - 1 subdevice: 0 - 32 output
166 * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output
167 * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input
168 * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output
169 */
170 ret = comedi_alloc_subdevices(dev, board->nsubdevs);
171 if (ret)
172 return ret;
173
174 subdev = 0;
175
176 if (board->di_nchan) {
177 nchan = min(board->di_nchan, 32);
178
H Hartley Sweeten2bac8ab2012-09-05 18:24:52 -0700179 s = &dev->subdevices[subdev];
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700180 /* Isolated digital inputs 0 to 15/31 */
181 s->type = COMEDI_SUBD_DI;
182 s->subdev_flags = SDF_READABLE;
183 s->n_chan = nchan;
184 s->maxdata = 1;
185 s->insn_bits = adl_pci7x3x_di_insn_bits;
186 s->range_table = &range_digital;
187
188 s->private = (void *)PCI7X3X_DIO_REG;
189
190 subdev++;
191
192 nchan = board->di_nchan - nchan;
193 if (nchan) {
H Hartley Sweeten2bac8ab2012-09-05 18:24:52 -0700194 s = &dev->subdevices[subdev];
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700195 /* Isolated digital inputs 32 to 63 */
196 s->type = COMEDI_SUBD_DI;
197 s->subdev_flags = SDF_READABLE;
198 s->n_chan = nchan;
199 s->maxdata = 1;
200 s->insn_bits = adl_pci7x3x_di_insn_bits;
201 s->range_table = &range_digital;
202
203 s->private = (void *)PCI743X_DIO_REG;
204
205 subdev++;
206 }
207 }
208
209 if (board->do_nchan) {
210 nchan = min(board->do_nchan, 32);
211
H Hartley Sweeten2bac8ab2012-09-05 18:24:52 -0700212 s = &dev->subdevices[subdev];
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700213 /* Isolated digital outputs 0 to 15/31 */
214 s->type = COMEDI_SUBD_DO;
215 s->subdev_flags = SDF_WRITABLE;
216 s->n_chan = nchan;
217 s->maxdata = 1;
218 s->insn_bits = adl_pci7x3x_do_insn_bits;
219 s->range_table = &range_digital;
220
221 s->private = (void *)PCI7X3X_DIO_REG;
222
223 subdev++;
224
225 nchan = board->do_nchan - nchan;
226 if (nchan) {
H Hartley Sweeten2bac8ab2012-09-05 18:24:52 -0700227 s = &dev->subdevices[subdev];
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700228 /* Isolated digital outputs 32 to 63 */
229 s->type = COMEDI_SUBD_DO;
230 s->subdev_flags = SDF_WRITABLE;
231 s->n_chan = nchan;
232 s->maxdata = 1;
233 s->insn_bits = adl_pci7x3x_do_insn_bits;
234 s->range_table = &range_digital;
235
236 s->private = (void *)PCI743X_DIO_REG;
237
238 subdev++;
239 }
240 }
241
242 dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n",
243 dev->board_name, board->di_nchan, board->do_nchan);
244
245 return 0;
246}
247
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700248static struct comedi_driver adl_pci7x3x_driver = {
249 .driver_name = "adl_pci7x3x",
250 .module = THIS_MODULE,
Ian Abbott750af5e2012-10-30 13:30:04 +0000251 .auto_attach = adl_pci7x3x_auto_attach,
H Hartley Sweeten7f072f52013-03-13 10:35:51 -0700252 .detach = comedi_pci_disable,
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700253};
254
Bill Pembertona690b7e2012-11-19 13:21:58 -0500255static int adl_pci7x3x_pci_probe(struct pci_dev *dev,
H Hartley Sweetenb8f4ac22013-03-05 09:53:41 -0700256 const struct pci_device_id *id)
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700257{
H Hartley Sweetenb8f4ac22013-03-05 09:53:41 -0700258 return comedi_pci_auto_config(dev, &adl_pci7x3x_driver,
259 id->driver_data);
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700260}
261
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700262static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = {
H Hartley Sweetenb5357e62013-03-05 09:59:07 -0700263 { PCI_VDEVICE(ADLINK, 0x7230), BOARD_PCI7230 },
264 { PCI_VDEVICE(ADLINK, 0x7233), BOARD_PCI7233 },
265 { PCI_VDEVICE(ADLINK, 0x7234), BOARD_PCI7234 },
266 { PCI_VDEVICE(ADLINK, 0x7432), BOARD_PCI7432 },
267 { PCI_VDEVICE(ADLINK, 0x7433), BOARD_PCI7433 },
268 { PCI_VDEVICE(ADLINK, 0x7434), BOARD_PCI7434 },
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700269 { 0 }
270};
271MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table);
272
273static struct pci_driver adl_pci7x3x_pci_driver = {
274 .name = "adl_pci7x3x",
275 .id_table = adl_pci7x3x_pci_table,
276 .probe = adl_pci7x3x_pci_probe,
Peter Huewe9901a4d2013-01-22 23:40:03 +0100277 .remove = comedi_pci_auto_unconfig,
H Hartley Sweeten8f567c32012-08-03 10:28:18 -0700278};
279module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver);
280
281MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards");
282MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
283MODULE_LICENSE("GPL");