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");