~ubuntu-branches/ubuntu/precise/linux-lowlatency/precise

« back to all changes in this revision

Viewing changes to drivers/staging/comedi/drivers/dt2815.c

  • Committer: Package Import Robot
  • Author(s): Alessio Igor Bogani
  • Date: 2011-10-26 11:13:05 UTC
  • Revision ID: package-import@ubuntu.com-20111026111305-tz023xykf0i6eosh
Tags: upstream-3.2.0
ImportĀ upstreamĀ versionĀ 3.2.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   comedi/drivers/dt2815.c
 
3
   Hardware driver for Data Translation DT2815
 
4
 
 
5
   COMEDI - Linux Control and Measurement Device Interface
 
6
   Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
 
7
 
 
8
   This program is free software; you can redistribute it and/or modify
 
9
   it under the terms of the GNU General Public License as published by
 
10
   the Free Software Foundation; either version 2 of the License, or
 
11
   (at your option) any later version.
 
12
 
 
13
   This program is distributed in the hope that it will be useful,
 
14
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
16
   GNU General Public License for more details.
 
17
 
 
18
   You should have received a copy of the GNU General Public License
 
19
   along with this program; if not, write to the Free Software
 
20
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 
 
22
 */
 
23
/*
 
24
Driver: dt2815
 
25
Description: Data Translation DT2815
 
26
Author: ds
 
27
Status: mostly complete, untested
 
28
Devices: [Data Translation] DT2815 (dt2815)
 
29
 
 
30
I'm not sure anyone has ever tested this board.  If you have information
 
31
contrary, please update.
 
32
 
 
33
Configuration options:
 
34
  [0] - I/O port base base address
 
35
  [1] - IRQ (unused)
 
36
  [2] - Voltage unipolar/bipolar configuration
 
37
        0 == unipolar 5V  (0V -- +5V)
 
38
        1 == bipolar 5V  (-5V -- +5V)
 
39
  [3] - Current offset configuration
 
40
        0 == disabled  (0mA -- +32mAV)
 
41
        1 == enabled  (+4mA -- +20mAV)
 
42
  [4] - Firmware program configuration
 
43
        0 == program 1 (see manual table 5-4)
 
44
        1 == program 2 (see manual table 5-4)
 
45
        2 == program 3 (see manual table 5-4)
 
46
        3 == program 4 (see manual table 5-4)
 
47
  [5] - Analog output 0 range configuration
 
48
        0 == voltage
 
49
        1 == current
 
50
  [6] - Analog output 1 range configuration (same options)
 
51
  [7] - Analog output 2 range configuration (same options)
 
52
  [8] - Analog output 3 range configuration (same options)
 
53
  [9] - Analog output 4 range configuration (same options)
 
54
  [10] - Analog output 5 range configuration (same options)
 
55
  [11] - Analog output 6 range configuration (same options)
 
56
  [12] - Analog output 7 range configuration (same options)
 
57
*/
 
58
 
 
59
#include "../comedidev.h"
 
60
 
 
61
#include <linux/ioport.h>
 
62
#include <linux/delay.h>
 
63
 
 
64
static const struct comedi_lrange
 
65
        range_dt2815_ao_32_current = {1, {RANGE_mA(0, 32)} };
 
66
 
 
67
static const struct comedi_lrange
 
68
        range_dt2815_ao_20_current = {1, {RANGE_mA(4, 20)} };
 
69
 
 
70
#define DT2815_SIZE 2
 
71
 
 
72
#define DT2815_DATA 0
 
73
#define DT2815_STATUS 1
 
74
 
 
75
static int dt2815_attach(struct comedi_device *dev,
 
76
                         struct comedi_devconfig *it);
 
77
static int dt2815_detach(struct comedi_device *dev);
 
78
static struct comedi_driver driver_dt2815 = {
 
79
        .driver_name = "dt2815",
 
80
        .module = THIS_MODULE,
 
81
        .attach = dt2815_attach,
 
82
        .detach = dt2815_detach,
 
83
};
 
84
 
 
85
static int __init driver_dt2815_init_module(void)
 
86
{
 
87
        return comedi_driver_register(&driver_dt2815);
 
88
}
 
89
 
 
90
static void __exit driver_dt2815_cleanup_module(void)
 
91
{
 
92
        comedi_driver_unregister(&driver_dt2815);
 
93
}
 
94
 
 
95
module_init(driver_dt2815_init_module);
 
96
module_exit(driver_dt2815_cleanup_module);
 
97
 
 
98
static void dt2815_free_resources(struct comedi_device *dev);
 
99
 
 
100
struct dt2815_private {
 
101
 
 
102
        const struct comedi_lrange *range_type_list[8];
 
103
        unsigned int ao_readback[8];
 
104
};
 
105
 
 
106
#define devpriv ((struct dt2815_private *)dev->private)
 
107
 
 
108
static int dt2815_wait_for_status(struct comedi_device *dev, int status)
 
109
{
 
110
        int i;
 
111
 
 
112
        for (i = 0; i < 100; i++) {
 
113
                if (inb(dev->iobase + DT2815_STATUS) == status)
 
114
                        break;
 
115
        }
 
116
        return status;
 
117
}
 
118
 
 
119
static int dt2815_ao_insn_read(struct comedi_device *dev,
 
120
                               struct comedi_subdevice *s,
 
121
                               struct comedi_insn *insn, unsigned int *data)
 
122
{
 
123
        int i;
 
124
        int chan = CR_CHAN(insn->chanspec);
 
125
 
 
126
        for (i = 0; i < insn->n; i++)
 
127
                data[i] = devpriv->ao_readback[chan];
 
128
 
 
129
        return i;
 
130
}
 
131
 
 
132
static int dt2815_ao_insn(struct comedi_device *dev, struct comedi_subdevice *s,
 
133
                          struct comedi_insn *insn, unsigned int *data)
 
134
{
 
135
        int i;
 
136
        int chan = CR_CHAN(insn->chanspec);
 
137
        unsigned int status;
 
138
        unsigned int lo, hi;
 
139
 
 
140
        for (i = 0; i < insn->n; i++) {
 
141
                lo = ((data[i] & 0x0f) << 4) | (chan << 1) | 0x01;
 
142
                hi = (data[i] & 0xff0) >> 4;
 
143
 
 
144
                status = dt2815_wait_for_status(dev, 0x00);
 
145
                if (status != 0) {
 
146
                        printk(KERN_WARNING "dt2815: failed to write low byte "
 
147
                               "on %d reason %x\n", chan, status);
 
148
                        return -EBUSY;
 
149
                }
 
150
 
 
151
                outb(lo, dev->iobase + DT2815_DATA);
 
152
 
 
153
                status = dt2815_wait_for_status(dev, 0x10);
 
154
                if (status != 0x10) {
 
155
                        printk(KERN_WARNING "dt2815: failed to write high byte "
 
156
                               "on %d reason %x\n", chan, status);
 
157
                        return -EBUSY;
 
158
                }
 
159
                devpriv->ao_readback[chan] = data[i];
 
160
        }
 
161
        return i;
 
162
}
 
163
 
 
164
/*
 
165
  options[0]   Board base address
 
166
  options[1]   IRQ (not applicable)
 
167
  options[2]   Voltage unipolar/bipolar configuration
 
168
                0 == unipolar 5V  (0V -- +5V)
 
169
                1 == bipolar 5V  (-5V -- +5V)
 
170
  options[3]   Current offset configuration
 
171
                0 == disabled  (0mA -- +32mAV)
 
172
                1 == enabled  (+4mA -- +20mAV)
 
173
  options[4]   Firmware program configuration
 
174
                0 == program 1 (see manual table 5-4)
 
175
                1 == program 2 (see manual table 5-4)
 
176
                2 == program 3 (see manual table 5-4)
 
177
                3 == program 4 (see manual table 5-4)
 
178
  options[5]   Analog output 0 range configuration
 
179
                0 == voltage
 
180
                1 == current
 
181
  options[6]   Analog output 1 range configuration
 
182
  ...
 
183
  options[12]   Analog output 7 range configuration
 
184
                0 == voltage
 
185
                1 == current
 
186
 */
 
187
 
 
188
static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 
189
{
 
190
        struct comedi_subdevice *s;
 
191
        int i;
 
192
        const struct comedi_lrange *current_range_type, *voltage_range_type;
 
193
        unsigned long iobase;
 
194
 
 
195
        iobase = it->options[0];
 
196
        printk(KERN_INFO "comedi%d: dt2815: 0x%04lx ", dev->minor, iobase);
 
197
        if (!request_region(iobase, DT2815_SIZE, "dt2815")) {
 
198
                printk(KERN_WARNING "I/O port conflict\n");
 
199
                return -EIO;
 
200
        }
 
201
 
 
202
        dev->iobase = iobase;
 
203
        dev->board_name = "dt2815";
 
204
 
 
205
        if (alloc_subdevices(dev, 1) < 0)
 
206
                return -ENOMEM;
 
207
        if (alloc_private(dev, sizeof(struct dt2815_private)) < 0)
 
208
                return -ENOMEM;
 
209
 
 
210
        s = dev->subdevices;
 
211
        /* ao subdevice */
 
212
        s->type = COMEDI_SUBD_AO;
 
213
        s->subdev_flags = SDF_WRITABLE;
 
214
        s->maxdata = 0xfff;
 
215
        s->n_chan = 8;
 
216
        s->insn_write = dt2815_ao_insn;
 
217
        s->insn_read = dt2815_ao_insn_read;
 
218
        s->range_table_list = devpriv->range_type_list;
 
219
 
 
220
        current_range_type = (it->options[3])
 
221
            ? &range_dt2815_ao_20_current : &range_dt2815_ao_32_current;
 
222
        voltage_range_type = (it->options[2])
 
223
            ? &range_bipolar5 : &range_unipolar5;
 
224
        for (i = 0; i < 8; i++) {
 
225
                devpriv->range_type_list[i] = (it->options[5 + i])
 
226
                    ? current_range_type : voltage_range_type;
 
227
        }
 
228
 
 
229
        /* Init the 2815 */
 
230
        outb(0x00, dev->iobase + DT2815_STATUS);
 
231
        for (i = 0; i < 100; i++) {
 
232
                /* This is incredibly slow (approx 20 ms) */
 
233
                unsigned int status;
 
234
 
 
235
                udelay(1000);
 
236
                status = inb(dev->iobase + DT2815_STATUS);
 
237
                if (status == 4) {
 
238
                        unsigned int program;
 
239
                        program = (it->options[4] & 0x3) << 3 | 0x7;
 
240
                        outb(program, dev->iobase + DT2815_DATA);
 
241
                        printk(KERN_INFO ", program: 0x%x (@t=%d)\n",
 
242
                               program, i);
 
243
                        break;
 
244
                } else if (status != 0x00) {
 
245
                        printk(KERN_WARNING "dt2815: unexpected status 0x%x "
 
246
                               "(@t=%d)\n", status, i);
 
247
                        if (status & 0x60)
 
248
                                outb(0x00, dev->iobase + DT2815_STATUS);
 
249
                }
 
250
        }
 
251
 
 
252
        return 0;
 
253
}
 
254
 
 
255
static void dt2815_free_resources(struct comedi_device *dev)
 
256
{
 
257
        if (dev->iobase)
 
258
                release_region(dev->iobase, DT2815_SIZE);
 
259
}
 
260
 
 
261
static int dt2815_detach(struct comedi_device *dev)
 
262
{
 
263
        printk(KERN_INFO "comedi%d: dt2815: remove\n", dev->minor);
 
264
 
 
265
        dt2815_free_resources(dev);
 
266
 
 
267
        return 0;
 
268
}
 
269
 
 
270
MODULE_AUTHOR("Comedi http://www.comedi.org");
 
271
MODULE_DESCRIPTION("Comedi low-level driver");
 
272
MODULE_LICENSE("GPL");