1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * addi_apci_3120.c
4 * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
5 *
6 * ADDI-DATA GmbH
7 * Dieselstrasse 3
8 * D-77833 Ottersweier
9 * Tel: +19(0)7223/9493-0
10 * Fax: +49(0)7223/9493-92
11 * http://www.addi-data.com
12 * info@addi-data.com
13 */
14
15#include <linux/module.h>
16#include <linux/interrupt.h>
17#include <linux/comedi/comedi_pci.h>
18
19#include "amcc_s5933.h"
20
21/*
22 * PCI BAR 0 register map (devpriv->amcc)
23 * see amcc_s5933.h for register and bit defines
24 */
25#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 BIT(29)
26
27/*
28 * PCI BAR 1 register map (dev->iobase)
29 */
30#define APCI3120_AI_FIFO_REG 0x00
31#define APCI3120_CTRL_REG 0x00
32#define APCI3120_CTRL_EXT_TRIG BIT(15)
33#define APCI3120_CTRL_GATE(x) BIT(12 + (x))
34#define APCI3120_CTRL_PR(x) (((x) & 0xf) << 8)
35#define APCI3120_CTRL_PA(x) (((x) & 0xf) << 0)
36#define APCI3120_AI_SOFTTRIG_REG 0x02
37#define APCI3120_STATUS_REG 0x02
38#define APCI3120_STATUS_EOC_INT BIT(15)
39#define APCI3120_STATUS_AMCC_INT BIT(14)
40#define APCI3120_STATUS_EOS_INT BIT(13)
41#define APCI3120_STATUS_TIMER2_INT BIT(12)
42#define APCI3120_STATUS_INT_MASK (0xf << 12)
43#define APCI3120_STATUS_TO_DI_BITS(x) (((x) >> 8) & 0xf)
44#define APCI3120_STATUS_TO_VERSION(x) (((x) >> 4) & 0xf)
45#define APCI3120_STATUS_FIFO_FULL BIT(2)
46#define APCI3120_STATUS_FIFO_EMPTY BIT(1)
47#define APCI3120_STATUS_DA_READY BIT(0)
48#define APCI3120_TIMER_REG 0x04
49#define APCI3120_CHANLIST_REG 0x06
50#define APCI3120_CHANLIST_INDEX(x) (((x) & 0xf) << 8)
51#define APCI3120_CHANLIST_UNIPOLAR BIT(7)
52#define APCI3120_CHANLIST_GAIN(x) (((x) & 0x3) << 4)
53#define APCI3120_CHANLIST_MUX(x) (((x) & 0xf) << 0)
54#define APCI3120_AO_REG(x) (0x08 + (((x) / 4) * 2))
55#define APCI3120_AO_MUX(x) (((x) & 0x3) << 14)
56#define APCI3120_AO_DATA(x) ((x) << 0)
57#define APCI3120_TIMER_MODE_REG 0x0c
58#define APCI3120_TIMER_MODE(_t, _m) ((_m) << ((_t) * 2))
59#define APCI3120_TIMER_MODE0 0 /* I8254_MODE0 */
60#define APCI3120_TIMER_MODE2 1 /* I8254_MODE2 */
61#define APCI3120_TIMER_MODE4 2 /* I8254_MODE4 */
62#define APCI3120_TIMER_MODE5 3 /* I8254_MODE5 */
63#define APCI3120_TIMER_MODE_MASK(_t) (3 << ((_t) * 2))
64#define APCI3120_CTR0_REG 0x0d
65#define APCI3120_CTR0_DO_BITS(x) ((x) << 4)
66#define APCI3120_CTR0_TIMER_SEL(x) ((x) << 0)
67#define APCI3120_MODE_REG 0x0e
68#define APCI3120_MODE_TIMER2_CLK(x) (((x) & 0x3) << 6)
69#define APCI3120_MODE_TIMER2_CLK_OSC APCI3120_MODE_TIMER2_CLK(0)
70#define APCI3120_MODE_TIMER2_CLK_OUT1 APCI3120_MODE_TIMER2_CLK(1)
71#define APCI3120_MODE_TIMER2_CLK_EOC APCI3120_MODE_TIMER2_CLK(2)
72#define APCI3120_MODE_TIMER2_CLK_EOS APCI3120_MODE_TIMER2_CLK(3)
73#define APCI3120_MODE_TIMER2_CLK_MASK APCI3120_MODE_TIMER2_CLK(3)
74#define APCI3120_MODE_TIMER2_AS(x) (((x) & 0x3) << 4)
75#define APCI3120_MODE_TIMER2_AS_TIMER APCI3120_MODE_TIMER2_AS(0)
76#define APCI3120_MODE_TIMER2_AS_COUNTER APCI3120_MODE_TIMER2_AS(1)
77#define APCI3120_MODE_TIMER2_AS_WDOG APCI3120_MODE_TIMER2_AS(2)
78#define APCI3120_MODE_TIMER2_AS_MASK APCI3120_MODE_TIMER2_AS(3)
79#define APCI3120_MODE_SCAN_ENA BIT(3)
80#define APCI3120_MODE_TIMER2_IRQ_ENA BIT(2)
81#define APCI3120_MODE_EOS_IRQ_ENA BIT(1)
82#define APCI3120_MODE_EOC_IRQ_ENA BIT(0)
83
84/*
85 * PCI BAR 2 register map (devpriv->addon)
86 */
87#define APCI3120_ADDON_ADDR_REG 0x00
88#define APCI3120_ADDON_DATA_REG 0x02
89#define APCI3120_ADDON_CTRL_REG 0x04
90#define APCI3120_ADDON_CTRL_AMWEN_ENA BIT(1)
91#define APCI3120_ADDON_CTRL_A2P_FIFO_ENA BIT(0)
92
93/*
94 * Board revisions
95 */
96#define APCI3120_REVA 0xa
97#define APCI3120_REVB 0xb
98#define APCI3120_REVA_OSC_BASE 70 /* 70ns = 14.29MHz */
99#define APCI3120_REVB_OSC_BASE 50 /* 50ns = 20MHz */
100
101static const struct comedi_lrange apci3120_ai_range = {
102 8, {
103 BIP_RANGE(10),
104 BIP_RANGE(5),
105 BIP_RANGE(2),
106 BIP_RANGE(1),
107 UNI_RANGE(10),
108 UNI_RANGE(5),
109 UNI_RANGE(2),
110 UNI_RANGE(1)
111 }
112};
113
114enum apci3120_boardid {
115 BOARD_APCI3120,
116 BOARD_APCI3001,
117};
118
119struct apci3120_board {
120 const char *name;
121 unsigned int ai_is_16bit:1;
122 unsigned int has_ao:1;
123};
124
125static const struct apci3120_board apci3120_boardtypes[] = {
126 [BOARD_APCI3120] = {
127 .name = "apci3120",
128 .ai_is_16bit = 1,
129 .has_ao = 1,
130 },
131 [BOARD_APCI3001] = {
132 .name = "apci3001",
133 },
134};
135
136struct apci3120_dmabuf {
137 unsigned short *virt;
138 dma_addr_t hw;
139 unsigned int size;
140 unsigned int use_size;
141};
142
143struct apci3120_private {
144 unsigned long amcc;
145 unsigned long addon;
146 unsigned int osc_base;
147 unsigned int use_dma:1;
148 unsigned int use_double_buffer:1;
149 unsigned int cur_dmabuf:1;
150 struct apci3120_dmabuf dmabuf[2];
151 unsigned char do_bits;
152 unsigned char timer_mode;
153 unsigned char mode;
154 unsigned short ctrl;
155};
156
157static void apci3120_addon_write(struct comedi_device *dev,
158 unsigned int val, unsigned int reg)
159{
160 struct apci3120_private *devpriv = dev->private;
161
162 /* 16-bit interface for AMCC add-on registers */
163
164 outw(value: reg, port: devpriv->addon + APCI3120_ADDON_ADDR_REG);
165 outw(value: val & 0xffff, port: devpriv->addon + APCI3120_ADDON_DATA_REG);
166
167 outw(value: reg + 2, port: devpriv->addon + APCI3120_ADDON_ADDR_REG);
168 outw(value: (val >> 16) & 0xffff, port: devpriv->addon + APCI3120_ADDON_DATA_REG);
169}
170
171static void apci3120_init_dma(struct comedi_device *dev,
172 struct apci3120_dmabuf *dmabuf)
173{
174 struct apci3120_private *devpriv = dev->private;
175
176 /* AMCC - enable transfer count and reset A2P FIFO */
177 outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
178 port: devpriv->amcc + AMCC_OP_REG_AGCSTS);
179
180 /* Add-On - enable transfer count and reset A2P FIFO */
181 apci3120_addon_write(dev, AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
182 AMCC_OP_REG_AGCSTS);
183
184 /* AMCC - enable transfers and reset A2P flags */
185 outl(RESET_A2P_FLAGS | EN_A2P_TRANSFERS,
186 port: devpriv->amcc + AMCC_OP_REG_MCSR);
187
188 /* Add-On - DMA start address */
189 apci3120_addon_write(dev, val: dmabuf->hw, AMCC_OP_REG_AMWAR);
190
191 /* Add-On - Number of acquisitions */
192 apci3120_addon_write(dev, val: dmabuf->use_size, AMCC_OP_REG_AMWTC);
193
194 /* AMCC - enable write complete (DMA) and set FIFO advance */
195 outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 | AINT_WRITE_COMPL,
196 port: devpriv->amcc + AMCC_OP_REG_INTCSR);
197
198 /* Add-On - enable DMA */
199 outw(APCI3120_ADDON_CTRL_AMWEN_ENA | APCI3120_ADDON_CTRL_A2P_FIFO_ENA,
200 port: devpriv->addon + APCI3120_ADDON_CTRL_REG);
201}
202
203static void apci3120_setup_dma(struct comedi_device *dev,
204 struct comedi_subdevice *s)
205{
206 struct apci3120_private *devpriv = dev->private;
207 struct comedi_cmd *cmd = &s->async->cmd;
208 struct apci3120_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
209 struct apci3120_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
210 unsigned int dmalen0 = dmabuf0->size;
211 unsigned int dmalen1 = dmabuf1->size;
212 unsigned int scan_bytes;
213
214 scan_bytes = comedi_samples_to_bytes(s, nsamples: cmd->scan_end_arg);
215
216 if (cmd->stop_src == TRIG_COUNT) {
217 /*
218 * Must we fill full first buffer? And must we fill
219 * full second buffer when first is once filled?
220 */
221 if (dmalen0 > (cmd->stop_arg * scan_bytes))
222 dmalen0 = cmd->stop_arg * scan_bytes;
223 else if (dmalen1 > (cmd->stop_arg * scan_bytes - dmalen0))
224 dmalen1 = cmd->stop_arg * scan_bytes - dmalen0;
225 }
226
227 if (cmd->flags & CMDF_WAKE_EOS) {
228 /* don't we want wake up every scan? */
229 if (dmalen0 > scan_bytes) {
230 dmalen0 = scan_bytes;
231 if (cmd->scan_end_arg & 1)
232 dmalen0 += 2;
233 }
234 if (dmalen1 > scan_bytes) {
235 dmalen1 = scan_bytes;
236 if (cmd->scan_end_arg & 1)
237 dmalen1 -= 2;
238 if (dmalen1 < 4)
239 dmalen1 = 4;
240 }
241 } else {
242 /* isn't output buff smaller that our DMA buff? */
243 if (dmalen0 > s->async->prealloc_bufsz)
244 dmalen0 = s->async->prealloc_bufsz;
245 if (dmalen1 > s->async->prealloc_bufsz)
246 dmalen1 = s->async->prealloc_bufsz;
247 }
248 dmabuf0->use_size = dmalen0;
249 dmabuf1->use_size = dmalen1;
250
251 apci3120_init_dma(dev, dmabuf: dmabuf0);
252}
253
254/*
255 * There are three timers on the board. They all use the same base
256 * clock with a fixed prescaler for each timer. The base clock used
257 * depends on the board version and type.
258 *
259 * APCI-3120 Rev A boards OSC = 14.29MHz base clock (~70ns)
260 * APCI-3120 Rev B boards OSC = 20MHz base clock (50ns)
261 * APCI-3001 boards OSC = 20MHz base clock (50ns)
262 *
263 * The prescalers for each timer are:
264 * Timer 0 CLK = OSC/10
265 * Timer 1 CLK = OSC/1000
266 * Timer 2 CLK = OSC/1000
267 */
268static unsigned int apci3120_ns_to_timer(struct comedi_device *dev,
269 unsigned int timer,
270 unsigned int ns,
271 unsigned int flags)
272{
273 struct apci3120_private *devpriv = dev->private;
274 unsigned int prescale = (timer == 0) ? 10 : 1000;
275 unsigned int timer_base = devpriv->osc_base * prescale;
276 unsigned int divisor;
277
278 switch (flags & CMDF_ROUND_MASK) {
279 case CMDF_ROUND_UP:
280 divisor = DIV_ROUND_UP(ns, timer_base);
281 break;
282 case CMDF_ROUND_DOWN:
283 divisor = ns / timer_base;
284 break;
285 case CMDF_ROUND_NEAREST:
286 default:
287 divisor = DIV_ROUND_CLOSEST(ns, timer_base);
288 break;
289 }
290
291 if (timer == 2) {
292 /* timer 2 is 24-bits */
293 if (divisor > 0x00ffffff)
294 divisor = 0x00ffffff;
295 } else {
296 /* timers 0 and 1 are 16-bits */
297 if (divisor > 0xffff)
298 divisor = 0xffff;
299 }
300 /* the timers require a minimum divisor of 2 */
301 if (divisor < 2)
302 divisor = 2;
303
304 return divisor;
305}
306
307static void apci3120_clr_timer2_interrupt(struct comedi_device *dev)
308{
309 /* a dummy read of APCI3120_CTR0_REG clears the timer 2 interrupt */
310 inb(port: dev->iobase + APCI3120_CTR0_REG);
311}
312
313static void apci3120_timer_write(struct comedi_device *dev,
314 unsigned int timer, unsigned int val)
315{
316 struct apci3120_private *devpriv = dev->private;
317
318 /* write 16-bit value to timer (lower 16-bits of timer 2) */
319 outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) |
320 APCI3120_CTR0_TIMER_SEL(timer),
321 port: dev->iobase + APCI3120_CTR0_REG);
322 outw(value: val & 0xffff, port: dev->iobase + APCI3120_TIMER_REG);
323
324 if (timer == 2) {
325 /* write upper 16-bits to timer 2 */
326 outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) |
327 APCI3120_CTR0_TIMER_SEL(timer + 1),
328 port: dev->iobase + APCI3120_CTR0_REG);
329 outw(value: (val >> 16) & 0xffff, port: dev->iobase + APCI3120_TIMER_REG);
330 }
331}
332
333static unsigned int apci3120_timer_read(struct comedi_device *dev,
334 unsigned int timer)
335{
336 struct apci3120_private *devpriv = dev->private;
337 unsigned int val;
338
339 /* read 16-bit value from timer (lower 16-bits of timer 2) */
340 outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) |
341 APCI3120_CTR0_TIMER_SEL(timer),
342 port: dev->iobase + APCI3120_CTR0_REG);
343 val = inw(port: dev->iobase + APCI3120_TIMER_REG);
344
345 if (timer == 2) {
346 /* read upper 16-bits from timer 2 */
347 outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits) |
348 APCI3120_CTR0_TIMER_SEL(timer + 1),
349 port: dev->iobase + APCI3120_CTR0_REG);
350 val |= (inw(port: dev->iobase + APCI3120_TIMER_REG) << 16);
351 }
352
353 return val;
354}
355
356static void apci3120_timer_set_mode(struct comedi_device *dev,
357 unsigned int timer, unsigned int mode)
358{
359 struct apci3120_private *devpriv = dev->private;
360
361 devpriv->timer_mode &= ~APCI3120_TIMER_MODE_MASK(timer);
362 devpriv->timer_mode |= APCI3120_TIMER_MODE(timer, mode);
363 outb(value: devpriv->timer_mode, port: dev->iobase + APCI3120_TIMER_MODE_REG);
364}
365
366static void apci3120_timer_enable(struct comedi_device *dev,
367 unsigned int timer, bool enable)
368{
369 struct apci3120_private *devpriv = dev->private;
370
371 if (enable)
372 devpriv->ctrl |= APCI3120_CTRL_GATE(timer);
373 else
374 devpriv->ctrl &= ~APCI3120_CTRL_GATE(timer);
375 outw(value: devpriv->ctrl, port: dev->iobase + APCI3120_CTRL_REG);
376}
377
378static void apci3120_exttrig_enable(struct comedi_device *dev, bool enable)
379{
380 struct apci3120_private *devpriv = dev->private;
381
382 if (enable)
383 devpriv->ctrl |= APCI3120_CTRL_EXT_TRIG;
384 else
385 devpriv->ctrl &= ~APCI3120_CTRL_EXT_TRIG;
386 outw(value: devpriv->ctrl, port: dev->iobase + APCI3120_CTRL_REG);
387}
388
389static void apci3120_set_chanlist(struct comedi_device *dev,
390 struct comedi_subdevice *s,
391 int n_chan, unsigned int *chanlist)
392{
393 struct apci3120_private *devpriv = dev->private;
394 int i;
395
396 /* set chanlist for scan */
397 for (i = 0; i < n_chan; i++) {
398 unsigned int chan = CR_CHAN(chanlist[i]);
399 unsigned int range = CR_RANGE(chanlist[i]);
400 unsigned int val;
401
402 val = APCI3120_CHANLIST_MUX(chan) |
403 APCI3120_CHANLIST_GAIN(range) |
404 APCI3120_CHANLIST_INDEX(i);
405
406 if (comedi_range_is_unipolar(s, range))
407 val |= APCI3120_CHANLIST_UNIPOLAR;
408
409 outw(value: val, port: dev->iobase + APCI3120_CHANLIST_REG);
410 }
411
412 /* a dummy read of APCI3120_TIMER_MODE_REG resets the ai FIFO */
413 inw(port: dev->iobase + APCI3120_TIMER_MODE_REG);
414
415 /* set scan length (PR) and scan start (PA) */
416 devpriv->ctrl = APCI3120_CTRL_PR(n_chan - 1) | APCI3120_CTRL_PA(0);
417 outw(value: devpriv->ctrl, port: dev->iobase + APCI3120_CTRL_REG);
418
419 /* enable chanlist scanning if necessary */
420 if (n_chan > 1)
421 devpriv->mode |= APCI3120_MODE_SCAN_ENA;
422}
423
424static void apci3120_interrupt_dma(struct comedi_device *dev,
425 struct comedi_subdevice *s)
426{
427 struct apci3120_private *devpriv = dev->private;
428 struct comedi_async *async = s->async;
429 struct comedi_cmd *cmd = &async->cmd;
430 struct apci3120_dmabuf *dmabuf;
431 unsigned int nbytes;
432 unsigned int nsamples;
433
434 dmabuf = &devpriv->dmabuf[devpriv->cur_dmabuf];
435
436 nbytes = dmabuf->use_size - inl(port: devpriv->amcc + AMCC_OP_REG_MWTC);
437
438 if (nbytes < dmabuf->use_size)
439 dev_err(dev->class_dev, "Interrupted DMA transfer!\n");
440 if (nbytes & 1) {
441 dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n");
442 async->events |= COMEDI_CB_ERROR;
443 return;
444 }
445
446 nsamples = comedi_bytes_to_samples(s, nbytes);
447 if (nsamples) {
448 comedi_buf_write_samples(s, data: dmabuf->virt, nsamples);
449
450 if (!(cmd->flags & CMDF_WAKE_EOS))
451 async->events |= COMEDI_CB_EOS;
452 }
453
454 if ((async->events & COMEDI_CB_CANCEL_MASK) ||
455 (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg))
456 return;
457
458 if (devpriv->use_double_buffer) {
459 /* switch DMA buffers for next interrupt */
460 devpriv->cur_dmabuf = !devpriv->cur_dmabuf;
461 dmabuf = &devpriv->dmabuf[devpriv->cur_dmabuf];
462 apci3120_init_dma(dev, dmabuf);
463 } else {
464 /* restart DMA if not using double buffering */
465 apci3120_init_dma(dev, dmabuf);
466 }
467}
468
469static irqreturn_t apci3120_interrupt(int irq, void *d)
470{
471 struct comedi_device *dev = d;
472 struct apci3120_private *devpriv = dev->private;
473 struct comedi_subdevice *s = dev->read_subdev;
474 struct comedi_async *async = s->async;
475 struct comedi_cmd *cmd = &async->cmd;
476 unsigned int status;
477 unsigned int int_amcc;
478
479 status = inw(port: dev->iobase + APCI3120_STATUS_REG);
480 int_amcc = inl(port: devpriv->amcc + AMCC_OP_REG_INTCSR);
481
482 if (!(status & APCI3120_STATUS_INT_MASK) &&
483 !(int_amcc & ANY_S593X_INT)) {
484 dev_err(dev->class_dev, "IRQ from unknown source\n");
485 return IRQ_NONE;
486 }
487
488 outl(value: int_amcc | AINT_INT_MASK, port: devpriv->amcc + AMCC_OP_REG_INTCSR);
489
490 if (devpriv->ctrl & APCI3120_CTRL_EXT_TRIG)
491 apci3120_exttrig_enable(dev, enable: false);
492
493 if (int_amcc & MASTER_ABORT_INT)
494 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
495 if (int_amcc & TARGET_ABORT_INT)
496 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
497
498 if ((status & APCI3120_STATUS_EOS_INT) &&
499 (devpriv->mode & APCI3120_MODE_EOS_IRQ_ENA)) {
500 unsigned short val;
501 int i;
502
503 for (i = 0; i < cmd->chanlist_len; i++) {
504 val = inw(port: dev->iobase + APCI3120_AI_FIFO_REG);
505 comedi_buf_write_samples(s, data: &val, nsamples: 1);
506 }
507
508 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
509 outb(value: devpriv->mode, port: dev->iobase + APCI3120_MODE_REG);
510 }
511
512 if (status & APCI3120_STATUS_TIMER2_INT) {
513 /*
514 * for safety...
515 * timer2 interrupts are not enabled in the driver
516 */
517 apci3120_clr_timer2_interrupt(dev);
518 }
519
520 if (status & APCI3120_STATUS_AMCC_INT) {
521 /* AMCC- Clear write complete interrupt (DMA) */
522 outl(AINT_WT_COMPLETE, port: devpriv->amcc + AMCC_OP_REG_INTCSR);
523
524 /* do some data transfer */
525 apci3120_interrupt_dma(dev, s);
526 }
527
528 if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
529 async->events |= COMEDI_CB_EOA;
530
531 comedi_handle_events(dev, s);
532
533 return IRQ_HANDLED;
534}
535
536static int apci3120_ai_cmd(struct comedi_device *dev,
537 struct comedi_subdevice *s)
538{
539 struct apci3120_private *devpriv = dev->private;
540 struct comedi_cmd *cmd = &s->async->cmd;
541 unsigned int divisor;
542
543 /* set default mode bits */
544 devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC |
545 APCI3120_MODE_TIMER2_AS_TIMER;
546
547 /* AMCC- Clear write complete interrupt (DMA) */
548 outl(AINT_WT_COMPLETE, port: devpriv->amcc + AMCC_OP_REG_INTCSR);
549
550 devpriv->cur_dmabuf = 0;
551
552 /* load chanlist for command scan */
553 apci3120_set_chanlist(dev, s, n_chan: cmd->chanlist_len, chanlist: cmd->chanlist);
554
555 if (cmd->start_src == TRIG_EXT)
556 apci3120_exttrig_enable(dev, enable: true);
557
558 if (cmd->scan_begin_src == TRIG_TIMER) {
559 /*
560 * Timer 1 is used in MODE2 (rate generator) to set the
561 * start time for each scan.
562 */
563 divisor = apci3120_ns_to_timer(dev, timer: 1, ns: cmd->scan_begin_arg,
564 flags: cmd->flags);
565 apci3120_timer_set_mode(dev, timer: 1, APCI3120_TIMER_MODE2);
566 apci3120_timer_write(dev, timer: 1, val: divisor);
567 }
568
569 /*
570 * Timer 0 is used in MODE2 (rate generator) to set the conversion
571 * time for each acquisition.
572 */
573 divisor = apci3120_ns_to_timer(dev, timer: 0, ns: cmd->convert_arg, flags: cmd->flags);
574 apci3120_timer_set_mode(dev, timer: 0, APCI3120_TIMER_MODE2);
575 apci3120_timer_write(dev, timer: 0, val: divisor);
576
577 if (devpriv->use_dma)
578 apci3120_setup_dma(dev, s);
579 else
580 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
581
582 /* set mode to enable acquisition */
583 outb(value: devpriv->mode, port: dev->iobase + APCI3120_MODE_REG);
584
585 if (cmd->scan_begin_src == TRIG_TIMER)
586 apci3120_timer_enable(dev, timer: 1, enable: true);
587 apci3120_timer_enable(dev, timer: 0, enable: true);
588
589 return 0;
590}
591
592static int apci3120_ai_cmdtest(struct comedi_device *dev,
593 struct comedi_subdevice *s,
594 struct comedi_cmd *cmd)
595{
596 unsigned int arg;
597 int err = 0;
598
599 /* Step 1 : check if triggers are trivially valid */
600
601 err |= comedi_check_trigger_src(src: &cmd->start_src, TRIG_NOW | TRIG_EXT);
602 err |= comedi_check_trigger_src(src: &cmd->scan_begin_src,
603 TRIG_TIMER | TRIG_FOLLOW);
604 err |= comedi_check_trigger_src(src: &cmd->convert_src, TRIG_TIMER);
605 err |= comedi_check_trigger_src(src: &cmd->scan_end_src, TRIG_COUNT);
606 err |= comedi_check_trigger_src(src: &cmd->stop_src, TRIG_COUNT | TRIG_NONE);
607
608 if (err)
609 return 1;
610
611 /* Step 2a : make sure trigger sources are unique */
612
613 err |= comedi_check_trigger_is_unique(src: cmd->start_src);
614 err |= comedi_check_trigger_is_unique(src: cmd->scan_begin_src);
615 err |= comedi_check_trigger_is_unique(src: cmd->stop_src);
616
617 /* Step 2b : and mutually compatible */
618
619 if (err)
620 return 2;
621
622 /* Step 3: check if arguments are trivially valid */
623
624 err |= comedi_check_trigger_arg_is(arg: &cmd->start_arg, val: 0);
625
626 if (cmd->scan_begin_src == TRIG_TIMER) { /* Test Delay timing */
627 err |= comedi_check_trigger_arg_min(arg: &cmd->scan_begin_arg,
628 val: 100000);
629 }
630
631 /* minimum conversion time per sample is 10us */
632 err |= comedi_check_trigger_arg_min(arg: &cmd->convert_arg, val: 10000);
633
634 err |= comedi_check_trigger_arg_min(arg: &cmd->chanlist_len, val: 1);
635 err |= comedi_check_trigger_arg_is(arg: &cmd->scan_end_arg,
636 val: cmd->chanlist_len);
637
638 if (cmd->stop_src == TRIG_COUNT)
639 err |= comedi_check_trigger_arg_min(arg: &cmd->stop_arg, val: 1);
640 else /* TRIG_NONE */
641 err |= comedi_check_trigger_arg_is(arg: &cmd->stop_arg, val: 0);
642
643 if (err)
644 return 3;
645
646 /* Step 4: fix up any arguments */
647
648 if (cmd->scan_begin_src == TRIG_TIMER) {
649 /* scan begin must be larger than the scan time */
650 arg = cmd->convert_arg * cmd->scan_end_arg;
651 err |= comedi_check_trigger_arg_min(arg: &cmd->scan_begin_arg, val: arg);
652 }
653
654 if (err)
655 return 4;
656
657 /* Step 5: check channel list if it exists */
658
659 return 0;
660}
661
662static int apci3120_cancel(struct comedi_device *dev,
663 struct comedi_subdevice *s)
664{
665 struct apci3120_private *devpriv = dev->private;
666
667 /* Add-On - disable DMA */
668 outw(value: 0, port: devpriv->addon + 4);
669
670 /* Add-On - disable bus master */
671 apci3120_addon_write(dev, val: 0, AMCC_OP_REG_AGCSTS);
672
673 /* AMCC - disable bus master */
674 outl(value: 0, port: devpriv->amcc + AMCC_OP_REG_MCSR);
675
676 /* disable all counters, ext trigger, and reset scan */
677 devpriv->ctrl = 0;
678 outw(value: devpriv->ctrl, port: dev->iobase + APCI3120_CTRL_REG);
679
680 /* DISABLE_ALL_INTERRUPT */
681 devpriv->mode = 0;
682 outb(value: devpriv->mode, port: dev->iobase + APCI3120_MODE_REG);
683
684 inw(port: dev->iobase + APCI3120_STATUS_REG);
685 devpriv->cur_dmabuf = 0;
686
687 return 0;
688}
689
690static int apci3120_ai_eoc(struct comedi_device *dev,
691 struct comedi_subdevice *s,
692 struct comedi_insn *insn,
693 unsigned long context)
694{
695 unsigned int status;
696
697 status = inw(port: dev->iobase + APCI3120_STATUS_REG);
698 if ((status & APCI3120_STATUS_EOC_INT) == 0)
699 return 0;
700 return -EBUSY;
701}
702
703static int apci3120_ai_insn_read(struct comedi_device *dev,
704 struct comedi_subdevice *s,
705 struct comedi_insn *insn,
706 unsigned int *data)
707{
708 struct apci3120_private *devpriv = dev->private;
709 unsigned int divisor;
710 int ret;
711 int i;
712
713 /* set mode for A/D conversions by software trigger with timer 0 */
714 devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC |
715 APCI3120_MODE_TIMER2_AS_TIMER;
716 outb(value: devpriv->mode, port: dev->iobase + APCI3120_MODE_REG);
717
718 /* load chanlist for single channel scan */
719 apci3120_set_chanlist(dev, s, n_chan: 1, chanlist: &insn->chanspec);
720
721 /*
722 * Timer 0 is used in MODE4 (software triggered strobe) to set the
723 * conversion time for each acquisition. Each conversion is triggered
724 * when the divisor is written to the timer, The conversion is done
725 * when the EOC bit in the status register is '0'.
726 */
727 apci3120_timer_set_mode(dev, timer: 0, APCI3120_TIMER_MODE4);
728 apci3120_timer_enable(dev, timer: 0, enable: true);
729
730 /* fixed conversion time of 10 us */
731 divisor = apci3120_ns_to_timer(dev, timer: 0, ns: 10000, CMDF_ROUND_NEAREST);
732
733 for (i = 0; i < insn->n; i++) {
734 /* trigger conversion */
735 apci3120_timer_write(dev, timer: 0, val: divisor);
736
737 ret = comedi_timeout(dev, s, insn, cb: apci3120_ai_eoc, context: 0);
738 if (ret)
739 return ret;
740
741 data[i] = inw(port: dev->iobase + APCI3120_AI_FIFO_REG);
742 }
743
744 return insn->n;
745}
746
747static int apci3120_ao_ready(struct comedi_device *dev,
748 struct comedi_subdevice *s,
749 struct comedi_insn *insn,
750 unsigned long context)
751{
752 unsigned int status;
753
754 status = inw(port: dev->iobase + APCI3120_STATUS_REG);
755 if (status & APCI3120_STATUS_DA_READY)
756 return 0;
757 return -EBUSY;
758}
759
760static int apci3120_ao_insn_write(struct comedi_device *dev,
761 struct comedi_subdevice *s,
762 struct comedi_insn *insn,
763 unsigned int *data)
764{
765 unsigned int chan = CR_CHAN(insn->chanspec);
766 int i;
767
768 for (i = 0; i < insn->n; i++) {
769 unsigned int val = data[i];
770 int ret;
771
772 ret = comedi_timeout(dev, s, insn, cb: apci3120_ao_ready, context: 0);
773 if (ret)
774 return ret;
775
776 outw(APCI3120_AO_MUX(chan) | APCI3120_AO_DATA(val),
777 port: dev->iobase + APCI3120_AO_REG(chan));
778
779 s->readback[chan] = val;
780 }
781
782 return insn->n;
783}
784
785static int apci3120_di_insn_bits(struct comedi_device *dev,
786 struct comedi_subdevice *s,
787 struct comedi_insn *insn,
788 unsigned int *data)
789{
790 unsigned int status;
791
792 status = inw(port: dev->iobase + APCI3120_STATUS_REG);
793 data[1] = APCI3120_STATUS_TO_DI_BITS(status);
794
795 return insn->n;
796}
797
798static int apci3120_do_insn_bits(struct comedi_device *dev,
799 struct comedi_subdevice *s,
800 struct comedi_insn *insn,
801 unsigned int *data)
802{
803 struct apci3120_private *devpriv = dev->private;
804
805 if (comedi_dio_update_state(s, data)) {
806 devpriv->do_bits = s->state;
807 outb(APCI3120_CTR0_DO_BITS(devpriv->do_bits),
808 port: dev->iobase + APCI3120_CTR0_REG);
809 }
810
811 data[1] = s->state;
812
813 return insn->n;
814}
815
816static int apci3120_timer_insn_config(struct comedi_device *dev,
817 struct comedi_subdevice *s,
818 struct comedi_insn *insn,
819 unsigned int *data)
820{
821 struct apci3120_private *devpriv = dev->private;
822 unsigned int divisor;
823 unsigned int status;
824 unsigned int mode;
825 unsigned int timer_mode;
826
827 switch (data[0]) {
828 case INSN_CONFIG_ARM:
829 apci3120_clr_timer2_interrupt(dev);
830 divisor = apci3120_ns_to_timer(dev, timer: 2, ns: data[1],
831 CMDF_ROUND_DOWN);
832 apci3120_timer_write(dev, timer: 2, val: divisor);
833 apci3120_timer_enable(dev, timer: 2, enable: true);
834 break;
835
836 case INSN_CONFIG_DISARM:
837 apci3120_timer_enable(dev, timer: 2, enable: false);
838 apci3120_clr_timer2_interrupt(dev);
839 break;
840
841 case INSN_CONFIG_GET_COUNTER_STATUS:
842 data[1] = 0;
843 data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
844 COMEDI_COUNTER_TERMINAL_COUNT;
845
846 if (devpriv->ctrl & APCI3120_CTRL_GATE(2)) {
847 data[1] |= COMEDI_COUNTER_ARMED;
848 data[1] |= COMEDI_COUNTER_COUNTING;
849 }
850 status = inw(port: dev->iobase + APCI3120_STATUS_REG);
851 if (status & APCI3120_STATUS_TIMER2_INT) {
852 data[1] &= ~COMEDI_COUNTER_COUNTING;
853 data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
854 }
855 break;
856
857 case INSN_CONFIG_SET_COUNTER_MODE:
858 switch (data[1]) {
859 case I8254_MODE0:
860 mode = APCI3120_MODE_TIMER2_AS_COUNTER;
861 timer_mode = APCI3120_TIMER_MODE0;
862 break;
863 case I8254_MODE2:
864 mode = APCI3120_MODE_TIMER2_AS_TIMER;
865 timer_mode = APCI3120_TIMER_MODE2;
866 break;
867 case I8254_MODE4:
868 mode = APCI3120_MODE_TIMER2_AS_TIMER;
869 timer_mode = APCI3120_TIMER_MODE4;
870 break;
871 case I8254_MODE5:
872 mode = APCI3120_MODE_TIMER2_AS_WDOG;
873 timer_mode = APCI3120_TIMER_MODE5;
874 break;
875 default:
876 return -EINVAL;
877 }
878 apci3120_timer_enable(dev, timer: 2, enable: false);
879 apci3120_clr_timer2_interrupt(dev);
880 apci3120_timer_set_mode(dev, timer: 2, mode: timer_mode);
881 devpriv->mode &= ~APCI3120_MODE_TIMER2_AS_MASK;
882 devpriv->mode |= mode;
883 outb(value: devpriv->mode, port: dev->iobase + APCI3120_MODE_REG);
884 break;
885
886 default:
887 return -EINVAL;
888 }
889
890 return insn->n;
891}
892
893static int apci3120_timer_insn_read(struct comedi_device *dev,
894 struct comedi_subdevice *s,
895 struct comedi_insn *insn,
896 unsigned int *data)
897{
898 int i;
899
900 for (i = 0; i < insn->n; i++)
901 data[i] = apci3120_timer_read(dev, timer: 2);
902
903 return insn->n;
904}
905
906static void apci3120_dma_alloc(struct comedi_device *dev)
907{
908 struct apci3120_private *devpriv = dev->private;
909 struct apci3120_dmabuf *dmabuf;
910 int order;
911 int i;
912
913 for (i = 0; i < 2; i++) {
914 dmabuf = &devpriv->dmabuf[i];
915 for (order = 2; order >= 0; order--) {
916 dmabuf->virt = dma_alloc_coherent(dev: dev->hw_dev,
917 PAGE_SIZE << order,
918 dma_handle: &dmabuf->hw,
919 GFP_KERNEL);
920 if (dmabuf->virt)
921 break;
922 }
923 if (!dmabuf->virt)
924 break;
925 dmabuf->size = PAGE_SIZE << order;
926
927 if (i == 0)
928 devpriv->use_dma = 1;
929 if (i == 1)
930 devpriv->use_double_buffer = 1;
931 }
932}
933
934static void apci3120_dma_free(struct comedi_device *dev)
935{
936 struct apci3120_private *devpriv = dev->private;
937 struct apci3120_dmabuf *dmabuf;
938 int i;
939
940 if (!devpriv)
941 return;
942
943 for (i = 0; i < 2; i++) {
944 dmabuf = &devpriv->dmabuf[i];
945 if (dmabuf->virt) {
946 dma_free_coherent(dev: dev->hw_dev, size: dmabuf->size,
947 cpu_addr: dmabuf->virt, dma_handle: dmabuf->hw);
948 }
949 }
950}
951
952static void apci3120_reset(struct comedi_device *dev)
953{
954 /* disable all interrupt sources */
955 outb(value: 0, port: dev->iobase + APCI3120_MODE_REG);
956
957 /* disable all counters, ext trigger, and reset scan */
958 outw(value: 0, port: dev->iobase + APCI3120_CTRL_REG);
959
960 /* clear interrupt status */
961 inw(port: dev->iobase + APCI3120_STATUS_REG);
962}
963
964static int apci3120_auto_attach(struct comedi_device *dev,
965 unsigned long context)
966{
967 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
968 const struct apci3120_board *board = NULL;
969 struct apci3120_private *devpriv;
970 struct comedi_subdevice *s;
971 unsigned int status;
972 int ret;
973
974 if (context < ARRAY_SIZE(apci3120_boardtypes))
975 board = &apci3120_boardtypes[context];
976 if (!board)
977 return -ENODEV;
978 dev->board_ptr = board;
979 dev->board_name = board->name;
980
981 devpriv = comedi_alloc_devpriv(dev, size: sizeof(*devpriv));
982 if (!devpriv)
983 return -ENOMEM;
984
985 ret = comedi_pci_enable(dev);
986 if (ret)
987 return ret;
988 pci_set_master(dev: pcidev);
989
990 dev->iobase = pci_resource_start(pcidev, 1);
991 devpriv->amcc = pci_resource_start(pcidev, 0);
992 devpriv->addon = pci_resource_start(pcidev, 2);
993
994 apci3120_reset(dev);
995
996 if (pcidev->irq > 0) {
997 ret = request_irq(irq: pcidev->irq, handler: apci3120_interrupt, IRQF_SHARED,
998 name: dev->board_name, dev);
999 if (ret == 0) {
1000 dev->irq = pcidev->irq;
1001
1002 apci3120_dma_alloc(dev);
1003 }
1004 }
1005
1006 status = inw(port: dev->iobase + APCI3120_STATUS_REG);
1007 if (APCI3120_STATUS_TO_VERSION(status) == APCI3120_REVB ||
1008 context == BOARD_APCI3001)
1009 devpriv->osc_base = APCI3120_REVB_OSC_BASE;
1010 else
1011 devpriv->osc_base = APCI3120_REVA_OSC_BASE;
1012
1013 ret = comedi_alloc_subdevices(dev, num_subdevices: 5);
1014 if (ret)
1015 return ret;
1016
1017 /* Analog Input subdevice */
1018 s = &dev->subdevices[0];
1019 s->type = COMEDI_SUBD_AI;
1020 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
1021 s->n_chan = 16;
1022 s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff;
1023 s->range_table = &apci3120_ai_range;
1024 s->insn_read = apci3120_ai_insn_read;
1025 if (dev->irq) {
1026 dev->read_subdev = s;
1027 s->subdev_flags |= SDF_CMD_READ;
1028 s->len_chanlist = s->n_chan;
1029 s->do_cmdtest = apci3120_ai_cmdtest;
1030 s->do_cmd = apci3120_ai_cmd;
1031 s->cancel = apci3120_cancel;
1032 }
1033
1034 /* Analog Output subdevice */
1035 s = &dev->subdevices[1];
1036 if (board->has_ao) {
1037 s->type = COMEDI_SUBD_AO;
1038 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1039 s->n_chan = 8;
1040 s->maxdata = 0x3fff;
1041 s->range_table = &range_bipolar10;
1042 s->insn_write = apci3120_ao_insn_write;
1043
1044 ret = comedi_alloc_subdev_readback(s);
1045 if (ret)
1046 return ret;
1047 } else {
1048 s->type = COMEDI_SUBD_UNUSED;
1049 }
1050
1051 /* Digital Input subdevice */
1052 s = &dev->subdevices[2];
1053 s->type = COMEDI_SUBD_DI;
1054 s->subdev_flags = SDF_READABLE;
1055 s->n_chan = 4;
1056 s->maxdata = 1;
1057 s->range_table = &range_digital;
1058 s->insn_bits = apci3120_di_insn_bits;
1059
1060 /* Digital Output subdevice */
1061 s = &dev->subdevices[3];
1062 s->type = COMEDI_SUBD_DO;
1063 s->subdev_flags = SDF_WRITABLE;
1064 s->n_chan = 4;
1065 s->maxdata = 1;
1066 s->range_table = &range_digital;
1067 s->insn_bits = apci3120_do_insn_bits;
1068
1069 /* Timer subdevice */
1070 s = &dev->subdevices[4];
1071 s->type = COMEDI_SUBD_TIMER;
1072 s->subdev_flags = SDF_READABLE;
1073 s->n_chan = 1;
1074 s->maxdata = 0x00ffffff;
1075 s->insn_config = apci3120_timer_insn_config;
1076 s->insn_read = apci3120_timer_insn_read;
1077
1078 return 0;
1079}
1080
1081static void apci3120_detach(struct comedi_device *dev)
1082{
1083 comedi_pci_detach(dev);
1084 apci3120_dma_free(dev);
1085}
1086
1087static struct comedi_driver apci3120_driver = {
1088 .driver_name = "addi_apci_3120",
1089 .module = THIS_MODULE,
1090 .auto_attach = apci3120_auto_attach,
1091 .detach = apci3120_detach,
1092};
1093
1094static int apci3120_pci_probe(struct pci_dev *dev,
1095 const struct pci_device_id *id)
1096{
1097 return comedi_pci_auto_config(pcidev: dev, driver: &apci3120_driver, context: id->driver_data);
1098}
1099
1100static const struct pci_device_id apci3120_pci_table[] = {
1101 { PCI_VDEVICE(AMCC, 0x818d), BOARD_APCI3120 },
1102 { PCI_VDEVICE(AMCC, 0x828d), BOARD_APCI3001 },
1103 { 0 }
1104};
1105MODULE_DEVICE_TABLE(pci, apci3120_pci_table);
1106
1107static struct pci_driver apci3120_pci_driver = {
1108 .name = "addi_apci_3120",
1109 .id_table = apci3120_pci_table,
1110 .probe = apci3120_pci_probe,
1111 .remove = comedi_pci_auto_unconfig,
1112};
1113module_comedi_pci_driver(apci3120_driver, apci3120_pci_driver);
1114
1115MODULE_AUTHOR("Comedi https://www.comedi.org");
1116MODULE_DESCRIPTION("ADDI-DATA APCI-3120, Analog input board");
1117MODULE_LICENSE("GPL");
1118

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