Merge 4.3-rc7 into staging-next
[linux-2.6-block.git] / drivers / staging / comedi / drivers / pcl730.c
CommitLineData
96a2d5f0
JLS
1/*
2 * comedi/drivers/pcl730.c
3 * Driver for Advantech PCL-730 and clones
4 * José Luis Sánchez
5 */
96a2d5f0 6
0ea0dcff
HS
7/*
8 * Driver: pcl730
9 * Description: Advantech PCL-730 (& compatibles)
835aa9aa
IA
10 * Devices: [Advantech] PCL-730 (pcl730), PCM-3730 (pcm3730), PCL-725 (pcl725),
11 * PCL-733 (pcl733), PCL-734 (pcl734),
12 * [ADLink] ACL-7130 (acl7130), ACL-7225b (acl7225b),
13 * [ICP] ISO-730 (iso730), P8R8-DIO (p8r8dio), P16R16-DIO (p16r16dio),
14 * [Diamond Systems] OPMM-1616-XT (opmm-1616-xt), PEARL-MM-P (pearl-mm-p),
15 * IR104-PBF (ir104-pbf),
0ea0dcff
HS
16 * Author: José Luis Sánchez (jsanchezv@teleline.es)
17 * Status: untested
18 *
19 * Configuration options:
20 * [0] - I/O port base
21 *
22 * Interrupts are not supported.
23 * The ACL-7130 card has an 8254 timer/counter not supported by this driver.
24 */
96a2d5f0 25
ce157f80 26#include <linux/module.h>
96a2d5f0
JLS
27#include "../comedidev.h"
28
145ff35b 29/*
08f81bf1 30 * Register map
145ff35b 31 *
08f81bf1
HS
32 * The register map varies slightly depending on the board type but
33 * all registers are 8-bit.
34 *
35 * The boardinfo 'io_range' is used to allow comedi to request the
36 * proper range required by the board.
37 *
38 * The comedi_subdevice 'private' data is used to pass the register
39 * offset to the (*insn_bits) functions to read/write the correct
40 * registers.
41 *
42 * The basic register mapping looks like this:
43 *
44 * BASE+0 Isolated outputs 0-7 (write) / inputs 0-7 (read)
45 * BASE+1 Isolated outputs 8-15 (write) / inputs 8-15 (read)
46 * BASE+2 TTL outputs 0-7 (write) / inputs 0-7 (read)
47 * BASE+3 TTL outputs 8-15 (write) / inputs 8-15 (read)
48 *
49 * The pcm3730 board does not have register BASE+1.
50 *
51 * The pcl725 and p8r8dio only have registers BASE+0 and BASE+1:
52 *
53 * BASE+0 Isolated outputs 0-7 (write) (read back on p8r8dio)
54 * BASE+1 Isolated inputs 0-7 (read)
55 *
56 * The acl7225b and p16r16dio boards have this register mapping:
57 *
58 * BASE+0 Isolated outputs 0-7 (write) (read back)
59 * BASE+1 Isolated outputs 8-15 (write) (read back)
60 * BASE+2 Isolated inputs 0-7 (read)
61 * BASE+3 Isolated inputs 8-15 (read)
62 *
63 * The pcl733 and pcl733 boards have this register mapping:
64 *
65 * BASE+0 Isolated outputs 0-7 (write) or inputs 0-7 (read)
66 * BASE+1 Isolated outputs 8-15 (write) or inputs 8-15 (read)
67 * BASE+2 Isolated outputs 16-23 (write) or inputs 16-23 (read)
68 * BASE+3 Isolated outputs 24-31 (write) or inputs 24-31 (read)
53030b13
HS
69 *
70 * The opmm-1616-xt board has this register mapping:
71 *
72 * BASE+0 Isolated outputs 0-7 (write) (read back)
73 * BASE+1 Isolated outputs 8-15 (write) (read back)
74 * BASE+2 Isolated inputs 0-7 (read)
75 * BASE+3 Isolated inputs 8-15 (read)
76 *
77 * These registers are not currently supported:
78 *
79 * BASE+2 Relay select register (write)
80 * BASE+3 Board reset control register (write)
81 * BASE+4 Interrupt control register (write)
82 * BASE+4 Change detect 7-0 status register (read)
83 * BASE+5 LED control register (write)
84 * BASE+5 Change detect 15-8 status register (read)
85 *
86 * The pearl-mm-p board has this register mapping:
87 *
88 * BASE+0 Isolated outputs 0-7 (write)
89 * BASE+1 Isolated outputs 8-15 (write)
757c1fa9
HS
90 *
91 * The ir104-pbf board has this register mapping:
92 *
93 * BASE+0 Isolated outputs 0-7 (write) (read back)
94 * BASE+1 Isolated outputs 8-15 (write) (read back)
95 * BASE+2 Isolated outputs 16-19 (write) (read back)
96 * BASE+4 Isolated inputs 0-7 (read)
97 * BASE+5 Isolated inputs 8-15 (read)
98 * BASE+6 Isolated inputs 16-19 (read)
145ff35b 99 */
96a2d5f0 100
292090dc 101struct pcl730_board {
145ff35b
HS
102 const char *name;
103 unsigned int io_range;
f68d07f0 104 unsigned is_pcl725:1;
207fb16d 105 unsigned is_acl7225b:1;
757c1fa9 106 unsigned is_ir104:1;
207fb16d 107 unsigned has_readback:1;
f68d07f0 108 unsigned has_ttl_io:1;
82e71174
HS
109 int n_subdevs;
110 int n_iso_out_chan;
111 int n_iso_in_chan;
f68d07f0 112 int n_ttl_chan;
292090dc
BP
113};
114
3e0d529c 115static const struct pcl730_board pcl730_boards[] = {
a32b885e
HS
116 {
117 .name = "pcl730",
118 .io_range = 0x04,
f68d07f0 119 .has_ttl_io = 1,
82e71174
HS
120 .n_subdevs = 4,
121 .n_iso_out_chan = 16,
122 .n_iso_in_chan = 16,
f68d07f0 123 .n_ttl_chan = 16,
a32b885e
HS
124 }, {
125 .name = "iso730",
126 .io_range = 0x04,
82e71174
HS
127 .n_subdevs = 4,
128 .n_iso_out_chan = 16,
129 .n_iso_in_chan = 16,
f68d07f0 130 .n_ttl_chan = 16,
a32b885e
HS
131 }, {
132 .name = "acl7130",
133 .io_range = 0x08,
f68d07f0 134 .has_ttl_io = 1,
82e71174
HS
135 .n_subdevs = 4,
136 .n_iso_out_chan = 16,
137 .n_iso_in_chan = 16,
f68d07f0 138 .n_ttl_chan = 16,
145ff35b
HS
139 }, {
140 .name = "pcm3730",
141 .io_range = 0x04,
f68d07f0 142 .has_ttl_io = 1,
82e71174
HS
143 .n_subdevs = 4,
144 .n_iso_out_chan = 8,
145 .n_iso_in_chan = 8,
f68d07f0
HS
146 .n_ttl_chan = 16,
147 }, {
148 .name = "pcl725",
149 .io_range = 0x02,
150 .is_pcl725 = 1,
82e71174
HS
151 .n_subdevs = 2,
152 .n_iso_out_chan = 8,
153 .n_iso_in_chan = 8,
ef5838d9
HS
154 }, {
155 .name = "p8r8dio",
156 .io_range = 0x02,
157 .is_pcl725 = 1,
158 .has_readback = 1,
159 .n_subdevs = 2,
160 .n_iso_out_chan = 8,
161 .n_iso_in_chan = 8,
207fb16d
HS
162 }, {
163 .name = "acl7225b",
164 .io_range = 0x08, /* only 4 are used */
165 .is_acl7225b = 1,
166 .has_readback = 1,
167 .n_subdevs = 2,
168 .n_iso_out_chan = 16,
169 .n_iso_in_chan = 16,
170 }, {
171 .name = "p16r16dio",
172 .io_range = 0x04,
173 .is_acl7225b = 1,
174 .has_readback = 1,
175 .n_subdevs = 2,
176 .n_iso_out_chan = 16,
177 .n_iso_in_chan = 16,
82e71174
HS
178 }, {
179 .name = "pcl733",
180 .io_range = 0x04,
181 .n_subdevs = 1,
182 .n_iso_in_chan = 32,
85a17285
HS
183 }, {
184 .name = "pcl734",
185 .io_range = 0x04,
186 .n_subdevs = 1,
187 .n_iso_out_chan = 32,
53030b13
HS
188 }, {
189 .name = "opmm-1616-xt",
190 .io_range = 0x10,
191 .is_acl7225b = 1,
192 .has_readback = 1,
193 .n_subdevs = 2,
194 .n_iso_out_chan = 16,
195 .n_iso_in_chan = 16,
196 }, {
197 .name = "pearl-mm-p",
198 .io_range = 0x02,
199 .n_subdevs = 1,
200 .n_iso_out_chan = 16,
757c1fa9
HS
201 }, {
202 .name = "ir104-pbf",
203 .io_range = 0x08,
204 .is_ir104 = 1,
205 .has_readback = 1,
206 .n_iso_out_chan = 20,
207 .n_iso_in_chan = 20,
a32b885e
HS
208 },
209};
210
d015d961
HS
211static int pcl730_do_insn_bits(struct comedi_device *dev,
212 struct comedi_subdevice *s,
213 struct comedi_insn *insn,
214 unsigned int *data)
96a2d5f0 215{
d015d961 216 unsigned long reg = (unsigned long)s->private;
b3ff824a 217 unsigned int mask;
d015d961 218
b3ff824a 219 mask = comedi_dio_update_state(s, data);
d015d961 220 if (mask) {
d015d961
HS
221 if (mask & 0x00ff)
222 outb(s->state & 0xff, dev->iobase + reg);
9382c06e 223 if ((mask & 0xff00) && (s->n_chan > 8))
d015d961 224 outb((s->state >> 8) & 0xff, dev->iobase + reg + 1);
9382c06e 225 if ((mask & 0xff0000) && (s->n_chan > 16))
85a17285 226 outb((s->state >> 16) & 0xff, dev->iobase + reg + 2);
9382c06e 227 if ((mask & 0xff000000) && (s->n_chan > 24))
85a17285 228 outb((s->state >> 24) & 0xff, dev->iobase + reg + 3);
96a2d5f0 229 }
96a2d5f0
JLS
230
231 data[1] = s->state;
232
a2714e3e 233 return insn->n;
96a2d5f0
JLS
234}
235
82e71174
HS
236static unsigned int pcl730_get_bits(struct comedi_device *dev,
237 struct comedi_subdevice *s)
96a2d5f0 238{
74f14a58 239 unsigned long reg = (unsigned long)s->private;
145ff35b
HS
240 unsigned int val;
241
242 val = inb(dev->iobase + reg);
243 if (s->n_chan > 8)
244 val |= (inb(dev->iobase + reg + 1) << 8);
82e71174
HS
245 if (s->n_chan > 16)
246 val |= (inb(dev->iobase + reg + 2) << 16);
247 if (s->n_chan > 24)
248 val |= (inb(dev->iobase + reg + 3) << 24);
249
250 return val;
251}
74f14a58 252
82e71174
HS
253static int pcl730_di_insn_bits(struct comedi_device *dev,
254 struct comedi_subdevice *s,
255 struct comedi_insn *insn,
256 unsigned int *data)
257{
258 data[1] = pcl730_get_bits(dev, s);
96a2d5f0 259
a2714e3e 260 return insn->n;
96a2d5f0
JLS
261}
262
293d5671
HS
263static int pcl730_attach(struct comedi_device *dev,
264 struct comedi_devconfig *it)
96a2d5f0 265{
81fec905 266 const struct pcl730_board *board = dev->board_ptr;
34c43922 267 struct comedi_subdevice *s;
82e71174 268 int subdev;
8b6c5694 269 int ret;
96a2d5f0 270
6f9aa29b
HS
271 ret = comedi_request_region(dev, it->options[0], board->io_range);
272 if (ret)
273 return ret;
96a2d5f0 274
82e71174 275 ret = comedi_alloc_subdevices(dev, board->n_subdevs);
8b6c5694
HS
276 if (ret)
277 return ret;
96a2d5f0 278
82e71174
HS
279 subdev = 0;
280
281 if (board->n_iso_out_chan) {
282 /* Isolated Digital Outputs */
283 s = &dev->subdevices[subdev++];
284 s->type = COMEDI_SUBD_DO;
285 s->subdev_flags = SDF_WRITABLE;
286 s->n_chan = board->n_iso_out_chan;
287 s->maxdata = 1;
288 s->range_table = &range_digital;
289 s->insn_bits = pcl730_do_insn_bits;
08f81bf1 290 s->private = (void *)0;
207fb16d
HS
291
292 /* get the initial state if supported */
293 if (board->has_readback)
294 s->state = pcl730_get_bits(dev, s);
82e71174
HS
295 }
296
297 if (board->n_iso_in_chan) {
298 /* Isolated Digital Inputs */
299 s = &dev->subdevices[subdev++];
300 s->type = COMEDI_SUBD_DI;
301 s->subdev_flags = SDF_READABLE;
302 s->n_chan = board->n_iso_in_chan;
303 s->maxdata = 1;
304 s->range_table = &range_digital;
305 s->insn_bits = pcl730_di_insn_bits;
f14b6226 306 s->private = board->is_ir104 ? (void *)4 :
757c1fa9 307 board->is_acl7225b ? (void *)2 :
08f81bf1 308 board->is_pcl725 ? (void *)1 : (void *)0;
82e71174 309 }
f68d07f0
HS
310
311 if (board->has_ttl_io) {
312 /* TTL Digital Outputs */
82e71174 313 s = &dev->subdevices[subdev++];
f68d07f0
HS
314 s->type = COMEDI_SUBD_DO;
315 s->subdev_flags = SDF_WRITABLE;
316 s->n_chan = board->n_ttl_chan;
317 s->maxdata = 1;
318 s->range_table = &range_digital;
319 s->insn_bits = pcl730_do_insn_bits;
08f81bf1 320 s->private = (void *)2;
f68d07f0
HS
321
322 /* TTL Digital Inputs */
82e71174 323 s = &dev->subdevices[subdev++];
f68d07f0
HS
324 s->type = COMEDI_SUBD_DI;
325 s->subdev_flags = SDF_READABLE;
326 s->n_chan = board->n_ttl_chan;
327 s->maxdata = 1;
328 s->range_table = &range_digital;
329 s->insn_bits = pcl730_di_insn_bits;
08f81bf1 330 s->private = (void *)2;
f68d07f0 331 }
96a2d5f0
JLS
332
333 return 0;
334}
335
294f930d 336static struct comedi_driver pcl730_driver = {
4c6dacbd
HS
337 .driver_name = "pcl730",
338 .module = THIS_MODULE,
339 .attach = pcl730_attach,
21208519 340 .detach = comedi_legacy_detach,
3e0d529c
HS
341 .board_name = &pcl730_boards[0].name,
342 .num_names = ARRAY_SIZE(pcl730_boards),
4c6dacbd
HS
343 .offset = sizeof(struct pcl730_board),
344};
294f930d 345module_comedi_driver(pcl730_driver);
4c6dacbd 346
90f703d3
AT
347MODULE_AUTHOR("Comedi http://www.comedi.org");
348MODULE_DESCRIPTION("Comedi low-level driver");
349MODULE_LICENSE("GPL");