a1279c24afb949a06e31269a89deb9ea84a5da25
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / pcl818.c
1 /*
2    comedi/drivers/pcl818.c
3
4    Author:  Michal Dobes <dobes@tesnet.cz>
5
6    hardware driver for Advantech cards:
7     card:   PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
8     driver: pcl818l,  pcl818h,  pcl818hd,  pcl818hg,  pcl818,  pcl718
9 */
10 /*
11 Driver: pcl818
12 Description: Advantech PCL-818 cards, PCL-718
13 Author: Michal Dobes <dobes@tesnet.cz>
14 Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
15   PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
16   PCL-718 (pcl718)
17 Status: works
18
19 All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
20 Differences are only at maximal sample speed, range list and FIFO
21 support.
22 The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
23 only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
24 PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
25 but this code is untested.
26 A word or two about DMA. Driver support DMA operations at two ways:
27 1) DMA uses two buffers and after one is filled then is generated
28    INT and DMA restart with second buffer. With this mode I'm unable run
29    more that 80Ksamples/secs without data dropouts on K6/233.
30 2) DMA uses one buffer and run in autoinit mode and the data are
31    from DMA buffer moved on the fly with 2kHz interrupts from RTC.
32    This mode is used if the interrupt 8 is available for allocation.
33    If not, then first DMA mode is used. With this I can run at
34    full speed one card (100ksamples/secs) or two cards with
35    60ksamples/secs each (more is problem on account of ISA limitations).
36    To use this mode you must have compiled  kernel with disabled
37    "Enhanced Real Time Clock Support".
38    Maybe you can have problems if you use xntpd or similar.
39    If you've data dropouts with DMA mode 2 then:
40     a) disable IDE DMA
41     b) switch text mode console to fb.
42
43    Options for PCL-818L:
44     [0] - IO Base
45     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
46     [2] - DMA   (0=disable, 1, 3)
47     [3] - 0, 10=10MHz clock for 8254
48               1= 1MHz clock for 8254
49     [4] - 0,  5=A/D input  -5V.. +5V
50           1, 10=A/D input -10V..+10V
51     [5] - 0,  5=D/A output 0-5V  (internal reference -5V)
52           1, 10=D/A output 0-10V (internal reference -10V)
53           2    =D/A output unknown (external reference)
54
55    Options for PCL-818, PCL-818H:
56     [0] - IO Base
57     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
58     [2] - DMA   (0=disable, 1, 3)
59     [3] - 0, 10=10MHz clock for 8254
60               1= 1MHz clock for 8254
61     [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
62           1, 10=D/A output 0-10V (internal reference -10V)
63           2    =D/A output unknown (external reference)
64
65    Options for PCL-818HD, PCL-818HG:
66     [0] - IO Base
67     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
68     [2] - DMA/FIFO  (-1=use FIFO, 0=disable both FIFO and DMA,
69                       1=use DMA ch 1, 3=use DMA ch 3)
70     [3] - 0, 10=10MHz clock for 8254
71               1= 1MHz clock for 8254
72     [4] - 0,  5=D/A output 0-5V  (internal reference -5V)
73           1, 10=D/A output 0-10V (internal reference -10V)
74           2    =D/A output unknown (external reference)
75
76    Options for PCL-718:
77     [0] - IO Base
78     [1] - IRQ   (0=disable, 2, 3, 4, 5, 6, 7)
79     [2] - DMA   (0=disable, 1, 3)
80     [3] - 0, 10=10MHz clock for 8254
81               1= 1MHz clock for 8254
82     [4] -     0=A/D Range is +/-10V
83               1=             +/-5V
84               2=             +/-2.5V
85               3=             +/-1V
86               4=             +/-0.5V
87               5=             user defined bipolar
88               6=             0-10V
89               7=             0-5V
90               8=             0-2V
91               9=             0-1V
92              10=             user defined unipolar
93     [5] - 0,  5=D/A outputs 0-5V  (internal reference -5V)
94           1, 10=D/A outputs 0-10V (internal reference -10V)
95               2=D/A outputs unknown (external reference)
96     [6] - 0, 60=max  60kHz A/D sampling
97           1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
98
99 */
100
101 #include <linux/module.h>
102 #include <linux/gfp.h>
103 #include <linux/delay.h>
104 #include <linux/io.h>
105 #include <linux/interrupt.h>
106 #include <asm/dma.h>
107
108 #include "../comedidev.h"
109
110 #include "comedi_fc.h"
111 #include "8253.h"
112
113 /* boards constants */
114
115 #define boardPCL818L 0
116 #define boardPCL818H 1
117 #define boardPCL818HD 2
118 #define boardPCL818HG 3
119 #define boardPCL818 4
120 #define boardPCL718 5
121
122 /*
123  * Register I/O map
124  */
125 #define PCL818_AI_LSB_REG                       0x00
126 #define PCL818_AI_MSB_REG                       0x01
127 #define PCL818_RANGE_REG                        0x01
128 #define PCL818_MUX_REG                          0x02
129 #define PCL818_MUX_SCAN(_first, _last)          (((_last) << 4) | (_first))
130 #define PCL818_DO_DI_LSB_REG                    0x03
131 #define PCL818_AO_LSB_REG(x)                    (0x04 + ((x) * 2))
132 #define PCL818_AO_MSB_REG(x)                    (0x05 + ((x) * 2))
133 #define PCL818_STATUS_REG                       0x08
134 #define PCL818_STATUS_NEXT_CHAN_MASK            (0xf << 0)
135 #define PCL818_STATUS_INT                       (1 << 4)
136 #define PCL818_STATUS_MUX                       (1 << 5)
137 #define PCL818_STATUS_UNI                       (1 << 6)
138 #define PCL818_STATUS_EOC                       (1 << 7)
139 #define PCL818_CTRL_REG                         0x09
140 #define PCL818_CTRL_DISABLE_TRIG                (0 << 0)
141 #define PCL818_CTRL_SOFT_TRIG                   (1 << 0)
142 #define PCL818_CTRL_EXT_TRIG                    (2 << 0)
143 #define PCL818_CTRL_PACER_TRIG                  (3 << 0)
144 #define PCL818_CTRL_DMAE                        (1 << 2)
145 #define PCL818_CTRL_IRQ(x)                      ((x) << 4)
146 #define PCL818_CTRL_INTE                        (1 << 7)
147 #define PCL818_CNTENABLE_REG                    0x0a
148 #define PCL818_CNTENABLE_PACER_ENA              (0 << 0)
149 #define PCL818_CNTENABLE_PACER_TRIG0            (1 << 0)
150 #define PCL818_CNTENABLE_CNT0_EXT_CLK           (0 << 1)
151 #define PCL818_CNTENABLE_CNT0_INT_CLK           (1 << 1)
152 #define PCL818_DO_DI_MSB_REG                    0x0b
153 #define PCL818_TIMER_BASE                       0x0c
154
155 /* W: fifo enable/disable */
156 #define PCL818_FI_ENABLE 6
157 /* W: fifo interrupt clear */
158 #define PCL818_FI_INTCLR 20
159 /* W: fifo interrupt clear */
160 #define PCL818_FI_FLUSH 25
161 /* R: fifo status */
162 #define PCL818_FI_STATUS 25
163 /* R: one record from FIFO */
164 #define PCL818_FI_DATALO 23
165 #define PCL818_FI_DATAHI 24
166
167 #define MAGIC_DMA_WORD 0x5a5a
168
169 static const struct comedi_lrange range_pcl818h_ai = {
170         9, {
171                 BIP_RANGE(5),
172                 BIP_RANGE(2.5),
173                 BIP_RANGE(1.25),
174                 BIP_RANGE(0.625),
175                 UNI_RANGE(10),
176                 UNI_RANGE(5),
177                 UNI_RANGE(2.5),
178                 UNI_RANGE(1.25),
179                 BIP_RANGE(10)
180         }
181 };
182
183 static const struct comedi_lrange range_pcl818hg_ai = {
184         10, {
185                 BIP_RANGE(5),
186                 BIP_RANGE(0.5),
187                 BIP_RANGE(0.05),
188                 BIP_RANGE(0.005),
189                 UNI_RANGE(10),
190                 UNI_RANGE(1),
191                 UNI_RANGE(0.1),
192                 UNI_RANGE(0.01),
193                 BIP_RANGE(10),
194                 BIP_RANGE(1),
195                 BIP_RANGE(0.1),
196                 BIP_RANGE(0.01)
197         }
198 };
199
200 static const struct comedi_lrange range_pcl818l_l_ai = {
201         4, {
202                 BIP_RANGE(5),
203                 BIP_RANGE(2.5),
204                 BIP_RANGE(1.25),
205                 BIP_RANGE(0.625)
206         }
207 };
208
209 static const struct comedi_lrange range_pcl818l_h_ai = {
210         4, {
211                 BIP_RANGE(10),
212                 BIP_RANGE(5),
213                 BIP_RANGE(2.5),
214                 BIP_RANGE(1.25)
215         }
216 };
217
218 static const struct comedi_lrange range718_bipolar1 = {
219         1, {
220                 BIP_RANGE(1)
221         }
222 };
223
224 static const struct comedi_lrange range718_bipolar0_5 = {
225         1, {
226                 BIP_RANGE(0.5)
227         }
228 };
229
230 static const struct comedi_lrange range718_unipolar2 = {
231         1, {
232                 UNI_RANGE(2)
233         }
234 };
235
236 static const struct comedi_lrange range718_unipolar1 = {
237         1, {
238                 BIP_RANGE(1)
239         }
240 };
241
242 struct pcl818_board {
243         const char *name;
244         unsigned int ns_min;
245         int n_aochan;
246         const struct comedi_lrange *ai_range_type;
247         unsigned int has_dma:1;
248         unsigned int has_fifo:1;
249         unsigned int is_818:1;
250 };
251
252 static const struct pcl818_board boardtypes[] = {
253         {
254                 .name           = "pcl818l",
255                 .ns_min         = 25000,
256                 .n_aochan       = 1,
257                 .ai_range_type  = &range_pcl818l_l_ai,
258                 .has_dma        = 1,
259                 .is_818         = 1,
260         }, {
261                 .name           = "pcl818h",
262                 .ns_min         = 10000,
263                 .n_aochan       = 1,
264                 .ai_range_type  = &range_pcl818h_ai,
265                 .has_dma        = 1,
266                 .is_818         = 1,
267         }, {
268                 .name           = "pcl818hd",
269                 .ns_min         = 10000,
270                 .n_aochan       = 1,
271                 .ai_range_type  = &range_pcl818h_ai,
272                 .has_dma        = 1,
273                 .has_fifo       = 1,
274                 .is_818         = 1,
275         }, {
276                 .name           = "pcl818hg",
277                 .ns_min         = 10000,
278                 .n_aochan       = 1,
279                 .ai_range_type  = &range_pcl818hg_ai,
280                 .has_dma        = 1,
281                 .has_fifo       = 1,
282                 .is_818         = 1,
283         }, {
284                 .name           = "pcl818",
285                 .ns_min         = 10000,
286                 .n_aochan       = 2,
287                 .ai_range_type  = &range_pcl818h_ai,
288                 .has_dma        = 1,
289                 .is_818         = 1,
290         }, {
291                 .name           = "pcl718",
292                 .ns_min         = 16000,
293                 .n_aochan       = 2,
294                 .ai_range_type  = &range_unipolar5,
295                 .has_dma        = 1,
296         }, {
297                 .name           = "pcm3718",
298                 .ns_min         = 10000,
299                 .ai_range_type  = &range_pcl818h_ai,
300                 .has_dma        = 1,
301                 .is_818         = 1,
302         },
303 };
304
305 struct pcl818_dma_desc {
306         void *virt_addr;        /* virtual address of DMA buffer */
307         dma_addr_t hw_addr;     /* hardware (bus) address of DMA buffer */
308         unsigned int size;      /* transfer size (in bytes) */
309 };
310
311 struct pcl818_private {
312         unsigned int dma;       /*  used DMA, 0=don't use DMA */
313         unsigned int hwdmasize;
314         struct pcl818_dma_desc dma_desc[2];
315         int cur_dma;
316         long dma_runs_to_end;   /*  how many we must permorm DMA transfer to end of record */
317         unsigned long last_dma_run;     /*  how many bytes we must transfer on last DMA page */
318         unsigned int ns_min;    /*  manimal allowed delay between samples (in us) for actual card */
319         int i8253_osc_base;     /*  1/frequency of on board oscilator in ns */
320         unsigned int act_chanlist[16];  /*  MUX setting for actual AI operations */
321         unsigned int act_chanlist_len;  /*  how long is actual MUX list */
322         unsigned int act_chanlist_pos;  /*  actual position in MUX list */
323         unsigned int ai_data_len;       /*  len of data buffer */
324         unsigned int divisor1;
325         unsigned int divisor2;
326         unsigned int usefifo:1;
327         unsigned int ai_cmd_running:1;
328         unsigned int ai_cmd_canceled:1;
329 };
330
331 static void pcl818_isadma_program(unsigned int dma_chan,
332                                   struct pcl818_dma_desc *dma)
333 {
334         unsigned long flags;
335
336         flags = claim_dma_lock();
337         clear_dma_ff(dma_chan);
338         set_dma_mode(dma_chan, DMA_MODE_READ);
339         set_dma_addr(dma_chan, dma->hw_addr);
340         set_dma_count(dma_chan, dma->size);
341         enable_dma(dma_chan);
342         release_dma_lock(flags);
343 }
344
345 static void pcl818_isadma_disable(unsigned int dma_chan)
346 {
347         unsigned long flags;
348
349         flags = claim_dma_lock();
350         disable_dma(dma_chan);
351         release_dma_lock(flags);
352 }
353
354 static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters)
355 {
356         struct pcl818_private *devpriv = dev->private;
357         unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
358
359         i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
360         i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
361         udelay(1);
362
363         if (load_counters) {
364                 i8254_write(timer_base, 0, 2, devpriv->divisor2);
365                 i8254_write(timer_base, 0, 1, devpriv->divisor1);
366         }
367 }
368
369 static void pcl818_ai_setup_dma(struct comedi_device *dev,
370                                 struct comedi_subdevice *s)
371 {
372         struct pcl818_private *devpriv = dev->private;
373         struct pcl818_dma_desc *dma = &devpriv->dma_desc[0];
374         struct comedi_cmd *cmd = &s->async->cmd;
375
376         pcl818_isadma_disable(devpriv->dma);
377         if (cmd->stop_src == TRIG_COUNT) {
378                 dma->size = cmd->stop_arg * comedi_bytes_per_scan(s);
379                 devpriv->dma_runs_to_end = dma->size / devpriv->hwdmasize;
380                 devpriv->last_dma_run = dma->size % devpriv->hwdmasize;
381                 devpriv->dma_runs_to_end--;
382                 if (devpriv->dma_runs_to_end >= 0)
383                         dma->size = devpriv->hwdmasize;
384         } else {
385                 dma->size = devpriv->hwdmasize;
386         }
387
388         devpriv->cur_dma = 0;
389
390         pcl818_isadma_program(devpriv->dma, dma);
391 }
392
393 static void pcl818_ai_setup_next_dma(struct comedi_device *dev,
394                                      struct comedi_subdevice *s)
395 {
396         struct pcl818_private *devpriv = dev->private;
397         struct comedi_cmd *cmd = &s->async->cmd;
398         struct pcl818_dma_desc *dma;
399
400         pcl818_isadma_disable(devpriv->dma);
401         devpriv->cur_dma = 1 - devpriv->cur_dma;
402         if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
403                 /* switch dma bufs */
404                 dma = &devpriv->dma_desc[devpriv->cur_dma];
405                 if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
406                         dma->size = devpriv->hwdmasize;
407                 else
408                         dma->size = devpriv->last_dma_run;
409
410                 pcl818_isadma_program(devpriv->dma, dma);
411         }
412
413         devpriv->dma_runs_to_end--;
414 }
415
416 static void pcl818_ai_set_chan_range(struct comedi_device *dev,
417                                      unsigned int chan,
418                                      unsigned int range)
419 {
420         outb(chan, dev->iobase + PCL818_MUX_REG);
421         outb(range, dev->iobase + PCL818_RANGE_REG);
422 }
423
424 static void pcl818_ai_set_chan_scan(struct comedi_device *dev,
425                                     unsigned int first_chan,
426                                     unsigned int last_chan)
427 {
428         outb(PCL818_MUX_SCAN(first_chan, last_chan),
429              dev->iobase + PCL818_MUX_REG);
430 }
431
432 static void pcl818_ai_setup_chanlist(struct comedi_device *dev,
433                                      unsigned int *chanlist,
434                                      unsigned int seglen)
435 {
436         struct pcl818_private *devpriv = dev->private;
437         unsigned int first_chan = CR_CHAN(chanlist[0]);
438         unsigned int last_chan;
439         unsigned int range;
440         int i;
441
442         devpriv->act_chanlist_len = seglen;
443         devpriv->act_chanlist_pos = 0;
444
445         /* store range list to card */
446         for (i = 0; i < seglen; i++) {
447                 last_chan = CR_CHAN(chanlist[i]);
448                 range = CR_RANGE(chanlist[i]);
449
450                 devpriv->act_chanlist[i] = last_chan;
451
452                 pcl818_ai_set_chan_range(dev, last_chan, range);
453         }
454
455         udelay(1);
456
457         pcl818_ai_set_chan_scan(dev, first_chan, last_chan);
458 }
459
460 static void pcl818_ai_clear_eoc(struct comedi_device *dev)
461 {
462         /* writing any value clears the interrupt request */
463         outb(0, dev->iobase + PCL818_STATUS_REG);
464 }
465
466 static void pcl818_ai_soft_trig(struct comedi_device *dev)
467 {
468         /* writing any value triggers a software conversion */
469         outb(0, dev->iobase + PCL818_AI_LSB_REG);
470 }
471
472 static unsigned int pcl818_ai_get_fifo_sample(struct comedi_device *dev,
473                                               struct comedi_subdevice *s,
474                                               unsigned int *chan)
475 {
476         unsigned int val;
477
478         val = inb(dev->iobase + PCL818_FI_DATALO);
479         val |= (inb(dev->iobase + PCL818_FI_DATAHI) << 8);
480
481         if (chan)
482                 *chan = val & 0xf;
483
484         return (val >> 4) & s->maxdata;
485 }
486
487 static unsigned int pcl818_ai_get_sample(struct comedi_device *dev,
488                                          struct comedi_subdevice *s,
489                                          unsigned int *chan)
490 {
491         unsigned int val;
492
493         val = inb(dev->iobase + PCL818_AI_MSB_REG) << 8;
494         val |= inb(dev->iobase + PCL818_AI_LSB_REG);
495
496         if (chan)
497                 *chan = val & 0xf;
498
499         return (val >> 4) & s->maxdata;
500 }
501
502 static int pcl818_ai_eoc(struct comedi_device *dev,
503                          struct comedi_subdevice *s,
504                          struct comedi_insn *insn,
505                          unsigned long context)
506 {
507         unsigned int status;
508
509         status = inb(dev->iobase + PCL818_STATUS_REG);
510         if (status & PCL818_STATUS_INT)
511                 return 0;
512         return -EBUSY;
513 }
514
515 static bool pcl818_ai_dropout(struct comedi_device *dev,
516                               struct comedi_subdevice *s,
517                               unsigned int chan)
518 {
519         struct pcl818_private *devpriv = dev->private;
520         unsigned int expected_chan;
521
522         expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
523         if (chan != expected_chan) {
524                 dev_dbg(dev->class_dev,
525                         "A/D mode1/3 %s - channel dropout %d!=%d !\n",
526                         (devpriv->dma) ? "DMA" :
527                         (devpriv->usefifo) ? "FIFO" : "IRQ",
528                         chan, expected_chan);
529                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
530                 return true;
531         }
532         return false;
533 }
534
535 static bool pcl818_ai_next_chan(struct comedi_device *dev,
536                                 struct comedi_subdevice *s)
537 {
538         struct pcl818_private *devpriv = dev->private;
539         struct comedi_cmd *cmd = &s->async->cmd;
540
541         devpriv->act_chanlist_pos++;
542         if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
543                 devpriv->act_chanlist_pos = 0;
544
545         if (cmd->stop_src == TRIG_COUNT &&
546             s->async->scans_done >= cmd->stop_arg) {
547                 s->async->events |= COMEDI_CB_EOA;
548                 return false;
549         }
550
551         return true;
552 }
553
554 static void pcl818_handle_eoc(struct comedi_device *dev,
555                               struct comedi_subdevice *s)
556 {
557         unsigned int chan;
558         unsigned int val;
559
560         if (pcl818_ai_eoc(dev, s, NULL, 0)) {
561                 dev_err(dev->class_dev, "A/D mode1/3 IRQ without DRDY!\n");
562                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
563                 return;
564         }
565
566         val = pcl818_ai_get_sample(dev, s, &chan);
567
568         if (pcl818_ai_dropout(dev, s, chan))
569                 return;
570
571         comedi_buf_write_samples(s, &val, 1);
572
573         pcl818_ai_next_chan(dev, s);
574 }
575
576 static void pcl818_handle_dma(struct comedi_device *dev,
577                               struct comedi_subdevice *s)
578 {
579         struct pcl818_private *devpriv = dev->private;
580         struct pcl818_dma_desc *dma = &devpriv->dma_desc[devpriv->cur_dma];
581         unsigned short *ptr = dma->virt_addr;
582         unsigned int nsamples = comedi_bytes_to_samples(s, dma->size);
583         unsigned int chan;
584         unsigned int val;
585         int i;
586
587         pcl818_ai_setup_next_dma(dev, s);
588
589         for (i = 0; i < nsamples; i++) {
590                 val = ptr[i];
591                 chan = val & 0xf;
592                 val = (val >> 4) & s->maxdata;
593
594                 if (pcl818_ai_dropout(dev, s, chan))
595                         break;
596
597                 comedi_buf_write_samples(s, &val, 1);
598
599                 if (!pcl818_ai_next_chan(dev, s))
600                         break;
601         }
602 }
603
604 static void pcl818_handle_fifo(struct comedi_device *dev,
605                                struct comedi_subdevice *s)
606 {
607         unsigned int status;
608         unsigned int chan;
609         unsigned int val;
610         int i, len;
611
612         status = inb(dev->iobase + PCL818_FI_STATUS);
613
614         if (status & 4) {
615                 dev_err(dev->class_dev, "A/D mode1/3 FIFO overflow!\n");
616                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
617                 return;
618         }
619
620         if (status & 1) {
621                 dev_err(dev->class_dev,
622                         "A/D mode1/3 FIFO interrupt without data!\n");
623                 s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
624                 return;
625         }
626
627         if (status & 2)
628                 len = 512;
629         else
630                 len = 0;
631
632         for (i = 0; i < len; i++) {
633                 val = pcl818_ai_get_fifo_sample(dev, s, &chan);
634
635                 if (pcl818_ai_dropout(dev, s, chan))
636                         break;
637
638                 comedi_buf_write_samples(s, &val, 1);
639
640                 if (!pcl818_ai_next_chan(dev, s))
641                         break;
642         }
643 }
644
645 static irqreturn_t pcl818_interrupt(int irq, void *d)
646 {
647         struct comedi_device *dev = d;
648         struct pcl818_private *devpriv = dev->private;
649         struct comedi_subdevice *s = dev->read_subdev;
650         struct comedi_cmd *cmd = &s->async->cmd;
651
652         if (!dev->attached || !devpriv->ai_cmd_running) {
653                 pcl818_ai_clear_eoc(dev);
654                 return IRQ_HANDLED;
655         }
656
657         if (devpriv->ai_cmd_canceled) {
658                 /*
659                  * The cleanup from ai_cancel() has been delayed
660                  * until now because the card doesn't seem to like
661                  * being reprogrammed while a DMA transfer is in
662                  * progress.
663                  */
664                 s->async->scans_done = cmd->stop_arg;
665                 s->cancel(dev, s);
666                 return IRQ_HANDLED;
667         }
668
669         if (devpriv->dma)
670                 pcl818_handle_dma(dev, s);
671         else if (devpriv->usefifo)
672                 pcl818_handle_fifo(dev, s);
673         else
674                 pcl818_handle_eoc(dev, s);
675
676         pcl818_ai_clear_eoc(dev);
677
678         comedi_handle_events(dev, s);
679         return IRQ_HANDLED;
680 }
681
682 static int check_channel_list(struct comedi_device *dev,
683                               struct comedi_subdevice *s,
684                               unsigned int *chanlist, unsigned int n_chan)
685 {
686         unsigned int chansegment[16];
687         unsigned int i, nowmustbechan, seglen, segpos;
688
689         /* correct channel and range number check itself comedi/range.c */
690         if (n_chan < 1) {
691                 dev_err(dev->class_dev, "range/channel list is empty!\n");
692                 return 0;
693         }
694
695         if (n_chan > 1) {
696                 /*  first channel is every time ok */
697                 chansegment[0] = chanlist[0];
698                 /*  build part of chanlist */
699                 for (i = 1, seglen = 1; i < n_chan; i++, seglen++) {
700                         /* we detect loop, this must by finish */
701
702                         if (chanlist[0] == chanlist[i])
703                                 break;
704                         nowmustbechan =
705                             (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
706                         if (nowmustbechan != CR_CHAN(chanlist[i])) {    /*  channel list isn't continuous :-( */
707                                 dev_dbg(dev->class_dev,
708                                         "channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
709                                         i, CR_CHAN(chanlist[i]), nowmustbechan,
710                                         CR_CHAN(chanlist[0]));
711                                 return 0;
712                         }
713                         /*  well, this is next correct channel in list */
714                         chansegment[i] = chanlist[i];
715                 }
716
717                 /*  check whole chanlist */
718                 for (i = 0, segpos = 0; i < n_chan; i++) {
719                         if (chanlist[i] != chansegment[i % seglen]) {
720                                 dev_dbg(dev->class_dev,
721                                         "bad channel or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
722                                         i, CR_CHAN(chansegment[i]),
723                                         CR_RANGE(chansegment[i]),
724                                         CR_AREF(chansegment[i]),
725                                         CR_CHAN(chanlist[i % seglen]),
726                                         CR_RANGE(chanlist[i % seglen]),
727                                         CR_AREF(chansegment[i % seglen]));
728                                 return 0;       /*  chan/gain list is strange */
729                         }
730                 }
731         } else {
732                 seglen = 1;
733         }
734         return seglen;
735 }
736
737 static int check_single_ended(unsigned int port)
738 {
739         if (inb(port + PCL818_STATUS_REG) & PCL818_STATUS_MUX)
740                 return 1;
741         return 0;
742 }
743
744 static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
745                       struct comedi_cmd *cmd)
746 {
747         const struct pcl818_board *board = dev->board_ptr;
748         struct pcl818_private *devpriv = dev->private;
749         int err = 0;
750         unsigned int arg;
751
752         /* Step 1 : check if triggers are trivially valid */
753
754         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
755         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
756         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
757         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
758         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
759
760         if (err)
761                 return 1;
762
763         /* Step 2a : make sure trigger sources are unique */
764
765         err |= cfc_check_trigger_is_unique(cmd->convert_src);
766         err |= cfc_check_trigger_is_unique(cmd->stop_src);
767
768         /* Step 2b : and mutually compatible */
769
770         if (err)
771                 return 2;
772
773         /* Step 3: check if arguments are trivially valid */
774
775         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
776         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
777
778         if (cmd->convert_src == TRIG_TIMER)
779                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
780                                                  board->ns_min);
781         else    /* TRIG_EXT */
782                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
783
784         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
785
786         if (cmd->stop_src == TRIG_COUNT)
787                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
788         else    /* TRIG_NONE */
789                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
790
791         if (err)
792                 return 3;
793
794         /* step 4: fix up any arguments */
795
796         if (cmd->convert_src == TRIG_TIMER) {
797                 arg = cmd->convert_arg;
798                 i8253_cascade_ns_to_timer(devpriv->i8253_osc_base,
799                                           &devpriv->divisor1,
800                                           &devpriv->divisor2,
801                                           &arg, cmd->flags);
802                 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
803         }
804
805         if (err)
806                 return 4;
807
808         /* step 5: complain about special chanlist considerations */
809
810         if (cmd->chanlist) {
811                 if (!check_channel_list(dev, s, cmd->chanlist,
812                                         cmd->chanlist_len))
813                         return 5;       /*  incorrect channels list */
814         }
815
816         return 0;
817 }
818
819 static int pcl818_ai_cmd(struct comedi_device *dev,
820                          struct comedi_subdevice *s)
821 {
822         struct pcl818_private *devpriv = dev->private;
823         struct comedi_cmd *cmd = &s->async->cmd;
824         unsigned int ctrl = 0;
825         unsigned int seglen;
826
827         if (devpriv->ai_cmd_running)
828                 return -EBUSY;
829
830         pcl818_start_pacer(dev, false);
831
832         seglen = check_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len);
833         if (seglen < 1)
834                 return -EINVAL;
835         pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
836
837         devpriv->ai_data_len = s->async->prealloc_bufsz;
838         devpriv->ai_cmd_running = 1;
839         devpriv->ai_cmd_canceled = 0;
840         devpriv->act_chanlist_pos = 0;
841         devpriv->dma_runs_to_end = 0;
842
843         if (cmd->convert_src == TRIG_TIMER)
844                 ctrl |= PCL818_CTRL_PACER_TRIG;
845         else
846                 ctrl |= PCL818_CTRL_EXT_TRIG;
847
848         outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
849
850         if (devpriv->dma) {
851                 pcl818_ai_setup_dma(dev, s);
852
853                 ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) |
854                         PCL818_CTRL_DMAE;
855         } else if (devpriv->usefifo) {
856                 /* enable FIFO */
857                 outb(1, dev->iobase + PCL818_FI_ENABLE);
858         } else {
859                 ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq);
860         }
861         outb(ctrl, dev->iobase + PCL818_CTRL_REG);
862
863         if (cmd->convert_src == TRIG_TIMER)
864                 pcl818_start_pacer(dev, true);
865
866         return 0;
867 }
868
869 static int pcl818_ai_cancel(struct comedi_device *dev,
870                             struct comedi_subdevice *s)
871 {
872         struct pcl818_private *devpriv = dev->private;
873         struct comedi_cmd *cmd = &s->async->cmd;
874
875         if (!devpriv->ai_cmd_running)
876                 return 0;
877
878         if (devpriv->dma) {
879                 if (cmd->stop_src == TRIG_NONE ||
880                     (cmd->stop_src == TRIG_COUNT &&
881                      s->async->scans_done < cmd->stop_arg)) {
882                         if (!devpriv->ai_cmd_canceled) {
883                                 /*
884                                 * Wait for running dma transfer to end,
885                                 * do cleanup in interrupt.
886                                 */
887                                 devpriv->ai_cmd_canceled = 1;
888                                 return 0;
889                         }
890                 }
891                 pcl818_isadma_disable(devpriv->dma);
892         }
893
894         outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
895         pcl818_start_pacer(dev, false);
896         pcl818_ai_clear_eoc(dev);
897
898         if (devpriv->usefifo) { /*  FIFO shutdown */
899                 outb(0, dev->iobase + PCL818_FI_INTCLR);
900                 outb(0, dev->iobase + PCL818_FI_FLUSH);
901                 outb(0, dev->iobase + PCL818_FI_ENABLE);
902         }
903         devpriv->ai_cmd_running = 0;
904         devpriv->ai_cmd_canceled = 0;
905
906         return 0;
907 }
908
909 static int pcl818_ai_insn_read(struct comedi_device *dev,
910                                struct comedi_subdevice *s,
911                                struct comedi_insn *insn,
912                                unsigned int *data)
913 {
914         unsigned int chan = CR_CHAN(insn->chanspec);
915         unsigned int range = CR_RANGE(insn->chanspec);
916         int ret = 0;
917         int i;
918
919         outb(PCL818_CTRL_SOFT_TRIG, dev->iobase + PCL818_CTRL_REG);
920
921         pcl818_ai_set_chan_range(dev, chan, range);
922         pcl818_ai_set_chan_scan(dev, chan, chan);
923
924         for (i = 0; i < insn->n; i++) {
925                 pcl818_ai_clear_eoc(dev);
926                 pcl818_ai_soft_trig(dev);
927
928                 ret = comedi_timeout(dev, s, insn, pcl818_ai_eoc, 0);
929                 if (ret)
930                         break;
931
932                 data[i] = pcl818_ai_get_sample(dev, s, NULL);
933         }
934         pcl818_ai_clear_eoc(dev);
935
936         return ret ? ret : insn->n;
937 }
938
939 static int pcl818_ao_insn_write(struct comedi_device *dev,
940                                 struct comedi_subdevice *s,
941                                 struct comedi_insn *insn,
942                                 unsigned int *data)
943 {
944         unsigned int chan = CR_CHAN(insn->chanspec);
945         unsigned int val = s->readback[chan];
946         int i;
947
948         for (i = 0; i < insn->n; i++) {
949                 val = data[i];
950                 outb((val & 0x000f) << 4,
951                      dev->iobase + PCL818_AO_LSB_REG(chan));
952                 outb((val & 0x0ff0) >> 4,
953                      dev->iobase + PCL818_AO_MSB_REG(chan));
954         }
955         s->readback[chan] = val;
956
957         return insn->n;
958 }
959
960 static int pcl818_di_insn_bits(struct comedi_device *dev,
961                                struct comedi_subdevice *s,
962                                struct comedi_insn *insn,
963                                unsigned int *data)
964 {
965         data[1] = inb(dev->iobase + PCL818_DO_DI_LSB_REG) |
966                   (inb(dev->iobase + PCL818_DO_DI_MSB_REG) << 8);
967
968         return insn->n;
969 }
970
971 static int pcl818_do_insn_bits(struct comedi_device *dev,
972                                struct comedi_subdevice *s,
973                                struct comedi_insn *insn,
974                                unsigned int *data)
975 {
976         if (comedi_dio_update_state(s, data)) {
977                 outb(s->state & 0xff, dev->iobase + PCL818_DO_DI_LSB_REG);
978                 outb((s->state >> 8), dev->iobase + PCL818_DO_DI_MSB_REG);
979         }
980
981         data[1] = s->state;
982
983         return insn->n;
984 }
985
986 static void pcl818_reset(struct comedi_device *dev)
987 {
988         const struct pcl818_board *board = dev->board_ptr;
989         unsigned long timer_base = dev->iobase + PCL818_TIMER_BASE;
990         unsigned int chan;
991
992         /* flush and disable the FIFO */
993         if (board->has_fifo) {
994                 outb(0, dev->iobase + PCL818_FI_INTCLR);
995                 outb(0, dev->iobase + PCL818_FI_FLUSH);
996                 outb(0, dev->iobase + PCL818_FI_ENABLE);
997         }
998
999         /* disable analog input trigger */
1000         outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
1001         pcl818_ai_clear_eoc(dev);
1002
1003         pcl818_ai_set_chan_range(dev, 0, 0);
1004
1005         /* stop pacer */
1006         outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
1007         i8254_set_mode(timer_base, 0, 2, I8254_MODE0 | I8254_BINARY);
1008         i8254_set_mode(timer_base, 0, 1, I8254_MODE0 | I8254_BINARY);
1009         i8254_set_mode(timer_base, 0, 0, I8254_MODE0 | I8254_BINARY);
1010
1011         /* set analog output channels to 0V */
1012         for (chan = 0; chan < board->n_aochan; chan++) {
1013                 outb(0, dev->iobase + PCL818_AO_LSB_REG(chan));
1014                 outb(0, dev->iobase + PCL818_AO_MSB_REG(chan));
1015         }
1016
1017         /* set all digital outputs low */
1018         outb(0, dev->iobase + PCL818_DO_DI_MSB_REG);
1019         outb(0, dev->iobase + PCL818_DO_DI_LSB_REG);
1020 }
1021
1022 static void pcl818_set_ai_range_table(struct comedi_device *dev,
1023                                       struct comedi_subdevice *s,
1024                                       struct comedi_devconfig *it)
1025 {
1026         const struct pcl818_board *board = dev->board_ptr;
1027
1028         /* default to the range table from the boardinfo */
1029         s->range_table = board->ai_range_type;
1030
1031         /* now check the user config option based on the boardtype */
1032         if (board->is_818) {
1033                 if (it->options[4] == 1 || it->options[4] == 10) {
1034                         /* secondary range list jumper selectable */
1035                         s->range_table = &range_pcl818l_h_ai;
1036                 }
1037         } else {
1038                 switch (it->options[4]) {
1039                 case 0:
1040                         s->range_table = &range_bipolar10;
1041                         break;
1042                 case 1:
1043                         s->range_table = &range_bipolar5;
1044                         break;
1045                 case 2:
1046                         s->range_table = &range_bipolar2_5;
1047                         break;
1048                 case 3:
1049                         s->range_table = &range718_bipolar1;
1050                         break;
1051                 case 4:
1052                         s->range_table = &range718_bipolar0_5;
1053                         break;
1054                 case 6:
1055                         s->range_table = &range_unipolar10;
1056                         break;
1057                 case 7:
1058                         s->range_table = &range_unipolar5;
1059                         break;
1060                 case 8:
1061                         s->range_table = &range718_unipolar2;
1062                         break;
1063                 case 9:
1064                         s->range_table = &range718_unipolar1;
1065                         break;
1066                 default:
1067                         s->range_table = &range_unknown;
1068                         break;
1069                 }
1070         }
1071 }
1072
1073 static int pcl818_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
1074 {
1075         struct pcl818_private *devpriv = dev->private;
1076         struct pcl818_dma_desc *dma;
1077         int i;
1078
1079         if (!(dma_chan == 3 || dma_chan == 1))
1080                 return 0;
1081
1082         if (request_dma(dma_chan, dev->board_name))
1083                 return 0;
1084         devpriv->dma = dma_chan;
1085
1086         devpriv->hwdmasize = PAGE_SIZE * 4;     /* we need 16KB */
1087
1088         for (i = 0; i < 2; i++) {
1089                 dma = &devpriv->dma_desc[i];
1090
1091                 dma->virt_addr = dma_alloc_coherent(NULL, devpriv->hwdmasize,
1092                                                     &dma->hw_addr, GFP_KERNEL);
1093                 if (!dma->virt_addr)
1094                         return -ENOMEM;
1095         }
1096         return 0;
1097 }
1098
1099 static void pcl818_free_dma(struct comedi_device *dev)
1100 {
1101         struct pcl818_private *devpriv = dev->private;
1102         struct pcl818_dma_desc *dma;
1103         int i;
1104
1105         if (!devpriv)
1106                 return;
1107
1108         if (devpriv->dma)
1109                 free_dma(devpriv->dma);
1110         for (i = 0; i < 2; i++) {
1111                 dma = &devpriv->dma_desc[i];
1112                 if (dma->virt_addr)
1113                         dma_free_coherent(NULL, devpriv->hwdmasize,
1114                                           dma->virt_addr, dma->hw_addr);
1115         }
1116 }
1117
1118 static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1119 {
1120         const struct pcl818_board *board = dev->board_ptr;
1121         struct pcl818_private *devpriv;
1122         struct comedi_subdevice *s;
1123         int ret;
1124
1125         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1126         if (!devpriv)
1127                 return -ENOMEM;
1128
1129         ret = comedi_request_region(dev, it->options[0],
1130                                     board->has_fifo ? 0x20 : 0x10);
1131         if (ret)
1132                 return ret;
1133
1134         /* we can use IRQ 2-7 for async command support */
1135         if (it->options[1] >= 2 && it->options[1] <= 7) {
1136                 ret = request_irq(it->options[1], pcl818_interrupt, 0,
1137                                   dev->board_name, dev);
1138                 if (ret == 0)
1139                         dev->irq = it->options[1];
1140         }
1141
1142         /* should we use the FIFO? */
1143         if (dev->irq && board->has_fifo && it->options[2] == -1)
1144                 devpriv->usefifo = 1;
1145
1146         /* we need an IRQ to do DMA on channel 3 or 1 */
1147         if (dev->irq && board->has_dma) {
1148                 ret = pcl818_alloc_dma(dev, it->options[2]);
1149                 if (ret)
1150                         return ret;
1151         }
1152
1153         ret = comedi_alloc_subdevices(dev, 4);
1154         if (ret)
1155                 return ret;
1156
1157         s = &dev->subdevices[0];
1158         s->type         = COMEDI_SUBD_AI;
1159         s->subdev_flags = SDF_READABLE;
1160         if (check_single_ended(dev->iobase)) {
1161                 s->n_chan       = 16;
1162                 s->subdev_flags |= SDF_COMMON | SDF_GROUND;
1163         } else {
1164                 s->n_chan       = 8;
1165                 s->subdev_flags |= SDF_DIFF;
1166         }
1167         s->maxdata      = 0x0fff;
1168
1169         pcl818_set_ai_range_table(dev, s, it);
1170
1171         s->insn_read    = pcl818_ai_insn_read;
1172         if (dev->irq) {
1173                 dev->read_subdev = s;
1174                 s->subdev_flags |= SDF_CMD_READ;
1175                 s->len_chanlist = s->n_chan;
1176                 s->do_cmdtest   = ai_cmdtest;
1177                 s->do_cmd       = pcl818_ai_cmd;
1178                 s->cancel       = pcl818_ai_cancel;
1179         }
1180
1181         /* Analog Output subdevice */
1182         s = &dev->subdevices[1];
1183         if (board->n_aochan) {
1184                 s->type         = COMEDI_SUBD_AO;
1185                 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
1186                 s->n_chan       = board->n_aochan;
1187                 s->maxdata      = 0x0fff;
1188                 s->range_table  = &range_unipolar5;
1189                 if (board->is_818) {
1190                         if ((it->options[4] == 1) || (it->options[4] == 10))
1191                                 s->range_table = &range_unipolar10;
1192                         if (it->options[4] == 2)
1193                                 s->range_table = &range_unknown;
1194                 } else {
1195                         if ((it->options[5] == 1) || (it->options[5] == 10))
1196                                 s->range_table = &range_unipolar10;
1197                         if (it->options[5] == 2)
1198                                 s->range_table = &range_unknown;
1199                 }
1200                 s->insn_write   = pcl818_ao_insn_write;
1201
1202                 ret = comedi_alloc_subdev_readback(s);
1203                 if (ret)
1204                         return ret;
1205         } else {
1206                 s->type         = COMEDI_SUBD_UNUSED;
1207         }
1208
1209         /* Digital Input subdevice */
1210         s = &dev->subdevices[2];
1211         s->type         = COMEDI_SUBD_DI;
1212         s->subdev_flags = SDF_READABLE;
1213         s->n_chan       = 16;
1214         s->maxdata      = 1;
1215         s->range_table  = &range_digital;
1216         s->insn_bits    = pcl818_di_insn_bits;
1217
1218         /* Digital Output subdevice */
1219         s = &dev->subdevices[3];
1220         s->type         = COMEDI_SUBD_DO;
1221         s->subdev_flags = SDF_WRITABLE;
1222         s->n_chan       = 16;
1223         s->maxdata      = 1;
1224         s->range_table  = &range_digital;
1225         s->insn_bits    = pcl818_do_insn_bits;
1226
1227         /* select 1/10MHz oscilator */
1228         if ((it->options[3] == 0) || (it->options[3] == 10))
1229                 devpriv->i8253_osc_base = I8254_OSC_BASE_10MHZ;
1230         else
1231                 devpriv->i8253_osc_base = I8254_OSC_BASE_1MHZ;
1232
1233         /* max sampling speed */
1234         devpriv->ns_min = board->ns_min;
1235
1236         if (!board->is_818) {
1237                 if ((it->options[6] == 1) || (it->options[6] == 100))
1238                         devpriv->ns_min = 10000;        /* extended PCL718 to 100kHz DAC */
1239         }
1240
1241         pcl818_reset(dev);
1242
1243         return 0;
1244 }
1245
1246 static void pcl818_detach(struct comedi_device *dev)
1247 {
1248         struct pcl818_private *devpriv = dev->private;
1249
1250         if (devpriv) {
1251                 pcl818_ai_cancel(dev, dev->read_subdev);
1252                 pcl818_reset(dev);
1253         }
1254         pcl818_free_dma(dev);
1255         comedi_legacy_detach(dev);
1256 }
1257
1258 static struct comedi_driver pcl818_driver = {
1259         .driver_name    = "pcl818",
1260         .module         = THIS_MODULE,
1261         .attach         = pcl818_attach,
1262         .detach         = pcl818_detach,
1263         .board_name     = &boardtypes[0].name,
1264         .num_names      = ARRAY_SIZE(boardtypes),
1265         .offset         = sizeof(struct pcl818_board),
1266 };
1267 module_comedi_driver(pcl818_driver);
1268
1269 MODULE_AUTHOR("Comedi http://www.comedi.org");
1270 MODULE_DESCRIPTION("Comedi low-level driver");
1271 MODULE_LICENSE("GPL");