RT-AC56 3.0.0.4.374.37 core
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / staging / comedi / drivers / dt2811.c
blob30786a944eb8c179b8a1e4f15d595550d805cb20
1 /*
2 comedi/drivers/dt2811.c
3 Hardware driver for Data Translation DT2811
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 ...
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.
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.
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.
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
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)
48 #include <linux/interrupt.h>
49 #include "../comedidev.h"
51 #include <linux/ioport.h>
53 static const char *driver_name = "dt2811";
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)
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)
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)
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)
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)
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)
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
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
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
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
148 0x04,0x05 (W) DADAT0 D/A Data Register 1
150 0x06 (R) DIO0 Digital Input Port 0
151 (W) DIO1 Digital Output Port 1
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
178 #define TIMEOUT 10000
180 #define DT2811_SIZE 8
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
194 * flags
197 /* ADCSR */
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
206 struct dt2811_board {
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;
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,
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,
227 #define this_board ((const struct dt2811_board *)dev->board_ptr)
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),
242 static int __init driver_dt2811_init_module(void)
244 return comedi_driver_register(&driver_dt2811);
247 static void __exit driver_dt2811_cleanup_module(void)
249 comedi_driver_unregister(&driver_dt2811);
252 module_init(driver_dt2811_init_module);
253 module_exit(driver_dt2811_cleanup_module);
255 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
256 struct comedi_insn *insn, unsigned int *data);
257 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
258 struct comedi_insn *insn, unsigned int *data);
259 static int dt2811_ao_insn_read(struct comedi_device *dev,
260 struct comedi_subdevice *s,
261 struct comedi_insn *insn, unsigned int *data);
262 static int dt2811_di_insn_bits(struct comedi_device *dev,
263 struct comedi_subdevice *s,
264 struct comedi_insn *insn, unsigned int *data);
265 static int dt2811_do_insn_bits(struct comedi_device *dev,
266 struct comedi_subdevice *s,
267 struct comedi_insn *insn, unsigned int *data);
269 enum { card_2811_pgh, card_2811_pgl };
271 struct dt2811_private {
272 int ntrig;
273 int curadchan;
274 enum {
275 adc_singleended, adc_diff, adc_pseudo_diff
276 } adc_mux;
277 enum {
278 dac_bipolar_5, dac_bipolar_2_5, dac_unipolar_5
279 } dac_range[2];
280 const struct comedi_lrange *range_type_list[2];
281 unsigned int ao_readback[2];
284 #define devpriv ((struct dt2811_private *)dev->private)
286 static const struct comedi_lrange *dac_range_types[] = {
287 &range_bipolar5,
288 &range_bipolar2_5,
289 &range_unipolar5
292 #define DT2811_TIMEOUT 5
296 options[0] Board base address
297 options[1] IRQ
298 options[2] Input configuration
299 0 == single-ended
300 1 == differential
301 2 == pseudo-differential
302 options[3] Analog input range configuration
303 0 == bipolar 5 (-5V -- +5V)
304 1 == bipolar 2.5V (-2.5V -- +2.5V)
305 2 == unipolar 5V (0V -- +5V)
306 options[4] Analog output 0 range configuration
307 0 == bipolar 5 (-5V -- +5V)
308 1 == bipolar 2.5V (-2.5V -- +2.5V)
309 2 == unipolar 5V (0V -- +5V)
310 options[5] Analog output 1 range configuration
311 0 == bipolar 5 (-5V -- +5V)
312 1 == bipolar 2.5V (-2.5V -- +2.5V)
313 2 == unipolar 5V (0V -- +5V)
316 static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it)
318 /* int i, irq; */
319 /* unsigned long irqs; */
320 /* long flags; */
322 int ret;
323 struct comedi_subdevice *s;
324 unsigned long iobase;
326 iobase = it->options[0];
328 printk(KERN_INFO "comedi%d: dt2811:base=0x%04lx\n", dev->minor, iobase);
330 if (!request_region(iobase, DT2811_SIZE, driver_name)) {
331 printk(KERN_ERR "I/O port conflict\n");
332 return -EIO;
335 dev->iobase = iobase;
336 dev->board_name = this_board->name;
340 ret = alloc_subdevices(dev, 4);
341 if (ret < 0)
342 return ret;
344 ret = alloc_private(dev, sizeof(struct dt2811_private));
345 if (ret < 0)
346 return ret;
348 switch (it->options[2]) {
349 case 0:
350 devpriv->adc_mux = adc_singleended;
351 break;
352 case 1:
353 devpriv->adc_mux = adc_diff;
354 break;
355 case 2:
356 devpriv->adc_mux = adc_pseudo_diff;
357 break;
358 default:
359 devpriv->adc_mux = adc_singleended;
360 break;
362 switch (it->options[4]) {
363 case 0:
364 devpriv->dac_range[0] = dac_bipolar_5;
365 break;
366 case 1:
367 devpriv->dac_range[0] = dac_bipolar_2_5;
368 break;
369 case 2:
370 devpriv->dac_range[0] = dac_unipolar_5;
371 break;
372 default:
373 devpriv->dac_range[0] = dac_bipolar_5;
374 break;
376 switch (it->options[5]) {
377 case 0:
378 devpriv->dac_range[1] = dac_bipolar_5;
379 break;
380 case 1:
381 devpriv->dac_range[1] = dac_bipolar_2_5;
382 break;
383 case 2:
384 devpriv->dac_range[1] = dac_unipolar_5;
385 break;
386 default:
387 devpriv->dac_range[1] = dac_bipolar_5;
388 break;
391 s = dev->subdevices + 0;
392 /* initialize the ADC subdevice */
393 s->type = COMEDI_SUBD_AI;
394 s->subdev_flags = SDF_READABLE | SDF_GROUND;
395 s->n_chan = devpriv->adc_mux == adc_diff ? 8 : 16;
396 s->insn_read = dt2811_ai_insn;
397 s->maxdata = 0xfff;
398 switch (it->options[3]) {
399 case 0:
400 default:
401 s->range_table = this_board->bip_5;
402 break;
403 case 1:
404 s->range_table = this_board->bip_2_5;
405 break;
406 case 2:
407 s->range_table = this_board->unip_5;
408 break;
411 s = dev->subdevices + 1;
412 /* ao subdevice */
413 s->type = COMEDI_SUBD_AO;
414 s->subdev_flags = SDF_WRITABLE;
415 s->n_chan = 2;
416 s->insn_write = dt2811_ao_insn;
417 s->insn_read = dt2811_ao_insn_read;
418 s->maxdata = 0xfff;
419 s->range_table_list = devpriv->range_type_list;
420 devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]];
421 devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]];
423 s = dev->subdevices + 2;
424 /* di subdevice */
425 s->type = COMEDI_SUBD_DI;
426 s->subdev_flags = SDF_READABLE;
427 s->n_chan = 8;
428 s->insn_bits = dt2811_di_insn_bits;
429 s->maxdata = 1;
430 s->range_table = &range_digital;
432 s = dev->subdevices + 3;
433 /* do subdevice */
434 s->type = COMEDI_SUBD_DO;
435 s->subdev_flags = SDF_WRITABLE;
436 s->n_chan = 8;
437 s->insn_bits = dt2811_do_insn_bits;
438 s->maxdata = 1;
439 s->state = 0;
440 s->range_table = &range_digital;
442 return 0;
445 static int dt2811_detach(struct comedi_device *dev)
447 printk(KERN_INFO "comedi%d: dt2811: remove\n", dev->minor);
449 if (dev->irq)
450 free_irq(dev->irq, dev);
451 if (dev->iobase)
452 release_region(dev->iobase, DT2811_SIZE);
454 return 0;
457 static int dt2811_ai_insn(struct comedi_device *dev, struct comedi_subdevice *s,
458 struct comedi_insn *insn, unsigned int *data)
460 int chan = CR_CHAN(insn->chanspec);
461 int timeout = DT2811_TIMEOUT;
462 int i;
464 for (i = 0; i < insn->n; i++) {
465 outb(chan, dev->iobase + DT2811_ADGCR);
467 while (timeout
468 && inb(dev->iobase + DT2811_ADCSR) & DT2811_ADBUSY)
469 timeout--;
470 if (!timeout)
471 return -ETIME;
473 data[i] = inb(dev->iobase + DT2811_ADDATLO);
474 data[i] |= inb(dev->iobase + DT2811_ADDATHI) << 8;
475 data[i] &= 0xfff;
478 return i;
482 static int dt2811_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
483 struct comedi_insn *insn, unsigned int *data)
485 int i;
486 int chan;
488 chan = CR_CHAN(insn->chanspec);
490 for (i = 0; i < insn->n; i++) {
491 outb(data[i] & 0xff, dev->iobase + DT2811_DADAT0LO + 2 * chan);
492 outb((data[i] >> 8) & 0xff,
493 dev->iobase + DT2811_DADAT0HI + 2 * chan);
494 devpriv->ao_readback[chan] = data[i];
497 return i;
500 static int dt2811_ao_insn_read(struct comedi_device *dev,
501 struct comedi_subdevice *s,
502 struct comedi_insn *insn, unsigned int *data)
504 int i;
505 int chan;
507 chan = CR_CHAN(insn->chanspec);
509 for (i = 0; i < insn->n; i++)
510 data[i] = devpriv->ao_readback[chan];
512 return i;
515 static int dt2811_di_insn_bits(struct comedi_device *dev,
516 struct comedi_subdevice *s,
517 struct comedi_insn *insn, unsigned int *data)
519 if (insn->n != 2)
520 return -EINVAL;
522 data[1] = inb(dev->iobase + DT2811_DIO);
524 return 2;
527 static int dt2811_do_insn_bits(struct comedi_device *dev,
528 struct comedi_subdevice *s,
529 struct comedi_insn *insn, unsigned int *data)
531 if (insn->n != 2)
532 return -EINVAL;
534 s->state &= ~data[0];
535 s->state |= data[0] & data[1];
536 outb(s->state, dev->iobase + DT2811_DIO);
538 data[1] = s->state;
540 return 2;
543 MODULE_AUTHOR("Comedi http://www.comedi.org");
544 MODULE_DESCRIPTION("Comedi low-level driver");
545 MODULE_LICENSE("GPL");