Merge tag 'gpio-for-linus' of git://git.secretlab.ca/git/linux
[GitHub/mt8127/android_kernel_alcatel_ttab.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
131 /* convert n samples */
132 for (n = 0; n < insn->n; n++) {
133 /* trigger conversion with out0 L to H */
134 outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */
135 outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */
136 /* mode 1 out0 H, L to H, start conversion */
137 outb(0x32, dev->iobase + CMO_R);
138 /* wait for conversion to end */
139 for (i = 0; i < TIMEOUT; i++) {
140 status = inb(dev->iobase + STA_R2);
141 if ((status & 0x03) != 0) {
142 dev_info(dev->class_dev,
143 "Overflow/run Error\n");
144 return -EOVERFLOW;
145 }
146 status = inb(dev->iobase + STA_R1);
147 if ((status & 0x02) != 0) {
148 dev_info(dev->class_dev, "Data Error\n");
149 return -ENODATA;
150 }
151 if ((status & 0x11) == 0x01) {
152 /* ADC conversion complete */
153 break;
154 }
155 udelay(1);
156 }
157 if (i == TIMEOUT) {
158 dev_info(dev->class_dev,
159 "timeout during ADC conversion\n");
160 return -ETIMEDOUT;
161 }
162 /* read data */
163 d = inw(dev->iobase + ADFIFO_R);
164 /* mangle the data as necessary */
165 /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */
166 d &= 0x0fff;
167 d ^= 0x0800;
168 data[n] = d;
169 }
170 return n;
171 }
172
173 /*
174 * Data acquisition is enabled.
175 * The counter 0 output is high.
176 * The I/O connector pin CLK1 drives counter 1 source.
177 * Multiple-channel scanning is disabled.
178 * All interrupts are disabled.
179 * The analog input range is set to +-10 V
180 * The analog input mode is single-ended.
181 * The analog input circuitry is initialized to channel 0.
182 * The A/D FIFO is cleared.
183 */
184 static void daq700_ai_config(struct comedi_device *dev,
185 struct comedi_subdevice *s)
186 {
187 unsigned long iobase = dev->iobase;
188
189 outb(0x80, iobase + CMD_R1); /* disable scanning, ADC to chan 0 */
190 outb(0x00, iobase + CMD_R2); /* clear all bits */
191 outb(0x00, iobase + CMD_R3); /* set +-10 range */
192 outb(0x32, iobase + CMO_R); /* config counter mode1, out0 to H */
193 outb(0x00, iobase + TIC_R); /* clear counter interrupt */
194 outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */
195 inw(iobase + ADFIFO_R); /* read 16bit junk from FIFO to clear */
196 }
197
198 static int daq700_auto_attach(struct comedi_device *dev,
199 unsigned long context)
200 {
201 struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
202 struct comedi_subdevice *s;
203 int ret;
204
205 link->config_flags |= CONF_AUTO_SET_IO;
206 ret = comedi_pcmcia_enable(dev, NULL);
207 if (ret)
208 return ret;
209 dev->iobase = link->resource[0]->start;
210
211 ret = comedi_alloc_subdevices(dev, 2);
212 if (ret)
213 return ret;
214
215 /* DAQCard-700 dio */
216 s = &dev->subdevices[0];
217 s->type = COMEDI_SUBD_DIO;
218 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
219 s->n_chan = 16;
220 s->range_table = &range_digital;
221 s->maxdata = 1;
222 s->insn_bits = daq700_dio_insn_bits;
223 s->insn_config = daq700_dio_insn_config;
224 s->state = 0;
225 s->io_bits = 0x00ff;
226
227 /* DAQCard-700 ai */
228 s = &dev->subdevices[1];
229 s->type = COMEDI_SUBD_AI;
230 /* we support single-ended (ground) */
231 s->subdev_flags = SDF_READABLE | SDF_GROUND;
232 s->n_chan = 16;
233 s->maxdata = (1 << 12) - 1;
234 s->range_table = &range_bipolar10;
235 s->insn_read = daq700_ai_rinsn;
236 daq700_ai_config(dev, s);
237
238 dev_info(dev->class_dev, "%s: %s, io 0x%lx\n",
239 dev->driver->driver_name,
240 dev->board_name,
241 dev->iobase);
242
243 return 0;
244 }
245
246 static struct comedi_driver daq700_driver = {
247 .driver_name = "ni_daq_700",
248 .module = THIS_MODULE,
249 .auto_attach = daq700_auto_attach,
250 .detach = comedi_pcmcia_disable,
251 };
252
253 static int daq700_cs_attach(struct pcmcia_device *link)
254 {
255 return comedi_pcmcia_auto_config(link, &daq700_driver);
256 }
257
258 static const struct pcmcia_device_id daq700_cs_ids[] = {
259 PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743),
260 PCMCIA_DEVICE_NULL
261 };
262 MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids);
263
264 static struct pcmcia_driver daq700_cs_driver = {
265 .name = "ni_daq_700",
266 .owner = THIS_MODULE,
267 .id_table = daq700_cs_ids,
268 .probe = daq700_cs_attach,
269 .remove = comedi_pcmcia_auto_unconfig,
270 };
271 module_comedi_pcmcia_driver(daq700_driver, daq700_cs_driver);
272
273 MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>");
274 MODULE_DESCRIPTION(
275 "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI");
276 MODULE_VERSION("0.2.00");
277 MODULE_LICENSE("GPL");