[go: nahoru, domu]

1/*
2 * ni_at_ao.c
3 * Driver for NI AT-AO-6/10 boards
4 *
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 2000,2002 David A. Schleef <ds@schleef.org>
7 *
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.
12 *
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.
17 */
18
19/*
20 * Driver: ni_at_ao
21 * Description: National Instruments AT-AO-6/10
22 * Devices: (National Instruments) AT-AO-6 [at-ao-6]
23 *          (National Instruments) AT-AO-10 [at-ao-10]
24 * Status: should work
25 * Author: David A. Schleef <ds@schleef.org>
26 * Updated: Sun Dec 26 12:26:28 EST 2004
27 *
28 * Configuration options:
29 *   [0] - I/O port base address
30 *   [1] - IRQ (unused)
31 *   [2] - DMA (unused)
32 *   [3] - analog output range, set by jumpers on hardware
33 *         0 for -10 to 10V bipolar
34 *         1 for 0V to 10V unipolar
35 */
36
37#include <linux/module.h>
38
39#include "../comedidev.h"
40
41#include "8253.h"
42
43/*
44 * Register map
45 *
46 * Register-level programming information can be found in NI
47 * document 320379.pdf.
48 */
49#define ATAO_DIO_REG		0x00
50#define ATAO_CFG2_REG		0x02
51#define ATAO_CFG2_CALLD_NOP	(0 << 14)
52#define ATAO_CFG2_CALLD(x)	((((x) >> 3) + 1) << 14)
53#define ATAO_CFG2_FFRTEN	(1 << 13)
54#define ATAO_CFG2_DACS(x)	(1 << (((x) / 2) + 8))
55#define ATAO_CFG2_LDAC(x)	(1 << (((x) / 2) + 3))
56#define ATAO_CFG2_PROMEN	(1 << 2)
57#define ATAO_CFG2_SCLK		(1 << 1)
58#define ATAO_CFG2_SDATA		(1 << 0)
59#define ATAO_CFG3_REG		0x04
60#define ATAO_CFG3_DMAMODE	(1 << 6)
61#define ATAO_CFG3_CLKOUT	(1 << 5)
62#define ATAO_CFG3_RCLKEN	(1 << 4)
63#define ATAO_CFG3_DOUTEN2	(1 << 3)
64#define ATAO_CFG3_DOUTEN1	(1 << 2)
65#define ATAO_CFG3_EN2_5V	(1 << 1)
66#define ATAO_CFG3_SCANEN	(1 << 0)
67#define ATAO_82C53_BASE		0x06
68#define ATAO_CFG1_REG		0x0a
69#define ATAO_CFG1_EXTINT2EN	(1 << 15)
70#define ATAO_CFG1_EXTINT1EN	(1 << 14)
71#define ATAO_CFG1_CNTINT2EN	(1 << 13)
72#define ATAO_CFG1_CNTINT1EN	(1 << 12)
73#define ATAO_CFG1_TCINTEN	(1 << 11)
74#define ATAO_CFG1_CNT1SRC	(1 << 10)
75#define ATAO_CFG1_CNT2SRC	(1 << 9)
76#define ATAO_CFG1_FIFOEN	(1 << 8)
77#define ATAO_CFG1_GRP2WR	(1 << 7)
78#define ATAO_CFG1_EXTUPDEN	(1 << 6)
79#define ATAO_CFG1_DMARQ		(1 << 5)
80#define ATAO_CFG1_DMAEN		(1 << 4)
81#define ATAO_CFG1_CH(x)		(((x) & 0xf) << 0)
82#define ATAO_STATUS_REG		0x0a
83#define ATAO_STATUS_FH		(1 << 6)
84#define ATAO_STATUS_FE		(1 << 5)
85#define ATAO_STATUS_FF		(1 << 4)
86#define ATAO_STATUS_INT2	(1 << 3)
87#define ATAO_STATUS_INT1	(1 << 2)
88#define ATAO_STATUS_TCINT	(1 << 1)
89#define ATAO_STATUS_PROMOUT	(1 << 0)
90#define ATAO_FIFO_WRITE_REG	0x0c
91#define ATAO_FIFO_CLEAR_REG	0x0c
92#define ATAO_AO_REG(x)		(0x0c + ((x) * 2))
93
94/* registers with _2_ are accessed when GRP2WR is set in CFG1 */
95#define ATAO_2_DMATCCLR_REG	0x00
96#define ATAO_2_INT1CLR_REG	0x02
97#define ATAO_2_INT2CLR_REG	0x04
98#define ATAO_2_RTSISHFT_REG	0x06
99#define ATAO_2_RTSISHFT_RSI	(1 << 0)
100#define ATAO_2_RTSISTRB_REG	0x07
101
102struct atao_board {
103	const char *name;
104	int n_ao_chans;
105};
106
107static const struct atao_board atao_boards[] = {
108	{
109		.name		= "at-ao-6",
110		.n_ao_chans	= 6,
111	}, {
112		.name		= "at-ao-10",
113		.n_ao_chans	= 10,
114	},
115};
116
117struct atao_private {
118	unsigned short cfg1;
119	unsigned short cfg3;
120
121	/* Used for caldac readback */
122	unsigned char caldac[21];
123};
124
125static void atao_select_reg_group(struct comedi_device *dev, int group)
126{
127	struct atao_private *devpriv = dev->private;
128
129	if (group)
130		devpriv->cfg1 |= ATAO_CFG1_GRP2WR;
131	else
132		devpriv->cfg1 &= ~ATAO_CFG1_GRP2WR;
133	outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG);
134}
135
136static int atao_ao_insn_write(struct comedi_device *dev,
137			      struct comedi_subdevice *s,
138			      struct comedi_insn *insn,
139			      unsigned int *data)
140{
141	unsigned int chan = CR_CHAN(insn->chanspec);
142	unsigned int val = s->readback[chan];
143	int i;
144
145	if (chan == 0)
146		atao_select_reg_group(dev, 1);
147
148	for (i = 0; i < insn->n; i++) {
149		val = data[i];
150
151		/* the hardware expects two's complement values */
152		outw(comedi_offset_munge(s, val),
153		     dev->iobase + ATAO_AO_REG(chan));
154	}
155	s->readback[chan] = val;
156
157	if (chan == 0)
158		atao_select_reg_group(dev, 0);
159
160	return insn->n;
161}
162
163static int atao_dio_insn_bits(struct comedi_device *dev,
164			      struct comedi_subdevice *s,
165			      struct comedi_insn *insn,
166			      unsigned int *data)
167{
168	if (comedi_dio_update_state(s, data))
169		outw(s->state, dev->iobase + ATAO_DIO_REG);
170
171	data[1] = inw(dev->iobase + ATAO_DIO_REG);
172
173	return insn->n;
174}
175
176static int atao_dio_insn_config(struct comedi_device *dev,
177				struct comedi_subdevice *s,
178				struct comedi_insn *insn,
179				unsigned int *data)
180{
181	struct atao_private *devpriv = dev->private;
182	unsigned int chan = CR_CHAN(insn->chanspec);
183	unsigned int mask;
184	int ret;
185
186	if (chan < 4)
187		mask = 0x0f;
188	else
189		mask = 0xf0;
190
191	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
192	if (ret)
193		return ret;
194
195	if (s->io_bits & 0x0f)
196		devpriv->cfg3 |= ATAO_CFG3_DOUTEN1;
197	else
198		devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN1;
199	if (s->io_bits & 0xf0)
200		devpriv->cfg3 |= ATAO_CFG3_DOUTEN2;
201	else
202		devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN2;
203
204	outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG);
205
206	return insn->n;
207}
208
209/*
210 * There are three DAC8800 TrimDACs on the board. These are 8-channel,
211 * 8-bit DACs that are used to calibrate the Analog Output channels.
212 * The factory default calibration values are stored in the EEPROM.
213 * The TrimDACs, and EEPROM addresses, are mapped as:
214 *
215 *        Channel       EEPROM  Description
216 *   -----------------  ------  -----------------------------------
217 *    0 - DAC0 Chan 0    0x30   AO Channel 0 Offset
218 *    1 - DAC0 Chan 1    0x31   AO Channel 0 Gain
219 *    2 - DAC0 Chan 2    0x32   AO Channel 1 Offset
220 *    3 - DAC0 Chan 3    0x33   AO Channel 1 Gain
221 *    4 - DAC0 Chan 4    0x34   AO Channel 2 Offset
222 *    5 - DAC0 Chan 5    0x35   AO Channel 2 Gain
223 *    6 - DAC0 Chan 6    0x36   AO Channel 3 Offset
224 *    7 - DAC0 Chan 7    0x37   AO Channel 3 Gain
225 *    8 - DAC1 Chan 0    0x38   AO Channel 4 Offset
226 *    9 - DAC1 Chan 1    0x39   AO Channel 4 Gain
227 *   10 - DAC1 Chan 2    0x3a   AO Channel 5 Offset
228 *   11 - DAC1 Chan 3    0x3b   AO Channel 5 Gain
229 *   12 - DAC1 Chan 4    0x3c   2.5V Offset
230 *   13 - DAC1 Chan 5    0x3d   AO Channel 6 Offset (at-ao-10 only)
231 *   14 - DAC1 Chan 6    0x3e   AO Channel 6 Gain   (at-ao-10 only)
232 *   15 - DAC1 Chan 7    0x3f   AO Channel 7 Offset (at-ao-10 only)
233 *   16 - DAC2 Chan 0    0x40   AO Channel 7 Gain   (at-ao-10 only)
234 *   17 - DAC2 Chan 1    0x41   AO Channel 8 Offset (at-ao-10 only)
235 *   18 - DAC2 Chan 2    0x42   AO Channel 8 Gain   (at-ao-10 only)
236 *   19 - DAC2 Chan 3    0x43   AO Channel 9 Offset (at-ao-10 only)
237 *   20 - DAC2 Chan 4    0x44   AO Channel 9 Gain   (at-ao-10 only)
238 *        DAC2 Chan 5    0x45   Reserved
239 *        DAC2 Chan 6    0x46   Reserved
240 *        DAC2 Chan 7    0x47   Reserved
241 */
242static int atao_calib_insn_write(struct comedi_device *dev,
243				 struct comedi_subdevice *s,
244				 struct comedi_insn *insn,
245				 unsigned int *data)
246{
247	struct atao_private *devpriv = dev->private;
248	unsigned int chan = CR_CHAN(insn->chanspec);
249	unsigned int bitstring;
250	unsigned int val;
251	int bit;
252
253	if (insn->n == 0)
254		return 0;
255
256	devpriv->caldac[chan] = data[insn->n - 1] & s->maxdata;
257
258	/* write the channel and last data value to the caldac */
259	bitstring = ((chan & 0x7) << 8) | devpriv->caldac[chan];
260
261	/* clock the bitstring to the caldac; MSB -> LSB */
262	for (bit = 1 << 10; bit; bit >>= 1) {
263		val = (bit & bitstring) ? ATAO_CFG2_SDATA : 0;
264
265		outw(val, dev->iobase + ATAO_CFG2_REG);
266		outw(val | ATAO_CFG2_SCLK, dev->iobase + ATAO_CFG2_REG);
267	}
268
269	/* strobe the caldac to load the value */
270	outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG);
271	outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
272
273	return insn->n;
274}
275
276static int atao_calib_insn_read(struct comedi_device *dev,
277				struct comedi_subdevice *s,
278				struct comedi_insn *insn,
279				unsigned int *data)
280{
281	struct atao_private *devpriv = dev->private;
282	unsigned int chan = CR_CHAN(insn->chanspec);
283	int i;
284
285	for (i = 0; i < insn->n; i++)
286		data[i] = devpriv->caldac[chan];
287
288	return insn->n;
289}
290
291static void atao_reset(struct comedi_device *dev)
292{
293	struct atao_private *devpriv = dev->private;
294	unsigned long timer_base = dev->iobase + ATAO_82C53_BASE;
295
296	/* This is the reset sequence described in the manual */
297
298	devpriv->cfg1 = 0;
299	outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG);
300
301	/* Put outputs of counter 1 and counter 2 in a high state */
302	i8254_set_mode(timer_base, 0, 0, I8254_MODE4 | I8254_BINARY);
303	i8254_set_mode(timer_base, 0, 1, I8254_MODE4 | I8254_BINARY);
304	i8254_write(timer_base, 0, 0, 0x0003);
305
306	outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
307
308	devpriv->cfg3 = 0;
309	outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG);
310
311	inw(dev->iobase + ATAO_FIFO_CLEAR_REG);
312
313	atao_select_reg_group(dev, 1);
314	outw(0, dev->iobase + ATAO_2_INT1CLR_REG);
315	outw(0, dev->iobase + ATAO_2_INT2CLR_REG);
316	outw(0, dev->iobase + ATAO_2_DMATCCLR_REG);
317	atao_select_reg_group(dev, 0);
318}
319
320static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
321{
322	const struct atao_board *board = dev->board_ptr;
323	struct atao_private *devpriv;
324	struct comedi_subdevice *s;
325	int ret;
326
327	ret = comedi_request_region(dev, it->options[0], 0x20);
328	if (ret)
329		return ret;
330
331	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
332	if (!devpriv)
333		return -ENOMEM;
334
335	ret = comedi_alloc_subdevices(dev, 4);
336	if (ret)
337		return ret;
338
339	/* Analog Output subdevice */
340	s = &dev->subdevices[0];
341	s->type		= COMEDI_SUBD_AO;
342	s->subdev_flags	= SDF_WRITABLE;
343	s->n_chan	= board->n_ao_chans;
344	s->maxdata	= 0x0fff;
345	s->range_table	= it->options[3] ? &range_unipolar10 : &range_bipolar10;
346	s->insn_write	= atao_ao_insn_write;
347	s->insn_read	= comedi_readback_insn_read;
348
349	ret = comedi_alloc_subdev_readback(s);
350	if (ret)
351		return ret;
352
353	/* Digital I/O subdevice */
354	s = &dev->subdevices[1];
355	s->type		= COMEDI_SUBD_DIO;
356	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
357	s->n_chan	= 8;
358	s->maxdata	= 1;
359	s->range_table	= &range_digital;
360	s->insn_bits	= atao_dio_insn_bits;
361	s->insn_config	= atao_dio_insn_config;
362
363	/* caldac subdevice */
364	s = &dev->subdevices[2];
365	s->type		= COMEDI_SUBD_CALIB;
366	s->subdev_flags	= SDF_WRITABLE | SDF_INTERNAL;
367	s->n_chan	= (board->n_ao_chans * 2) + 1;
368	s->maxdata	= 0xff;
369	s->insn_read	= atao_calib_insn_read;
370	s->insn_write	= atao_calib_insn_write;
371
372	/* EEPROM subdevice */
373	s = &dev->subdevices[3];
374	s->type		= COMEDI_SUBD_UNUSED;
375
376	atao_reset(dev);
377
378	return 0;
379}
380
381static struct comedi_driver ni_at_ao_driver = {
382	.driver_name	= "ni_at_ao",
383	.module		= THIS_MODULE,
384	.attach		= atao_attach,
385	.detach		= comedi_legacy_detach,
386	.board_name	= &atao_boards[0].name,
387	.offset		= sizeof(struct atao_board),
388	.num_names	= ARRAY_SIZE(atao_boards),
389};
390module_comedi_driver(ni_at_ao_driver);
391
392MODULE_AUTHOR("Comedi http://www.comedi.org");
393MODULE_DESCRIPTION("Comedi driver for NI AT-AO-6/10 boards");
394MODULE_LICENSE("GPL");
395