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