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#include <linux/module.h>
33#include "../comedidev.h"
34#include <linux/delay.h>
35
36#define DT2801_TIMEOUT 1000
37
38
39
40
41#define DT2801_MAX_DMA_SIZE (64 * 1024)
42
43
44
45
46
47#define DT_C_RESET 0x0
48#define DT_C_CLEAR_ERR 0x1
49#define DT_C_READ_ERRREG 0x2
50#define DT_C_SET_CLOCK 0x3
51
52#define DT_C_TEST 0xb
53#define DT_C_STOP 0xf
54
55#define DT_C_SET_DIGIN 0x4
56#define DT_C_SET_DIGOUT 0x5
57#define DT_C_READ_DIG 0x6
58#define DT_C_WRITE_DIG 0x7
59
60#define DT_C_WRITE_DAIM 0x8
61#define DT_C_SET_DA 0x9
62#define DT_C_WRITE_DA 0xa
63
64#define DT_C_READ_ADIM 0xc
65#define DT_C_SET_AD 0xd
66#define DT_C_READ_AD 0xe
67
68
69
70
71
72#define DT_MOD_DMA BIT(4)
73#define DT_MOD_CONT BIT(5)
74#define DT_MOD_EXTCLK BIT(6)
75#define DT_MOD_EXTTRIG BIT(7)
76
77
78#define DT_S_DATA_OUT_READY BIT(0)
79#define DT_S_DATA_IN_FULL BIT(1)
80#define DT_S_READY BIT(2)
81#define DT_S_COMMAND BIT(3)
82#define DT_S_COMPOSITE_ERROR BIT(7)
83
84
85#define DT2801_DATA 0
86#define DT2801_STATUS 1
87#define DT2801_CMD 1
88
89#if 0
90
91static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = {
92 4, {
93 BIP_RANGE(10),
94 BIP_RANGE(5),
95 BIP_RANGE(2.5),
96 BIP_RANGE(1.25)
97 }
98};
99#endif
100static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = {
101 4, {
102 BIP_RANGE(10),
103 BIP_RANGE(1),
104 BIP_RANGE(0.1),
105 BIP_RANGE(0.02)
106 }
107};
108
109#if 0
110
111static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = {
112 4, {
113 UNI_RANGE(10),
114 UNI_RANGE(5),
115 UNI_RANGE(2.5),
116 UNI_RANGE(1.25)
117 }
118};
119#endif
120static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = {
121 4, {
122 UNI_RANGE(10),
123 UNI_RANGE(1),
124 UNI_RANGE(0.1),
125 UNI_RANGE(0.02)
126 }
127};
128
129struct dt2801_board {
130 const char *name;
131 int boardcode;
132 int ad_diff;
133 int ad_chan;
134 int adbits;
135 int adrangetype;
136 int dabits;
137};
138
139
140
141
142
143static const struct dt2801_board boardtypes[] = {
144 {
145 .name = "dt2801",
146 .boardcode = 0x09,
147 .ad_diff = 2,
148 .ad_chan = 16,
149 .adbits = 12,
150 .adrangetype = 0,
151 .dabits = 12},
152 {
153 .name = "dt2801-a",
154 .boardcode = 0x52,
155 .ad_diff = 2,
156 .ad_chan = 16,
157 .adbits = 12,
158 .adrangetype = 0,
159 .dabits = 12},
160 {
161 .name = "dt2801/5716a",
162 .boardcode = 0x82,
163 .ad_diff = 1,
164 .ad_chan = 16,
165 .adbits = 16,
166 .adrangetype = 1,
167 .dabits = 12},
168 {
169 .name = "dt2805",
170 .boardcode = 0x12,
171 .ad_diff = 1,
172 .ad_chan = 16,
173 .adbits = 12,
174 .adrangetype = 0,
175 .dabits = 12},
176 {
177 .name = "dt2805/5716a",
178 .boardcode = 0x92,
179 .ad_diff = 1,
180 .ad_chan = 16,
181 .adbits = 16,
182 .adrangetype = 1,
183 .dabits = 12},
184 {
185 .name = "dt2808",
186 .boardcode = 0x20,
187 .ad_diff = 0,
188 .ad_chan = 16,
189 .adbits = 12,
190 .adrangetype = 2,
191 .dabits = 8},
192 {
193 .name = "dt2818",
194 .boardcode = 0xa2,
195 .ad_diff = 0,
196 .ad_chan = 4,
197 .adbits = 12,
198 .adrangetype = 0,
199 .dabits = 12},
200 {
201 .name = "dt2809",
202 .boardcode = 0xb0,
203 .ad_diff = 0,
204 .ad_chan = 8,
205 .adbits = 12,
206 .adrangetype = 1,
207 .dabits = 12},
208};
209
210struct dt2801_private {
211 const struct comedi_lrange *dac_range_types[2];
212};
213
214
215
216
217
218
219
220
221
222
223
224
225
226static int dt2801_readdata(struct comedi_device *dev, int *data)
227{
228 int stat = 0;
229 int timeout = DT2801_TIMEOUT;
230
231 do {
232 stat = inb_p(dev->iobase + DT2801_STATUS);
233 if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY))
234 return stat;
235 if (stat & DT_S_DATA_OUT_READY) {
236 *data = inb_p(dev->iobase + DT2801_DATA);
237 return 0;
238 }
239 } while (--timeout > 0);
240
241 return -ETIME;
242}
243
244static int dt2801_readdata2(struct comedi_device *dev, int *data)
245{
246 int lb = 0;
247 int hb = 0;
248 int ret;
249
250 ret = dt2801_readdata(dev, &lb);
251 if (ret)
252 return ret;
253 ret = dt2801_readdata(dev, &hb);
254 if (ret)
255 return ret;
256
257 *data = (hb << 8) + lb;
258 return 0;
259}
260
261static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
262{
263 int stat = 0;
264 int timeout = DT2801_TIMEOUT;
265
266 do {
267 stat = inb_p(dev->iobase + DT2801_STATUS);
268
269 if (stat & DT_S_COMPOSITE_ERROR)
270 return stat;
271 if (!(stat & DT_S_DATA_IN_FULL)) {
272 outb_p(data & 0xff, dev->iobase + DT2801_DATA);
273 return 0;
274 }
275 } while (--timeout > 0);
276
277 return -ETIME;
278}
279
280static int dt2801_writedata2(struct comedi_device *dev, unsigned int data)
281{
282 int ret;
283
284 ret = dt2801_writedata(dev, data & 0xff);
285 if (ret < 0)
286 return ret;
287 ret = dt2801_writedata(dev, data >> 8);
288 if (ret < 0)
289 return ret;
290
291 return 0;
292}
293
294static int dt2801_wait_for_ready(struct comedi_device *dev)
295{
296 int timeout = DT2801_TIMEOUT;
297 int stat;
298
299 stat = inb_p(dev->iobase + DT2801_STATUS);
300 if (stat & DT_S_READY)
301 return 0;
302 do {
303 stat = inb_p(dev->iobase + DT2801_STATUS);
304
305 if (stat & DT_S_COMPOSITE_ERROR)
306 return stat;
307 if (stat & DT_S_READY)
308 return 0;
309 } while (--timeout > 0);
310
311 return -ETIME;
312}
313
314static void dt2801_writecmd(struct comedi_device *dev, int command)
315{
316 int stat;
317
318 dt2801_wait_for_ready(dev);
319
320 stat = inb_p(dev->iobase + DT2801_STATUS);
321 if (stat & DT_S_COMPOSITE_ERROR) {
322 dev_dbg(dev->class_dev,
323 "composite-error in %s, ignoring\n", __func__);
324 }
325 if (!(stat & DT_S_READY))
326 dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__);
327 outb_p(command, dev->iobase + DT2801_CMD);
328}
329
330static int dt2801_reset(struct comedi_device *dev)
331{
332 int board_code = 0;
333 unsigned int stat;
334 int timeout;
335
336
337 inb_p(dev->iobase + DT2801_DATA);
338 inb_p(dev->iobase + DT2801_DATA);
339 inb_p(dev->iobase + DT2801_DATA);
340 inb_p(dev->iobase + DT2801_DATA);
341
342
343 outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
344
345
346 udelay(100);
347 timeout = 10000;
348 do {
349 stat = inb_p(dev->iobase + DT2801_STATUS);
350 if (stat & DT_S_READY)
351 break;
352 } while (timeout--);
353 if (!timeout)
354 dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat);
355
356
357
358 outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
359
360
361 udelay(100);
362 timeout = 10000;
363 do {
364 stat = inb_p(dev->iobase + DT2801_STATUS);
365 if (stat & DT_S_READY)
366 break;
367 } while (timeout--);
368 if (!timeout)
369 dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat);
370
371 dt2801_readdata(dev, &board_code);
372
373 return board_code;
374}
375
376static int probe_number_of_ai_chans(struct comedi_device *dev)
377{
378 int n_chans;
379 int stat;
380 int data;
381
382 for (n_chans = 0; n_chans < 16; n_chans++) {
383 dt2801_writecmd(dev, DT_C_READ_ADIM);
384 dt2801_writedata(dev, 0);
385 dt2801_writedata(dev, n_chans);
386 stat = dt2801_readdata2(dev, &data);
387
388 if (stat)
389 break;
390 }
391
392 dt2801_reset(dev);
393 dt2801_reset(dev);
394
395 return n_chans;
396}
397
398static const struct comedi_lrange *dac_range_table[] = {
399 &range_bipolar10,
400 &range_bipolar5,
401 &range_bipolar2_5,
402 &range_unipolar10,
403 &range_unipolar5
404};
405
406static const struct comedi_lrange *dac_range_lkup(int opt)
407{
408 if (opt < 0 || opt >= 5)
409 return &range_unknown;
410 return dac_range_table[opt];
411}
412
413static const struct comedi_lrange *ai_range_lkup(int type, int opt)
414{
415 switch (type) {
416 case 0:
417 return (opt) ?
418 &range_dt2801_ai_pgl_unipolar :
419 &range_dt2801_ai_pgl_bipolar;
420 case 1:
421 return (opt) ? &range_unipolar10 : &range_bipolar10;
422 case 2:
423 return &range_unipolar5;
424 }
425 return &range_unknown;
426}
427
428static int dt2801_error(struct comedi_device *dev, int stat)
429{
430 if (stat < 0) {
431 if (stat == -ETIME)
432 dev_dbg(dev->class_dev, "timeout\n");
433 else
434 dev_dbg(dev->class_dev, "error %d\n", stat);
435 return stat;
436 }
437 dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat);
438
439 dt2801_reset(dev);
440 dt2801_reset(dev);
441
442 return -EIO;
443}
444
445static int dt2801_ai_insn_read(struct comedi_device *dev,
446 struct comedi_subdevice *s,
447 struct comedi_insn *insn, unsigned int *data)
448{
449 int d;
450 int stat;
451 int i;
452
453 for (i = 0; i < insn->n; i++) {
454 dt2801_writecmd(dev, DT_C_READ_ADIM);
455 dt2801_writedata(dev, CR_RANGE(insn->chanspec));
456 dt2801_writedata(dev, CR_CHAN(insn->chanspec));
457 stat = dt2801_readdata2(dev, &d);
458
459 if (stat != 0)
460 return dt2801_error(dev, stat);
461
462 data[i] = d;
463 }
464
465 return i;
466}
467
468static int dt2801_ao_insn_write(struct comedi_device *dev,
469 struct comedi_subdevice *s,
470 struct comedi_insn *insn,
471 unsigned int *data)
472{
473 unsigned int chan = CR_CHAN(insn->chanspec);
474
475 dt2801_writecmd(dev, DT_C_WRITE_DAIM);
476 dt2801_writedata(dev, chan);
477 dt2801_writedata2(dev, data[0]);
478
479 s->readback[chan] = data[0];
480
481 return 1;
482}
483
484static int dt2801_dio_insn_bits(struct comedi_device *dev,
485 struct comedi_subdevice *s,
486 struct comedi_insn *insn,
487 unsigned int *data)
488{
489 int which = (s == &dev->subdevices[3]) ? 1 : 0;
490 unsigned int val = 0;
491
492 if (comedi_dio_update_state(s, data)) {
493 dt2801_writecmd(dev, DT_C_WRITE_DIG);
494 dt2801_writedata(dev, which);
495 dt2801_writedata(dev, s->state);
496 }
497
498 dt2801_writecmd(dev, DT_C_READ_DIG);
499 dt2801_writedata(dev, which);
500 dt2801_readdata(dev, &val);
501
502 data[1] = val;
503
504 return insn->n;
505}
506
507static int dt2801_dio_insn_config(struct comedi_device *dev,
508 struct comedi_subdevice *s,
509 struct comedi_insn *insn,
510 unsigned int *data)
511{
512 int ret;
513
514 ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
515 if (ret)
516 return ret;
517
518 dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN);
519 dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0);
520
521 return insn->n;
522}
523
524
525
526
527
528
529
530
531
532
533static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
534{
535 const struct dt2801_board *board;
536 struct dt2801_private *devpriv;
537 struct comedi_subdevice *s;
538 int board_code, type;
539 int ret = 0;
540 int n_ai_chans;
541
542 ret = comedi_request_region(dev, it->options[0], 0x2);
543 if (ret)
544 return ret;
545
546
547
548 board_code = dt2801_reset(dev);
549
550
551 if (!board_code)
552 board_code = dt2801_reset(dev);
553
554 for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
555 if (boardtypes[type].boardcode == board_code)
556 goto havetype;
557 }
558 dev_dbg(dev->class_dev,
559 "unrecognized board code=0x%02x, contact author\n", board_code);
560 type = 0;
561
562havetype:
563 dev->board_ptr = boardtypes + type;
564 board = dev->board_ptr;
565
566 n_ai_chans = probe_number_of_ai_chans(dev);
567
568 ret = comedi_alloc_subdevices(dev, 4);
569 if (ret)
570 goto out;
571
572 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
573 if (!devpriv)
574 return -ENOMEM;
575
576 dev->board_name = board->name;
577
578 s = &dev->subdevices[0];
579
580 s->type = COMEDI_SUBD_AI;
581 s->subdev_flags = SDF_READABLE | SDF_GROUND;
582#if 1
583 s->n_chan = n_ai_chans;
584#else
585 if (it->options[2])
586 s->n_chan = board->ad_chan;
587 else
588 s->n_chan = board->ad_chan / 2;
589#endif
590 s->maxdata = (1 << board->adbits) - 1;
591 s->range_table = ai_range_lkup(board->adrangetype, it->options[3]);
592 s->insn_read = dt2801_ai_insn_read;
593
594 s = &dev->subdevices[1];
595
596 s->type = COMEDI_SUBD_AO;
597 s->subdev_flags = SDF_WRITABLE;
598 s->n_chan = 2;
599 s->maxdata = (1 << board->dabits) - 1;
600 s->range_table_list = devpriv->dac_range_types;
601 devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
602 devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
603 s->insn_write = dt2801_ao_insn_write;
604
605 ret = comedi_alloc_subdev_readback(s);
606 if (ret)
607 return ret;
608
609 s = &dev->subdevices[2];
610
611 s->type = COMEDI_SUBD_DIO;
612 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
613 s->n_chan = 8;
614 s->maxdata = 1;
615 s->range_table = &range_digital;
616 s->insn_bits = dt2801_dio_insn_bits;
617 s->insn_config = dt2801_dio_insn_config;
618
619 s = &dev->subdevices[3];
620
621 s->type = COMEDI_SUBD_DIO;
622 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
623 s->n_chan = 8;
624 s->maxdata = 1;
625 s->range_table = &range_digital;
626 s->insn_bits = dt2801_dio_insn_bits;
627 s->insn_config = dt2801_dio_insn_config;
628
629 ret = 0;
630out:
631 return ret;
632}
633
634static struct comedi_driver dt2801_driver = {
635 .driver_name = "dt2801",
636 .module = THIS_MODULE,
637 .attach = dt2801_attach,
638 .detach = comedi_legacy_detach,
639};
640module_comedi_driver(dt2801_driver);
641
642MODULE_AUTHOR("Comedi http://www.comedi.org");
643MODULE_DESCRIPTION("Comedi low-level driver");
644MODULE_LICENSE("GPL");
645