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