Staging: comedi: Remove lsampl_t and sampl_t typedefs
[GitHub/mt8127/android_kernel_alcatel_ttab.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
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)
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
99static const comedi_lrange range_rti800_ai_10_bipolar = { 4, {
100 BIP_RANGE(10),
101 BIP_RANGE(1),
102 BIP_RANGE(0.1),
103 BIP_RANGE(0.02)
104 }
105};
106static const comedi_lrange range_rti800_ai_5_bipolar = { 4, {
107 BIP_RANGE(5),
108 BIP_RANGE(0.5),
109 BIP_RANGE(0.05),
110 BIP_RANGE(0.01)
111 }
112};
113static const comedi_lrange range_rti800_ai_unipolar = { 4, {
114 UNI_RANGE(10),
115 UNI_RANGE(1),
116 UNI_RANGE(0.1),
117 UNI_RANGE(0.02)
118 }
119};
120
121typedef struct {
122 const char *name;
123 int has_ao;
124} boardtype;
125static const boardtype boardtypes[] = {
126 {"rti800", 0},
127 {"rti815", 1},
128};
129
130#define this_board ((const boardtype *)dev->board_ptr)
131
132static int rti800_attach(comedi_device * dev, comedi_devconfig * it);
133static int rti800_detach(comedi_device * dev);
134static comedi_driver driver_rti800 = {
135 driver_name:"rti800",
136 module:THIS_MODULE,
137 attach:rti800_attach,
138 detach:rti800_detach,
139 num_names:sizeof(boardtypes) / sizeof(boardtype),
140 board_name:&boardtypes[0].name,
141 offset:sizeof(boardtype),
142};
143
144COMEDI_INITCLEANUP(driver_rti800);
145
146static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG);
147
148typedef struct {
149 enum {
150 adc_diff, adc_pseudodiff, adc_singleended
151 } adc_mux;
152 enum {
153 adc_bipolar10, adc_bipolar5, adc_unipolar10
154 } adc_range;
155 enum {
156 adc_2comp, adc_straight
157 } adc_coding;
158 enum {
159 dac_bipolar10, dac_unipolar10
160 } dac0_range, dac1_range;
161 enum {
162 dac_2comp, dac_straight
163 } dac0_coding, dac1_coding;
164 const comedi_lrange *ao_range_type_list[2];
790c5541 165 unsigned int ao_readback[2];
fc59905e
DS
166 int muxgain_bits;
167} rti800_private;
168
169#define devpriv ((rti800_private *)dev->private)
170
171#define RTI800_TIMEOUT 100
172
173static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG)
174{
175 return IRQ_HANDLED;
176}
177
178// settling delay times in usec for different gains
179static const int gaindelay[] = { 10, 20, 40, 80 };
180
181static int rti800_ai_insn_read(comedi_device * dev, comedi_subdevice * s,
790c5541 182 comedi_insn * insn, unsigned int * data)
fc59905e
DS
183{
184 int i, t;
185 int status;
186 int chan = CR_CHAN(insn->chanspec);
187 unsigned gain = CR_RANGE(insn->chanspec);
188 unsigned muxgain_bits;
189
190 inb(dev->iobase + RTI800_ADCHI);
191 outb(0, dev->iobase + RTI800_CLRFLAGS);
192
193 muxgain_bits = chan | (gain << 5);
194 if (muxgain_bits != devpriv->muxgain_bits) {
195 devpriv->muxgain_bits = muxgain_bits;
196 outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN);
197 /* without a delay here, the RTI_OVERRUN bit
198 * gets set, and you will have an error. */
199 if (insn->n > 0) {
200 BUG_ON(gain >=
201 sizeof(gaindelay) / sizeof(gaindelay[0]));
202 comedi_udelay(gaindelay[gain]);
203 }
204 }
205
206 for (i = 0; i < insn->n; i++) {
207 outb(0, dev->iobase + RTI800_CONVERT);
208 for (t = RTI800_TIMEOUT; t; t--) {
209 status = inb(dev->iobase + RTI800_CSR);
210 if (status & RTI800_OVERRUN) {
211 rt_printk("rti800: a/d overrun\n");
212 outb(0, dev->iobase + RTI800_CLRFLAGS);
213 return -EIO;
214 }
215 if (status & RTI800_DONE)
216 break;
217 comedi_udelay(1);
218 }
219 if (t == 0) {
220 rt_printk("rti800: timeout\n");
221 return -ETIME;
222 }
223 data[i] = inb(dev->iobase + RTI800_ADCLO);
224 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
225
226 if (devpriv->adc_coding == adc_2comp) {
227 data[i] ^= 0x800;
228 }
229 }
230
231 return i;
232}
233
234static int rti800_ao_insn_read(comedi_device * dev, comedi_subdevice * s,
790c5541 235 comedi_insn * insn, unsigned int * data)
fc59905e
DS
236{
237 int i;
238 int chan = CR_CHAN(insn->chanspec);
239
240 for (i = 0; i < insn->n; i++)
241 data[i] = devpriv->ao_readback[chan];
242
243 return i;
244}
245
246static int rti800_ao_insn_write(comedi_device * dev, comedi_subdevice * s,
790c5541 247 comedi_insn * insn, unsigned int * data)
fc59905e
DS
248{
249 int chan = CR_CHAN(insn->chanspec);
250 int d;
251 int i;
252
253 for (i = 0; i < insn->n; i++) {
254 devpriv->ao_readback[chan] = d = data[i];
255 if (devpriv->dac0_coding == dac_2comp) {
256 d ^= 0x800;
257 }
258 outb(d & 0xff,
259 dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
260 outb(d >> 8,
261 dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI));
262 }
263 return i;
264}
265
266static int rti800_di_insn_bits(comedi_device * dev, comedi_subdevice * s,
790c5541 267 comedi_insn * insn, unsigned int * data)
fc59905e
DS
268{
269 if (insn->n != 2)
270 return -EINVAL;
271 data[1] = inb(dev->iobase + RTI800_DI);
272 return 2;
273}
274
275static int rti800_do_insn_bits(comedi_device * dev, comedi_subdevice * s,
790c5541 276 comedi_insn * insn, unsigned int * data)
fc59905e
DS
277{
278 if (insn->n != 2)
279 return -EINVAL;
280
281 if (data[0]) {
282 s->state &= ~data[0];
283 s->state |= data[0] & data[1];
284 /* Outputs are inverted... */
285 outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
286 }
287
288 data[1] = s->state;
289
290 return 2;
291}
292
293/*
294 options[0] - I/O port
295 options[1] - irq
296 options[2] - a/d mux
297 0=differential, 1=pseudodiff, 2=single
298 options[3] - a/d range
299 0=bipolar10, 1=bipolar5, 2=unipolar10
300 options[4] - a/d coding
301 0=2's comp, 1=straight binary
302 options[5] - dac0 range
303 0=bipolar10, 1=unipolar10
304 options[6] - dac0 coding
305 0=2's comp, 1=straight binary
306 options[7] - dac1 range
307 options[8] - dac1 coding
308 */
309
310static int rti800_attach(comedi_device * dev, comedi_devconfig * it)
311{
312 unsigned int irq;
313 unsigned long iobase;
314 int ret;
315 comedi_subdevice *s;
316
317 iobase = it->options[0];
318 printk("comedi%d: rti800: 0x%04lx ", dev->minor, iobase);
319 if (!request_region(iobase, RTI800_SIZE, "rti800")) {
320 printk("I/O port conflict\n");
321 return -EIO;
322 }
323 dev->iobase = iobase;
324
325#ifdef DEBUG
326 printk("fingerprint=%x,%x,%x,%x,%x ",
327 inb(dev->iobase + 0),
328 inb(dev->iobase + 1),
329 inb(dev->iobase + 2),
330 inb(dev->iobase + 3), inb(dev->iobase + 4));
331#endif
332
333 outb(0, dev->iobase + RTI800_CSR);
334 inb(dev->iobase + RTI800_ADCHI);
335 outb(0, dev->iobase + RTI800_CLRFLAGS);
336
337 irq = it->options[1];
338 if (irq) {
339 printk("( irq = %u )", irq);
340 if ((ret = comedi_request_irq(irq, rti800_interrupt, 0,
341 "rti800", dev)) < 0) {
342 printk(" Failed to allocate IRQ\n");
343 return ret;
344 }
345 dev->irq = irq;
346 } else {
347 printk("( no irq )");
348 }
349
350 dev->board_name = this_board->name;
351
352 if ((ret = alloc_subdevices(dev, 4)) < 0)
353 return ret;
354 if ((ret = alloc_private(dev, sizeof(rti800_private))) < 0)
355 return ret;
356
357 devpriv->adc_mux = it->options[2];
358 devpriv->adc_range = it->options[3];
359 devpriv->adc_coding = it->options[4];
360 devpriv->dac0_range = it->options[5];
361 devpriv->dac0_coding = it->options[6];
362 devpriv->dac1_range = it->options[7];
363 devpriv->dac1_coding = it->options[8];
364 devpriv->muxgain_bits = -1;
365
366 s = dev->subdevices + 0;
367 /* ai subdevice */
368 s->type = COMEDI_SUBD_AI;
369 s->subdev_flags = SDF_READABLE | SDF_GROUND;
370 s->n_chan = (devpriv->adc_mux ? 16 : 8);
371 s->insn_read = rti800_ai_insn_read;
372 s->maxdata = 0xfff;
373 switch (devpriv->adc_range) {
374 case adc_bipolar10:
375 s->range_table = &range_rti800_ai_10_bipolar;
376 break;
377 case adc_bipolar5:
378 s->range_table = &range_rti800_ai_5_bipolar;
379 break;
380 case adc_unipolar10:
381 s->range_table = &range_rti800_ai_unipolar;
382 break;
383 }
384
385 s++;
386 if (this_board->has_ao) {
387 /* ao subdevice (only on rti815) */
388 s->type = COMEDI_SUBD_AO;
389 s->subdev_flags = SDF_WRITABLE;
390 s->n_chan = 2;
391 s->insn_read = rti800_ao_insn_read;
392 s->insn_write = rti800_ao_insn_write;
393 s->maxdata = 0xfff;
394 s->range_table_list = devpriv->ao_range_type_list;
395 switch (devpriv->dac0_range) {
396 case dac_bipolar10:
397 devpriv->ao_range_type_list[0] = &range_bipolar10;
398 break;
399 case dac_unipolar10:
400 devpriv->ao_range_type_list[0] = &range_unipolar10;
401 break;
402 }
403 switch (devpriv->dac1_range) {
404 case dac_bipolar10:
405 devpriv->ao_range_type_list[1] = &range_bipolar10;
406 break;
407 case dac_unipolar10:
408 devpriv->ao_range_type_list[1] = &range_unipolar10;
409 break;
410 }
411 } else {
412 s->type = COMEDI_SUBD_UNUSED;
413 }
414
415 s++;
416 /* di */
417 s->type = COMEDI_SUBD_DI;
418 s->subdev_flags = SDF_READABLE;
419 s->n_chan = 8;
420 s->insn_bits = rti800_di_insn_bits;
421 s->maxdata = 1;
422 s->range_table = &range_digital;
423
424 s++;
425 /* do */
426 s->type = COMEDI_SUBD_DO;
427 s->subdev_flags = SDF_WRITABLE;
428 s->n_chan = 8;
429 s->insn_bits = rti800_do_insn_bits;
430 s->maxdata = 1;
431 s->range_table = &range_digital;
432
433/* don't yet know how to deal with counter/timers */
434#if 0
435 s++;
436 /* do */
437 s->type = COMEDI_SUBD_TIMER;
438#endif
439
440 printk("\n");
441
442 return 0;
443}
444
445static int rti800_detach(comedi_device * dev)
446{
447 printk("comedi%d: rti800: remove\n", dev->minor);
448
449 if (dev->iobase)
450 release_region(dev->iobase, RTI800_SIZE);
451
452 if (dev->irq)
453 comedi_free_irq(dev->irq, dev);
454
455 return 0;
456}