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