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