2 comedi/drivers/ni_670x.c
3 Hardware driver for NI 670x devices
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1997-2001 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.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 Description: National Instruments 670x
26 Author: Bart Joris <bjoris@advalvas.be>
27 Updated: Wed, 11 Dec 2002 18:25:35 -0800
28 Devices: [National Instruments] PCI-6703 (ni_670x), PCI-6704
31 Commands are not supported.
35 Bart Joris <bjoris@advalvas.be> Last updated on 20/08/2001
39 322110a.pdf PCI/PXI-6704 User Manual
40 322110b.pdf PCI/PXI-6703/6704 User Manual
44 #include <linux/pci.h>
45 #include <linux/interrupt.h>
46 #include <linux/slab.h>
48 #include "../comedidev.h"
52 #define AO_VALUE_OFFSET 0x00
53 #define AO_CHAN_OFFSET 0x0c
54 #define AO_STATUS_OFFSET 0x10
55 #define AO_CONTROL_OFFSET 0x10
56 #define DIO_PORT0_DIR_OFFSET 0x20
57 #define DIO_PORT0_DATA_OFFSET 0x24
58 #define DIO_PORT1_DIR_OFFSET 0x28
59 #define DIO_PORT1_DATA_OFFSET 0x2c
60 #define MISC_STATUS_OFFSET 0x14
61 #define MISC_CONTROL_OFFSET 0x14
63 enum ni_670x_boardid
{
69 struct ni_670x_board
{
71 unsigned short ao_chans
;
74 static const struct ni_670x_board ni_670x_boards
[] = {
89 struct ni_670x_private
{
91 struct mite_struct
*mite
;
94 unsigned int ao_readback
[32];
97 static int ni_670x_ao_winsn(struct comedi_device
*dev
,
98 struct comedi_subdevice
*s
,
99 struct comedi_insn
*insn
, unsigned int *data
)
101 struct ni_670x_private
*devpriv
= dev
->private;
103 int chan
= CR_CHAN(insn
->chanspec
);
105 /* Channel number mapping :
107 NI 6703/ NI 6704 | NI 6704 Only
108 ----------------------------------------------------
109 vch(0) : 0 | ich(16) : 1
110 vch(1) : 2 | ich(17) : 3
114 vch(15) : 30 | ich(31) : 31 */
116 for (i
= 0; i
< insn
->n
; i
++) {
117 /* First write in channel register which channel to use */
118 writel(((chan
& 15) << 1) | ((chan
& 16) >> 4),
119 devpriv
->mite
->daq_io_addr
+ AO_CHAN_OFFSET
);
120 /* write channel value */
121 writel(data
[i
], devpriv
->mite
->daq_io_addr
+ AO_VALUE_OFFSET
);
122 devpriv
->ao_readback
[chan
] = data
[i
];
128 static int ni_670x_ao_rinsn(struct comedi_device
*dev
,
129 struct comedi_subdevice
*s
,
130 struct comedi_insn
*insn
, unsigned int *data
)
132 struct ni_670x_private
*devpriv
= dev
->private;
134 int chan
= CR_CHAN(insn
->chanspec
);
136 for (i
= 0; i
< insn
->n
; i
++)
137 data
[i
] = devpriv
->ao_readback
[chan
];
142 static int ni_670x_dio_insn_bits(struct comedi_device
*dev
,
143 struct comedi_subdevice
*s
,
144 struct comedi_insn
*insn
, unsigned int *data
)
146 struct ni_670x_private
*devpriv
= dev
->private;
147 void __iomem
*io_addr
= devpriv
->mite
->daq_io_addr
+
148 DIO_PORT0_DATA_OFFSET
;
149 unsigned int mask
= data
[0];
150 unsigned int bits
= data
[1];
154 s
->state
|= (bits
& mask
);
156 writel(s
->state
, io_addr
);
159 data
[1] = readl(io_addr
);
164 static int ni_670x_dio_insn_config(struct comedi_device
*dev
,
165 struct comedi_subdevice
*s
,
166 struct comedi_insn
*insn
, unsigned int *data
)
168 struct ni_670x_private
*devpriv
= dev
->private;
169 int chan
= CR_CHAN(insn
->chanspec
);
172 case INSN_CONFIG_DIO_OUTPUT
:
173 s
->io_bits
|= 1 << chan
;
175 case INSN_CONFIG_DIO_INPUT
:
176 s
->io_bits
&= ~(1 << chan
);
178 case INSN_CONFIG_DIO_QUERY
:
180 (s
->io_bits
& (1 << chan
)) ? COMEDI_OUTPUT
: COMEDI_INPUT
;
187 writel(s
->io_bits
, devpriv
->mite
->daq_io_addr
+ DIO_PORT0_DIR_OFFSET
);
192 static int ni_670x_auto_attach(struct comedi_device
*dev
,
193 unsigned long context
)
195 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
196 const struct ni_670x_board
*thisboard
= NULL
;
197 struct ni_670x_private
*devpriv
;
198 struct comedi_subdevice
*s
;
202 if (context
< ARRAY_SIZE(ni_670x_boards
))
203 thisboard
= &ni_670x_boards
[context
];
206 dev
->board_ptr
= thisboard
;
207 dev
->board_name
= thisboard
->name
;
209 ret
= comedi_pci_enable(dev
);
213 devpriv
= kzalloc(sizeof(*devpriv
), GFP_KERNEL
);
216 dev
->private = devpriv
;
218 devpriv
->mite
= mite_alloc(pcidev
);
222 ret
= mite_setup(devpriv
->mite
);
224 dev_warn(dev
->class_dev
, "error setting up mite\n");
228 ret
= comedi_alloc_subdevices(dev
, 2);
232 s
= &dev
->subdevices
[0];
233 /* analog output subdevice */
234 s
->type
= COMEDI_SUBD_AO
;
235 s
->subdev_flags
= SDF_WRITABLE
;
236 s
->n_chan
= thisboard
->ao_chans
;
238 if (s
->n_chan
== 32) {
239 const struct comedi_lrange
**range_table_list
;
241 range_table_list
= kmalloc(sizeof(struct comedi_lrange
*) * 32,
243 if (!range_table_list
)
245 s
->range_table_list
= range_table_list
;
246 for (i
= 0; i
< 16; i
++) {
247 range_table_list
[i
] = &range_bipolar10
;
248 range_table_list
[16 + i
] = &range_0_20mA
;
251 s
->range_table
= &range_bipolar10
;
253 s
->insn_write
= &ni_670x_ao_winsn
;
254 s
->insn_read
= &ni_670x_ao_rinsn
;
256 s
= &dev
->subdevices
[1];
257 /* digital i/o subdevice */
258 s
->type
= COMEDI_SUBD_DIO
;
259 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
262 s
->range_table
= &range_digital
;
263 s
->insn_bits
= ni_670x_dio_insn_bits
;
264 s
->insn_config
= ni_670x_dio_insn_config
;
266 /* Config of misc registers */
267 writel(0x10, devpriv
->mite
->daq_io_addr
+ MISC_CONTROL_OFFSET
);
268 /* Config of ao registers */
269 writel(0x00, devpriv
->mite
->daq_io_addr
+ AO_CONTROL_OFFSET
);
271 dev_info(dev
->class_dev
, "%s: %s attached\n",
272 dev
->driver
->driver_name
, dev
->board_name
);
277 static void ni_670x_detach(struct comedi_device
*dev
)
279 struct ni_670x_private
*devpriv
= dev
->private;
280 struct comedi_subdevice
*s
;
282 if (dev
->n_subdevices
) {
283 s
= &dev
->subdevices
[0];
285 kfree(s
->range_table_list
);
287 if (devpriv
&& devpriv
->mite
) {
288 mite_unsetup(devpriv
->mite
);
289 mite_free(devpriv
->mite
);
291 comedi_pci_disable(dev
);
294 static struct comedi_driver ni_670x_driver
= {
295 .driver_name
= "ni_670x",
296 .module
= THIS_MODULE
,
297 .auto_attach
= ni_670x_auto_attach
,
298 .detach
= ni_670x_detach
,
301 static int ni_670x_pci_probe(struct pci_dev
*dev
,
302 const struct pci_device_id
*id
)
304 return comedi_pci_auto_config(dev
, &ni_670x_driver
, id
->driver_data
);
307 static DEFINE_PCI_DEVICE_TABLE(ni_670x_pci_table
) = {
308 { PCI_VDEVICE(NI
, 0x1290), BOARD_PCI6704
},
309 { PCI_VDEVICE(NI
, 0x1920), BOARD_PXI6704
},
310 { PCI_VDEVICE(NI
, 0x2c90), BOARD_PCI6703
},
313 MODULE_DEVICE_TABLE(pci
, ni_670x_pci_table
);
315 static struct pci_driver ni_670x_pci_driver
= {
317 .id_table
= ni_670x_pci_table
,
318 .probe
= ni_670x_pci_probe
,
319 .remove
= comedi_pci_auto_unconfig
,
321 module_comedi_pci_driver(ni_670x_driver
, ni_670x_pci_driver
);
323 MODULE_AUTHOR("Comedi http://www.comedi.org");
324 MODULE_DESCRIPTION("Comedi low-level driver");
325 MODULE_LICENSE("GPL");