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