Merge branch 'master' of git://git.kernel.org/pub/scm/fs/xfs/xfs
[pandora-kernel.git] / drivers / staging / comedi / drivers / rti800.c
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 /*
24 Driver: rti800
25 Description: Analog Devices RTI-800/815
26 Author: ds
27 Status: unknown
28 Updated: Fri, 05 Sep 2008 14:50:44 +0100
29 Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
30
31 Configuration 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
99 static const struct 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 };
106 static const struct 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 };
113 static const struct 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
121 struct rti800_board {
122
123         const char *name;
124         int has_ao;
125 };
126
127 static const struct rti800_board boardtypes[] = {
128         {"rti800", 0},
129         {"rti815", 1},
130 };
131
132 #define this_board ((const struct rti800_board *)dev->board_ptr)
133
134 static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * it);
135 static int rti800_detach(struct comedi_device * dev);
136 static struct comedi_driver driver_rti800 = {
137       driver_name:"rti800",
138       module:THIS_MODULE,
139       attach:rti800_attach,
140       detach:rti800_detach,
141       num_names:sizeof(boardtypes) / sizeof(struct rti800_board),
142       board_name:&boardtypes[0].name,
143       offset:sizeof(struct rti800_board),
144 };
145
146 COMEDI_INITCLEANUP(driver_rti800);
147
148 static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG);
149
150 struct rti800_private {
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;
166         const struct comedi_lrange *ao_range_type_list[2];
167         unsigned int ao_readback[2];
168         int muxgain_bits;
169 };
170
171 #define devpriv ((struct rti800_private *)dev->private)
172
173 #define RTI800_TIMEOUT 100
174
175 static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG)
176 {
177         return IRQ_HANDLED;
178 }
179
180 // settling delay times in usec for different gains
181 static const int gaindelay[] = { 10, 20, 40, 80 };
182
183 static int rti800_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
184         struct comedi_insn * insn, unsigned int * data)
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) {
202                         BUG_ON(gain >=
203                                 sizeof(gaindelay) / sizeof(gaindelay[0]));
204                         comedi_udelay(gaindelay[gain]);
205                 }
206         }
207
208         for (i = 0; i < insn->n; i++) {
209                 outb(0, dev->iobase + RTI800_CONVERT);
210                 for (t = RTI800_TIMEOUT; t; t--) {
211                         status = inb(dev->iobase + RTI800_CSR);
212                         if (status & RTI800_OVERRUN) {
213                                 rt_printk("rti800: a/d overrun\n");
214                                 outb(0, dev->iobase + RTI800_CLRFLAGS);
215                                 return -EIO;
216                         }
217                         if (status & RTI800_DONE)
218                                 break;
219                         comedi_udelay(1);
220                 }
221                 if (t == 0) {
222                         rt_printk("rti800: timeout\n");
223                         return -ETIME;
224                 }
225                 data[i] = inb(dev->iobase + RTI800_ADCLO);
226                 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8;
227
228                 if (devpriv->adc_coding == adc_2comp) {
229                         data[i] ^= 0x800;
230                 }
231         }
232
233         return i;
234 }
235
236 static int rti800_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s,
237         struct comedi_insn * insn, unsigned int * data)
238 {
239         int i;
240         int chan = CR_CHAN(insn->chanspec);
241
242         for (i = 0; i < insn->n; i++)
243                 data[i] = devpriv->ao_readback[chan];
244
245         return i;
246 }
247
248 static int rti800_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s,
249         struct comedi_insn * insn, unsigned int * data)
250 {
251         int chan = CR_CHAN(insn->chanspec);
252         int d;
253         int i;
254
255         for (i = 0; i < insn->n; i++) {
256                 devpriv->ao_readback[chan] = d = data[i];
257                 if (devpriv->dac0_coding == dac_2comp) {
258                         d ^= 0x800;
259                 }
260                 outb(d & 0xff,
261                         dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO));
262                 outb(d >> 8,
263                         dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI));
264         }
265         return i;
266 }
267
268 static int rti800_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
269         struct comedi_insn * insn, unsigned int * data)
270 {
271         if (insn->n != 2)
272                 return -EINVAL;
273         data[1] = inb(dev->iobase + RTI800_DI);
274         return 2;
275 }
276
277 static int rti800_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
278         struct comedi_insn * insn, unsigned int * data)
279 {
280         if (insn->n != 2)
281                 return -EINVAL;
282
283         if (data[0]) {
284                 s->state &= ~data[0];
285                 s->state |= data[0] & data[1];
286                 /* Outputs are inverted... */
287                 outb(s->state ^ 0xff, dev->iobase + RTI800_DO);
288         }
289
290         data[1] = s->state;
291
292         return 2;
293 }
294
295 /*
296    options[0] - I/O port
297    options[1] - irq
298    options[2] - a/d mux
299         0=differential, 1=pseudodiff, 2=single
300    options[3] - a/d range
301         0=bipolar10, 1=bipolar5, 2=unipolar10
302    options[4] - a/d coding
303         0=2's comp, 1=straight binary
304    options[5] - dac0 range
305         0=bipolar10, 1=unipolar10
306    options[6] - dac0 coding
307         0=2's comp, 1=straight binary
308    options[7] - dac1 range
309    options[8] - dac1 coding
310  */
311
312 static int rti800_attach(struct comedi_device * dev, struct comedi_devconfig * it)
313 {
314         unsigned int irq;
315         unsigned long iobase;
316         int ret;
317         struct comedi_subdevice *s;
318
319         iobase = it->options[0];
320         printk("comedi%d: rti800: 0x%04lx ", dev->minor, iobase);
321         if (!request_region(iobase, RTI800_SIZE, "rti800")) {
322                 printk("I/O port conflict\n");
323                 return -EIO;
324         }
325         dev->iobase = iobase;
326
327 #ifdef DEBUG
328         printk("fingerprint=%x,%x,%x,%x,%x ",
329                 inb(dev->iobase + 0),
330                 inb(dev->iobase + 1),
331                 inb(dev->iobase + 2),
332                 inb(dev->iobase + 3), inb(dev->iobase + 4));
333 #endif
334
335         outb(0, dev->iobase + RTI800_CSR);
336         inb(dev->iobase + RTI800_ADCHI);
337         outb(0, dev->iobase + RTI800_CLRFLAGS);
338
339         irq = it->options[1];
340         if (irq) {
341                 printk("( irq = %u )", irq);
342                 if ((ret = comedi_request_irq(irq, rti800_interrupt, 0,
343                                         "rti800", dev)) < 0) {
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
354         if ((ret = alloc_subdevices(dev, 4)) < 0)
355                 return ret;
356         if ((ret = alloc_private(dev, sizeof(struct rti800_private))) < 0)
357                 return ret;
358
359         devpriv->adc_mux = it->options[2];
360         devpriv->adc_range = it->options[3];
361         devpriv->adc_coding = it->options[4];
362         devpriv->dac0_range = it->options[5];
363         devpriv->dac0_coding = it->options[6];
364         devpriv->dac1_range = it->options[7];
365         devpriv->dac1_coding = it->options[8];
366         devpriv->muxgain_bits = -1;
367
368         s = dev->subdevices + 0;
369         /* ai subdevice */
370         s->type = COMEDI_SUBD_AI;
371         s->subdev_flags = SDF_READABLE | SDF_GROUND;
372         s->n_chan = (devpriv->adc_mux ? 16 : 8);
373         s->insn_read = rti800_ai_insn_read;
374         s->maxdata = 0xfff;
375         switch (devpriv->adc_range) {
376         case adc_bipolar10:
377                 s->range_table = &range_rti800_ai_10_bipolar;
378                 break;
379         case adc_bipolar5:
380                 s->range_table = &range_rti800_ai_5_bipolar;
381                 break;
382         case adc_unipolar10:
383                 s->range_table = &range_rti800_ai_unipolar;
384                 break;
385         }
386
387         s++;
388         if (this_board->has_ao) {
389                 /* ao subdevice (only on rti815) */
390                 s->type = COMEDI_SUBD_AO;
391                 s->subdev_flags = SDF_WRITABLE;
392                 s->n_chan = 2;
393                 s->insn_read = rti800_ao_insn_read;
394                 s->insn_write = rti800_ao_insn_write;
395                 s->maxdata = 0xfff;
396                 s->range_table_list = devpriv->ao_range_type_list;
397                 switch (devpriv->dac0_range) {
398                 case dac_bipolar10:
399                         devpriv->ao_range_type_list[0] = &range_bipolar10;
400                         break;
401                 case dac_unipolar10:
402                         devpriv->ao_range_type_list[0] = &range_unipolar10;
403                         break;
404                 }
405                 switch (devpriv->dac1_range) {
406                 case dac_bipolar10:
407                         devpriv->ao_range_type_list[1] = &range_bipolar10;
408                         break;
409                 case dac_unipolar10:
410                         devpriv->ao_range_type_list[1] = &range_unipolar10;
411                         break;
412                 }
413         } else {
414                 s->type = COMEDI_SUBD_UNUSED;
415         }
416
417         s++;
418         /* di */
419         s->type = COMEDI_SUBD_DI;
420         s->subdev_flags = SDF_READABLE;
421         s->n_chan = 8;
422         s->insn_bits = rti800_di_insn_bits;
423         s->maxdata = 1;
424         s->range_table = &range_digital;
425
426         s++;
427         /* do */
428         s->type = COMEDI_SUBD_DO;
429         s->subdev_flags = SDF_WRITABLE;
430         s->n_chan = 8;
431         s->insn_bits = rti800_do_insn_bits;
432         s->maxdata = 1;
433         s->range_table = &range_digital;
434
435 /* don't yet know how to deal with counter/timers */
436 #if 0
437         s++;
438         /* do */
439         s->type = COMEDI_SUBD_TIMER;
440 #endif
441
442         printk("\n");
443
444         return 0;
445 }
446
447 static int rti800_detach(struct comedi_device * dev)
448 {
449         printk("comedi%d: rti800: remove\n", dev->minor);
450
451         if (dev->iobase)
452                 release_region(dev->iobase, RTI800_SIZE);
453
454         if (dev->irq)
455                 comedi_free_irq(dev->irq, dev);
456
457         return 0;
458 }