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