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