staging: comedi: comedi_test: simplify time since last AI scan
[deliverable/linux.git] / drivers / staging / comedi / drivers / aio_aio12_8.c
CommitLineData
7623199a 1/*
471c5d6c
HS
2 * aio_aio12_8.c
3 * Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board
4 * Copyright (C) 2006 C&C Technologies, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
7623199a
PM
16
17/*
471c5d6c
HS
18 * Driver: aio_aio12_8
19 * Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board
20 * Author: Pablo Mejia <pablo.mejia@cctechnol.com>
21 * Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8),
22 * [Access I/O] PC-104 AI12-8 (aio_ai12_8),
fbea1876 23 * [Access I/O] PC-104 AO12-4 (aio_ao12_4)
471c5d6c
HS
24 * Status: experimental
25 *
26 * Configuration Options:
27 * [0] - I/O port base address
28 *
29 * Notes:
30 * Only synchronous operations are supported.
31 */
7623199a 32
ce157f80 33#include <linux/module.h>
7623199a 34#include "../comedidev.h"
ffe4a317
HS
35
36#include "comedi_8254.h"
7623199a
PM
37#include "8255.h"
38
d4fec101
HS
39/*
40 * Register map
41 */
42#define AIO12_8_STATUS_REG 0x00
4dc4f282
HS
43#define AIO12_8_STATUS_ADC_EOC BIT(7)
44#define AIO12_8_STATUS_PORT_C_COS BIT(6)
45#define AIO12_8_STATUS_IRQ_ENA BIT(2)
d4fec101 46#define AIO12_8_INTERRUPT_REG 0x01
4dc4f282
HS
47#define AIO12_8_INTERRUPT_ADC BIT(7)
48#define AIO12_8_INTERRUPT_COS BIT(6)
49#define AIO12_8_INTERRUPT_COUNTER1 BIT(5)
50#define AIO12_8_INTERRUPT_PORT_C3 BIT(4)
51#define AIO12_8_INTERRUPT_PORT_C0 BIT(3)
52#define AIO12_8_INTERRUPT_ENA BIT(2)
d4fec101 53#define AIO12_8_ADC_REG 0x02
4dc4f282
HS
54#define AIO12_8_ADC_MODE(x) (((x) & 0x3) << 6)
55#define AIO12_8_ADC_MODE_NORMAL AIO12_8_ADC_MODE(0)
56#define AIO12_8_ADC_MODE_INT_CLK AIO12_8_ADC_MODE(1)
57#define AIO12_8_ADC_MODE_STANDBY AIO12_8_ADC_MODE(2)
58#define AIO12_8_ADC_MODE_POWERDOWN AIO12_8_ADC_MODE(3)
59#define AIO12_8_ADC_ACQ(x) (((x) & 0x1) << 5)
60#define AIO12_8_ADC_ACQ_3USEC AIO12_8_ADC_ACQ(0)
61#define AIO12_8_ADC_ACQ_PROGRAM AIO12_8_ADC_ACQ(1)
d4fec101
HS
62#define AIO12_8_ADC_RANGE(x) ((x) << 3)
63#define AIO12_8_ADC_CHAN(x) ((x) << 0)
64#define AIO12_8_DAC_REG(x) (0x04 + (x) * 2)
65#define AIO12_8_8254_BASE_REG 0x0c
66#define AIO12_8_8255_BASE_REG 0x10
67#define AIO12_8_DIO_CONTROL_REG 0x14
4dc4f282 68#define AIO12_8_DIO_CONTROL_TST BIT(0)
d4fec101
HS
69#define AIO12_8_ADC_TRIGGER_REG 0x15
70#define AIO12_8_ADC_TRIGGER_RANGE(x) ((x) << 3)
71#define AIO12_8_ADC_TRIGGER_CHAN(x) ((x) << 0)
72#define AIO12_8_TRIGGER_REG 0x16
4dc4f282
HS
73#define AIO12_8_TRIGGER_ADTRIG BIT(1)
74#define AIO12_8_TRIGGER_DACTRIG BIT(0)
d4fec101
HS
75#define AIO12_8_COS_REG 0x17
76#define AIO12_8_DAC_ENABLE_REG 0x18
4dc4f282 77#define AIO12_8_DAC_ENABLE_REF_ENA BIT(0)
7623199a 78
c5fcb7ca
HS
79static const struct comedi_lrange aio_aio12_8_range = {
80 4, {
81 UNI_RANGE(5),
82 BIP_RANGE(5),
83 UNI_RANGE(10),
84 BIP_RANGE(10)
85 }
86};
87
74753712 88struct aio12_8_boardtype {
7623199a 89 const char *name;
6db70e39
HS
90 unsigned int has_ai:1;
91 unsigned int has_ao:1;
74753712 92};
7623199a 93
74753712 94static const struct aio12_8_boardtype board_types[] = {
7623199a 95 {
862edd6b 96 .name = "aio_aio12_8",
6db70e39
HS
97 .has_ai = 1,
98 .has_ao = 1,
862edd6b
HS
99 }, {
100 .name = "aio_ai12_8",
6db70e39 101 .has_ai = 1,
862edd6b 102 }, {
fbea1876 103 .name = "aio_ao12_4",
6db70e39 104 .has_ao = 1,
862edd6b 105 },
7623199a
PM
106};
107
0862a46f
HS
108static int aio_aio12_8_ai_eoc(struct comedi_device *dev,
109 struct comedi_subdevice *s,
110 struct comedi_insn *insn,
111 unsigned long context)
112{
113 unsigned int status;
114
115 status = inb(dev->iobase + AIO12_8_STATUS_REG);
116 if (status & AIO12_8_STATUS_ADC_EOC)
117 return 0;
118 return -EBUSY;
119}
120
0a85b6f0
MT
121static int aio_aio12_8_ai_read(struct comedi_device *dev,
122 struct comedi_subdevice *s,
ee4c7709
HS
123 struct comedi_insn *insn,
124 unsigned int *data)
7623199a 125{
d4fec101
HS
126 unsigned int chan = CR_CHAN(insn->chanspec);
127 unsigned int range = CR_RANGE(insn->chanspec);
ee4c7709 128 unsigned int val;
d4fec101 129 unsigned char control;
0862a46f 130 int ret;
ee4c7709 131 int i;
7623199a 132
d4fec101
HS
133 /*
134 * Setup the control byte for internal 2MHz clock, 3uS conversion,
135 * at the desired range of the requested channel.
136 */
137 control = AIO12_8_ADC_MODE_NORMAL | AIO12_8_ADC_ACQ_3USEC |
138 AIO12_8_ADC_RANGE(range) | AIO12_8_ADC_CHAN(chan);
139
140 /* Read status to clear EOC latch */
141 inb(dev->iobase + AIO12_8_STATUS_REG);
7623199a 142
ee4c7709 143 for (i = 0; i < insn->n; i++) {
2696fb57 144 /* Setup and start conversion */
d4fec101 145 outb(control, dev->iobase + AIO12_8_ADC_REG);
7623199a 146
2696fb57 147 /* Wait for conversion to complete */
0862a46f 148 ret = comedi_timeout(dev, s, insn, aio_aio12_8_ai_eoc, 0);
22ca19d9 149 if (ret)
0862a46f 150 return ret;
d4fec101 151
ee4c7709
HS
152 val = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata;
153
154 /* munge bipolar 2's complement data to offset binary */
155 if (comedi_range_is_bipolar(s, range))
156 val = comedi_offset_munge(s, val);
157
158 data[i] = val;
7623199a 159 }
d4fec101
HS
160
161 return insn->n;
7623199a
PM
162}
163
9ac58133
HS
164static int aio_aio12_8_ao_insn_write(struct comedi_device *dev,
165 struct comedi_subdevice *s,
166 struct comedi_insn *insn,
167 unsigned int *data)
7623199a 168{
d4fec101 169 unsigned int chan = CR_CHAN(insn->chanspec);
9ac58133 170 unsigned int val = s->readback[chan];
7623199a 171 int i;
7623199a 172
2696fb57 173 /* enable DACs */
d4fec101 174 outb(AIO12_8_DAC_ENABLE_REF_ENA, dev->iobase + AIO12_8_DAC_ENABLE_REG);
7623199a
PM
175
176 for (i = 0; i < insn->n; i++) {
d4fec101 177 val = data[i];
9ac58133 178 outw(val, dev->iobase + AIO12_8_DAC_REG(chan));
7623199a 179 }
9ac58133 180 s->readback[chan] = val;
d4fec101 181
7623199a
PM
182 return insn->n;
183}
184
ffe4a317
HS
185static int aio_aio12_8_counter_insn_config(struct comedi_device *dev,
186 struct comedi_subdevice *s,
187 struct comedi_insn *insn,
188 unsigned int *data)
189{
190 unsigned int chan = CR_CHAN(insn->chanspec);
191
192 switch (data[0]) {
193 case INSN_CONFIG_GET_CLOCK_SRC:
194 /*
195 * Channels 0 and 2 have external clock sources.
196 * Channel 1 has a fixed 1 MHz clock source.
197 */
198 data[0] = 0;
199 data[1] = (chan == 1) ? I8254_OSC_BASE_1MHZ : 0;
200 break;
201 default:
202 return -EINVAL;
203 }
204
205 return insn->n;
206}
207
0a85b6f0
MT
208static int aio_aio12_8_attach(struct comedi_device *dev,
209 struct comedi_devconfig *it)
7623199a 210{
b37e1d6e 211 const struct aio12_8_boardtype *board = dev->board_ptr;
34c43922 212 struct comedi_subdevice *s;
8b6c5694 213 int ret;
7623199a 214
a5958514
HS
215 ret = comedi_request_region(dev, it->options[0], 32);
216 if (ret)
217 return ret;
7623199a 218
ffe4a317
HS
219 dev->pacer = comedi_8254_init(dev->iobase + AIO12_8_8254_BASE_REG,
220 0, I8254_IO8, 0);
221 if (!dev->pacer)
222 return -ENOMEM;
223
862edd6b 224 ret = comedi_alloc_subdevices(dev, 4);
8b6c5694
HS
225 if (ret)
226 return ret;
7623199a 227
6db70e39 228 /* Analog Input subdevice */
ef83beae 229 s = &dev->subdevices[0];
6db70e39 230 if (board->has_ai) {
862edd6b
HS
231 s->type = COMEDI_SUBD_AI;
232 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
6db70e39 233 s->n_chan = 8;
862edd6b 234 s->maxdata = 0x0fff;
c5fcb7ca 235 s->range_table = &aio_aio12_8_range;
862edd6b
HS
236 s->insn_read = aio_aio12_8_ai_read;
237 } else {
238 s->type = COMEDI_SUBD_UNUSED;
239 }
240
6db70e39 241 /* Analog Output subdevice */
ef83beae 242 s = &dev->subdevices[1];
6db70e39 243 if (board->has_ao) {
862edd6b 244 s->type = COMEDI_SUBD_AO;
1198f6b0 245 s->subdev_flags = SDF_WRITABLE | SDF_GROUND;
862edd6b
HS
246 s->n_chan = 4;
247 s->maxdata = 0x0fff;
c5fcb7ca 248 s->range_table = &aio_aio12_8_range;
9ac58133 249 s->insn_write = aio_aio12_8_ao_insn_write;
9ac58133
HS
250
251 ret = comedi_alloc_subdev_readback(s);
252 if (ret)
253 return ret;
862edd6b
HS
254 } else {
255 s->type = COMEDI_SUBD_UNUSED;
256 }
257
9f4d30dd 258 /* Digital I/O subdevice (8255) */
ef83beae 259 s = &dev->subdevices[2];
4085e93b 260 ret = subdev_8255_init(dev, s, NULL, AIO12_8_8255_BASE_REG);
862edd6b
HS
261 if (ret)
262 return ret;
263
ffe4a317 264 /* Counter subdevice (8254) */
ef83beae 265 s = &dev->subdevices[3];
ffe4a317
HS
266 comedi_8254_subdevice_init(s, dev->pacer);
267
268 dev->pacer->insn_config = aio_aio12_8_counter_insn_config;
862edd6b 269
7623199a
PM
270 return 0;
271}
272
294f930d
HS
273static struct comedi_driver aio_aio12_8_driver = {
274 .driver_name = "aio_aio12_8",
275 .module = THIS_MODULE,
276 .attach = aio_aio12_8_attach,
588ba6dc 277 .detach = comedi_legacy_detach,
294f930d
HS
278 .board_name = &board_types[0].name,
279 .num_names = ARRAY_SIZE(board_types),
280 .offset = sizeof(struct aio12_8_boardtype),
7623199a 281};
294f930d 282module_comedi_driver(aio_aio12_8_driver);
90f703d3
AT
283
284MODULE_AUTHOR("Comedi http://www.comedi.org");
180480ed 285MODULE_DESCRIPTION("Comedi driver for Access I/O AIO12-8 Analog I/O Board");
90f703d3 286MODULE_LICENSE("GPL");
This page took 0.825714 seconds and 5 git commands to generate.