1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * comedi/drivers/amplc_pci230.c
4 * Driver for Amplicon PCI230 and PCI260 Multifunction I/O boards.
5 *
6 * Copyright (C) 2001 Allan Willcox <allanwillcox@ozemail.com.au>
7 *
8 * COMEDI - Linux Control and Measurement Device Interface
9 * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
10 */
11
12/*
13 * Driver: amplc_pci230
14 * Description: Amplicon PCI230, PCI260 Multifunction I/O boards
15 * Author: Allan Willcox <allanwillcox@ozemail.com.au>,
16 * Steve D Sharples <steve.sharples@nottingham.ac.uk>,
17 * Ian Abbott <abbotti@mev.co.uk>
18 * Updated: Mon, 01 Sep 2014 10:09:16 +0000
19 * Devices: [Amplicon] PCI230 (amplc_pci230), PCI230+, PCI260, PCI260+
20 * Status: works
21 *
22 * Configuration options:
23 * none
24 *
25 * Manual configuration of PCI cards is not supported; they are configured
26 * automatically.
27 *
28 * The PCI230+ and PCI260+ have the same PCI device IDs as the PCI230 and
29 * PCI260, but can be distinguished by the size of the PCI regions. A
30 * card will be configured as a "+" model if detected as such.
31 *
32 * Subdevices:
33 *
34 * PCI230(+) PCI260(+)
35 * --------- ---------
36 * Subdevices 3 1
37 * 0 AI AI
38 * 1 AO
39 * 2 DIO
40 *
41 * AI Subdevice:
42 *
43 * The AI subdevice has 16 single-ended channels or 8 differential
44 * channels.
45 *
46 * The PCI230 and PCI260 cards have 12-bit resolution. The PCI230+ and
47 * PCI260+ cards have 16-bit resolution.
48 *
49 * For differential mode, use inputs 2N and 2N+1 for channel N (e.g. use
50 * inputs 14 and 15 for channel 7). If the card is physically a PCI230
51 * or PCI260 then it actually uses a "pseudo-differential" mode where the
52 * inputs are sampled a few microseconds apart. The PCI230+ and PCI260+
53 * use true differential sampling. Another difference is that if the
54 * card is physically a PCI230 or PCI260, the inverting input is 2N,
55 * whereas for a PCI230+ or PCI260+ the inverting input is 2N+1. So if a
56 * PCI230 is physically replaced by a PCI230+ (or a PCI260 with a
57 * PCI260+) and differential mode is used, the differential inputs need
58 * to be physically swapped on the connector.
59 *
60 * The following input ranges are supported:
61 *
62 * 0 => [-10, +10] V
63 * 1 => [-5, +5] V
64 * 2 => [-2.5, +2.5] V
65 * 3 => [-1.25, +1.25] V
66 * 4 => [0, 10] V
67 * 5 => [0, 5] V
68 * 6 => [0, 2.5] V
69 *
70 * AI Commands:
71 *
72 * +=========+==============+===========+============+==========+
73 * |start_src|scan_begin_src|convert_src|scan_end_src| stop_src |
74 * +=========+==============+===========+============+==========+
75 * |TRIG_NOW | TRIG_FOLLOW |TRIG_TIMER | TRIG_COUNT |TRIG_NONE |
76 * |TRIG_INT | |TRIG_EXT(3)| |TRIG_COUNT|
77 * | | |TRIG_INT | | |
78 * | |--------------|-----------| | |
79 * | | TRIG_TIMER(1)|TRIG_TIMER | | |
80 * | | TRIG_EXT(2) | | | |
81 * | | TRIG_INT | | | |
82 * +---------+--------------+-----------+------------+----------+
83 *
84 * Note 1: If AI command and AO command are used simultaneously, only
85 * one may have scan_begin_src == TRIG_TIMER.
86 *
87 * Note 2: For PCI230 and PCI230+, scan_begin_src == TRIG_EXT uses
88 * DIO channel 16 (pin 49) which will need to be configured as
89 * a digital input. For PCI260+, the EXTTRIG/EXTCONVCLK input
90 * (pin 17) is used instead. For PCI230, scan_begin_src ==
91 * TRIG_EXT is not supported. The trigger is a rising edge
92 * on the input.
93 *
94 * Note 3: For convert_src == TRIG_EXT, the EXTTRIG/EXTCONVCLK input
95 * (pin 25 on PCI230(+), pin 17 on PCI260(+)) is used. The
96 * convert_arg value is interpreted as follows:
97 *
98 * convert_arg == (CR_EDGE | 0) => rising edge
99 * convert_arg == (CR_EDGE | CR_INVERT | 0) => falling edge
100 * convert_arg == 0 => falling edge (backwards compatibility)
101 * convert_arg == 1 => rising edge (backwards compatibility)
102 *
103 * All entries in the channel list must use the same analogue reference.
104 * If the analogue reference is not AREF_DIFF (not differential) each
105 * pair of channel numbers (0 and 1, 2 and 3, etc.) must use the same
106 * input range. The input ranges used in the sequence must be all
107 * bipolar (ranges 0 to 3) or all unipolar (ranges 4 to 6). The channel
108 * sequence must consist of 1 or more identical subsequences. Within the
109 * subsequence, channels must be in ascending order with no repeated
110 * channels. For example, the following sequences are valid: 0 1 2 3
111 * (single valid subsequence), 0 2 3 5 0 2 3 5 (repeated valid
112 * subsequence), 1 1 1 1 (repeated valid subsequence). The following
113 * sequences are invalid: 0 3 2 1 (invalid subsequence), 0 2 3 5 0 2 3
114 * (incompletely repeated subsequence). Some versions of the PCI230+ and
115 * PCI260+ have a bug that requires a subsequence longer than one entry
116 * long to include channel 0.
117 *
118 * AO Subdevice:
119 *
120 * The AO subdevice has 2 channels with 12-bit resolution.
121 * The following output ranges are supported:
122 * 0 => [0, 10] V
123 * 1 => [-10, +10] V
124 *
125 * AO Commands:
126 *
127 * +=========+==============+===========+============+==========+
128 * |start_src|scan_begin_src|convert_src|scan_end_src| stop_src |
129 * +=========+==============+===========+============+==========+
130 * |TRIG_INT | TRIG_TIMER(1)| TRIG_NOW | TRIG_COUNT |TRIG_NONE |
131 * | | TRIG_EXT(2) | | |TRIG_COUNT|
132 * | | TRIG_INT | | | |
133 * +---------+--------------+-----------+------------+----------+
134 *
135 * Note 1: If AI command and AO command are used simultaneously, only
136 * one may have scan_begin_src == TRIG_TIMER.
137 *
138 * Note 2: scan_begin_src == TRIG_EXT is only supported if the card is
139 * configured as a PCI230+ and is only supported on later
140 * versions of the card. As a card configured as a PCI230+ is
141 * not guaranteed to support external triggering, please consider
142 * this support to be a bonus. It uses the EXTTRIG/ EXTCONVCLK
143 * input (PCI230+ pin 25). Triggering will be on the rising edge
144 * unless the CR_INVERT flag is set in scan_begin_arg.
145 *
146 * The channels in the channel sequence must be in ascending order with
147 * no repeats. All entries in the channel sequence must use the same
148 * output range.
149 *
150 * DIO Subdevice:
151 *
152 * The DIO subdevice is a 8255 chip providing 24 DIO channels. The DIO
153 * channels are configurable as inputs or outputs in four groups:
154 *
155 * Port A - channels 0 to 7
156 * Port B - channels 8 to 15
157 * Port CL - channels 16 to 19
158 * Port CH - channels 20 to 23
159 *
160 * Only mode 0 of the 8255 chip is supported.
161 *
162 * Bit 0 of port C (DIO channel 16) is also used as an external scan
163 * trigger input for AI commands on PCI230 and PCI230+, so would need to
164 * be configured as an input to use it for that purpose.
165 */
166
167/*
168 * Extra triggered scan functionality, interrupt bug-fix added by Steve
169 * Sharples. Support for PCI230+/260+, more triggered scan functionality,
170 * and workarounds for (or detection of) various hardware problems added
171 * by Ian Abbott.
172 */
173
174#include <linux/module.h>
175#include <linux/delay.h>
176#include <linux/interrupt.h>
177#include <linux/comedi/comedi_pci.h>
178#include <linux/comedi/comedi_8255.h>
179#include <linux/comedi/comedi_8254.h>
180
181/*
182 * PCI230 PCI configuration register information
183 */
184#define PCI_DEVICE_ID_PCI230 0x0000
185#define PCI_DEVICE_ID_PCI260 0x0006
186
187/*
188 * PCI230 i/o space 1 registers.
189 */
190#define PCI230_PPI_X_BASE 0x00 /* User PPI (82C55) base */
191#define PCI230_PPI_X_A 0x00 /* User PPI (82C55) port A */
192#define PCI230_PPI_X_B 0x01 /* User PPI (82C55) port B */
193#define PCI230_PPI_X_C 0x02 /* User PPI (82C55) port C */
194#define PCI230_PPI_X_CMD 0x03 /* User PPI (82C55) control word */
195#define PCI230_Z2_CT_BASE 0x14 /* 82C54 counter/timer base */
196#define PCI230_ZCLK_SCE 0x1A /* Group Z Clock Configuration */
197#define PCI230_ZGAT_SCE 0x1D /* Group Z Gate Configuration */
198#define PCI230_INT_SCE 0x1E /* Interrupt source mask (w) */
199#define PCI230_INT_STAT 0x1E /* Interrupt status (r) */
200
201/*
202 * PCI230 i/o space 2 registers.
203 */
204#define PCI230_DACCON 0x00 /* DAC control */
205#define PCI230_DACOUT1 0x02 /* DAC channel 0 (w) */
206#define PCI230_DACOUT2 0x04 /* DAC channel 1 (w) (not FIFO mode) */
207#define PCI230_ADCDATA 0x08 /* ADC data (r) */
208#define PCI230_ADCSWTRIG 0x08 /* ADC software trigger (w) */
209#define PCI230_ADCCON 0x0A /* ADC control */
210#define PCI230_ADCEN 0x0C /* ADC channel enable bits */
211#define PCI230_ADCG 0x0E /* ADC gain control bits */
212/* PCI230+ i/o space 2 additional registers. */
213#define PCI230P_ADCTRIG 0x10 /* ADC start acquisition trigger */
214#define PCI230P_ADCTH 0x12 /* ADC analog trigger threshold */
215#define PCI230P_ADCFFTH 0x14 /* ADC FIFO interrupt threshold */
216#define PCI230P_ADCFFLEV 0x16 /* ADC FIFO level (r) */
217#define PCI230P_ADCPTSC 0x18 /* ADC pre-trigger sample count (r) */
218#define PCI230P_ADCHYST 0x1A /* ADC analog trigger hysteresys */
219#define PCI230P_EXTFUNC 0x1C /* Extended functions */
220#define PCI230P_HWVER 0x1E /* Hardware version (r) */
221/* PCI230+ hardware version 2 onwards. */
222#define PCI230P2_DACDATA 0x02 /* DAC data (FIFO mode) (w) */
223#define PCI230P2_DACSWTRIG 0x02 /* DAC soft trigger (FIFO mode) (r) */
224#define PCI230P2_DACEN 0x06 /* DAC channel enable (FIFO mode) */
225
226/*
227 * DACCON read-write values.
228 */
229#define PCI230_DAC_OR(x) (((x) & 0x1) << 0)
230#define PCI230_DAC_OR_UNI PCI230_DAC_OR(0) /* Output unipolar */
231#define PCI230_DAC_OR_BIP PCI230_DAC_OR(1) /* Output bipolar */
232#define PCI230_DAC_OR_MASK PCI230_DAC_OR(1)
233/*
234 * The following applies only if DAC FIFO support is enabled in the EXTFUNC
235 * register (and only for PCI230+ hardware version 2 onwards).
236 */
237#define PCI230P2_DAC_FIFO_EN BIT(8) /* FIFO enable */
238/*
239 * The following apply only if the DAC FIFO is enabled (and only for PCI230+
240 * hardware version 2 onwards).
241 */
242#define PCI230P2_DAC_TRIG(x) (((x) & 0x7) << 2)
243#define PCI230P2_DAC_TRIG_NONE PCI230P2_DAC_TRIG(0) /* none */
244#define PCI230P2_DAC_TRIG_SW PCI230P2_DAC_TRIG(1) /* soft trig */
245#define PCI230P2_DAC_TRIG_EXTP PCI230P2_DAC_TRIG(2) /* ext + edge */
246#define PCI230P2_DAC_TRIG_EXTN PCI230P2_DAC_TRIG(3) /* ext - edge */
247#define PCI230P2_DAC_TRIG_Z2CT0 PCI230P2_DAC_TRIG(4) /* Z2 CT0 out */
248#define PCI230P2_DAC_TRIG_Z2CT1 PCI230P2_DAC_TRIG(5) /* Z2 CT1 out */
249#define PCI230P2_DAC_TRIG_Z2CT2 PCI230P2_DAC_TRIG(6) /* Z2 CT2 out */
250#define PCI230P2_DAC_TRIG_MASK PCI230P2_DAC_TRIG(7)
251#define PCI230P2_DAC_FIFO_WRAP BIT(7) /* FIFO wraparound mode */
252#define PCI230P2_DAC_INT_FIFO(x) (((x) & 7) << 9)
253#define PCI230P2_DAC_INT_FIFO_EMPTY PCI230P2_DAC_INT_FIFO(0) /* empty */
254#define PCI230P2_DAC_INT_FIFO_NEMPTY PCI230P2_DAC_INT_FIFO(1) /* !empty */
255#define PCI230P2_DAC_INT_FIFO_NHALF PCI230P2_DAC_INT_FIFO(2) /* !half */
256#define PCI230P2_DAC_INT_FIFO_HALF PCI230P2_DAC_INT_FIFO(3) /* half */
257#define PCI230P2_DAC_INT_FIFO_NFULL PCI230P2_DAC_INT_FIFO(4) /* !full */
258#define PCI230P2_DAC_INT_FIFO_FULL PCI230P2_DAC_INT_FIFO(5) /* full */
259#define PCI230P2_DAC_INT_FIFO_MASK PCI230P2_DAC_INT_FIFO(7)
260
261/*
262 * DACCON read-only values.
263 */
264#define PCI230_DAC_BUSY BIT(1) /* DAC busy. */
265/*
266 * The following apply only if the DAC FIFO is enabled (and only for PCI230+
267 * hardware version 2 onwards).
268 */
269#define PCI230P2_DAC_FIFO_UNDERRUN_LATCHED BIT(5) /* Underrun error */
270#define PCI230P2_DAC_FIFO_EMPTY BIT(13) /* FIFO empty */
271#define PCI230P2_DAC_FIFO_FULL BIT(14) /* FIFO full */
272#define PCI230P2_DAC_FIFO_HALF BIT(15) /* FIFO half full */
273
274/*
275 * DACCON write-only, transient values.
276 */
277/*
278 * The following apply only if the DAC FIFO is enabled (and only for PCI230+
279 * hardware version 2 onwards).
280 */
281#define PCI230P2_DAC_FIFO_UNDERRUN_CLEAR BIT(5) /* Clear underrun */
282#define PCI230P2_DAC_FIFO_RESET BIT(12) /* FIFO reset */
283
284/*
285 * PCI230+ hardware version 2 DAC FIFO levels.
286 */
287#define PCI230P2_DAC_FIFOLEVEL_HALF 512
288#define PCI230P2_DAC_FIFOLEVEL_FULL 1024
289/* Free space in DAC FIFO. */
290#define PCI230P2_DAC_FIFOROOM_EMPTY PCI230P2_DAC_FIFOLEVEL_FULL
291#define PCI230P2_DAC_FIFOROOM_ONETOHALF \
292 (PCI230P2_DAC_FIFOLEVEL_FULL - PCI230P2_DAC_FIFOLEVEL_HALF)
293#define PCI230P2_DAC_FIFOROOM_HALFTOFULL 1
294#define PCI230P2_DAC_FIFOROOM_FULL 0
295
296/*
297 * ADCCON read/write values.
298 */
299#define PCI230_ADC_TRIG(x) (((x) & 0x7) << 0)
300#define PCI230_ADC_TRIG_NONE PCI230_ADC_TRIG(0) /* none */
301#define PCI230_ADC_TRIG_SW PCI230_ADC_TRIG(1) /* soft trig */
302#define PCI230_ADC_TRIG_EXTP PCI230_ADC_TRIG(2) /* ext + edge */
303#define PCI230_ADC_TRIG_EXTN PCI230_ADC_TRIG(3) /* ext - edge */
304#define PCI230_ADC_TRIG_Z2CT0 PCI230_ADC_TRIG(4) /* Z2 CT0 out*/
305#define PCI230_ADC_TRIG_Z2CT1 PCI230_ADC_TRIG(5) /* Z2 CT1 out */
306#define PCI230_ADC_TRIG_Z2CT2 PCI230_ADC_TRIG(6) /* Z2 CT2 out */
307#define PCI230_ADC_TRIG_MASK PCI230_ADC_TRIG(7)
308#define PCI230_ADC_IR(x) (((x) & 0x1) << 3)
309#define PCI230_ADC_IR_UNI PCI230_ADC_IR(0) /* Input unipolar */
310#define PCI230_ADC_IR_BIP PCI230_ADC_IR(1) /* Input bipolar */
311#define PCI230_ADC_IR_MASK PCI230_ADC_IR(1)
312#define PCI230_ADC_IM(x) (((x) & 0x1) << 4)
313#define PCI230_ADC_IM_SE PCI230_ADC_IM(0) /* single ended */
314#define PCI230_ADC_IM_DIF PCI230_ADC_IM(1) /* differential */
315#define PCI230_ADC_IM_MASK PCI230_ADC_IM(1)
316#define PCI230_ADC_FIFO_EN BIT(8) /* FIFO enable */
317#define PCI230_ADC_INT_FIFO(x) (((x) & 0x7) << 9)
318#define PCI230_ADC_INT_FIFO_EMPTY PCI230_ADC_INT_FIFO(0) /* empty */
319#define PCI230_ADC_INT_FIFO_NEMPTY PCI230_ADC_INT_FIFO(1) /* !empty */
320#define PCI230_ADC_INT_FIFO_NHALF PCI230_ADC_INT_FIFO(2) /* !half */
321#define PCI230_ADC_INT_FIFO_HALF PCI230_ADC_INT_FIFO(3) /* half */
322#define PCI230_ADC_INT_FIFO_NFULL PCI230_ADC_INT_FIFO(4) /* !full */
323#define PCI230_ADC_INT_FIFO_FULL PCI230_ADC_INT_FIFO(5) /* full */
324#define PCI230P_ADC_INT_FIFO_THRESH PCI230_ADC_INT_FIFO(7) /* threshold */
325#define PCI230_ADC_INT_FIFO_MASK PCI230_ADC_INT_FIFO(7)
326
327/*
328 * ADCCON write-only, transient values.
329 */
330#define PCI230_ADC_FIFO_RESET BIT(12) /* FIFO reset */
331#define PCI230_ADC_GLOB_RESET BIT(13) /* Global reset */
332
333/*
334 * ADCCON read-only values.
335 */
336#define PCI230_ADC_BUSY BIT(15) /* ADC busy */
337#define PCI230_ADC_FIFO_EMPTY BIT(12) /* FIFO empty */
338#define PCI230_ADC_FIFO_FULL BIT(13) /* FIFO full */
339#define PCI230_ADC_FIFO_HALF BIT(14) /* FIFO half full */
340#define PCI230_ADC_FIFO_FULL_LATCHED BIT(5) /* FIFO overrun occurred */
341
342/*
343 * PCI230 ADC FIFO levels.
344 */
345#define PCI230_ADC_FIFOLEVEL_HALFFULL 2049 /* Value for FIFO half full */
346#define PCI230_ADC_FIFOLEVEL_FULL 4096 /* FIFO size */
347
348/*
349 * PCI230+ EXTFUNC values.
350 */
351/* Route EXTTRIG pin to external gate inputs. */
352#define PCI230P_EXTFUNC_GAT_EXTTRIG BIT(0)
353/* PCI230+ hardware version 2 values. */
354/* Allow DAC FIFO to be enabled. */
355#define PCI230P2_EXTFUNC_DACFIFO BIT(1)
356
357/*
358 * Counter/timer clock input configuration sources.
359 */
360#define CLK_CLK 0 /* reserved (channel-specific clock) */
361#define CLK_10MHZ 1 /* internal 10 MHz clock */
362#define CLK_1MHZ 2 /* internal 1 MHz clock */
363#define CLK_100KHZ 3 /* internal 100 kHz clock */
364#define CLK_10KHZ 4 /* internal 10 kHz clock */
365#define CLK_1KHZ 5 /* internal 1 kHz clock */
366#define CLK_OUTNM1 6 /* output of channel-1 modulo total */
367#define CLK_EXT 7 /* external clock */
368
369static unsigned int pci230_clk_config(unsigned int chan, unsigned int src)
370{
371 return ((chan & 3) << 3) | (src & 7);
372}
373
374/*
375 * Counter/timer gate input configuration sources.
376 */
377#define GAT_VCC 0 /* VCC (i.e. enabled) */
378#define GAT_GND 1 /* GND (i.e. disabled) */
379#define GAT_EXT 2 /* external gate input (PPCn on PCI230) */
380#define GAT_NOUTNM2 3 /* inverted output of channel-2 modulo total */
381
382static unsigned int pci230_gat_config(unsigned int chan, unsigned int src)
383{
384 return ((chan & 3) << 3) | (src & 7);
385}
386
387/*
388 * Summary of CLK_OUTNM1 and GAT_NOUTNM2 connections for PCI230 and PCI260:
389 *
390 * Channel's Channel's
391 * clock input gate input
392 * Channel CLK_OUTNM1 GAT_NOUTNM2
393 * ------- ---------- -----------
394 * Z2-CT0 Z2-CT2-OUT /Z2-CT1-OUT
395 * Z2-CT1 Z2-CT0-OUT /Z2-CT2-OUT
396 * Z2-CT2 Z2-CT1-OUT /Z2-CT0-OUT
397 */
398
399/*
400 * Interrupt enables/status register values.
401 */
402#define PCI230_INT_DISABLE 0
403#define PCI230_INT_PPI_C0 BIT(0)
404#define PCI230_INT_PPI_C3 BIT(1)
405#define PCI230_INT_ADC BIT(2)
406#define PCI230_INT_ZCLK_CT1 BIT(5)
407/* For PCI230+ hardware version 2 when DAC FIFO enabled. */
408#define PCI230P2_INT_DAC BIT(4)
409
410/*
411 * (Potentially) shared resources and their owners
412 */
413enum {
414 RES_Z2CT0 = BIT(0), /* Z2-CT0 */
415 RES_Z2CT1 = BIT(1), /* Z2-CT1 */
416 RES_Z2CT2 = BIT(2) /* Z2-CT2 */
417};
418
419enum {
420 OWNER_AICMD, /* Owned by AI command */
421 OWNER_AOCMD, /* Owned by AO command */
422 NUM_OWNERS /* Number of owners */
423};
424
425/*
426 * Handy macros.
427 */
428
429/* Combine old and new bits. */
430#define COMBINE(old, new, mask) (((old) & ~(mask)) | ((new) & (mask)))
431
432/* Current CPU. XXX should this be hard_smp_processor_id()? */
433#define THISCPU smp_processor_id()
434
435/*
436 * Board descriptions for the two boards supported.
437 */
438
439struct pci230_board {
440 const char *name;
441 unsigned short id;
442 unsigned char ai_bits;
443 unsigned char ao_bits;
444 unsigned char min_hwver; /* Minimum hardware version supported. */
445 unsigned int have_dio:1;
446};
447
448static const struct pci230_board pci230_boards[] = {
449 {
450 .name = "pci230+",
451 .id = PCI_DEVICE_ID_PCI230,
452 .ai_bits = 16,
453 .ao_bits = 12,
454 .have_dio = true,
455 .min_hwver = 1,
456 },
457 {
458 .name = "pci260+",
459 .id = PCI_DEVICE_ID_PCI260,
460 .ai_bits = 16,
461 .min_hwver = 1,
462 },
463 {
464 .name = "pci230",
465 .id = PCI_DEVICE_ID_PCI230,
466 .ai_bits = 12,
467 .ao_bits = 12,
468 .have_dio = true,
469 },
470 {
471 .name = "pci260",
472 .id = PCI_DEVICE_ID_PCI260,
473 .ai_bits = 12,
474 },
475};
476
477struct pci230_private {
478 spinlock_t isr_spinlock; /* Interrupt spin lock */
479 spinlock_t res_spinlock; /* Shared resources spin lock */
480 spinlock_t ai_stop_spinlock; /* Spin lock for stopping AI command */
481 spinlock_t ao_stop_spinlock; /* Spin lock for stopping AO command */
482 unsigned long daqio; /* PCI230's DAQ I/O space */
483 int intr_cpuid; /* ID of CPU running ISR */
484 unsigned short hwver; /* Hardware version (for '+' models) */
485 unsigned short adccon; /* ADCCON register value */
486 unsigned short daccon; /* DACCON register value */
487 unsigned short adcfifothresh; /* ADC FIFO threshold (PCI230+/260+) */
488 unsigned short adcg; /* ADCG register value */
489 unsigned char ier; /* Interrupt enable bits */
490 unsigned char res_owned[NUM_OWNERS]; /* Owned resources */
491 unsigned int intr_running:1; /* Flag set in interrupt routine */
492 unsigned int ai_bipolar:1; /* Flag AI range is bipolar */
493 unsigned int ao_bipolar:1; /* Flag AO range is bipolar */
494 unsigned int ai_cmd_started:1; /* Flag AI command started */
495 unsigned int ao_cmd_started:1; /* Flag AO command started */
496};
497
498/* PCI230 clock source periods in ns */
499static const unsigned int pci230_timebase[8] = {
500 [CLK_10MHZ] = I8254_OSC_BASE_10MHZ,
501 [CLK_1MHZ] = I8254_OSC_BASE_1MHZ,
502 [CLK_100KHZ] = I8254_OSC_BASE_100KHZ,
503 [CLK_10KHZ] = I8254_OSC_BASE_10KHZ,
504 [CLK_1KHZ] = I8254_OSC_BASE_1KHZ,
505};
506
507/* PCI230 analogue input range table */
508static const struct comedi_lrange pci230_ai_range = {
509 7, {
510 BIP_RANGE(10),
511 BIP_RANGE(5),
512 BIP_RANGE(2.5),
513 BIP_RANGE(1.25),
514 UNI_RANGE(10),
515 UNI_RANGE(5),
516 UNI_RANGE(2.5)
517 }
518};
519
520/* PCI230 analogue gain bits for each input range. */
521static const unsigned char pci230_ai_gain[7] = { 0, 1, 2, 3, 1, 2, 3 };
522
523/* PCI230 analogue output range table */
524static const struct comedi_lrange pci230_ao_range = {
525 2, {
526 UNI_RANGE(10),
527 BIP_RANGE(10)
528 }
529};
530
531static unsigned short pci230_ai_read(struct comedi_device *dev)
532{
533 const struct pci230_board *board = dev->board_ptr;
534 struct pci230_private *devpriv = dev->private;
535 unsigned short data;
536
537 /* Read sample. */
538 data = inw(port: devpriv->daqio + PCI230_ADCDATA);
539 /*
540 * PCI230 is 12 bit - stored in upper bits of 16 bit register
541 * (lower four bits reserved for expansion). PCI230+ is 16 bit AI.
542 *
543 * If a bipolar range was specified, mangle it
544 * (twos complement->straight binary).
545 */
546 if (devpriv->ai_bipolar)
547 data ^= 0x8000;
548 data >>= (16 - board->ai_bits);
549 return data;
550}
551
552static unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
553 unsigned short datum)
554{
555 const struct pci230_board *board = dev->board_ptr;
556 struct pci230_private *devpriv = dev->private;
557
558 /*
559 * PCI230 is 12 bit - stored in upper bits of 16 bit register (lower
560 * four bits reserved for expansion). PCI230+ is also 12 bit AO.
561 */
562 datum <<= (16 - board->ao_bits);
563 /*
564 * If a bipolar range was specified, mangle it
565 * (straight binary->twos complement).
566 */
567 if (devpriv->ao_bipolar)
568 datum ^= 0x8000;
569 return datum;
570}
571
572static void pci230_ao_write_nofifo(struct comedi_device *dev,
573 unsigned short datum, unsigned int chan)
574{
575 struct pci230_private *devpriv = dev->private;
576
577 /* Write mangled datum to appropriate DACOUT register. */
578 outw(value: pci230_ao_mangle_datum(dev, datum),
579 port: devpriv->daqio + ((chan == 0) ? PCI230_DACOUT1 : PCI230_DACOUT2));
580}
581
582static void pci230_ao_write_fifo(struct comedi_device *dev,
583 unsigned short datum, unsigned int chan)
584{
585 struct pci230_private *devpriv = dev->private;
586
587 /* Write mangled datum to appropriate DACDATA register. */
588 outw(value: pci230_ao_mangle_datum(dev, datum),
589 port: devpriv->daqio + PCI230P2_DACDATA);
590}
591
592static bool pci230_claim_shared(struct comedi_device *dev,
593 unsigned char res_mask, unsigned int owner)
594{
595 struct pci230_private *devpriv = dev->private;
596 unsigned int o;
597 unsigned long irqflags;
598
599 spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
600 for (o = 0; o < NUM_OWNERS; o++) {
601 if (o == owner)
602 continue;
603 if (devpriv->res_owned[o] & res_mask) {
604 spin_unlock_irqrestore(lock: &devpriv->res_spinlock,
605 flags: irqflags);
606 return false;
607 }
608 }
609 devpriv->res_owned[owner] |= res_mask;
610 spin_unlock_irqrestore(lock: &devpriv->res_spinlock, flags: irqflags);
611 return true;
612}
613
614static void pci230_release_shared(struct comedi_device *dev,
615 unsigned char res_mask, unsigned int owner)
616{
617 struct pci230_private *devpriv = dev->private;
618 unsigned long irqflags;
619
620 spin_lock_irqsave(&devpriv->res_spinlock, irqflags);
621 devpriv->res_owned[owner] &= ~res_mask;
622 spin_unlock_irqrestore(lock: &devpriv->res_spinlock, flags: irqflags);
623}
624
625static void pci230_release_all_resources(struct comedi_device *dev,
626 unsigned int owner)
627{
628 pci230_release_shared(dev, res_mask: (unsigned char)~0, owner);
629}
630
631static unsigned int pci230_divide_ns(u64 ns, unsigned int timebase,
632 unsigned int flags)
633{
634 u64 div;
635 unsigned int rem;
636
637 div = ns;
638 rem = do_div(div, timebase);
639 switch (flags & CMDF_ROUND_MASK) {
640 default:
641 case CMDF_ROUND_NEAREST:
642 div += DIV_ROUND_CLOSEST(rem, timebase);
643 break;
644 case CMDF_ROUND_DOWN:
645 break;
646 case CMDF_ROUND_UP:
647 div += DIV_ROUND_UP(rem, timebase);
648 break;
649 }
650 return div > UINT_MAX ? UINT_MAX : (unsigned int)div;
651}
652
653/*
654 * Given desired period in ns, returns the required internal clock source
655 * and gets the initial count.
656 */
657static unsigned int pci230_choose_clk_count(u64 ns, unsigned int *count,
658 unsigned int flags)
659{
660 unsigned int clk_src, cnt;
661
662 for (clk_src = CLK_10MHZ;; clk_src++) {
663 cnt = pci230_divide_ns(ns, timebase: pci230_timebase[clk_src], flags);
664 if (cnt <= 65536 || clk_src == CLK_1KHZ)
665 break;
666 }
667 *count = cnt;
668 return clk_src;
669}
670
671static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int flags)
672{
673 unsigned int count;
674 unsigned int clk_src;
675
676 clk_src = pci230_choose_clk_count(ns: *ns, count: &count, flags);
677 *ns = count * pci230_timebase[clk_src];
678}
679
680static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
681 unsigned int mode, u64 ns,
682 unsigned int flags)
683{
684 unsigned int clk_src;
685 unsigned int count;
686
687 /* Set mode. */
688 comedi_8254_set_mode(i8254: dev->pacer, counter: ct, mode);
689 /* Determine clock source and count. */
690 clk_src = pci230_choose_clk_count(ns, count: &count, flags);
691 /* Program clock source. */
692 outb(value: pci230_clk_config(chan: ct, src: clk_src), port: dev->iobase + PCI230_ZCLK_SCE);
693 /* Set initial count. */
694 if (count >= 65536)
695 count = 0;
696
697 comedi_8254_write(i8254: dev->pacer, counter: ct, val: count);
698}
699
700static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
701{
702 /* Counter ct, 8254 mode 1, initial count not written. */
703 comedi_8254_set_mode(i8254: dev->pacer, counter: ct, mode: I8254_MODE1);
704}
705
706static int pci230_ai_eoc(struct comedi_device *dev,
707 struct comedi_subdevice *s,
708 struct comedi_insn *insn,
709 unsigned long context)
710{
711 struct pci230_private *devpriv = dev->private;
712 unsigned int status;
713
714 status = inw(port: devpriv->daqio + PCI230_ADCCON);
715 if ((status & PCI230_ADC_FIFO_EMPTY) == 0)
716 return 0;
717 return -EBUSY;
718}
719
720static int pci230_ai_insn_read(struct comedi_device *dev,
721 struct comedi_subdevice *s,
722 struct comedi_insn *insn, unsigned int *data)
723{
724 struct pci230_private *devpriv = dev->private;
725 unsigned int n;
726 unsigned int chan, range, aref;
727 unsigned int gainshift;
728 unsigned short adccon, adcen;
729 int ret;
730
731 /* Unpack channel and range. */
732 chan = CR_CHAN(insn->chanspec);
733 range = CR_RANGE(insn->chanspec);
734 aref = CR_AREF(insn->chanspec);
735 if (aref == AREF_DIFF) {
736 /* Differential. */
737 if (chan >= s->n_chan / 2) {
738 dev_dbg(dev->class_dev,
739 "%s: differential channel number out of range 0 to %u\n",
740 __func__, (s->n_chan / 2) - 1);
741 return -EINVAL;
742 }
743 }
744
745 /*
746 * Use Z2-CT2 as a conversion trigger instead of the built-in
747 * software trigger, as otherwise triggering of differential channels
748 * doesn't work properly for some versions of PCI230/260. Also set
749 * FIFO mode because the ADC busy bit only works for software triggers.
750 */
751 adccon = PCI230_ADC_TRIG_Z2CT2 | PCI230_ADC_FIFO_EN;
752 /* Set Z2-CT2 output low to avoid any false triggers. */
753 comedi_8254_set_mode(i8254: dev->pacer, counter: 2, mode: I8254_MODE0);
754 devpriv->ai_bipolar = comedi_range_is_bipolar(s, range);
755 if (aref == AREF_DIFF) {
756 /* Differential. */
757 gainshift = chan * 2;
758 if (devpriv->hwver == 0) {
759 /*
760 * Original PCI230/260 expects both inputs of the
761 * differential channel to be enabled.
762 */
763 adcen = 3 << gainshift;
764 } else {
765 /*
766 * PCI230+/260+ expects only one input of the
767 * differential channel to be enabled.
768 */
769 adcen = 1 << gainshift;
770 }
771 adccon |= PCI230_ADC_IM_DIF;
772 } else {
773 /* Single ended. */
774 adcen = 1 << chan;
775 gainshift = chan & ~1;
776 adccon |= PCI230_ADC_IM_SE;
777 }
778 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift)) |
779 (pci230_ai_gain[range] << gainshift);
780 if (devpriv->ai_bipolar)
781 adccon |= PCI230_ADC_IR_BIP;
782 else
783 adccon |= PCI230_ADC_IR_UNI;
784
785 /*
786 * Enable only this channel in the scan list - otherwise by default
787 * we'll get one sample from each channel.
788 */
789 outw(value: adcen, port: devpriv->daqio + PCI230_ADCEN);
790
791 /* Set gain for channel. */
792 outw(value: devpriv->adcg, port: devpriv->daqio + PCI230_ADCG);
793
794 /* Specify uni/bip, se/diff, conversion source, and reset FIFO. */
795 devpriv->adccon = adccon;
796 outw(value: adccon | PCI230_ADC_FIFO_RESET, port: devpriv->daqio + PCI230_ADCCON);
797
798 /* Convert n samples */
799 for (n = 0; n < insn->n; n++) {
800 /*
801 * Trigger conversion by toggling Z2-CT2 output
802 * (finish with output high).
803 */
804 comedi_8254_set_mode(i8254: dev->pacer, counter: 2, mode: I8254_MODE0);
805 comedi_8254_set_mode(i8254: dev->pacer, counter: 2, mode: I8254_MODE1);
806
807 /* wait for conversion to end */
808 ret = comedi_timeout(dev, s, insn, cb: pci230_ai_eoc, context: 0);
809 if (ret)
810 return ret;
811
812 /* read data */
813 data[n] = pci230_ai_read(dev);
814 }
815
816 /* return the number of samples read/written */
817 return n;
818}
819
820static int pci230_ao_insn_write(struct comedi_device *dev,
821 struct comedi_subdevice *s,
822 struct comedi_insn *insn,
823 unsigned int *data)
824{
825 struct pci230_private *devpriv = dev->private;
826 unsigned int chan = CR_CHAN(insn->chanspec);
827 unsigned int range = CR_RANGE(insn->chanspec);
828 unsigned int val = s->readback[chan];
829 int i;
830
831 /*
832 * Set range - see analogue output range table; 0 => unipolar 10V,
833 * 1 => bipolar +/-10V range scale
834 */
835 devpriv->ao_bipolar = comedi_range_is_bipolar(s, range);
836 outw(value: range, port: devpriv->daqio + PCI230_DACCON);
837
838 for (i = 0; i < insn->n; i++) {
839 val = data[i];
840 pci230_ao_write_nofifo(dev, datum: val, chan);
841 }
842 s->readback[chan] = val;
843
844 return insn->n;
845}
846
847static int pci230_ao_check_chanlist(struct comedi_device *dev,
848 struct comedi_subdevice *s,
849 struct comedi_cmd *cmd)
850{
851 unsigned int prev_chan = CR_CHAN(cmd->chanlist[0]);
852 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
853 int i;
854
855 for (i = 1; i < cmd->chanlist_len; i++) {
856 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
857 unsigned int range = CR_RANGE(cmd->chanlist[i]);
858
859 if (chan < prev_chan) {
860 dev_dbg(dev->class_dev,
861 "%s: channel numbers must increase\n",
862 __func__);
863 return -EINVAL;
864 }
865
866 if (range != range0) {
867 dev_dbg(dev->class_dev,
868 "%s: channels must have the same range\n",
869 __func__);
870 return -EINVAL;
871 }
872
873 prev_chan = chan;
874 }
875
876 return 0;
877}
878
879static int pci230_ao_cmdtest(struct comedi_device *dev,
880 struct comedi_subdevice *s, struct comedi_cmd *cmd)
881{
882 const struct pci230_board *board = dev->board_ptr;
883 struct pci230_private *devpriv = dev->private;
884 int err = 0;
885 unsigned int tmp;
886
887 /* Step 1 : check if triggers are trivially valid */
888
889 err |= comedi_check_trigger_src(src: &cmd->start_src, TRIG_INT);
890
891 tmp = TRIG_TIMER | TRIG_INT;
892 if (board->min_hwver > 0 && devpriv->hwver >= 2) {
893 /*
894 * For PCI230+ hardware version 2 onwards, allow external
895 * trigger from EXTTRIG/EXTCONVCLK input (PCI230+ pin 25).
896 *
897 * FIXME: The permitted scan_begin_src values shouldn't depend
898 * on devpriv->hwver (the detected card's actual hardware
899 * version). They should only depend on board->min_hwver
900 * (the static capabilities of the configured card). To fix
901 * it, a new card model, e.g. "pci230+2" would have to be
902 * defined with min_hwver set to 2. It doesn't seem worth it
903 * for this alone. At the moment, please consider
904 * scan_begin_src==TRIG_EXT support to be a bonus rather than a
905 * guarantee!
906 */
907 tmp |= TRIG_EXT;
908 }
909 err |= comedi_check_trigger_src(src: &cmd->scan_begin_src, flags: tmp);
910
911 err |= comedi_check_trigger_src(src: &cmd->convert_src, TRIG_NOW);
912 err |= comedi_check_trigger_src(src: &cmd->scan_end_src, TRIG_COUNT);
913 err |= comedi_check_trigger_src(src: &cmd->stop_src, TRIG_COUNT | TRIG_NONE);
914
915 if (err)
916 return 1;
917
918 /* Step 2a : make sure trigger sources are unique */
919
920 err |= comedi_check_trigger_is_unique(src: cmd->scan_begin_src);
921 err |= comedi_check_trigger_is_unique(src: cmd->stop_src);
922
923 /* Step 2b : and mutually compatible */
924
925 if (err)
926 return 2;
927
928 /* Step 3: check if arguments are trivially valid */
929
930 err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg, val: 0);
931
932#define MAX_SPEED_AO 8000 /* 8000 ns => 125 kHz */
933/*
934 * Comedi limit due to unsigned int cmd. Driver limit =
935 * 2^16 (16bit * counter) * 1000000ns (1kHz onboard clock) = 65.536s
936 */
937#define MIN_SPEED_AO 4294967295u /* 4294967295ns = 4.29s */
938
939 switch (cmd->scan_begin_src) {
940 case TRIG_TIMER:
941 err |= comedi_check_trigger_arg_min(arg: &cmd->scan_begin_arg,
942 MAX_SPEED_AO);
943 err |= comedi_check_trigger_arg_max(arg: &cmd->scan_begin_arg,
944 MIN_SPEED_AO);
945 break;
946 case TRIG_EXT:
947 /*
948 * External trigger - for PCI230+ hardware version 2 onwards.
949 */
950 /* Trigger number must be 0. */
951 if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) {
952 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
953 ~CR_FLAGS_MASK);
954 err |= -EINVAL;
955 }
956 /*
957 * The only flags allowed are CR_EDGE and CR_INVERT.
958 * The CR_EDGE flag is ignored.
959 */
960 if (cmd->scan_begin_arg & CR_FLAGS_MASK &
961 ~(CR_EDGE | CR_INVERT)) {
962 cmd->scan_begin_arg =
963 COMBINE(cmd->scan_begin_arg, 0,
964 CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT));
965 err |= -EINVAL;
966 }
967 break;
968 default:
969 err |= comedi_check_trigger_arg_is(arg: &cmd->scan_begin_arg, val: 0);
970 break;
971 }
972
973 err |= comedi_check_trigger_arg_is(arg: &cmd->scan_end_arg,
974 val: cmd->chanlist_len);
975
976 if (cmd->stop_src == TRIG_COUNT)
977 err |= comedi_check_trigger_arg_min(arg: &cmd->stop_arg, val: 1);
978 else /* TRIG_NONE */
979 err |= comedi_check_trigger_arg_is(arg: &cmd->stop_arg, val: 0);
980
981 if (err)
982 return 3;
983
984 /* Step 4: fix up any arguments */
985
986 if (cmd->scan_begin_src == TRIG_TIMER) {
987 tmp = cmd->scan_begin_arg;
988 pci230_ns_to_single_timer(ns: &cmd->scan_begin_arg, flags: cmd->flags);
989 if (tmp != cmd->scan_begin_arg)
990 err++;
991 }
992
993 if (err)
994 return 4;
995
996 /* Step 5: check channel list if it exists */
997 if (cmd->chanlist && cmd->chanlist_len > 0)
998 err |= pci230_ao_check_chanlist(dev, s, cmd);
999
1000 if (err)
1001 return 5;
1002
1003 return 0;
1004}
1005
1006static void pci230_ao_stop(struct comedi_device *dev,
1007 struct comedi_subdevice *s)
1008{
1009 struct pci230_private *devpriv = dev->private;
1010 unsigned long irqflags;
1011 unsigned char intsrc;
1012 bool started;
1013 struct comedi_cmd *cmd;
1014
1015 spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
1016 started = devpriv->ao_cmd_started;
1017 devpriv->ao_cmd_started = false;
1018 spin_unlock_irqrestore(lock: &devpriv->ao_stop_spinlock, flags: irqflags);
1019 if (!started)
1020 return;
1021 cmd = &s->async->cmd;
1022 if (cmd->scan_begin_src == TRIG_TIMER) {
1023 /* Stop scan rate generator. */
1024 pci230_cancel_ct(dev, ct: 1);
1025 }
1026 /* Determine interrupt source. */
1027 if (devpriv->hwver < 2) {
1028 /* Not using DAC FIFO. Using CT1 interrupt. */
1029 intsrc = PCI230_INT_ZCLK_CT1;
1030 } else {
1031 /* Using DAC FIFO interrupt. */
1032 intsrc = PCI230P2_INT_DAC;
1033 }
1034 /*
1035 * Disable interrupt and wait for interrupt routine to finish running
1036 * unless we are called from the interrupt routine.
1037 */
1038 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1039 devpriv->ier &= ~intsrc;
1040 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
1041 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
1042 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1043 }
1044 outb(value: devpriv->ier, port: dev->iobase + PCI230_INT_SCE);
1045 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
1046 if (devpriv->hwver >= 2) {
1047 /*
1048 * Using DAC FIFO. Reset FIFO, clear underrun error,
1049 * disable FIFO.
1050 */
1051 devpriv->daccon &= PCI230_DAC_OR_MASK;
1052 outw(value: devpriv->daccon | PCI230P2_DAC_FIFO_RESET |
1053 PCI230P2_DAC_FIFO_UNDERRUN_CLEAR,
1054 port: devpriv->daqio + PCI230_DACCON);
1055 }
1056 /* Release resources. */
1057 pci230_release_all_resources(dev, owner: OWNER_AOCMD);
1058}
1059
1060static void pci230_handle_ao_nofifo(struct comedi_device *dev,
1061 struct comedi_subdevice *s)
1062{
1063 struct comedi_async *async = s->async;
1064 struct comedi_cmd *cmd = &async->cmd;
1065 unsigned short data;
1066 int i;
1067
1068 if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
1069 return;
1070
1071 for (i = 0; i < cmd->chanlist_len; i++) {
1072 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
1073
1074 if (!comedi_buf_read_samples(s, data: &data, nsamples: 1)) {
1075 async->events |= COMEDI_CB_OVERFLOW;
1076 return;
1077 }
1078 pci230_ao_write_nofifo(dev, datum: data, chan);
1079 s->readback[chan] = data;
1080 }
1081
1082 if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
1083 async->events |= COMEDI_CB_EOA;
1084}
1085
1086/*
1087 * Loads DAC FIFO (if using it) from buffer.
1088 * Returns false if AO finished due to completion or error, true if still going.
1089 */
1090static bool pci230_handle_ao_fifo(struct comedi_device *dev,
1091 struct comedi_subdevice *s)
1092{
1093 struct pci230_private *devpriv = dev->private;
1094 struct comedi_async *async = s->async;
1095 struct comedi_cmd *cmd = &async->cmd;
1096 unsigned int num_scans = comedi_nscans_left(s, nscans: 0);
1097 unsigned int room;
1098 unsigned short dacstat;
1099 unsigned int i, n;
1100 unsigned int events = 0;
1101
1102 /* Get DAC FIFO status. */
1103 dacstat = inw(port: devpriv->daqio + PCI230_DACCON);
1104
1105 if (cmd->stop_src == TRIG_COUNT && num_scans == 0)
1106 events |= COMEDI_CB_EOA;
1107
1108 if (events == 0) {
1109 /* Check for FIFO underrun. */
1110 if (dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) {
1111 dev_err(dev->class_dev, "AO FIFO underrun\n");
1112 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
1113 }
1114 /*
1115 * Check for buffer underrun if FIFO less than half full
1116 * (otherwise there will be loads of "DAC FIFO not half full"
1117 * interrupts).
1118 */
1119 if (num_scans == 0 &&
1120 (dacstat & PCI230P2_DAC_FIFO_HALF) == 0) {
1121 dev_err(dev->class_dev, "AO buffer underrun\n");
1122 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
1123 }
1124 }
1125 if (events == 0) {
1126 /* Determine how much room is in the FIFO (in samples). */
1127 if (dacstat & PCI230P2_DAC_FIFO_FULL)
1128 room = PCI230P2_DAC_FIFOROOM_FULL;
1129 else if (dacstat & PCI230P2_DAC_FIFO_HALF)
1130 room = PCI230P2_DAC_FIFOROOM_HALFTOFULL;
1131 else if (dacstat & PCI230P2_DAC_FIFO_EMPTY)
1132 room = PCI230P2_DAC_FIFOROOM_EMPTY;
1133 else
1134 room = PCI230P2_DAC_FIFOROOM_ONETOHALF;
1135 /* Convert room to number of scans that can be added. */
1136 room /= cmd->chanlist_len;
1137 /* Determine number of scans to process. */
1138 if (num_scans > room)
1139 num_scans = room;
1140 /* Process scans. */
1141 for (n = 0; n < num_scans; n++) {
1142 for (i = 0; i < cmd->chanlist_len; i++) {
1143 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
1144 unsigned short datum;
1145
1146 comedi_buf_read_samples(s, data: &datum, nsamples: 1);
1147 pci230_ao_write_fifo(dev, datum, chan);
1148 s->readback[chan] = datum;
1149 }
1150 }
1151
1152 if (cmd->stop_src == TRIG_COUNT &&
1153 async->scans_done >= cmd->stop_arg) {
1154 /*
1155 * All data for the command has been written
1156 * to FIFO. Set FIFO interrupt trigger level
1157 * to 'empty'.
1158 */
1159 devpriv->daccon &= ~PCI230P2_DAC_INT_FIFO_MASK;
1160 devpriv->daccon |= PCI230P2_DAC_INT_FIFO_EMPTY;
1161 outw(value: devpriv->daccon, port: devpriv->daqio + PCI230_DACCON);
1162 }
1163 /* Check if FIFO underrun occurred while writing to FIFO. */
1164 dacstat = inw(port: devpriv->daqio + PCI230_DACCON);
1165 if (dacstat & PCI230P2_DAC_FIFO_UNDERRUN_LATCHED) {
1166 dev_err(dev->class_dev, "AO FIFO underrun\n");
1167 events |= COMEDI_CB_OVERFLOW | COMEDI_CB_ERROR;
1168 }
1169 }
1170 async->events |= events;
1171 return !(async->events & COMEDI_CB_CANCEL_MASK);
1172}
1173
1174static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev,
1175 struct comedi_subdevice *s,
1176 unsigned int trig_num)
1177{
1178 struct pci230_private *devpriv = dev->private;
1179 unsigned long irqflags;
1180
1181 if (trig_num)
1182 return -EINVAL;
1183
1184 spin_lock_irqsave(&devpriv->ao_stop_spinlock, irqflags);
1185 if (!devpriv->ao_cmd_started) {
1186 spin_unlock_irqrestore(lock: &devpriv->ao_stop_spinlock, flags: irqflags);
1187 return 1;
1188 }
1189 /* Perform scan. */
1190 if (devpriv->hwver < 2) {
1191 /* Not using DAC FIFO. */
1192 spin_unlock_irqrestore(lock: &devpriv->ao_stop_spinlock, flags: irqflags);
1193 pci230_handle_ao_nofifo(dev, s);
1194 comedi_handle_events(dev, s);
1195 } else {
1196 /* Using DAC FIFO. */
1197 /* Read DACSWTRIG register to trigger conversion. */
1198 inw(port: devpriv->daqio + PCI230P2_DACSWTRIG);
1199 spin_unlock_irqrestore(lock: &devpriv->ao_stop_spinlock, flags: irqflags);
1200 }
1201 /* Delay. Should driver be responsible for this? */
1202 /* XXX TODO: See if DAC busy bit can be used. */
1203 udelay(8);
1204 return 1;
1205}
1206
1207static void pci230_ao_start(struct comedi_device *dev,
1208 struct comedi_subdevice *s)
1209{
1210 struct pci230_private *devpriv = dev->private;
1211 struct comedi_async *async = s->async;
1212 struct comedi_cmd *cmd = &async->cmd;
1213 unsigned long irqflags;
1214
1215 devpriv->ao_cmd_started = true;
1216
1217 if (devpriv->hwver >= 2) {
1218 /* Using DAC FIFO. */
1219 unsigned short scantrig;
1220 bool run;
1221
1222 /* Preload FIFO data. */
1223 run = pci230_handle_ao_fifo(dev, s);
1224 comedi_handle_events(dev, s);
1225 if (!run) {
1226 /* Stopped. */
1227 return;
1228 }
1229 /* Set scan trigger source. */
1230 switch (cmd->scan_begin_src) {
1231 case TRIG_TIMER:
1232 scantrig = PCI230P2_DAC_TRIG_Z2CT1;
1233 break;
1234 case TRIG_EXT:
1235 /* Trigger on EXTTRIG/EXTCONVCLK pin. */
1236 if ((cmd->scan_begin_arg & CR_INVERT) == 0) {
1237 /* +ve edge */
1238 scantrig = PCI230P2_DAC_TRIG_EXTP;
1239 } else {
1240 /* -ve edge */
1241 scantrig = PCI230P2_DAC_TRIG_EXTN;
1242 }
1243 break;
1244 case TRIG_INT:
1245 scantrig = PCI230P2_DAC_TRIG_SW;
1246 break;
1247 default:
1248 /* Shouldn't get here. */
1249 scantrig = PCI230P2_DAC_TRIG_NONE;
1250 break;
1251 }
1252 devpriv->daccon =
1253 (devpriv->daccon & ~PCI230P2_DAC_TRIG_MASK) | scantrig;
1254 outw(value: devpriv->daccon, port: devpriv->daqio + PCI230_DACCON);
1255 }
1256 switch (cmd->scan_begin_src) {
1257 case TRIG_TIMER:
1258 if (devpriv->hwver < 2) {
1259 /* Not using DAC FIFO. */
1260 /* Enable CT1 timer interrupt. */
1261 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1262 devpriv->ier |= PCI230_INT_ZCLK_CT1;
1263 outb(value: devpriv->ier, port: dev->iobase + PCI230_INT_SCE);
1264 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock,
1265 flags: irqflags);
1266 }
1267 /* Set CT1 gate high to start counting. */
1268 outb(value: pci230_gat_config(chan: 1, GAT_VCC),
1269 port: dev->iobase + PCI230_ZGAT_SCE);
1270 break;
1271 case TRIG_INT:
1272 async->inttrig = pci230_ao_inttrig_scan_begin;
1273 break;
1274 }
1275 if (devpriv->hwver >= 2) {
1276 /* Using DAC FIFO. Enable DAC FIFO interrupt. */
1277 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1278 devpriv->ier |= PCI230P2_INT_DAC;
1279 outb(value: devpriv->ier, port: dev->iobase + PCI230_INT_SCE);
1280 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
1281 }
1282}
1283
1284static int pci230_ao_inttrig_start(struct comedi_device *dev,
1285 struct comedi_subdevice *s,
1286 unsigned int trig_num)
1287{
1288 struct comedi_cmd *cmd = &s->async->cmd;
1289
1290 if (trig_num != cmd->start_src)
1291 return -EINVAL;
1292
1293 s->async->inttrig = NULL;
1294 pci230_ao_start(dev, s);
1295
1296 return 1;
1297}
1298
1299static int pci230_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
1300{
1301 struct pci230_private *devpriv = dev->private;
1302 unsigned short daccon;
1303 unsigned int range;
1304
1305 /* Get the command. */
1306 struct comedi_cmd *cmd = &s->async->cmd;
1307
1308 if (cmd->scan_begin_src == TRIG_TIMER) {
1309 /* Claim Z2-CT1. */
1310 if (!pci230_claim_shared(dev, res_mask: RES_Z2CT1, owner: OWNER_AOCMD))
1311 return -EBUSY;
1312 }
1313
1314 /*
1315 * Set range - see analogue output range table; 0 => unipolar 10V,
1316 * 1 => bipolar +/-10V range scale
1317 */
1318 range = CR_RANGE(cmd->chanlist[0]);
1319 devpriv->ao_bipolar = comedi_range_is_bipolar(s, range);
1320 daccon = devpriv->ao_bipolar ? PCI230_DAC_OR_BIP : PCI230_DAC_OR_UNI;
1321 /* Use DAC FIFO for hardware version 2 onwards. */
1322 if (devpriv->hwver >= 2) {
1323 unsigned short dacen;
1324 unsigned int i;
1325
1326 dacen = 0;
1327 for (i = 0; i < cmd->chanlist_len; i++)
1328 dacen |= 1 << CR_CHAN(cmd->chanlist[i]);
1329
1330 /* Set channel scan list. */
1331 outw(value: dacen, port: devpriv->daqio + PCI230P2_DACEN);
1332 /*
1333 * Enable DAC FIFO.
1334 * Set DAC scan source to 'none'.
1335 * Set DAC FIFO interrupt trigger level to 'not half full'.
1336 * Reset DAC FIFO and clear underrun.
1337 *
1338 * N.B. DAC FIFO interrupts are currently disabled.
1339 */
1340 daccon |= PCI230P2_DAC_FIFO_EN | PCI230P2_DAC_FIFO_RESET |
1341 PCI230P2_DAC_FIFO_UNDERRUN_CLEAR |
1342 PCI230P2_DAC_TRIG_NONE | PCI230P2_DAC_INT_FIFO_NHALF;
1343 }
1344
1345 /* Set DACCON. */
1346 outw(value: daccon, port: devpriv->daqio + PCI230_DACCON);
1347 /* Preserve most of DACCON apart from write-only, transient bits. */
1348 devpriv->daccon = daccon & ~(PCI230P2_DAC_FIFO_RESET |
1349 PCI230P2_DAC_FIFO_UNDERRUN_CLEAR);
1350
1351 if (cmd->scan_begin_src == TRIG_TIMER) {
1352 /*
1353 * Set the counter timer 1 to the specified scan frequency.
1354 * cmd->scan_begin_arg is sampling period in ns.
1355 * Gate it off for now.
1356 */
1357 outb(value: pci230_gat_config(chan: 1, GAT_GND),
1358 port: dev->iobase + PCI230_ZGAT_SCE);
1359 pci230_ct_setup_ns_mode(dev, ct: 1, mode: I8254_MODE3,
1360 ns: cmd->scan_begin_arg,
1361 flags: cmd->flags);
1362 }
1363
1364 /* N.B. cmd->start_src == TRIG_INT */
1365 s->async->inttrig = pci230_ao_inttrig_start;
1366
1367 return 0;
1368}
1369
1370static int pci230_ao_cancel(struct comedi_device *dev,
1371 struct comedi_subdevice *s)
1372{
1373 pci230_ao_stop(dev, s);
1374 return 0;
1375}
1376
1377static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
1378{
1379 unsigned int min_scan_period, chanlist_len;
1380 int err = 0;
1381
1382 chanlist_len = cmd->chanlist_len;
1383 if (cmd->chanlist_len == 0)
1384 chanlist_len = 1;
1385
1386 min_scan_period = chanlist_len * cmd->convert_arg;
1387 if (min_scan_period < chanlist_len ||
1388 min_scan_period < cmd->convert_arg) {
1389 /* Arithmetic overflow. */
1390 min_scan_period = UINT_MAX;
1391 err++;
1392 }
1393 if (cmd->scan_begin_arg < min_scan_period) {
1394 cmd->scan_begin_arg = min_scan_period;
1395 err++;
1396 }
1397
1398 return !err;
1399}
1400
1401static int pci230_ai_check_chanlist(struct comedi_device *dev,
1402 struct comedi_subdevice *s,
1403 struct comedi_cmd *cmd)
1404{
1405 struct pci230_private *devpriv = dev->private;
1406 unsigned int max_diff_chan = (s->n_chan / 2) - 1;
1407 unsigned int prev_chan = 0;
1408 unsigned int prev_range = 0;
1409 unsigned int prev_aref = 0;
1410 bool prev_bipolar = false;
1411 unsigned int subseq_len = 0;
1412 int i;
1413
1414 for (i = 0; i < cmd->chanlist_len; i++) {
1415 unsigned int chanspec = cmd->chanlist[i];
1416 unsigned int chan = CR_CHAN(chanspec);
1417 unsigned int range = CR_RANGE(chanspec);
1418 unsigned int aref = CR_AREF(chanspec);
1419 bool bipolar = comedi_range_is_bipolar(s, range);
1420
1421 if (aref == AREF_DIFF && chan >= max_diff_chan) {
1422 dev_dbg(dev->class_dev,
1423 "%s: differential channel number out of range 0 to %u\n",
1424 __func__, max_diff_chan);
1425 return -EINVAL;
1426 }
1427
1428 if (i > 0) {
1429 /*
1430 * Channel numbers must strictly increase or
1431 * subsequence must repeat exactly.
1432 */
1433 if (chan <= prev_chan && subseq_len == 0)
1434 subseq_len = i;
1435
1436 if (subseq_len > 0 &&
1437 cmd->chanlist[i % subseq_len] != chanspec) {
1438 dev_dbg(dev->class_dev,
1439 "%s: channel numbers must increase or sequence must repeat exactly\n",
1440 __func__);
1441 return -EINVAL;
1442 }
1443
1444 if (aref != prev_aref) {
1445 dev_dbg(dev->class_dev,
1446 "%s: channel sequence analogue references must be all the same (single-ended or differential)\n",
1447 __func__);
1448 return -EINVAL;
1449 }
1450
1451 if (bipolar != prev_bipolar) {
1452 dev_dbg(dev->class_dev,
1453 "%s: channel sequence ranges must be all bipolar or all unipolar\n",
1454 __func__);
1455 return -EINVAL;
1456 }
1457
1458 if (aref != AREF_DIFF && range != prev_range &&
1459 ((chan ^ prev_chan) & ~1) == 0) {
1460 dev_dbg(dev->class_dev,
1461 "%s: single-ended channel pairs must have the same range\n",
1462 __func__);
1463 return -EINVAL;
1464 }
1465 }
1466 prev_chan = chan;
1467 prev_range = range;
1468 prev_aref = aref;
1469 prev_bipolar = bipolar;
1470 }
1471
1472 if (subseq_len == 0)
1473 subseq_len = cmd->chanlist_len;
1474
1475 if (cmd->chanlist_len % subseq_len) {
1476 dev_dbg(dev->class_dev,
1477 "%s: sequence must repeat exactly\n", __func__);
1478 return -EINVAL;
1479 }
1480
1481 /*
1482 * Buggy PCI230+ or PCI260+ requires channel 0 to be (first) in the
1483 * sequence if the sequence contains more than one channel. Hardware
1484 * versions 1 and 2 have the bug. There is no hardware version 3.
1485 *
1486 * Actually, there are two firmwares that report themselves as
1487 * hardware version 1 (the boards have different ADC chips with
1488 * slightly different timing requirements, which was supposed to
1489 * be invisible to software). The first one doesn't seem to have
1490 * the bug, but the second one does, and we can't tell them apart!
1491 */
1492 if (devpriv->hwver > 0 && devpriv->hwver < 4) {
1493 if (subseq_len > 1 && CR_CHAN(cmd->chanlist[0])) {
1494 dev_info(dev->class_dev,
1495 "amplc_pci230: ai_cmdtest: Buggy PCI230+/260+ h/w version %u requires first channel of multi-channel sequence to be 0 (corrected in h/w version 4)\n",
1496 devpriv->hwver);
1497 return -EINVAL;
1498 }
1499 }
1500
1501 return 0;
1502}
1503
1504static int pci230_ai_cmdtest(struct comedi_device *dev,
1505 struct comedi_subdevice *s, struct comedi_cmd *cmd)
1506{
1507 const struct pci230_board *board = dev->board_ptr;
1508 struct pci230_private *devpriv = dev->private;
1509 int err = 0;
1510 unsigned int tmp;
1511
1512 /* Step 1 : check if triggers are trivially valid */
1513
1514 err |= comedi_check_trigger_src(src: &cmd->start_src, TRIG_NOW | TRIG_INT);
1515
1516 tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT;
1517 if (board->have_dio || board->min_hwver > 0) {
1518 /*
1519 * Unfortunately, we cannot trigger a scan off an external
1520 * source on the PCI260 board, since it uses the PPIC0 (DIO)
1521 * input, which isn't present on the PCI260. For PCI260+
1522 * we can use the EXTTRIG/EXTCONVCLK input on pin 17 instead.
1523 */
1524 tmp |= TRIG_EXT;
1525 }
1526 err |= comedi_check_trigger_src(src: &cmd->scan_begin_src, flags: tmp);
1527 err |= comedi_check_trigger_src(src: &cmd->convert_src,
1528 TRIG_TIMER | TRIG_INT | TRIG_EXT);
1529 err |= comedi_check_trigger_src(src: &cmd->scan_end_src, TRIG_COUNT);
1530 err |= comedi_check_trigger_src(src: &cmd->stop_src, TRIG_COUNT | TRIG_NONE);
1531
1532 if (err)
1533 return 1;
1534
1535 /* Step 2a : make sure trigger sources are unique */
1536
1537 err |= comedi_check_trigger_is_unique(src: cmd->start_src);
1538 err |= comedi_check_trigger_is_unique(src: cmd->scan_begin_src);
1539 err |= comedi_check_trigger_is_unique(src: cmd->convert_src);
1540 err |= comedi_check_trigger_is_unique(src: cmd->stop_src);
1541
1542 /* Step 2b : and mutually compatible */
1543
1544 /*
1545 * If scan_begin_src is not TRIG_FOLLOW, then a monostable will be
1546 * set up to generate a fixed number of timed conversion pulses.
1547 */
1548 if (cmd->scan_begin_src != TRIG_FOLLOW &&
1549 cmd->convert_src != TRIG_TIMER)
1550 err |= -EINVAL;
1551
1552 if (err)
1553 return 2;
1554
1555 /* Step 3: check if arguments are trivially valid */
1556
1557 err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg, val: 0);
1558
1559#define MAX_SPEED_AI_SE 3200 /* PCI230 SE: 3200 ns => 312.5 kHz */
1560#define MAX_SPEED_AI_DIFF 8000 /* PCI230 DIFF: 8000 ns => 125 kHz */
1561#define MAX_SPEED_AI_PLUS 4000 /* PCI230+: 4000 ns => 250 kHz */
1562/*
1563 * Comedi limit due to unsigned int cmd. Driver limit =
1564 * 2^16 (16bit * counter) * 1000000ns (1kHz onboard clock) = 65.536s
1565 */
1566#define MIN_SPEED_AI 4294967295u /* 4294967295ns = 4.29s */
1567
1568 if (cmd->convert_src == TRIG_TIMER) {
1569 unsigned int max_speed_ai;
1570
1571 if (devpriv->hwver == 0) {
1572 /*
1573 * PCI230 or PCI260. Max speed depends whether
1574 * single-ended or pseudo-differential.
1575 */
1576 if (cmd->chanlist && cmd->chanlist_len > 0) {
1577 /* Peek analogue reference of first channel. */
1578 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF)
1579 max_speed_ai = MAX_SPEED_AI_DIFF;
1580 else
1581 max_speed_ai = MAX_SPEED_AI_SE;
1582
1583 } else {
1584 /* No channel list. Assume single-ended. */
1585 max_speed_ai = MAX_SPEED_AI_SE;
1586 }
1587 } else {
1588 /* PCI230+ or PCI260+. */
1589 max_speed_ai = MAX_SPEED_AI_PLUS;
1590 }
1591
1592 err |= comedi_check_trigger_arg_min(arg: &cmd->convert_arg,
1593 val: max_speed_ai);
1594 err |= comedi_check_trigger_arg_max(arg: &cmd->convert_arg,
1595 MIN_SPEED_AI);
1596 } else if (cmd->convert_src == TRIG_EXT) {
1597 /*
1598 * external trigger
1599 *
1600 * convert_arg == (CR_EDGE | 0)
1601 * => trigger on +ve edge.
1602 * convert_arg == (CR_EDGE | CR_INVERT | 0)
1603 * => trigger on -ve edge.
1604 */
1605 if (cmd->convert_arg & CR_FLAGS_MASK) {
1606 /* Trigger number must be 0. */
1607 if (cmd->convert_arg & ~CR_FLAGS_MASK) {
1608 cmd->convert_arg = COMBINE(cmd->convert_arg, 0,
1609 ~CR_FLAGS_MASK);
1610 err |= -EINVAL;
1611 }
1612 /*
1613 * The only flags allowed are CR_INVERT and CR_EDGE.
1614 * CR_EDGE is required.
1615 */
1616 if ((cmd->convert_arg & CR_FLAGS_MASK & ~CR_INVERT) !=
1617 CR_EDGE) {
1618 /* Set CR_EDGE, preserve CR_INVERT. */
1619 cmd->convert_arg =
1620 COMBINE(cmd->start_arg, CR_EDGE | 0,
1621 CR_FLAGS_MASK & ~CR_INVERT);
1622 err |= -EINVAL;
1623 }
1624 } else {
1625 /*
1626 * Backwards compatibility with previous versions:
1627 * convert_arg == 0 => trigger on -ve edge.
1628 * convert_arg == 1 => trigger on +ve edge.
1629 */
1630 err |= comedi_check_trigger_arg_max(arg: &cmd->convert_arg,
1631 val: 1);
1632 }
1633 } else {
1634 err |= comedi_check_trigger_arg_is(arg: &cmd->convert_arg, val: 0);
1635 }
1636
1637 err |= comedi_check_trigger_arg_is(arg: &cmd->scan_end_arg,
1638 val: cmd->chanlist_len);
1639
1640 if (cmd->stop_src == TRIG_COUNT)
1641 err |= comedi_check_trigger_arg_min(arg: &cmd->stop_arg, val: 1);
1642 else /* TRIG_NONE */
1643 err |= comedi_check_trigger_arg_is(arg: &cmd->stop_arg, val: 0);
1644
1645 if (cmd->scan_begin_src == TRIG_EXT) {
1646 /*
1647 * external "trigger" to begin each scan:
1648 * scan_begin_arg==0 => use PPC0 input -> gate of CT0 -> gate
1649 * of CT2 (sample convert trigger is CT2)
1650 */
1651 if (cmd->scan_begin_arg & ~CR_FLAGS_MASK) {
1652 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1653 ~CR_FLAGS_MASK);
1654 err |= -EINVAL;
1655 }
1656 /* The only flag allowed is CR_EDGE, which is ignored. */
1657 if (cmd->scan_begin_arg & CR_FLAGS_MASK & ~CR_EDGE) {
1658 cmd->scan_begin_arg = COMBINE(cmd->scan_begin_arg, 0,
1659 CR_FLAGS_MASK & ~CR_EDGE);
1660 err |= -EINVAL;
1661 }
1662 } else if (cmd->scan_begin_src == TRIG_TIMER) {
1663 /* N.B. cmd->convert_arg is also TRIG_TIMER */
1664 if (!pci230_ai_check_scan_period(cmd))
1665 err |= -EINVAL;
1666
1667 } else {
1668 err |= comedi_check_trigger_arg_is(arg: &cmd->scan_begin_arg, val: 0);
1669 }
1670
1671 if (err)
1672 return 3;
1673
1674 /* Step 4: fix up any arguments */
1675
1676 if (cmd->convert_src == TRIG_TIMER) {
1677 tmp = cmd->convert_arg;
1678 pci230_ns_to_single_timer(ns: &cmd->convert_arg, flags: cmd->flags);
1679 if (tmp != cmd->convert_arg)
1680 err++;
1681 }
1682
1683 if (cmd->scan_begin_src == TRIG_TIMER) {
1684 /* N.B. cmd->convert_arg is also TRIG_TIMER */
1685 tmp = cmd->scan_begin_arg;
1686 pci230_ns_to_single_timer(ns: &cmd->scan_begin_arg, flags: cmd->flags);
1687 if (!pci230_ai_check_scan_period(cmd)) {
1688 /* Was below minimum required. Round up. */
1689 pci230_ns_to_single_timer(ns: &cmd->scan_begin_arg,
1690 CMDF_ROUND_UP);
1691 pci230_ai_check_scan_period(cmd);
1692 }
1693 if (tmp != cmd->scan_begin_arg)
1694 err++;
1695 }
1696
1697 if (err)
1698 return 4;
1699
1700 /* Step 5: check channel list if it exists */
1701 if (cmd->chanlist && cmd->chanlist_len > 0)
1702 err |= pci230_ai_check_chanlist(dev, s, cmd);
1703
1704 if (err)
1705 return 5;
1706
1707 return 0;
1708}
1709
1710static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev,
1711 struct comedi_subdevice *s)
1712{
1713 struct pci230_private *devpriv = dev->private;
1714 struct comedi_cmd *cmd = &s->async->cmd;
1715 unsigned int wake;
1716 unsigned short triglev;
1717 unsigned short adccon;
1718
1719 if (cmd->flags & CMDF_WAKE_EOS)
1720 wake = cmd->scan_end_arg - s->async->cur_chan;
1721 else
1722 wake = comedi_nsamples_left(s, PCI230_ADC_FIFOLEVEL_HALFFULL);
1723
1724 if (wake >= PCI230_ADC_FIFOLEVEL_HALFFULL) {
1725 triglev = PCI230_ADC_INT_FIFO_HALF;
1726 } else if (wake > 1 && devpriv->hwver > 0) {
1727 /* PCI230+/260+ programmable FIFO interrupt level. */
1728 if (devpriv->adcfifothresh != wake) {
1729 devpriv->adcfifothresh = wake;
1730 outw(value: wake, port: devpriv->daqio + PCI230P_ADCFFTH);
1731 }
1732 triglev = PCI230P_ADC_INT_FIFO_THRESH;
1733 } else {
1734 triglev = PCI230_ADC_INT_FIFO_NEMPTY;
1735 }
1736 adccon = (devpriv->adccon & ~PCI230_ADC_INT_FIFO_MASK) | triglev;
1737 if (adccon != devpriv->adccon) {
1738 devpriv->adccon = adccon;
1739 outw(value: adccon, port: devpriv->daqio + PCI230_ADCCON);
1740 }
1741}
1742
1743static int pci230_ai_inttrig_convert(struct comedi_device *dev,
1744 struct comedi_subdevice *s,
1745 unsigned int trig_num)
1746{
1747 struct pci230_private *devpriv = dev->private;
1748 unsigned long irqflags;
1749 unsigned int delayus;
1750
1751 if (trig_num)
1752 return -EINVAL;
1753
1754 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
1755 if (!devpriv->ai_cmd_started) {
1756 spin_unlock_irqrestore(lock: &devpriv->ai_stop_spinlock, flags: irqflags);
1757 return 1;
1758 }
1759 /*
1760 * Trigger conversion by toggling Z2-CT2 output.
1761 * Finish with output high.
1762 */
1763 comedi_8254_set_mode(i8254: dev->pacer, counter: 2, mode: I8254_MODE0);
1764 comedi_8254_set_mode(i8254: dev->pacer, counter: 2, mode: I8254_MODE1);
1765 /*
1766 * Delay. Should driver be responsible for this? An
1767 * alternative would be to wait until conversion is complete,
1768 * but we can't tell when it's complete because the ADC busy
1769 * bit has a different meaning when FIFO enabled (and when
1770 * FIFO not enabled, it only works for software triggers).
1771 */
1772 if ((devpriv->adccon & PCI230_ADC_IM_MASK) == PCI230_ADC_IM_DIF &&
1773 devpriv->hwver == 0) {
1774 /* PCI230/260 in differential mode */
1775 delayus = 8;
1776 } else {
1777 /* single-ended or PCI230+/260+ */
1778 delayus = 4;
1779 }
1780 spin_unlock_irqrestore(lock: &devpriv->ai_stop_spinlock, flags: irqflags);
1781 udelay(delayus);
1782 return 1;
1783}
1784
1785static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev,
1786 struct comedi_subdevice *s,
1787 unsigned int trig_num)
1788{
1789 struct pci230_private *devpriv = dev->private;
1790 unsigned long irqflags;
1791 unsigned char zgat;
1792
1793 if (trig_num)
1794 return -EINVAL;
1795
1796 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
1797 if (devpriv->ai_cmd_started) {
1798 /* Trigger scan by waggling CT0 gate source. */
1799 zgat = pci230_gat_config(chan: 0, GAT_GND);
1800 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
1801 zgat = pci230_gat_config(chan: 0, GAT_VCC);
1802 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
1803 }
1804 spin_unlock_irqrestore(lock: &devpriv->ai_stop_spinlock, flags: irqflags);
1805
1806 return 1;
1807}
1808
1809static void pci230_ai_stop(struct comedi_device *dev,
1810 struct comedi_subdevice *s)
1811{
1812 struct pci230_private *devpriv = dev->private;
1813 unsigned long irqflags;
1814 struct comedi_cmd *cmd;
1815 bool started;
1816
1817 spin_lock_irqsave(&devpriv->ai_stop_spinlock, irqflags);
1818 started = devpriv->ai_cmd_started;
1819 devpriv->ai_cmd_started = false;
1820 spin_unlock_irqrestore(lock: &devpriv->ai_stop_spinlock, flags: irqflags);
1821 if (!started)
1822 return;
1823 cmd = &s->async->cmd;
1824 if (cmd->convert_src == TRIG_TIMER) {
1825 /* Stop conversion rate generator. */
1826 pci230_cancel_ct(dev, ct: 2);
1827 }
1828 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1829 /* Stop scan period monostable. */
1830 pci230_cancel_ct(dev, ct: 0);
1831 }
1832 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1833 /*
1834 * Disable ADC interrupt and wait for interrupt routine to finish
1835 * running unless we are called from the interrupt routine.
1836 */
1837 devpriv->ier &= ~PCI230_INT_ADC;
1838 while (devpriv->intr_running && devpriv->intr_cpuid != THISCPU) {
1839 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
1840 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1841 }
1842 outb(value: devpriv->ier, port: dev->iobase + PCI230_INT_SCE);
1843 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
1844 /*
1845 * Reset FIFO, disable FIFO and set start conversion source to none.
1846 * Keep se/diff and bip/uni settings.
1847 */
1848 devpriv->adccon =
1849 (devpriv->adccon & (PCI230_ADC_IR_MASK | PCI230_ADC_IM_MASK)) |
1850 PCI230_ADC_TRIG_NONE;
1851 outw(value: devpriv->adccon | PCI230_ADC_FIFO_RESET,
1852 port: devpriv->daqio + PCI230_ADCCON);
1853 /* Release resources. */
1854 pci230_release_all_resources(dev, owner: OWNER_AICMD);
1855}
1856
1857static void pci230_ai_start(struct comedi_device *dev,
1858 struct comedi_subdevice *s)
1859{
1860 struct pci230_private *devpriv = dev->private;
1861 unsigned long irqflags;
1862 unsigned short conv;
1863 struct comedi_async *async = s->async;
1864 struct comedi_cmd *cmd = &async->cmd;
1865
1866 devpriv->ai_cmd_started = true;
1867
1868 /* Enable ADC FIFO trigger level interrupt. */
1869 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
1870 devpriv->ier |= PCI230_INT_ADC;
1871 outb(value: devpriv->ier, port: dev->iobase + PCI230_INT_SCE);
1872 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
1873
1874 /*
1875 * Update conversion trigger source which is currently set
1876 * to CT2 output, which is currently stuck high.
1877 */
1878 switch (cmd->convert_src) {
1879 default:
1880 conv = PCI230_ADC_TRIG_NONE;
1881 break;
1882 case TRIG_TIMER:
1883 /* Using CT2 output. */
1884 conv = PCI230_ADC_TRIG_Z2CT2;
1885 break;
1886 case TRIG_EXT:
1887 if (cmd->convert_arg & CR_EDGE) {
1888 if ((cmd->convert_arg & CR_INVERT) == 0) {
1889 /* Trigger on +ve edge. */
1890 conv = PCI230_ADC_TRIG_EXTP;
1891 } else {
1892 /* Trigger on -ve edge. */
1893 conv = PCI230_ADC_TRIG_EXTN;
1894 }
1895 } else {
1896 /* Backwards compatibility. */
1897 if (cmd->convert_arg) {
1898 /* Trigger on +ve edge. */
1899 conv = PCI230_ADC_TRIG_EXTP;
1900 } else {
1901 /* Trigger on -ve edge. */
1902 conv = PCI230_ADC_TRIG_EXTN;
1903 }
1904 }
1905 break;
1906 case TRIG_INT:
1907 /*
1908 * Use CT2 output for software trigger due to problems
1909 * in differential mode on PCI230/260.
1910 */
1911 conv = PCI230_ADC_TRIG_Z2CT2;
1912 break;
1913 }
1914 devpriv->adccon = (devpriv->adccon & ~PCI230_ADC_TRIG_MASK) | conv;
1915 outw(value: devpriv->adccon, port: devpriv->daqio + PCI230_ADCCON);
1916 if (cmd->convert_src == TRIG_INT)
1917 async->inttrig = pci230_ai_inttrig_convert;
1918
1919 /*
1920 * Update FIFO interrupt trigger level, which is currently
1921 * set to "full".
1922 */
1923 pci230_ai_update_fifo_trigger_level(dev, s);
1924 if (cmd->convert_src == TRIG_TIMER) {
1925 /* Update timer gates. */
1926 unsigned char zgat;
1927
1928 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1929 /*
1930 * Conversion timer CT2 needs to be gated by
1931 * inverted output of monostable CT2.
1932 */
1933 zgat = pci230_gat_config(chan: 2, GAT_NOUTNM2);
1934 } else {
1935 /*
1936 * Conversion timer CT2 needs to be gated on
1937 * continuously.
1938 */
1939 zgat = pci230_gat_config(chan: 2, GAT_VCC);
1940 }
1941 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
1942 if (cmd->scan_begin_src != TRIG_FOLLOW) {
1943 /* Set monostable CT0 trigger source. */
1944 switch (cmd->scan_begin_src) {
1945 default:
1946 zgat = pci230_gat_config(chan: 0, GAT_VCC);
1947 break;
1948 case TRIG_EXT:
1949 /*
1950 * For CT0 on PCI230, the external trigger
1951 * (gate) signal comes from PPC0, which is
1952 * channel 16 of the DIO subdevice. The
1953 * application needs to configure this as an
1954 * input in order to use it as an external scan
1955 * trigger.
1956 */
1957 zgat = pci230_gat_config(chan: 0, GAT_EXT);
1958 break;
1959 case TRIG_TIMER:
1960 /*
1961 * Monostable CT0 triggered by rising edge on
1962 * inverted output of CT1 (falling edge on CT1).
1963 */
1964 zgat = pci230_gat_config(chan: 0, GAT_NOUTNM2);
1965 break;
1966 case TRIG_INT:
1967 /*
1968 * Monostable CT0 is triggered by inttrig
1969 * function waggling the CT0 gate source.
1970 */
1971 zgat = pci230_gat_config(chan: 0, GAT_VCC);
1972 break;
1973 }
1974 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
1975 switch (cmd->scan_begin_src) {
1976 case TRIG_TIMER:
1977 /*
1978 * Scan period timer CT1 needs to be
1979 * gated on to start counting.
1980 */
1981 zgat = pci230_gat_config(chan: 1, GAT_VCC);
1982 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
1983 break;
1984 case TRIG_INT:
1985 async->inttrig = pci230_ai_inttrig_scan_begin;
1986 break;
1987 }
1988 }
1989 } else if (cmd->convert_src != TRIG_INT) {
1990 /* No longer need Z2-CT2. */
1991 pci230_release_shared(dev, res_mask: RES_Z2CT2, owner: OWNER_AICMD);
1992 }
1993}
1994
1995static int pci230_ai_inttrig_start(struct comedi_device *dev,
1996 struct comedi_subdevice *s,
1997 unsigned int trig_num)
1998{
1999 struct comedi_cmd *cmd = &s->async->cmd;
2000
2001 if (trig_num != cmd->start_arg)
2002 return -EINVAL;
2003
2004 s->async->inttrig = NULL;
2005 pci230_ai_start(dev, s);
2006
2007 return 1;
2008}
2009
2010static void pci230_handle_ai(struct comedi_device *dev,
2011 struct comedi_subdevice *s)
2012{
2013 struct pci230_private *devpriv = dev->private;
2014 struct comedi_async *async = s->async;
2015 struct comedi_cmd *cmd = &async->cmd;
2016 unsigned int status_fifo;
2017 unsigned int i;
2018 unsigned int nsamples;
2019 unsigned int fifoamount;
2020 unsigned short val;
2021
2022 /* Determine number of samples to read. */
2023 nsamples = comedi_nsamples_left(s, PCI230_ADC_FIFOLEVEL_HALFFULL);
2024 if (nsamples == 0)
2025 return;
2026
2027 fifoamount = 0;
2028 for (i = 0; i < nsamples; i++) {
2029 if (fifoamount == 0) {
2030 /* Read FIFO state. */
2031 status_fifo = inw(port: devpriv->daqio + PCI230_ADCCON);
2032 if (status_fifo & PCI230_ADC_FIFO_FULL_LATCHED) {
2033 /*
2034 * Report error otherwise FIFO overruns will go
2035 * unnoticed by the caller.
2036 */
2037 dev_err(dev->class_dev, "AI FIFO overrun\n");
2038 async->events |= COMEDI_CB_ERROR;
2039 break;
2040 } else if (status_fifo & PCI230_ADC_FIFO_EMPTY) {
2041 /* FIFO empty. */
2042 break;
2043 } else if (status_fifo & PCI230_ADC_FIFO_HALF) {
2044 /* FIFO half full. */
2045 fifoamount = PCI230_ADC_FIFOLEVEL_HALFFULL;
2046 } else if (devpriv->hwver > 0) {
2047 /* Read PCI230+/260+ ADC FIFO level. */
2048 fifoamount = inw(port: devpriv->daqio +
2049 PCI230P_ADCFFLEV);
2050 if (fifoamount == 0)
2051 break; /* Shouldn't happen. */
2052 } else {
2053 /* FIFO not empty. */
2054 fifoamount = 1;
2055 }
2056 }
2057
2058 val = pci230_ai_read(dev);
2059 if (!comedi_buf_write_samples(s, data: &val, nsamples: 1))
2060 break;
2061
2062 fifoamount--;
2063
2064 if (cmd->stop_src == TRIG_COUNT &&
2065 async->scans_done >= cmd->stop_arg) {
2066 async->events |= COMEDI_CB_EOA;
2067 break;
2068 }
2069 }
2070
2071 /* update FIFO interrupt trigger level if still running */
2072 if (!(async->events & COMEDI_CB_CANCEL_MASK))
2073 pci230_ai_update_fifo_trigger_level(dev, s);
2074}
2075
2076static int pci230_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
2077{
2078 struct pci230_private *devpriv = dev->private;
2079 unsigned int i, chan, range, diff;
2080 unsigned int res_mask;
2081 unsigned short adccon, adcen;
2082 unsigned char zgat;
2083
2084 /* Get the command. */
2085 struct comedi_async *async = s->async;
2086 struct comedi_cmd *cmd = &async->cmd;
2087
2088 /*
2089 * Determine which shared resources are needed.
2090 */
2091 res_mask = 0;
2092 /*
2093 * Need Z2-CT2 to supply a conversion trigger source at a high
2094 * logic level, even if not doing timed conversions.
2095 */
2096 res_mask |= RES_Z2CT2;
2097 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2098 /* Using Z2-CT0 monostable to gate Z2-CT2 conversion timer */
2099 res_mask |= RES_Z2CT0;
2100 if (cmd->scan_begin_src == TRIG_TIMER) {
2101 /* Using Z2-CT1 for scan frequency */
2102 res_mask |= RES_Z2CT1;
2103 }
2104 }
2105 /* Claim resources. */
2106 if (!pci230_claim_shared(dev, res_mask, owner: OWNER_AICMD))
2107 return -EBUSY;
2108
2109 /*
2110 * Steps:
2111 * - Set channel scan list.
2112 * - Set channel gains.
2113 * - Enable and reset FIFO, specify uni/bip, se/diff, and set
2114 * start conversion source to point to something at a high logic
2115 * level (we use the output of counter/timer 2 for this purpose.
2116 * - PAUSE to allow things to settle down.
2117 * - Reset the FIFO again because it needs resetting twice and there
2118 * may have been a false conversion trigger on some versions of
2119 * PCI230/260 due to the start conversion source being set to a
2120 * high logic level.
2121 * - Enable ADC FIFO level interrupt.
2122 * - Set actual conversion trigger source and FIFO interrupt trigger
2123 * level.
2124 * - If convert_src is TRIG_TIMER, set up the timers.
2125 */
2126
2127 adccon = PCI230_ADC_FIFO_EN;
2128 adcen = 0;
2129
2130 if (CR_AREF(cmd->chanlist[0]) == AREF_DIFF) {
2131 /* Differential - all channels must be differential. */
2132 diff = 1;
2133 adccon |= PCI230_ADC_IM_DIF;
2134 } else {
2135 /* Single ended - all channels must be single-ended. */
2136 diff = 0;
2137 adccon |= PCI230_ADC_IM_SE;
2138 }
2139
2140 range = CR_RANGE(cmd->chanlist[0]);
2141 devpriv->ai_bipolar = comedi_range_is_bipolar(s, range);
2142 if (devpriv->ai_bipolar)
2143 adccon |= PCI230_ADC_IR_BIP;
2144 else
2145 adccon |= PCI230_ADC_IR_UNI;
2146
2147 for (i = 0; i < cmd->chanlist_len; i++) {
2148 unsigned int gainshift;
2149
2150 chan = CR_CHAN(cmd->chanlist[i]);
2151 range = CR_RANGE(cmd->chanlist[i]);
2152 if (diff) {
2153 gainshift = 2 * chan;
2154 if (devpriv->hwver == 0) {
2155 /*
2156 * Original PCI230/260 expects both inputs of
2157 * the differential channel to be enabled.
2158 */
2159 adcen |= 3 << gainshift;
2160 } else {
2161 /*
2162 * PCI230+/260+ expects only one input of the
2163 * differential channel to be enabled.
2164 */
2165 adcen |= 1 << gainshift;
2166 }
2167 } else {
2168 gainshift = chan & ~1;
2169 adcen |= 1 << chan;
2170 }
2171 devpriv->adcg = (devpriv->adcg & ~(3 << gainshift)) |
2172 (pci230_ai_gain[range] << gainshift);
2173 }
2174
2175 /* Set channel scan list. */
2176 outw(value: adcen, port: devpriv->daqio + PCI230_ADCEN);
2177
2178 /* Set channel gains. */
2179 outw(value: devpriv->adcg, port: devpriv->daqio + PCI230_ADCG);
2180
2181 /*
2182 * Set counter/timer 2 output high for use as the initial start
2183 * conversion source.
2184 */
2185 comedi_8254_set_mode(i8254: dev->pacer, counter: 2, mode: I8254_MODE1);
2186
2187 /*
2188 * Temporarily use CT2 output as conversion trigger source and
2189 * temporarily set FIFO interrupt trigger level to 'full'.
2190 */
2191 adccon |= PCI230_ADC_INT_FIFO_FULL | PCI230_ADC_TRIG_Z2CT2;
2192
2193 /*
2194 * Enable and reset FIFO, specify FIFO trigger level full, specify
2195 * uni/bip, se/diff, and temporarily set the start conversion source
2196 * to CT2 output. Note that CT2 output is currently high, and this
2197 * will produce a false conversion trigger on some versions of the
2198 * PCI230/260, but that will be dealt with later.
2199 */
2200 devpriv->adccon = adccon;
2201 outw(value: adccon | PCI230_ADC_FIFO_RESET, port: devpriv->daqio + PCI230_ADCCON);
2202
2203 /*
2204 * Delay -
2205 * Failure to include this will result in the first few channels'-worth
2206 * of data being corrupt, normally manifesting itself by large negative
2207 * voltages. It seems the board needs time to settle between the first
2208 * FIFO reset (above) and the second FIFO reset (below). Setting the
2209 * channel gains and scan list _before_ the first FIFO reset also
2210 * helps, though only slightly.
2211 */
2212 usleep_range(min: 25, max: 100);
2213
2214 /* Reset FIFO again. */
2215 outw(value: adccon | PCI230_ADC_FIFO_RESET, port: devpriv->daqio + PCI230_ADCCON);
2216
2217 if (cmd->convert_src == TRIG_TIMER) {
2218 /*
2219 * Set up CT2 as conversion timer, but gate it off for now.
2220 * Note, counter/timer output 2 can be monitored on the
2221 * connector: PCI230 pin 21, PCI260 pin 18.
2222 */
2223 zgat = pci230_gat_config(chan: 2, GAT_GND);
2224 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
2225 /* Set counter/timer 2 to the specified conversion period. */
2226 pci230_ct_setup_ns_mode(dev, ct: 2, mode: I8254_MODE3, ns: cmd->convert_arg,
2227 flags: cmd->flags);
2228 if (cmd->scan_begin_src != TRIG_FOLLOW) {
2229 /*
2230 * Set up monostable on CT0 output for scan timing. A
2231 * rising edge on the trigger (gate) input of CT0 will
2232 * trigger the monostable, causing its output to go low
2233 * for the configured period. The period depends on
2234 * the conversion period and the number of conversions
2235 * in the scan.
2236 *
2237 * Set the trigger high before setting up the
2238 * monostable to stop it triggering. The trigger
2239 * source will be changed later.
2240 */
2241 zgat = pci230_gat_config(chan: 0, GAT_VCC);
2242 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
2243 pci230_ct_setup_ns_mode(dev, ct: 0, mode: I8254_MODE1,
2244 ns: ((u64)cmd->convert_arg *
2245 cmd->scan_end_arg),
2246 CMDF_ROUND_UP);
2247 if (cmd->scan_begin_src == TRIG_TIMER) {
2248 /*
2249 * Monostable on CT0 will be triggered by
2250 * output of CT1 at configured scan frequency.
2251 *
2252 * Set up CT1 but gate it off for now.
2253 */
2254 zgat = pci230_gat_config(chan: 1, GAT_GND);
2255 outb(value: zgat, port: dev->iobase + PCI230_ZGAT_SCE);
2256 pci230_ct_setup_ns_mode(dev, ct: 1, mode: I8254_MODE3,
2257 ns: cmd->scan_begin_arg,
2258 flags: cmd->flags);
2259 }
2260 }
2261 }
2262
2263 if (cmd->start_src == TRIG_INT)
2264 s->async->inttrig = pci230_ai_inttrig_start;
2265 else /* TRIG_NOW */
2266 pci230_ai_start(dev, s);
2267
2268 return 0;
2269}
2270
2271static int pci230_ai_cancel(struct comedi_device *dev,
2272 struct comedi_subdevice *s)
2273{
2274 pci230_ai_stop(dev, s);
2275 return 0;
2276}
2277
2278/* Interrupt handler */
2279static irqreturn_t pci230_interrupt(int irq, void *d)
2280{
2281 unsigned char status_int, valid_status_int, temp_ier;
2282 struct comedi_device *dev = d;
2283 struct pci230_private *devpriv = dev->private;
2284 struct comedi_subdevice *s_ao = dev->write_subdev;
2285 struct comedi_subdevice *s_ai = dev->read_subdev;
2286 unsigned long irqflags;
2287
2288 /* Read interrupt status/enable register. */
2289 status_int = inb(port: dev->iobase + PCI230_INT_STAT);
2290
2291 if (status_int == PCI230_INT_DISABLE)
2292 return IRQ_NONE;
2293
2294 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2295 valid_status_int = devpriv->ier & status_int;
2296 /*
2297 * Disable triggered interrupts.
2298 * (Only those interrupts that need re-enabling, are, later in the
2299 * handler).
2300 */
2301 temp_ier = devpriv->ier & ~status_int;
2302 outb(value: temp_ier, port: dev->iobase + PCI230_INT_SCE);
2303 devpriv->intr_running = true;
2304 devpriv->intr_cpuid = THISCPU;
2305 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
2306
2307 /*
2308 * Check the source of interrupt and handle it.
2309 * The PCI230 can cope with concurrent ADC, DAC, PPI C0 and C3
2310 * interrupts. However, at present (Comedi-0.7.60) does not allow
2311 * concurrent execution of commands, instructions or a mixture of the
2312 * two.
2313 */
2314
2315 if (valid_status_int & PCI230_INT_ZCLK_CT1)
2316 pci230_handle_ao_nofifo(dev, s: s_ao);
2317
2318 if (valid_status_int & PCI230P2_INT_DAC)
2319 pci230_handle_ao_fifo(dev, s: s_ao);
2320
2321 if (valid_status_int & PCI230_INT_ADC)
2322 pci230_handle_ai(dev, s: s_ai);
2323
2324 /* Reenable interrupts. */
2325 spin_lock_irqsave(&devpriv->isr_spinlock, irqflags);
2326 if (devpriv->ier != temp_ier)
2327 outb(value: devpriv->ier, port: dev->iobase + PCI230_INT_SCE);
2328 devpriv->intr_running = false;
2329 spin_unlock_irqrestore(lock: &devpriv->isr_spinlock, flags: irqflags);
2330
2331 if (s_ao)
2332 comedi_handle_events(dev, s: s_ao);
2333 comedi_handle_events(dev, s: s_ai);
2334
2335 return IRQ_HANDLED;
2336}
2337
2338/* Check if PCI device matches a specific board. */
2339static bool pci230_match_pci_board(const struct pci230_board *board,
2340 struct pci_dev *pci_dev)
2341{
2342 /* assume pci_dev->device != PCI_DEVICE_ID_INVALID */
2343 if (board->id != pci_dev->device)
2344 return false;
2345 if (board->min_hwver == 0)
2346 return true;
2347 /* Looking for a '+' model. First check length of registers. */
2348 if (pci_resource_len(pci_dev, 3) < 32)
2349 return false; /* Not a '+' model. */
2350 /*
2351 * TODO: temporarily enable PCI device and read the hardware version
2352 * register. For now, assume it's okay.
2353 */
2354 return true;
2355}
2356
2357/* Look for board matching PCI device. */
2358static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev)
2359{
2360 unsigned int i;
2361
2362 for (i = 0; i < ARRAY_SIZE(pci230_boards); i++)
2363 if (pci230_match_pci_board(board: &pci230_boards[i], pci_dev))
2364 return &pci230_boards[i];
2365 return NULL;
2366}
2367
2368static int pci230_auto_attach(struct comedi_device *dev,
2369 unsigned long context_unused)
2370{
2371 struct pci_dev *pci_dev = comedi_to_pci_dev(dev);
2372 const struct pci230_board *board;
2373 struct pci230_private *devpriv;
2374 struct comedi_subdevice *s;
2375 int rc;
2376
2377 dev_info(dev->class_dev, "amplc_pci230: attach pci %s\n",
2378 pci_name(pci_dev));
2379
2380 devpriv = comedi_alloc_devpriv(dev, size: sizeof(*devpriv));
2381 if (!devpriv)
2382 return -ENOMEM;
2383
2384 spin_lock_init(&devpriv->isr_spinlock);
2385 spin_lock_init(&devpriv->res_spinlock);
2386 spin_lock_init(&devpriv->ai_stop_spinlock);
2387 spin_lock_init(&devpriv->ao_stop_spinlock);
2388
2389 board = pci230_find_pci_board(pci_dev);
2390 if (!board) {
2391 dev_err(dev->class_dev,
2392 "amplc_pci230: BUG! cannot determine board type!\n");
2393 return -EINVAL;
2394 }
2395 dev->board_ptr = board;
2396 dev->board_name = board->name;
2397
2398 rc = comedi_pci_enable(dev);
2399 if (rc)
2400 return rc;
2401
2402 /*
2403 * Read base addresses of the PCI230's two I/O regions from PCI
2404 * configuration register.
2405 */
2406 dev->iobase = pci_resource_start(pci_dev, 2);
2407 devpriv->daqio = pci_resource_start(pci_dev, 3);
2408 dev_dbg(dev->class_dev,
2409 "%s I/O region 1 0x%04lx I/O region 2 0x%04lx\n",
2410 dev->board_name, dev->iobase, devpriv->daqio);
2411 /* Read bits of DACCON register - only the output range. */
2412 devpriv->daccon = inw(port: devpriv->daqio + PCI230_DACCON) &
2413 PCI230_DAC_OR_MASK;
2414 /*
2415 * Read hardware version register and set extended function register
2416 * if they exist.
2417 */
2418 if (pci_resource_len(pci_dev, 3) >= 32) {
2419 unsigned short extfunc = 0;
2420
2421 devpriv->hwver = inw(port: devpriv->daqio + PCI230P_HWVER);
2422 if (devpriv->hwver < board->min_hwver) {
2423 dev_err(dev->class_dev,
2424 "%s - bad hardware version - got %u, need %u\n",
2425 dev->board_name, devpriv->hwver,
2426 board->min_hwver);
2427 return -EIO;
2428 }
2429 if (devpriv->hwver > 0) {
2430 if (!board->have_dio) {
2431 /*
2432 * No DIO ports. Route counters' external gates
2433 * to the EXTTRIG signal (PCI260+ pin 17).
2434 * (Otherwise, they would be routed to DIO
2435 * inputs PC0, PC1 and PC2 which don't exist
2436 * on PCI260[+].)
2437 */
2438 extfunc |= PCI230P_EXTFUNC_GAT_EXTTRIG;
2439 }
2440 if (board->ao_bits && devpriv->hwver >= 2) {
2441 /* Enable DAC FIFO functionality. */
2442 extfunc |= PCI230P2_EXTFUNC_DACFIFO;
2443 }
2444 }
2445 outw(value: extfunc, port: devpriv->daqio + PCI230P_EXTFUNC);
2446 if (extfunc & PCI230P2_EXTFUNC_DACFIFO) {
2447 /*
2448 * Temporarily enable DAC FIFO, reset it and disable
2449 * FIFO wraparound.
2450 */
2451 outw(value: devpriv->daccon | PCI230P2_DAC_FIFO_EN |
2452 PCI230P2_DAC_FIFO_RESET,
2453 port: devpriv->daqio + PCI230_DACCON);
2454 /* Clear DAC FIFO channel enable register. */
2455 outw(value: 0, port: devpriv->daqio + PCI230P2_DACEN);
2456 /* Disable DAC FIFO. */
2457 outw(value: devpriv->daccon, port: devpriv->daqio + PCI230_DACCON);
2458 }
2459 }
2460 /* Disable board's interrupts. */
2461 outb(value: 0, port: dev->iobase + PCI230_INT_SCE);
2462 /* Set ADC to a reasonable state. */
2463 devpriv->adcg = 0;
2464 devpriv->adccon = PCI230_ADC_TRIG_NONE | PCI230_ADC_IM_SE |
2465 PCI230_ADC_IR_BIP;
2466 outw(BIT(0), port: devpriv->daqio + PCI230_ADCEN);
2467 outw(value: devpriv->adcg, port: devpriv->daqio + PCI230_ADCG);
2468 outw(value: devpriv->adccon | PCI230_ADC_FIFO_RESET,
2469 port: devpriv->daqio + PCI230_ADCCON);
2470
2471 if (pci_dev->irq) {
2472 rc = request_irq(irq: pci_dev->irq, handler: pci230_interrupt, IRQF_SHARED,
2473 name: dev->board_name, dev);
2474 if (rc == 0)
2475 dev->irq = pci_dev->irq;
2476 }
2477
2478 dev->pacer = comedi_8254_io_alloc(iobase: dev->iobase + PCI230_Z2_CT_BASE,
2479 osc_base: 0, I8254_IO8, regshift: 0);
2480 if (IS_ERR(ptr: dev->pacer))
2481 return PTR_ERR(ptr: dev->pacer);
2482
2483 rc = comedi_alloc_subdevices(dev, num_subdevices: 3);
2484 if (rc)
2485 return rc;
2486
2487 s = &dev->subdevices[0];
2488 /* analog input subdevice */
2489 s->type = COMEDI_SUBD_AI;
2490 s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND;
2491 s->n_chan = 16;
2492 s->maxdata = (1 << board->ai_bits) - 1;
2493 s->range_table = &pci230_ai_range;
2494 s->insn_read = pci230_ai_insn_read;
2495 s->len_chanlist = 256; /* but there are restrictions. */
2496 if (dev->irq) {
2497 dev->read_subdev = s;
2498 s->subdev_flags |= SDF_CMD_READ;
2499 s->do_cmd = pci230_ai_cmd;
2500 s->do_cmdtest = pci230_ai_cmdtest;
2501 s->cancel = pci230_ai_cancel;
2502 }
2503
2504 s = &dev->subdevices[1];
2505 /* analog output subdevice */
2506 if (board->ao_bits) {
2507 s->type = COMEDI_SUBD_AO;
2508 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
2509 s->n_chan = 2;
2510 s->maxdata = (1 << board->ao_bits) - 1;
2511 s->range_table = &pci230_ao_range;
2512 s->insn_write = pci230_ao_insn_write;
2513 s->len_chanlist = 2;
2514 if (dev->irq) {
2515 dev->write_subdev = s;
2516 s->subdev_flags |= SDF_CMD_WRITE;
2517 s->do_cmd = pci230_ao_cmd;
2518 s->do_cmdtest = pci230_ao_cmdtest;
2519 s->cancel = pci230_ao_cancel;
2520 }
2521
2522 rc = comedi_alloc_subdev_readback(s);
2523 if (rc)
2524 return rc;
2525 } else {
2526 s->type = COMEDI_SUBD_UNUSED;
2527 }
2528
2529 s = &dev->subdevices[2];
2530 /* digital i/o subdevice */
2531 if (board->have_dio) {
2532 rc = subdev_8255_io_init(dev, s, PCI230_PPI_X_BASE);
2533 if (rc)
2534 return rc;
2535 } else {
2536 s->type = COMEDI_SUBD_UNUSED;
2537 }
2538
2539 return 0;
2540}
2541
2542static struct comedi_driver amplc_pci230_driver = {
2543 .driver_name = "amplc_pci230",
2544 .module = THIS_MODULE,
2545 .auto_attach = pci230_auto_attach,
2546 .detach = comedi_pci_detach,
2547};
2548
2549static int amplc_pci230_pci_probe(struct pci_dev *dev,
2550 const struct pci_device_id *id)
2551{
2552 return comedi_pci_auto_config(pcidev: dev, driver: &amplc_pci230_driver,
2553 context: id->driver_data);
2554}
2555
2556static const struct pci_device_id amplc_pci230_pci_table[] = {
2557 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI230) },
2558 { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_PCI260) },
2559 { 0 }
2560};
2561MODULE_DEVICE_TABLE(pci, amplc_pci230_pci_table);
2562
2563static struct pci_driver amplc_pci230_pci_driver = {
2564 .name = "amplc_pci230",
2565 .id_table = amplc_pci230_pci_table,
2566 .probe = amplc_pci230_pci_probe,
2567 .remove = comedi_pci_auto_unconfig,
2568};
2569module_comedi_pci_driver(amplc_pci230_driver, amplc_pci230_pci_driver);
2570
2571MODULE_AUTHOR("Comedi https://www.comedi.org");
2572MODULE_DESCRIPTION("Comedi driver for Amplicon PCI230(+) and PCI260(+)");
2573MODULE_LICENSE("GPL");
2574

source code of linux/drivers/comedi/drivers/amplc_pci230.c