-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Driver for DataTranslation DT2815 From: David Schleef <ds@schleef.org> Cc: Ian Abbott <abbotti@mev.co.uk> Cc: Frank Mori Hess <fmhess@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
- Loading branch information
David Schleef
authored and
Greg Kroah-Hartman
committed
Apr 3, 2009
1 parent
a211ea9
commit d6a929b
Showing
1 changed file
with
262 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,262 @@ | ||
/* | ||
comedi/drivers/dt2815.c | ||
Hardware driver for Data Translation DT2815 | ||
COMEDI - Linux Control and Measurement Device Interface | ||
Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se> | ||
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: dt2815 | ||
Description: Data Translation DT2815 | ||
Author: ds | ||
Status: mostly complete, untested | ||
Devices: [Data Translation] DT2815 (dt2815) | ||
I'm not sure anyone has ever tested this board. If you have information | ||
contrary, please update. | ||
Configuration options: | ||
[0] - I/O port base base address | ||
[1] - IRQ (unused) | ||
[2] - Voltage unipolar/bipolar configuration | ||
0 == unipolar 5V (0V -- +5V) | ||
1 == bipolar 5V (-5V -- +5V) | ||
[3] - Current offset configuration | ||
0 == disabled (0mA -- +32mAV) | ||
1 == enabled (+4mA -- +20mAV) | ||
[4] - Firmware program configuration | ||
0 == program 1 (see manual table 5-4) | ||
1 == program 2 (see manual table 5-4) | ||
2 == program 3 (see manual table 5-4) | ||
3 == program 4 (see manual table 5-4) | ||
[5] - Analog output 0 range configuration | ||
0 == voltage | ||
1 == current | ||
[6] - Analog output 1 range configuration (same options) | ||
[7] - Analog output 2 range configuration (same options) | ||
[8] - Analog output 3 range configuration (same options) | ||
[9] - Analog output 4 range configuration (same options) | ||
[10] - Analog output 5 range configuration (same options) | ||
[11] - Analog output 6 range configuration (same options) | ||
[12] - Analog output 7 range configuration (same options) | ||
*/ | ||
|
||
#include "../comedidev.h" | ||
|
||
#include <linux/ioport.h> | ||
#include <linux/delay.h> | ||
|
||
static const comedi_lrange range_dt2815_ao_32_current = { 1, { | ||
RANGE_mA(0, 32) | ||
} | ||
}; | ||
static const comedi_lrange range_dt2815_ao_20_current = { 1, { | ||
RANGE_mA(4, 20) | ||
} | ||
}; | ||
|
||
#define DT2815_SIZE 2 | ||
|
||
#define DT2815_DATA 0 | ||
#define DT2815_STATUS 1 | ||
|
||
static int dt2815_attach(comedi_device * dev, comedi_devconfig * it); | ||
static int dt2815_detach(comedi_device * dev); | ||
static comedi_driver driver_dt2815 = { | ||
driver_name:"dt2815", | ||
module:THIS_MODULE, | ||
attach:dt2815_attach, | ||
detach:dt2815_detach, | ||
}; | ||
|
||
COMEDI_INITCLEANUP(driver_dt2815); | ||
|
||
static void dt2815_free_resources(comedi_device * dev); | ||
|
||
typedef struct { | ||
const comedi_lrange *range_type_list[8]; | ||
lsampl_t ao_readback[8]; | ||
} dt2815_private; | ||
|
||
#define devpriv ((dt2815_private *)dev->private) | ||
|
||
static int dt2815_wait_for_status(comedi_device * dev, int status) | ||
{ | ||
int i; | ||
|
||
for (i = 0; i < 100; i++) { | ||
if (inb(dev->iobase + DT2815_STATUS) == status) | ||
break; | ||
} | ||
return status; | ||
} | ||
|
||
static int dt2815_ao_insn_read(comedi_device * dev, comedi_subdevice * s, | ||
comedi_insn * insn, lsampl_t * data) | ||
{ | ||
int i; | ||
int chan = CR_CHAN(insn->chanspec); | ||
|
||
for (i = 0; i < insn->n; i++) { | ||
data[i] = devpriv->ao_readback[chan]; | ||
} | ||
|
||
return i; | ||
} | ||
|
||
static int dt2815_ao_insn(comedi_device * dev, comedi_subdevice * s, | ||
comedi_insn * insn, lsampl_t * data) | ||
{ | ||
int i; | ||
int chan = CR_CHAN(insn->chanspec); | ||
unsigned int status; | ||
unsigned int lo, hi; | ||
|
||
for (i = 0; i < insn->n; i++) { | ||
lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01; | ||
hi = (data[i] & 0xff0) >> 4; | ||
|
||
status = dt2815_wait_for_status(dev, 0x00); | ||
if (status != 0) { | ||
rt_printk | ||
("dt2815: failed to write low byte on %d reason %x\n", | ||
chan, status); | ||
return -EBUSY; | ||
} | ||
|
||
outb(lo, dev->iobase + DT2815_DATA); | ||
|
||
status = dt2815_wait_for_status(dev, 0x10); | ||
if (status != 0x10) { | ||
rt_printk | ||
("dt2815: failed to write high byte on %d reason %x\n", | ||
chan, status); | ||
return -EBUSY; | ||
} | ||
devpriv->ao_readback[chan] = data[i]; | ||
} | ||
return i; | ||
} | ||
|
||
/* | ||
options[0] Board base address | ||
options[1] IRQ (not applicable) | ||
options[2] Voltage unipolar/bipolar configuration | ||
0 == unipolar 5V (0V -- +5V) | ||
1 == bipolar 5V (-5V -- +5V) | ||
options[3] Current offset configuration | ||
0 == disabled (0mA -- +32mAV) | ||
1 == enabled (+4mA -- +20mAV) | ||
options[4] Firmware program configuration | ||
0 == program 1 (see manual table 5-4) | ||
1 == program 2 (see manual table 5-4) | ||
2 == program 3 (see manual table 5-4) | ||
3 == program 4 (see manual table 5-4) | ||
options[5] Analog output 0 range configuration | ||
0 == voltage | ||
1 == current | ||
options[6] Analog output 1 range configuration | ||
... | ||
options[12] Analog output 7 range configuration | ||
0 == voltage | ||
1 == current | ||
*/ | ||
|
||
static int dt2815_attach(comedi_device * dev, comedi_devconfig * it) | ||
{ | ||
comedi_subdevice *s; | ||
int i; | ||
const comedi_lrange *current_range_type, *voltage_range_type; | ||
unsigned long iobase; | ||
|
||
iobase = it->options[0]; | ||
printk("comedi%d: dt2815: 0x%04lx ", dev->minor, iobase); | ||
if (!request_region(iobase, DT2815_SIZE, "dt2815")) { | ||
printk("I/O port conflict\n"); | ||
return -EIO; | ||
} | ||
|
||
dev->iobase = iobase; | ||
dev->board_name = "dt2815"; | ||
|
||
if (alloc_subdevices(dev, 1) < 0) | ||
return -ENOMEM; | ||
if (alloc_private(dev, sizeof(dt2815_private)) < 0) | ||
return -ENOMEM; | ||
|
||
s = dev->subdevices; | ||
/* ao subdevice */ | ||
s->type = COMEDI_SUBD_AO; | ||
s->subdev_flags = SDF_WRITABLE; | ||
s->maxdata = 0xfff; | ||
s->n_chan = 8; | ||
s->insn_write = dt2815_ao_insn; | ||
s->insn_read = dt2815_ao_insn_read; | ||
s->range_table_list = devpriv->range_type_list; | ||
|
||
current_range_type = (it->options[3]) | ||
? &range_dt2815_ao_20_current : &range_dt2815_ao_32_current; | ||
voltage_range_type = (it->options[2]) | ||
? &range_bipolar5 : &range_unipolar5; | ||
for (i = 0; i < 8; i++) { | ||
devpriv->range_type_list[i] = (it->options[5 + i]) | ||
? current_range_type : voltage_range_type; | ||
} | ||
|
||
/* Init the 2815 */ | ||
outb(0x00, dev->iobase + DT2815_STATUS); | ||
for (i = 0; i < 100; i++) { | ||
/* This is incredibly slow (approx 20 ms) */ | ||
unsigned int status; | ||
|
||
comedi_udelay(1000); | ||
status = inb(dev->iobase + DT2815_STATUS); | ||
if (status == 4) { | ||
unsigned int program; | ||
program = (it->options[4] & 0x3) << 3 | 0x7; | ||
outb(program, dev->iobase + DT2815_DATA); | ||
printk(", program: 0x%x (@t=%d)\n", program, i); | ||
break; | ||
} else if (status != 0x00) { | ||
printk("dt2815: unexpected status 0x%x (@t=%d)\n", | ||
status, i); | ||
if (status & 0x60) { | ||
outb(0x00, dev->iobase + DT2815_STATUS); | ||
} | ||
} | ||
} | ||
|
||
printk("\n"); | ||
|
||
return 0; | ||
} | ||
|
||
static void dt2815_free_resources(comedi_device * dev) | ||
{ | ||
if (dev->iobase) | ||
release_region(dev->iobase, DT2815_SIZE); | ||
} | ||
|
||
static int dt2815_detach(comedi_device * dev) | ||
{ | ||
printk("comedi%d: dt2815: remove\n", dev->minor); | ||
|
||
dt2815_free_resources(dev); | ||
|
||
return 0; | ||
} |