Add the rt linux 4.1.3-rt3 as base
[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 && hw_counter == devpriv->initial_hw_count) {
415                 num_samples = 0;
416         } else {
417                 /* The calculation of num_samples looks odd, but it uses the following facts.
418                  * 16 bit hardware counter is initialized with value of zero (which really
419                  * means 0x1000).  The counter decrements by one on each conversion
420                  * (when the counter decrements from zero it goes to 0xffff).  num_samples
421                  * is a 16 bit variable, so it will roll over in a similar fashion to the
422                  * hardware counter.  Work it out, and this is what you get. */
423                 num_samples = -hw_counter - devpriv->adc_count;
424         }
425         /*  check if we only need some of the points */
426         if (cmd->stop_src == TRIG_COUNT) {
427                 if (num_samples > cmd->stop_arg * cmd->chanlist_len)
428                         num_samples = cmd->stop_arg * cmd->chanlist_len;
429         }
430         /*  make sure we dont try to get too many points if fifo has overrun */
431         if (num_samples > FIFO_SIZE)
432                 num_samples = FIFO_SIZE;
433         insw(dev->iobase, devpriv->ai_buffer, num_samples);
434         munge_sample_array(devpriv->ai_buffer, num_samples);
435         comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples);
436         devpriv->adc_count += num_samples;
437
438         if (cmd->stop_src == TRIG_COUNT) {
439                 if (devpriv->adc_count >= cmd->stop_arg * cmd->chanlist_len) {
440                         /* end of acquisition */
441                         async->events |= COMEDI_CB_EOA;
442                 }
443         }
444
445         /* this probably won't catch overruns since the card doesn't generate
446          * overrun interrupts, but we might as well try */
447         if (status & OVRUN) {
448                 async->events |= COMEDI_CB_ERROR;
449                 dev_err(dev->class_dev, "fifo overflow\n");
450         }
451
452         comedi_handle_events(dev, s);
453 }
454
455 static int das16m1_poll(struct comedi_device *dev, struct comedi_subdevice *s)
456 {
457         unsigned long flags;
458         unsigned int status;
459
460         /*  prevent race with interrupt handler */
461         spin_lock_irqsave(&dev->spinlock, flags);
462         status = inb(dev->iobase + DAS16M1_CS);
463         das16m1_handler(dev, status);
464         spin_unlock_irqrestore(&dev->spinlock, flags);
465
466         return comedi_buf_n_bytes_ready(s);
467 }
468
469 static irqreturn_t das16m1_interrupt(int irq, void *d)
470 {
471         int status;
472         struct comedi_device *dev = d;
473
474         if (!dev->attached) {
475                 dev_err(dev->class_dev, "premature interrupt\n");
476                 return IRQ_HANDLED;
477         }
478         /*  prevent race with comedi_poll() */
479         spin_lock(&dev->spinlock);
480
481         status = inb(dev->iobase + DAS16M1_CS);
482
483         if ((status & (IRQDATA | OVRUN)) == 0) {
484                 dev_err(dev->class_dev, "spurious interrupt\n");
485                 spin_unlock(&dev->spinlock);
486                 return IRQ_NONE;
487         }
488
489         das16m1_handler(dev, status);
490
491         /* clear interrupt */
492         outb(0, dev->iobase + DAS16M1_CLEAR_INTR);
493
494         spin_unlock(&dev->spinlock);
495         return IRQ_HANDLED;
496 }
497
498 static int das16m1_irq_bits(unsigned int irq)
499 {
500         switch (irq) {
501         case 10:
502                 return 0x0;
503         case 11:
504                 return 0x1;
505         case 12:
506                 return 0x2;
507         case 15:
508                 return 0x3;
509         case 2:
510                 return 0x4;
511         case 3:
512                 return 0x5;
513         case 5:
514                 return 0x6;
515         case 7:
516                 return 0x7;
517         default:
518                 return 0x0;
519         }
520 }
521
522 /*
523  * Options list:
524  *   0  I/O base
525  *   1  IRQ
526  */
527 static int das16m1_attach(struct comedi_device *dev,
528                           struct comedi_devconfig *it)
529 {
530         struct das16m1_private_struct *devpriv;
531         struct comedi_subdevice *s;
532         int ret;
533
534         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
535         if (!devpriv)
536                 return -ENOMEM;
537
538         ret = comedi_request_region(dev, it->options[0], 0x10);
539         if (ret)
540                 return ret;
541         /* Request an additional region for the 8255 */
542         ret = __comedi_request_region(dev, dev->iobase + DAS16M1_82C55,
543                                       DAS16M1_SIZE2);
544         if (ret)
545                 return ret;
546         devpriv->extra_iobase = dev->iobase + DAS16M1_82C55;
547
548         /* only irqs 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, and 15 are valid */
549         if ((1 << it->options[1]) & 0xdcfc) {
550                 ret = request_irq(it->options[1], das16m1_interrupt, 0,
551                                   dev->board_name, dev);
552                 if (ret == 0)
553                         dev->irq = it->options[1];
554         }
555
556         dev->pacer = comedi_8254_init(dev->iobase + DAS16M1_8254_SECOND,
557                                       I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
558         if (!dev->pacer)
559                 return -ENOMEM;
560
561         devpriv->counter = comedi_8254_init(dev->iobase + DAS16M1_8254_FIRST,
562                                             0, I8254_IO8, 0);
563         if (!devpriv->counter)
564                 return -ENOMEM;
565
566         ret = comedi_alloc_subdevices(dev, 4);
567         if (ret)
568                 return ret;
569
570         s = &dev->subdevices[0];
571         /* ai */
572         s->type = COMEDI_SUBD_AI;
573         s->subdev_flags = SDF_READABLE | SDF_DIFF;
574         s->n_chan = 8;
575         s->maxdata = (1 << 12) - 1;
576         s->range_table = &range_das16m1;
577         s->insn_read = das16m1_ai_rinsn;
578         if (dev->irq) {
579                 dev->read_subdev = s;
580                 s->subdev_flags |= SDF_CMD_READ;
581                 s->len_chanlist = 256;
582                 s->do_cmdtest = das16m1_cmd_test;
583                 s->do_cmd = das16m1_cmd_exec;
584                 s->cancel = das16m1_cancel;
585                 s->poll = das16m1_poll;
586         }
587
588         s = &dev->subdevices[1];
589         /* di */
590         s->type = COMEDI_SUBD_DI;
591         s->subdev_flags = SDF_READABLE;
592         s->n_chan = 4;
593         s->maxdata = 1;
594         s->range_table = &range_digital;
595         s->insn_bits = das16m1_di_rbits;
596
597         s = &dev->subdevices[2];
598         /* do */
599         s->type = COMEDI_SUBD_DO;
600         s->subdev_flags = SDF_WRITABLE;
601         s->n_chan = 4;
602         s->maxdata = 1;
603         s->range_table = &range_digital;
604         s->insn_bits = das16m1_do_wbits;
605
606         s = &dev->subdevices[3];
607         /* 8255 */
608         ret = subdev_8255_init(dev, s, NULL, DAS16M1_82C55);
609         if (ret)
610                 return ret;
611
612         /*  initialize digital output lines */
613         outb(0, dev->iobase + DAS16M1_DIO);
614
615         /* set the interrupt level */
616         devpriv->control_state = das16m1_irq_bits(dev->irq) << 4;
617         outb(devpriv->control_state, dev->iobase + DAS16M1_INTR_CONTROL);
618
619         return 0;
620 }
621
622 static void das16m1_detach(struct comedi_device *dev)
623 {
624         struct das16m1_private_struct *devpriv = dev->private;
625
626         if (devpriv) {
627                 if (devpriv->extra_iobase)
628                         release_region(devpriv->extra_iobase, DAS16M1_SIZE2);
629                 kfree(devpriv->counter);
630         }
631         comedi_legacy_detach(dev);
632 }
633
634 static struct comedi_driver das16m1_driver = {
635         .driver_name    = "das16m1",
636         .module         = THIS_MODULE,
637         .attach         = das16m1_attach,
638         .detach         = das16m1_detach,
639 };
640 module_comedi_driver(das16m1_driver);
641
642 MODULE_AUTHOR("Comedi http://www.comedi.org");
643 MODULE_DESCRIPTION("Comedi low-level driver");
644 MODULE_LICENSE("GPL");