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 PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
12 * PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752,
13 * PCI-1753/E, PCI-1754, PCI-1756, PCI-1762
14 * Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
15 * PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
16 * PCI-1751, PCI-1752, PCI-1753,
17 * PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
19 * Author: Michal Dobes <dobes@tesnet.cz>
20 * Updated: Mon, 09 Jan 2012 12:40:46 +0000
23 * Configuration Options: not applicable, uses PCI auto config
26 #include <linux/module.h>
27 #include <linux/delay.h>
29 #include "../comedi_pci.h"
32 #include "comedi_8254.h"
34 /* hardware types of the cards */
36 TYPE_PCI1730
, TYPE_PCI1733
, TYPE_PCI1734
, TYPE_PCI1735
, TYPE_PCI1736
,
41 TYPE_PCI1753
, TYPE_PCI1753E
,
42 TYPE_PCI1754
, TYPE_PCI1756
,
46 #define MAX_DI_SUBDEVS 2 /* max number of DI subdevices per card */
47 #define MAX_DO_SUBDEVS 2 /* max number of DO subdevices per card */
48 #define MAX_DIO_SUBDEVG 2 /* max number of DIO subdevices group per
52 * Register offset definitions
55 /* PCI-1730, PCI-1733, PCI-1736 interrupt control registers */
56 #define PCI173X_INT_EN_REG 0x08 /* R/W: enable/disable */
57 #define PCI173X_INT_RF_REG 0x0c /* R/W: falling/rising edge */
58 #define PCI173X_INT_CLR_REG 0x10 /* R/W: clear */
60 /* PCI-1739U, PCI-1750, PCI1751 interrupt control registers */
61 #define PCI1750_INT_REG 0x20 /* R/W: status/control */
63 /* PCI-1753, PCI-1753E interrupt control registers */
64 #define PCI1753_INT_REG(x) (0x10 + (x)) /* R/W: control group 0 to 3 */
65 #define PCI1753E_INT_REG(x) (0x30 + (x)) /* R/W: control group 0 to 3 */
67 /* PCI-1754, PCI-1756 interrupt control registers */
68 #define PCI1754_INT_REG(x) (0x08 + (x) * 2) /* R/W: control group 0 to 3 */
70 /* PCI-1752, PCI-1756 special registers */
71 #define PCI1752_CFC_REG 0x12 /* R/W: channel freeze function */
73 /* Advantech PCI-1762 registers */
74 #define PCI1762_ICR 6 /* W: Interrupt control register */
75 #define PCI1762_ISR 6 /* R: Interrupt status register */
78 int chans
; /* num of chans or 8255 devices */
79 unsigned long addr
; /* PCI address ofset */
82 struct dio_boardtype
{
83 const char *name
; /* board name */
84 enum hw_cards_id cardtype
;
86 struct diosubd_data sdi
[MAX_DI_SUBDEVS
]; /* DI chans */
87 struct diosubd_data sdo
[MAX_DO_SUBDEVS
]; /* DO chans */
88 struct diosubd_data sdio
[MAX_DIO_SUBDEVG
]; /* DIO 8255 chans */
90 unsigned long timer_regbase
;
91 unsigned int is_16bit
:1;
94 static const struct dio_boardtype boardtypes
[] = {
97 .cardtype
= TYPE_PCI1730
,
99 .sdi
[0] = { 16, 0x02, }, /* DI 0-15 */
100 .sdi
[1] = { 16, 0x00, }, /* ISO DI 0-15 */
101 .sdo
[0] = { 16, 0x02, }, /* DO 0-15 */
102 .sdo
[1] = { 16, 0x00, }, /* ISO DO 0-15 */
107 .cardtype
= TYPE_PCI1733
,
109 .sdi
[1] = { 32, 0x00, }, /* ISO DI 0-31 */
114 .cardtype
= TYPE_PCI1734
,
116 .sdo
[1] = { 32, 0x00, }, /* ISO DO 0-31 */
121 .cardtype
= TYPE_PCI1735
,
123 .sdi
[0] = { 32, 0x00, }, /* DI 0-31 */
124 .sdo
[0] = { 32, 0x00, }, /* DO 0-31 */
126 .timer_regbase
= 0x04,
130 .cardtype
= TYPE_PCI1736
,
132 .sdi
[1] = { 16, 0x00, }, /* ISO DI 0-15 */
133 .sdo
[1] = { 16, 0x00, }, /* ISO DO 0-15 */
138 .cardtype
= TYPE_PCI1739
,
140 .sdio
[0] = { 2, 0x00, }, /* 8255 DIO */
145 .cardtype
= TYPE_PCI1750
,
147 .sdi
[1] = { 16, 0x00, }, /* ISO DI 0-15 */
148 .sdo
[1] = { 16, 0x00, }, /* ISO DO 0-15 */
152 .cardtype
= TYPE_PCI1751
,
154 .sdio
[0] = { 2, 0x00, }, /* 8255 DIO */
155 .timer_regbase
= 0x18,
159 .cardtype
= TYPE_PCI1752
,
161 .sdo
[0] = { 32, 0x00, }, /* DO 0-31 */
162 .sdo
[1] = { 32, 0x04, }, /* DO 32-63 */
168 .cardtype
= TYPE_PCI1753
,
170 .sdio
[0] = { 4, 0x00, }, /* 8255 DIO */
174 .cardtype
= TYPE_PCI1753E
,
176 .sdio
[0] = { 4, 0x00, }, /* 8255 DIO */
177 .sdio
[1] = { 4, 0x20, }, /* 8255 DIO */
181 .cardtype
= TYPE_PCI1754
,
183 .sdi
[0] = { 32, 0x00, }, /* DI 0-31 */
184 .sdi
[1] = { 32, 0x04, }, /* DI 32-63 */
190 .cardtype
= TYPE_PCI1756
,
192 .sdi
[1] = { 32, 0x00, }, /* DI 0-31 */
193 .sdo
[1] = { 32, 0x04, }, /* DO 0-31 */
199 .cardtype
= TYPE_PCI1762
,
201 .sdi
[1] = { 16, 0x02, }, /* ISO DI 0-15 */
202 .sdo
[1] = { 16, 0x00, }, /* ISO DO 0-15 */
208 static int pci_dio_insn_bits_di_b(struct comedi_device
*dev
,
209 struct comedi_subdevice
*s
,
210 struct comedi_insn
*insn
,
213 unsigned long reg
= (unsigned long)s
->private;
214 unsigned long iobase
= dev
->iobase
+ reg
;
216 data
[1] = inb(iobase
);
218 data
[1] |= (inb(iobase
+ 1) << 8);
220 data
[1] |= (inb(iobase
+ 2) << 16);
222 data
[1] |= (inb(iobase
+ 3) << 24);
227 static int pci_dio_insn_bits_di_w(struct comedi_device
*dev
,
228 struct comedi_subdevice
*s
,
229 struct comedi_insn
*insn
,
232 unsigned long reg
= (unsigned long)s
->private;
233 unsigned long iobase
= dev
->iobase
+ reg
;
235 data
[1] = inw(iobase
);
237 data
[1] |= (inw(iobase
+ 2) << 16);
242 static int pci_dio_insn_bits_do_b(struct comedi_device
*dev
,
243 struct comedi_subdevice
*s
,
244 struct comedi_insn
*insn
,
247 unsigned long reg
= (unsigned long)s
->private;
248 unsigned long iobase
= dev
->iobase
+ reg
;
250 if (comedi_dio_update_state(s
, data
)) {
251 outb(s
->state
& 0xff, iobase
);
253 outb((s
->state
>> 8) & 0xff, iobase
+ 1);
255 outb((s
->state
>> 16) & 0xff, iobase
+ 2);
257 outb((s
->state
>> 24) & 0xff, iobase
+ 3);
265 static int pci_dio_insn_bits_do_w(struct comedi_device
*dev
,
266 struct comedi_subdevice
*s
,
267 struct comedi_insn
*insn
,
270 unsigned long reg
= (unsigned long)s
->private;
271 unsigned long iobase
= dev
->iobase
+ reg
;
273 if (comedi_dio_update_state(s
, data
)) {
274 outw(s
->state
& 0xffff, iobase
);
276 outw((s
->state
>> 16) & 0xffff, iobase
+ 2);
284 static int pci_dio_reset(struct comedi_device
*dev
)
286 const struct dio_boardtype
*board
= dev
->board_ptr
;
288 /* disable channel freeze function on the PCI-1752/1756 boards */
289 if (board
->cardtype
== TYPE_PCI1752
|| board
->cardtype
== TYPE_PCI1756
)
290 outw(0, dev
->iobase
+ PCI1752_CFC_REG
);
292 /* disable and clear interrupts */
293 switch (board
->cardtype
) {
297 outb(0, dev
->iobase
+ PCI173X_INT_EN_REG
);
298 outb(0x0f, dev
->iobase
+ PCI173X_INT_CLR_REG
);
299 outb(0, dev
->iobase
+ PCI173X_INT_RF_REG
);
304 outb(0x88, dev
->iobase
+ PCI1750_INT_REG
);
308 outb(0x88, dev
->iobase
+ PCI1753_INT_REG(0));
309 outb(0x80, dev
->iobase
+ PCI1753_INT_REG(1));
310 outb(0x80, dev
->iobase
+ PCI1753_INT_REG(2));
311 outb(0x80, dev
->iobase
+ PCI1753_INT_REG(3));
312 if (board
->cardtype
== TYPE_PCI1753E
) {
313 outb(0x88, dev
->iobase
+ PCI1753E_INT_REG(0));
314 outb(0x80, dev
->iobase
+ PCI1753E_INT_REG(1));
315 outb(0x80, dev
->iobase
+ PCI1753E_INT_REG(2));
316 outb(0x80, dev
->iobase
+ PCI1753E_INT_REG(3));
321 outw(0x08, dev
->iobase
+ PCI1754_INT_REG(0));
322 outw(0x08, dev
->iobase
+ PCI1754_INT_REG(1));
323 if (board
->cardtype
== TYPE_PCI1754
) {
324 outw(0x08, dev
->iobase
+ PCI1754_INT_REG(2));
325 outw(0x08, dev
->iobase
+ PCI1754_INT_REG(3));
329 outw(0x0101, dev
->iobase
+ PCI1762_ICR
);
338 static unsigned long pci_dio_override_cardtype(struct pci_dev
*pcidev
,
339 unsigned long cardtype
)
342 * Change cardtype from TYPE_PCI1753 to TYPE_PCI1753E if expansion
343 * board available. Need to enable PCI device and request the main
344 * registers PCI BAR temporarily to perform the test.
346 if (cardtype
!= TYPE_PCI1753
)
348 if (pci_enable_device(pcidev
) < 0)
350 if (pci_request_region(pcidev
, 2, "adv_pci_dio") == 0) {
352 * This test is based on Advantech's "advdaq" driver source
353 * (which declares its module licence as "GPL" although the
354 * driver source does not include a "COPYING" file).
356 unsigned long reg
= pci_resource_start(pcidev
, 2) + 53;
359 if ((inb(reg
) & 0x07) == 0x02) {
361 if ((inb(reg
) & 0x07) == 0x05)
362 cardtype
= TYPE_PCI1753E
;
364 pci_release_region(pcidev
, 2);
366 pci_disable_device(pcidev
);
370 static int pci_dio_auto_attach(struct comedi_device
*dev
,
371 unsigned long context
)
373 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
374 const struct dio_boardtype
*board
= NULL
;
375 const struct diosubd_data
*d
;
376 struct comedi_subdevice
*s
;
377 int ret
, subdev
, i
, j
;
379 if (context
< ARRAY_SIZE(boardtypes
))
380 board
= &boardtypes
[context
];
383 dev
->board_ptr
= board
;
384 dev
->board_name
= board
->name
;
386 ret
= comedi_pci_enable(dev
);
389 if (board
->cardtype
== TYPE_PCI1736
)
390 dev
->iobase
= pci_resource_start(pcidev
, 0);
392 dev
->iobase
= pci_resource_start(pcidev
, 2);
396 ret
= comedi_alloc_subdevices(dev
, board
->nsubdevs
);
401 for (i
= 0; i
< MAX_DI_SUBDEVS
; i
++) {
404 s
= &dev
->subdevices
[subdev
++];
405 s
->type
= COMEDI_SUBD_DI
;
406 s
->subdev_flags
= SDF_READABLE
;
407 s
->n_chan
= d
->chans
;
409 s
->range_table
= &range_digital
;
410 s
->insn_bits
= board
->is_16bit
411 ? pci_dio_insn_bits_di_w
412 : pci_dio_insn_bits_di_b
;
413 s
->private = (void *)d
->addr
;
417 for (i
= 0; i
< MAX_DO_SUBDEVS
; i
++) {
420 s
= &dev
->subdevices
[subdev
++];
421 s
->type
= COMEDI_SUBD_DO
;
422 s
->subdev_flags
= SDF_WRITABLE
;
423 s
->n_chan
= d
->chans
;
425 s
->range_table
= &range_digital
;
426 s
->insn_bits
= board
->is_16bit
427 ? pci_dio_insn_bits_do_w
428 : pci_dio_insn_bits_do_b
;
429 s
->private = (void *)d
->addr
;
431 /* reset all outputs to 0 */
432 if (board
->is_16bit
) {
433 outw(0, dev
->iobase
+ d
->addr
);
435 outw(0, dev
->iobase
+ d
->addr
+ 2);
437 outb(0, dev
->iobase
+ d
->addr
);
439 outb(0, dev
->iobase
+ d
->addr
+ 1);
441 outb(0, dev
->iobase
+ d
->addr
+ 2);
443 outb(0, dev
->iobase
+ d
->addr
+ 3);
448 for (i
= 0; i
< MAX_DIO_SUBDEVG
; i
++) {
450 for (j
= 0; j
< d
->chans
; j
++) {
451 s
= &dev
->subdevices
[subdev
++];
452 ret
= subdev_8255_init(dev
, s
, NULL
,
453 d
->addr
+ j
* I8255_SIZE
);
460 s
= &dev
->subdevices
[subdev
++];
461 s
->type
= COMEDI_SUBD_DI
;
462 s
->subdev_flags
= SDF_READABLE
| SDF_INTERNAL
;
465 s
->range_table
= &range_digital
;
466 s
->insn_bits
= board
->is_16bit
? pci_dio_insn_bits_di_w
467 : pci_dio_insn_bits_di_b
;
468 s
->private = (void *)board
->id_reg
;
471 if (board
->timer_regbase
) {
472 s
= &dev
->subdevices
[subdev
++];
474 dev
->pacer
= comedi_8254_init(dev
->iobase
+
475 board
->timer_regbase
,
480 comedi_8254_subdevice_init(s
, dev
->pacer
);
486 static struct comedi_driver adv_pci_dio_driver
= {
487 .driver_name
= "adv_pci_dio",
488 .module
= THIS_MODULE
,
489 .auto_attach
= pci_dio_auto_attach
,
490 .detach
= comedi_pci_detach
,
493 static int adv_pci_dio_pci_probe(struct pci_dev
*dev
,
494 const struct pci_device_id
*id
)
496 unsigned long cardtype
;
498 cardtype
= pci_dio_override_cardtype(dev
, id
->driver_data
);
499 return comedi_pci_auto_config(dev
, &adv_pci_dio_driver
, cardtype
);
502 static const struct pci_device_id adv_pci_dio_pci_table
[] = {
503 { PCI_VDEVICE(ADVANTECH
, 0x1730), TYPE_PCI1730
},
504 { PCI_VDEVICE(ADVANTECH
, 0x1733), TYPE_PCI1733
},
505 { PCI_VDEVICE(ADVANTECH
, 0x1734), TYPE_PCI1734
},
506 { PCI_VDEVICE(ADVANTECH
, 0x1735), TYPE_PCI1735
},
507 { PCI_VDEVICE(ADVANTECH
, 0x1736), TYPE_PCI1736
},
508 { PCI_VDEVICE(ADVANTECH
, 0x1739), TYPE_PCI1739
},
509 { PCI_VDEVICE(ADVANTECH
, 0x1750), TYPE_PCI1750
},
510 { PCI_VDEVICE(ADVANTECH
, 0x1751), TYPE_PCI1751
},
511 { PCI_VDEVICE(ADVANTECH
, 0x1752), TYPE_PCI1752
},
512 { PCI_VDEVICE(ADVANTECH
, 0x1753), TYPE_PCI1753
},
513 { PCI_VDEVICE(ADVANTECH
, 0x1754), TYPE_PCI1754
},
514 { PCI_VDEVICE(ADVANTECH
, 0x1756), TYPE_PCI1756
},
515 { PCI_VDEVICE(ADVANTECH
, 0x1762), TYPE_PCI1762
},
518 MODULE_DEVICE_TABLE(pci
, adv_pci_dio_pci_table
);
520 static struct pci_driver adv_pci_dio_pci_driver
= {
521 .name
= "adv_pci_dio",
522 .id_table
= adv_pci_dio_pci_table
,
523 .probe
= adv_pci_dio_pci_probe
,
524 .remove
= comedi_pci_auto_unconfig
,
526 module_comedi_pci_driver(adv_pci_dio_driver
, adv_pci_dio_pci_driver
);
528 MODULE_AUTHOR("Comedi http://www.comedi.org");
529 MODULE_DESCRIPTION("Comedi low-level driver");
530 MODULE_LICENSE("GPL");