Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[deliverable/linux.git] / drivers / staging / comedi / drivers / das800.c
CommitLineData
3726e56b
FMH
1/*
2 comedi/drivers/das800.c
3 Driver for Keitley das800 series boards and compatibles
4 Copyright (C) 2000 Frank Mori Hess <fmhess@users.sourceforge.net>
5
6 COMEDI - Linux Control and Measurement Device Interface
7 Copyright (C) 2000 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.
3726e56b
FMH
18*/
19/*
20Driver: das800
21Description: Keithley Metrabyte DAS800 (& compatibles)
22Author: Frank Mori Hess <fmhess@users.sourceforge.net>
23Devices: [Keithley Metrabyte] DAS-800 (das-800), DAS-801 (das-801),
24 DAS-802 (das-802),
25 [Measurement Computing] CIO-DAS800 (cio-das800),
26 CIO-DAS801 (cio-das801), CIO-DAS802 (cio-das802),
27 CIO-DAS802/16 (cio-das802/16)
28Status: works, cio-das802/16 untested - email me if you have tested it
29
30Configuration options:
31 [0] - I/O port base address
32 [1] - IRQ (optional, required for timed or externally triggered conversions)
33
34Notes:
35 IRQ can be omitted, although the cmd interface will not work without it.
36
37 All entries in the channel/gain list must use the same gain and be
38 consecutive channels counting upwards in channel number (these are
39 hardware limitations.)
40
41 I've never tested the gain setting stuff since I only have a
42 DAS-800 board with fixed gain.
43
44 The cio-das802/16 does not have a fifo-empty status bit! Therefore
45 only fifo-half-full transfers are possible with this card.
46*/
47/*
48
49cmd triggers supported:
50 start_src: TRIG_NOW | TRIG_EXT
51 scan_begin_src: TRIG_FOLLOW
52 scan_end_src: TRIG_COUNT
53 convert_src: TRIG_TIMER | TRIG_EXT
54 stop_src: TRIG_NONE | TRIG_COUNT
55
56
57*/
58
ce157f80 59#include <linux/module.h>
25436dc9 60#include <linux/interrupt.h>
3726e56b
FMH
61#include "../comedidev.h"
62
3726e56b
FMH
63#include <linux/delay.h>
64
65#include "8253.h"
66#include "comedi_fc.h"
67
2696fb57 68#define N_CHAN_AI 8 /* number of analog input channels */
3726e56b
FMH
69
70/* Registers for the das800 */
71
72#define DAS800_LSB 0
73#define FIFO_EMPTY 0x1
74#define FIFO_OVF 0x2
75#define DAS800_MSB 1
76#define DAS800_CONTROL1 2
77#define CONTROL1_INTE 0x8
78#define DAS800_CONV_CONTROL 2
79#define ITE 0x1
80#define CASC 0x2
81#define DTEN 0x4
82#define IEOC 0x8
83#define EACS 0x10
84#define CONV_HCEN 0x80
85#define DAS800_SCAN_LIMITS 2
86#define DAS800_STATUS 2
87#define IRQ 0x8
88#define BUSY 0x80
89#define DAS800_GAIN 3
eca7cf72
HS
90#define CIO_FFOV 0x8 /* cio-das802/16 fifo overflow */
91#define CIO_ENHF 0x90 /* cio-das802/16 fifo half full int ena */
3726e56b
FMH
92#define CONTROL1 0x80
93#define CONV_CONTROL 0xa0
94#define SCAN_LIMITS 0xc0
95#define ID 0xe0
96#define DAS800_8254 4
97#define DAS800_STATUS2 7
98#define STATUS2_HCEN 0x80
99#define STATUS2_INTE 0X20
100#define DAS800_ID 7
101
7f340859
HS
102#define DAS802_16_HALF_FIFO_SZ 128
103
febc2ed6 104struct das800_board {
3726e56b
FMH
105 const char *name;
106 int ai_speed;
9ced1de6 107 const struct comedi_lrange *ai_range;
3726e56b 108 int resolution;
febc2ed6 109};
3726e56b 110
9ced1de6 111static const struct comedi_lrange range_das801_ai = {
b678075f
HS
112 9, {
113 BIP_RANGE(5),
114 BIP_RANGE(10),
115 UNI_RANGE(10),
116 BIP_RANGE(0.5),
117 UNI_RANGE(1),
118 BIP_RANGE(0.05),
119 UNI_RANGE(0.1),
120 BIP_RANGE(0.01),
121 UNI_RANGE(0.02)
122 }
3726e56b
FMH
123};
124
9ced1de6 125static const struct comedi_lrange range_cio_das801_ai = {
b678075f
HS
126 9, {
127 BIP_RANGE(5),
128 BIP_RANGE(10),
129 UNI_RANGE(10),
130 BIP_RANGE(0.5),
131 UNI_RANGE(1),
132 BIP_RANGE(0.05),
133 UNI_RANGE(0.1),
134 BIP_RANGE(0.005),
135 UNI_RANGE(0.01)
136 }
3726e56b
FMH
137};
138
9ced1de6 139static const struct comedi_lrange range_das802_ai = {
b678075f
HS
140 9, {
141 BIP_RANGE(5),
142 BIP_RANGE(10),
143 UNI_RANGE(10),
144 BIP_RANGE(2.5),
145 UNI_RANGE(5),
146 BIP_RANGE(1.25),
147 UNI_RANGE(2.5),
148 BIP_RANGE(0.625),
149 UNI_RANGE(1.25)
150 }
3726e56b
FMH
151};
152
9ced1de6 153static const struct comedi_lrange range_das80216_ai = {
b678075f
HS
154 8, {
155 BIP_RANGE(10),
156 UNI_RANGE(10),
157 BIP_RANGE(5),
158 UNI_RANGE(5),
159 BIP_RANGE(2.5),
160 UNI_RANGE(2.5),
161 BIP_RANGE(1.25),
162 UNI_RANGE(1.25)
163 }
3726e56b
FMH
164};
165
c1a59171
HS
166enum das800_boardinfo {
167 BOARD_DAS800,
168 BOARD_CIODAS800,
169 BOARD_DAS801,
170 BOARD_CIODAS801,
171 BOARD_DAS802,
172 BOARD_CIODAS802,
173 BOARD_CIODAS80216,
174};
3726e56b 175
febc2ed6 176static const struct das800_board das800_boards[] = {
c1a59171
HS
177 [BOARD_DAS800] = {
178 .name = "das-800",
179 .ai_speed = 25000,
180 .ai_range = &range_bipolar5,
181 .resolution = 12,
182 },
183 [BOARD_CIODAS800] = {
184 .name = "cio-das800",
185 .ai_speed = 20000,
186 .ai_range = &range_bipolar5,
187 .resolution = 12,
188 },
189 [BOARD_DAS801] = {
190 .name = "das-801",
191 .ai_speed = 25000,
192 .ai_range = &range_das801_ai,
193 .resolution = 12,
194 },
195 [BOARD_CIODAS801] = {
196 .name = "cio-das801",
197 .ai_speed = 20000,
198 .ai_range = &range_cio_das801_ai,
199 .resolution = 12,
200 },
201 [BOARD_DAS802] = {
202 .name = "das-802",
203 .ai_speed = 25000,
204 .ai_range = &range_das802_ai,
205 .resolution = 12,
206 },
207 [BOARD_CIODAS802] = {
208 .name = "cio-das802",
209 .ai_speed = 20000,
210 .ai_range = &range_das802_ai,
211 .resolution = 12,
212 },
213 [BOARD_CIODAS80216] = {
214 .name = "cio-das802/16",
215 .ai_speed = 10000,
216 .ai_range = &range_das80216_ai,
217 .resolution = 16,
218 },
3726e56b
FMH
219};
220
938f185d 221struct das800_private {
808cea5a 222 unsigned int count; /* number of data points left to be taken */
808cea5a
HS
223 unsigned int divisor1; /* counter 1 value for timed conversions */
224 unsigned int divisor2; /* counter 2 value for timed conversions */
ad5774fc 225 unsigned int do_bits; /* digital output bits */
938f185d 226};
3726e56b 227
0a8fc089
HS
228static void das800_ind_write(struct comedi_device *dev,
229 unsigned val, unsigned reg)
230{
231 /*
232 * Select dev->iobase + 2 to be desired register
233 * then write to that register.
234 */
235 outb(reg, dev->iobase + DAS800_GAIN);
236 outb(val, dev->iobase + 2);
237}
238
239static unsigned das800_ind_read(struct comedi_device *dev, unsigned reg)
240{
241 /*
242 * Select dev->iobase + 7 to be desired register
243 * then read from that register.
244 */
245 outb(reg, dev->iobase + DAS800_GAIN);
246 return inb(dev->iobase + 7);
247}
248
57d1ebf7 249static void das800_enable(struct comedi_device *dev)
3726e56b 250{
b7793094 251 const struct das800_board *thisboard = dev->board_ptr;
9a1a6cf8 252 struct das800_private *devpriv = dev->private;
3726e56b 253 unsigned long irq_flags;
9a1a6cf8 254
5f74ea14 255 spin_lock_irqsave(&dev->spinlock, irq_flags);
2696fb57 256 /* enable fifo-half full interrupts for cio-das802/16 */
3726e56b
FMH
257 if (thisboard->resolution == 16)
258 outb(CIO_ENHF, dev->iobase + DAS800_GAIN);
0a8fc089
HS
259 /* enable hardware triggering */
260 das800_ind_write(dev, CONV_HCEN, CONV_CONTROL);
261 /* enable card's interrupt */
262 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
5f74ea14 263 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
264}
265
57d1ebf7 266static void das800_disable(struct comedi_device *dev)
3726e56b
FMH
267{
268 unsigned long irq_flags;
0a8fc089 269
5f74ea14 270 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089
HS
271 /* disable hardware triggering of conversions */
272 das800_ind_write(dev, 0x0, CONV_CONTROL);
5f74ea14 273 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
274}
275
52c9e62c 276static void das800_set_frequency(struct comedi_device *dev)
62c3b4bf
HS
277{
278 struct das800_private *devpriv = dev->private;
52c9e62c 279 unsigned long timer_base = dev->iobase + DAS800_8254;
62c3b4bf 280
52c9e62c
HS
281 i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
282 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
283 i8254_write(timer_base, 0, 1, devpriv->divisor1);
284 i8254_write(timer_base, 0, 2, devpriv->divisor2);
62c3b4bf
HS
285}
286
fe9b0850
HS
287static int das800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
288{
289 struct das800_private *devpriv = dev->private;
290
fe9b0850 291 devpriv->count = 0;
57d1ebf7 292 das800_disable(dev);
fe9b0850
HS
293 return 0;
294}
295
1626657f
HS
296static int das800_ai_check_chanlist(struct comedi_device *dev,
297 struct comedi_subdevice *s,
298 struct comedi_cmd *cmd)
299{
300 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
301 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
302 int i;
303
304 for (i = 1; i < cmd->chanlist_len; i++) {
305 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
306 unsigned int range = CR_RANGE(cmd->chanlist[i]);
307
308 if (chan != (chan0 + i) % s->n_chan) {
309 dev_dbg(dev->class_dev,
310 "chanlist must be consecutive, counting upwards\n");
311 return -EINVAL;
312 }
313
314 if (range != range0) {
315 dev_dbg(dev->class_dev,
316 "chanlist must all have the same gain\n");
317 return -EINVAL;
318 }
319 }
320
321 return 0;
322}
323
0a85b6f0
MT
324static int das800_ai_do_cmdtest(struct comedi_device *dev,
325 struct comedi_subdevice *s,
326 struct comedi_cmd *cmd)
3726e56b 327{
b7793094 328 const struct das800_board *thisboard = dev->board_ptr;
9a1a6cf8 329 struct das800_private *devpriv = dev->private;
3726e56b 330 int err = 0;
58245cc9 331 unsigned int arg;
3726e56b 332
27020ffe 333 /* Step 1 : check if triggers are trivially valid */
3726e56b 334
27020ffe
HS
335 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
336 err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
337 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
338 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
339 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
3726e56b
FMH
340
341 if (err)
342 return 1;
343
27020ffe 344 /* Step 2a : make sure trigger sources are unique */
3726e56b 345
27020ffe
HS
346 err |= cfc_check_trigger_is_unique(cmd->start_src);
347 err |= cfc_check_trigger_is_unique(cmd->convert_src);
348 err |= cfc_check_trigger_is_unique(cmd->stop_src);
349
350 /* Step 2b : and mutually compatible */
3726e56b
FMH
351
352 if (err)
353 return 2;
354
50b825ff 355 /* Step 3: check if arguments are trivially valid */
3726e56b 356
50b825ff
HS
357 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
358
359 if (cmd->convert_src == TRIG_TIMER)
360 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
361 thisboard->ai_speed);
362
363 err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
364 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
365
366 if (cmd->stop_src == TRIG_COUNT)
367 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
368 else /* TRIG_NONE */
369 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
3726e56b
FMH
370
371 if (err)
372 return 3;
373
374 /* step 4: fix up any arguments */
375
376 if (cmd->convert_src == TRIG_TIMER) {
58245cc9 377 arg = cmd->convert_arg;
cb9cfd7e
HS
378 i8253_cascade_ns_to_timer(I8254_OSC_BASE_1MHZ,
379 &devpriv->divisor1,
380 &devpriv->divisor2,
58245cc9
HS
381 &arg, cmd->flags);
382 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
3726e56b
FMH
383 }
384
385 if (err)
386 return 4;
387
1626657f
HS
388 /* Step 5: check channel list if it exists */
389 if (cmd->chanlist && cmd->chanlist_len > 0)
390 err |= das800_ai_check_chanlist(dev, s, cmd);
3726e56b
FMH
391
392 if (err)
393 return 5;
394
395 return 0;
396}
397
0a85b6f0
MT
398static int das800_ai_do_cmd(struct comedi_device *dev,
399 struct comedi_subdevice *s)
3726e56b 400{
b7793094 401 const struct das800_board *thisboard = dev->board_ptr;
9a1a6cf8 402 struct das800_private *devpriv = dev->private;
d24160f8 403 struct comedi_async *async = s->async;
8ffffae6
HS
404 struct comedi_cmd *cmd = &async->cmd;
405 unsigned int gain = CR_RANGE(cmd->chanlist[0]);
406 unsigned int start_chan = CR_CHAN(cmd->chanlist[0]);
407 unsigned int end_chan = (start_chan + cmd->chanlist_len - 1) % 8;
d24160f8 408 unsigned int scan_chans = (end_chan << 3) | start_chan;
3726e56b
FMH
409 int conv_bits;
410 unsigned long irq_flags;
3726e56b 411
57d1ebf7 412 das800_disable(dev);
3726e56b 413
5f74ea14 414 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 415 /* set scan limits */
d24160f8 416 das800_ind_write(dev, scan_chans, SCAN_LIMITS);
5f74ea14 417 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
418
419 /* set gain */
3726e56b
FMH
420 if (thisboard->resolution == 12 && gain > 0)
421 gain += 0x7;
422 gain &= 0xf;
423 outb(gain, dev->iobase + DAS800_GAIN);
424
9dad12fe 425 if (cmd->stop_src == TRIG_COUNT)
8ffffae6 426 devpriv->count = cmd->stop_arg * cmd->chanlist_len;
9dad12fe 427 else /* TRIG_NONE */
3726e56b 428 devpriv->count = 0;
3726e56b
FMH
429
430 /* enable auto channel scan, send interrupts on end of conversion
431 * and set clock source to internal or external
432 */
433 conv_bits = 0;
434 conv_bits |= EACS | IEOC;
8ffffae6 435 if (cmd->start_src == TRIG_EXT)
3726e56b 436 conv_bits |= DTEN;
8ffffae6 437 if (cmd->convert_src == TRIG_TIMER) {
3726e56b
FMH
438 conv_bits |= CASC | ITE;
439 /* set conversion frequency */
52c9e62c 440 das800_set_frequency(dev);
3726e56b
FMH
441 }
442
5f74ea14 443 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 444 das800_ind_write(dev, conv_bits, CONV_CONTROL);
5f74ea14 445 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
0a8fc089 446
57d1ebf7 447 das800_enable(dev);
3726e56b
FMH
448 return 0;
449}
450
b4780a3a
HS
451static unsigned int das800_ai_get_sample(struct comedi_device *dev)
452{
453 unsigned int lsb = inb(dev->iobase + DAS800_LSB);
454 unsigned int msb = inb(dev->iobase + DAS800_MSB);
455
456 return (msb << 8) | lsb;
457}
458
fe9b0850
HS
459static irqreturn_t das800_interrupt(int irq, void *d)
460{
fe9b0850 461 struct comedi_device *dev = d;
fe9b0850 462 struct das800_private *devpriv = dev->private;
7f340859 463 struct comedi_subdevice *s = dev->read_subdev;
9dad12fe
HS
464 struct comedi_async *async;
465 struct comedi_cmd *cmd;
fe9b0850 466 unsigned long irq_flags;
7f340859
HS
467 unsigned int status;
468 unsigned int val;
469 bool fifo_empty;
470 bool fifo_overflow;
471 int i;
fe9b0850
HS
472
473 status = inb(dev->iobase + DAS800_STATUS);
fe9b0850
HS
474 if (!(status & IRQ))
475 return IRQ_NONE;
7f340859 476 if (!dev->attached)
fe9b0850
HS
477 return IRQ_HANDLED;
478
9dad12fe
HS
479 async = s->async;
480 cmd = &async->cmd;
481
fe9b0850 482 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 483 status = das800_ind_read(dev, CONTROL1) & STATUS2_HCEN;
7f340859
HS
484 /*
485 * Don't release spinlock yet since we want to make sure
486 * no one else disables hardware conversions.
487 */
488
489 /* if hardware conversions are not enabled, then quit */
fe9b0850
HS
490 if (status == 0) {
491 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
492 return IRQ_HANDLED;
493 }
494
7f340859
HS
495 for (i = 0; i < DAS802_16_HALF_FIFO_SZ; i++) {
496 val = das800_ai_get_sample(dev);
497 if (s->maxdata == 0x0fff) {
498 fifo_empty = !!(val & FIFO_EMPTY);
499 fifo_overflow = !!(val & FIFO_OVF);
fe9b0850 500 } else {
7f340859
HS
501 /* cio-das802/16 has no fifo empty status bit */
502 fifo_empty = false;
503 fifo_overflow = !!(inb(dev->iobase + DAS800_GAIN) &
504 CIO_FFOV);
fe9b0850 505 }
7f340859 506 if (fifo_empty || fifo_overflow)
fe9b0850 507 break;
7f340859
HS
508
509 if (s->maxdata == 0x0fff)
510 val >>= 4; /* 12-bit sample */
511
fe9b0850 512 /* if there are more data points to collect */
9dad12fe 513 if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) {
fe9b0850 514 /* write data point to buffer */
7f340859
HS
515 cfc_write_to_buffer(s, val & s->maxdata);
516 devpriv->count--;
fe9b0850
HS
517 }
518 }
519 async->events |= COMEDI_CB_BLOCK;
7f340859 520
fe9b0850
HS
521 if (fifo_overflow) {
522 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
fe9b0850 523 async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
f382898f 524 cfc_handle_events(dev, s);
fe9b0850
HS
525 return IRQ_HANDLED;
526 }
7f340859 527
9dad12fe 528 if (cmd->stop_src == TRIG_NONE || devpriv->count > 0) {
fe9b0850
HS
529 /* Re-enable card's interrupt.
530 * We already have spinlock, so indirect addressing is safe */
0a8fc089
HS
531 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
532 CONTROL1);
fe9b0850 533 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
fe9b0850 534 } else {
7f340859 535 /* otherwise, stop taking data */
fe9b0850 536 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
57d1ebf7 537 das800_disable(dev);
fe9b0850
HS
538 async->events |= COMEDI_CB_EOA;
539 }
f382898f 540 cfc_handle_events(dev, s);
fe9b0850
HS
541 return IRQ_HANDLED;
542}
543
90bc68ec
HS
544static int das800_ai_eoc(struct comedi_device *dev,
545 struct comedi_subdevice *s,
546 struct comedi_insn *insn,
547 unsigned long context)
b4780a3a 548{
90bc68ec 549 unsigned int status;
b4780a3a 550
90bc68ec
HS
551 status = inb(dev->iobase + DAS800_STATUS);
552 if ((status & BUSY) == 0)
553 return 0;
554 return -EBUSY;
b4780a3a
HS
555}
556
d7427345
HS
557static int das800_ai_insn_read(struct comedi_device *dev,
558 struct comedi_subdevice *s,
559 struct comedi_insn *insn,
560 unsigned int *data)
3726e56b 561{
9a1a6cf8 562 struct das800_private *devpriv = dev->private;
b4780a3a
HS
563 unsigned int chan = CR_CHAN(insn->chanspec);
564 unsigned int range = CR_RANGE(insn->chanspec);
3726e56b 565 unsigned long irq_flags;
b4780a3a
HS
566 unsigned int val;
567 int ret;
568 int i;
3726e56b 569
57d1ebf7 570 das800_disable(dev);
3726e56b
FMH
571
572 /* set multiplexer */
5f74ea14 573 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 574 das800_ind_write(dev, chan | devpriv->do_bits, CONTROL1);
5f74ea14 575 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
3726e56b
FMH
576
577 /* set gain / range */
b4780a3a 578 if (s->maxdata == 0x0fff && range)
3726e56b
FMH
579 range += 0x7;
580 range &= 0xf;
581 outb(range, dev->iobase + DAS800_GAIN);
582
5f74ea14 583 udelay(5);
3726e56b 584
b4780a3a 585 for (i = 0; i < insn->n; i++) {
3726e56b
FMH
586 /* trigger conversion */
587 outb_p(0, dev->iobase + DAS800_MSB);
588
90bc68ec 589 ret = comedi_timeout(dev, s, insn, das800_ai_eoc, 0);
b4780a3a
HS
590 if (ret)
591 return ret;
592
593 val = das800_ai_get_sample(dev);
594 if (s->maxdata == 0x0fff)
595 val >>= 4; /* 12-bit sample */
596 data[i] = val & s->maxdata;
3726e56b
FMH
597 }
598
b4780a3a 599 return insn->n;
3726e56b
FMH
600}
601
d7427345
HS
602static int das800_di_insn_bits(struct comedi_device *dev,
603 struct comedi_subdevice *s,
604 struct comedi_insn *insn,
605 unsigned int *data)
3726e56b 606{
e245b6d1 607 data[1] = (inb(dev->iobase + DAS800_STATUS) >> 4) & 0x7;
3726e56b 608
a2714e3e 609 return insn->n;
3726e56b
FMH
610}
611
d7427345
HS
612static int das800_do_insn_bits(struct comedi_device *dev,
613 struct comedi_subdevice *s,
614 struct comedi_insn *insn,
615 unsigned int *data)
3726e56b 616{
9a1a6cf8 617 struct das800_private *devpriv = dev->private;
3726e56b
FMH
618 unsigned long irq_flags;
619
97f4289a 620 if (comedi_dio_update_state(s, data)) {
26234771 621 devpriv->do_bits = s->state << 4;
3726e56b 622
26234771
HS
623 spin_lock_irqsave(&dev->spinlock, irq_flags);
624 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits,
625 CONTROL1);
626 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
627 }
3726e56b 628
26234771 629 data[1] = s->state;
3726e56b 630
a2714e3e 631 return insn->n;
3726e56b
FMH
632}
633
4f71ceeb
HS
634static int das800_probe(struct comedi_device *dev)
635{
b7793094 636 const struct das800_board *thisboard = dev->board_ptr;
c1a59171 637 int board = thisboard ? thisboard - das800_boards : -EINVAL;
4f71ceeb
HS
638 int id_bits;
639 unsigned long irq_flags;
4f71ceeb
HS
640
641 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 642 id_bits = das800_ind_read(dev, ID) & 0x3;
4f71ceeb
HS
643 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
644
4f71ceeb
HS
645 switch (id_bits) {
646 case 0x0:
c1a59171
HS
647 if (board == BOARD_DAS800 || board == BOARD_CIODAS800)
648 break;
4f71ceeb 649 dev_dbg(dev->class_dev, "Board model (probed): DAS-800\n");
c1a59171 650 board = BOARD_DAS800;
4f71ceeb
HS
651 break;
652 case 0x2:
c1a59171
HS
653 if (board == BOARD_DAS801 || board == BOARD_CIODAS801)
654 break;
4f71ceeb 655 dev_dbg(dev->class_dev, "Board model (probed): DAS-801\n");
c1a59171 656 board = BOARD_DAS801;
4f71ceeb
HS
657 break;
658 case 0x3:
c1a59171
HS
659 if (board == BOARD_DAS802 || board == BOARD_CIODAS802 ||
660 board == BOARD_CIODAS80216)
661 break;
4f71ceeb 662 dev_dbg(dev->class_dev, "Board model (probed): DAS-802\n");
c1a59171 663 board = BOARD_DAS802;
4f71ceeb
HS
664 break;
665 default:
c1a59171 666 dev_dbg(dev->class_dev, "Board model: 0x%x (unknown)\n",
4f71ceeb 667 id_bits);
c1a59171 668 board = -EINVAL;
4f71ceeb
HS
669 break;
670 }
c1a59171 671 return board;
4f71ceeb
HS
672}
673
92046ae4
HS
674static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it)
675{
1d57261c 676 const struct das800_board *thisboard;
92046ae4
HS
677 struct das800_private *devpriv;
678 struct comedi_subdevice *s;
679 unsigned int irq = it->options[1];
680 unsigned long irq_flags;
681 int board;
682 int ret;
683
0bdab509 684 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
92046ae4
HS
685 if (!devpriv)
686 return -ENOMEM;
92046ae4 687
862755ec 688 ret = comedi_request_region(dev, it->options[0], 0x8);
92046ae4
HS
689 if (ret)
690 return ret;
691
692 board = das800_probe(dev);
693 if (board < 0) {
694 dev_dbg(dev->class_dev, "unable to determine board type\n");
695 return -ENODEV;
696 }
697 dev->board_ptr = das800_boards + board;
b7793094 698 thisboard = dev->board_ptr;
f05ffb6e 699 dev->board_name = thisboard->name;
92046ae4 700
f05ffb6e
HS
701 if (irq > 1 && irq <= 7) {
702 ret = request_irq(irq, das800_interrupt, 0, dev->board_name,
703 dev);
704 if (ret == 0)
705 dev->irq = irq;
92046ae4 706 }
92046ae4
HS
707
708 ret = comedi_alloc_subdevices(dev, 3);
709 if (ret)
710 return ret;
711
d7427345 712 /* Analog Input subdevice */
92046ae4
HS
713 s = &dev->subdevices[0];
714 dev->read_subdev = s;
77630119
HS
715 s->type = COMEDI_SUBD_AI;
716 s->subdev_flags = SDF_READABLE | SDF_GROUND;
717 s->n_chan = 8;
718 s->maxdata = (1 << thisboard->resolution) - 1;
719 s->range_table = thisboard->ai_range;
d7427345 720 s->insn_read = das800_ai_insn_read;
77630119
HS
721 if (dev->irq) {
722 s->subdev_flags |= SDF_CMD_READ;
723 s->len_chanlist = 8;
724 s->do_cmdtest = das800_ai_do_cmdtest;
725 s->do_cmd = das800_ai_do_cmd;
726 s->cancel = das800_cancel;
727 }
92046ae4 728
d7427345 729 /* Digital Input subdevice */
92046ae4 730 s = &dev->subdevices[1];
d7427345
HS
731 s->type = COMEDI_SUBD_DI;
732 s->subdev_flags = SDF_READABLE;
733 s->n_chan = 3;
734 s->maxdata = 1;
735 s->range_table = &range_digital;
736 s->insn_bits = das800_di_insn_bits;
737
738 /* Digital Output subdevice */
92046ae4 739 s = &dev->subdevices[2];
d7427345
HS
740 s->type = COMEDI_SUBD_DO;
741 s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
742 s->n_chan = 4;
743 s->maxdata = 1;
744 s->range_table = &range_digital;
745 s->insn_bits = das800_do_insn_bits;
92046ae4 746
57d1ebf7 747 das800_disable(dev);
92046ae4
HS
748
749 /* initialize digital out channels */
750 spin_lock_irqsave(&dev->spinlock, irq_flags);
0a8fc089 751 das800_ind_write(dev, CONTROL1_INTE | devpriv->do_bits, CONTROL1);
92046ae4
HS
752 spin_unlock_irqrestore(&dev->spinlock, irq_flags);
753
754 return 0;
755};
756
79a8c0e2
HS
757static struct comedi_driver driver_das800 = {
758 .driver_name = "das800",
759 .module = THIS_MODULE,
760 .attach = das800_attach,
761 .detach = comedi_legacy_detach,
762 .num_names = ARRAY_SIZE(das800_boards),
763 .board_name = &das800_boards[0].name,
764 .offset = sizeof(struct das800_board),
765};
766module_comedi_driver(driver_das800);
767
90f703d3
AT
768MODULE_AUTHOR("Comedi http://www.comedi.org");
769MODULE_DESCRIPTION("Comedi low-level driver");
770MODULE_LICENSE("GPL");
This page took 0.669147 seconds and 5 git commands to generate.