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