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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96#include <linux/module.h>
97#include <linux/interrupt.h>
98#include <linux/slab.h>
99
100#include "../comedi_pci.h"
101
102#include "comedi_8254.h"
103
104
105
106
107#define PCI224_Z2_BASE 0x14
108#define PCI224_ZCLK_SCE 0x1A
109#define PCI224_ZGAT_SCE 0x1D
110#define PCI224_INT_SCE 0x1E
111
112
113
114
115
116#define PCI224_DACDATA 0x00
117#define PCI224_SOFTTRIG 0x00
118#define PCI224_DACCON 0x02
119#define PCI224_FIFOSIZ 0x04
120#define PCI224_DACCEN 0x06
121
122
123
124
125
126#define PCI224_DACCON_TRIG(x) (((x) & 0x7) << 0)
127#define PCI224_DACCON_TRIG_MASK PCI224_DACCON_TRIG(7)
128#define PCI224_DACCON_TRIG_NONE PCI224_DACCON_TRIG(0)
129#define PCI224_DACCON_TRIG_SW PCI224_DACCON_TRIG(1)
130#define PCI224_DACCON_TRIG_EXTP PCI224_DACCON_TRIG(2)
131#define PCI224_DACCON_TRIG_EXTN PCI224_DACCON_TRIG(3)
132#define PCI224_DACCON_TRIG_Z2CT0 PCI224_DACCON_TRIG(4)
133#define PCI224_DACCON_TRIG_Z2CT1 PCI224_DACCON_TRIG(5)
134#define PCI224_DACCON_TRIG_Z2CT2 PCI224_DACCON_TRIG(6)
135
136#define PCI224_DACCON_POLAR(x) (((x) & 0x1) << 3)
137#define PCI224_DACCON_POLAR_MASK PCI224_DACCON_POLAR(1)
138#define PCI224_DACCON_POLAR_UNI PCI224_DACCON_POLAR(0)
139#define PCI224_DACCON_POLAR_BI PCI224_DACCON_POLAR(1)
140
141#define PCI224_DACCON_VREF(x) (((x) & 0x3) << 4)
142#define PCI224_DACCON_VREF_MASK PCI224_DACCON_VREF(3)
143#define PCI224_DACCON_VREF_1_25 PCI224_DACCON_VREF(0)
144#define PCI224_DACCON_VREF_2_5 PCI224_DACCON_VREF(1)
145#define PCI224_DACCON_VREF_5 PCI224_DACCON_VREF(2)
146#define PCI224_DACCON_VREF_10 PCI224_DACCON_VREF(3)
147
148#define PCI224_DACCON_FIFOWRAP BIT(7)
149
150#define PCI224_DACCON_FIFOENAB BIT(8)
151
152#define PCI224_DACCON_FIFOINTR(x) (((x) & 0x7) << 9)
153#define PCI224_DACCON_FIFOINTR_MASK PCI224_DACCON_FIFOINTR(7)
154#define PCI224_DACCON_FIFOINTR_EMPTY PCI224_DACCON_FIFOINTR(0)
155#define PCI224_DACCON_FIFOINTR_NEMPTY PCI224_DACCON_FIFOINTR(1)
156#define PCI224_DACCON_FIFOINTR_NHALF PCI224_DACCON_FIFOINTR(2)
157#define PCI224_DACCON_FIFOINTR_HALF PCI224_DACCON_FIFOINTR(3)
158#define PCI224_DACCON_FIFOINTR_NFULL PCI224_DACCON_FIFOINTR(4)
159#define PCI224_DACCON_FIFOINTR_FULL PCI224_DACCON_FIFOINTR(5)
160
161#define PCI224_DACCON_FIFOFL(x) (((x) & 0x7) << 12)
162#define PCI224_DACCON_FIFOFL_MASK PCI224_DACCON_FIFOFL(7)
163#define PCI224_DACCON_FIFOFL_EMPTY PCI224_DACCON_FIFOFL(1)
164#define PCI224_DACCON_FIFOFL_ONETOHALF PCI224_DACCON_FIFOFL(0)
165#define PCI224_DACCON_FIFOFL_HALFTOFULL PCI224_DACCON_FIFOFL(4)
166#define PCI224_DACCON_FIFOFL_FULL PCI224_DACCON_FIFOFL(6)
167
168#define PCI224_DACCON_BUSY BIT(15)
169
170#define PCI224_DACCON_FIFORESET BIT(12)
171
172#define PCI224_DACCON_GLOBALRESET BIT(13)
173
174
175
176
177#define PCI224_FIFO_SIZE 4096
178
179
180
181
182
183
184#define PCI224_FIFO_ROOM_EMPTY PCI224_FIFO_SIZE
185#define PCI224_FIFO_ROOM_ONETOHALF (PCI224_FIFO_SIZE / 2)
186#define PCI224_FIFO_ROOM_HALFTOFULL 1
187#define PCI224_FIFO_ROOM_FULL 0
188
189
190
191
192#define CLK_CLK 0
193#define CLK_10MHZ 1
194#define CLK_1MHZ 2
195#define CLK_100KHZ 3
196#define CLK_10KHZ 4
197#define CLK_1KHZ 5
198#define CLK_OUTNM1 6
199#define CLK_EXT 7
200
201static unsigned int pci224_clk_config(unsigned int chan, unsigned int src)
202{
203 return ((chan & 3) << 3) | (src & 7);
204}
205
206
207
208
209#define GAT_VCC 0
210#define GAT_GND 1
211#define GAT_EXT 2
212#define GAT_NOUTNM2 3
213
214static unsigned int pci224_gat_config(unsigned int chan, unsigned int src)
215{
216 return ((chan & 3) << 3) | (src & 7);
217}
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234#define PCI224_INTR_EXT 0x01
235#define PCI224_INTR_DAC 0x04
236#define PCI224_INTR_Z2CT1 0x20
237
238#define PCI224_INTR_EDGE_BITS (PCI224_INTR_EXT | PCI224_INTR_Z2CT1)
239#define PCI224_INTR_LEVEL_BITS PCI224_INTR_DACFIFO
240
241
242
243
244
245
246#define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
247
248
249#define THISCPU smp_processor_id()
250
251
252#define AO_CMD_STARTED 0
253
254
255
256
257
258
259
260
261
262
263
264
265
266static const struct comedi_lrange range_pci224 = {
267 10, {
268
269 BIP_RANGE(10),
270 BIP_RANGE(5),
271 BIP_RANGE(2.5),
272 BIP_RANGE(1.25),
273 UNI_RANGE(10),
274 UNI_RANGE(5),
275 UNI_RANGE(2.5),
276 UNI_RANGE(1.25),
277
278 RANGE_ext(-1, 1),
279 RANGE_ext(0, 1),
280 }
281};
282
283static const unsigned short hwrange_pci224[10] = {
284
285 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_10,
286 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_5,
287 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_2_5,
288 PCI224_DACCON_POLAR_BI | PCI224_DACCON_VREF_1_25,
289 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_10,
290 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_5,
291 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_2_5,
292 PCI224_DACCON_POLAR_UNI | PCI224_DACCON_VREF_1_25,
293
294 PCI224_DACCON_POLAR_BI,
295 PCI224_DACCON_POLAR_UNI,
296};
297
298
299static const unsigned char range_check_pci224[10] = {
300 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
301};
302
303
304
305
306
307
308
309
310static const struct comedi_lrange range_pci234 = {
311 4, {
312
313 BIP_RANGE(10),
314
315 BIP_RANGE(5),
316
317 RANGE_ext(-2, 2),
318
319 RANGE_ext(-1, 1),
320 }
321};
322
323
324static const unsigned short hwrange_pci234[4] = {
325 PCI224_DACCON_POLAR_BI,
326 PCI224_DACCON_POLAR_BI,
327 PCI224_DACCON_POLAR_BI,
328 PCI224_DACCON_POLAR_BI,
329};
330
331
332static const unsigned char range_check_pci234[4] = {
333 0, 0, 1, 1,
334};
335
336
337
338
339
340enum pci224_model { pci224_model, pci234_model };
341
342struct pci224_board {
343 const char *name;
344 unsigned int ao_chans;
345 unsigned int ao_bits;
346 const struct comedi_lrange *ao_range;
347 const unsigned short *ao_hwrange;
348 const unsigned char *ao_range_check;
349};
350
351static const struct pci224_board pci224_boards[] = {
352 [pci224_model] = {
353 .name = "pci224",
354 .ao_chans = 16,
355 .ao_bits = 12,
356 .ao_range = &range_pci224,
357 .ao_hwrange = &hwrange_pci224[0],
358 .ao_range_check = &range_check_pci224[0],
359 },
360 [pci234_model] = {
361 .name = "pci234",
362 .ao_chans = 4,
363 .ao_bits = 16,
364 .ao_range = &range_pci234,
365 .ao_hwrange = &hwrange_pci234[0],
366 .ao_range_check = &range_check_pci234[0],
367 },
368};
369
370struct pci224_private {
371 unsigned long iobase1;
372 unsigned long state;
373 spinlock_t ao_spinlock;
374 unsigned short *ao_scan_vals;
375 unsigned char *ao_scan_order;
376 int intr_cpuid;
377 short intr_running;
378 unsigned short daccon;
379 unsigned short ao_enab;
380 unsigned char intsce;
381};
382
383
384
385
386static void
387pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
388 unsigned int data)
389{
390 const struct pci224_board *board = dev->board_ptr;
391 struct pci224_private *devpriv = dev->private;
392 unsigned short mangled;
393
394
395 outw(1 << chan, dev->iobase + PCI224_DACCEN);
396
397 devpriv->daccon = COMBINE(devpriv->daccon, board->ao_hwrange[range],
398 PCI224_DACCON_POLAR_MASK |
399 PCI224_DACCON_VREF_MASK);
400 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
401 dev->iobase + PCI224_DACCON);
402
403
404
405
406
407 mangled = (unsigned short)data << (16 - board->ao_bits);
408 if ((devpriv->daccon & PCI224_DACCON_POLAR_MASK) ==
409 PCI224_DACCON_POLAR_BI) {
410 mangled ^= 0x8000;
411 }
412
413 outw(mangled, dev->iobase + PCI224_DACDATA);
414
415 inw(dev->iobase + PCI224_SOFTTRIG);
416}
417
418static int pci224_ao_insn_write(struct comedi_device *dev,
419 struct comedi_subdevice *s,
420 struct comedi_insn *insn,
421 unsigned int *data)
422{
423 unsigned int chan = CR_CHAN(insn->chanspec);
424 unsigned int range = CR_RANGE(insn->chanspec);
425 unsigned int val = s->readback[chan];
426 int i;
427
428 for (i = 0; i < insn->n; i++) {
429 val = data[i];
430 pci224_ao_set_data(dev, chan, range, val);
431 }
432 s->readback[chan] = val;
433
434 return insn->n;
435}
436
437
438
439
440static void pci224_ao_stop(struct comedi_device *dev,
441 struct comedi_subdevice *s)
442{
443 struct pci224_private *devpriv = dev->private;
444 unsigned long flags;
445
446 if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state))
447 return;
448
449 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
450
451 devpriv->intsce = 0;
452 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
453
454
455
456
457
458
459
460
461
462
463
464 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
465 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
466 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
467 }
468 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
469
470 outw(0, dev->iobase + PCI224_DACCEN);
471 devpriv->daccon =
472 COMBINE(devpriv->daccon,
473 PCI224_DACCON_TRIG_SW | PCI224_DACCON_FIFOINTR_EMPTY,
474 PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
475 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
476 dev->iobase + PCI224_DACCON);
477}
478
479
480
481
482static void pci224_ao_start(struct comedi_device *dev,
483 struct comedi_subdevice *s)
484{
485 struct pci224_private *devpriv = dev->private;
486 struct comedi_cmd *cmd = &s->async->cmd;
487 unsigned long flags;
488
489 set_bit(AO_CMD_STARTED, &devpriv->state);
490
491
492 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
493 if (cmd->stop_src == TRIG_EXT)
494 devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC;
495 else
496 devpriv->intsce = PCI224_INTR_DAC;
497
498 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
499 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
500}
501
502
503
504
505static void pci224_ao_handle_fifo(struct comedi_device *dev,
506 struct comedi_subdevice *s)
507{
508 struct pci224_private *devpriv = dev->private;
509 struct comedi_cmd *cmd = &s->async->cmd;
510 unsigned int num_scans = comedi_nscans_left(s, 0);
511 unsigned int room;
512 unsigned short dacstat;
513 unsigned int i, n;
514
515
516 dacstat = inw(dev->iobase + PCI224_DACCON);
517 switch (dacstat & PCI224_DACCON_FIFOFL_MASK) {
518 case PCI224_DACCON_FIFOFL_EMPTY:
519 room = PCI224_FIFO_ROOM_EMPTY;
520 if (cmd->stop_src == TRIG_COUNT &&
521 s->async->scans_done >= cmd->stop_arg) {
522
523 s->async->events |= COMEDI_CB_EOA;
524 comedi_handle_events(dev, s);
525 return;
526 }
527 break;
528 case PCI224_DACCON_FIFOFL_ONETOHALF:
529 room = PCI224_FIFO_ROOM_ONETOHALF;
530 break;
531 case PCI224_DACCON_FIFOFL_HALFTOFULL:
532 room = PCI224_FIFO_ROOM_HALFTOFULL;
533 break;
534 default:
535 room = PCI224_FIFO_ROOM_FULL;
536 break;
537 }
538 if (room >= PCI224_FIFO_ROOM_ONETOHALF) {
539
540 if (num_scans == 0) {
541
542 dev_err(dev->class_dev, "AO buffer underrun\n");
543 s->async->events |= COMEDI_CB_OVERFLOW;
544 }
545 }
546
547 room /= cmd->chanlist_len;
548
549
550 if (num_scans > room)
551 num_scans = room;
552
553
554 for (n = 0; n < num_scans; n++) {
555 comedi_buf_read_samples(s, &devpriv->ao_scan_vals[0],
556 cmd->chanlist_len);
557 for (i = 0; i < cmd->chanlist_len; i++) {
558 outw(devpriv->ao_scan_vals[devpriv->ao_scan_order[i]],
559 dev->iobase + PCI224_DACDATA);
560 }
561 }
562 if (cmd->stop_src == TRIG_COUNT &&
563 s->async->scans_done >= cmd->stop_arg) {
564
565
566
567
568 devpriv->daccon = COMBINE(devpriv->daccon,
569 PCI224_DACCON_FIFOINTR_EMPTY,
570 PCI224_DACCON_FIFOINTR_MASK);
571 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
572 }
573 if ((devpriv->daccon & PCI224_DACCON_TRIG_MASK) ==
574 PCI224_DACCON_TRIG_NONE) {
575 unsigned short trig;
576
577
578
579
580
581
582
583
584
585
586
587
588
589 if (cmd->scan_begin_src == TRIG_TIMER) {
590 trig = PCI224_DACCON_TRIG_Z2CT0;
591 } else {
592
593 if (cmd->scan_begin_arg & CR_INVERT)
594 trig = PCI224_DACCON_TRIG_EXTN;
595 else
596 trig = PCI224_DACCON_TRIG_EXTP;
597 }
598 devpriv->daccon =
599 COMBINE(devpriv->daccon, trig, PCI224_DACCON_TRIG_MASK);
600 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
601 }
602
603 comedi_handle_events(dev, s);
604}
605
606static int pci224_ao_inttrig_start(struct comedi_device *dev,
607 struct comedi_subdevice *s,
608 unsigned int trig_num)
609{
610 struct comedi_cmd *cmd = &s->async->cmd;
611
612 if (trig_num != cmd->start_arg)
613 return -EINVAL;
614
615 s->async->inttrig = NULL;
616 pci224_ao_start(dev, s);
617
618 return 1;
619}
620
621static int pci224_ao_check_chanlist(struct comedi_device *dev,
622 struct comedi_subdevice *s,
623 struct comedi_cmd *cmd)
624{
625 const struct pci224_board *board = dev->board_ptr;
626 unsigned int range_check_0;
627 unsigned int chan_mask = 0;
628 int i;
629
630 range_check_0 = board->ao_range_check[CR_RANGE(cmd->chanlist[0])];
631 for (i = 0; i < cmd->chanlist_len; i++) {
632 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
633
634 if (chan_mask & (1 << chan)) {
635 dev_dbg(dev->class_dev,
636 "%s: entries in chanlist must contain no duplicate channels\n",
637 __func__);
638 return -EINVAL;
639 }
640 chan_mask |= 1 << chan;
641
642 if (board->ao_range_check[CR_RANGE(cmd->chanlist[i])] !=
643 range_check_0) {
644 dev_dbg(dev->class_dev,
645 "%s: entries in chanlist have incompatible ranges\n",
646 __func__);
647 return -EINVAL;
648 }
649 }
650
651 return 0;
652}
653
654#define MAX_SCAN_PERIOD 0xFFFFFFFFU
655#define MIN_SCAN_PERIOD 2500
656#define CONVERT_PERIOD 625
657
658
659
660
661static int
662pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
663 struct comedi_cmd *cmd)
664{
665 int err = 0;
666 unsigned int arg;
667
668
669
670 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT);
671 err |= comedi_check_trigger_src(&cmd->scan_begin_src,
672 TRIG_EXT | TRIG_TIMER);
673 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
674 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
675 err |= comedi_check_trigger_src(&cmd->stop_src,
676 TRIG_COUNT | TRIG_EXT | TRIG_NONE);
677
678 if (err)
679 return 1;
680
681
682
683 err |= comedi_check_trigger_is_unique(cmd->start_src);
684 err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
685 err |= comedi_check_trigger_is_unique(cmd->stop_src);
686
687
688
689
690
691
692
693 arg = 0;
694 if (cmd->start_src & TRIG_EXT)
695 arg++;
696 if (cmd->scan_begin_src & TRIG_EXT)
697 arg++;
698 if (cmd->stop_src & TRIG_EXT)
699 arg++;
700 if (arg > 1)
701 err |= -EINVAL;
702
703 if (err)
704 return 2;
705
706
707
708 switch (cmd->start_src) {
709 case TRIG_INT:
710 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
711 break;
712 case TRIG_EXT:
713
714 if (cmd->start_arg & ~CR_FLAGS_MASK) {
715 cmd->start_arg =
716 COMBINE(cmd->start_arg, 0, ~CR_FLAGS_MASK);
717 err |= -EINVAL;
718 }
719
720 if (cmd->start_arg & CR_FLAGS_MASK & ~CR_EDGE) {
721 cmd->start_arg = COMBINE(cmd->start_arg, 0,
722 CR_FLAGS_MASK & ~CR_EDGE);
723 err |= -EINVAL;
724 }
725 break;
726 }
727
728 switch (cmd->scan_begin_src) {
729 case TRIG_TIMER:
730 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
731 MAX_SCAN_PERIOD);
732
733 arg = cmd->chanlist_len * CONVERT_PERIOD;
734 if (arg < MIN_SCAN_PERIOD)
735 arg = MIN_SCAN_PERIOD;
736 err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, arg);
737 break;
738 case TRIG_EXT:
739
740 if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) {
741 cmd->scan_begin_arg =
742 COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK);
743 err |= -EINVAL;
744 }
745
746 if (cmd->scan_begin_arg & CR_FLAGS_MASK &
747 ~(CR_EDGE | CR_INVERT)) {
748 cmd->scan_begin_arg =
749 COMBINE(cmd->scan_begin_arg, 0,
750 CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
751 err |= -EINVAL;
752 }
753 break;
754 }
755
756 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
757 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
758 cmd->chanlist_len);
759
760 switch (cmd->stop_src) {
761 case TRIG_COUNT:
762 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
763 break;
764 case TRIG_EXT:
765
766 if (cmd->stop_arg & ~CR_FLAGS_MASK) {
767 cmd->stop_arg =
768 COMBINE(cmd->stop_arg, 0, ~CR_FLAGS_MASK);
769 err |= -EINVAL;
770 }
771
772 if (cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) {
773 cmd->stop_arg =
774 COMBINE(cmd->stop_arg, 0, CR_FLAGS_MASK & ~CR_EDGE);
775 }
776 break;
777 case TRIG_NONE:
778 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
779 break;
780 }
781
782 if (err)
783 return 3;
784
785
786
787 if (cmd->scan_begin_src == TRIG_TIMER) {
788 arg = cmd->scan_begin_arg;
789
790 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
791 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
792 }
793
794 if (err)
795 return 4;
796
797
798 if (cmd->chanlist && cmd->chanlist_len > 0)
799 err |= pci224_ao_check_chanlist(dev, s, cmd);
800
801 if (err)
802 return 5;
803
804 return 0;
805}
806
807static void pci224_ao_start_pacer(struct comedi_device *dev,
808 struct comedi_subdevice *s)
809{
810 struct pci224_private *devpriv = dev->private;
811
812
813
814
815
816
817 outb(pci224_gat_config(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
818
819
820 outb(pci224_gat_config(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
821
822 outb(pci224_clk_config(2, CLK_10MHZ),
823 devpriv->iobase1 + PCI224_ZCLK_SCE);
824
825 outb(pci224_clk_config(0, CLK_OUTNM1),
826 devpriv->iobase1 + PCI224_ZCLK_SCE);
827
828 comedi_8254_pacer_enable(dev->pacer, 2, 0, false);
829}
830
831static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
832{
833 const struct pci224_board *board = dev->board_ptr;
834 struct pci224_private *devpriv = dev->private;
835 struct comedi_cmd *cmd = &s->async->cmd;
836 int range;
837 unsigned int i, j;
838 unsigned int ch;
839 unsigned int rank;
840 unsigned long flags;
841
842
843 if (!cmd->chanlist || cmd->chanlist_len == 0)
844 return -EINVAL;
845
846
847 devpriv->ao_enab = 0;
848
849 for (i = 0; i < cmd->chanlist_len; i++) {
850 ch = CR_CHAN(cmd->chanlist[i]);
851 devpriv->ao_enab |= 1U << ch;
852 rank = 0;
853 for (j = 0; j < cmd->chanlist_len; j++) {
854 if (CR_CHAN(cmd->chanlist[j]) < ch)
855 rank++;
856 }
857 devpriv->ao_scan_order[rank] = i;
858 }
859
860
861 outw(devpriv->ao_enab, dev->iobase + PCI224_DACCEN);
862
863
864 range = CR_RANGE(cmd->chanlist[0]);
865
866
867
868
869
870
871
872
873
874 devpriv->daccon =
875 COMBINE(devpriv->daccon,
876 board->ao_hwrange[range] | PCI224_DACCON_TRIG_NONE |
877 PCI224_DACCON_FIFOINTR_NHALF,
878 PCI224_DACCON_POLAR_MASK | PCI224_DACCON_VREF_MASK |
879 PCI224_DACCON_TRIG_MASK | PCI224_DACCON_FIFOINTR_MASK);
880 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
881 dev->iobase + PCI224_DACCON);
882
883 if (cmd->scan_begin_src == TRIG_TIMER) {
884 comedi_8254_update_divisors(dev->pacer);
885 pci224_ao_start_pacer(dev, s);
886 }
887
888 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
889 if (cmd->start_src == TRIG_INT) {
890 s->async->inttrig = pci224_ao_inttrig_start;
891 } else {
892
893 devpriv->intsce |= PCI224_INTR_EXT;
894 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
895 }
896 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
897
898 return 0;
899}
900
901
902
903
904static int pci224_ao_cancel(struct comedi_device *dev,
905 struct comedi_subdevice *s)
906{
907 pci224_ao_stop(dev, s);
908 return 0;
909}
910
911
912
913
914static void
915pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
916 void *data, unsigned int num_bytes, unsigned int chan_index)
917{
918 const struct pci224_board *board = dev->board_ptr;
919 struct comedi_cmd *cmd = &s->async->cmd;
920 unsigned short *array = data;
921 unsigned int length = num_bytes / sizeof(*array);
922 unsigned int offset;
923 unsigned int shift;
924 unsigned int i;
925
926
927 shift = 16 - board->ao_bits;
928
929 if ((board->ao_hwrange[CR_RANGE(cmd->chanlist[0])] &
930 PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) {
931
932 offset = 0;
933 } else {
934
935 offset = 32768;
936 }
937
938 for (i = 0; i < length; i++)
939 array[i] = (array[i] << shift) - offset;
940}
941
942
943
944
945static irqreturn_t pci224_interrupt(int irq, void *d)
946{
947 struct comedi_device *dev = d;
948 struct pci224_private *devpriv = dev->private;
949 struct comedi_subdevice *s = dev->write_subdev;
950 struct comedi_cmd *cmd;
951 unsigned char intstat, valid_intstat;
952 unsigned char curenab;
953 int retval = 0;
954 unsigned long flags;
955
956 intstat = inb(devpriv->iobase1 + PCI224_INT_SCE) & 0x3F;
957 if (intstat) {
958 retval = 1;
959 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
960 valid_intstat = devpriv->intsce & intstat;
961
962 curenab = devpriv->intsce & ~intstat;
963 outb(curenab, devpriv->iobase1 + PCI224_INT_SCE);
964 devpriv->intr_running = 1;
965 devpriv->intr_cpuid = THISCPU;
966 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
967 if (valid_intstat) {
968 cmd = &s->async->cmd;
969 if (valid_intstat & PCI224_INTR_EXT) {
970 devpriv->intsce &= ~PCI224_INTR_EXT;
971 if (cmd->start_src == TRIG_EXT)
972 pci224_ao_start(dev, s);
973 else if (cmd->stop_src == TRIG_EXT)
974 pci224_ao_stop(dev, s);
975 }
976 if (valid_intstat & PCI224_INTR_DAC)
977 pci224_ao_handle_fifo(dev, s);
978 }
979
980 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
981 if (curenab != devpriv->intsce) {
982 outb(devpriv->intsce,
983 devpriv->iobase1 + PCI224_INT_SCE);
984 }
985 devpriv->intr_running = 0;
986 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
987 }
988 return IRQ_RETVAL(retval);
989}
990
991static int
992pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
993{
994 struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
995 const struct pci224_board *board = NULL;
996 struct pci224_private *devpriv;
997 struct comedi_subdevice *s;
998 unsigned int irq;
999 int ret;
1000
1001 if (context_model < ARRAY_SIZE(pci224_boards))
1002 board = &pci224_boards[context_model];
1003 if (!board || !board->name) {
1004 dev_err(dev->class_dev,
1005 "amplc_pci224: BUG! cannot determine board type!\n");
1006 return -EINVAL;
1007 }
1008 dev->board_ptr = board;
1009 dev->board_name = board->name;
1010
1011 dev_info(dev->class_dev, "amplc_pci224: attach pci %s - %s\n",
1012 pci_name(pci_dev), dev->board_name);
1013
1014 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1015 if (!devpriv)
1016 return -ENOMEM;
1017
1018 ret = comedi_pci_enable(dev);
1019 if (ret)
1020 return ret;
1021
1022 spin_lock_init(&devpriv->ao_spinlock);
1023
1024 devpriv->iobase1 = pci_resource_start(pci_dev, 2);
1025 dev->iobase = pci_resource_start(pci_dev, 3);
1026 irq = pci_dev->irq;
1027
1028
1029 devpriv->ao_scan_vals = kmalloc_array(board->ao_chans,
1030 sizeof(devpriv->ao_scan_vals[0]),
1031 GFP_KERNEL);
1032 if (!devpriv->ao_scan_vals)
1033 return -ENOMEM;
1034
1035
1036 devpriv->ao_scan_order =
1037 kmalloc_array(board->ao_chans,
1038 sizeof(devpriv->ao_scan_order[0]),
1039 GFP_KERNEL);
1040 if (!devpriv->ao_scan_order)
1041 return -ENOMEM;
1042
1043
1044 devpriv->intsce = 0;
1045 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
1046
1047
1048 outw(PCI224_DACCON_GLOBALRESET, dev->iobase + PCI224_DACCON);
1049 outw(0, dev->iobase + PCI224_DACCEN);
1050 outw(0, dev->iobase + PCI224_FIFOSIZ);
1051 devpriv->daccon = PCI224_DACCON_TRIG_SW | PCI224_DACCON_POLAR_BI |
1052 PCI224_DACCON_FIFOENAB | PCI224_DACCON_FIFOINTR_EMPTY;
1053 outw(devpriv->daccon | PCI224_DACCON_FIFORESET,
1054 dev->iobase + PCI224_DACCON);
1055
1056 dev->pacer = comedi_8254_init(devpriv->iobase1 + PCI224_Z2_BASE,
1057 I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
1058 if (!dev->pacer)
1059 return -ENOMEM;
1060
1061 ret = comedi_alloc_subdevices(dev, 1);
1062 if (ret)
1063 return ret;
1064
1065 s = &dev->subdevices[0];
1066
1067 s->type = COMEDI_SUBD_AO;
1068 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE;
1069 s->n_chan = board->ao_chans;
1070 s->maxdata = (1 << board->ao_bits) - 1;
1071 s->range_table = board->ao_range;
1072 s->insn_write = pci224_ao_insn_write;
1073 s->len_chanlist = s->n_chan;
1074 dev->write_subdev = s;
1075 s->do_cmd = pci224_ao_cmd;
1076 s->do_cmdtest = pci224_ao_cmdtest;
1077 s->cancel = pci224_ao_cancel;
1078 s->munge = pci224_ao_munge;
1079
1080 ret = comedi_alloc_subdev_readback(s);
1081 if (ret)
1082 return ret;
1083
1084 if (irq) {
1085 ret = request_irq(irq, pci224_interrupt, IRQF_SHARED,
1086 dev->board_name, dev);
1087 if (ret < 0) {
1088 dev_err(dev->class_dev,
1089 "error! unable to allocate irq %u\n", irq);
1090 return ret;
1091 }
1092 dev->irq = irq;
1093 }
1094
1095 return 0;
1096}
1097
1098static void pci224_detach(struct comedi_device *dev)
1099{
1100 struct pci224_private *devpriv = dev->private;
1101
1102 comedi_pci_detach(dev);
1103 if (devpriv) {
1104 kfree(devpriv->ao_scan_vals);
1105 kfree(devpriv->ao_scan_order);
1106 }
1107}
1108
1109static struct comedi_driver amplc_pci224_driver = {
1110 .driver_name = "amplc_pci224",
1111 .module = THIS_MODULE,
1112 .detach = pci224_detach,
1113 .auto_attach = pci224_auto_attach,
1114 .board_name = &pci224_boards[0].name,
1115 .offset = sizeof(struct pci224_board),
1116 .num_names = ARRAY_SIZE(pci224_boards),
1117};
1118
1119static int amplc_pci224_pci_probe(struct pci_dev *dev,
1120 const struct pci_device_id *id)
1121{
1122 return comedi_pci_auto_config(dev, &lc_pci224_driver,
1123 id->driver_data);
1124}
1125
1126static const struct pci_device_id amplc_pci224_pci_table[] = {
1127 { PCI_VDEVICE(AMPLICON, 0x0007), pci224_model },
1128 { PCI_VDEVICE(AMPLICON, 0x0008), pci234_model },
1129 { 0 }
1130};
1131MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
1132
1133static struct pci_driver amplc_pci224_pci_driver = {
1134 .name = "amplc_pci224",
1135 .id_table = amplc_pci224_pci_table,
1136 .probe = amplc_pci224_pci_probe,
1137 .remove = comedi_pci_auto_unconfig,
1138};
1139module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
1140
1141MODULE_AUTHOR("Comedi https://www.comedi.org");
1142MODULE_DESCRIPTION("Comedi driver for Amplicon PCI224 and PCI234 AO boards");
1143MODULE_LICENSE("GPL");
1144