Staging: comedi: remove RT code
[safe/jmp/linux-2.6] / drivers / staging / comedi / drivers / dt2811.c
1 /*
2    comedi/drivers/dt2811.c
3    Hardware driver for Data Translation DT2811
4
5    COMEDI - Linux Control and Measurement Device Interface
6    History:
7    Base Version  - David A. Schleef <ds@schleef.org>
8    December 1998 - Updated to work.  David does not have a DT2811
9    board any longer so this was suffering from bitrot.
10    Updated performed by ...
11
12    This program is free software; you can redistribute it and/or modify
13    it under the terms of the GNU General Public License as published by
14    the Free Software Foundation; either version 2 of the License, or
15    (at your option) any later version.
16
17    This program is distributed in the hope that it will be useful,
18    but WITHOUT ANY WARRANTY; without even the implied warranty of
19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20    GNU General Public License for more details.
21
22    You should have received a copy of the GNU General Public License
23    along with this program; if not, write to the Free Software
24    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25  */
26 /*
27 Driver: dt2811
28 Description: Data Translation DT2811
29 Author: ds
30 Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh)
31 Status: works
32
33 Configuration options:
34   [0] - I/O port base address
35   [1] - IRQ, although this is currently unused
36   [2] - A/D reference
37           0 = signle-ended
38           1 = differential
39           2 = pseudo-differential (common reference)
40   [3] - A/D range
41           0 = [-5,5]
42           1 = [-2.5,2.5]
43           2 = [0,5]
44   [4] - D/A 0 range (same choices)
45   [4] - D/A 1 range (same choices)
46 */
47
48 #include <linux/interrupt.h>
49 #include "../comedidev.h"
50
51 #include <linux/ioport.h>
52
53 static const char *driver_name = "dt2811";
54
55 static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = { 4, {
56                         RANGE(0, 5),
57                         RANGE(0, 2.5),
58                         RANGE(0, 1.25),
59                         RANGE(0, 0.625)
60         }
61 };
62 static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = { 4, {
63                         RANGE(-2.5, 2.5),
64                         RANGE(-1.25, 1.25),
65                         RANGE(-0.625, 0.625),
66                         RANGE(-0.3125, 0.3125)
67         }
68 };
69 static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = { 4, {
70                         RANGE(-5, 5),
71                         RANGE(-2.5, 2.5),
72                         RANGE(-1.25, 1.25),
73                         RANGE(-0.625, 0.625)
74         }
75 };
76 static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = { 4, {
77                         RANGE(0, 5),
78                         RANGE(0, 0.5),
79                         RANGE(0, 0.05),
80                         RANGE(0, 0.01)
81         }
82 };
83 static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = { 4, {
84                         RANGE(-2.5, 2.5),
85                         RANGE(-0.25, 0.25),
86                         RANGE(-0.025, 0.025),
87                         RANGE(-0.005, 0.005)
88         }
89 };
90 static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = { 4, {
91                         RANGE(-5, 5),
92                         RANGE(-0.5, 0.5),
93                         RANGE(-0.05, 0.05),
94                         RANGE(-0.01, 0.01)
95         }
96 };
97
98 /*
99
100    0x00    ADCSR R/W  A/D Control/Status Register
101    bit 7 - (R) 1 indicates A/D conversion done
102    reading ADDAT clears bit
103    (W) ignored
104    bit 6 - (R) 1 indicates A/D error
105    (W) ignored
106    bit 5 - (R) 1 indicates A/D busy, cleared at end
107    of conversion
108    (W) ignored
109    bit 4 - (R) 0
110    (W)
111    bit 3 - (R) 0
112    bit 2 - (R/W) 1 indicates interrupts enabled
113    bits 1,0 - (R/W) mode bits
114    00  single conversion on ADGCR load
115    01  continuous conversion, internal clock,
116    (clock enabled on ADGCR load)
117    10  continuous conversion, internal clock,
118    external trigger
119    11  continuous conversion, external clock,
120    external trigger
121
122    0x01    ADGCR R/W A/D Gain/Channel Register
123    bit 6,7 - (R/W) gain select
124    00  gain=1, both PGH, PGL models
125    01  gain=2 PGH, 10 PGL
126    10  gain=4 PGH, 100 PGL
127    11  gain=8 PGH, 500 PGL
128    bit 4,5 - reserved
129    bit 3-0 - (R/W) channel select
130    channel number from 0-15
131
132    0x02,0x03 (R) ADDAT A/D Data Register
133    (W) DADAT0 D/A Data Register 0
134    0x02 low byte
135    0x03 high byte
136
137    0x04,0x05 (W) DADAT0 D/A Data Register 1
138
139    0x06 (R) DIO0 Digital Input Port 0
140    (W) DIO1 Digital Output Port 1
141
142    0x07 TMRCTR (R/W) Timer/Counter Register
143    bits 6,7 - reserved
144    bits 5-3 - Timer frequency control (mantissa)
145    543  divisor  freqency (kHz)
146    000  1        600
147    001  10       60
148    010  2        300
149    011  3        200
150    100  4        150
151    101  5        120
152    110  6        100
153    111  12       50
154    bits 2-0 - Timer frequency control (exponent)
155    210  multiply divisor/divide frequency by
156    000  1
157    001  10
158    010  100
159    011  1000
160    100  10000
161    101  100000
162    110  1000000
163    111  10000000
164
165  */
166
167 #define TIMEOUT 10000
168
169 #define DT2811_SIZE 8
170
171 #define DT2811_ADCSR 0
172 #define DT2811_ADGCR 1
173 #define DT2811_ADDATLO 2
174 #define DT2811_ADDATHI 3
175 #define DT2811_DADAT0LO 2
176 #define DT2811_DADAT0HI 3
177 #define DT2811_DADAT1LO 4
178 #define DT2811_DADAT1HI 5
179 #define DT2811_DIO 6
180 #define DT2811_TMRCTR 7
181
182 /*
183  * flags
184  */
185
186 /* ADCSR */
187
188 #define DT2811_ADDONE   0x80
189 #define DT2811_ADERROR  0x40
190 #define DT2811_ADBUSY   0x20
191 #define DT2811_CLRERROR 0x10
192 #define DT2811_INTENB   0x04
193 #define DT2811_ADMODE   0x03
194
195 struct dt2811_board {
196
197         const char *name;
198         const struct comedi_lrange *bip_5;
199         const struct comedi_lrange *bip_2_5;
200         const struct comedi_lrange *unip_5;
201 };
202
203 static const struct dt2811_board boardtypes[] = {
204         {"dt2811-pgh",
205                         &range_dt2811_pgh_ai_5_bipolar,
206                         &range_dt2811_pgh_ai_2_5_bipolar,
207                         &range_dt2811_pgh_ai_5_unipolar,
208                 },
209         {"dt2811-pgl",
210                         &range_dt2811_pgl_ai_5_bipolar,
211                         &range_dt2811_pgl_ai_2_5_bipolar,
212                         &range_dt2811_pgl_ai_5_unipolar,
213                 },
214 };
215
216 #define this_board ((const struct dt2811_board *)dev->board_ptr)
217
218 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it);
219 static int dt2811_detach(struct comedi_device *dev);
220 static struct comedi_driver driver_dt2811 = {
221         .driver_name = "dt2811",
222         .module = THIS_MODULE,
223         .attach = dt2811_attach,
224         .detach = dt2811_detach,
225         .board_name = &boardtypes[0].name,
226         .num_names = ARRAY_SIZE(boardtypes),
227         .offset = sizeof(struct dt2811_board),
228 };
229
230 COMEDI_INITCLEANUP(driver_dt2811);
231
232 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
233         struct comedi_insn *insn, unsigned int *data);
234 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
235         struct comedi_insn *insn, unsigned int *data);
236 static int dt2811_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
237         struct comedi_insn *insn, unsigned int *data);
238 static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
239         struct comedi_insn *insn, unsigned int *data);
240 static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
241         struct comedi_insn *insn, unsigned int *data);
242
243 enum { card_2811_pgh, card_2811_pgl };
244
245 struct dt2811_private {
246         int ntrig;
247         int curadchan;
248         enum {
249                 adc_singleended, adc_diff, adc_pseudo_diff
250         } adc_mux;
251         enum {
252                 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
253         } dac_range[2];
254         const struct comedi_lrange *range_type_list[2];
255         unsigned int ao_readback[2];
256 };
257
258 #define devpriv ((struct dt2811_private *)dev->private)
259
260 static const struct comedi_lrange *dac_range_types[] = {
261         &range_bipolar5,
262         &range_bipolar2_5,
263         &range_unipolar5
264 };
265
266 #define DT2811_TIMEOUT 5
267
268 #if 0
269 static irqreturn_t dt2811_interrupt(int irq, void *d)
270 {
271         int lo, hi;
272         int data;
273         struct comedi_device *dev = d;
274
275         if (!dev->attached) {
276                 comedi_error(dev, "spurious interrupt");
277                 return IRQ_HANDLED;
278         }
279
280         lo = inb(dev->iobase + DT2811_ADDATLO);
281         hi = inb(dev->iobase + DT2811_ADDATHI);
282
283         data = lo + (hi << 8);
284
285         if (!(--devpriv->ntrig)) {
286                 /* how to turn off acquisition */
287                 s->async->events |= COMEDI_SB_EOA;
288         }
289         comedi_event(dev, s);
290         return IRQ_HANDLED;
291 }
292 #endif
293
294 /*
295   options[0]   Board base address
296   options[1]   IRQ
297   options[2]   Input configuration
298                  0 == single-ended
299                  1 == differential
300                  2 == pseudo-differential
301   options[3]   Analog input range configuration
302                  0 == bipolar 5  (-5V -- +5V)
303                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
304                  2 == unipolar 5V  (0V -- +5V)
305   options[4]   Analog output 0 range configuration
306                  0 == bipolar 5  (-5V -- +5V)
307                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
308                  2 == unipolar 5V  (0V -- +5V)
309   options[5]   Analog output 1 range configuration
310                  0 == bipolar 5  (-5V -- +5V)
311                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
312                  2 == unipolar 5V  (0V -- +5V)
313 */
314
315 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
316 {
317         /* int i, irq; */
318         /* unsigned long irqs; */
319         /* long flags; */
320
321         int ret;
322         struct comedi_subdevice *s;
323         unsigned long iobase;
324
325         iobase = it->options[0];
326
327         printk("comedi%d: dt2811: base=0x%04lx\n", dev->minor, iobase);
328
329         if (!request_region(iobase, DT2811_SIZE, driver_name)) {
330                 printk("I/O port conflict\n");
331                 return -EIO;
332         }
333
334         dev->iobase = iobase;
335         dev->board_name = this_board->name;
336
337 #if 0
338         outb(0, dev->iobase + DT2811_ADCSR);
339         udelay(100);
340         i = inb(dev->iobase + DT2811_ADDATLO);
341         i = inb(dev->iobase + DT2811_ADDATHI);
342 #endif
343
344 #if 0
345         irq = it->options[1];
346         if (irq < 0) {
347                 save_flags(flags);
348                 sti();
349                 irqs = probe_irq_on();
350
351                 outb(DT2811_CLRERROR | DT2811_INTENB,
352                         dev->iobase + DT2811_ADCSR);
353                 outb(0, dev->iobase + DT2811_ADGCR);
354
355                 udelay(100);
356
357                 irq = probe_irq_off(irqs);
358                 restore_flags(flags);
359
360                 /*outb(DT2811_CLRERROR|DT2811_INTENB,dev->iobase+DT2811_ADCSR); */
361
362                 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR) {
363                         printk("error probing irq (bad) \n");
364                 }
365                 dev->irq = 0;
366                 if (irq > 0) {
367                         i = inb(dev->iobase + DT2811_ADDATLO);
368                         i = inb(dev->iobase + DT2811_ADDATHI);
369                         printk("(irq = %d)\n", irq);
370                         ret = request_irq(irq, dt2811_interrupt, 0,
371                                 driver_name, dev);
372                         if (ret < 0)
373                                 return -EIO;
374                         dev->irq = irq;
375                 } else if (irq == 0) {
376                         printk("(no irq)\n");
377                 } else {
378                         printk("( multiple irq's -- this is bad! )\n");
379                 }
380         }
381 #endif
382
383         ret = alloc_subdevices(dev, 4);
384         if (ret < 0)
385                 return ret;
386
387         ret = alloc_private(dev, sizeof(struct dt2811_private));
388         if (ret < 0)
389                 return ret;
390
391         switch (it->options[2]) {
392         case 0:
393                 devpriv->adc_mux = adc_singleended;
394                 break;
395         case 1:
396                 devpriv->adc_mux = adc_diff;
397                 break;
398         case 2:
399                 devpriv->adc_mux = adc_pseudo_diff;
400                 break;
401         default:
402                 devpriv->adc_mux = adc_singleended;
403                 break;
404         }
405         switch (it->options[4]) {
406         case 0:
407                 devpriv->dac_range[0] = dac_bipolar_5;
408                 break;
409         case 1:
410                 devpriv->dac_range[0] = dac_bipolar_2_5;
411                 break;
412         case 2:
413                 devpriv->dac_range[0] = dac_unipolar_5;
414                 break;
415         default:
416                 devpriv->dac_range[0] = dac_bipolar_5;
417                 break;
418         }
419         switch (it->options[5]) {
420         case 0:
421                 devpriv->dac_range[1] = dac_bipolar_5;
422                 break;
423         case 1:
424                 devpriv->dac_range[1] = dac_bipolar_2_5;
425                 break;
426         case 2:
427                 devpriv->dac_range[1] = dac_unipolar_5;
428                 break;
429         default:
430                 devpriv->dac_range[1] = dac_bipolar_5;
431                 break;
432         }
433
434         s = dev->subdevices + 0;
435         /* initialize the ADC subdevice */
436         s->type = COMEDI_SUBD_AI;
437         s->subdev_flags = SDF_READABLE | SDF_GROUND;
438         s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
439         s->insn_read = dt2811_ai_insn;
440         s->maxdata = 0xfff;
441         switch (it->options[3]) {
442         case 0:
443         default:
444                 s->range_table = this_board->bip_5;
445                 break;
446         case 1:
447                 s->range_table = this_board->bip_2_5;
448                 break;
449         case 2:
450                 s->range_table = this_board->unip_5;
451                 break;
452         }
453
454         s = dev->subdevices + 1;
455         /* ao subdevice */
456         s->type = COMEDI_SUBD_AO;
457         s->subdev_flags = SDF_WRITABLE;
458         s->n_chan = 2;
459         s->insn_write = dt2811_ao_insn;
460         s->insn_read = dt2811_ao_insn_read;
461         s->maxdata = 0xfff;
462         s->range_table_list = devpriv->range_type_list;
463         devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
464         devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
465
466         s = dev->subdevices + 2;
467         /* di subdevice */
468         s->type = COMEDI_SUBD_DI;
469         s->subdev_flags = SDF_READABLE;
470         s->n_chan = 8;
471         s->insn_bits = dt2811_di_insn_bits;
472         s->maxdata = 1;
473         s->range_table = &range_digital;
474
475         s = dev->subdevices + 3;
476         /* do subdevice */
477         s->type = COMEDI_SUBD_DO;
478         s->subdev_flags = SDF_WRITABLE;
479         s->n_chan = 8;
480         s->insn_bits = dt2811_do_insn_bits;
481         s->maxdata = 1;
482         s->state = 0;
483         s->range_table = &range_digital;
484
485         return 0;
486 }
487
488 static int dt2811_detach(struct comedi_device *dev)
489 {
490         printk("comedi%d: dt2811: remove\n", dev->minor);
491
492         if (dev->irq) {
493                 free_irq(dev->irq, dev);
494         }
495         if (dev->iobase) {
496                 release_region(dev->iobase, DT2811_SIZE);
497         }
498
499         return 0;
500 }
501
502 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
503         struct comedi_insn *insn, unsigned int *data)
504 {
505         int chan = CR_CHAN(insn->chanspec);
506         int timeout = DT2811_TIMEOUT;
507         int i;
508
509         for (i = 0; i < insn->n; i++) {
510                 outb(chan, dev->iobase + DT2811_ADGCR);
511
512                 while (timeout
513                         && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
514                         timeout--;
515                 if (!timeout)
516                         return -ETIME;
517
518                 data[i] = inb(dev->iobase + DT2811_ADDATLO);
519                 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
520                 data[i] &= 0xfff;
521         }
522
523         return i;
524 }
525
526 #if 0
527 /* Wow.  This is code from the Comedi stone age.  But it hasn't been
528  * replaced, so I'll let it stay. */
529 int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
530 {
531         struct comedi_device *dev = comedi_devices + minor;
532
533         if (adtrig->n < 1)
534                 return 0;
535         dev->curadchan = adtrig->chan;
536         switch (dev->i_admode) {
537         case COMEDI_MDEMAND:
538                 dev->ntrig = adtrig->n - 1;
539                 /*printk("dt2811: AD soft trigger\n"); */
540                 /*outb(DT2811_CLRERROR|DT2811_INTENB,dev->iobase+DT2811_ADCSR); */ /* not neccessary */
541                 outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
542                 do_gettimeofday(&trigtime);
543                 break;
544         case COMEDI_MCONTS:
545                 dev->ntrig = adtrig->n;
546                 break;
547         }
548
549         return 0;
550 }
551 #endif
552
553 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
554         struct comedi_insn *insn, unsigned int *data)
555 {
556         int i;
557         int chan;
558
559         chan = CR_CHAN(insn->chanspec);
560
561         for (i = 0; i < insn->n; i++) {
562                 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
563                 outb((data[i] >> 8) & 0xff,
564                         dev->iobase + DT2811_DADAT0HI + 2 * chan);
565                 devpriv->ao_readback[chan] = data[i];
566         }
567
568         return i;
569 }
570
571 static int dt2811_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
572         struct comedi_insn *insn, unsigned int *data)
573 {
574         int i;
575         int chan;
576
577         chan = CR_CHAN(insn->chanspec);
578
579         for (i = 0; i < insn->n; i++) {
580                 data[i] = devpriv->ao_readback[chan];
581         }
582
583         return i;
584 }
585
586 static int dt2811_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
587         struct comedi_insn *insn, unsigned int *data)
588 {
589         if (insn->n != 2)
590                 return -EINVAL;
591
592         data[1] = inb(dev->iobase + DT2811_DIO);
593
594         return 2;
595 }
596
597 static int dt2811_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
598         struct comedi_insn *insn, unsigned int *data)
599 {
600         if (insn->n != 2)
601                 return -EINVAL;
602
603         s->state &= ~data[0];
604         s->state |= data[0] & data[1];
605         outb(s->state, dev->iobase + DT2811_DIO);
606
607         data[1] = s->state;
608
609         return 2;
610 }