Merge tag 'for-4.1' of git://git.kernel.org/pub/scm/linux/kernel/git/kishon/linux...
[deliverable/linux.git] / drivers / staging / comedi / drivers / adv_pci1710.c
1 /*
2 * comedi/drivers/adv_pci1710.c
3 *
4 * Author: Michal Dobes <dobes@tesnet.cz>
5 *
6 * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7 * for testing and informations.
8 *
9 * hardware driver for Advantech cards:
10 * card: PCI-1710, PCI-1710HG, PCI-1711, PCI-1713, PCI-1720, PCI-1731
11 * driver: pci1710, pci1710hg, pci1711, pci1713, pci1720, pci1731
12 *
13 * Options:
14 * [0] - PCI bus number - if bus number and slot number are 0,
15 * then driver search for first unused card
16 * [1] - PCI slot number
17 *
18 */
19 /*
20 Driver: adv_pci1710
21 Description: Advantech PCI-1710, PCI-1710HG, PCI-1711, PCI-1713,
22 Advantech PCI-1720, PCI-1731
23 Author: Michal Dobes <dobes@tesnet.cz>
24 Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG (pci1710hg),
25 PCI-1711 (adv_pci1710), PCI-1713, PCI-1720,
26 PCI-1731
27 Status: works
28
29 This driver supports AI, AO, DI and DO subdevices.
30 AI subdevice supports cmd and insn interface,
31 other subdevices support only insn interface.
32
33 The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
34 driver cannot distinguish between them, as would be normal for a
35 PCI driver.
36
37 Configuration options:
38 [0] - PCI bus of device (optional)
39 [1] - PCI slot of device (optional)
40 If bus/slot is not specified, the first available PCI
41 device will be used.
42 */
43
44 #include <linux/module.h>
45 #include <linux/pci.h>
46 #include <linux/interrupt.h>
47
48 #include "../comedidev.h"
49
50 #include "comedi_fc.h"
51 #include "8253.h"
52 #include "amcc_s5933.h"
53
54 #define PCI171x_AD_DATA 0 /* R: A/D data */
55 #define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
56 #define PCI171x_RANGE 2 /* W: A/D gain/range register */
57 #define PCI171x_MUX 4 /* W: A/D multiplexor control */
58 #define PCI171x_STATUS 6 /* R: status register */
59 #define PCI171x_CONTROL 6 /* W: control register */
60 #define PCI171x_CLRINT 8 /* W: clear interrupts request */
61 #define PCI171x_CLRFIFO 9 /* W: clear FIFO */
62 #define PCI171x_DA1 10 /* W: D/A register */
63 #define PCI171x_DA2 12 /* W: D/A register */
64 #define PCI171x_DAREF 14 /* W: D/A reference control */
65 #define PCI171x_DI 16 /* R: digi inputs */
66 #define PCI171x_DO 16 /* R: digi inputs */
67
68 #define PCI171X_TIMER_BASE 0x18
69
70 #define PCI171x_CNT0 24 /* R/W: 8254 counter 0 */
71 #define PCI171x_CNT1 26 /* R/W: 8254 counter 1 */
72 #define PCI171x_CNT2 28 /* R/W: 8254 counter 2 */
73 #define PCI171x_CNTCTRL 30 /* W: 8254 counter control */
74
75 /* upper bits from status register (PCI171x_STATUS) (lower is same with control
76 * reg) */
77 #define Status_FE 0x0100 /* 1=FIFO is empty */
78 #define Status_FH 0x0200 /* 1=FIFO is half full */
79 #define Status_FF 0x0400 /* 1=FIFO is full, fatal error */
80 #define Status_IRQ 0x0800 /* 1=IRQ occurred */
81 /* bits from control register (PCI171x_CONTROL) */
82 #define Control_CNT0 0x0040 /* 1=CNT0 have external source,
83 * 0=have internal 100kHz source */
84 #define Control_ONEFH 0x0020 /* 1=IRQ on FIFO is half full, 0=every sample */
85 #define Control_IRQEN 0x0010 /* 1=enable IRQ */
86 #define Control_GATE 0x0008 /* 1=enable external trigger GATE (8254?) */
87 #define Control_EXT 0x0004 /* 1=external trigger source */
88 #define Control_PACER 0x0002 /* 1=enable internal 8254 trigger source */
89 #define Control_SW 0x0001 /* 1=enable software trigger source */
90 /* bits from counter control register (PCI171x_CNTCTRL) */
91 #define Counter_BCD 0x0001 /* 0 = binary counter, 1 = BCD counter */
92 #define Counter_M0 0x0002 /* M0-M2 select modes 0-5 */
93 #define Counter_M1 0x0004 /* 000 = mode 0, 010 = mode 2 ... */
94 #define Counter_M2 0x0008
95 #define Counter_RW0 0x0010 /* RW0/RW1 select read/write mode */
96 #define Counter_RW1 0x0020
97 #define Counter_SC0 0x0040 /* Select Counter. Only 00 or 11 may */
98 #define Counter_SC1 0x0080 /* be used, 00 for CNT0,
99 * 11 for read-back command */
100
101 #define PCI1720_DA0 0 /* W: D/A register 0 */
102 #define PCI1720_DA1 2 /* W: D/A register 1 */
103 #define PCI1720_DA2 4 /* W: D/A register 2 */
104 #define PCI1720_DA3 6 /* W: D/A register 3 */
105 #define PCI1720_RANGE 8 /* R/W: D/A range register */
106 #define PCI1720_SYNCOUT 9 /* W: D/A synchronized output register */
107 #define PCI1720_SYNCONT 15 /* R/W: D/A synchronized control */
108
109 /* D/A synchronized control (PCI1720_SYNCONT) */
110 #define Syncont_SC0 1 /* set synchronous output mode */
111
112 static const struct comedi_lrange range_pci1710_3 = {
113 9, {
114 BIP_RANGE(5),
115 BIP_RANGE(2.5),
116 BIP_RANGE(1.25),
117 BIP_RANGE(0.625),
118 BIP_RANGE(10),
119 UNI_RANGE(10),
120 UNI_RANGE(5),
121 UNI_RANGE(2.5),
122 UNI_RANGE(1.25)
123 }
124 };
125
126 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
127 0x10, 0x11, 0x12, 0x13 };
128
129 static const struct comedi_lrange range_pci1710hg = {
130 12, {
131 BIP_RANGE(5),
132 BIP_RANGE(0.5),
133 BIP_RANGE(0.05),
134 BIP_RANGE(0.005),
135 BIP_RANGE(10),
136 BIP_RANGE(1),
137 BIP_RANGE(0.1),
138 BIP_RANGE(0.01),
139 UNI_RANGE(10),
140 UNI_RANGE(1),
141 UNI_RANGE(0.1),
142 UNI_RANGE(0.01)
143 }
144 };
145
146 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
147 0x05, 0x06, 0x07, 0x10, 0x11,
148 0x12, 0x13 };
149
150 static const struct comedi_lrange range_pci17x1 = {
151 5, {
152 BIP_RANGE(10),
153 BIP_RANGE(5),
154 BIP_RANGE(2.5),
155 BIP_RANGE(1.25),
156 BIP_RANGE(0.625)
157 }
158 };
159
160 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
161
162 static const struct comedi_lrange pci1720_ao_range = {
163 4, {
164 UNI_RANGE(5),
165 UNI_RANGE(10),
166 BIP_RANGE(5),
167 BIP_RANGE(10)
168 }
169 };
170
171 static const struct comedi_lrange pci171x_ao_range = {
172 2, {
173 UNI_RANGE(5),
174 UNI_RANGE(10)
175 }
176 };
177
178 enum pci1710_boardid {
179 BOARD_PCI1710,
180 BOARD_PCI1710HG,
181 BOARD_PCI1711,
182 BOARD_PCI1713,
183 BOARD_PCI1720,
184 BOARD_PCI1731,
185 };
186
187 struct boardtype {
188 const char *name; /* board name */
189 int n_aichan; /* num of A/D chans */
190 const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
191 const char *rangecode_ai; /* range codes for programming */
192 unsigned int is_pci1713:1;
193 unsigned int is_pci1720:1;
194 unsigned int has_irq:1;
195 unsigned int has_large_fifo:1; /* 4K or 1K FIFO */
196 unsigned int has_diff_ai:1;
197 unsigned int has_ao:1;
198 unsigned int has_di_do:1;
199 unsigned int has_counter:1;
200 };
201
202 static const struct boardtype boardtypes[] = {
203 [BOARD_PCI1710] = {
204 .name = "pci1710",
205 .n_aichan = 16,
206 .rangelist_ai = &range_pci1710_3,
207 .rangecode_ai = range_codes_pci1710_3,
208 .has_irq = 1,
209 .has_large_fifo = 1,
210 .has_diff_ai = 1,
211 .has_ao = 1,
212 .has_di_do = 1,
213 .has_counter = 1,
214 },
215 [BOARD_PCI1710HG] = {
216 .name = "pci1710hg",
217 .n_aichan = 16,
218 .rangelist_ai = &range_pci1710hg,
219 .rangecode_ai = range_codes_pci1710hg,
220 .has_irq = 1,
221 .has_large_fifo = 1,
222 .has_diff_ai = 1,
223 .has_ao = 1,
224 .has_di_do = 1,
225 .has_counter = 1,
226 },
227 [BOARD_PCI1711] = {
228 .name = "pci1711",
229 .n_aichan = 16,
230 .rangelist_ai = &range_pci17x1,
231 .rangecode_ai = range_codes_pci17x1,
232 .has_irq = 1,
233 .has_ao = 1,
234 .has_di_do = 1,
235 .has_counter = 1,
236 },
237 [BOARD_PCI1713] = {
238 .name = "pci1713",
239 .n_aichan = 32,
240 .rangelist_ai = &range_pci1710_3,
241 .rangecode_ai = range_codes_pci1710_3,
242 .is_pci1713 = 1,
243 .has_irq = 1,
244 .has_large_fifo = 1,
245 .has_diff_ai = 1,
246 },
247 [BOARD_PCI1720] = {
248 .name = "pci1720",
249 .is_pci1720 = 1,
250 .has_ao = 1,
251 },
252 [BOARD_PCI1731] = {
253 .name = "pci1731",
254 .n_aichan = 16,
255 .rangelist_ai = &range_pci17x1,
256 .rangecode_ai = range_codes_pci17x1,
257 .has_irq = 1,
258 .has_di_do = 1,
259 },
260 };
261
262 struct pci1710_private {
263 unsigned int max_samples;
264 unsigned int CntrlReg; /* Control register */
265 unsigned char ai_et;
266 unsigned int ai_et_CntrlReg;
267 unsigned int ai_et_MuxVal;
268 unsigned int next_divisor1;
269 unsigned int next_divisor2;
270 unsigned int divisor1;
271 unsigned int divisor2;
272 unsigned int act_chanlist[32]; /* list of scanned channel */
273 unsigned char saved_seglen; /* len of the non-repeating chanlist */
274 unsigned char da_ranges; /* copy of D/A outpit range register */
275 unsigned int cnt0_write_wait; /* after a write, wait for update of the
276 * internal state */
277 };
278
279 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
280 struct comedi_subdevice *s,
281 struct comedi_cmd *cmd)
282 {
283 struct pci1710_private *devpriv = dev->private;
284 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
285 unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
286 unsigned int next_chan = (chan0 + 1) % s->n_chan;
287 unsigned int chansegment[32];
288 unsigned int seglen;
289 int i;
290
291 if (cmd->chanlist_len == 1) {
292 devpriv->saved_seglen = cmd->chanlist_len;
293 return 0;
294 }
295
296 /* first channel is always ok */
297 chansegment[0] = cmd->chanlist[0];
298
299 for (i = 1; i < cmd->chanlist_len; i++) {
300 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
301 unsigned int aref = CR_AREF(cmd->chanlist[i]);
302
303 if (cmd->chanlist[0] == cmd->chanlist[i])
304 break; /* we detected a loop, stop */
305
306 if (aref == AREF_DIFF && (chan & 1)) {
307 dev_err(dev->class_dev,
308 "Odd channel cannot be differential input!\n");
309 return -EINVAL;
310 }
311
312 if (last_aref == AREF_DIFF)
313 next_chan = (next_chan + 1) % s->n_chan;
314 if (chan != next_chan) {
315 dev_err(dev->class_dev,
316 "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
317 i, chan, next_chan, chan0);
318 return -EINVAL;
319 }
320
321 /* next correct channel in list */
322 chansegment[i] = cmd->chanlist[i];
323 last_aref = aref;
324 }
325 seglen = i;
326
327 for (i = 0; i < cmd->chanlist_len; i++) {
328 if (cmd->chanlist[i] != chansegment[i % seglen]) {
329 dev_err(dev->class_dev,
330 "bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
331 i, CR_CHAN(chansegment[i]),
332 CR_RANGE(chansegment[i]),
333 CR_AREF(chansegment[i]),
334 CR_CHAN(cmd->chanlist[i % seglen]),
335 CR_RANGE(cmd->chanlist[i % seglen]),
336 CR_AREF(chansegment[i % seglen]));
337 return -EINVAL;
338 }
339 }
340 devpriv->saved_seglen = seglen;
341
342 return 0;
343 }
344
345 static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
346 struct comedi_subdevice *s,
347 unsigned int *chanlist,
348 unsigned int n_chan,
349 unsigned int seglen)
350 {
351 const struct boardtype *board = dev->board_ptr;
352 struct pci1710_private *devpriv = dev->private;
353 unsigned int first_chan = CR_CHAN(chanlist[0]);
354 unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
355 unsigned int i;
356
357 for (i = 0; i < seglen; i++) { /* store range list to card */
358 unsigned int chan = CR_CHAN(chanlist[i]);
359 unsigned int range = CR_RANGE(chanlist[i]);
360 unsigned int aref = CR_AREF(chanlist[i]);
361 unsigned int rangeval;
362
363 rangeval = board->rangecode_ai[range];
364 if (aref == AREF_DIFF)
365 rangeval |= 0x0020;
366
367 /* select channel and set range */
368 outw(chan | (chan << 8), dev->iobase + PCI171x_MUX);
369 outw(rangeval, dev->iobase + PCI171x_RANGE);
370
371 devpriv->act_chanlist[i] = chan;
372 }
373 for ( ; i < n_chan; i++) /* store remainder of channel list */
374 devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
375
376 /* select channel interval to scan */
377 devpriv->ai_et_MuxVal = first_chan | (last_chan << 8);
378 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
379 }
380
381 static int pci171x_ai_eoc(struct comedi_device *dev,
382 struct comedi_subdevice *s,
383 struct comedi_insn *insn,
384 unsigned long context)
385 {
386 unsigned int status;
387
388 status = inw(dev->iobase + PCI171x_STATUS);
389 if ((status & Status_FE) == 0)
390 return 0;
391 return -EBUSY;
392 }
393
394 static int pci171x_ai_read_sample(struct comedi_device *dev,
395 struct comedi_subdevice *s,
396 unsigned int cur_chan,
397 unsigned int *val)
398 {
399 const struct boardtype *board = dev->board_ptr;
400 struct pci1710_private *devpriv = dev->private;
401 unsigned int sample;
402 unsigned int chan;
403
404 sample = inw(dev->iobase + PCI171x_AD_DATA);
405 if (!board->is_pci1713) {
406 /*
407 * The upper 4 bits of the 16-bit sample are the channel number
408 * that the sample was acquired from. Verify that this channel
409 * number matches the expected channel number.
410 */
411 chan = sample >> 12;
412 if (chan != devpriv->act_chanlist[cur_chan]) {
413 dev_err(dev->class_dev,
414 "A/D data droput: received from channel %d, expected %d\n",
415 chan, devpriv->act_chanlist[cur_chan]);
416 return -ENODATA;
417 }
418 }
419 *val = sample & s->maxdata;
420 return 0;
421 }
422
423 static int pci171x_ai_insn_read(struct comedi_device *dev,
424 struct comedi_subdevice *s,
425 struct comedi_insn *insn,
426 unsigned int *data)
427 {
428 struct pci1710_private *devpriv = dev->private;
429 int ret = 0;
430 int i;
431
432 devpriv->CntrlReg &= Control_CNT0;
433 devpriv->CntrlReg |= Control_SW; /* set software trigger */
434 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
435 outb(0, dev->iobase + PCI171x_CLRFIFO);
436 outb(0, dev->iobase + PCI171x_CLRINT);
437
438 pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
439
440 for (i = 0; i < insn->n; i++) {
441 unsigned int val;
442
443 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
444
445 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
446 if (ret)
447 break;
448
449 ret = pci171x_ai_read_sample(dev, s, 0, &val);
450 if (ret)
451 break;
452
453 data[i] = val;
454 }
455
456 outb(0, dev->iobase + PCI171x_CLRFIFO);
457 outb(0, dev->iobase + PCI171x_CLRINT);
458
459 return ret ? ret : insn->n;
460 }
461
462 static int pci171x_ao_insn_write(struct comedi_device *dev,
463 struct comedi_subdevice *s,
464 struct comedi_insn *insn,
465 unsigned int *data)
466 {
467 struct pci1710_private *devpriv = dev->private;
468 unsigned int chan = CR_CHAN(insn->chanspec);
469 unsigned int range = CR_RANGE(insn->chanspec);
470 unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
471 unsigned int val = s->readback[chan];
472 int i;
473
474 devpriv->da_ranges &= ~(1 << (chan << 1));
475 devpriv->da_ranges |= (range << (chan << 1));
476 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
477
478 for (i = 0; i < insn->n; i++) {
479 val = data[i];
480 outw(val, dev->iobase + reg);
481 }
482
483 s->readback[chan] = val;
484
485 return insn->n;
486 }
487
488 static int pci171x_di_insn_bits(struct comedi_device *dev,
489 struct comedi_subdevice *s,
490 struct comedi_insn *insn,
491 unsigned int *data)
492 {
493 data[1] = inw(dev->iobase + PCI171x_DI);
494
495 return insn->n;
496 }
497
498 static int pci171x_do_insn_bits(struct comedi_device *dev,
499 struct comedi_subdevice *s,
500 struct comedi_insn *insn,
501 unsigned int *data)
502 {
503 if (comedi_dio_update_state(s, data))
504 outw(s->state, dev->iobase + PCI171x_DO);
505
506 data[1] = s->state;
507
508 return insn->n;
509 }
510
511 static void pci171x_start_pacer(struct comedi_device *dev,
512 bool load_counters)
513 {
514 struct pci1710_private *devpriv = dev->private;
515 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
516
517 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
518 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
519
520 if (load_counters) {
521 i8254_write(timer_base, 1, 2, devpriv->divisor2);
522 i8254_write(timer_base, 1, 1, devpriv->divisor1);
523 }
524 }
525
526 static int pci171x_counter_insn_read(struct comedi_device *dev,
527 struct comedi_subdevice *s,
528 struct comedi_insn *insn,
529 unsigned int *data)
530 {
531 unsigned int msb, lsb, ccntrl;
532 int i;
533
534 ccntrl = 0xD2; /* count only */
535 for (i = 0; i < insn->n; i++) {
536 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
537
538 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
539 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
540
541 data[0] = lsb | (msb << 8);
542 }
543
544 return insn->n;
545 }
546
547 static int pci171x_counter_insn_write(struct comedi_device *dev,
548 struct comedi_subdevice *s,
549 struct comedi_insn *insn,
550 unsigned int *data)
551 {
552 struct pci1710_private *devpriv = dev->private;
553 uint msb, lsb, ccntrl, status;
554
555 lsb = data[0] & 0x00FF;
556 msb = (data[0] & 0xFF00) >> 8;
557
558 /* write lsb, then msb */
559 outw(lsb, dev->iobase + PCI171x_CNT0);
560 outw(msb, dev->iobase + PCI171x_CNT0);
561
562 if (devpriv->cnt0_write_wait) {
563 /* wait for the new count to be loaded */
564 ccntrl = 0xE2;
565 do {
566 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
567 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
568 } while (status & 0x40);
569 }
570
571 return insn->n;
572 }
573
574 static int pci171x_counter_insn_config(struct comedi_device *dev,
575 struct comedi_subdevice *s,
576 struct comedi_insn *insn,
577 unsigned int *data)
578 {
579 #ifdef unused
580 /* This doesn't work like a normal Comedi counter config */
581 struct pci1710_private *devpriv = dev->private;
582 uint ccntrl = 0;
583
584 devpriv->cnt0_write_wait = data[0] & 0x20;
585
586 /* internal or external clock? */
587 if (!(data[0] & 0x10)) { /* internal */
588 devpriv->CntrlReg &= ~Control_CNT0;
589 } else {
590 devpriv->CntrlReg |= Control_CNT0;
591 }
592 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
593
594 if (data[0] & 0x01)
595 ccntrl |= Counter_M0;
596 if (data[0] & 0x02)
597 ccntrl |= Counter_M1;
598 if (data[0] & 0x04)
599 ccntrl |= Counter_M2;
600 if (data[0] & 0x08)
601 ccntrl |= Counter_BCD;
602 ccntrl |= Counter_RW0; /* set read/write mode */
603 ccntrl |= Counter_RW1;
604 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
605 #endif
606
607 return 1;
608 }
609
610 static int pci1720_ao_insn_write(struct comedi_device *dev,
611 struct comedi_subdevice *s,
612 struct comedi_insn *insn,
613 unsigned int *data)
614 {
615 struct pci1710_private *devpriv = dev->private;
616 unsigned int chan = CR_CHAN(insn->chanspec);
617 unsigned int range = CR_RANGE(insn->chanspec);
618 unsigned int val;
619 int i;
620
621 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
622 val |= (range << (chan << 1));
623 if (val != devpriv->da_ranges) {
624 outb(val, dev->iobase + PCI1720_RANGE);
625 devpriv->da_ranges = val;
626 }
627
628 val = s->readback[chan];
629 for (i = 0; i < insn->n; i++) {
630 val = data[i];
631 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
632 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
633 }
634
635 s->readback[chan] = val;
636
637 return insn->n;
638 }
639
640 static int pci171x_ai_cancel(struct comedi_device *dev,
641 struct comedi_subdevice *s)
642 {
643 struct pci1710_private *devpriv = dev->private;
644
645 devpriv->CntrlReg &= Control_CNT0;
646 devpriv->CntrlReg |= Control_SW;
647 /* reset any operations */
648 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
649 pci171x_start_pacer(dev, false);
650 outb(0, dev->iobase + PCI171x_CLRFIFO);
651 outb(0, dev->iobase + PCI171x_CLRINT);
652
653 return 0;
654 }
655
656 static void pci1710_handle_every_sample(struct comedi_device *dev,
657 struct comedi_subdevice *s)
658 {
659 struct comedi_cmd *cmd = &s->async->cmd;
660 unsigned int status;
661 unsigned int val;
662 int ret;
663
664 status = inw(dev->iobase + PCI171x_STATUS);
665 if (status & Status_FE) {
666 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
667 s->async->events |= COMEDI_CB_ERROR;
668 return;
669 }
670 if (status & Status_FF) {
671 dev_dbg(dev->class_dev,
672 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
673 s->async->events |= COMEDI_CB_ERROR;
674 return;
675 }
676
677 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
678
679 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
680 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
681 if (ret) {
682 s->async->events |= COMEDI_CB_ERROR;
683 break;
684 }
685
686 comedi_buf_write_samples(s, &val, 1);
687
688 if (cmd->stop_src == TRIG_COUNT &&
689 s->async->scans_done >= cmd->stop_arg) {
690 s->async->events |= COMEDI_CB_EOA;
691 break;
692 }
693 }
694
695 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
696 }
697
698 static void pci1710_handle_fifo(struct comedi_device *dev,
699 struct comedi_subdevice *s)
700 {
701 struct pci1710_private *devpriv = dev->private;
702 struct comedi_async *async = s->async;
703 struct comedi_cmd *cmd = &async->cmd;
704 unsigned int status;
705 int i;
706
707 status = inw(dev->iobase + PCI171x_STATUS);
708 if (!(status & Status_FH)) {
709 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
710 async->events |= COMEDI_CB_ERROR;
711 return;
712 }
713 if (status & Status_FF) {
714 dev_dbg(dev->class_dev,
715 "A/D FIFO Full status (Fatal Error!)\n");
716 async->events |= COMEDI_CB_ERROR;
717 return;
718 }
719
720 for (i = 0; i < devpriv->max_samples; i++) {
721 unsigned int val;
722 int ret;
723
724 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
725 if (ret) {
726 s->async->events |= COMEDI_CB_ERROR;
727 break;
728 }
729
730 if (!comedi_buf_write_samples(s, &val, 1))
731 break;
732
733 if (cmd->stop_src == TRIG_COUNT &&
734 async->scans_done >= cmd->stop_arg) {
735 async->events |= COMEDI_CB_EOA;
736 break;
737 }
738 }
739
740 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
741 }
742
743 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
744 {
745 struct comedi_device *dev = d;
746 struct pci1710_private *devpriv = dev->private;
747 struct comedi_subdevice *s;
748 struct comedi_cmd *cmd;
749
750 if (!dev->attached) /* is device attached? */
751 return IRQ_NONE; /* no, exit */
752
753 s = dev->read_subdev;
754 cmd = &s->async->cmd;
755
756 /* is this interrupt from our board? */
757 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
758 return IRQ_NONE; /* no, exit */
759
760 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
761 devpriv->ai_et = 0;
762 devpriv->CntrlReg &= Control_CNT0;
763 devpriv->CntrlReg |= Control_SW; /* set software trigger */
764 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
765 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
766 outb(0, dev->iobase + PCI171x_CLRFIFO);
767 outb(0, dev->iobase + PCI171x_CLRINT);
768 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
769 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
770 pci171x_start_pacer(dev, true);
771 return IRQ_HANDLED;
772 }
773
774 if (cmd->flags & CMDF_WAKE_EOS)
775 pci1710_handle_every_sample(dev, s);
776 else
777 pci1710_handle_fifo(dev, s);
778
779 comedi_handle_events(dev, s);
780
781 return IRQ_HANDLED;
782 }
783
784 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
785 {
786 struct pci1710_private *devpriv = dev->private;
787 struct comedi_cmd *cmd = &s->async->cmd;
788
789 pci171x_start_pacer(dev, false);
790
791 pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
792 devpriv->saved_seglen);
793
794 outb(0, dev->iobase + PCI171x_CLRFIFO);
795 outb(0, dev->iobase + PCI171x_CLRINT);
796
797 devpriv->CntrlReg &= Control_CNT0;
798 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
799 devpriv->CntrlReg |= Control_ONEFH;
800
801 devpriv->divisor1 = devpriv->next_divisor1;
802 devpriv->divisor2 = devpriv->next_divisor2;
803
804 if (cmd->convert_src == TRIG_TIMER) {
805 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
806 if (cmd->start_src == TRIG_EXT) {
807 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
808 devpriv->CntrlReg &=
809 ~(Control_PACER | Control_ONEFH | Control_GATE);
810 devpriv->CntrlReg |= Control_EXT;
811 devpriv->ai_et = 1;
812 } else { /* TRIG_NOW */
813 devpriv->ai_et = 0;
814 }
815 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
816
817 if (cmd->start_src == TRIG_NOW)
818 pci171x_start_pacer(dev, true);
819 } else { /* TRIG_EXT */
820 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
821 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
822 }
823
824 return 0;
825 }
826
827 static int pci171x_ai_cmdtest(struct comedi_device *dev,
828 struct comedi_subdevice *s,
829 struct comedi_cmd *cmd)
830 {
831 struct pci1710_private *devpriv = dev->private;
832 int err = 0;
833 unsigned int arg;
834
835 /* Step 1 : check if triggers are trivially valid */
836
837 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
838 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
839 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
840 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
841 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
842
843 if (err)
844 return 1;
845
846 /* step 2a: make sure trigger sources are unique */
847
848 err |= cfc_check_trigger_is_unique(cmd->start_src);
849 err |= cfc_check_trigger_is_unique(cmd->convert_src);
850 err |= cfc_check_trigger_is_unique(cmd->stop_src);
851
852 /* step 2b: and mutually compatible */
853
854 if (err)
855 return 2;
856
857 /* Step 3: check if arguments are trivially valid */
858
859 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
860 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
861
862 if (cmd->convert_src == TRIG_TIMER)
863 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
864 else /* TRIG_FOLLOW */
865 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
866
867 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
868
869 if (cmd->stop_src == TRIG_COUNT)
870 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
871 else /* TRIG_NONE */
872 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
873
874 if (err)
875 return 3;
876
877 /* step 4: fix up any arguments */
878
879 if (cmd->convert_src == TRIG_TIMER) {
880 arg = cmd->convert_arg;
881 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
882 &devpriv->next_divisor1,
883 &devpriv->next_divisor2,
884 &arg, cmd->flags);
885 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
886 }
887
888 if (err)
889 return 4;
890
891 /* Step 5: check channel list */
892
893 err |= pci171x_ai_check_chanlist(dev, s, cmd);
894
895 if (err)
896 return 5;
897
898 return 0;
899 }
900
901 static int pci171x_reset(struct comedi_device *dev)
902 {
903 const struct boardtype *board = dev->board_ptr;
904 struct pci1710_private *devpriv = dev->private;
905
906 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
907 /* Software trigger, CNT0=external */
908 devpriv->CntrlReg = Control_SW | Control_CNT0;
909 /* reset any operations */
910 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
911 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
912 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
913 pci171x_start_pacer(dev, false);
914 devpriv->da_ranges = 0;
915 if (board->has_ao) {
916 /* set DACs to 0..5V */
917 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
918 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
919 outw(0, dev->iobase + PCI171x_DA2);
920 }
921 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
922 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
923 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
924
925 return 0;
926 }
927
928 static int pci1720_reset(struct comedi_device *dev)
929 {
930 struct pci1710_private *devpriv = dev->private;
931 /* set synchronous output mode */
932 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
933 devpriv->da_ranges = 0xAA;
934 /* set all ranges to +/-5V */
935 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
936 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
937 outw(0x0800, dev->iobase + PCI1720_DA1);
938 outw(0x0800, dev->iobase + PCI1720_DA2);
939 outw(0x0800, dev->iobase + PCI1720_DA3);
940 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
941
942 return 0;
943 }
944
945 static int pci1710_reset(struct comedi_device *dev)
946 {
947 const struct boardtype *board = dev->board_ptr;
948
949 if (board->is_pci1720)
950 return pci1720_reset(dev);
951
952 return pci171x_reset(dev);
953 }
954
955 static int pci1710_auto_attach(struct comedi_device *dev,
956 unsigned long context)
957 {
958 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
959 const struct boardtype *board = NULL;
960 struct pci1710_private *devpriv;
961 struct comedi_subdevice *s;
962 int ret, subdev, n_subdevices;
963
964 if (context < ARRAY_SIZE(boardtypes))
965 board = &boardtypes[context];
966 if (!board)
967 return -ENODEV;
968 dev->board_ptr = board;
969 dev->board_name = board->name;
970
971 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
972 if (!devpriv)
973 return -ENOMEM;
974
975 ret = comedi_pci_enable(dev);
976 if (ret)
977 return ret;
978 dev->iobase = pci_resource_start(pcidev, 2);
979
980 n_subdevices = 0;
981 if (board->n_aichan)
982 n_subdevices++;
983 if (board->has_ao)
984 n_subdevices++;
985 if (board->has_di_do)
986 n_subdevices += 2;
987 if (board->has_counter)
988 n_subdevices++;
989
990 ret = comedi_alloc_subdevices(dev, n_subdevices);
991 if (ret)
992 return ret;
993
994 pci1710_reset(dev);
995
996 if (board->has_irq && pcidev->irq) {
997 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
998 IRQF_SHARED, dev->board_name, dev);
999 if (ret == 0)
1000 dev->irq = pcidev->irq;
1001 }
1002
1003 subdev = 0;
1004
1005 if (board->n_aichan) {
1006 s = &dev->subdevices[subdev];
1007 s->type = COMEDI_SUBD_AI;
1008 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1009 if (board->has_diff_ai)
1010 s->subdev_flags |= SDF_DIFF;
1011 s->n_chan = board->n_aichan;
1012 s->maxdata = 0x0fff;
1013 s->range_table = board->rangelist_ai;
1014 s->insn_read = pci171x_ai_insn_read;
1015 if (dev->irq) {
1016 dev->read_subdev = s;
1017 s->subdev_flags |= SDF_CMD_READ;
1018 s->len_chanlist = s->n_chan;
1019 s->do_cmdtest = pci171x_ai_cmdtest;
1020 s->do_cmd = pci171x_ai_cmd;
1021 s->cancel = pci171x_ai_cancel;
1022 }
1023 subdev++;
1024 }
1025
1026 if (board->has_ao) {
1027 s = &dev->subdevices[subdev];
1028 s->type = COMEDI_SUBD_AO;
1029 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1030 s->maxdata = 0x0fff;
1031 if (board->is_pci1720) {
1032 s->n_chan = 4;
1033 s->range_table = &pci1720_ao_range;
1034 s->insn_write = pci1720_ao_insn_write;
1035 } else {
1036 s->n_chan = 2;
1037 s->range_table = &pci171x_ao_range;
1038 s->insn_write = pci171x_ao_insn_write;
1039 }
1040
1041 ret = comedi_alloc_subdev_readback(s);
1042 if (ret)
1043 return ret;
1044
1045 /* initialize the readback values to match the board reset */
1046 if (board->is_pci1720) {
1047 int i;
1048
1049 for (i = 0; i < s->n_chan; i++)
1050 s->readback[i] = 0x0800;
1051 }
1052
1053 subdev++;
1054 }
1055
1056 if (board->has_di_do) {
1057 s = &dev->subdevices[subdev];
1058 s->type = COMEDI_SUBD_DI;
1059 s->subdev_flags = SDF_READABLE;
1060 s->n_chan = 16;
1061 s->maxdata = 1;
1062 s->range_table = &range_digital;
1063 s->insn_bits = pci171x_di_insn_bits;
1064 subdev++;
1065
1066 s = &dev->subdevices[subdev];
1067 s->type = COMEDI_SUBD_DO;
1068 s->subdev_flags = SDF_WRITABLE;
1069 s->n_chan = 16;
1070 s->maxdata = 1;
1071 s->range_table = &range_digital;
1072 s->insn_bits = pci171x_do_insn_bits;
1073 subdev++;
1074 }
1075
1076 if (board->has_counter) {
1077 s = &dev->subdevices[subdev];
1078 s->type = COMEDI_SUBD_COUNTER;
1079 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1080 s->n_chan = 1;
1081 s->maxdata = 0xffff;
1082 s->range_table = &range_unknown;
1083 s->insn_read = pci171x_counter_insn_read;
1084 s->insn_write = pci171x_counter_insn_write;
1085 s->insn_config = pci171x_counter_insn_config;
1086 subdev++;
1087 }
1088
1089 /* max_samples is half the FIFO size (2 bytes/sample) */
1090 devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
1091
1092 return 0;
1093 }
1094
1095 static void pci1710_detach(struct comedi_device *dev)
1096 {
1097 if (dev->iobase)
1098 pci1710_reset(dev);
1099 comedi_pci_detach(dev);
1100 }
1101
1102 static struct comedi_driver adv_pci1710_driver = {
1103 .driver_name = "adv_pci1710",
1104 .module = THIS_MODULE,
1105 .auto_attach = pci1710_auto_attach,
1106 .detach = pci1710_detach,
1107 };
1108
1109 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1110 const struct pci_device_id *id)
1111 {
1112 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1113 id->driver_data);
1114 }
1115
1116 static const struct pci_device_id adv_pci1710_pci_table[] = {
1117 {
1118 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1119 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1120 .driver_data = BOARD_PCI1710,
1121 }, {
1122 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1123 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1124 .driver_data = BOARD_PCI1710,
1125 }, {
1126 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1127 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1128 .driver_data = BOARD_PCI1710,
1129 }, {
1130 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1131 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1132 .driver_data = BOARD_PCI1710,
1133 }, {
1134 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1135 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1136 .driver_data = BOARD_PCI1710,
1137 }, {
1138 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1139 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1140 .driver_data = BOARD_PCI1710,
1141 }, {
1142 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1143 .driver_data = BOARD_PCI1710,
1144 }, {
1145 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1146 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1147 .driver_data = BOARD_PCI1710HG,
1148 }, {
1149 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1150 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1151 .driver_data = BOARD_PCI1710HG,
1152 }, {
1153 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1154 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1155 .driver_data = BOARD_PCI1710HG,
1156 }, {
1157 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1158 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1159 .driver_data = BOARD_PCI1710HG,
1160 }, {
1161 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1162 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1163 .driver_data = BOARD_PCI1710HG,
1164 }, {
1165 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1166 .driver_data = BOARD_PCI1710HG,
1167 },
1168 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1169 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1170 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1171 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1172 { 0 }
1173 };
1174 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1175
1176 static struct pci_driver adv_pci1710_pci_driver = {
1177 .name = "adv_pci1710",
1178 .id_table = adv_pci1710_pci_table,
1179 .probe = adv_pci1710_pci_probe,
1180 .remove = comedi_pci_auto_unconfig,
1181 };
1182 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1183
1184 MODULE_AUTHOR("Comedi http://www.comedi.org");
1185 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1186 MODULE_LICENSE("GPL");
This page took 0.056767 seconds and 5 git commands to generate.