2 * comedi/drivers/adv_pci_dio.c
4 * Author: Michal Dobes <dobes@tesnet.cz>
6 * Hardware driver for Advantech PCI DIO cards.
11 * Description: Advantech Digital I/O Cards
12 * Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
13 * PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
14 * PCI-1751, PCI-1752, PCI-1753, PCI-1753+PCI-1753E,
15 * PCI-1754, PCI-1756, PCI-1762
16 * Author: Michal Dobes <dobes@tesnet.cz>
17 * Updated: Mon, 09 Jan 2012 12:40:46 +0000
20 * Configuration Options: not applicable, uses PCI auto config
23 #include <linux/module.h>
24 #include <linux/delay.h>
26 #include "../comedi_pci.h"
29 #include "comedi_8254.h"
32 * Register offset definitions
35 /* PCI-1730, PCI-1733, PCI-1736 interrupt control registers */
36 #define PCI173X_INT_EN_REG 0x08 /* R/W: enable/disable */
37 #define PCI173X_INT_RF_REG 0x0c /* R/W: falling/rising edge */
38 #define PCI173X_INT_CLR_REG 0x10 /* R/W: clear */
40 /* PCI-1739U, PCI-1750, PCI1751 interrupt control registers */
41 #define PCI1750_INT_REG 0x20 /* R/W: status/control */
43 /* PCI-1753, PCI-1753E interrupt control registers */
44 #define PCI1753_INT_REG(x) (0x10 + (x)) /* R/W: control group 0 to 3 */
45 #define PCI1753E_INT_REG(x) (0x30 + (x)) /* R/W: control group 0 to 3 */
47 /* PCI-1754, PCI-1756 interrupt control registers */
48 #define PCI1754_INT_REG(x) (0x08 + (x) * 2) /* R/W: control group 0 to 3 */
50 /* PCI-1752, PCI-1756 special registers */
51 #define PCI1752_CFC_REG 0x12 /* R/W: channel freeze function */
53 /* PCI-1762 interrupt control registers */
54 #define PCI1762_INT_REG 0x06 /* R/W: status/control */
56 /* maximum number of subdevice descriptions in the boardinfo */
57 #define PCI_DIO_MAX_DI_SUBDEVS 2 /* 2 x 8/16/32 input channels max */
58 #define PCI_DIO_MAX_DO_SUBDEVS 2 /* 2 x 8/16/32 output channels max */
59 #define PCI_DIO_MAX_DIO_SUBDEVG 2 /* 2 x any number of 8255 devices max */
61 enum pci_dio_boardid {
79 int chans; /* num of chans or 8255 devices */
80 unsigned long addr; /* PCI address ofset */
83 struct dio_boardtype {
84 const char *name; /* board name */
86 struct diosubd_data sdi[PCI_DIO_MAX_DI_SUBDEVS];
87 struct diosubd_data sdo[PCI_DIO_MAX_DO_SUBDEVS];
88 struct diosubd_data sdio[PCI_DIO_MAX_DIO_SUBDEVG];
90 unsigned long timer_regbase;
91 unsigned int is_16bit:1;
94 static const struct dio_boardtype boardtypes[] = {
98 .sdi[0] = { 16, 0x02, }, /* DI 0-15 */
99 .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */
100 .sdo[0] = { 16, 0x02, }, /* DO 0-15 */
101 .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
107 .sdi[1] = { 32, 0x00, }, /* ISO DI 0-31 */
113 .sdo[1] = { 32, 0x00, }, /* ISO DO 0-31 */
119 .sdi[0] = { 32, 0x00, }, /* DI 0-31 */
120 .sdo[0] = { 32, 0x00, }, /* DO 0-31 */
122 .timer_regbase = 0x04,
127 .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */
128 .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
134 .sdio[0] = { 2, 0x00, }, /* 8255 DIO */
140 .sdi[1] = { 16, 0x00, }, /* ISO DI 0-15 */
141 .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
146 .sdio[0] = { 2, 0x00, }, /* 8255 DIO */
147 .timer_regbase = 0x18,
152 .sdo[0] = { 32, 0x00, }, /* DO 0-31 */
153 .sdo[1] = { 32, 0x04, }, /* DO 32-63 */
160 .sdio[0] = { 4, 0x00, }, /* 8255 DIO */
165 .sdio[0] = { 4, 0x00, }, /* 8255 DIO */
166 .sdio[1] = { 4, 0x20, }, /* 8255 DIO */
171 .sdi[0] = { 32, 0x00, }, /* DI 0-31 */
172 .sdi[1] = { 32, 0x04, }, /* DI 32-63 */
179 .sdi[1] = { 32, 0x00, }, /* DI 0-31 */
180 .sdo[1] = { 32, 0x04, }, /* DO 0-31 */
187 .sdi[1] = { 16, 0x02, }, /* ISO DI 0-15 */
188 .sdo[1] = { 16, 0x00, }, /* ISO DO 0-15 */
194 static int pci_dio_insn_bits_di_b(struct comedi_device *dev,
195 struct comedi_subdevice *s,
196 struct comedi_insn *insn,
199 unsigned long reg = (unsigned long)s->private;
200 unsigned long iobase = dev->iobase + reg;
202 data[1] = inb(iobase);
204 data[1] |= (inb(iobase + 1) << 8);
206 data[1] |= (inb(iobase + 2) << 16);
208 data[1] |= (inb(iobase + 3) << 24);
213 static int pci_dio_insn_bits_di_w(struct comedi_device *dev,
214 struct comedi_subdevice *s,
215 struct comedi_insn *insn,
218 unsigned long reg = (unsigned long)s->private;
219 unsigned long iobase = dev->iobase + reg;
221 data[1] = inw(iobase);
223 data[1] |= (inw(iobase + 2) << 16);
228 static int pci_dio_insn_bits_do_b(struct comedi_device *dev,
229 struct comedi_subdevice *s,
230 struct comedi_insn *insn,
233 unsigned long reg = (unsigned long)s->private;
234 unsigned long iobase = dev->iobase + reg;
236 if (comedi_dio_update_state(s, data)) {
237 outb(s->state & 0xff, iobase);
239 outb((s->state >> 8) & 0xff, iobase + 1);
241 outb((s->state >> 16) & 0xff, iobase + 2);
243 outb((s->state >> 24) & 0xff, iobase + 3);
251 static int pci_dio_insn_bits_do_w(struct comedi_device *dev,
252 struct comedi_subdevice *s,
253 struct comedi_insn *insn,
256 unsigned long reg = (unsigned long)s->private;
257 unsigned long iobase = dev->iobase + reg;
259 if (comedi_dio_update_state(s, data)) {
260 outw(s->state & 0xffff, iobase);
262 outw((s->state >> 16) & 0xffff, iobase + 2);
270 static int pci_dio_reset(struct comedi_device *dev, unsigned long cardtype)
272 /* disable channel freeze function on the PCI-1752/1756 boards */
273 if (cardtype == TYPE_PCI1752 || cardtype == TYPE_PCI1756)
274 outw(0, dev->iobase + PCI1752_CFC_REG);
276 /* disable and clear interrupts */
281 outb(0, dev->iobase + PCI173X_INT_EN_REG);
282 outb(0x0f, dev->iobase + PCI173X_INT_CLR_REG);
283 outb(0, dev->iobase + PCI173X_INT_RF_REG);
288 outb(0x88, dev->iobase + PCI1750_INT_REG);
292 outb(0x88, dev->iobase + PCI1753_INT_REG(0));
293 outb(0x80, dev->iobase + PCI1753_INT_REG(1));
294 outb(0x80, dev->iobase + PCI1753_INT_REG(2));
295 outb(0x80, dev->iobase + PCI1753_INT_REG(3));
296 if (cardtype == TYPE_PCI1753E) {
297 outb(0x88, dev->iobase + PCI1753E_INT_REG(0));
298 outb(0x80, dev->iobase + PCI1753E_INT_REG(1));
299 outb(0x80, dev->iobase + PCI1753E_INT_REG(2));
300 outb(0x80, dev->iobase + PCI1753E_INT_REG(3));
305 outw(0x08, dev->iobase + PCI1754_INT_REG(0));
306 outw(0x08, dev->iobase + PCI1754_INT_REG(1));
307 if (cardtype == TYPE_PCI1754) {
308 outw(0x08, dev->iobase + PCI1754_INT_REG(2));
309 outw(0x08, dev->iobase + PCI1754_INT_REG(3));
313 outw(0x0101, dev->iobase + PCI1762_INT_REG);
322 static int pci_dio_auto_attach(struct comedi_device *dev,
323 unsigned long context)
325 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
326 const struct dio_boardtype *board = NULL;
327 const struct diosubd_data *d;
328 struct comedi_subdevice *s;
329 int ret, subdev, i, j;
331 if (context < ARRAY_SIZE(boardtypes))
332 board = &boardtypes[context];
335 dev->board_ptr = board;
336 dev->board_name = board->name;
338 ret = comedi_pci_enable(dev);
341 if (context == TYPE_PCI1736)
342 dev->iobase = pci_resource_start(pcidev, 0);
344 dev->iobase = pci_resource_start(pcidev, 2);
346 pci_dio_reset(dev, context);
348 ret = comedi_alloc_subdevices(dev, board->nsubdevs);
353 for (i = 0; i < PCI_DIO_MAX_DI_SUBDEVS; i++) {
356 s = &dev->subdevices[subdev++];
357 s->type = COMEDI_SUBD_DI;
358 s->subdev_flags = SDF_READABLE;
359 s->n_chan = d->chans;
361 s->range_table = &range_digital;
362 s->insn_bits = board->is_16bit
363 ? pci_dio_insn_bits_di_w
364 : pci_dio_insn_bits_di_b;
365 s->private = (void *)d->addr;
369 for (i = 0; i < PCI_DIO_MAX_DO_SUBDEVS; i++) {
372 s = &dev->subdevices[subdev++];
373 s->type = COMEDI_SUBD_DO;
374 s->subdev_flags = SDF_WRITABLE;
375 s->n_chan = d->chans;
377 s->range_table = &range_digital;
378 s->insn_bits = board->is_16bit
379 ? pci_dio_insn_bits_do_w
380 : pci_dio_insn_bits_do_b;
381 s->private = (void *)d->addr;
383 /* reset all outputs to 0 */
384 if (board->is_16bit) {
385 outw(0, dev->iobase + d->addr);
387 outw(0, dev->iobase + d->addr + 2);
389 outb(0, dev->iobase + d->addr);
391 outb(0, dev->iobase + d->addr + 1);
393 outb(0, dev->iobase + d->addr + 2);
395 outb(0, dev->iobase + d->addr + 3);
400 for (i = 0; i < PCI_DIO_MAX_DIO_SUBDEVG; i++) {
402 for (j = 0; j < d->chans; j++) {
403 s = &dev->subdevices[subdev++];
404 ret = subdev_8255_init(dev, s, NULL,
405 d->addr + j * I8255_SIZE);
412 s = &dev->subdevices[subdev++];
413 s->type = COMEDI_SUBD_DI;
414 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
417 s->range_table = &range_digital;
418 s->insn_bits = board->is_16bit ? pci_dio_insn_bits_di_w
419 : pci_dio_insn_bits_di_b;
420 s->private = (void *)board->id_reg;
423 if (board->timer_regbase) {
424 s = &dev->subdevices[subdev++];
426 dev->pacer = comedi_8254_init(dev->iobase +
427 board->timer_regbase,
432 comedi_8254_subdevice_init(s, dev->pacer);
438 static struct comedi_driver adv_pci_dio_driver = {
439 .driver_name = "adv_pci_dio",
440 .module = THIS_MODULE,
441 .auto_attach = pci_dio_auto_attach,
442 .detach = comedi_pci_detach,
445 static unsigned long pci_dio_override_cardtype(struct pci_dev *pcidev,
446 unsigned long cardtype)
449 * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion
450 * board available. Need to enable PCI device and request the main
451 * registers PCI BAR temporarily to perform the test.
453 if (cardtype != TYPE_PCI1753)
455 if (pci_enable_device(pcidev) < 0)
457 if (pci_request_region(pcidev, 2, "adv_pci_dio") == 0) {
459 * This test is based on Advantech's "advdaq" driver source
460 * (which declares its module licence as "GPL" although the
461 * driver source does not include a "COPYING" file).
463 unsigned long reg = pci_resource_start(pcidev, 2) + 53;
466 if ((inb(reg) & 0x07) == 0x02) {
468 if ((inb(reg) & 0x07) == 0x05)
469 cardtype = TYPE_PCI1753E;
471 pci_release_region(pcidev, 2);
473 pci_disable_device(pcidev);
477 static int adv_pci_dio_pci_probe(struct pci_dev *dev,
478 const struct pci_device_id *id)
480 unsigned long cardtype;
482 cardtype = pci_dio_override_cardtype(dev, id->driver_data);
483 return comedi_pci_auto_config(dev, &adv_pci_dio_driver, cardtype);
486 static const struct pci_device_id adv_pci_dio_pci_table[] = {
487 { PCI_VDEVICE(ADVANTECH, 0x1730), TYPE_PCI1730 },
488 { PCI_VDEVICE(ADVANTECH, 0x1733), TYPE_PCI1733 },
489 { PCI_VDEVICE(ADVANTECH, 0x1734), TYPE_PCI1734 },
490 { PCI_VDEVICE(ADVANTECH, 0x1735), TYPE_PCI1735 },
491 { PCI_VDEVICE(ADVANTECH, 0x1736), TYPE_PCI1736 },
492 { PCI_VDEVICE(ADVANTECH, 0x1739), TYPE_PCI1739 },
493 { PCI_VDEVICE(ADVANTECH, 0x1750), TYPE_PCI1750 },
494 { PCI_VDEVICE(ADVANTECH, 0x1751), TYPE_PCI1751 },
495 { PCI_VDEVICE(ADVANTECH, 0x1752), TYPE_PCI1752 },
496 { PCI_VDEVICE(ADVANTECH, 0x1753), TYPE_PCI1753 },
497 { PCI_VDEVICE(ADVANTECH, 0x1754), TYPE_PCI1754 },
498 { PCI_VDEVICE(ADVANTECH, 0x1756), TYPE_PCI1756 },
499 { PCI_VDEVICE(ADVANTECH, 0x1762), TYPE_PCI1762 },
502 MODULE_DEVICE_TABLE(pci, adv_pci_dio_pci_table);
504 static struct pci_driver adv_pci_dio_pci_driver = {
505 .name = "adv_pci_dio",
506 .id_table = adv_pci_dio_pci_table,
507 .probe = adv_pci_dio_pci_probe,
508 .remove = comedi_pci_auto_unconfig,
510 module_comedi_pci_driver(adv_pci_dio_driver, adv_pci_dio_pci_driver);
512 MODULE_AUTHOR("Comedi http://www.comedi.org");
513 MODULE_DESCRIPTION("Comedi driver for Advantech Digital I/O Cards");
514 MODULE_LICENSE("GPL");