1 // SPDX-License-Identifier: GPL-2.0+
3 * comedi/drivers/amplc_pci224.c
4 * Driver for Amplicon PCI224 and PCI234 AO boards.
6 * Copyright (C) 2005 MEV Ltd. <https://www.mev.co.uk/>
8 * COMEDI - Linux Control and Measurement Device Interface
9 * Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
13 * Driver: amplc_pci224
14 * Description: Amplicon PCI224, PCI234
15 * Author: Ian Abbott <abbotti@mev.co.uk>
16 * Devices: [Amplicon] PCI224 (amplc_pci224), PCI234
17 * Updated: Thu, 31 Jul 2014 11:08:03 +0000
18 * Status: works, but see caveats
22 * - ao_insn read/write
23 * - ao_do_cmd mode with the following sources:
25 * - start_src TRIG_INT TRIG_EXT
26 * - scan_begin_src TRIG_TIMER TRIG_EXT
27 * - convert_src TRIG_NOW
28 * - scan_end_src TRIG_COUNT
29 * - stop_src TRIG_COUNT TRIG_EXT TRIG_NONE
31 * The channel list must contain at least one channel with no repeated
32 * channels. The scan end count must equal the number of channels in
35 * There is only one external trigger source so only one of start_src,
36 * scan_begin_src or stop_src may use TRIG_EXT.
38 * Configuration options:
41 * Manual configuration of PCI cards is not supported; they are configured
44 * Output range selection - PCI224:
46 * Output ranges on PCI224 are partly software-selectable and partly
47 * hardware-selectable according to jumper LK1. All channels are set
50 * - LK1 position 1-2 (factory default) corresponds to the following
53 * 0: [-10V,+10V]; 1: [-5V,+5V]; 2: [-2.5V,+2.5V], 3: [-1.25V,+1.25V],
54 * 4: [0,+10V], 5: [0,+5V], 6: [0,+2.5V], 7: [0,+1.25V]
56 * - LK1 position 2-3 corresponds to the following Comedi ranges, using
57 * an external voltage reference:
62 * Output range selection - PCI234:
64 * Output ranges on PCI234 are hardware-selectable according to jumper
65 * LK1 which affects all channels, and jumpers LK2, LK3, LK4 and LK5
66 * which affect channels 0, 1, 2 and 3 individually. LK1 chooses between
67 * an internal 5V reference and an external voltage reference (Vext).
68 * LK2/3/4/5 choose (per channel) to double the reference or not according
69 * to the following table:
71 * LK1 position LK2/3/4/5 pos Comedi range
72 * ------------- ------------- --------------
73 * 2-3 (factory) 1-2 (factory) 0: [-10V,+10V]
74 * 2-3 (factory) 2-3 1: [-5V,+5V]
75 * 1-2 1-2 (factory) 2: [-2*Vext,+2*Vext]
76 * 1-2 2-3 3: [-Vext,+Vext]
80 * 1) All channels on the PCI224 share the same range. Any change to the
81 * range as a result of insn_write or a streaming command will affect
82 * the output voltages of all channels, including those not specified
83 * by the instruction or command.
85 * 2) For the analog output command, the first scan may be triggered
86 * falsely at the start of acquisition. This occurs when the DAC scan
87 * trigger source is switched from 'none' to 'timer' (scan_begin_src =
88 * TRIG_TIMER) or 'external' (scan_begin_src == TRIG_EXT) at the start
89 * of acquisition and the trigger source is at logic level 1 at the
90 * time of the switch. This is very likely for TRIG_TIMER. For
91 * TRIG_EXT, it depends on the state of the external line and whether
92 * the CR_INVERT flag has been set. The remaining scans are triggered
96 #include <linux/module.h>
97 #include <linux/interrupt.h>
98 #include <linux/slab.h>
100 #include "../comedi_pci.h"
102 #include "comedi_8254.h"
105 * PCI224/234 i/o space 1 (PCIBAR2) registers.
107 #define PCI224_Z2_BASE 0x14 /* 82C54 counter/timer */
108 #define PCI224_ZCLK_SCE 0x1A /* Group Z Clock Configuration Register */
109 #define PCI224_ZGAT_SCE 0x1D /* Group Z Gate Configuration Register */
110 #define PCI224_INT_SCE 0x1E /* ISR Interrupt source mask register */
111 /* /Interrupt status */
114 * PCI224/234 i/o space 2 (PCIBAR3) 16-bit registers.
116 #define PCI224_DACDATA 0x00 /* (w-o) DAC FIFO data. */
117 #define PCI224_SOFTTRIG 0x00 /* (r-o) DAC software scan trigger. */
118 #define PCI224_DACCON 0x02 /* (r/w) DAC status/configuration. */
119 #define PCI224_FIFOSIZ 0x04 /* (w-o) FIFO size for wraparound mode. */
120 #define PCI224_DACCEN 0x06 /* (w-o) DAC channel enable register. */
125 /* (r/w) Scan trigger. */
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) /* none */
129 #define PCI224_DACCON_TRIG_SW PCI224_DACCON_TRIG(1) /* soft trig */
130 #define PCI224_DACCON_TRIG_EXTP PCI224_DACCON_TRIG(2) /* ext + edge */
131 #define PCI224_DACCON_TRIG_EXTN PCI224_DACCON_TRIG(3) /* ext - edge */
132 #define PCI224_DACCON_TRIG_Z2CT0 PCI224_DACCON_TRIG(4) /* Z2 CT0 out */
133 #define PCI224_DACCON_TRIG_Z2CT1 PCI224_DACCON_TRIG(5) /* Z2 CT1 out */
134 #define PCI224_DACCON_TRIG_Z2CT2 PCI224_DACCON_TRIG(6) /* Z2 CT2 out */
135 /* (r/w) Polarity (PCI224 only, PCI234 always bipolar!). */
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) /* [0,+V] */
139 #define PCI224_DACCON_POLAR_BI PCI224_DACCON_POLAR(1) /* [-V,+V] */
140 /* (r/w) Internal Vref (PCI224 only, when LK1 in position 1-2). */
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) /* 1.25V */
144 #define PCI224_DACCON_VREF_2_5 PCI224_DACCON_VREF(1) /* 2.5V */
145 #define PCI224_DACCON_VREF_5 PCI224_DACCON_VREF(2) /* 5V */
146 #define PCI224_DACCON_VREF_10 PCI224_DACCON_VREF(3) /* 10V */
147 /* (r/w) Wraparound mode enable (to play back stored waveform). */
148 #define PCI224_DACCON_FIFOWRAP BIT(7)
149 /* (r/w) FIFO enable. It MUST be set! */
150 #define PCI224_DACCON_FIFOENAB BIT(8)
151 /* (r/w) FIFO interrupt trigger level (most values are not very useful). */
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) /* empty */
155 #define PCI224_DACCON_FIFOINTR_NEMPTY PCI224_DACCON_FIFOINTR(1) /* !empty */
156 #define PCI224_DACCON_FIFOINTR_NHALF PCI224_DACCON_FIFOINTR(2) /* !half */
157 #define PCI224_DACCON_FIFOINTR_HALF PCI224_DACCON_FIFOINTR(3) /* half */
158 #define PCI224_DACCON_FIFOINTR_NFULL PCI224_DACCON_FIFOINTR(4) /* !full */
159 #define PCI224_DACCON_FIFOINTR_FULL PCI224_DACCON_FIFOINTR(5) /* full */
160 /* (r-o) FIFO fill level. */
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) /* 0 */
164 #define PCI224_DACCON_FIFOFL_ONETOHALF PCI224_DACCON_FIFOFL(0) /* 1-2048 */
165 #define PCI224_DACCON_FIFOFL_HALFTOFULL PCI224_DACCON_FIFOFL(4) /* 2049-4095 */
166 #define PCI224_DACCON_FIFOFL_FULL PCI224_DACCON_FIFOFL(6) /* 4096 */
167 /* (r-o) DAC busy flag. */
168 #define PCI224_DACCON_BUSY BIT(15)
169 /* (w-o) FIFO reset. */
170 #define PCI224_DACCON_FIFORESET BIT(12)
171 /* (w-o) Global reset (not sure what it does). */
172 #define PCI224_DACCON_GLOBALRESET BIT(13)
177 #define PCI224_FIFO_SIZE 4096
180 * DAC FIFO guaranteed minimum room available, depending on reported fill level.
181 * The maximum room available depends on the reported fill level and how much
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
190 * Counter/timer clock input configuration sources.
192 #define CLK_CLK 0 /* reserved (channel-specific clock) */
193 #define CLK_10MHZ 1 /* internal 10 MHz clock */
194 #define CLK_1MHZ 2 /* internal 1 MHz clock */
195 #define CLK_100KHZ 3 /* internal 100 kHz clock */
196 #define CLK_10KHZ 4 /* internal 10 kHz clock */
197 #define CLK_1KHZ 5 /* internal 1 kHz clock */
198 #define CLK_OUTNM1 6 /* output of channel-1 modulo total */
199 #define CLK_EXT 7 /* external clock */
201 static unsigned int pci224_clk_config(unsigned int chan, unsigned int src)
203 return ((chan & 3) << 3) | (src & 7);
207 * Counter/timer gate input configuration sources.
209 #define GAT_VCC 0 /* VCC (i.e. enabled) */
210 #define GAT_GND 1 /* GND (i.e. disabled) */
211 #define GAT_EXT 2 /* reserved (external gate input) */
212 #define GAT_NOUTNM2 3 /* inverted output of channel-2 modulo total */
214 static unsigned int pci224_gat_config(unsigned int chan, unsigned int src)
216 return ((chan & 3) << 3) | (src & 7);
220 * Summary of CLK_OUTNM1 and GAT_NOUTNM2 connections for PCI224 and PCI234:
222 * Channel's Channel's
223 * clock input gate input
224 * Channel CLK_OUTNM1 GAT_NOUTNM2
225 * ------- ---------- -----------
226 * Z2-CT0 Z2-CT2-OUT /Z2-CT1-OUT
227 * Z2-CT1 Z2-CT0-OUT /Z2-CT2-OUT
228 * Z2-CT2 Z2-CT1-OUT /Z2-CT0-OUT
232 * Interrupt enable/status bits
234 #define PCI224_INTR_EXT 0x01 /* rising edge on external input */
235 #define PCI224_INTR_DAC 0x04 /* DAC (FIFO) interrupt */
236 #define PCI224_INTR_Z2CT1 0x20 /* rising edge on Z2-CT1 output */
238 #define PCI224_INTR_EDGE_BITS (PCI224_INTR_EXT | PCI224_INTR_Z2CT1)
239 #define PCI224_INTR_LEVEL_BITS PCI224_INTR_DACFIFO
245 /* Combine old and new bits. */
246 #define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
248 /* Current CPU. XXX should this be hard_smp_processor_id()? */
249 #define THISCPU smp_processor_id()
251 /* State bits for use with atomic bit operations. */
252 #define AO_CMD_STARTED 0
259 * The ranges for PCI224.
261 * These are partly hardware-selectable by jumper LK1 and partly
262 * software-selectable.
264 * All channels share the same hardware range.
266 static const struct comedi_lrange range_pci224 = {
268 /* jumper LK1 in position 1-2 (factory default) */
277 /* jumper LK1 in position 2-3 */
278 RANGE_ext(-1, 1), /* bipolar [-Vext,+Vext] */
279 RANGE_ext(0, 1), /* unipolar [0,+Vext] */
283 static const unsigned short hwrange_pci224[10] = {
284 /* jumper LK1 in position 1-2 (factory default) */
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 /* jumper LK1 in position 2-3 */
294 PCI224_DACCON_POLAR_BI,
295 PCI224_DACCON_POLAR_UNI,
298 /* Used to check all channels set to the same range on PCI224. */
299 static const unsigned char range_check_pci224[10] = {
300 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
304 * The ranges for PCI234.
306 * These are all hardware-selectable by jumper LK1 affecting all channels,
307 * and jumpers LK2, LK3, LK4 and LK5 affecting channels 0, 1, 2 and 3
310 static const struct comedi_lrange range_pci234 = {
312 /* LK1: 1-2 (fact def), LK2/3/4/5: 2-3 (fac def) */
314 /* LK1: 1-2 (fact def), LK2/3/4/5: 1-2 */
316 /* LK1: 2-3, LK2/3/4/5: 2-3 (fac def) */
317 RANGE_ext(-2, 2), /* bipolar [-2*Vext,+2*Vext] */
318 /* LK1: 2-3, LK2/3/4/5: 1-2 */
319 RANGE_ext(-1, 1), /* bipolar [-Vext,+Vext] */
323 /* N.B. PCI234 ignores the polarity bit, but software uses it. */
324 static 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,
331 /* Used to check all channels use same LK1 setting on PCI234. */
332 static const unsigned char range_check_pci234[4] = {
337 * Board descriptions.
340 enum pci224_model { pci224_model, pci234_model };
342 struct pci224_board {
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;
351 static const struct pci224_board pci224_boards[] = {
356 .ao_range = &range_pci224,
357 .ao_hwrange = &hwrange_pci224[0],
358 .ao_range_check = &range_check_pci224[0],
364 .ao_range = &range_pci234,
365 .ao_hwrange = &hwrange_pci234[0],
366 .ao_range_check = &range_check_pci234[0],
370 struct pci224_private {
371 unsigned long iobase1;
373 spinlock_t ao_spinlock; /* spinlock for AO command handling */
374 unsigned short *ao_scan_vals;
375 unsigned char *ao_scan_order;
378 unsigned short daccon;
379 unsigned short ao_enab; /* max 16 channels so 'short' will do */
380 unsigned char intsce;
384 * Called from the 'insn_write' function to perform a single write.
387 pci224_ao_set_data(struct comedi_device *dev, int chan, int range,
390 const struct pci224_board *board = dev->board_ptr;
391 struct pci224_private *devpriv = dev->private;
392 unsigned short mangled;
394 /* Enable the channel. */
395 outw(1 << chan, dev->iobase + PCI224_DACCEN);
396 /* Set range and reset FIFO. */
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);
403 * Mangle the data. The hardware expects:
404 * - bipolar: 16-bit 2's complement
405 * - unipolar: 16-bit unsigned
407 mangled = (unsigned short)data << (16 - board->ao_bits);
408 if ((devpriv->daccon & PCI224_DACCON_POLAR_MASK) ==
409 PCI224_DACCON_POLAR_BI) {
412 /* Write mangled data to the FIFO. */
413 outw(mangled, dev->iobase + PCI224_DACDATA);
414 /* Trigger the conversion. */
415 inw(dev->iobase + PCI224_SOFTTRIG);
418 static int pci224_ao_insn_write(struct comedi_device *dev,
419 struct comedi_subdevice *s,
420 struct comedi_insn *insn,
423 unsigned int chan = CR_CHAN(insn->chanspec);
424 unsigned int range = CR_RANGE(insn->chanspec);
425 unsigned int val = s->readback[chan];
428 for (i = 0; i < insn->n; i++) {
430 pci224_ao_set_data(dev, chan, range, val);
432 s->readback[chan] = val;
438 * Kills a command running on the AO subdevice.
440 static void pci224_ao_stop(struct comedi_device *dev,
441 struct comedi_subdevice *s)
443 struct pci224_private *devpriv = dev->private;
446 if (!test_and_clear_bit(AO_CMD_STARTED, &devpriv->state))
449 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
450 /* Kill the interrupts. */
452 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
454 * Interrupt routine may or may not be running. We may or may not
455 * have been called from the interrupt routine (directly or
456 * indirectly via a comedi_events() callback routine). It's highly
457 * unlikely that we've been called from some other interrupt routine
458 * but who knows what strange things coders get up to!
460 * If the interrupt routine is currently running, wait for it to
461 * finish, unless we appear to have been called via the interrupt
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);
468 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
469 /* Reconfigure DAC for insn_write usage. */
470 outw(0, dev->iobase + PCI224_DACCEN); /* Disable channels. */
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);
480 * Handles start of acquisition for the AO subdevice.
482 static void pci224_ao_start(struct comedi_device *dev,
483 struct comedi_subdevice *s)
485 struct pci224_private *devpriv = dev->private;
486 struct comedi_cmd *cmd = &s->async->cmd;
489 set_bit(AO_CMD_STARTED, &devpriv->state);
491 /* Enable interrupts. */
492 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
493 if (cmd->stop_src == TRIG_EXT)
494 devpriv->intsce = PCI224_INTR_EXT | PCI224_INTR_DAC;
496 devpriv->intsce = PCI224_INTR_DAC;
498 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
499 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
503 * Handles interrupts from the DAC FIFO.
505 static void pci224_ao_handle_fifo(struct comedi_device *dev,
506 struct comedi_subdevice *s)
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);
512 unsigned short dacstat;
515 /* Determine how much room is in the FIFO (in samples). */
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 /* FIFO empty at end of counted acquisition. */
523 s->async->events |= COMEDI_CB_EOA;
524 comedi_handle_events(dev, s);
528 case PCI224_DACCON_FIFOFL_ONETOHALF:
529 room = PCI224_FIFO_ROOM_ONETOHALF;
531 case PCI224_DACCON_FIFOFL_HALFTOFULL:
532 room = PCI224_FIFO_ROOM_HALFTOFULL;
535 room = PCI224_FIFO_ROOM_FULL;
538 if (room >= PCI224_FIFO_ROOM_ONETOHALF) {
539 /* FIFO is less than half-full. */
540 if (num_scans == 0) {
541 /* Nothing left to put in the FIFO. */
542 dev_err(dev->class_dev, "AO buffer underrun\n");
543 s->async->events |= COMEDI_CB_OVERFLOW;
546 /* Determine how many new scans can be put in the FIFO. */
547 room /= cmd->chanlist_len;
549 /* Determine how many scans to process. */
550 if (num_scans > room)
554 for (n = 0; n < num_scans; n++) {
555 comedi_buf_read_samples(s, &devpriv->ao_scan_vals[0],
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);
562 if (cmd->stop_src == TRIG_COUNT &&
563 s->async->scans_done >= cmd->stop_arg) {
565 * Change FIFO interrupt trigger level to wait
566 * until FIFO is empty.
568 devpriv->daccon = COMBINE(devpriv->daccon,
569 PCI224_DACCON_FIFOINTR_EMPTY,
570 PCI224_DACCON_FIFOINTR_MASK);
571 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
573 if ((devpriv->daccon & PCI224_DACCON_TRIG_MASK) ==
574 PCI224_DACCON_TRIG_NONE) {
578 * This is the initial DAC FIFO interrupt at the
579 * start of the acquisition. The DAC's scan trigger
580 * has been set to 'none' up until now.
582 * Now that data has been written to the FIFO, the
583 * DAC's scan trigger source can be set to the
586 * BUG: The first scan will be triggered immediately
587 * if the scan trigger source is at logic level 1.
589 if (cmd->scan_begin_src == TRIG_TIMER) {
590 trig = PCI224_DACCON_TRIG_Z2CT0;
592 /* cmd->scan_begin_src == TRIG_EXT */
593 if (cmd->scan_begin_arg & CR_INVERT)
594 trig = PCI224_DACCON_TRIG_EXTN;
596 trig = PCI224_DACCON_TRIG_EXTP;
599 COMBINE(devpriv->daccon, trig, PCI224_DACCON_TRIG_MASK);
600 outw(devpriv->daccon, dev->iobase + PCI224_DACCON);
603 comedi_handle_events(dev, s);
606 static int pci224_ao_inttrig_start(struct comedi_device *dev,
607 struct comedi_subdevice *s,
608 unsigned int trig_num)
610 struct comedi_cmd *cmd = &s->async->cmd;
612 if (trig_num != cmd->start_arg)
615 s->async->inttrig = NULL;
616 pci224_ao_start(dev, s);
621 static int pci224_ao_check_chanlist(struct comedi_device *dev,
622 struct comedi_subdevice *s,
623 struct comedi_cmd *cmd)
625 const struct pci224_board *board = dev->board_ptr;
626 unsigned int range_check_0;
627 unsigned int chan_mask = 0;
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]);
634 if (chan_mask & (1 << chan)) {
635 dev_dbg(dev->class_dev,
636 "%s: entries in chanlist must contain no duplicate channels\n",
640 chan_mask |= 1 << chan;
642 if (board->ao_range_check[CR_RANGE(cmd->chanlist[i])] !=
644 dev_dbg(dev->class_dev,
645 "%s: entries in chanlist have incompatible ranges\n",
654 #define MAX_SCAN_PERIOD 0xFFFFFFFFU
655 #define MIN_SCAN_PERIOD 2500
656 #define CONVERT_PERIOD 625
659 * 'do_cmdtest' function for AO subdevice.
662 pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
663 struct comedi_cmd *cmd)
668 /* Step 1 : check if triggers are trivially valid */
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);
681 /* Step 2a : make sure trigger sources are unique */
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);
687 /* Step 2b : and mutually compatible */
690 * There's only one external trigger signal (which makes these
691 * tests easier). Only one thing can use it.
694 if (cmd->start_src & TRIG_EXT)
696 if (cmd->scan_begin_src & TRIG_EXT)
698 if (cmd->stop_src & TRIG_EXT)
706 /* Step 3: check if arguments are trivially valid */
708 switch (cmd->start_src) {
710 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
713 /* Force to external trigger 0. */
714 if (cmd->start_arg & ~CR_FLAGS_MASK) {
716 COMBINE(cmd->start_arg, 0, ~CR_FLAGS_MASK);
719 /* The only flag allowed is CR_EDGE, which is ignored. */
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);
728 switch (cmd->scan_begin_src) {
730 err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg,
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);
739 /* Force to external trigger 0. */
740 if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) {
741 cmd->scan_begin_arg =
742 COMBINE(cmd->scan_begin_arg, 0, ~CR_FLAGS_MASK);
745 /* Only allow flags CR_EDGE and CR_INVERT. Ignore CR_EDGE. */
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));
756 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
757 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
760 switch (cmd->stop_src) {
762 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
765 /* Force to external trigger 0. */
766 if (cmd->stop_arg & ~CR_FLAGS_MASK) {
768 COMBINE(cmd->stop_arg, 0, ~CR_FLAGS_MASK);
771 /* The only flag allowed is CR_EDGE, which is ignored. */
772 if (cmd->stop_arg & CR_FLAGS_MASK & ~CR_EDGE) {
774 COMBINE(cmd->stop_arg, 0, CR_FLAGS_MASK & ~CR_EDGE);
778 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
785 /* Step 4: fix up any arguments. */
787 if (cmd->scan_begin_src == TRIG_TIMER) {
788 arg = cmd->scan_begin_arg;
789 /* Use two timers. */
790 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
791 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
797 /* Step 5: check channel list if it exists */
798 if (cmd->chanlist && cmd->chanlist_len > 0)
799 err |= pci224_ao_check_chanlist(dev, s, cmd);
807 static void pci224_ao_start_pacer(struct comedi_device *dev,
808 struct comedi_subdevice *s)
810 struct pci224_private *devpriv = dev->private;
813 * The output of timer Z2-0 will be used as the scan trigger
816 /* Make sure Z2-0 is gated on. */
817 outb(pci224_gat_config(0, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
818 /* Cascading with Z2-2. */
819 /* Make sure Z2-2 is gated on. */
820 outb(pci224_gat_config(2, GAT_VCC), devpriv->iobase1 + PCI224_ZGAT_SCE);
821 /* Z2-2 needs 10 MHz clock. */
822 outb(pci224_clk_config(2, CLK_10MHZ),
823 devpriv->iobase1 + PCI224_ZCLK_SCE);
824 /* Z2-0 is clocked from Z2-2's output. */
825 outb(pci224_clk_config(0, CLK_OUTNM1),
826 devpriv->iobase1 + PCI224_ZCLK_SCE);
828 comedi_8254_pacer_enable(dev->pacer, 2, 0, false);
831 static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
833 const struct pci224_board *board = dev->board_ptr;
834 struct pci224_private *devpriv = dev->private;
835 struct comedi_cmd *cmd = &s->async->cmd;
842 /* Cannot handle null/empty chanlist. */
843 if (!cmd->chanlist || cmd->chanlist_len == 0)
846 /* Determine which channels are enabled and their load order. */
847 devpriv->ao_enab = 0;
849 for (i = 0; i < cmd->chanlist_len; i++) {
850 ch = CR_CHAN(cmd->chanlist[i]);
851 devpriv->ao_enab |= 1U << ch;
853 for (j = 0; j < cmd->chanlist_len; j++) {
854 if (CR_CHAN(cmd->chanlist[j]) < ch)
857 devpriv->ao_scan_order[rank] = i;
860 /* Set enabled channels. */
861 outw(devpriv->ao_enab, dev->iobase + PCI224_DACCEN);
863 /* Determine range and polarity. All channels the same. */
864 range = CR_RANGE(cmd->chanlist[0]);
867 * Set DAC range and polarity.
868 * Set DAC scan trigger source to 'none'.
869 * Set DAC FIFO interrupt trigger level to 'not half full'.
872 * N.B. DAC FIFO interrupts are currently disabled.
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);
883 if (cmd->scan_begin_src == TRIG_TIMER) {
884 comedi_8254_update_divisors(dev->pacer);
885 pci224_ao_start_pacer(dev, s);
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 { /* TRIG_EXT */
892 /* Enable external interrupt trigger to start acquisition. */
893 devpriv->intsce |= PCI224_INTR_EXT;
894 outb(devpriv->intsce, devpriv->iobase1 + PCI224_INT_SCE);
896 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
902 * 'cancel' function for AO subdevice.
904 static int pci224_ao_cancel(struct comedi_device *dev,
905 struct comedi_subdevice *s)
907 pci224_ao_stop(dev, s);
912 * 'munge' data for AO command.
915 pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s,
916 void *data, unsigned int num_bytes, unsigned int chan_index)
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);
926 /* The hardware expects 16-bit numbers. */
927 shift = 16 - board->ao_bits;
928 /* Channels will be all bipolar or all unipolar. */
929 if ((board->ao_hwrange[CR_RANGE(cmd->chanlist[0])] &
930 PCI224_DACCON_POLAR_MASK) == PCI224_DACCON_POLAR_UNI) {
937 /* Munge the data. */
938 for (i = 0; i < length; i++)
939 array[i] = (array[i] << shift) - offset;
945 static irqreturn_t pci224_interrupt(int irq, void *d)
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;
956 intstat = inb(devpriv->iobase1 + PCI224_INT_SCE) & 0x3F;
959 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
960 valid_intstat = devpriv->intsce & intstat;
961 /* Temporarily disable interrupt sources. */
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);
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);
976 if (valid_intstat & PCI224_INTR_DAC)
977 pci224_ao_handle_fifo(dev, s);
979 /* Reenable interrupt sources. */
980 spin_lock_irqsave(&devpriv->ao_spinlock, flags);
981 if (curenab != devpriv->intsce) {
982 outb(devpriv->intsce,
983 devpriv->iobase1 + PCI224_INT_SCE);
985 devpriv->intr_running = 0;
986 spin_unlock_irqrestore(&devpriv->ao_spinlock, flags);
988 return IRQ_RETVAL(retval);
992 pci224_auto_attach(struct comedi_device *dev, unsigned long context_model)
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;
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");
1008 dev->board_ptr = board;
1009 dev->board_name = board->name;
1011 dev_info(dev->class_dev, "amplc_pci224: attach pci %s - %s\n",
1012 pci_name(pci_dev), dev->board_name);
1014 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1018 ret = comedi_pci_enable(dev);
1022 spin_lock_init(&devpriv->ao_spinlock);
1024 devpriv->iobase1 = pci_resource_start(pci_dev, 2);
1025 dev->iobase = pci_resource_start(pci_dev, 3);
1028 /* Allocate buffer to hold values for AO channel scan. */
1029 devpriv->ao_scan_vals = kmalloc_array(board->ao_chans,
1030 sizeof(devpriv->ao_scan_vals[0]),
1032 if (!devpriv->ao_scan_vals)
1035 /* Allocate buffer to hold AO channel scan order. */
1036 devpriv->ao_scan_order =
1037 kmalloc_array(board->ao_chans,
1038 sizeof(devpriv->ao_scan_order[0]),
1040 if (!devpriv->ao_scan_order)
1043 /* Disable interrupt sources. */
1044 devpriv->intsce = 0;
1045 outb(0, devpriv->iobase1 + PCI224_INT_SCE);
1047 /* Initialize the DAC hardware. */
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);
1056 dev->pacer = comedi_8254_init(devpriv->iobase1 + PCI224_Z2_BASE,
1057 I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
1061 ret = comedi_alloc_subdevices(dev, 1);
1065 s = &dev->subdevices[0];
1066 /* Analog output subdevice. */
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;
1080 ret = comedi_alloc_subdev_readback(s);
1085 ret = request_irq(irq, pci224_interrupt, IRQF_SHARED,
1086 dev->board_name, dev);
1088 dev_err(dev->class_dev,
1089 "error! unable to allocate irq %u\n", irq);
1098 static void pci224_detach(struct comedi_device *dev)
1100 struct pci224_private *devpriv = dev->private;
1102 comedi_pci_detach(dev);
1104 kfree(devpriv->ao_scan_vals);
1105 kfree(devpriv->ao_scan_order);
1109 static 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),
1119 static int amplc_pci224_pci_probe(struct pci_dev *dev,
1120 const struct pci_device_id *id)
1122 return comedi_pci_auto_config(dev, &lc_pci224_driver,
1126 static const struct pci_device_id amplc_pci224_pci_table[] = {
1127 { PCI_VDEVICE(AMPLICON, 0x0007), pci224_model },
1128 { PCI_VDEVICE(AMPLICON, 0x0008), pci234_model },
1131 MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table);
1133 static 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,
1139 module_comedi_pci_driver(amplc_pci224_driver, amplc_pci224_pci_driver);
1141 MODULE_AUTHOR("Comedi https://www.comedi.org");
1142 MODULE_DESCRIPTION("Comedi driver for Amplicon PCI224 and PCI234 AO boards");
1143 MODULE_LICENSE("GPL");