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