Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / 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 /*
23 Driver: dt2811
24 Description: Data Translation DT2811
25 Author: ds
26 Devices: [Data Translation] DT2811-PGL (dt2811-pgl), DT2811-PGH (dt2811-pgh)
27 Status: works
28
29 Configuration options:
30   [0] - I/O port base address
31   [1] - IRQ, although this is currently unused
32   [2] - A/D reference
33           0 = signle-ended
34           1 = differential
35           2 = pseudo-differential (common reference)
36   [3] - A/D range
37           0 = [-5, 5]
38           1 = [-2.5, 2.5]
39           2 = [0, 5]
40   [4] - D/A 0 range (same choices)
41   [4] - D/A 1 range (same choices)
42 */
43
44 #include <linux/module.h>
45 #include "../comedidev.h"
46
47 static const struct comedi_lrange range_dt2811_pgh_ai_5_unipolar = {
48         4, {
49                 UNI_RANGE(5),
50                 UNI_RANGE(2.5),
51                 UNI_RANGE(1.25),
52                 UNI_RANGE(0.625)
53         }
54 };
55
56 static const struct comedi_lrange range_dt2811_pgh_ai_2_5_bipolar = {
57         4, {
58                 BIP_RANGE(2.5),
59                 BIP_RANGE(1.25),
60                 BIP_RANGE(0.625),
61                 BIP_RANGE(0.3125)
62         }
63 };
64
65 static const struct comedi_lrange range_dt2811_pgh_ai_5_bipolar = {
66         4, {
67                 BIP_RANGE(5),
68                 BIP_RANGE(2.5),
69                 BIP_RANGE(1.25),
70                 BIP_RANGE(0.625)
71         }
72 };
73
74 static const struct comedi_lrange range_dt2811_pgl_ai_5_unipolar = {
75         4, {
76                 UNI_RANGE(5),
77                 UNI_RANGE(0.5),
78                 UNI_RANGE(0.05),
79                 UNI_RANGE(0.01)
80         }
81 };
82
83 static const struct comedi_lrange range_dt2811_pgl_ai_2_5_bipolar = {
84         4, {
85                 BIP_RANGE(2.5),
86                 BIP_RANGE(0.25),
87                 BIP_RANGE(0.025),
88                 BIP_RANGE(0.005)
89         }
90 };
91
92 static const struct comedi_lrange range_dt2811_pgl_ai_5_bipolar = {
93         4, {
94                 BIP_RANGE(5),
95                 BIP_RANGE(0.5),
96                 BIP_RANGE(0.05),
97                 BIP_RANGE(0.01)
98         }
99 };
100
101 /*
102
103    0x00    ADCSR R/W  A/D Control/Status Register
104    bit 7 - (R) 1 indicates A/D conversion done
105    reading ADDAT clears bit
106    (W) ignored
107    bit 6 - (R) 1 indicates A/D error
108    (W) ignored
109    bit 5 - (R) 1 indicates A/D busy, cleared at end
110    of conversion
111    (W) ignored
112    bit 4 - (R) 0
113    (W)
114    bit 3 - (R) 0
115    bit 2 - (R/W) 1 indicates interrupts enabled
116    bits 1,0 - (R/W) mode bits
117    00  single conversion on ADGCR load
118    01  continuous conversion, internal clock,
119    (clock enabled on ADGCR load)
120    10  continuous conversion, internal clock,
121    external trigger
122    11  continuous conversion, external clock,
123    external trigger
124
125    0x01    ADGCR R/W A/D Gain/Channel Register
126    bit 6,7 - (R/W) gain select
127    00  gain=1, both PGH, PGL models
128    01  gain=2 PGH, 10 PGL
129    10  gain=4 PGH, 100 PGL
130    11  gain=8 PGH, 500 PGL
131    bit 4,5 - reserved
132    bit 3-0 - (R/W) channel select
133    channel number from 0-15
134
135    0x02,0x03 (R) ADDAT A/D Data Register
136    (W) DADAT0 D/A Data Register 0
137    0x02 low byte
138    0x03 high byte
139
140    0x04,0x05 (W) DADAT0 D/A Data Register 1
141
142    0x06 (R) DIO0 Digital Input Port 0
143    (W) DIO1 Digital Output Port 1
144
145    0x07 TMRCTR (R/W) Timer/Counter Register
146    bits 6,7 - reserved
147    bits 5-3 - Timer frequency control (mantissa)
148    543  divisor  freqency (kHz)
149    000  1        600
150    001  10       60
151    010  2        300
152    011  3        200
153    100  4        150
154    101  5        120
155    110  6        100
156    111  12       50
157    bits 2-0 - Timer frequency control (exponent)
158    210  multiply divisor/divide frequency by
159    000  1
160    001  10
161    010  100
162    011  1000
163    100  10000
164    101  100000
165    110  1000000
166    111  10000000
167
168  */
169
170 #define TIMEOUT 10000
171
172 #define DT2811_ADCSR 0
173 #define DT2811_ADGCR 1
174 #define DT2811_ADDATLO 2
175 #define DT2811_ADDATHI 3
176 #define DT2811_DADAT0LO 2
177 #define DT2811_DADAT0HI 3
178 #define DT2811_DADAT1LO 4
179 #define DT2811_DADAT1HI 5
180 #define DT2811_DIO 6
181 #define DT2811_TMRCTR 7
182
183 /*
184  * flags
185  */
186
187 /* ADCSR */
188
189 #define DT2811_ADDONE   0x80
190 #define DT2811_ADERROR  0x40
191 #define DT2811_ADBUSY   0x20
192 #define DT2811_CLRERROR 0x10
193 #define DT2811_INTENB   0x04
194 #define DT2811_ADMODE   0x03
195
196 struct dt2811_board {
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 enum { card_2811_pgh, card_2811_pgl };
204
205 struct dt2811_private {
206         int ntrig;
207         int curadchan;
208         enum {
209                 adc_singleended, adc_diff, adc_pseudo_diff
210         } adc_mux;
211         enum {
212                 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
213         } dac_range[2];
214         const struct comedi_lrange *range_type_list[2];
215 };
216
217 static const struct comedi_lrange *dac_range_types[] = {
218         &range_bipolar5,
219         &range_bipolar2_5,
220         &range_unipolar5
221 };
222
223 static int dt2811_ai_eoc(struct comedi_device *dev,
224                          struct comedi_subdevice *s,
225                          struct comedi_insn *insn,
226                          unsigned long context)
227 {
228         unsigned int status;
229
230         status = inb(dev->iobase + DT2811_ADCSR);
231         if ((status & DT2811_ADBUSY) == 0)
232                 return 0;
233         return -EBUSY;
234 }
235
236 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
237                           struct comedi_insn *insn, unsigned int *data)
238 {
239         int chan = CR_CHAN(insn->chanspec);
240         int ret;
241         int i;
242
243         for (i = 0; i < insn->n; i++) {
244                 outb(chan, dev->iobase + DT2811_ADGCR);
245
246                 ret = comedi_timeout(dev, s, insn, dt2811_ai_eoc, 0);
247                 if (ret)
248                         return ret;
249
250                 data[i] = inb(dev->iobase + DT2811_ADDATLO);
251                 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
252                 data[i] &= 0xfff;
253         }
254
255         return i;
256 }
257
258 static int dt2811_ao_insn_write(struct comedi_device *dev,
259                                 struct comedi_subdevice *s,
260                                 struct comedi_insn *insn,
261                                 unsigned int *data)
262 {
263         unsigned int chan = CR_CHAN(insn->chanspec);
264         unsigned int val = s->readback[chan];
265         int i;
266
267         for (i = 0; i < insn->n; i++) {
268                 val = data[i];
269                 outb(val & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
270                 outb((val >> 8) & 0xff,
271                      dev->iobase + DT2811_DADAT0HI + 2 * chan);
272         }
273         s->readback[chan] = val;
274
275         return insn->n;
276 }
277
278 static int dt2811_di_insn_bits(struct comedi_device *dev,
279                                struct comedi_subdevice *s,
280                                struct comedi_insn *insn, unsigned int *data)
281 {
282         data[1] = inb(dev->iobase + DT2811_DIO);
283
284         return insn->n;
285 }
286
287 static int dt2811_do_insn_bits(struct comedi_device *dev,
288                                struct comedi_subdevice *s,
289                                struct comedi_insn *insn,
290                                unsigned int *data)
291 {
292         if (comedi_dio_update_state(s, data))
293                 outb(s->state, dev->iobase + DT2811_DIO);
294
295         data[1] = s->state;
296
297         return insn->n;
298 }
299
300 /*
301   options[0]   Board base address
302   options[1]   IRQ
303   options[2]   Input configuration
304                  0 == single-ended
305                  1 == differential
306                  2 == pseudo-differential
307   options[3]   Analog input range configuration
308                  0 == bipolar 5  (-5V -- +5V)
309                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
310                  2 == unipolar 5V  (0V -- +5V)
311   options[4]   Analog output 0 range configuration
312                  0 == bipolar 5  (-5V -- +5V)
313                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
314                  2 == unipolar 5V  (0V -- +5V)
315   options[5]   Analog output 1 range configuration
316                  0 == bipolar 5  (-5V -- +5V)
317                  1 == bipolar 2.5V  (-2.5V -- +2.5V)
318                  2 == unipolar 5V  (0V -- +5V)
319 */
320 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
321 {
322         /* int i; */
323         const struct dt2811_board *board = dev->board_ptr;
324         struct dt2811_private *devpriv;
325         int ret;
326         struct comedi_subdevice *s;
327
328         ret = comedi_request_region(dev, it->options[0], 0x8);
329         if (ret)
330                 return ret;
331
332 #if 0
333         outb(0, dev->iobase + DT2811_ADCSR);
334         udelay(100);
335         i = inb(dev->iobase + DT2811_ADDATLO);
336         i = inb(dev->iobase + DT2811_ADDATHI);
337 #endif
338
339         ret = comedi_alloc_subdevices(dev, 4);
340         if (ret)
341                 return ret;
342
343         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
344         if (!devpriv)
345                 return -ENOMEM;
346
347         switch (it->options[2]) {
348         case 0:
349                 devpriv->adc_mux = adc_singleended;
350                 break;
351         case 1:
352                 devpriv->adc_mux = adc_diff;
353                 break;
354         case 2:
355                 devpriv->adc_mux = adc_pseudo_diff;
356                 break;
357         default:
358                 devpriv->adc_mux = adc_singleended;
359                 break;
360         }
361         switch (it->options[4]) {
362         case 0:
363                 devpriv->dac_range[0] = dac_bipolar_5;
364                 break;
365         case 1:
366                 devpriv->dac_range[0] = dac_bipolar_2_5;
367                 break;
368         case 2:
369                 devpriv->dac_range[0] = dac_unipolar_5;
370                 break;
371         default:
372                 devpriv->dac_range[0] = dac_bipolar_5;
373                 break;
374         }
375         switch (it->options[5]) {
376         case 0:
377                 devpriv->dac_range[1] = dac_bipolar_5;
378                 break;
379         case 1:
380                 devpriv->dac_range[1] = dac_bipolar_2_5;
381                 break;
382         case 2:
383                 devpriv->dac_range[1] = dac_unipolar_5;
384                 break;
385         default:
386                 devpriv->dac_range[1] = dac_bipolar_5;
387                 break;
388         }
389
390         s = &dev->subdevices[0];
391         /* initialize the ADC subdevice */
392         s->type = COMEDI_SUBD_AI;
393         s->subdev_flags = SDF_READABLE | SDF_GROUND;
394         s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
395         s->insn_read = dt2811_ai_insn;
396         s->maxdata = 0xfff;
397         switch (it->options[3]) {
398         case 0:
399         default:
400                 s->range_table = board->bip_5;
401                 break;
402         case 1:
403                 s->range_table = board->bip_2_5;
404                 break;
405         case 2:
406                 s->range_table = board->unip_5;
407                 break;
408         }
409
410         s = &dev->subdevices[1];
411         /* ao subdevice */
412         s->type = COMEDI_SUBD_AO;
413         s->subdev_flags = SDF_WRITABLE;
414         s->n_chan = 2;
415         s->maxdata = 0xfff;
416         s->range_table_list = devpriv->range_type_list;
417         devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
418         devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
419         s->insn_write = dt2811_ao_insn_write;
420
421         ret = comedi_alloc_subdev_readback(s);
422         if (ret)
423                 return ret;
424
425         s = &dev->subdevices[2];
426         /* di subdevice */
427         s->type = COMEDI_SUBD_DI;
428         s->subdev_flags = SDF_READABLE;
429         s->n_chan = 8;
430         s->insn_bits = dt2811_di_insn_bits;
431         s->maxdata = 1;
432         s->range_table = &range_digital;
433
434         s = &dev->subdevices[3];
435         /* do subdevice */
436         s->type = COMEDI_SUBD_DO;
437         s->subdev_flags = SDF_WRITABLE;
438         s->n_chan = 8;
439         s->insn_bits = dt2811_do_insn_bits;
440         s->maxdata = 1;
441         s->state = 0;
442         s->range_table = &range_digital;
443
444         return 0;
445 }
446
447 static const struct dt2811_board boardtypes[] = {
448         {
449                 .name           = "dt2811-pgh",
450                 .bip_5          = &range_dt2811_pgh_ai_5_bipolar,
451                 .bip_2_5        = &range_dt2811_pgh_ai_2_5_bipolar,
452                 .unip_5         = &range_dt2811_pgh_ai_5_unipolar,
453         }, {
454                 .name           = "dt2811-pgl",
455                 .bip_5          = &range_dt2811_pgl_ai_5_bipolar,
456                 .bip_2_5        = &range_dt2811_pgl_ai_2_5_bipolar,
457                 .unip_5         = &range_dt2811_pgl_ai_5_unipolar,
458         },
459 };
460
461 static struct comedi_driver dt2811_driver = {
462         .driver_name    = "dt2811",
463         .module         = THIS_MODULE,
464         .attach         = dt2811_attach,
465         .detach         = comedi_legacy_detach,
466         .board_name     = &boardtypes[0].name,
467         .num_names      = ARRAY_SIZE(boardtypes),
468         .offset         = sizeof(struct dt2811_board),
469 };
470 module_comedi_driver(dt2811_driver);
471
472 MODULE_AUTHOR("Comedi http://www.comedi.org");
473 MODULE_DESCRIPTION("Comedi low-level driver");
474 MODULE_LICENSE("GPL");