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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58#include <linux/module.h>
59#include <linux/delay.h>
60#include <linux/gfp.h>
61#include <linux/interrupt.h>
62#include <linux/io.h>
63
64#include "../comedidev.h"
65
66#include "comedi_isadma.h"
67
68
69
70
71#define DT2821_ADCSR_REG 0x00
72#define DT2821_ADCSR_ADERR BIT(15)
73#define DT2821_ADCSR_ADCLK BIT(9)
74#define DT2821_ADCSR_MUXBUSY BIT(8)
75#define DT2821_ADCSR_ADDONE BIT(7)
76#define DT2821_ADCSR_IADDONE BIT(6)
77#define DT2821_ADCSR_GS(x) (((x) & 0x3) << 4)
78#define DT2821_ADCSR_CHAN(x) (((x) & 0xf) << 0)
79#define DT2821_CHANCSR_REG 0x02
80#define DT2821_CHANCSR_LLE BIT(15)
81#define DT2821_CHANCSR_TO_PRESLA(x) (((x) >> 8) & 0xf)
82#define DT2821_CHANCSR_NUMB(x) ((((x) - 1) & 0xf) << 0)
83#define DT2821_ADDAT_REG 0x04
84#define DT2821_DACSR_REG 0x06
85#define DT2821_DACSR_DAERR BIT(15)
86#define DT2821_DACSR_YSEL(x) ((x) << 9)
87#define DT2821_DACSR_SSEL BIT(8)
88#define DT2821_DACSR_DACRDY BIT(7)
89#define DT2821_DACSR_IDARDY BIT(6)
90#define DT2821_DACSR_DACLK BIT(5)
91#define DT2821_DACSR_HBOE BIT(1)
92#define DT2821_DACSR_LBOE BIT(0)
93#define DT2821_DADAT_REG 0x08
94#define DT2821_DIODAT_REG 0x0a
95#define DT2821_SUPCSR_REG 0x0c
96#define DT2821_SUPCSR_DMAD BIT(15)
97#define DT2821_SUPCSR_ERRINTEN BIT(14)
98#define DT2821_SUPCSR_CLRDMADNE BIT(13)
99#define DT2821_SUPCSR_DDMA BIT(12)
100#define DT2821_SUPCSR_DS(x) (((x) & 0x3) << 10)
101#define DT2821_SUPCSR_DS_PIO DT2821_SUPCSR_DS(0)
102#define DT2821_SUPCSR_DS_AD_CLK DT2821_SUPCSR_DS(1)
103#define DT2821_SUPCSR_DS_DA_CLK DT2821_SUPCSR_DS(2)
104#define DT2821_SUPCSR_DS_AD_TRIG DT2821_SUPCSR_DS(3)
105#define DT2821_SUPCSR_BUFFB BIT(9)
106#define DT2821_SUPCSR_SCDN BIT(8)
107#define DT2821_SUPCSR_DACON BIT(7)
108#define DT2821_SUPCSR_ADCINIT BIT(6)
109#define DT2821_SUPCSR_DACINIT BIT(5)
110#define DT2821_SUPCSR_PRLD BIT(4)
111#define DT2821_SUPCSR_STRIG BIT(3)
112#define DT2821_SUPCSR_XTRIG BIT(2)
113#define DT2821_SUPCSR_XCLK BIT(1)
114#define DT2821_SUPCSR_BDINIT BIT(0)
115#define DT2821_TMRCTR_REG 0x0e
116#define DT2821_TMRCTR_PRESCALE(x) (((x) & 0xf) << 8)
117#define DT2821_TMRCTR_DIVIDER(x) ((255 - ((x) & 0xff)) << 0)
118
119
120#define DT2821_OSC_BASE 250
121#define DT2821_PRESCALE(x) BIT(x)
122#define DT2821_PRESCALE_MAX 15
123#define DT2821_DIVIDER_MAX 255
124#define DT2821_OSC_MAX (DT2821_OSC_BASE * \
125 DT2821_PRESCALE(DT2821_PRESCALE_MAX) * \
126 DT2821_DIVIDER_MAX)
127
128static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
129 4, {
130 BIP_RANGE(10),
131 BIP_RANGE(5),
132 BIP_RANGE(2.5),
133 BIP_RANGE(1.25)
134 }
135};
136
137static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
138 4, {
139 UNI_RANGE(10),
140 UNI_RANGE(5),
141 UNI_RANGE(2.5),
142 UNI_RANGE(1.25)
143 }
144};
145
146static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
147 4, {
148 BIP_RANGE(5),
149 BIP_RANGE(2.5),
150 BIP_RANGE(1.25),
151 BIP_RANGE(0.625)
152 }
153};
154
155static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
156 4, {
157 UNI_RANGE(5),
158 UNI_RANGE(2.5),
159 UNI_RANGE(1.25),
160 UNI_RANGE(0.625)
161 }
162};
163
164static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
165 4, {
166 BIP_RANGE(10),
167 BIP_RANGE(1),
168 BIP_RANGE(0.1),
169 BIP_RANGE(0.02)
170 }
171};
172
173static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
174 4, {
175 UNI_RANGE(10),
176 UNI_RANGE(1),
177 UNI_RANGE(0.1),
178 UNI_RANGE(0.02)
179 }
180};
181
182
183
184
185
186
187static const struct comedi_lrange dt282x_ao_range = {
188 5, {
189 BIP_RANGE(10),
190 BIP_RANGE(5),
191 BIP_RANGE(2.5),
192 UNI_RANGE(10),
193 UNI_RANGE(5),
194 }
195};
196
197struct dt282x_board {
198 const char *name;
199 unsigned int ai_maxdata;
200 int adchan_se;
201 int adchan_di;
202 int ai_speed;
203 int ispgl;
204 int dachan;
205 unsigned int ao_maxdata;
206};
207
208static const struct dt282x_board boardtypes[] = {
209 {
210 .name = "dt2821",
211 .ai_maxdata = 0x0fff,
212 .adchan_se = 16,
213 .adchan_di = 8,
214 .ai_speed = 20000,
215 .dachan = 2,
216 .ao_maxdata = 0x0fff,
217 }, {
218 .name = "dt2821-f",
219 .ai_maxdata = 0x0fff,
220 .adchan_se = 16,
221 .adchan_di = 8,
222 .ai_speed = 6500,
223 .dachan = 2,
224 .ao_maxdata = 0x0fff,
225 }, {
226 .name = "dt2821-g",
227 .ai_maxdata = 0x0fff,
228 .adchan_se = 16,
229 .adchan_di = 8,
230 .ai_speed = 4000,
231 .dachan = 2,
232 .ao_maxdata = 0x0fff,
233 }, {
234 .name = "dt2823",
235 .ai_maxdata = 0xffff,
236 .adchan_di = 4,
237 .ai_speed = 10000,
238 .dachan = 2,
239 .ao_maxdata = 0xffff,
240 }, {
241 .name = "dt2824-pgh",
242 .ai_maxdata = 0x0fff,
243 .adchan_se = 16,
244 .adchan_di = 8,
245 .ai_speed = 20000,
246 }, {
247 .name = "dt2824-pgl",
248 .ai_maxdata = 0x0fff,
249 .adchan_se = 16,
250 .adchan_di = 8,
251 .ai_speed = 20000,
252 .ispgl = 1,
253 }, {
254 .name = "dt2825",
255 .ai_maxdata = 0x0fff,
256 .adchan_se = 16,
257 .adchan_di = 8,
258 .ai_speed = 20000,
259 .ispgl = 1,
260 .dachan = 2,
261 .ao_maxdata = 0x0fff,
262 }, {
263 .name = "dt2827",
264 .ai_maxdata = 0xffff,
265 .adchan_di = 4,
266 .ai_speed = 10000,
267 .dachan = 2,
268 .ao_maxdata = 0x0fff,
269 }, {
270 .name = "dt2828",
271 .ai_maxdata = 0x0fff,
272 .adchan_se = 4,
273 .ai_speed = 10000,
274 .dachan = 2,
275 .ao_maxdata = 0x0fff,
276 }, {
277 .name = "dt2829",
278 .ai_maxdata = 0xffff,
279 .adchan_se = 8,
280 .ai_speed = 33250,
281 .dachan = 2,
282 .ao_maxdata = 0xffff,
283 }, {
284 .name = "dt21-ez",
285 .ai_maxdata = 0x0fff,
286 .adchan_se = 16,
287 .adchan_di = 8,
288 .ai_speed = 10000,
289 .dachan = 2,
290 .ao_maxdata = 0x0fff,
291 }, {
292 .name = "dt23-ez",
293 .ai_maxdata = 0xffff,
294 .adchan_se = 16,
295 .adchan_di = 8,
296 .ai_speed = 10000,
297 }, {
298 .name = "dt24-ez",
299 .ai_maxdata = 0x0fff,
300 .adchan_se = 16,
301 .adchan_di = 8,
302 .ai_speed = 10000,
303 }, {
304 .name = "dt24-ez-pgl",
305 .ai_maxdata = 0x0fff,
306 .adchan_se = 16,
307 .adchan_di = 8,
308 .ai_speed = 10000,
309 .ispgl = 1,
310 },
311};
312
313struct dt282x_private {
314 struct comedi_isadma *dma;
315 unsigned int ad_2scomp:1;
316 unsigned int divisor;
317 int dacsr;
318 int adcsr;
319 int supcsr;
320 int ntrig;
321 int nread;
322 int dma_dir;
323};
324
325static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
326{
327 struct dt282x_private *devpriv = dev->private;
328 struct comedi_isadma *dma = devpriv->dma;
329 struct comedi_isadma_desc *desc = &dma->desc[dma_index];
330
331 if (!devpriv->ntrig)
332 return 0;
333
334 if (n == 0)
335 n = desc->maxsize;
336 if (n > devpriv->ntrig * 2)
337 n = devpriv->ntrig * 2;
338 devpriv->ntrig -= n / 2;
339
340 desc->size = n;
341 comedi_isadma_set_mode(desc, devpriv->dma_dir);
342
343 comedi_isadma_program(desc);
344
345 return n;
346}
347
348static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
349{
350 struct dt282x_private *devpriv = dev->private;
351 struct comedi_isadma *dma = devpriv->dma;
352 struct comedi_isadma_desc *desc = &dma->desc[dma_index];
353
354 desc->size = n;
355 comedi_isadma_set_mode(desc, devpriv->dma_dir);
356
357 comedi_isadma_program(desc);
358
359 return n;
360}
361
362static void dt282x_disable_dma(struct comedi_device *dev)
363{
364 struct dt282x_private *devpriv = dev->private;
365 struct comedi_isadma *dma = devpriv->dma;
366 struct comedi_isadma_desc *desc;
367 int i;
368
369 for (i = 0; i < 2; i++) {
370 desc = &dma->desc[i];
371 comedi_isadma_disable(desc->chan);
372 }
373}
374
375static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
376{
377 unsigned int prescale, base, divider;
378
379 for (prescale = 0; prescale <= DT2821_PRESCALE_MAX; prescale++) {
380 if (prescale == 1)
381 continue;
382 base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
383 switch (flags & CMDF_ROUND_MASK) {
384 case CMDF_ROUND_NEAREST:
385 default:
386 divider = DIV_ROUND_CLOSEST(*ns, base);
387 break;
388 case CMDF_ROUND_DOWN:
389 divider = (*ns) / base;
390 break;
391 case CMDF_ROUND_UP:
392 divider = DIV_ROUND_UP(*ns, base);
393 break;
394 }
395 if (divider <= DT2821_DIVIDER_MAX)
396 break;
397 }
398 if (divider > DT2821_DIVIDER_MAX) {
399 prescale = DT2821_PRESCALE_MAX;
400 divider = DT2821_DIVIDER_MAX;
401 base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
402 }
403 *ns = divider * base;
404 return DT2821_TMRCTR_PRESCALE(prescale) |
405 DT2821_TMRCTR_DIVIDER(divider);
406}
407
408static void dt282x_munge(struct comedi_device *dev,
409 struct comedi_subdevice *s,
410 unsigned short *buf,
411 unsigned int nbytes)
412{
413 struct dt282x_private *devpriv = dev->private;
414 unsigned int val;
415 int i;
416
417 if (nbytes % 2)
418 dev_err(dev->class_dev,
419 "bug! odd number of bytes from dma xfer\n");
420
421 for (i = 0; i < nbytes / 2; i++) {
422 val = buf[i];
423 val &= s->maxdata;
424 if (devpriv->ad_2scomp)
425 val = comedi_offset_munge(s, val);
426
427 buf[i] = val;
428 }
429}
430
431static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
432 struct comedi_subdevice *s,
433 int cur_dma)
434{
435 struct dt282x_private *devpriv = dev->private;
436 struct comedi_isadma *dma = devpriv->dma;
437 struct comedi_isadma_desc *desc = &dma->desc[cur_dma];
438 unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize);
439 unsigned int nbytes;
440
441 nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples);
442 if (nbytes)
443 dt282x_prep_ao_dma(dev, cur_dma, nbytes);
444 else
445 dev_err(dev->class_dev, "AO underrun\n");
446
447 return nbytes;
448}
449
450static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
451 struct comedi_subdevice *s)
452{
453 struct dt282x_private *devpriv = dev->private;
454 struct comedi_isadma *dma = devpriv->dma;
455 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
456
457 outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
458 dev->iobase + DT2821_SUPCSR_REG);
459
460 comedi_isadma_disable(desc->chan);
461
462 if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma))
463 s->async->events |= COMEDI_CB_OVERFLOW;
464
465 dma->cur_dma = 1 - dma->cur_dma;
466}
467
468static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
469 struct comedi_subdevice *s)
470{
471 struct dt282x_private *devpriv = dev->private;
472 struct comedi_isadma *dma = devpriv->dma;
473 struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
474 unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
475 int ret;
476
477 outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
478 dev->iobase + DT2821_SUPCSR_REG);
479
480 comedi_isadma_disable(desc->chan);
481
482 dt282x_munge(dev, s, desc->virt_addr, desc->size);
483 ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples);
484 if (ret != desc->size)
485 return;
486
487 devpriv->nread -= nsamples;
488 if (devpriv->nread < 0) {
489 dev_info(dev->class_dev, "nread off by one\n");
490 devpriv->nread = 0;
491 }
492 if (!devpriv->nread) {
493 s->async->events |= COMEDI_CB_EOA;
494 return;
495 }
496#if 0
497
498
499 if (!devpriv->ntrig) {
500 devpriv->supcsr &= ~DT2821_SUPCSR_DDMA;
501 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
502 }
503#endif
504
505 dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
506
507 dma->cur_dma = 1 - dma->cur_dma;
508}
509
510static irqreturn_t dt282x_interrupt(int irq, void *d)
511{
512 struct comedi_device *dev = d;
513 struct dt282x_private *devpriv = dev->private;
514 struct comedi_subdevice *s = dev->read_subdev;
515 struct comedi_subdevice *s_ao = dev->write_subdev;
516 unsigned int supcsr, adcsr, dacsr;
517 int handled = 0;
518
519 if (!dev->attached) {
520 dev_err(dev->class_dev, "spurious interrupt\n");
521 return IRQ_HANDLED;
522 }
523
524 adcsr = inw(dev->iobase + DT2821_ADCSR_REG);
525 dacsr = inw(dev->iobase + DT2821_DACSR_REG);
526 supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
527 if (supcsr & DT2821_SUPCSR_DMAD) {
528 if (devpriv->dma_dir == COMEDI_ISADMA_READ)
529 dt282x_ai_dma_interrupt(dev, s);
530 else
531 dt282x_ao_dma_interrupt(dev, s_ao);
532 handled = 1;
533 }
534 if (adcsr & DT2821_ADCSR_ADERR) {
535 if (devpriv->nread != 0) {
536 dev_err(dev->class_dev, "A/D error\n");
537 s->async->events |= COMEDI_CB_ERROR;
538 }
539 handled = 1;
540 }
541 if (dacsr & DT2821_DACSR_DAERR) {
542 dev_err(dev->class_dev, "D/A error\n");
543 s_ao->async->events |= COMEDI_CB_ERROR;
544 handled = 1;
545 }
546#if 0
547 if (adcsr & DT2821_ADCSR_ADDONE) {
548 unsigned short data;
549
550 data = inw(dev->iobase + DT2821_ADDAT_REG);
551 data &= s->maxdata;
552 if (devpriv->ad_2scomp)
553 data = comedi_offset_munge(s, data);
554
555 comedi_buf_write_samples(s, &data, 1);
556
557 devpriv->nread--;
558 if (!devpriv->nread) {
559 s->async->events |= COMEDI_CB_EOA;
560 } else {
561 if (supcsr & DT2821_SUPCSR_SCDN)
562 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
563 dev->iobase + DT2821_SUPCSR_REG);
564 }
565 handled = 1;
566 }
567#endif
568 comedi_handle_events(dev, s);
569 comedi_handle_events(dev, s_ao);
570
571 return IRQ_RETVAL(handled);
572}
573
574static void dt282x_load_changain(struct comedi_device *dev, int n,
575 unsigned int *chanlist)
576{
577 struct dt282x_private *devpriv = dev->private;
578 int i;
579
580 outw(DT2821_CHANCSR_LLE | DT2821_CHANCSR_NUMB(n),
581 dev->iobase + DT2821_CHANCSR_REG);
582 for (i = 0; i < n; i++) {
583 unsigned int chan = CR_CHAN(chanlist[i]);
584 unsigned int range = CR_RANGE(chanlist[i]);
585
586 outw(devpriv->adcsr |
587 DT2821_ADCSR_GS(range) |
588 DT2821_ADCSR_CHAN(chan),
589 dev->iobase + DT2821_ADCSR_REG);
590 }
591 outw(DT2821_CHANCSR_NUMB(n), dev->iobase + DT2821_CHANCSR_REG);
592}
593
594static int dt282x_ai_timeout(struct comedi_device *dev,
595 struct comedi_subdevice *s,
596 struct comedi_insn *insn,
597 unsigned long context)
598{
599 unsigned int status;
600
601 status = inw(dev->iobase + DT2821_ADCSR_REG);
602 switch (context) {
603 case DT2821_ADCSR_MUXBUSY:
604 if ((status & DT2821_ADCSR_MUXBUSY) == 0)
605 return 0;
606 break;
607 case DT2821_ADCSR_ADDONE:
608 if (status & DT2821_ADCSR_ADDONE)
609 return 0;
610 break;
611 default:
612 return -EINVAL;
613 }
614 return -EBUSY;
615}
616
617
618
619
620
621
622
623static int dt282x_ai_insn_read(struct comedi_device *dev,
624 struct comedi_subdevice *s,
625 struct comedi_insn *insn,
626 unsigned int *data)
627{
628 struct dt282x_private *devpriv = dev->private;
629 unsigned int val;
630 int ret;
631 int i;
632
633
634 devpriv->adcsr = DT2821_ADCSR_ADCLK;
635 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
636
637 dt282x_load_changain(dev, 1, &insn->chanspec);
638
639 outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
640 dev->iobase + DT2821_SUPCSR_REG);
641 ret = comedi_timeout(dev, s, insn,
642 dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
643 if (ret)
644 return ret;
645
646 for (i = 0; i < insn->n; i++) {
647 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
648 dev->iobase + DT2821_SUPCSR_REG);
649
650 ret = comedi_timeout(dev, s, insn,
651 dt282x_ai_timeout, DT2821_ADCSR_ADDONE);
652 if (ret)
653 return ret;
654
655 val = inw(dev->iobase + DT2821_ADDAT_REG);
656 val &= s->maxdata;
657 if (devpriv->ad_2scomp)
658 val = comedi_offset_munge(s, val);
659
660 data[i] = val;
661 }
662
663 return i;
664}
665
666static int dt282x_ai_cmdtest(struct comedi_device *dev,
667 struct comedi_subdevice *s,
668 struct comedi_cmd *cmd)
669{
670 const struct dt282x_board *board = dev->board_ptr;
671 struct dt282x_private *devpriv = dev->private;
672 int err = 0;
673 unsigned int arg;
674
675
676
677 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
678 err |= comedi_check_trigger_src(&cmd->scan_begin_src,
679 TRIG_FOLLOW | TRIG_EXT);
680 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
681 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
682 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
683
684 if (err)
685 return 1;
686
687
688
689 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
690 err |= comedi_check_trigger_is_unique(cmd->stop_src);
691
692
693
694 if (err)
695 return 2;
696
697
698
699 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
700 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
701 err |= comedi_check_trigger_arg_max(&cmd->convert_arg, DT2821_OSC_MAX);
702 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
703 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
704 cmd->chanlist_len);
705
706 if (cmd->stop_src == TRIG_COUNT)
707 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
708 else
709 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
710
711 if (err)
712 return 3;
713
714
715
716 arg = cmd->convert_arg;
717 devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
718 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
719
720 if (err)
721 return 4;
722
723 return 0;
724}
725
726static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
727{
728 struct dt282x_private *devpriv = dev->private;
729 struct comedi_isadma *dma = devpriv->dma;
730 struct comedi_cmd *cmd = &s->async->cmd;
731 int ret;
732
733 dt282x_disable_dma(dev);
734
735 outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
736
737 devpriv->supcsr = DT2821_SUPCSR_ERRINTEN;
738 if (cmd->scan_begin_src == TRIG_FOLLOW)
739 devpriv->supcsr = DT2821_SUPCSR_DS_AD_CLK;
740 else
741 devpriv->supcsr = DT2821_SUPCSR_DS_AD_TRIG;
742 outw(devpriv->supcsr |
743 DT2821_SUPCSR_CLRDMADNE |
744 DT2821_SUPCSR_BUFFB |
745 DT2821_SUPCSR_ADCINIT,
746 dev->iobase + DT2821_SUPCSR_REG);
747
748 devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
749 devpriv->nread = devpriv->ntrig;
750
751 devpriv->dma_dir = COMEDI_ISADMA_READ;
752 dma->cur_dma = 0;
753 dt282x_prep_ai_dma(dev, 0, 0);
754 if (devpriv->ntrig) {
755 dt282x_prep_ai_dma(dev, 1, 0);
756 devpriv->supcsr |= DT2821_SUPCSR_DDMA;
757 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
758 }
759
760 devpriv->adcsr = 0;
761
762 dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
763
764 devpriv->adcsr = DT2821_ADCSR_ADCLK | DT2821_ADCSR_IADDONE;
765 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
766
767 outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
768 dev->iobase + DT2821_SUPCSR_REG);
769 ret = comedi_timeout(dev, s, NULL,
770 dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
771 if (ret)
772 return ret;
773
774 if (cmd->scan_begin_src == TRIG_FOLLOW) {
775 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
776 dev->iobase + DT2821_SUPCSR_REG);
777 } else {
778 devpriv->supcsr |= DT2821_SUPCSR_XTRIG;
779 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
780 }
781
782 return 0;
783}
784
785static int dt282x_ai_cancel(struct comedi_device *dev,
786 struct comedi_subdevice *s)
787{
788 struct dt282x_private *devpriv = dev->private;
789
790 dt282x_disable_dma(dev);
791
792 devpriv->adcsr = 0;
793 outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
794
795 devpriv->supcsr = 0;
796 outw(devpriv->supcsr | DT2821_SUPCSR_ADCINIT,
797 dev->iobase + DT2821_SUPCSR_REG);
798
799 return 0;
800}
801
802static int dt282x_ao_insn_write(struct comedi_device *dev,
803 struct comedi_subdevice *s,
804 struct comedi_insn *insn,
805 unsigned int *data)
806{
807 struct dt282x_private *devpriv = dev->private;
808 unsigned int chan = CR_CHAN(insn->chanspec);
809 unsigned int range = CR_RANGE(insn->chanspec);
810 int i;
811
812 devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
813
814 for (i = 0; i < insn->n; i++) {
815 unsigned int val = data[i];
816
817 s->readback[chan] = val;
818
819 if (comedi_range_is_bipolar(s, range))
820 val = comedi_offset_munge(s, val);
821
822 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
823
824 outw(val, dev->iobase + DT2821_DADAT_REG);
825
826 outw(devpriv->supcsr | DT2821_SUPCSR_DACON,
827 dev->iobase + DT2821_SUPCSR_REG);
828 }
829
830 return insn->n;
831}
832
833static int dt282x_ao_cmdtest(struct comedi_device *dev,
834 struct comedi_subdevice *s,
835 struct comedi_cmd *cmd)
836{
837 struct dt282x_private *devpriv = dev->private;
838 int err = 0;
839 unsigned int arg;
840
841
842
843 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
844 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
845 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
846 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
847 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
848
849 if (err)
850 return 1;
851
852
853
854 err |= comedi_check_trigger_is_unique(cmd->stop_src);
855
856
857
858 if (err)
859 return 2;
860
861
862
863 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
864 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
865 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
866 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
867 cmd->chanlist_len);
868
869 if (cmd->stop_src == TRIG_COUNT)
870 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
871 else
872 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
873
874 if (err)
875 return 3;
876
877
878
879 arg = cmd->scan_begin_arg;
880 devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
881 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
882
883 if (err)
884 return 4;
885
886 return 0;
887}
888
889static int dt282x_ao_inttrig(struct comedi_device *dev,
890 struct comedi_subdevice *s,
891 unsigned int trig_num)
892{
893 struct dt282x_private *devpriv = dev->private;
894 struct comedi_cmd *cmd = &s->async->cmd;
895
896 if (trig_num != cmd->start_src)
897 return -EINVAL;
898
899 if (!dt282x_ao_setup_dma(dev, s, 0))
900 return -EPIPE;
901
902 if (!dt282x_ao_setup_dma(dev, s, 1))
903 return -EPIPE;
904
905 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
906 dev->iobase + DT2821_SUPCSR_REG);
907 s->async->inttrig = NULL;
908
909 return 1;
910}
911
912static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
913{
914 struct dt282x_private *devpriv = dev->private;
915 struct comedi_isadma *dma = devpriv->dma;
916 struct comedi_cmd *cmd = &s->async->cmd;
917
918 dt282x_disable_dma(dev);
919
920 devpriv->supcsr = DT2821_SUPCSR_ERRINTEN |
921 DT2821_SUPCSR_DS_DA_CLK |
922 DT2821_SUPCSR_DDMA;
923 outw(devpriv->supcsr |
924 DT2821_SUPCSR_CLRDMADNE |
925 DT2821_SUPCSR_BUFFB |
926 DT2821_SUPCSR_DACINIT,
927 dev->iobase + DT2821_SUPCSR_REG);
928
929 devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
930 devpriv->nread = devpriv->ntrig;
931
932 devpriv->dma_dir = COMEDI_ISADMA_WRITE;
933 dma->cur_dma = 0;
934
935 outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
936
937
938 devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
939
940 devpriv->dacsr |= (DT2821_DACSR_SSEL |
941 DT2821_DACSR_DACLK |
942 DT2821_DACSR_IDARDY);
943 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
944
945 s->async->inttrig = dt282x_ao_inttrig;
946
947 return 0;
948}
949
950static int dt282x_ao_cancel(struct comedi_device *dev,
951 struct comedi_subdevice *s)
952{
953 struct dt282x_private *devpriv = dev->private;
954
955 dt282x_disable_dma(dev);
956
957
958 devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
959
960 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
961
962 devpriv->supcsr = 0;
963 outw(devpriv->supcsr | DT2821_SUPCSR_DACINIT,
964 dev->iobase + DT2821_SUPCSR_REG);
965
966 return 0;
967}
968
969static int dt282x_dio_insn_bits(struct comedi_device *dev,
970 struct comedi_subdevice *s,
971 struct comedi_insn *insn,
972 unsigned int *data)
973{
974 if (comedi_dio_update_state(s, data))
975 outw(s->state, dev->iobase + DT2821_DIODAT_REG);
976
977 data[1] = inw(dev->iobase + DT2821_DIODAT_REG);
978
979 return insn->n;
980}
981
982static int dt282x_dio_insn_config(struct comedi_device *dev,
983 struct comedi_subdevice *s,
984 struct comedi_insn *insn,
985 unsigned int *data)
986{
987 struct dt282x_private *devpriv = dev->private;
988 unsigned int chan = CR_CHAN(insn->chanspec);
989 unsigned int mask;
990 int ret;
991
992 if (chan < 8)
993 mask = 0x00ff;
994 else
995 mask = 0xff00;
996
997 ret = comedi_dio_insn_config(dev, s, insn, data, mask);
998 if (ret)
999 return ret;
1000
1001 devpriv->dacsr &= ~(DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
1002 if (s->io_bits & 0x00ff)
1003 devpriv->dacsr |= DT2821_DACSR_LBOE;
1004 if (s->io_bits & 0xff00)
1005 devpriv->dacsr |= DT2821_DACSR_HBOE;
1006
1007 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
1008
1009 return insn->n;
1010}
1011
1012static const struct comedi_lrange *const ai_range_table[] = {
1013 &range_dt282x_ai_lo_bipolar,
1014 &range_dt282x_ai_lo_unipolar,
1015 &range_dt282x_ai_5_bipolar,
1016 &range_dt282x_ai_5_unipolar
1017};
1018
1019static const struct comedi_lrange *const ai_range_pgl_table[] = {
1020 &range_dt282x_ai_hi_bipolar,
1021 &range_dt282x_ai_hi_unipolar
1022};
1023
1024static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1025{
1026 if (ispgl) {
1027 if (x < 0 || x >= 2)
1028 x = 0;
1029 return ai_range_pgl_table[x];
1030 }
1031
1032 if (x < 0 || x >= 4)
1033 x = 0;
1034 return ai_range_table[x];
1035}
1036
1037static void dt282x_alloc_dma(struct comedi_device *dev,
1038 struct comedi_devconfig *it)
1039{
1040 struct dt282x_private *devpriv = dev->private;
1041 unsigned int irq_num = it->options[1];
1042 unsigned int dma_chan[2];
1043
1044 if (it->options[2] < it->options[3]) {
1045 dma_chan[0] = it->options[2];
1046 dma_chan[1] = it->options[3];
1047 } else {
1048 dma_chan[0] = it->options[3];
1049 dma_chan[1] = it->options[2];
1050 }
1051
1052 if (!irq_num || dma_chan[0] == dma_chan[1] ||
1053 dma_chan[0] < 5 || dma_chan[0] > 7 ||
1054 dma_chan[1] < 5 || dma_chan[1] > 7)
1055 return;
1056
1057 if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev))
1058 return;
1059
1060
1061 devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1],
1062 PAGE_SIZE, 0);
1063 if (!devpriv->dma)
1064 free_irq(irq_num, dev);
1065}
1066
1067static void dt282x_free_dma(struct comedi_device *dev)
1068{
1069 struct dt282x_private *devpriv = dev->private;
1070
1071 if (devpriv)
1072 comedi_isadma_free(devpriv->dma);
1073}
1074
1075static int dt282x_initialize(struct comedi_device *dev)
1076{
1077
1078 outw(DT2821_SUPCSR_BDINIT, dev->iobase + DT2821_SUPCSR_REG);
1079 inw(dev->iobase + DT2821_ADCSR_REG);
1080
1081
1082
1083
1084
1085 if (((inw(dev->iobase + DT2821_ADCSR_REG) & 0xfff0) != 0x7c00) ||
1086 ((inw(dev->iobase + DT2821_CHANCSR_REG) & 0xf0f0) != 0x70f0) ||
1087 ((inw(dev->iobase + DT2821_DACSR_REG) & 0x7c93) != 0x7c90) ||
1088 ((inw(dev->iobase + DT2821_SUPCSR_REG) & 0xf8ff) != 0x0000) ||
1089 ((inw(dev->iobase + DT2821_TMRCTR_REG) & 0xff00) != 0xf000)) {
1090 dev_err(dev->class_dev, "board not found\n");
1091 return -EIO;
1092 }
1093 return 0;
1094}
1095
1096static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1097{
1098 const struct dt282x_board *board = dev->board_ptr;
1099 struct dt282x_private *devpriv;
1100 struct comedi_subdevice *s;
1101 int ret;
1102
1103 ret = comedi_request_region(dev, it->options[0], 0x10);
1104 if (ret)
1105 return ret;
1106
1107 ret = dt282x_initialize(dev);
1108 if (ret)
1109 return ret;
1110
1111 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1112 if (!devpriv)
1113 return -ENOMEM;
1114
1115
1116 dt282x_alloc_dma(dev, it);
1117
1118 ret = comedi_alloc_subdevices(dev, 3);
1119 if (ret)
1120 return ret;
1121
1122
1123 s = &dev->subdevices[0];
1124 s->type = COMEDI_SUBD_AI;
1125 s->subdev_flags = SDF_READABLE;
1126 if ((it->options[4] && board->adchan_di) || board->adchan_se == 0) {
1127 s->subdev_flags |= SDF_DIFF;
1128 s->n_chan = board->adchan_di;
1129 } else {
1130 s->subdev_flags |= SDF_COMMON;
1131 s->n_chan = board->adchan_se;
1132 }
1133 s->maxdata = board->ai_maxdata;
1134
1135 s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]);
1136 devpriv->ad_2scomp = it->options[5] ? 1 : 0;
1137
1138 s->insn_read = dt282x_ai_insn_read;
1139 if (dev->irq) {
1140 dev->read_subdev = s;
1141 s->subdev_flags |= SDF_CMD_READ;
1142 s->len_chanlist = s->n_chan;
1143 s->do_cmdtest = dt282x_ai_cmdtest;
1144 s->do_cmd = dt282x_ai_cmd;
1145 s->cancel = dt282x_ai_cancel;
1146 }
1147
1148
1149 s = &dev->subdevices[1];
1150 if (board->dachan) {
1151 s->type = COMEDI_SUBD_AO;
1152 s->subdev_flags = SDF_WRITABLE;
1153 s->n_chan = board->dachan;
1154 s->maxdata = board->ao_maxdata;
1155
1156 s->range_table = &dt282x_ao_range;
1157 s->insn_write = dt282x_ao_insn_write;
1158 if (dev->irq) {
1159 dev->write_subdev = s;
1160 s->subdev_flags |= SDF_CMD_WRITE;
1161 s->len_chanlist = s->n_chan;
1162 s->do_cmdtest = dt282x_ao_cmdtest;
1163 s->do_cmd = dt282x_ao_cmd;
1164 s->cancel = dt282x_ao_cancel;
1165 }
1166
1167 ret = comedi_alloc_subdev_readback(s);
1168 if (ret)
1169 return ret;
1170 } else {
1171 s->type = COMEDI_SUBD_UNUSED;
1172 }
1173
1174
1175 s = &dev->subdevices[2];
1176 s->type = COMEDI_SUBD_DIO;
1177 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1178 s->n_chan = 16;
1179 s->maxdata = 1;
1180 s->range_table = &range_digital;
1181 s->insn_bits = dt282x_dio_insn_bits;
1182 s->insn_config = dt282x_dio_insn_config;
1183
1184 return 0;
1185}
1186
1187static void dt282x_detach(struct comedi_device *dev)
1188{
1189 dt282x_free_dma(dev);
1190 comedi_legacy_detach(dev);
1191}
1192
1193static struct comedi_driver dt282x_driver = {
1194 .driver_name = "dt282x",
1195 .module = THIS_MODULE,
1196 .attach = dt282x_attach,
1197 .detach = dt282x_detach,
1198 .board_name = &boardtypes[0].name,
1199 .num_names = ARRAY_SIZE(boardtypes),
1200 .offset = sizeof(struct dt282x_board),
1201};
1202module_comedi_driver(dt282x_driver);
1203
1204MODULE_AUTHOR("Comedi http://www.comedi.org");
1205MODULE_DESCRIPTION("Comedi driver for Data Translation DT2821 series");
1206MODULE_LICENSE("GPL");
1207