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