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