Version:  2.0.40 2.2.26 2.4.37 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7

Linux/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_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 int *val)
303 {
304         const struct boardtype *board = dev->board_ptr;
305         struct pci1710_private *devpriv = dev->private;
306         unsigned int 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 int 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 int 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 int 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");
963 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us