2 comedi/drivers/pci1723.c
4 COMEDI - Linux Control and Measurement Device Interface
5 Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
19 Description: Advantech PCI-1723
20 Author: yonggang <rsmgnu@gmail.com>, Ian Abbott <abbotti@mev.co.uk>
21 Devices: [Advantech] PCI-1723 (adv_pci1723)
22 Updated: Mon, 14 Apr 2008 15:12:56 +0100
25 Configuration Options:
26 [0] - PCI bus of device (optional)
27 [1] - PCI slot of device (optional)
29 If bus/slot is not specified, the first supported
30 PCI device found will be used.
32 Subdevice 0 is 8-channel AO, 16-bit, range +/- 10 V.
34 Subdevice 1 is 16-channel DIO. The channels are configurable as input or
35 output in 2 groups (0 to 7, 8 to 15). Configuring any channel implicitly
36 configures all channels in the same group.
40 1. Add the two milliamp ranges to the AO subdevice (0 to 20 mA, 4 to 20 mA).
41 2. Read the initial ranges and values of the AO subdevice at start-up instead
42 of reinitializing them.
43 3. Implement calibration.
46 #include <linux/module.h>
47 #include <linux/pci.h>
49 #include "../comedidev.h"
51 /* all the registers for the pci1723 board */
52 #define PCI1723_DA(N) ((N)<<1) /* W: D/A register N (0 to 7) */
54 #define PCI1723_SYN_SET 0x12 /* synchronized set register */
55 #define PCI1723_ALL_CHNNELE_SYN_STROBE 0x12
56 /* synchronized status register */
58 #define PCI1723_RANGE_CALIBRATION_MODE 0x14
59 /* range and calibration mode */
60 #define PCI1723_RANGE_CALIBRATION_STATUS 0x14
61 /* range and calibration status */
63 #define PCI1723_CONTROL_CMD_CALIBRATION_FUN 0x16
65 * SADC control command for
66 * calibration function
68 #define PCI1723_STATUS_CMD_CALIBRATION_FUN 0x16
70 * SADC control status for
71 * calibration function
74 #define PCI1723_CALIBRATION_PARA_STROBE 0x18
75 /* Calibration parameter strobe */
77 #define PCI1723_DIGITAL_IO_PORT_SET 0x1A /* Digital I/O port setting */
78 #define PCI1723_DIGITAL_IO_PORT_MODE 0x1A /* Digital I/O port mode */
80 #define PCI1723_WRITE_DIGITAL_OUTPUT_CMD 0x1C
81 /* Write digital output command */
82 #define PCI1723_READ_DIGITAL_INPUT_DATA 0x1C /* Read digital input data */
84 #define PCI1723_WRITE_CAL_CMD 0x1E /* Write calibration command */
85 #define PCI1723_READ_CAL_STATUS 0x1E /* Read calibration status */
87 #define PCI1723_SYN_STROBE 0x20 /* Synchronized strobe */
89 #define PCI1723_RESET_ALL_CHN_STROBE 0x22
90 /* Reset all D/A channels strobe */
92 #define PCI1723_RESET_CAL_CONTROL_STROBE 0x24
94 * Reset the calibration
98 #define PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE 0x26
100 * Change D/A channels output
104 #define PCI1723_SELECT_CALIBRATION 0x28 /* Select the calibration Ref_V */
106 struct pci1723_private
{
107 unsigned char da_range
[8]; /* D/A output range for each channel */
108 unsigned short ao_data
[8]; /* data output buffer */
112 * The pci1723 card reset;
114 static int pci1723_reset(struct comedi_device
*dev
)
116 struct pci1723_private
*devpriv
= dev
->private;
119 outw(0x01, dev
->iobase
+ PCI1723_SYN_SET
);
120 /* set synchronous output mode */
122 for (i
= 0; i
< 8; i
++) {
123 /* set all outputs to 0V */
124 devpriv
->ao_data
[i
] = 0x8000;
125 outw(devpriv
->ao_data
[i
], dev
->iobase
+ PCI1723_DA(i
));
126 /* set all ranges to +/- 10V */
127 devpriv
->da_range
[i
] = 0;
128 outw(((devpriv
->da_range
[i
] << 4) | i
),
129 PCI1723_RANGE_CALIBRATION_MODE
);
132 outw(0, dev
->iobase
+ PCI1723_CHANGE_CHA_OUTPUT_TYPE_STROBE
);
134 outw(0, dev
->iobase
+ PCI1723_SYN_STROBE
); /* update outputs */
136 /* set asynchronous output mode */
137 outw(0, dev
->iobase
+ PCI1723_SYN_SET
);
142 static int pci1723_insn_read_ao(struct comedi_device
*dev
,
143 struct comedi_subdevice
*s
,
144 struct comedi_insn
*insn
, unsigned int *data
)
146 struct pci1723_private
*devpriv
= dev
->private;
149 chan
= CR_CHAN(insn
->chanspec
);
150 for (n
= 0; n
< insn
->n
; n
++)
151 data
[n
] = devpriv
->ao_data
[chan
];
159 static int pci1723_ao_write_winsn(struct comedi_device
*dev
,
160 struct comedi_subdevice
*s
,
161 struct comedi_insn
*insn
, unsigned int *data
)
163 struct pci1723_private
*devpriv
= dev
->private;
164 unsigned int chan
= CR_CHAN(insn
->chanspec
);
167 for (n
= 0; n
< insn
->n
; n
++) {
168 devpriv
->ao_data
[chan
] = data
[n
];
169 outw(data
[n
], dev
->iobase
+ PCI1723_DA(chan
));
176 digital i/o config/query
178 static int pci1723_dio_insn_config(struct comedi_device
*dev
,
179 struct comedi_subdevice
*s
,
180 struct comedi_insn
*insn
, unsigned int *data
)
182 unsigned int chan
= CR_CHAN(insn
->chanspec
);
192 ret
= comedi_dio_insn_config(dev
, s
, insn
, data
, mask
);
196 /* update hardware DIO mode */
197 mode
= 0x0000; /* assume output */
198 if (!(s
->io_bits
& 0x00ff))
199 mode
|= 0x0001; /* low byte input */
200 if (!(s
->io_bits
& 0xff00))
201 mode
|= 0x0002; /* high byte input */
202 outw(mode
, dev
->iobase
+ PCI1723_DIGITAL_IO_PORT_SET
);
207 static int pci1723_dio_insn_bits(struct comedi_device
*dev
,
208 struct comedi_subdevice
*s
,
209 struct comedi_insn
*insn
,
212 if (comedi_dio_update_state(s
, data
))
213 outw(s
->state
, dev
->iobase
+ PCI1723_WRITE_DIGITAL_OUTPUT_CMD
);
215 data
[1] = inw(dev
->iobase
+ PCI1723_READ_DIGITAL_INPUT_DATA
);
220 static int pci1723_auto_attach(struct comedi_device
*dev
,
221 unsigned long context_unused
)
223 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
224 struct pci1723_private
*devpriv
;
225 struct comedi_subdevice
*s
;
228 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
232 ret
= comedi_pci_enable(dev
);
235 dev
->iobase
= pci_resource_start(pcidev
, 2);
237 ret
= comedi_alloc_subdevices(dev
, 2);
241 s
= &dev
->subdevices
[0];
242 dev
->write_subdev
= s
;
243 s
->type
= COMEDI_SUBD_AO
;
244 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
248 s
->range_table
= &range_bipolar10
;
249 s
->insn_write
= pci1723_ao_write_winsn
;
250 s
->insn_read
= pci1723_insn_read_ao
;
252 s
= &dev
->subdevices
[1];
253 s
->type
= COMEDI_SUBD_DIO
;
254 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
257 s
->len_chanlist
= 16;
258 s
->range_table
= &range_digital
;
259 s
->insn_config
= pci1723_dio_insn_config
;
260 s
->insn_bits
= pci1723_dio_insn_bits
;
262 /* read DIO config */
263 switch (inw(dev
->iobase
+ PCI1723_DIGITAL_IO_PORT_MODE
) & 0x03) {
264 case 0x00: /* low byte output, high byte output */
267 case 0x01: /* low byte input, high byte output */
270 case 0x02: /* low byte output, high byte input */
273 case 0x03: /* low byte input, high byte input */
277 /* read DIO port state */
278 s
->state
= inw(dev
->iobase
+ PCI1723_READ_DIGITAL_INPUT_DATA
);
285 static void pci1723_detach(struct comedi_device
*dev
)
289 comedi_pci_detach(dev
);
292 static struct comedi_driver adv_pci1723_driver
= {
293 .driver_name
= "adv_pci1723",
294 .module
= THIS_MODULE
,
295 .auto_attach
= pci1723_auto_attach
,
296 .detach
= pci1723_detach
,
299 static int adv_pci1723_pci_probe(struct pci_dev
*dev
,
300 const struct pci_device_id
*id
)
302 return comedi_pci_auto_config(dev
, &adv_pci1723_driver
,
306 static const struct pci_device_id adv_pci1723_pci_table
[] = {
307 { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH
, 0x1723) },
310 MODULE_DEVICE_TABLE(pci
, adv_pci1723_pci_table
);
312 static struct pci_driver adv_pci1723_pci_driver
= {
313 .name
= "adv_pci1723",
314 .id_table
= adv_pci1723_pci_table
,
315 .probe
= adv_pci1723_pci_probe
,
316 .remove
= comedi_pci_auto_unconfig
,
318 module_comedi_pci_driver(adv_pci1723_driver
, adv_pci1723_pci_driver
);
320 MODULE_AUTHOR("Comedi http://www.comedi.org");
321 MODULE_DESCRIPTION("Comedi low-level driver");
322 MODULE_LICENSE("GPL");