]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/ni_daq_700.c
Linux 3.12-rc6
[karo-tx-linux.git] / drivers / staging / comedi / drivers / ni_daq_700.c
1 /*
2  *     comedi/drivers/ni_daq_700.c
3  *     Driver for DAQCard-700 DIO/AI
4  *     copied from 8255
5  *
6  *     COMEDI - Linux Control and Measurement Device Interface
7  *     Copyright (C) 1998 David A. Schleef <ds@schleef.org>
8  *
9  *     This program is free software; you can redistribute it and/or modify
10  *     it under the terms of the GNU General Public License as published by
11  *     the Free Software Foundation; either version 2 of the License, or
12  *     (at your option) any later version.
13  *
14  *     This program is distributed in the hope that it will be useful,
15  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *     GNU General Public License for more details.
18  */
19
20 /*
21 Driver: ni_daq_700
22 Description: National Instruments PCMCIA DAQCard-700 DIO only
23 Author: Fred Brooks <nsaspook@nsaspook.com>,
24   based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es>
25 Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700)
26 Status: works
27 Updated: Wed, 19 Sep 2012 12:07:20 +0000
28
29 The daqcard-700 appears in Comedi as a  digital I/O subdevice (0) with
30 16 channels and a analog input subdevice (1) with 16 single-ended channels.
31
32 Digital:  The channel 0 corresponds to the daqcard-700's output
33 port, bit 0; channel 8 corresponds to the input port, bit 0.
34
35 Digital direction configuration: channels 0-7 output, 8-15 input (8225 device
36 emu as port A output, port B input, port C N/A).
37
38 Analog: The input  range is 0 to 4095 for -10 to +10 volts
39 IRQ is assigned but not used.
40
41 Version 0.1     Original DIO only driver
42 Version 0.2     DIO and basic AI analog input support on 16 se channels
43
44 Manuals:        Register level: http://www.ni.com/pdf/manuals/340698.pdf
45                 User Manual:    http://www.ni.com/pdf/manuals/320676d.pdf
46 */
47
48 #include <linux/module.h>
49 #include <linux/delay.h>
50 #include <linux/interrupt.h>
51
52 #include "../comedidev.h"
53
54 #include <pcmcia/cistpl.h>
55 #include <pcmcia/ds.h>
56
57 /* daqcard700 registers */
58 #define DIO_W           0x04    /* WO 8bit */
59 #define DIO_R           0x05    /* RO 8bit */
60 #define CMD_R1          0x00    /* WO 8bit */
61 #define CMD_R2          0x07    /* RW 8bit */
62 #define CMD_R3          0x05    /* W0 8bit */
63 #define STA_R1          0x00    /* RO 8bit */
64 #define STA_R2          0x01    /* RO 8bit */
65 #define ADFIFO_R        0x02    /* RO 16bit */
66 #define ADCLEAR_R       0x01    /* WO 8bit */
67 #define CDA_R0          0x08    /* RW 8bit */
68 #define CDA_R1          0x09    /* RW 8bit */
69 #define CDA_R2          0x0A    /* RW 8bit */
70 #define CMO_R           0x0B    /* RO 8bit */
71 #define TIC_R           0x06    /* WO 8bit */
72
73 static int daq700_dio_insn_bits(struct comedi_device *dev,
74                                 struct comedi_subdevice *s,
75                                 struct comedi_insn *insn, unsigned int *data)
76 {
77         if (data[0]) {
78                 s->state &= ~data[0];
79                 s->state |= (data[0] & data[1]);
80
81                 if (data[0] & 0xff)
82                         outb(s->state & 0xff, dev->iobase + DIO_W);
83         }
84
85         data[1] = s->state & 0xff;
86         data[1] |= inb(dev->iobase + DIO_R) << 8;
87
88         return insn->n;
89 }
90
91 static int daq700_dio_insn_config(struct comedi_device *dev,
92                                   struct comedi_subdevice *s,
93                                   struct comedi_insn *insn,
94                                   unsigned int *data)
95 {
96         int ret;
97
98         ret = comedi_dio_insn_config(dev, s, insn, data, 0);
99         if (ret)
100                 return ret;
101
102         /* The DIO channels are not configurable, fix the io_bits */
103         s->io_bits = 0x00ff;
104
105         return insn->n;
106 }
107
108 static int daq700_ai_rinsn(struct comedi_device *dev,
109                            struct comedi_subdevice *s,
110                            struct comedi_insn *insn, unsigned int *data)
111 {
112         int n, i, chan;
113         int d;
114         unsigned int status;
115         enum { TIMEOUT = 100 };
116
117         chan = CR_CHAN(insn->chanspec);
118         /* write channel to multiplexer */
119         /* set mask scan bit high to disable scanning */
120         outb(chan | 0x80, dev->iobase + CMD_R1);
121
122         /* convert n samples */
123         for (n = 0; n < insn->n; n++) {
124                 /* trigger conversion with out0 L to H */
125                 outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */
126                 outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
127                 /* mode 1 out0 H, L to H, start conversion */
128                 outb(0x32, dev->iobase + CMO_R);
129                 /* wait for conversion to end */
130                 for (i = 0; i < TIMEOUT; i++) {
131                         status = inb(dev->iobase + STA_R2);
132                         if ((status & 0x03) != 0) {
133                                 dev_info(dev->class_dev,
134                                          "Overflow/run Error\n");
135                                 return -EOVERFLOW;
136                         }
137                         status = inb(dev->iobase + STA_R1);
138                         if ((status & 0x02) != 0) {
139                                 dev_info(dev->class_dev, "Data Error\n");
140                                 return -ENODATA;
141                         }
142                         if ((status & 0x11) == 0x01) {
143                                 /* ADC conversion complete */
144                                 break;
145                         }
146                         udelay(1);
147                 }
148                 if (i == TIMEOUT) {
149                         dev_info(dev->class_dev,
150                                  "timeout during ADC conversion\n");
151                         return -ETIMEDOUT;
152                 }
153                 /* read data */
154                 d = inw(dev->iobase + ADFIFO_R);
155                 /* mangle the data as necessary */
156                 /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */
157                 d &= 0x0fff;
158                 d ^= 0x0800;
159                 data[n] = d;
160         }
161         return n;
162 }
163
164 /*
165  * Data acquisition is enabled.
166  * The counter 0 output is high.
167  * The I/O connector pin CLK1 drives counter 1 source.
168  * Multiple-channel scanning is disabled.
169  * All interrupts are disabled.
170  * The analog input range is set to +-10 V
171  * The analog input mode is single-ended.
172  * The analog input circuitry is initialized to channel 0.
173  * The A/D FIFO is cleared.
174  */
175 static void daq700_ai_config(struct comedi_device *dev,
176                              struct comedi_subdevice *s)
177 {
178         unsigned long iobase = dev->iobase;
179
180         outb(0x80, iobase + CMD_R1);    /* disable scanning, ADC to chan 0 */
181         outb(0x00, iobase + CMD_R2);    /* clear all bits */
182         outb(0x00, iobase + CMD_R3);    /* set +-10 range */
183         outb(0x32, iobase + CMO_R);     /* config counter mode1, out0 to H */
184         outb(0x00, iobase + TIC_R);     /* clear counter interrupt */
185         outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */
186         inw(iobase + ADFIFO_R);         /* read 16bit junk from FIFO to clear */
187 }
188
189 static int daq700_auto_attach(struct comedi_device *dev,
190                               unsigned long context)
191 {
192         struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
193         struct comedi_subdevice *s;
194         int ret;
195
196         link->config_flags |= CONF_AUTO_SET_IO;
197         ret = comedi_pcmcia_enable(dev, NULL);
198         if (ret)
199                 return ret;
200         dev->iobase = link->resource[0]->start;
201
202         ret = comedi_alloc_subdevices(dev, 2);
203         if (ret)
204                 return ret;
205
206         /* DAQCard-700 dio */
207         s = &dev->subdevices[0];
208         s->type         = COMEDI_SUBD_DIO;
209         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
210         s->n_chan       = 16;
211         s->range_table  = &range_digital;
212         s->maxdata      = 1;
213         s->insn_bits    = daq700_dio_insn_bits;
214         s->insn_config  = daq700_dio_insn_config;
215         s->state        = 0;
216         s->io_bits      = 0x00ff;
217
218         /* DAQCard-700 ai */
219         s = &dev->subdevices[1];
220         s->type = COMEDI_SUBD_AI;
221         /* we support single-ended (ground)  */
222         s->subdev_flags = SDF_READABLE | SDF_GROUND;
223         s->n_chan = 16;
224         s->maxdata = (1 << 12) - 1;
225         s->range_table = &range_bipolar10;
226         s->insn_read = daq700_ai_rinsn;
227         daq700_ai_config(dev, s);
228
229         dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
230                 dev->driver->driver_name,
231                 dev->board_name,
232                 dev->iobase);
233
234         return 0;
235 }
236
237 static struct comedi_driver daq700_driver = {
238         .driver_name    = "ni_daq_700",
239         .module         = THIS_MODULE,
240         .auto_attach    = daq700_auto_attach,
241         .detach         = comedi_pcmcia_disable,
242 };
243
244 static int daq700_cs_attach(struct pcmcia_device *link)
245 {
246         return comedi_pcmcia_auto_config(link, &daq700_driver);
247 }
248
249 static const struct pcmcia_device_id daq700_cs_ids[] = {
250         PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
251         PCMCIA_DEVICE_NULL
252 };
253 MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
254
255 static struct pcmcia_driver daq700_cs_driver = {
256         .name           = "ni_daq_700",
257         .owner          = THIS_MODULE,
258         .id_table       = daq700_cs_ids,
259         .probe          = daq700_cs_attach,
260         .remove         = comedi_pcmcia_auto_unconfig,
261 };
262 module_comedi_pcmcia_driver(daq700_driver, daq700_cs_driver);
263
264 MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
265 MODULE_DESCRIPTION(
266         "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
267 MODULE_VERSION("0.2.00");
268 MODULE_LICENSE("GPL");