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