Staging: comedi: convert usbdux* to use firmware_request
[deliverable/linux.git] / drivers / staging / comedi / drivers / rti800.c
CommitLineData
fc59905e
DS
1/*
2 comedi/drivers/rti800.c
3 Hardware driver for Analog Devices RTI-800/815 board
4
5 COMEDI - Linux Control and Measurement Device Interface
6 Copyright (C) 1998 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 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22 */
23/*
24Driver: rti800
25Description: Analog Devices RTI-800/815
26Author: ds
27Status: unknown
28Updated: Fri, 05 Sep 2008 14:50:44 +0100
29Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
30
31Configuration options:
32 [0] - I/O port base address
33 [1] - IRQ
34 [2] - A/D reference
35 0 = differential
36 1 = pseudodifferential (common)
37 2 = single-ended
38 [3] - A/D range
39 0 = [-10,10]
40 1 = [-5,5]
41 2 = [0,10]
42 [4] - A/D encoding
43 0 = two's complement
44 1 = straight binary
45 [5] - DAC 0 range
46 0 = [-10,10]
47 1 = [0,10]
48 [6] - DAC 0 encoding
49 0 = two's complement
50 1 = straight binary
51 [7] - DAC 1 range (same as DAC 0)
52 [8] - DAC 1 encoding (same as DAC 0)
53*/
54
55#include "../comedidev.h"
56
57#include <linux/ioport.h>
58
59#define RTI800_SIZE 16
60
61#define RTI800_CSR 0
62#define RTI800_MUXGAIN 1
63#define RTI800_CONVERT 2
64#define RTI800_ADCLO 3
65#define RTI800_ADCHI 4
66#define RTI800_DAC0LO 5
67#define RTI800_DAC0HI 6
68#define RTI800_DAC1LO 7
69#define RTI800_DAC1HI 8
70#define RTI800_CLRFLAGS 9
71#define RTI800_DI 10
72#define RTI800_DO 11
73#define RTI800_9513A_DATA 12
74#define RTI800_9513A_CNTRL 13
75#define RTI800_9513A_STATUS 13
76
77/*
78 * flags for CSR register
79 */
80
81#define RTI800_BUSY 0x80
82#define RTI800_DONE 0x40
83#define RTI800_OVERRUN 0x20
84#define RTI800_TCR 0x10
85#define RTI800_DMA_ENAB 0x08
86#define RTI800_INTR_TC 0x04
87#define RTI800_INTR_EC 0x02
88#define RTI800_INTR_OVRN 0x01
89
90#define Am9513_8BITBUS
91
f7cbd7aa
BP
92#define Am9513_output_control(a) outb(a, dev->iobase+RTI800_9513A_CNTRL)
93#define Am9513_output_data(a) outb(a, dev->iobase+RTI800_9513A_DATA)
fc59905e
DS
94#define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA)
95#define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS)
96
97#include "am9513.h"
98
9ced1de6 99static const struct comedi_lrange range_rti800_ai_10_bipolar = { 4, {
fc59905e
DS
100 BIP_RANGE(10),
101 BIP_RANGE(1),
102 BIP_RANGE(0.1),
103 BIP_RANGE(0.02)
104 }
105};
9ced1de6 106static const struct comedi_lrange range_rti800_ai_5_bipolar = { 4, {
fc59905e
DS
107 BIP_RANGE(5),
108 BIP_RANGE(0.5),
109 BIP_RANGE(0.05),
110 BIP_RANGE(0.01)
111 }
112};
9ced1de6 113static const struct comedi_lrange range_rti800_ai_unipolar = { 4, {
fc59905e
DS
114 UNI_RANGE(10),
115 UNI_RANGE(1),
116 UNI_RANGE(0.1),
117 UNI_RANGE(0.02)
118 }
119};
120
1de6a6fd
BP
121struct rti800_board {
122
fc59905e
DS
123 const char *name;
124 int has_ao;
1de6a6fd
BP
125};
126
127static const struct rti800_board boardtypes[] = {
fc59905e
DS
128 {"rti800", 0},
129 {"rti815", 1},
130};
131
1de6a6fd 132#define this_board ((const struct rti800_board *)dev->board_ptr)
fc59905e 133
da91b269
BP
134static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it);
135static int rti800_detach(struct comedi_device *dev);
139dfbdf 136static struct comedi_driver driver_rti800 = {
68c3dbff
BP
137 .driver_name = "rti800",
138 .module = THIS_MODULE,
139 .attach = rti800_attach,
140 .detach = rti800_detach,
8629efa4 141 .num_names = ARRAY_SIZE(boardtypes),
68c3dbff
BP
142 .board_name = &boardtypes[0].name,
143 .offset = sizeof(struct rti800_board),
fc59905e
DS
144};
145
146COMEDI_INITCLEANUP(driver_rti800);
147
70265d24 148static irqreturn_t rti800_interrupt(int irq, void *dev);
fc59905e 149
9335f261 150struct rti800_private {
fc59905e
DS
151 enum {
152 adc_diff, adc_pseudodiff, adc_singleended
153 } adc_mux;
154 enum {
155 adc_bipolar10, adc_bipolar5, adc_unipolar10
156 } adc_range;
157 enum {
158 adc_2comp, adc_straight
159 } adc_coding;
160 enum {
161 dac_bipolar10, dac_unipolar10
162 } dac0_range, dac1_range;
163 enum {
164 dac_2comp, dac_straight
165 } dac0_coding, dac1_coding;
9ced1de6 166 const struct comedi_lrange *ao_range_type_list[2];
790c5541 167 unsigned int ao_readback[2];
fc59905e 168 int muxgain_bits;
9335f261 169};
fc59905e 170
9335f261 171#define devpriv ((struct rti800_private *)dev->private)
fc59905e
DS
172
173#define RTI800_TIMEOUT 100
174
70265d24 175static irqreturn_t rti800_interrupt(int irq, void *dev)
fc59905e
DS
176{
177 return IRQ_HANDLED;
178}
179
2696fb57 180/* settling delay times in usec for different gains */
fc59905e
DS
181static const int gaindelay[] = { 10, 20, 40, 80 };
182
da91b269
BP
183static int rti800_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
184 struct comedi_insn *insn, unsigned int *data)
fc59905e
DS
185{
186 int i, t;
187 int status;
188 int chan = CR_CHAN(insn->chanspec);
189 unsigned gain = CR_RANGE(insn->chanspec);
190 unsigned muxgain_bits;
191
192 inb(dev->iobase + RTI800_ADCHI);
193 outb(0, dev->iobase + RTI800_CLRFLAGS);
194
195 muxgain_bits = chan | (gain << 5);
196 if (muxgain_bits != devpriv->muxgain_bits) {
197 devpriv->muxgain_bits = muxgain_bits;
198 outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN);
199 /* without a delay here, the RTI_OVERRUN bit
200 * gets set, and you will have an error. */
201 if (insn->n > 0) {
8629efa4 202 BUG_ON(gain >= ARRAY_SIZE(gaindelay));
fc59905e
DS
203 comedi_udelay(gaindelay[gain]);
204 }
205 }
206
207 for (i = 0; i < insn->n; i++) {
208 outb(0, dev->iobase + RTI800_CONVERT);
209 for (t = RTI800_TIMEOUT; t; t--) {
210 status = inb(dev->iobase + RTI800_CSR);
211 if (status & RTI800_OVERRUN) {
212 rt_printk("rti800: a/d overrun\n");
213 outb(0, dev->iobase + RTI800_CLRFLAGS);
214 return -EIO;
215 }
216 if (status & RTI800_DONE)
217 break;
218 comedi_udelay(1);
219 }
220 if (t == 0) {
221 rt_printk("rti800: timeout\n");
222 return -ETIME;
223 }
224 data[i] = inb(dev->iobase + RTI800_ADCLO);
225 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
226
227 if (devpriv->adc_coding == adc_2comp) {
228 data[i] ^= 0x800;
229 }
230 }
231
232 return i;
233}
234
da91b269
BP
235static int rti800_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s,
236 struct comedi_insn *insn, unsigned int *data)
fc59905e
DS
237{
238 int i;
239 int chan = CR_CHAN(insn->chanspec);
240
241 for (i = 0; i < insn->n; i++)
242 data[i] = devpriv->ao_readback[chan];
243
244 return i;
245}
246
da91b269
BP
247static int rti800_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s,
248 struct comedi_insn *insn, unsigned int *data)
fc59905e
DS
249{
250 int chan = CR_CHAN(insn->chanspec);
251 int d;
252 int i;
253
254 for (i = 0; i < insn->n; i++) {
255 devpriv->ao_readback[chan] = d = data[i];
256 if (devpriv->dac0_coding == dac_2comp) {
257 d ^= 0x800;
258 }
259 outb(d & 0xff,
260 dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
261 outb(d >> 8,
262 dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI));
263 }
264 return i;
265}
266
da91b269
BP
267static int rti800_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
268 struct comedi_insn *insn, unsigned int *data)
fc59905e
DS
269{
270 if (insn->n != 2)
271 return -EINVAL;
272 data[1] = inb(dev->iobase + RTI800_DI);
273 return 2;
274}
275
da91b269
BP
276static int rti800_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s,
277 struct comedi_insn *insn, unsigned int *data)
fc59905e
DS
278{
279 if (insn->n != 2)
280 return -EINVAL;
281
282 if (data[0]) {
283 s->state &= ~data[0];
284 s->state |= data[0] & data[1];
285 /* Outputs are inverted... */
286 outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
287 }
288
289 data[1] = s->state;
290
291 return 2;
292}
293
294/*
295 options[0] - I/O port
296 options[1] - irq
297 options[2] - a/d mux
298 0=differential, 1=pseudodiff, 2=single
299 options[3] - a/d range
300 0=bipolar10, 1=bipolar5, 2=unipolar10
301 options[4] - a/d coding
302 0=2's comp, 1=straight binary
303 options[5] - dac0 range
304 0=bipolar10, 1=unipolar10
305 options[6] - dac0 coding
306 0=2's comp, 1=straight binary
307 options[7] - dac1 range
308 options[8] - dac1 coding
309 */
310
da91b269 311static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
fc59905e
DS
312{
313 unsigned int irq;
314 unsigned long iobase;
315 int ret;
34c43922 316 struct comedi_subdevice *s;
fc59905e
DS
317
318 iobase = it->options[0];
319 printk("comedi%d: rti800: 0x%04lx ", dev->minor, iobase);
320 if (!request_region(iobase, RTI800_SIZE, "rti800")) {
321 printk("I/O port conflict\n");
322 return -EIO;
323 }
324 dev->iobase = iobase;
325
326#ifdef DEBUG
327 printk("fingerprint=%x,%x,%x,%x,%x ",
328 inb(dev->iobase + 0),
329 inb(dev->iobase + 1),
330 inb(dev->iobase + 2),
331 inb(dev->iobase + 3), inb(dev->iobase + 4));
332#endif
333
334 outb(0, dev->iobase + RTI800_CSR);
335 inb(dev->iobase + RTI800_ADCHI);
336 outb(0, dev->iobase + RTI800_CLRFLAGS);
337
338 irq = it->options[1];
339 if (irq) {
340 printk("( irq = %u )", irq);
c3744138
BP
341 ret = comedi_request_irq(irq, rti800_interrupt, 0,
342 "rti800", dev);
343 if (ret < 0) {
fc59905e
DS
344 printk(" Failed to allocate IRQ\n");
345 return ret;
346 }
347 dev->irq = irq;
348 } else {
349 printk("( no irq )");
350 }
351
352 dev->board_name = this_board->name;
353
c3744138
BP
354 ret = alloc_subdevices(dev, 4);
355 if (ret < 0)
fc59905e 356 return ret;
c3744138
BP
357
358 ret = alloc_private(dev, sizeof(struct rti800_private));
359 if (ret < 0)
fc59905e
DS
360 return ret;
361
362 devpriv->adc_mux = it->options[2];
363 devpriv->adc_range = it->options[3];
364 devpriv->adc_coding = it->options[4];
365 devpriv->dac0_range = it->options[5];
366 devpriv->dac0_coding = it->options[6];
367 devpriv->dac1_range = it->options[7];
368 devpriv->dac1_coding = it->options[8];
369 devpriv->muxgain_bits = -1;
370
371 s = dev->subdevices + 0;
372 /* ai subdevice */
373 s->type = COMEDI_SUBD_AI;
374 s->subdev_flags = SDF_READABLE | SDF_GROUND;
375 s->n_chan = (devpriv->adc_mux ? 16 : 8);
376 s->insn_read = rti800_ai_insn_read;
377 s->maxdata = 0xfff;
378 switch (devpriv->adc_range) {
379 case adc_bipolar10:
380 s->range_table = &range_rti800_ai_10_bipolar;
381 break;
382 case adc_bipolar5:
383 s->range_table = &range_rti800_ai_5_bipolar;
384 break;
385 case adc_unipolar10:
386 s->range_table = &range_rti800_ai_unipolar;
387 break;
388 }
389
390 s++;
391 if (this_board->has_ao) {
392 /* ao subdevice (only on rti815) */
393 s->type = COMEDI_SUBD_AO;
394 s->subdev_flags = SDF_WRITABLE;
395 s->n_chan = 2;
396 s->insn_read = rti800_ao_insn_read;
397 s->insn_write = rti800_ao_insn_write;
398 s->maxdata = 0xfff;
399 s->range_table_list = devpriv->ao_range_type_list;
400 switch (devpriv->dac0_range) {
401 case dac_bipolar10:
402 devpriv->ao_range_type_list[0] = &range_bipolar10;
403 break;
404 case dac_unipolar10:
405 devpriv->ao_range_type_list[0] = &range_unipolar10;
406 break;
407 }
408 switch (devpriv->dac1_range) {
409 case dac_bipolar10:
410 devpriv->ao_range_type_list[1] = &range_bipolar10;
411 break;
412 case dac_unipolar10:
413 devpriv->ao_range_type_list[1] = &range_unipolar10;
414 break;
415 }
416 } else {
417 s->type = COMEDI_SUBD_UNUSED;
418 }
419
420 s++;
421 /* di */
422 s->type = COMEDI_SUBD_DI;
423 s->subdev_flags = SDF_READABLE;
424 s->n_chan = 8;
425 s->insn_bits = rti800_di_insn_bits;
426 s->maxdata = 1;
427 s->range_table = &range_digital;
428
429 s++;
430 /* do */
431 s->type = COMEDI_SUBD_DO;
432 s->subdev_flags = SDF_WRITABLE;
433 s->n_chan = 8;
434 s->insn_bits = rti800_do_insn_bits;
435 s->maxdata = 1;
436 s->range_table = &range_digital;
437
438/* don't yet know how to deal with counter/timers */
439#if 0
440 s++;
441 /* do */
442 s->type = COMEDI_SUBD_TIMER;
443#endif
444
445 printk("\n");
446
447 return 0;
448}
449
da91b269 450static int rti800_detach(struct comedi_device *dev)
fc59905e
DS
451{
452 printk("comedi%d: rti800: remove\n", dev->minor);
453
454 if (dev->iobase)
455 release_region(dev->iobase, RTI800_SIZE);
456
457 if (dev->irq)
458 comedi_free_irq(dev->irq, dev);
459
460 return 0;
461}
This page took 0.079755 seconds and 5 git commands to generate.