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