1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#include <linux/module.h>
37
38#include "../comedidev.h"
39
40#include "comedi_8254.h"
41
42
43
44
45
46
47
48#define ATAO_DIO_REG 0x00
49#define ATAO_CFG2_REG 0x02
50#define ATAO_CFG2_CALLD_NOP (0 << 14)
51#define ATAO_CFG2_CALLD(x) ((((x) >> 3) + 1) << 14)
52#define ATAO_CFG2_FFRTEN (1 << 13)
53#define ATAO_CFG2_DACS(x) (1 << (((x) / 2) + 8))
54#define ATAO_CFG2_LDAC(x) (1 << (((x) / 2) + 3))
55#define ATAO_CFG2_PROMEN (1 << 2)
56#define ATAO_CFG2_SCLK (1 << 1)
57#define ATAO_CFG2_SDATA (1 << 0)
58#define ATAO_CFG3_REG 0x04
59#define ATAO_CFG3_DMAMODE (1 << 6)
60#define ATAO_CFG3_CLKOUT (1 << 5)
61#define ATAO_CFG3_RCLKEN (1 << 4)
62#define ATAO_CFG3_DOUTEN2 (1 << 3)
63#define ATAO_CFG3_DOUTEN1 (1 << 2)
64#define ATAO_CFG3_EN2_5V (1 << 1)
65#define ATAO_CFG3_SCANEN (1 << 0)
66#define ATAO_82C53_BASE 0x06
67#define ATAO_CFG1_REG 0x0a
68#define ATAO_CFG1_EXTINT2EN (1 << 15)
69#define ATAO_CFG1_EXTINT1EN (1 << 14)
70#define ATAO_CFG1_CNTINT2EN (1 << 13)
71#define ATAO_CFG1_CNTINT1EN (1 << 12)
72#define ATAO_CFG1_TCINTEN (1 << 11)
73#define ATAO_CFG1_CNT1SRC (1 << 10)
74#define ATAO_CFG1_CNT2SRC (1 << 9)
75#define ATAO_CFG1_FIFOEN (1 << 8)
76#define ATAO_CFG1_GRP2WR (1 << 7)
77#define ATAO_CFG1_EXTUPDEN (1 << 6)
78#define ATAO_CFG1_DMARQ (1 << 5)
79#define ATAO_CFG1_DMAEN (1 << 4)
80#define ATAO_CFG1_CH(x) (((x) & 0xf) << 0)
81#define ATAO_STATUS_REG 0x0a
82#define ATAO_STATUS_FH (1 << 6)
83#define ATAO_STATUS_FE (1 << 5)
84#define ATAO_STATUS_FF (1 << 4)
85#define ATAO_STATUS_INT2 (1 << 3)
86#define ATAO_STATUS_INT1 (1 << 2)
87#define ATAO_STATUS_TCINT (1 << 1)
88#define ATAO_STATUS_PROMOUT (1 << 0)
89#define ATAO_FIFO_WRITE_REG 0x0c
90#define ATAO_FIFO_CLEAR_REG 0x0c
91#define ATAO_AO_REG(x) (0x0c + ((x) * 2))
92
93
94#define ATAO_2_DMATCCLR_REG 0x00
95#define ATAO_2_INT1CLR_REG 0x02
96#define ATAO_2_INT2CLR_REG 0x04
97#define ATAO_2_RTSISHFT_REG 0x06
98#define ATAO_2_RTSISHFT_RSI (1 << 0)
99#define ATAO_2_RTSISTRB_REG 0x07
100
101struct atao_board {
102 const char *name;
103 int n_ao_chans;
104};
105
106static const struct atao_board atao_boards[] = {
107 {
108 .name = "at-ao-6",
109 .n_ao_chans = 6,
110 }, {
111 .name = "at-ao-10",
112 .n_ao_chans = 10,
113 },
114};
115
116struct atao_private {
117 unsigned short cfg1;
118 unsigned short cfg3;
119
120
121 unsigned char caldac[21];
122};
123
124static void atao_select_reg_group(struct comedi_device *dev, int group)
125{
126 struct atao_private *devpriv = dev->private;
127
128 if (group)
129 devpriv->cfg1 |= ATAO_CFG1_GRP2WR;
130 else
131 devpriv->cfg1 &= ~ATAO_CFG1_GRP2WR;
132 outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG);
133}
134
135static int atao_ao_insn_write(struct comedi_device *dev,
136 struct comedi_subdevice *s,
137 struct comedi_insn *insn,
138 unsigned int *data)
139{
140 unsigned int chan = CR_CHAN(insn->chanspec);
141 unsigned int val = s->readback[chan];
142 int i;
143
144 if (chan == 0)
145 atao_select_reg_group(dev, 1);
146
147 for (i = 0; i < insn->n; i++) {
148 val = data[i];
149
150
151 outw(comedi_offset_munge(s, val),
152 dev->iobase + ATAO_AO_REG(chan));
153 }
154 s->readback[chan] = val;
155
156 if (chan == 0)
157 atao_select_reg_group(dev, 0);
158
159 return insn->n;
160}
161
162static int atao_dio_insn_bits(struct comedi_device *dev,
163 struct comedi_subdevice *s,
164 struct comedi_insn *insn,
165 unsigned int *data)
166{
167 if (comedi_dio_update_state(s, data))
168 outw(s->state, dev->iobase + ATAO_DIO_REG);
169
170 data[1] = inw(dev->iobase + ATAO_DIO_REG);
171
172 return insn->n;
173}
174
175static int atao_dio_insn_config(struct comedi_device *dev,
176 struct comedi_subdevice *s,
177 struct comedi_insn *insn,
178 unsigned int *data)
179{
180 struct atao_private *devpriv = dev->private;
181 unsigned int chan = CR_CHAN(insn->chanspec);
182 unsigned int mask;
183 int ret;
184
185 if (chan < 4)
186 mask = 0x0f;
187 else
188 mask = 0xf0;
189
190 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
191 if (ret)
192 return ret;
193
194 if (s->io_bits & 0x0f)
195 devpriv->cfg3 |= ATAO_CFG3_DOUTEN1;
196 else
197 devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN1;
198 if (s->io_bits & 0xf0)
199 devpriv->cfg3 |= ATAO_CFG3_DOUTEN2;
200 else
201 devpriv->cfg3 &= ~ATAO_CFG3_DOUTEN2;
202
203 outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG);
204
205 return insn->n;
206}
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241static int atao_calib_insn_write(struct comedi_device *dev,
242 struct comedi_subdevice *s,
243 struct comedi_insn *insn,
244 unsigned int *data)
245{
246 unsigned int chan = CR_CHAN(insn->chanspec);
247
248 if (insn->n) {
249 unsigned int val = data[insn->n - 1];
250 unsigned int bitstring = ((chan & 0x7) << 8) | val;
251 unsigned int bits;
252 int bit;
253
254
255
256 for (bit = 1 << 10; bit; bit >>= 1) {
257 bits = (bit & bitstring) ? ATAO_CFG2_SDATA : 0;
258
259 outw(bits, dev->iobase + ATAO_CFG2_REG);
260 outw(bits | ATAO_CFG2_SCLK,
261 dev->iobase + ATAO_CFG2_REG);
262 }
263
264
265 outw(ATAO_CFG2_CALLD(chan), dev->iobase + ATAO_CFG2_REG);
266 outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
267
268 s->readback[chan] = val;
269 }
270
271 return insn->n;
272}
273
274static void atao_reset(struct comedi_device *dev)
275{
276 struct atao_private *devpriv = dev->private;
277
278
279
280 devpriv->cfg1 = 0;
281 outw(devpriv->cfg1, dev->iobase + ATAO_CFG1_REG);
282
283
284 comedi_8254_set_mode(dev->pacer, 0, I8254_MODE4 | I8254_BINARY);
285 comedi_8254_set_mode(dev->pacer, 1, I8254_MODE4 | I8254_BINARY);
286 comedi_8254_write(dev->pacer, 0, 0x0003);
287
288 outw(ATAO_CFG2_CALLD_NOP, dev->iobase + ATAO_CFG2_REG);
289
290 devpriv->cfg3 = 0;
291 outw(devpriv->cfg3, dev->iobase + ATAO_CFG3_REG);
292
293 inw(dev->iobase + ATAO_FIFO_CLEAR_REG);
294
295 atao_select_reg_group(dev, 1);
296 outw(0, dev->iobase + ATAO_2_INT1CLR_REG);
297 outw(0, dev->iobase + ATAO_2_INT2CLR_REG);
298 outw(0, dev->iobase + ATAO_2_DMATCCLR_REG);
299 atao_select_reg_group(dev, 0);
300}
301
302static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it)
303{
304 const struct atao_board *board = dev->board_ptr;
305 struct atao_private *devpriv;
306 struct comedi_subdevice *s;
307 int ret;
308
309 ret = comedi_request_region(dev, it->options[0], 0x20);
310 if (ret)
311 return ret;
312
313 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
314 if (!devpriv)
315 return -ENOMEM;
316
317 dev->pacer = comedi_8254_init(dev->iobase + ATAO_82C53_BASE,
318 0, I8254_IO8, 0);
319 if (!dev->pacer)
320 return -ENOMEM;
321
322 ret = comedi_alloc_subdevices(dev, 4);
323 if (ret)
324 return ret;
325
326
327 s = &dev->subdevices[0];
328 s->type = COMEDI_SUBD_AO;
329 s->subdev_flags = SDF_WRITABLE;
330 s->n_chan = board->n_ao_chans;
331 s->maxdata = 0x0fff;
332 s->range_table = it->options[3] ? &range_unipolar10 : &range_bipolar10;
333 s->insn_write = atao_ao_insn_write;
334
335 ret = comedi_alloc_subdev_readback(s);
336 if (ret)
337 return ret;
338
339
340 s = &dev->subdevices[1];
341 s->type = COMEDI_SUBD_DIO;
342 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
343 s->n_chan = 8;
344 s->maxdata = 1;
345 s->range_table = &range_digital;
346 s->insn_bits = atao_dio_insn_bits;
347 s->insn_config = atao_dio_insn_config;
348
349
350 s = &dev->subdevices[2];
351 s->type = COMEDI_SUBD_CALIB;
352 s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL;
353 s->n_chan = (board->n_ao_chans * 2) + 1;
354 s->maxdata = 0xff;
355 s->insn_write = atao_calib_insn_write;
356
357 ret = comedi_alloc_subdev_readback(s);
358 if (ret)
359 return ret;
360
361
362 s = &dev->subdevices[3];
363 s->type = COMEDI_SUBD_UNUSED;
364
365 atao_reset(dev);
366
367 return 0;
368}
369
370static struct comedi_driver ni_at_ao_driver = {
371 .driver_name = "ni_at_ao",
372 .module = THIS_MODULE,
373 .attach = atao_attach,
374 .detach = comedi_legacy_detach,
375 .board_name = &atao_boards[0].name,
376 .offset = sizeof(struct atao_board),
377 .num_names = ARRAY_SIZE(atao_boards),
378};
379module_comedi_driver(ni_at_ao_driver);
380
381MODULE_AUTHOR("Comedi http://www.comedi.org");
382MODULE_DESCRIPTION("Comedi driver for NI AT-AO-6/10 boards");
383MODULE_LICENSE("GPL");
384