KVM: x86: update KVM_SAVE_MSRS_BEGIN to correct value
[cascardo/linux.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 #define this_board ((const struct dt2811_board *)dev->board_ptr)
215
216 enum { card_2811_pgh, card_2811_pgl };
217
218 struct dt2811_private {
219         int ntrig;
220         int curadchan;
221         enum {
222                 adc_singleended, adc_diff, adc_pseudo_diff
223         } adc_mux;
224         enum {
225                 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
226         } dac_range[2];
227         const struct comedi_lrange *range_type_list[2];
228         unsigned int ao_readback[2];
229 };
230
231 #define devpriv ((struct dt2811_private *)dev->private)
232
233 static const struct comedi_lrange *dac_range_types[] = {
234         &range_bipolar5,
235         &range_bipolar2_5,
236         &range_unipolar5
237 };
238
239 #define DT2811_TIMEOUT 5
240
241 #if 0
242 static irqreturn_t dt2811_interrupt(int irq, void *d)
243 {
244         int lo, hi;
245         int data;
246         struct comedi_device *dev = d;
247
248         if (!dev->attached) {
249                 comedi_error(dev, "spurious interrupt");
250                 return IRQ_HANDLED;
251         }
252
253         lo = inb(dev->iobase + DT2811_ADDATLO);
254         hi = inb(dev->iobase + DT2811_ADDATHI);
255
256         data = lo + (hi << 8);
257
258         if (!(--devpriv->ntrig)) {
259                 /* how to turn off acquisition */
260                 s->async->events |= COMEDI_SB_EOA;
261         }
262         comedi_event(dev, s);
263         return IRQ_HANDLED;
264 }
265 #endif
266
267 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
268                           struct comedi_insn *insn, unsigned int *data)
269 {
270         int chan = CR_CHAN(insn->chanspec);
271         int timeout = DT2811_TIMEOUT;
272         int i;
273
274         for (i = 0; i < insn->n; i++) {
275                 outb(chan, dev->iobase + DT2811_ADGCR);
276
277                 while (timeout
278                        && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
279                         timeout--;
280                 if (!timeout)
281                         return -ETIME;
282
283                 data[i] = inb(dev->iobase + DT2811_ADDATLO);
284                 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
285                 data[i] &= 0xfff;
286         }
287
288         return i;
289 }
290
291 #if 0
292 /* Wow.  This is code from the Comedi stone age.  But it hasn't been
293  * replaced, so I'll let it stay. */
294 int dt2811_adtrig(kdev_t minor, comedi_adtrig *adtrig)
295 {
296         struct comedi_device *dev = comedi_devices + minor;
297
298         if (adtrig->n < 1)
299                 return 0;
300         dev->curadchan = adtrig->chan;
301         switch (dev->i_admode) {
302         case COMEDI_MDEMAND:
303                 dev->ntrig = adtrig->n - 1;
304                 /* not necessary */
305                 /*printk("dt2811: AD soft trigger\n"); */
306                 /*outb(DT2811_CLRERROR|DT2811_INTENB,
307                         dev->iobase+DT2811_ADCSR); */
308                 outb(dev->curadchan, dev->iobase + DT2811_ADGCR);
309                 do_gettimeofday(&trigtime);
310                 break;
311         case COMEDI_MCONTS:
312                 dev->ntrig = adtrig->n;
313                 break;
314         }
315
316         return 0;
317 }
318 #endif
319
320 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
321                           struct comedi_insn *insn, unsigned int *data)
322 {
323         int i;
324         int chan;
325
326         chan = CR_CHAN(insn->chanspec);
327
328         for (i = 0; i < insn->n; i++) {
329                 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
330                 outb((data[i] >> 8) & 0xff,
331                      dev->iobase + DT2811_DADAT0HI + 2 * chan);
332                 devpriv->ao_readback[chan] = data[i];
333         }
334
335         return i;
336 }
337
338 static int dt2811_ao_insn_read(struct comedi_device *dev,
339                                struct comedi_subdevice *s,
340                                struct comedi_insn *insn, unsigned int *data)
341 {
342         int i;
343         int chan;
344
345         chan = CR_CHAN(insn->chanspec);
346
347         for (i = 0; i < insn->n; i++)
348                 data[i] = devpriv->ao_readback[chan];
349
350         return i;
351 }
352
353 static int dt2811_di_insn_bits(struct comedi_device *dev,
354                                struct comedi_subdevice *s,
355                                struct comedi_insn *insn, unsigned int *data)
356 {
357         if (insn->n != 2)
358                 return -EINVAL;
359
360         data[1] = inb(dev->iobase + DT2811_DIO);
361
362         return 2;
363 }
364
365 static int dt2811_do_insn_bits(struct comedi_device *dev,
366                                struct comedi_subdevice *s,
367                                struct comedi_insn *insn, unsigned int *data)
368 {
369         if (insn->n != 2)
370                 return -EINVAL;
371
372         s->state &= ~data[0];
373         s->state |= data[0] & data[1];
374         outb(s->state, dev->iobase + DT2811_DIO);
375
376         data[1] = s->state;
377
378         return 2;
379 }
380
381 /*
382   options[0]   Board base address
383   options[1]   IRQ
384   options[2]   Input configuration
385                  0 == single-ended
386                  1 == differential
387                  2 == pseudo-differential
388   options[3]   Analog input range configuration
389                  0 == bipolar 5  (-5V -- +5V)
390                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
391                  2 == unipolar 5V  (0V -- +5V)
392   options[4]   Analog output 0 range configuration
393                  0 == bipolar 5  (-5V -- +5V)
394                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
395                  2 == unipolar 5V  (0V -- +5V)
396   options[5]   Analog output 1 range configuration
397                  0 == bipolar 5  (-5V -- +5V)
398                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
399                  2 == unipolar 5V  (0V -- +5V)
400 */
401 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
402 {
403         /* int i, irq; */
404         /* unsigned long irqs; */
405         /* long flags; */
406
407         int ret;
408         struct comedi_subdevice *s;
409         unsigned long iobase;
410
411         iobase = it->options[0];
412
413         printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase);
414
415         if (!request_region(iobase, DT2811_SIZE, driver_name)) {
416                 printk(KERN_ERR "I/O port conflict\n");
417                 return -EIO;
418         }
419
420         dev->iobase = iobase;
421         dev->board_name = this_board->name;
422
423 #if 0
424         outb(0, dev->iobase + DT2811_ADCSR);
425         udelay(100);
426         i = inb(dev->iobase + DT2811_ADDATLO);
427         i = inb(dev->iobase + DT2811_ADDATHI);
428 #endif
429
430 #if 0
431         irq = it->options[1];
432         if (irq < 0) {
433                 save_flags(flags);
434                 sti();
435                 irqs = probe_irq_on();
436
437                 outb(DT2811_CLRERROR | DT2811_INTENB,
438                      dev->iobase + DT2811_ADCSR);
439                 outb(0, dev->iobase + DT2811_ADGCR);
440
441                 udelay(100);
442
443                 irq = probe_irq_off(irqs);
444                 restore_flags(flags);
445
446                 /*outb(DT2811_CLRERROR|DT2811_INTENB,
447                         dev->iobase+DT2811_ADCSR);*/
448
449                 if (inb(dev->iobase + DT2811_ADCSR) & DT2811_ADERROR)
450                         printk(KERN_ERR "error probing irq (bad)\n");
451                 dev->irq = 0;
452                 if (irq > 0) {
453                         i = inb(dev->iobase + DT2811_ADDATLO);
454                         i = inb(dev->iobase + DT2811_ADDATHI);
455                         printk(KERN_INFO "(irq = %d)\n", irq);
456                         ret = request_irq(irq, dt2811_interrupt, 0,
457                                           driver_name, dev);
458                         if (ret < 0)
459                                 return -EIO;
460                         dev->irq = irq;
461                 } else if (irq == 0) {
462                         printk(KERN_INFO "(no irq)\n");
463                 } else {
464                         printk(KERN_ERR "( multiple irq's -- this is bad! )\n");
465                 }
466         }
467 #endif
468
469         ret = alloc_subdevices(dev, 4);
470         if (ret < 0)
471                 return ret;
472
473         ret = alloc_private(dev, sizeof(struct dt2811_private));
474         if (ret < 0)
475                 return ret;
476
477         switch (it->options[2]) {
478         case 0:
479                 devpriv->adc_mux = adc_singleended;
480                 break;
481         case 1:
482                 devpriv->adc_mux = adc_diff;
483                 break;
484         case 2:
485                 devpriv->adc_mux = adc_pseudo_diff;
486                 break;
487         default:
488                 devpriv->adc_mux = adc_singleended;
489                 break;
490         }
491         switch (it->options[4]) {
492         case 0:
493                 devpriv->dac_range[0] = dac_bipolar_5;
494                 break;
495         case 1:
496                 devpriv->dac_range[0] = dac_bipolar_2_5;
497                 break;
498         case 2:
499                 devpriv->dac_range[0] = dac_unipolar_5;
500                 break;
501         default:
502                 devpriv->dac_range[0] = dac_bipolar_5;
503                 break;
504         }
505         switch (it->options[5]) {
506         case 0:
507                 devpriv->dac_range[1] = dac_bipolar_5;
508                 break;
509         case 1:
510                 devpriv->dac_range[1] = dac_bipolar_2_5;
511                 break;
512         case 2:
513                 devpriv->dac_range[1] = dac_unipolar_5;
514                 break;
515         default:
516                 devpriv->dac_range[1] = dac_bipolar_5;
517                 break;
518         }
519
520         s = dev->subdevices + 0;
521         /* initialize the ADC subdevice */
522         s->type = COMEDI_SUBD_AI;
523         s->subdev_flags = SDF_READABLE | SDF_GROUND;
524         s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
525         s->insn_read = dt2811_ai_insn;
526         s->maxdata = 0xfff;
527         switch (it->options[3]) {
528         case 0:
529         default:
530                 s->range_table = this_board->bip_5;
531                 break;
532         case 1:
533                 s->range_table = this_board->bip_2_5;
534                 break;
535         case 2:
536                 s->range_table = this_board->unip_5;
537                 break;
538         }
539
540         s = dev->subdevices + 1;
541         /* ao subdevice */
542         s->type = COMEDI_SUBD_AO;
543         s->subdev_flags = SDF_WRITABLE;
544         s->n_chan = 2;
545         s->insn_write = dt2811_ao_insn;
546         s->insn_read = dt2811_ao_insn_read;
547         s->maxdata = 0xfff;
548         s->range_table_list = devpriv->range_type_list;
549         devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
550         devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
551
552         s = dev->subdevices + 2;
553         /* di subdevice */
554         s->type = COMEDI_SUBD_DI;
555         s->subdev_flags = SDF_READABLE;
556         s->n_chan = 8;
557         s->insn_bits = dt2811_di_insn_bits;
558         s->maxdata = 1;
559         s->range_table = &range_digital;
560
561         s = dev->subdevices + 3;
562         /* do subdevice */
563         s->type = COMEDI_SUBD_DO;
564         s->subdev_flags = SDF_WRITABLE;
565         s->n_chan = 8;
566         s->insn_bits = dt2811_do_insn_bits;
567         s->maxdata = 1;
568         s->state = 0;
569         s->range_table = &range_digital;
570
571         return 0;
572 }
573
574 static void dt2811_detach(struct comedi_device *dev)
575 {
576         if (dev->irq)
577                 free_irq(dev->irq, dev);
578         if (dev->iobase)
579                 release_region(dev->iobase, DT2811_SIZE);
580 }
581
582 static const struct dt2811_board boardtypes[] = {
583         {
584                 .name           = "dt2811-pgh",
585                 .bip_5          = &range_dt2811_pgh_ai_5_bipolar,
586                 .bip_2_5        = &range_dt2811_pgh_ai_2_5_bipolar,
587                 .unip_5         = &range_dt2811_pgh_ai_5_unipolar,
588         }, {
589                 .name           = "dt2811-pgl",
590                 .bip_5          = &range_dt2811_pgl_ai_5_bipolar,
591                 .bip_2_5        = &range_dt2811_pgl_ai_2_5_bipolar,
592                 .unip_5         = &range_dt2811_pgl_ai_5_unipolar,
593         },
594 };
595
596 static struct comedi_driver dt2811_driver = {
597         .driver_name    = "dt2811",
598         .module         = THIS_MODULE,
599         .attach         = dt2811_attach,
600         .detach         = dt2811_detach,
601         .board_name     = &boardtypes[0].name,
602         .num_names      = ARRAY_SIZE(boardtypes),
603         .offset         = sizeof(struct dt2811_board),
604 };
605 module_comedi_driver(dt2811_driver);
606
607 MODULE_AUTHOR("Comedi http://www.comedi.org");
608 MODULE_DESCRIPTION("Comedi low-level driver");
609 MODULE_LICENSE("GPL");