Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | /*
comedi/drivers/aio_aio12_8.c
Driver for Access I/O Products PC-104 AIO12-8 Analog I/O Board
Copyright (C) 2006 C&C Technologies, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
Driver: aio_aio12_8
Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board
Author: Pablo Mejia <pablo.mejia@cctechnol.com>
Devices:
[Access I/O] PC-104 AIO12-8
Status: experimental
Configuration Options:
[0] - I/O port base address
Notes:
Only synchronous operations are supported.
*/
#include "../comedidev.h"
#include <linux/ioport.h>
#include "8255.h"
#define AIO12_8_STATUS 0x00
#define AIO12_8_INTERRUPT 0x01
#define AIO12_8_ADC 0x02
#define AIO12_8_DAC_0 0x04
#define AIO12_8_DAC_1 0x06
#define AIO12_8_DAC_2 0x08
#define AIO12_8_DAC_3 0x0A
#define AIO12_8_COUNTER_0 0x0C
#define AIO12_8_COUNTER_1 0x0D
#define AIO12_8_COUNTER_2 0x0E
#define AIO12_8_COUNTER_CONTROL 0x0F
#define AIO12_8_DIO_0 0x10
#define AIO12_8_DIO_1 0x11
#define AIO12_8_DIO_2 0x12
#define AIO12_8_DIO_STATUS 0x13
#define AIO12_8_DIO_CONTROL 0x14
#define AIO12_8_ADC_TRIGGER_CONTROL 0x15
#define AIO12_8_TRIGGER 0x16
#define AIO12_8_POWER 0x17
#define STATUS_ADC_EOC 0x80
#define ADC_MODE_NORMAL 0x00
#define ADC_MODE_INTERNAL_CLOCK 0x40
#define ADC_MODE_STANDBY 0x80
#define ADC_MODE_POWERDOWN 0xC0
#define DAC_ENABLE 0x18
struct aio12_8_boardtype {
const char *name;
};
static const struct aio12_8_boardtype board_types[] = {
{
.name = "aio_aio12_8"},
};
#define thisboard ((const struct aio12_8_boardtype *) dev->board_ptr)
struct aio12_8_private {
unsigned int ao_readback[4];
};
#define devpriv ((struct aio12_8_private *) dev->private)
static int aio_aio12_8_ai_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
int n;
unsigned char control =
ADC_MODE_NORMAL |
(CR_RANGE(insn->chanspec) << 3) | CR_CHAN(insn->chanspec);
/* read status to clear EOC latch */
inb(dev->iobase + AIO12_8_STATUS);
for (n = 0; n < insn->n; n++) {
int timeout = 5;
/* Setup and start conversion */
outb(control, dev->iobase + AIO12_8_ADC);
/* Wait for conversion to complete */
while (timeout &&
!(inb(dev->iobase + AIO12_8_STATUS) & STATUS_ADC_EOC)) {
timeout--;
printk(KERN_ERR "timeout %d\n", timeout);
udelay(1);
}
if (timeout == 0) {
comedi_error(dev, "ADC timeout");
return -EIO;
}
data[n] = inw(dev->iobase + AIO12_8_ADC) & 0x0FFF;
}
return n;
}
static int aio_aio12_8_ao_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
int i;
int val = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
for (i = 0; i < insn->n; i++)
data[i] = val;
return insn->n;
}
static int aio_aio12_8_ao_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
int i;
int chan = CR_CHAN(insn->chanspec);
unsigned long port = dev->iobase + AIO12_8_DAC_0 + (2 * chan);
/* enable DACs */
outb(0x01, dev->iobase + DAC_ENABLE);
for (i = 0; i < insn->n; i++) {
outb(data[i] & 0xFF, port); /* LSB */
outb((data[i] >> 8) & 0x0F, port + 1); /* MSB */
devpriv->ao_readback[chan] = data[i];
}
return insn->n;
}
static const struct comedi_lrange range_aio_aio12_8 = {
4,
{
UNI_RANGE(5),
BIP_RANGE(5),
UNI_RANGE(10),
BIP_RANGE(10),
}
};
static int aio_aio12_8_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
int iobase;
struct comedi_subdevice *s;
iobase = it->options[0];
if (!request_region(iobase, 24, "aio_aio12_8")) {
printk(KERN_ERR "I/O port conflict");
return -EIO;
}
dev->board_name = thisboard->name;
dev->iobase = iobase;
if (alloc_private(dev, sizeof(struct aio12_8_private)) < 0)
return -ENOMEM;
if (alloc_subdevices(dev, 3) < 0)
return -ENOMEM;
s = &dev->subdevices[0];
s->type = COMEDI_SUBD_AI;
s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
s->n_chan = 8;
s->maxdata = (1 << 12) - 1;
s->range_table = &range_aio_aio12_8;
s->insn_read = aio_aio12_8_ai_read;
s = &dev->subdevices[1];
s->type = COMEDI_SUBD_AO;
s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF;
s->n_chan = 4;
s->maxdata = (1 << 12) - 1;
s->range_table = &range_aio_aio12_8;
s->insn_read = aio_aio12_8_ao_read;
s->insn_write = aio_aio12_8_ao_write;
s = &dev->subdevices[2];
subdev_8255_init(dev, s, NULL, dev->iobase + AIO12_8_DIO_0);
return 0;
}
static int aio_aio12_8_detach(struct comedi_device *dev)
{
subdev_8255_cleanup(dev, &dev->subdevices[2]);
if (dev->iobase)
release_region(dev->iobase, 24);
return 0;
}
static struct comedi_driver driver_aio_aio12_8 = {
.driver_name = "aio_aio12_8",
.module = THIS_MODULE,
.attach = aio_aio12_8_attach,
.detach = aio_aio12_8_detach,
.board_name = &board_types[0].name,
.num_names = 1,
.offset = sizeof(struct aio12_8_boardtype),
};
static int __init driver_aio_aio12_8_init_module(void)
{
return comedi_driver_register(&driver_aio_aio12_8);
}
static void __exit driver_aio_aio12_8_cleanup_module(void)
{
comedi_driver_unregister(&driver_aio_aio12_8);
}
module_init(driver_aio_aio12_8_init_module);
module_exit(driver_aio_aio12_8_cleanup_module);
MODULE_AUTHOR("Comedi http://www.comedi.org");
MODULE_DESCRIPTION("Comedi low-level driver");
MODULE_LICENSE("GPL");
|