]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blob - drivers/staging/comedi/drivers/das16m1.c
Merge tag 'pinctrl-v4.1-1' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw...
[mirror_ubuntu-zesty-kernel.git] / 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");