Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / fl512.c
1 /*
2  * fl512.c
3  * Anders Gnistrup <ex18@kalman.iau.dtu.dk>
4  *
5  * COMEDI - Linux Control and Measurement Device Interface
6  * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  */
18
19 /*
20  * Driver: fl512
21  * Description: unknown
22  * Author: Anders Gnistrup <ex18@kalman.iau.dtu.dk>
23  * Devices: [unknown] FL512 (fl512)
24  * Status: unknown
25  *
26  * Digital I/O is not supported.
27  *
28  * Configuration options:
29  *   [0] - I/O port base address
30  */
31
32 #include <linux/module.h>
33 #include "../comedidev.h"
34
35 #include <linux/delay.h>
36
37 /*
38  * Register I/O map
39  */
40 #define FL512_AI_LSB_REG                0x02
41 #define FL512_AI_MSB_REG                0x03
42 #define FL512_AI_MUX_REG                0x02
43 #define FL512_AI_START_CONV_REG         0x03
44 #define FL512_AO_DATA_REG(x)            (0x04 + ((x) * 2))
45 #define FL512_AO_TRIG_REG(x)            (0x04 + ((x) * 2))
46
47 static const struct comedi_lrange range_fl512 = {
48         4, {
49                 BIP_RANGE(0.5),
50                 BIP_RANGE(1),
51                 BIP_RANGE(5),
52                 BIP_RANGE(10),
53                 UNI_RANGE(1),
54                 UNI_RANGE(5),
55                 UNI_RANGE(10)
56         }
57 };
58
59 static int fl512_ai_insn_read(struct comedi_device *dev,
60                               struct comedi_subdevice *s,
61                               struct comedi_insn *insn,
62                               unsigned int *data)
63 {
64         unsigned int chan = CR_CHAN(insn->chanspec);
65         unsigned int val;
66         int i;
67
68         outb(chan, dev->iobase + FL512_AI_MUX_REG);
69
70         for (i = 0; i < insn->n; i++) {
71                 outb(0, dev->iobase + FL512_AI_START_CONV_REG);
72
73                 /* XXX should test "done" flag instead of delay */
74                 udelay(30);
75
76                 val = inb(dev->iobase + FL512_AI_LSB_REG);
77                 val |= (inb(dev->iobase + FL512_AI_MSB_REG) << 8);
78                 val &= s->maxdata;
79
80                 data[i] = val;
81         }
82
83         return insn->n;
84 }
85
86 static int fl512_ao_insn_write(struct comedi_device *dev,
87                                struct comedi_subdevice *s,
88                                struct comedi_insn *insn,
89                                unsigned int *data)
90 {
91         unsigned int chan = CR_CHAN(insn->chanspec);
92         unsigned int val = s->readback[chan];
93         int i;
94
95         for (i = 0; i < insn->n; i++) {
96                 val = data[i];
97
98                 /* write LSB, MSB then trigger conversion */
99                 outb(val & 0x0ff, dev->iobase + FL512_AO_DATA_REG(chan));
100                 outb((val >> 8) & 0xf, dev->iobase + FL512_AO_DATA_REG(chan));
101                 inb(dev->iobase + FL512_AO_TRIG_REG(chan));
102         }
103         s->readback[chan] = val;
104
105         return insn->n;
106 }
107
108 static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it)
109 {
110         struct comedi_subdevice *s;
111         int ret;
112
113         ret = comedi_request_region(dev, it->options[0], 0x10);
114         if (ret)
115                 return ret;
116
117         ret = comedi_alloc_subdevices(dev, 2);
118         if (ret)
119                 return ret;
120
121         /* Analog Input subdevice */
122         s = &dev->subdevices[0];
123         s->type         = COMEDI_SUBD_AI;
124         s->subdev_flags = SDF_READABLE | SDF_GROUND;
125         s->n_chan       = 16;
126         s->maxdata      = 0x0fff;
127         s->range_table  = &range_fl512;
128         s->insn_read    = fl512_ai_insn_read;
129
130         /* Analog Output subdevice */
131         s = &dev->subdevices[1];
132         s->type         = COMEDI_SUBD_AO;
133         s->subdev_flags = SDF_WRITABLE;
134         s->n_chan       = 2;
135         s->maxdata      = 0x0fff;
136         s->range_table  = &range_fl512;
137         s->insn_write   = fl512_ao_insn_write;
138
139         ret = comedi_alloc_subdev_readback(s);
140         if (ret)
141                 return ret;
142
143         return 0;
144 }
145
146 static struct comedi_driver fl512_driver = {
147         .driver_name    = "fl512",
148         .module         = THIS_MODULE,
149         .attach         = fl512_attach,
150         .detach         = comedi_legacy_detach,
151 };
152 module_comedi_driver(fl512_driver);
153
154 MODULE_AUTHOR("Comedi http://www.comedi.org");
155 MODULE_DESCRIPTION("Comedi low-level driver");
156 MODULE_LICENSE("GPL");