MAINTAINERS: Add phy-miphy28lp.c and phy-miphy365x.c to ARCH/STI architecture
[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 unsigned int chan = CR_CHAN(insn->chanspec);
430 int ret = 0;
431 int i;
432
433 devpriv->CntrlReg &= Control_CNT0;
434 devpriv->CntrlReg |= Control_SW; /* set software trigger */
435 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
436 outb(0, dev->iobase + PCI171x_CLRFIFO);
437 outb(0, dev->iobase + PCI171x_CLRINT);
438
439 pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
440
441 for (i = 0; i < insn->n; i++) {
442 unsigned int val;
443
444 outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */
445
446 ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
447 if (ret)
448 break;
449
450 ret = pci171x_ai_read_sample(dev, s, chan, &val);
451 if (ret)
452 break;
453
454 data[i] = val;
455 }
456
457 outb(0, dev->iobase + PCI171x_CLRFIFO);
458 outb(0, dev->iobase + PCI171x_CLRINT);
459
460 return ret ? ret : insn->n;
461 }
462
463 static int pci171x_ao_insn_write(struct comedi_device *dev,
464 struct comedi_subdevice *s,
465 struct comedi_insn *insn,
466 unsigned int *data)
467 {
468 struct pci1710_private *devpriv = dev->private;
469 unsigned int chan = CR_CHAN(insn->chanspec);
470 unsigned int range = CR_RANGE(insn->chanspec);
471 unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
472 unsigned int val = s->readback[chan];
473 int i;
474
475 devpriv->da_ranges &= ~(1 << (chan << 1));
476 devpriv->da_ranges |= (range << (chan << 1));
477 outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
478
479 for (i = 0; i < insn->n; i++) {
480 val = data[i];
481 outw(val, dev->iobase + reg);
482 }
483
484 s->readback[chan] = val;
485
486 return insn->n;
487 }
488
489 static int pci171x_di_insn_bits(struct comedi_device *dev,
490 struct comedi_subdevice *s,
491 struct comedi_insn *insn,
492 unsigned int *data)
493 {
494 data[1] = inw(dev->iobase + PCI171x_DI);
495
496 return insn->n;
497 }
498
499 static int pci171x_do_insn_bits(struct comedi_device *dev,
500 struct comedi_subdevice *s,
501 struct comedi_insn *insn,
502 unsigned int *data)
503 {
504 if (comedi_dio_update_state(s, data))
505 outw(s->state, dev->iobase + PCI171x_DO);
506
507 data[1] = s->state;
508
509 return insn->n;
510 }
511
512 static void pci171x_start_pacer(struct comedi_device *dev,
513 bool load_counters)
514 {
515 struct pci1710_private *devpriv = dev->private;
516 unsigned long timer_base = dev->iobase + PCI171X_TIMER_BASE;
517
518 i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY);
519 i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY);
520
521 if (load_counters) {
522 i8254_write(timer_base, 1, 2, devpriv->divisor2);
523 i8254_write(timer_base, 1, 1, devpriv->divisor1);
524 }
525 }
526
527 static int pci171x_counter_insn_read(struct comedi_device *dev,
528 struct comedi_subdevice *s,
529 struct comedi_insn *insn,
530 unsigned int *data)
531 {
532 unsigned int msb, lsb, ccntrl;
533 int i;
534
535 ccntrl = 0xD2; /* count only */
536 for (i = 0; i < insn->n; i++) {
537 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
538
539 lsb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
540 msb = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
541
542 data[0] = lsb | (msb << 8);
543 }
544
545 return insn->n;
546 }
547
548 static int pci171x_counter_insn_write(struct comedi_device *dev,
549 struct comedi_subdevice *s,
550 struct comedi_insn *insn,
551 unsigned int *data)
552 {
553 struct pci1710_private *devpriv = dev->private;
554 uint msb, lsb, ccntrl, status;
555
556 lsb = data[0] & 0x00FF;
557 msb = (data[0] & 0xFF00) >> 8;
558
559 /* write lsb, then msb */
560 outw(lsb, dev->iobase + PCI171x_CNT0);
561 outw(msb, dev->iobase + PCI171x_CNT0);
562
563 if (devpriv->cnt0_write_wait) {
564 /* wait for the new count to be loaded */
565 ccntrl = 0xE2;
566 do {
567 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
568 status = inw(dev->iobase + PCI171x_CNT0) & 0xFF;
569 } while (status & 0x40);
570 }
571
572 return insn->n;
573 }
574
575 static int pci171x_counter_insn_config(struct comedi_device *dev,
576 struct comedi_subdevice *s,
577 struct comedi_insn *insn,
578 unsigned int *data)
579 {
580 #ifdef unused
581 /* This doesn't work like a normal Comedi counter config */
582 struct pci1710_private *devpriv = dev->private;
583 uint ccntrl = 0;
584
585 devpriv->cnt0_write_wait = data[0] & 0x20;
586
587 /* internal or external clock? */
588 if (!(data[0] & 0x10)) { /* internal */
589 devpriv->CntrlReg &= ~Control_CNT0;
590 } else {
591 devpriv->CntrlReg |= Control_CNT0;
592 }
593 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
594
595 if (data[0] & 0x01)
596 ccntrl |= Counter_M0;
597 if (data[0] & 0x02)
598 ccntrl |= Counter_M1;
599 if (data[0] & 0x04)
600 ccntrl |= Counter_M2;
601 if (data[0] & 0x08)
602 ccntrl |= Counter_BCD;
603 ccntrl |= Counter_RW0; /* set read/write mode */
604 ccntrl |= Counter_RW1;
605 outw(ccntrl, dev->iobase + PCI171x_CNTCTRL);
606 #endif
607
608 return 1;
609 }
610
611 static int pci1720_ao_insn_write(struct comedi_device *dev,
612 struct comedi_subdevice *s,
613 struct comedi_insn *insn,
614 unsigned int *data)
615 {
616 struct pci1710_private *devpriv = dev->private;
617 unsigned int chan = CR_CHAN(insn->chanspec);
618 unsigned int range = CR_RANGE(insn->chanspec);
619 unsigned int val;
620 int i;
621
622 val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
623 val |= (range << (chan << 1));
624 if (val != devpriv->da_ranges) {
625 outb(val, dev->iobase + PCI1720_RANGE);
626 devpriv->da_ranges = val;
627 }
628
629 val = s->readback[chan];
630 for (i = 0; i < insn->n; i++) {
631 val = data[i];
632 outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
633 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
634 }
635
636 s->readback[chan] = val;
637
638 return insn->n;
639 }
640
641 static int pci171x_ai_cancel(struct comedi_device *dev,
642 struct comedi_subdevice *s)
643 {
644 struct pci1710_private *devpriv = dev->private;
645
646 devpriv->CntrlReg &= Control_CNT0;
647 devpriv->CntrlReg |= Control_SW;
648 /* reset any operations */
649 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
650 pci171x_start_pacer(dev, false);
651 outb(0, dev->iobase + PCI171x_CLRFIFO);
652 outb(0, dev->iobase + PCI171x_CLRINT);
653
654 return 0;
655 }
656
657 static void pci1710_handle_every_sample(struct comedi_device *dev,
658 struct comedi_subdevice *s)
659 {
660 struct comedi_cmd *cmd = &s->async->cmd;
661 unsigned int status;
662 unsigned int val;
663 int ret;
664
665 status = inw(dev->iobase + PCI171x_STATUS);
666 if (status & Status_FE) {
667 dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
668 s->async->events |= COMEDI_CB_ERROR;
669 return;
670 }
671 if (status & Status_FF) {
672 dev_dbg(dev->class_dev,
673 "A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
674 s->async->events |= COMEDI_CB_ERROR;
675 return;
676 }
677
678 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
679
680 for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
681 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
682 if (ret) {
683 s->async->events |= COMEDI_CB_ERROR;
684 break;
685 }
686
687 comedi_buf_write_samples(s, &val, 1);
688
689 if (cmd->stop_src == TRIG_COUNT &&
690 s->async->scans_done >= cmd->stop_arg) {
691 s->async->events |= COMEDI_CB_EOA;
692 break;
693 }
694 }
695
696 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
697 }
698
699 static void pci1710_handle_fifo(struct comedi_device *dev,
700 struct comedi_subdevice *s)
701 {
702 struct pci1710_private *devpriv = dev->private;
703 struct comedi_async *async = s->async;
704 struct comedi_cmd *cmd = &async->cmd;
705 unsigned int status;
706 int i;
707
708 status = inw(dev->iobase + PCI171x_STATUS);
709 if (!(status & Status_FH)) {
710 dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
711 async->events |= COMEDI_CB_ERROR;
712 return;
713 }
714 if (status & Status_FF) {
715 dev_dbg(dev->class_dev,
716 "A/D FIFO Full status (Fatal Error!)\n");
717 async->events |= COMEDI_CB_ERROR;
718 return;
719 }
720
721 for (i = 0; i < devpriv->max_samples; i++) {
722 unsigned int val;
723 int ret;
724
725 ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
726 if (ret) {
727 s->async->events |= COMEDI_CB_ERROR;
728 break;
729 }
730
731 if (!comedi_buf_write_samples(s, &val, 1))
732 break;
733
734 if (cmd->stop_src == TRIG_COUNT &&
735 async->scans_done >= cmd->stop_arg) {
736 async->events |= COMEDI_CB_EOA;
737 break;
738 }
739 }
740
741 outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
742 }
743
744 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
745 {
746 struct comedi_device *dev = d;
747 struct pci1710_private *devpriv = dev->private;
748 struct comedi_subdevice *s;
749 struct comedi_cmd *cmd;
750
751 if (!dev->attached) /* is device attached? */
752 return IRQ_NONE; /* no, exit */
753
754 s = dev->read_subdev;
755 cmd = &s->async->cmd;
756
757 /* is this interrupt from our board? */
758 if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ))
759 return IRQ_NONE; /* no, exit */
760
761 if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */
762 devpriv->ai_et = 0;
763 devpriv->CntrlReg &= Control_CNT0;
764 devpriv->CntrlReg |= Control_SW; /* set software trigger */
765 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
766 devpriv->CntrlReg = devpriv->ai_et_CntrlReg;
767 outb(0, dev->iobase + PCI171x_CLRFIFO);
768 outb(0, dev->iobase + PCI171x_CLRINT);
769 outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
770 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
771 pci171x_start_pacer(dev, true);
772 return IRQ_HANDLED;
773 }
774
775 if (cmd->flags & CMDF_WAKE_EOS)
776 pci1710_handle_every_sample(dev, s);
777 else
778 pci1710_handle_fifo(dev, s);
779
780 comedi_handle_events(dev, s);
781
782 return IRQ_HANDLED;
783 }
784
785 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
786 {
787 struct pci1710_private *devpriv = dev->private;
788 struct comedi_cmd *cmd = &s->async->cmd;
789
790 pci171x_start_pacer(dev, false);
791
792 pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
793 devpriv->saved_seglen);
794
795 outb(0, dev->iobase + PCI171x_CLRFIFO);
796 outb(0, dev->iobase + PCI171x_CLRINT);
797
798 devpriv->CntrlReg &= Control_CNT0;
799 if ((cmd->flags & CMDF_WAKE_EOS) == 0)
800 devpriv->CntrlReg |= Control_ONEFH;
801
802 devpriv->divisor1 = devpriv->next_divisor1;
803 devpriv->divisor2 = devpriv->next_divisor2;
804
805 if (cmd->convert_src == TRIG_TIMER) {
806 devpriv->CntrlReg |= Control_PACER | Control_IRQEN;
807 if (cmd->start_src == TRIG_EXT) {
808 devpriv->ai_et_CntrlReg = devpriv->CntrlReg;
809 devpriv->CntrlReg &=
810 ~(Control_PACER | Control_ONEFH | Control_GATE);
811 devpriv->CntrlReg |= Control_EXT;
812 devpriv->ai_et = 1;
813 } else { /* TRIG_NOW */
814 devpriv->ai_et = 0;
815 }
816 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
817
818 if (cmd->start_src == TRIG_NOW)
819 pci171x_start_pacer(dev, true);
820 } else { /* TRIG_EXT */
821 devpriv->CntrlReg |= Control_EXT | Control_IRQEN;
822 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
823 }
824
825 return 0;
826 }
827
828 static int pci171x_ai_cmdtest(struct comedi_device *dev,
829 struct comedi_subdevice *s,
830 struct comedi_cmd *cmd)
831 {
832 struct pci1710_private *devpriv = dev->private;
833 int err = 0;
834 unsigned int arg;
835
836 /* Step 1 : check if triggers are trivially valid */
837
838 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
839 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
840 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
841 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
842 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
843
844 if (err)
845 return 1;
846
847 /* step 2a: make sure trigger sources are unique */
848
849 err |= cfc_check_trigger_is_unique(cmd->start_src);
850 err |= cfc_check_trigger_is_unique(cmd->convert_src);
851 err |= cfc_check_trigger_is_unique(cmd->stop_src);
852
853 /* step 2b: and mutually compatible */
854
855 if (err)
856 return 2;
857
858 /* Step 3: check if arguments are trivially valid */
859
860 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
861 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
862
863 if (cmd->convert_src == TRIG_TIMER)
864 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
865 else /* TRIG_FOLLOW */
866 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
867
868 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
869
870 if (cmd->stop_src == TRIG_COUNT)
871 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
872 else /* TRIG_NONE */
873 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
874
875 if (err)
876 return 3;
877
878 /* step 4: fix up any arguments */
879
880 if (cmd->convert_src == TRIG_TIMER) {
881 arg = cmd->convert_arg;
882 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
883 &devpriv->next_divisor1,
884 &devpriv->next_divisor2,
885 &arg, cmd->flags);
886 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
887 }
888
889 if (err)
890 return 4;
891
892 /* Step 5: check channel list */
893
894 err |= pci171x_ai_check_chanlist(dev, s, cmd);
895
896 if (err)
897 return 5;
898
899 return 0;
900 }
901
902 static int pci171x_reset(struct comedi_device *dev)
903 {
904 const struct boardtype *board = dev->board_ptr;
905 struct pci1710_private *devpriv = dev->private;
906
907 outw(0x30, dev->iobase + PCI171x_CNTCTRL);
908 /* Software trigger, CNT0=external */
909 devpriv->CntrlReg = Control_SW | Control_CNT0;
910 /* reset any operations */
911 outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
912 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
913 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
914 pci171x_start_pacer(dev, false);
915 devpriv->da_ranges = 0;
916 if (board->has_ao) {
917 /* set DACs to 0..5V */
918 outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
919 outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
920 outw(0, dev->iobase + PCI171x_DA2);
921 }
922 outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
923 outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
924 outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
925
926 return 0;
927 }
928
929 static int pci1720_reset(struct comedi_device *dev)
930 {
931 struct pci1710_private *devpriv = dev->private;
932 /* set synchronous output mode */
933 outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT);
934 devpriv->da_ranges = 0xAA;
935 /* set all ranges to +/-5V */
936 outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE);
937 outw(0x0800, dev->iobase + PCI1720_DA0); /* set outputs to 0V */
938 outw(0x0800, dev->iobase + PCI1720_DA1);
939 outw(0x0800, dev->iobase + PCI1720_DA2);
940 outw(0x0800, dev->iobase + PCI1720_DA3);
941 outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
942
943 return 0;
944 }
945
946 static int pci1710_reset(struct comedi_device *dev)
947 {
948 const struct boardtype *board = dev->board_ptr;
949
950 if (board->is_pci1720)
951 return pci1720_reset(dev);
952
953 return pci171x_reset(dev);
954 }
955
956 static int pci1710_auto_attach(struct comedi_device *dev,
957 unsigned long context)
958 {
959 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
960 const struct boardtype *board = NULL;
961 struct pci1710_private *devpriv;
962 struct comedi_subdevice *s;
963 int ret, subdev, n_subdevices;
964
965 if (context < ARRAY_SIZE(boardtypes))
966 board = &boardtypes[context];
967 if (!board)
968 return -ENODEV;
969 dev->board_ptr = board;
970 dev->board_name = board->name;
971
972 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
973 if (!devpriv)
974 return -ENOMEM;
975
976 ret = comedi_pci_enable(dev);
977 if (ret)
978 return ret;
979 dev->iobase = pci_resource_start(pcidev, 2);
980
981 n_subdevices = 0;
982 if (board->n_aichan)
983 n_subdevices++;
984 if (board->has_ao)
985 n_subdevices++;
986 if (board->has_di_do)
987 n_subdevices += 2;
988 if (board->has_counter)
989 n_subdevices++;
990
991 ret = comedi_alloc_subdevices(dev, n_subdevices);
992 if (ret)
993 return ret;
994
995 pci1710_reset(dev);
996
997 if (board->has_irq && pcidev->irq) {
998 ret = request_irq(pcidev->irq, interrupt_service_pci1710,
999 IRQF_SHARED, dev->board_name, dev);
1000 if (ret == 0)
1001 dev->irq = pcidev->irq;
1002 }
1003
1004 subdev = 0;
1005
1006 if (board->n_aichan) {
1007 s = &dev->subdevices[subdev];
1008 s->type = COMEDI_SUBD_AI;
1009 s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
1010 if (board->has_diff_ai)
1011 s->subdev_flags |= SDF_DIFF;
1012 s->n_chan = board->n_aichan;
1013 s->maxdata = 0x0fff;
1014 s->range_table = board->rangelist_ai;
1015 s->insn_read = pci171x_ai_insn_read;
1016 if (dev->irq) {
1017 dev->read_subdev = s;
1018 s->subdev_flags |= SDF_CMD_READ;
1019 s->len_chanlist = s->n_chan;
1020 s->do_cmdtest = pci171x_ai_cmdtest;
1021 s->do_cmd = pci171x_ai_cmd;
1022 s->cancel = pci171x_ai_cancel;
1023 }
1024 subdev++;
1025 }
1026
1027 if (board->has_ao) {
1028 s = &dev->subdevices[subdev];
1029 s->type = COMEDI_SUBD_AO;
1030 s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
1031 s->maxdata = 0x0fff;
1032 if (board->is_pci1720) {
1033 s->n_chan = 4;
1034 s->range_table = &pci1720_ao_range;
1035 s->insn_write = pci1720_ao_insn_write;
1036 } else {
1037 s->n_chan = 2;
1038 s->range_table = &pci171x_ao_range;
1039 s->insn_write = pci171x_ao_insn_write;
1040 }
1041
1042 ret = comedi_alloc_subdev_readback(s);
1043 if (ret)
1044 return ret;
1045
1046 /* initialize the readback values to match the board reset */
1047 if (board->is_pci1720) {
1048 int i;
1049
1050 for (i = 0; i < s->n_chan; i++)
1051 s->readback[i] = 0x0800;
1052 }
1053
1054 subdev++;
1055 }
1056
1057 if (board->has_di_do) {
1058 s = &dev->subdevices[subdev];
1059 s->type = COMEDI_SUBD_DI;
1060 s->subdev_flags = SDF_READABLE;
1061 s->n_chan = 16;
1062 s->maxdata = 1;
1063 s->range_table = &range_digital;
1064 s->insn_bits = pci171x_di_insn_bits;
1065 subdev++;
1066
1067 s = &dev->subdevices[subdev];
1068 s->type = COMEDI_SUBD_DO;
1069 s->subdev_flags = SDF_WRITABLE;
1070 s->n_chan = 16;
1071 s->maxdata = 1;
1072 s->range_table = &range_digital;
1073 s->insn_bits = pci171x_do_insn_bits;
1074 subdev++;
1075 }
1076
1077 if (board->has_counter) {
1078 s = &dev->subdevices[subdev];
1079 s->type = COMEDI_SUBD_COUNTER;
1080 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1081 s->n_chan = 1;
1082 s->maxdata = 0xffff;
1083 s->range_table = &range_unknown;
1084 s->insn_read = pci171x_counter_insn_read;
1085 s->insn_write = pci171x_counter_insn_write;
1086 s->insn_config = pci171x_counter_insn_config;
1087 subdev++;
1088 }
1089
1090 /* max_samples is half the FIFO size (2 bytes/sample) */
1091 devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
1092
1093 return 0;
1094 }
1095
1096 static void pci1710_detach(struct comedi_device *dev)
1097 {
1098 if (dev->iobase)
1099 pci1710_reset(dev);
1100 comedi_pci_detach(dev);
1101 }
1102
1103 static struct comedi_driver adv_pci1710_driver = {
1104 .driver_name = "adv_pci1710",
1105 .module = THIS_MODULE,
1106 .auto_attach = pci1710_auto_attach,
1107 .detach = pci1710_detach,
1108 };
1109
1110 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1111 const struct pci_device_id *id)
1112 {
1113 return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1114 id->driver_data);
1115 }
1116
1117 static const struct pci_device_id adv_pci1710_pci_table[] = {
1118 {
1119 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1120 PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1121 .driver_data = BOARD_PCI1710,
1122 }, {
1123 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1124 PCI_VENDOR_ID_ADVANTECH, 0x0000),
1125 .driver_data = BOARD_PCI1710,
1126 }, {
1127 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1128 PCI_VENDOR_ID_ADVANTECH, 0xb100),
1129 .driver_data = BOARD_PCI1710,
1130 }, {
1131 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1132 PCI_VENDOR_ID_ADVANTECH, 0xb200),
1133 .driver_data = BOARD_PCI1710,
1134 }, {
1135 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1136 PCI_VENDOR_ID_ADVANTECH, 0xc100),
1137 .driver_data = BOARD_PCI1710,
1138 }, {
1139 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1140 PCI_VENDOR_ID_ADVANTECH, 0xc200),
1141 .driver_data = BOARD_PCI1710,
1142 }, {
1143 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1144 .driver_data = BOARD_PCI1710,
1145 }, {
1146 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1147 PCI_VENDOR_ID_ADVANTECH, 0x0002),
1148 .driver_data = BOARD_PCI1710HG,
1149 }, {
1150 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1151 PCI_VENDOR_ID_ADVANTECH, 0xb102),
1152 .driver_data = BOARD_PCI1710HG,
1153 }, {
1154 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1155 PCI_VENDOR_ID_ADVANTECH, 0xb202),
1156 .driver_data = BOARD_PCI1710HG,
1157 }, {
1158 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1159 PCI_VENDOR_ID_ADVANTECH, 0xc102),
1160 .driver_data = BOARD_PCI1710HG,
1161 }, {
1162 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1163 PCI_VENDOR_ID_ADVANTECH, 0xc202),
1164 .driver_data = BOARD_PCI1710HG,
1165 }, {
1166 PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1167 .driver_data = BOARD_PCI1710HG,
1168 },
1169 { PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1170 { PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1171 { PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1172 { PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1173 { 0 }
1174 };
1175 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1176
1177 static struct pci_driver adv_pci1710_pci_driver = {
1178 .name = "adv_pci1710",
1179 .id_table = adv_pci1710_pci_table,
1180 .probe = adv_pci1710_pci_probe,
1181 .remove = comedi_pci_auto_unconfig,
1182 };
1183 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1184
1185 MODULE_AUTHOR("Comedi http://www.comedi.org");
1186 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1187 MODULE_LICENSE("GPL");
This page took 0.056051 seconds and 5 git commands to generate.