3 * Comedi driver for ADLink 6208 series cards
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
21 * Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards
22 * Devices: [ADLink] PCI-6208 (adl_pci6208), PCI-6216
23 * Author: nsyeow <nsyeow@pd.jaring.my>
24 * Updated: Wed, 11 Feb 2015 11:37:18 +0000
27 * Configuration Options: not applicable, uses PCI auto config
29 * All supported devices share the same PCI device ID and are treated as a
30 * PCI-6216 with 16 analog output channels. On a PCI-6208, the upper 8
31 * channels exist in registers, but don't go to DAC chips.
34 #include <linux/module.h>
35 #include <linux/delay.h>
37 #include "../comedi_pci.h"
40 * PCI-6208/6216-GL register map
42 #define PCI6208_AO_CONTROL(x) (0x00 + (2 * (x)))
43 #define PCI6208_AO_STATUS 0x00
44 #define PCI6208_AO_STATUS_DATA_SEND BIT(0)
45 #define PCI6208_DIO 0x40
46 #define PCI6208_DIO_DO_MASK (0x0f)
47 #define PCI6208_DIO_DO_SHIFT (0)
48 #define PCI6208_DIO_DI_MASK (0xf0)
49 #define PCI6208_DIO_DI_SHIFT (4)
51 static int pci6208_ao_eoc(struct comedi_device
*dev
,
52 struct comedi_subdevice
*s
,
53 struct comedi_insn
*insn
,
54 unsigned long context
)
58 status
= inw(dev
->iobase
+ PCI6208_AO_STATUS
);
59 if ((status
& PCI6208_AO_STATUS_DATA_SEND
) == 0)
64 static int pci6208_ao_insn_write(struct comedi_device
*dev
,
65 struct comedi_subdevice
*s
,
66 struct comedi_insn
*insn
,
69 unsigned int chan
= CR_CHAN(insn
->chanspec
);
70 unsigned int val
= s
->readback
[chan
];
74 for (i
= 0; i
< insn
->n
; i
++) {
77 /* D/A transfer rate is 2.2us */
78 ret
= comedi_timeout(dev
, s
, insn
, pci6208_ao_eoc
, 0);
82 /* the hardware expects two's complement values */
83 outw(comedi_offset_munge(s
, val
),
84 dev
->iobase
+ PCI6208_AO_CONTROL(chan
));
86 s
->readback
[chan
] = val
;
92 static int pci6208_di_insn_bits(struct comedi_device
*dev
,
93 struct comedi_subdevice
*s
,
94 struct comedi_insn
*insn
,
99 val
= inw(dev
->iobase
+ PCI6208_DIO
);
100 val
= (val
& PCI6208_DIO_DI_MASK
) >> PCI6208_DIO_DI_SHIFT
;
107 static int pci6208_do_insn_bits(struct comedi_device
*dev
,
108 struct comedi_subdevice
*s
,
109 struct comedi_insn
*insn
,
112 if (comedi_dio_update_state(s
, data
))
113 outw(s
->state
, dev
->iobase
+ PCI6208_DIO
);
120 static int pci6208_auto_attach(struct comedi_device
*dev
,
121 unsigned long context_unused
)
123 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
124 struct comedi_subdevice
*s
;
128 ret
= comedi_pci_enable(dev
);
131 dev
->iobase
= pci_resource_start(pcidev
, 2);
133 ret
= comedi_alloc_subdevices(dev
, 3);
137 s
= &dev
->subdevices
[0];
138 /* analog output subdevice */
139 s
->type
= COMEDI_SUBD_AO
;
140 s
->subdev_flags
= SDF_WRITABLE
;
141 s
->n_chan
= 16; /* Only 8 usable on PCI-6208 */
143 s
->range_table
= &range_bipolar10
;
144 s
->insn_write
= pci6208_ao_insn_write
;
146 ret
= comedi_alloc_subdev_readback(s
);
150 s
= &dev
->subdevices
[1];
151 /* digital input subdevice */
152 s
->type
= COMEDI_SUBD_DI
;
153 s
->subdev_flags
= SDF_READABLE
;
156 s
->range_table
= &range_digital
;
157 s
->insn_bits
= pci6208_di_insn_bits
;
159 s
= &dev
->subdevices
[2];
160 /* digital output subdevice */
161 s
->type
= COMEDI_SUBD_DO
;
162 s
->subdev_flags
= SDF_WRITABLE
;
165 s
->range_table
= &range_digital
;
166 s
->insn_bits
= pci6208_do_insn_bits
;
169 * Get the read back signals from the digital outputs
170 * and save it as the initial state for the subdevice.
172 val
= inw(dev
->iobase
+ PCI6208_DIO
);
173 val
= (val
& PCI6208_DIO_DO_MASK
) >> PCI6208_DIO_DO_SHIFT
;
179 static struct comedi_driver adl_pci6208_driver
= {
180 .driver_name
= "adl_pci6208",
181 .module
= THIS_MODULE
,
182 .auto_attach
= pci6208_auto_attach
,
183 .detach
= comedi_pci_detach
,
186 static int adl_pci6208_pci_probe(struct pci_dev
*dev
,
187 const struct pci_device_id
*id
)
189 return comedi_pci_auto_config(dev
, &adl_pci6208_driver
,
193 static const struct pci_device_id adl_pci6208_pci_table
[] = {
194 { PCI_DEVICE(PCI_VENDOR_ID_ADLINK
, 0x6208) },
195 { PCI_DEVICE_SUB(PCI_VENDOR_ID_PLX
, PCI_DEVICE_ID_PLX_9050
,
199 MODULE_DEVICE_TABLE(pci
, adl_pci6208_pci_table
);
201 static struct pci_driver adl_pci6208_pci_driver
= {
202 .name
= "adl_pci6208",
203 .id_table
= adl_pci6208_pci_table
,
204 .probe
= adl_pci6208_pci_probe
,
205 .remove
= comedi_pci_auto_unconfig
,
207 module_comedi_pci_driver(adl_pci6208_driver
, adl_pci6208_pci_driver
);
209 MODULE_AUTHOR("Comedi http://www.comedi.org");
210 MODULE_DESCRIPTION("Comedi driver for ADLink 6208 series cards");
211 MODULE_LICENSE("GPL");