These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / das16m1.c
1 /*
2     comedi/drivers/das16m1.c
3     CIO-DAS16/M1 driver
4     Author: Frank Mori Hess, based on code from the das16
5       driver.
6     Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>
7
8     COMEDI - Linux Control and Measurement Device Interface
9     Copyright (C) 2000 David A. Schleef <ds@schleef.org>
10
11     This program is free software; you can redistribute it and/or modify
12     it under the terms of the GNU General Public License as published by
13     the Free Software Foundation; either version 2 of the License, or
14     (at your option) any later version.
15
16     This program is distributed in the hope that it will be useful,
17     but WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19     GNU General Public License for more details.
20 */
21 /*
22 Driver: das16m1
23 Description: CIO-DAS16/M1
24 Author: Frank Mori Hess <fmhess@users.sourceforge.net>
25 Devices: [Measurement Computing] CIO-DAS16/M1 (das16m1)
26 Status: works
27
28 This driver supports a single board - the CIO-DAS16/M1.
29 As far as I know, there are no other boards that have
30 the same register layout.  Even the CIO-DAS16/M1/16 is
31 significantly different.
32
33 I was _barely_ able to reach the full 1 MHz capability
34 of this board, using a hard real-time interrupt
35 (set the TRIG_RT flag in your struct comedi_cmd and use
36 rtlinux or RTAI).  The board can't do dma, so the bottleneck is
37 pulling the data across the ISA bus.  I timed the interrupt
38 handler, and it took my computer ~470 microseconds to pull 512
39 samples from the board.  So at 1 Mhz sampling rate,
40 expect your CPU to be spending almost all of its
41 time in the interrupt handler.
42
43 This board has some unusual restrictions for its channel/gain list.  If the
44 list has 2 or more channels in it, then two conditions must be satisfied:
45 (1) - even/odd channels must appear at even/odd indices in the list
46 (2) - the list must have an even number of entries.
47
48 Options:
49         [0] - base io address
50         [1] - irq (optional, but you probably want it)
51
52 irq can be omitted, although the cmd interface will not work without it.
53 */
54
55 #include <linux/module.h>
56 #include <linux/slab.h>
57 #include <linux/interrupt.h>
58 #include "../comedidev.h"
59
60 #include "8255.h"
61 #include "comedi_8254.h"
62
63 #define DAS16M1_SIZE2 8
64
65 #define FIFO_SIZE 1024          /*  1024 sample fifo */
66
67 /*
68     CIO-DAS16_M1.pdf
69
70     "cio-das16/m1"
71
72   0             a/d bits 0-3, mux               start 12 bit
73   1             a/d bits 4-11           unused
74   2             status          control
75   3             di 4 bit                do 4 bit
76   4             unused                  clear interrupt
77   5             interrupt, pacer
78   6             channel/gain queue address
79   7             channel/gain queue data
80   89ab          8254
81   cdef          8254
82   400           8255
83   404-407       8254
84
85 */
86
87 #define DAS16M1_AI             0        /*  16-bit wide register */
88 #define   AI_CHAN(x)             ((x) & 0xf)
89 #define DAS16M1_CS             2
90 #define   EXT_TRIG_BIT           0x1
91 #define   OVRUN                  0x20
92 #define   IRQDATA                0x80
93 #define DAS16M1_DIO            3
94 #define DAS16M1_CLEAR_INTR     4
95 #define DAS16M1_INTR_CONTROL   5
96 #define   EXT_PACER              0x2
97 #define   INT_PACER              0x3
98 #define   PACER_MASK             0x3
99 #define   INTE                   0x80
100 #define DAS16M1_QUEUE_ADDR     6
101 #define DAS16M1_QUEUE_DATA     7
102 #define   Q_CHAN(x)              ((x) & 0x7)
103 #define   Q_RANGE(x)             (((x) & 0xf) << 4)
104 #define   UNIPOLAR               0x40
105 #define DAS16M1_8254_FIRST             0x8
106 #define DAS16M1_8254_SECOND            0xc
107 #define DAS16M1_82C55                  0x400
108 #define DAS16M1_8254_THIRD             0x404
109
110 static const struct comedi_lrange range_das16m1 = {
111         9, {
112                 BIP_RANGE(5),
113                 BIP_RANGE(2.5),
114                 BIP_RANGE(1.25),
115                 BIP_RANGE(0.625),
116                 UNI_RANGE(10),
117                 UNI_RANGE(5),
118                 UNI_RANGE(2.5),
119                 UNI_RANGE(1.25),
120                 BIP_RANGE(10)
121         }
122 };
123
124 struct das16m1_private_struct {
125         struct comedi_8254 *counter;
126         unsigned int control_state;
127         unsigned int adc_count; /*  number of samples completed */
128         /* initial value in lower half of hardware conversion counter,
129          * needed to keep track of whether new count has been loaded into
130          * counter yet (loaded by first sample conversion) */
131         u16 initial_hw_count;
132         unsigned short ai_buffer[FIFO_SIZE];
133         unsigned long extra_iobase;
134 };
135
136 static inline unsigned short munge_sample(unsigned short data)
137 {
138         return (data >> 4) & 0xfff;
139 }
140
141 static void munge_sample_array(unsigned short *array, unsigned int num_elements)
142 {
143         unsigned int i;
144
145         for (i = 0; i < num_elements; i++)
146                 array[i] = munge_sample(array[i]);
147 }
148
149 static int das16m1_ai_check_chanlist(struct comedi_device *dev,
150                                      struct comedi_subdevice *s,
151                                      struct comedi_cmd *cmd)
152 {
153         int i;
154
155         if (cmd->chanlist_len == 1)
156                 return 0;
157
158         if ((cmd->chanlist_len % 2) != 0) {
159                 dev_dbg(dev->class_dev,
160                         "chanlist must be of even length or length 1\n");
161                 return -EINVAL;
162         }
163
164         for (i = 0; i < cmd->chanlist_len; i++) {
165                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
166
167                 if ((i % 2) != (chan % 2)) {
168                         dev_dbg(dev->class_dev,
169                                 "even/odd channels must go have even/odd chanlist indices\n");
170                         return -EINVAL;
171                 }
172         }
173
174         return 0;
175 }
176
177 static int das16m1_cmd_test(struct comedi_device *dev,
178                             struct comedi_subdevice *s, struct comedi_cmd *cmd)
179 {
180         int err = 0;
181
182         /* Step 1 : check if triggers are trivially valid */
183
184         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
185         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
186         err |= comedi_check_trigger_src(&cmd->convert_src,
187                                         TRIG_TIMER | TRIG_EXT);
188         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
189         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
190
191         if (err)
192                 return 1;
193
194         /* Step 2a : make sure trigger sources are unique */
195
196         err |= comedi_check_trigger_is_unique(cmd->start_src);
197         err |= comedi_check_trigger_is_unique(cmd->convert_src);
198         err |= comedi_check_trigger_is_unique(cmd->stop_src);
199
200         /* Step 2b : and mutually compatible */
201
202         if (err)
203                 return 2;
204
205         /* Step 3: check if arguments are trivially valid */
206
207         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
208
209         if (cmd->scan_begin_src == TRIG_FOLLOW) /* internal trigger */
210                 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
211
212         if (cmd->convert_src == TRIG_TIMER)
213                 err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 1000);
214
215         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
216                                            cmd->chanlist_len);
217
218         if (cmd->stop_src == TRIG_COUNT)
219                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
220         else    /* TRIG_NONE */
221                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
222
223         if (err)
224                 return 3;
225
226         /* step 4: fix up arguments */
227
228         if (cmd->convert_src == TRIG_TIMER) {
229                 unsigned int arg = cmd->convert_arg;
230
231                 comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
232                 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
233         }
234
235         if (err)
236                 return 4;
237
238         /* Step 5: check channel list if it exists */
239         if (cmd->chanlist && cmd->chanlist_len > 0)
240                 err |= das16m1_ai_check_chanlist(dev, s, cmd);
241
242         if (err)
243                 return 5;
244
245         return 0;
246 }
247
248 static int das16m1_cmd_exec(struct comedi_device *dev,
249                             struct comedi_subdevice *s)
250 {
251         struct das16m1_private_struct *devpriv = dev->private;
252         struct comedi_async *async = s->async;
253         struct comedi_cmd *cmd = &async->cmd;
254         unsigned int byte, i;
255
256         /* disable interrupts and internal pacer */
257         devpriv->control_state &= ~INTE & ~PACER_MASK;
258         outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
259
260         /*  set software count */
261         devpriv->adc_count = 0;
262
263         /*
264          * Initialize lower half of hardware counter, used to determine how
265          * many samples are in fifo.  Value doesn't actually load into counter
266          * until counter's next clock (the next a/d conversion).
267          */
268         comedi_8254_set_mode(devpriv->counter, 1, I8254_MODE2 | I8254_BINARY);
269         comedi_8254_write(devpriv->counter, 1, 0);
270
271         /*
272          * Remember current reading of counter so we know when counter has
273          * actually been loaded.
274          */
275         devpriv->initial_hw_count = comedi_8254_read(devpriv->counter, 1);
276
277         /* setup channel/gain queue */
278         for (i = 0; i < cmd->chanlist_len; i++) {
279                 outb(i, dev->iobase + DAS16M1_QUEUE_ADDR);
280                 byte =
281                     Q_CHAN(CR_CHAN(cmd->chanlist[i])) |
282                     Q_RANGE(CR_RANGE(cmd->chanlist[i]));
283                 outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);
284         }
285
286         /* enable interrupts and set internal pacer counter mode and counts */
287         devpriv->control_state &= ~PACER_MASK;
288         if (cmd->convert_src == TRIG_TIMER) {
289                 comedi_8254_update_divisors(dev->pacer);
290                 comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
291                 devpriv->control_state |= INT_PACER;
292         } else {        /* TRIG_EXT */
293                 devpriv->control_state |= EXT_PACER;
294         }
295
296         /*  set control & status register */
297         byte = 0;
298         /* if we are using external start trigger (also board dislikes having
299          * both start and conversion triggers external simultaneously) */
300         if (cmd->start_src == TRIG_EXT && cmd->convert_src != TRIG_EXT)
301                 byte |= EXT_TRIG_BIT;
302
303         outb(byte, dev->iobase + DAS16M1_CS);
304         /* clear interrupt bit */
305         outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
306
307         devpriv->control_state |= INTE;
308         outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
309
310         return 0;
311 }
312
313 static int das16m1_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
314 {
315         struct das16m1_private_struct *devpriv = dev->private;
316
317         devpriv->control_state &= ~INTE & ~PACER_MASK;
318         outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
319
320         return 0;
321 }
322
323 static int das16m1_ai_eoc(struct comedi_device *dev,
324                           struct comedi_subdevice *s,
325                           struct comedi_insn *insn,
326                           unsigned long context)
327 {
328         unsigned int status;
329
330         status = inb(dev->iobase + DAS16M1_CS);
331         if (status & IRQDATA)
332                 return 0;
333         return -EBUSY;
334 }
335
336 static int das16m1_ai_rinsn(struct comedi_device *dev,
337                             struct comedi_subdevice *s,
338                             struct comedi_insn *insn, unsigned int *data)
339 {
340         struct das16m1_private_struct *devpriv = dev->private;
341         int ret;
342         int n;
343         int byte;
344
345         /* disable interrupts and internal pacer */
346         devpriv->control_state &= ~INTE & ~PACER_MASK;
347         outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
348
349         /* setup channel/gain queue */
350         outb(0, dev->iobase + DAS16M1_QUEUE_ADDR);
351         byte =
352             Q_CHAN(CR_CHAN(insn->chanspec)) | Q_RANGE(CR_RANGE(insn->chanspec));
353         outb(byte, dev->iobase + DAS16M1_QUEUE_DATA);
354
355         for (n = 0; n < insn->n; n++) {
356                 /* clear IRQDATA bit */
357                 outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
358                 /* trigger conversion */
359                 outb(0, dev->iobase);
360
361                 ret = comedi_timeout(dev, s, insn, das16m1_ai_eoc, 0);
362                 if (ret)
363                         return ret;
364
365                 data[n] = munge_sample(inw(dev->iobase));
366         }
367
368         return n;
369 }
370
371 static int das16m1_di_rbits(struct comedi_device *dev,
372                             struct comedi_subdevice *s,
373                             struct comedi_insn *insn, unsigned int *data)
374 {
375         unsigned int bits;
376
377         bits = inb(dev->iobase + DAS16M1_DIO) & 0xf;
378         data[1] = bits;
379         data[0] = 0;
380
381         return insn->n;
382 }
383
384 static int das16m1_do_wbits(struct comedi_device *dev,
385                             struct comedi_subdevice *s,
386                             struct comedi_insn *insn,
387                             unsigned int *data)
388 {
389         if (comedi_dio_update_state(s, data))
390                 outb(s->state, dev->iobase + DAS16M1_DIO);
391
392         data[1] = s->state;
393
394         return insn->n;
395 }
396
397 static void das16m1_handler(struct comedi_device *dev, unsigned int status)
398 {
399         struct das16m1_private_struct *devpriv = dev->private;
400         struct comedi_subdevice *s;
401         struct comedi_async *async;
402         struct comedi_cmd *cmd;
403         u16 num_samples;
404         u16 hw_counter;
405
406         s = dev->read_subdev;
407         async = s->async;
408         cmd = &async->cmd;
409
410         /* figure out how many samples are in fifo */
411         hw_counter = comedi_8254_read(devpriv->counter, 1);
412         /* make sure hardware counter reading is not bogus due to initial value
413          * not having been loaded yet */
414         if (devpriv->adc_count == 0 &&
415             hw_counter == devpriv->initial_hw_count) {
416                 num_samples = 0;
417         } else {
418                 /* The calculation of num_samples looks odd, but it uses the
419                  * following facts. 16 bit hardware counter is initialized with
420                  * value of zero (which really means 0x1000).  The counter
421                  * decrements by one on each conversion (when the counter
422                  * decrements from zero it goes to 0xffff).  num_samples is a
423                  * 16 bit variable, so it will roll over in a similar fashion
424                  * to the hardware counter.  Work it out, and this is what you
425                  * get. */
426                 num_samples = -hw_counter - devpriv->adc_count;
427         }
428         /*  check if we only need some of the points */
429         if (cmd->stop_src == TRIG_COUNT) {
430                 if (num_samples > cmd->stop_arg * cmd->chanlist_len)
431                         num_samples = cmd->stop_arg * cmd->chanlist_len;
432         }
433         /*  make sure we dont try to get too many points if fifo has overrun */
434         if (num_samples > FIFO_SIZE)
435                 num_samples = FIFO_SIZE;
436         insw(dev->iobase, devpriv->ai_buffer, num_samples);
437         munge_sample_array(devpriv->ai_buffer, num_samples);
438         comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples);
439         devpriv->adc_count += num_samples;
440
441         if (cmd->stop_src == TRIG_COUNT) {
442                 if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) {
443                         /* end of acquisition */
444                         async->events |= COMEDI_CB_EOA;
445                 }
446         }
447
448         /* this probably won't catch overruns since the card doesn't generate
449          * overrun interrupts, but we might as well try */
450         if (status & OVRUN) {
451                 async->events |= COMEDI_CB_ERROR;
452                 dev_err(dev->class_dev, "fifo overflow\n");
453         }
454
455         comedi_handle_events(dev, s);
456 }
457
458 static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
459 {
460         unsigned long flags;
461         unsigned int status;
462
463         /*  prevent race with interrupt handler */
464         spin_lock_irqsave(&dev->spinlock, flags);
465         status = inb(dev->iobase + DAS16M1_CS);
466         das16m1_handler(dev, status);
467         spin_unlock_irqrestore(&dev->spinlock, flags);
468
469         return comedi_buf_n_bytes_ready(s);
470 }
471
472 static irqreturn_t das16m1_interrupt(int irq, void *d)
473 {
474         int status;
475         struct comedi_device *dev = d;
476
477         if (!dev->attached) {
478                 dev_err(dev->class_dev, "premature interrupt\n");
479                 return IRQ_HANDLED;
480         }
481         /*  prevent race with comedi_poll() */
482         spin_lock(&dev->spinlock);
483
484         status = inb(dev->iobase + DAS16M1_CS);
485
486         if ((status & (IRQDATA | OVRUN)) == 0) {
487                 dev_err(dev->class_dev, "spurious interrupt\n");
488                 spin_unlock(&dev->spinlock);
489                 return IRQ_NONE;
490         }
491
492         das16m1_handler(dev, status);
493
494         /* clear interrupt */
495         outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
496
497         spin_unlock(&dev->spinlock);
498         return IRQ_HANDLED;
499 }
500
501 static int das16m1_irq_bits(unsigned int irq)
502 {
503         switch (irq) {
504         case 10:
505                 return 0x0;
506         case 11:
507                 return 0x1;
508         case 12:
509                 return 0x2;
510         case 15:
511                 return 0x3;
512         case 2:
513                 return 0x4;
514         case 3:
515                 return 0x5;
516         case 5:
517                 return 0x6;
518         case 7:
519                 return 0x7;
520         default:
521                 return 0x0;
522         }
523 }
524
525 /*
526  * Options list:
527  *   0  I/O base
528  *   1  IRQ
529  */
530 static int das16m1_attach(struct comedi_device *dev,
531                           struct comedi_devconfig *it)
532 {
533         struct das16m1_private_struct *devpriv;
534         struct comedi_subdevice *s;
535         int ret;
536
537         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
538         if (!devpriv)
539                 return -ENOMEM;
540
541         ret = comedi_request_region(dev, it->options[0], 0x10);
542         if (ret)
543                 return ret;
544         /* Request an additional region for the 8255 */
545         ret = __comedi_request_region(dev, dev->iobase + DAS16M1_82C55,
546                                       DAS16M1_SIZE2);
547         if (ret)
548                 return ret;
549         devpriv->extra_iobase = dev->iobase + DAS16M1_82C55;
550
551         /* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */
552         if ((1 << it->options[1]) & 0xdcfc) {
553                 ret = request_irq(it->options[1], das16m1_interrupt, 0,
554                                   dev->board_name, dev);
555                 if (ret == 0)
556                         dev->irq = it->options[1];
557         }
558
559         dev->pacer = comedi_8254_init(dev->iobase + DAS16M1_8254_SECOND,
560                                       I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
561         if (!dev->pacer)
562                 return -ENOMEM;
563
564         devpriv->counter = comedi_8254_init(dev->iobase + DAS16M1_8254_FIRST,
565                                             0, I8254_IO8, 0);
566         if (!devpriv->counter)
567                 return -ENOMEM;
568
569         ret = comedi_alloc_subdevices(dev, 4);
570         if (ret)
571                 return ret;
572
573         s = &dev->subdevices[0];
574         /* ai */
575         s->type = COMEDI_SUBD_AI;
576         s->subdev_flags = SDF_READABLE | SDF_DIFF;
577         s->n_chan = 8;
578         s->maxdata = (1 << 12) - 1;
579         s->range_table = &range_das16m1;
580         s->insn_read = das16m1_ai_rinsn;
581         if (dev->irq) {
582                 dev->read_subdev = s;
583                 s->subdev_flags |= SDF_CMD_READ;
584                 s->len_chanlist = 256;
585                 s->do_cmdtest = das16m1_cmd_test;
586                 s->do_cmd = das16m1_cmd_exec;
587                 s->cancel = das16m1_cancel;
588                 s->poll = das16m1_poll;
589         }
590
591         s = &dev->subdevices[1];
592         /* di */
593         s->type = COMEDI_SUBD_DI;
594         s->subdev_flags = SDF_READABLE;
595         s->n_chan = 4;
596         s->maxdata = 1;
597         s->range_table = &range_digital;
598         s->insn_bits = das16m1_di_rbits;
599
600         s = &dev->subdevices[2];
601         /* do */
602         s->type = COMEDI_SUBD_DO;
603         s->subdev_flags = SDF_WRITABLE;
604         s->n_chan = 4;
605         s->maxdata = 1;
606         s->range_table = &range_digital;
607         s->insn_bits = das16m1_do_wbits;
608
609         s = &dev->subdevices[3];
610         /* 8255 */
611         ret = subdev_8255_init(dev, s, NULL, DAS16M1_82C55);
612         if (ret)
613                 return ret;
614
615         /*  initialize digital output lines */
616         outb(0, dev->iobase + DAS16M1_DIO);
617
618         /* set the interrupt level */
619         devpriv->control_state = das16m1_irq_bits(dev->irq) << 4;
620         outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
621
622         return 0;
623 }
624
625 static void das16m1_detach(struct comedi_device *dev)
626 {
627         struct das16m1_private_struct *devpriv = dev->private;
628
629         if (devpriv) {
630                 if (devpriv->extra_iobase)
631                         release_region(devpriv->extra_iobase, DAS16M1_SIZE2);
632                 kfree(devpriv->counter);
633         }
634         comedi_legacy_detach(dev);
635 }
636
637 static struct comedi_driver das16m1_driver = {
638         .driver_name    = "das16m1",
639         .module         = THIS_MODULE,
640         .attach         = das16m1_attach,
641         .detach         = das16m1_detach,
642 };
643 module_comedi_driver(das16m1_driver);
644
645 MODULE_AUTHOR("Comedi http://www.comedi.org");
646 MODULE_DESCRIPTION("Comedi low-level driver");
647 MODULE_LICENSE("GPL");