staging: comedi: amplc_pci224: convert driver to use the comedi_8254 module
[deliverable/linux.git] / drivers / staging / comedi / drivers / cb_pcidas.c
CommitLineData
59c7dd3d
IM
1/*
2 comedi/drivers/cb_pcidas.c
3
4 Developed by Ivan Martinez and Frank Mori Hess, with valuable help from
5 David Schleef and the rest of the Comedi developers comunity.
6
7 Copyright (C) 2001-2003 Ivan Martinez <imr@oersted.dtu.dk>
8 Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
9
10 COMEDI - Linux Control and Measurement Device Interface
11 Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
12
13 This program is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2 of the License, or
16 (at your option) any later version.
17
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
59c7dd3d
IM
22*/
23/*
24Driver: cb_pcidas
d478b5f6
HS
25Description: MeasurementComputing PCI-DAS series
26 with the AMCC S5933 PCI controller
59c7dd3d
IM
27Author: Ivan Martinez <imr@oersted.dtu.dk>,
28 Frank Mori Hess <fmhess@users.sourceforge.net>
29Updated: 2003-3-11
30Devices: [Measurement Computing] PCI-DAS1602/16 (cb_pcidas),
31 PCI-DAS1602/16jr, PCI-DAS1602/12, PCI-DAS1200, PCI-DAS1200jr,
32 PCI-DAS1000, PCI-DAS1001, PCI_DAS1002
33
34Status:
35 There are many reports of the driver being used with most of the
36 supported cards. Despite no detailed log is maintained, it can
37 be said that the driver is quite tested and stable.
38
39 The boards may be autocalibrated using the comedi_calibrate
40 utility.
41
3b96f250 42Configuration options: not applicable, uses PCI auto config
59c7dd3d
IM
43
44For commands, the scanned channels must be consecutive
45(i.e. 4-5-6-7, 2-3-4,...), and must all have the same
46range and aref.
f1bc4343
BD
47
48AI Triggering:
49 For start_src == TRIG_EXT, the A/D EXTERNAL TRIGGER IN (pin 45) is used.
50 For 1602 series, the start_arg is interpreted as follows:
bc04bec0
MI
51 start_arg == 0 => gated trigger (level high)
52 start_arg == CR_INVERT => gated trigger (level low)
f1bc4343
BD
53 start_arg == CR_EDGE => Rising edge
54 start_arg == CR_EDGE | CR_INVERT => Falling edge
55 For the other boards the trigger will be done on rising edge
59c7dd3d
IM
56*/
57/*
58
59TODO:
60
61analog triggering on 1602 series
62*/
63
ce157f80 64#include <linux/module.h>
33782dd5 65#include <linux/pci.h>
59c7dd3d 66#include <linux/delay.h>
70265d24 67#include <linux/interrupt.h>
59c7dd3d 68
33782dd5
HS
69#include "../comedidev.h"
70
59c7dd3d
IM
71#include "8253.h"
72#include "8255.h"
73#include "amcc_s5933.h"
59c7dd3d
IM
74#include "comedi_fc.h"
75
6993197b
HS
76#define AI_BUFFER_SIZE 1024 /* max ai fifo size */
77#define AO_BUFFER_SIZE 1024 /* max ao fifo size */
78#define NUM_CHANNELS_8800 8
79#define NUM_CHANNELS_7376 1
80#define NUM_CHANNELS_8402 2
81#define NUM_CHANNELS_DAC08 1
59c7dd3d 82
59c7dd3d 83/* Control/Status registers */
6993197b
HS
84#define INT_ADCFIFO 0 /* INTERRUPT / ADC FIFO register */
85#define INT_EOS 0x1 /* int end of scan */
86#define INT_FHF 0x2 /* int fifo half full */
87#define INT_FNE 0x3 /* int fifo not empty */
88#define INT_MASK 0x3 /* mask of int select bits */
89#define INTE 0x4 /* int enable */
90#define DAHFIE 0x8 /* dac half full int enable */
91#define EOAIE 0x10 /* end of acq. int enable */
92#define DAHFI 0x20 /* dac half full status / clear */
93#define EOAI 0x40 /* end of acq. int status / clear */
94#define INT 0x80 /* int status / clear */
95#define EOBI 0x200 /* end of burst int status */
96#define ADHFI 0x400 /* half-full int status */
97#define ADNEI 0x800 /* fifo not empty int status (latch) */
98#define ADNE 0x1000 /* fifo not empty status (realtime) */
99#define DAEMIE 0x1000 /* dac empty int enable */
100#define LADFUL 0x2000 /* fifo overflow / clear */
101#define DAEMI 0x4000 /* dac fifo empty int status / clear */
102
103#define ADCMUX_CONT 2 /* ADC CHANNEL MUX AND CONTROL reg */
104#define BEGIN_SCAN(x) ((x) & 0xf)
105#define END_SCAN(x) (((x) & 0xf) << 4)
106#define GAIN_BITS(x) (((x) & 0x3) << 8)
107#define UNIP 0x800 /* Analog front-end unipolar mode */
108#define SE 0x400 /* Inputs in single-ended mode */
109#define PACER_MASK 0x3000 /* pacer source bits */
110#define PACER_INT 0x1000 /* int. pacer */
111#define PACER_EXT_FALL 0x2000 /* ext. falling edge */
112#define PACER_EXT_RISE 0x3000 /* ext. rising edge */
113#define EOC 0x4000 /* adc not busy */
114
115#define TRIG_CONTSTAT 4 /* TRIGGER CONTROL/STATUS register */
116#define SW_TRIGGER 0x1 /* software start trigger */
117#define EXT_TRIGGER 0x2 /* ext. start trigger */
118#define ANALOG_TRIGGER 0x3 /* ext. analog trigger */
119#define TRIGGER_MASK 0x3 /* start trigger mask */
120#define TGPOL 0x04 /* invert trigger (1602 only) */
121#define TGSEL 0x08 /* edge/level trigerred (1602 only) */
122#define TGEN 0x10 /* enable external start trigger */
123#define BURSTE 0x20 /* burst mode enable */
124#define XTRCL 0x80 /* clear external trigger */
125
126#define CALIBRATION_REG 6 /* CALIBRATION register */
127#define SELECT_8800_BIT 0x100 /* select 8800 caldac */
128#define SELECT_TRIMPOT_BIT 0x200 /* select ad7376 trim pot */
129#define SELECT_DAC08_BIT 0x400 /* select dac08 caldac */
59c7dd3d 130#define CAL_SRC_BITS(x) (((x) & 0x7) << 11)
6993197b
HS
131#define CAL_EN_BIT 0x4000 /* calibration source enable */
132#define SERIAL_DATA_IN_BIT 0x8000 /* serial data bit going to caldac */
59c7dd3d 133
7368348c
HS
134#define DAC_CSR 0x8 /* dac control and status register */
135#define DACEN 0x02 /* dac enable */
136#define DAC_MODE_UPDATE_BOTH 0x80 /* update both dacs */
137
59c7dd3d
IM
138static inline unsigned int DAC_RANGE(unsigned int channel, unsigned int range)
139{
140 return (range & 0x3) << (8 + 2 * (channel & 0x1));
141}
0a85b6f0 142
59c7dd3d
IM
143static inline unsigned int DAC_RANGE_MASK(unsigned int channel)
144{
145 return 0x3 << (8 + 2 * (channel & 0x1));
146};
147
cf530aa4 148/* bits for 1602 series only */
6993197b
HS
149#define DAC_EMPTY 0x1 /* fifo empty, read, write clear */
150#define DAC_START 0x4 /* start/arm fifo operations */
151#define DAC_PACER_MASK 0x18 /* bits that set pacer source */
152#define DAC_PACER_INT 0x8 /* int. pacing */
153#define DAC_PACER_EXT_FALL 0x10 /* ext. pacing, falling edge */
154#define DAC_PACER_EXT_RISE 0x18 /* ext. pacing, rising edge */
7368348c 155
59c7dd3d
IM
156static inline unsigned int DAC_CHAN_EN(unsigned int channel)
157{
cf530aa4 158 return 1 << (5 + (channel & 0x1)); /* enable channel 0 or 1 */
59c7dd3d
IM
159};
160
161/* analog input fifo */
6993197b
HS
162#define ADCDATA 0 /* ADC DATA register */
163#define ADCFIFOCLR 2 /* ADC FIFO CLEAR */
59c7dd3d 164
cf530aa4 165/* pacer, counter, dio registers */
6993197b
HS
166#define ADC8254 0
167#define DIO_8255 4
168#define DAC8254 8
59c7dd3d 169
cf530aa4 170/* analog output registers for 100x, 1200 series */
59c7dd3d
IM
171static inline unsigned int DAC_DATA_REG(unsigned int channel)
172{
173 return 2 * (channel & 0x1);
174}
175
176/* analog output registers for 1602 series*/
6993197b
HS
177#define DACDATA 0 /* DAC DATA register */
178#define DACFIFOCLR 2 /* DAC FIFO CLEAR */
179
180#define IS_UNIPOLAR 0x4 /* unipolar range mask */
59c7dd3d 181
cf530aa4 182/* analog input ranges for most boards */
9ced1de6 183static const struct comedi_lrange cb_pcidas_ranges = {
1491ca0d
HS
184 8, {
185 BIP_RANGE(10),
186 BIP_RANGE(5),
187 BIP_RANGE(2.5),
188 BIP_RANGE(1.25),
189 UNI_RANGE(10),
190 UNI_RANGE(5),
191 UNI_RANGE(2.5),
192 UNI_RANGE(1.25)
193 }
59c7dd3d
IM
194};
195
cf530aa4 196/* pci-das1001 input ranges */
9ced1de6 197static const struct comedi_lrange cb_pcidas_alt_ranges = {
1491ca0d
HS
198 8, {
199 BIP_RANGE(10),
200 BIP_RANGE(1),
201 BIP_RANGE(0.1),
202 BIP_RANGE(0.01),
203 UNI_RANGE(10),
204 UNI_RANGE(1),
205 UNI_RANGE(0.1),
206 UNI_RANGE(0.01)
207 }
59c7dd3d
IM
208};
209
cf530aa4 210/* analog output ranges */
9ced1de6 211static const struct comedi_lrange cb_pcidas_ao_ranges = {
1491ca0d
HS
212 4, {
213 BIP_RANGE(5),
214 BIP_RANGE(10),
215 UNI_RANGE(5),
216 UNI_RANGE(10)
217 }
59c7dd3d
IM
218};
219
220enum trimpot_model {
221 AD7376,
222 AD8402,
223};
224
9b315bcb
HS
225enum cb_pcidas_boardid {
226 BOARD_PCIDAS1602_16,
227 BOARD_PCIDAS1200,
228 BOARD_PCIDAS1602_12,
229 BOARD_PCIDAS1200_JR,
230 BOARD_PCIDAS1602_16_JR,
231 BOARD_PCIDAS1000,
232 BOARD_PCIDAS1001,
233 BOARD_PCIDAS1002,
234};
235
5c2670cb 236struct cb_pcidas_board {
59c7dd3d 237 const char *name;
8f608fc8 238 int ai_nchan; /* Inputs in single-ended mode */
cf530aa4
BP
239 int ai_bits; /* analog input resolution */
240 int ai_speed; /* fastest conversion period in ns */
241 int ao_nchan; /* number of analog out channels */
242 int has_ao_fifo; /* analog output has fifo */
d478b5f6 243 int ao_scan_speed; /* analog output scan speed for 1602 series */
cf530aa4 244 int fifo_size; /* number of samples fifo can hold */
9ced1de6 245 const struct comedi_lrange *ranges;
59c7dd3d
IM
246 enum trimpot_model trimpot;
247 unsigned has_dac08:1;
23e3cce3 248 unsigned is_1602:1;
5c2670cb 249};
59c7dd3d 250
5c2670cb 251static const struct cb_pcidas_board cb_pcidas_boards[] = {
9b315bcb 252 [BOARD_PCIDAS1602_16] = {
17883d63 253 .name = "pci-das1602/16",
8f608fc8 254 .ai_nchan = 16,
17883d63
HS
255 .ai_bits = 16,
256 .ai_speed = 5000,
257 .ao_nchan = 2,
258 .has_ao_fifo = 1,
259 .ao_scan_speed = 10000,
260 .fifo_size = 512,
261 .ranges = &cb_pcidas_ranges,
262 .trimpot = AD8402,
263 .has_dac08 = 1,
264 .is_1602 = 1,
9b315bcb
HS
265 },
266 [BOARD_PCIDAS1200] = {
17883d63 267 .name = "pci-das1200",
8f608fc8 268 .ai_nchan = 16,
17883d63
HS
269 .ai_bits = 12,
270 .ai_speed = 3200,
271 .ao_nchan = 2,
17883d63
HS
272 .fifo_size = 1024,
273 .ranges = &cb_pcidas_ranges,
274 .trimpot = AD7376,
9b315bcb
HS
275 },
276 [BOARD_PCIDAS1602_12] = {
17883d63 277 .name = "pci-das1602/12",
8f608fc8 278 .ai_nchan = 16,
17883d63
HS
279 .ai_bits = 12,
280 .ai_speed = 3200,
281 .ao_nchan = 2,
282 .has_ao_fifo = 1,
283 .ao_scan_speed = 4000,
284 .fifo_size = 1024,
285 .ranges = &cb_pcidas_ranges,
286 .trimpot = AD7376,
17883d63 287 .is_1602 = 1,
9b315bcb
HS
288 },
289 [BOARD_PCIDAS1200_JR] = {
17883d63 290 .name = "pci-das1200/jr",
8f608fc8 291 .ai_nchan = 16,
17883d63
HS
292 .ai_bits = 12,
293 .ai_speed = 3200,
17883d63
HS
294 .fifo_size = 1024,
295 .ranges = &cb_pcidas_ranges,
296 .trimpot = AD7376,
9b315bcb
HS
297 },
298 [BOARD_PCIDAS1602_16_JR] = {
17883d63 299 .name = "pci-das1602/16/jr",
8f608fc8 300 .ai_nchan = 16,
17883d63
HS
301 .ai_bits = 16,
302 .ai_speed = 5000,
17883d63
HS
303 .fifo_size = 512,
304 .ranges = &cb_pcidas_ranges,
305 .trimpot = AD8402,
306 .has_dac08 = 1,
307 .is_1602 = 1,
9b315bcb
HS
308 },
309 [BOARD_PCIDAS1000] = {
17883d63 310 .name = "pci-das1000",
8f608fc8 311 .ai_nchan = 16,
17883d63
HS
312 .ai_bits = 12,
313 .ai_speed = 4000,
17883d63
HS
314 .fifo_size = 1024,
315 .ranges = &cb_pcidas_ranges,
316 .trimpot = AD7376,
9b315bcb
HS
317 },
318 [BOARD_PCIDAS1001] = {
17883d63 319 .name = "pci-das1001",
8f608fc8 320 .ai_nchan = 16,
17883d63
HS
321 .ai_bits = 12,
322 .ai_speed = 6800,
323 .ao_nchan = 2,
17883d63
HS
324 .fifo_size = 1024,
325 .ranges = &cb_pcidas_alt_ranges,
326 .trimpot = AD7376,
9b315bcb
HS
327 },
328 [BOARD_PCIDAS1002] = {
17883d63 329 .name = "pci-das1002",
8f608fc8 330 .ai_nchan = 16,
17883d63
HS
331 .ai_bits = 12,
332 .ai_speed = 6800,
333 .ao_nchan = 2,
17883d63
HS
334 .fifo_size = 1024,
335 .ranges = &cb_pcidas_ranges,
336 .trimpot = AD7376,
17883d63 337 },
59c7dd3d
IM
338};
339
c77e2589 340struct cb_pcidas_private {
0cdfbe15 341 /* base addresses */
59c7dd3d
IM
342 unsigned long s5933_config;
343 unsigned long control_status;
344 unsigned long adc_fifo;
59c7dd3d 345 unsigned long ao_registers;
0cdfbe15 346 /* divisors of master clock for analog input pacing */
59c7dd3d
IM
347 unsigned int divisor1;
348 unsigned int divisor2;
0cdfbe15
HS
349 /* bits to write to registers */
350 unsigned int adc_fifo_bits;
351 unsigned int s5933_intcsr_bits;
352 unsigned int ao_control_bits;
353 /* fifo buffers */
79e3b119
IA
354 unsigned short ai_buffer[AI_BUFFER_SIZE];
355 unsigned short ao_buffer[AO_BUFFER_SIZE];
0cdfbe15 356 /* divisors of master clock for analog output pacing */
59c7dd3d
IM
357 unsigned int ao_divisor1;
358 unsigned int ao_divisor2;
59c7dd3d 359 unsigned int calibration_source;
c77e2589 360};
59c7dd3d 361
814900c9 362static inline unsigned int cal_enable_bits(struct comedi_device *dev)
59c7dd3d 363{
82d8c74d
HS
364 struct cb_pcidas_private *devpriv = dev->private;
365
59c7dd3d
IM
366 return CAL_EN_BIT | CAL_SRC_BITS(devpriv->calibration_source);
367}
368
06cb9ba8
HS
369static int cb_pcidas_ai_eoc(struct comedi_device *dev,
370 struct comedi_subdevice *s,
371 struct comedi_insn *insn,
372 unsigned long context)
373{
374 struct cb_pcidas_private *devpriv = dev->private;
375 unsigned int status;
376
377 status = inw(devpriv->control_status + ADCMUX_CONT);
378 if (status & EOC)
379 return 0;
380 return -EBUSY;
381}
382
0a85b6f0
MT
383static int cb_pcidas_ai_rinsn(struct comedi_device *dev,
384 struct comedi_subdevice *s,
385 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 386{
82d8c74d 387 struct cb_pcidas_private *devpriv = dev->private;
f66faa57
HS
388 unsigned int chan = CR_CHAN(insn->chanspec);
389 unsigned int range = CR_RANGE(insn->chanspec);
390 unsigned int aref = CR_AREF(insn->chanspec);
59c7dd3d 391 unsigned int bits;
06cb9ba8
HS
392 int ret;
393 int n;
f66faa57
HS
394
395 /* enable calibration input if appropriate */
59c7dd3d
IM
396 if (insn->chanspec & CR_ALT_SOURCE) {
397 outw(cal_enable_bits(dev),
0a85b6f0 398 devpriv->control_status + CALIBRATION_REG);
f66faa57 399 chan = 0;
59c7dd3d
IM
400 } else {
401 outw(0, devpriv->control_status + CALIBRATION_REG);
59c7dd3d 402 }
f66faa57
HS
403
404 /* set mux limits and gain */
405 bits = BEGIN_SCAN(chan) | END_SCAN(chan) | GAIN_BITS(range);
406 /* set unipolar/bipolar */
407 if (range & IS_UNIPOLAR)
59c7dd3d 408 bits |= UNIP;
f66faa57
HS
409 /* set single-ended/differential */
410 if (aref != AREF_DIFF)
59c7dd3d
IM
411 bits |= SE;
412 outw(bits, devpriv->control_status + ADCMUX_CONT);
413
414 /* clear fifo */
415 outw(0, devpriv->adc_fifo + ADCFIFOCLR);
416
417 /* convert n samples */
418 for (n = 0; n < insn->n; n++) {
419 /* trigger conversion */
420 outw(0, devpriv->adc_fifo + ADCDATA);
421
422 /* wait for conversion to end */
06cb9ba8
HS
423 ret = comedi_timeout(dev, s, insn, cb_pcidas_ai_eoc, 0);
424 if (ret)
425 return ret;
59c7dd3d
IM
426
427 /* read data */
428 data[n] = inw(devpriv->adc_fifo + ADCDATA);
429 }
430
431 /* return the number of samples read/written */
432 return n;
433}
434
da91b269 435static int ai_config_insn(struct comedi_device *dev, struct comedi_subdevice *s,
0a85b6f0 436 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 437{
f3c34b2f 438 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d 439 int id = data[0];
f3c34b2f 440 unsigned int source = data[1];
59c7dd3d
IM
441
442 switch (id) {
443 case INSN_CONFIG_ALT_SOURCE:
f3c34b2f
HS
444 if (source >= 8) {
445 dev_err(dev->class_dev,
446 "invalid calibration source: %i\n",
447 source);
448 return -EINVAL;
449 }
450 devpriv->calibration_source = source;
59c7dd3d
IM
451 break;
452 default:
453 return -EINVAL;
59c7dd3d 454 }
f3c34b2f 455 return insn->n;
59c7dd3d
IM
456}
457
cf530aa4 458/* analog output insn for pcidas-1000 and 1200 series */
0a85b6f0
MT
459static int cb_pcidas_ao_nofifo_winsn(struct comedi_device *dev,
460 struct comedi_subdevice *s,
461 struct comedi_insn *insn,
462 unsigned int *data)
59c7dd3d 463{
82d8c74d 464 struct cb_pcidas_private *devpriv = dev->private;
7671896c
HS
465 unsigned int chan = CR_CHAN(insn->chanspec);
466 unsigned int range = CR_RANGE(insn->chanspec);
59c7dd3d
IM
467 unsigned long flags;
468
7671896c 469 /* set channel and range */
5f74ea14 470 spin_lock_irqsave(&dev->spinlock, flags);
7671896c
HS
471 devpriv->ao_control_bits &= (~DAC_MODE_UPDATE_BOTH &
472 ~DAC_RANGE_MASK(chan));
473 devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range));
59c7dd3d 474 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 475 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 476
7671896c 477 /* remember value for readback */
46da1c8f 478 s->readback[chan] = data[0];
7671896c
HS
479
480 /* send data */
481 outw(data[0], devpriv->ao_registers + DAC_DATA_REG(chan));
59c7dd3d 482
7671896c 483 return insn->n;
59c7dd3d
IM
484}
485
cf530aa4 486/* analog output insn for pcidas-1602 series */
0a85b6f0
MT
487static int cb_pcidas_ao_fifo_winsn(struct comedi_device *dev,
488 struct comedi_subdevice *s,
489 struct comedi_insn *insn, unsigned int *data)
59c7dd3d 490{
82d8c74d 491 struct cb_pcidas_private *devpriv = dev->private;
b78332da
HS
492 unsigned int chan = CR_CHAN(insn->chanspec);
493 unsigned int range = CR_RANGE(insn->chanspec);
59c7dd3d
IM
494 unsigned long flags;
495
b78332da 496 /* clear dac fifo */
59c7dd3d
IM
497 outw(0, devpriv->ao_registers + DACFIFOCLR);
498
b78332da 499 /* set channel and range */
5f74ea14 500 spin_lock_irqsave(&dev->spinlock, flags);
b78332da
HS
501 devpriv->ao_control_bits &= (~DAC_CHAN_EN(0) & ~DAC_CHAN_EN(1) &
502 ~DAC_RANGE_MASK(chan) & ~DAC_PACER_MASK);
503 devpriv->ao_control_bits |= (DACEN | DAC_RANGE(chan, range) |
504 DAC_CHAN_EN(chan) | DAC_START);
59c7dd3d 505 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 506 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 507
b78332da 508 /* remember value for readback */
46da1c8f 509 s->readback[chan] = data[0];
b78332da
HS
510
511 /* send data */
59c7dd3d
IM
512 outw(data[0], devpriv->ao_registers + DACDATA);
513
b78332da 514 return insn->n;
59c7dd3d
IM
515}
516
536af69e
HS
517static int wait_for_nvram_ready(unsigned long s5933_base_addr)
518{
519 static const int timeout = 1000;
520 unsigned int i;
521
522 for (i = 0; i < timeout; i++) {
523 if ((inb(s5933_base_addr +
524 AMCC_OP_REG_MCSR_NVCMD) & MCSR_NV_BUSY)
525 == 0)
526 return 0;
527 udelay(1);
528 }
529 return -1;
530}
531
532static int nvram_read(struct comedi_device *dev, unsigned int address,
533 uint8_t *data)
534{
82d8c74d 535 struct cb_pcidas_private *devpriv = dev->private;
536af69e
HS
536 unsigned long iobase = devpriv->s5933_config;
537
538 if (wait_for_nvram_ready(iobase) < 0)
539 return -ETIMEDOUT;
540
541 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_LOW_ADDR,
542 iobase + AMCC_OP_REG_MCSR_NVCMD);
543 outb(address & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
544 outb(MCSR_NV_ENABLE | MCSR_NV_LOAD_HIGH_ADDR,
545 iobase + AMCC_OP_REG_MCSR_NVCMD);
546 outb((address >> 8) & 0xff, iobase + AMCC_OP_REG_MCSR_NVDATA);
547 outb(MCSR_NV_ENABLE | MCSR_NV_READ, iobase + AMCC_OP_REG_MCSR_NVCMD);
548
549 if (wait_for_nvram_ready(iobase) < 0)
550 return -ETIMEDOUT;
551
552 *data = inb(iobase + AMCC_OP_REG_MCSR_NVDATA);
553
554 return 0;
555}
556
0a85b6f0
MT
557static int eeprom_read_insn(struct comedi_device *dev,
558 struct comedi_subdevice *s,
559 struct comedi_insn *insn, unsigned int *data)
59c7dd3d
IM
560{
561 uint8_t nvram_data;
562 int retval;
563
564 retval = nvram_read(dev, CR_CHAN(insn->chanspec), &nvram_data);
565 if (retval < 0)
566 return retval;
567
568 data[0] = nvram_data;
569
570 return 1;
571}
572
0c15d553
HS
573static void write_calibration_bitstream(struct comedi_device *dev,
574 unsigned int register_bits,
575 unsigned int bitstream,
576 unsigned int bitstream_length)
577{
82d8c74d 578 struct cb_pcidas_private *devpriv = dev->private;
0c15d553
HS
579 static const int write_delay = 1;
580 unsigned int bit;
581
582 for (bit = 1 << (bitstream_length - 1); bit; bit >>= 1) {
583 if (bitstream & bit)
584 register_bits |= SERIAL_DATA_IN_BIT;
585 else
586 register_bits &= ~SERIAL_DATA_IN_BIT;
587 udelay(write_delay);
588 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
589 }
590}
591
f52e5e44
HS
592static void caldac_8800_write(struct comedi_device *dev,
593 unsigned int chan, uint8_t val)
0c15d553 594{
82d8c74d 595 struct cb_pcidas_private *devpriv = dev->private;
0c15d553 596 static const int bitstream_length = 11;
f52e5e44 597 unsigned int bitstream = ((chan & 0x7) << 8) | val;
0c15d553
HS
598 static const int caldac_8800_udelay = 1;
599
0c15d553
HS
600 write_calibration_bitstream(dev, cal_enable_bits(dev), bitstream,
601 bitstream_length);
602
603 udelay(caldac_8800_udelay);
604 outw(cal_enable_bits(dev) | SELECT_8800_BIT,
605 devpriv->control_status + CALIBRATION_REG);
606 udelay(caldac_8800_udelay);
607 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
0c15d553
HS
608}
609
f52e5e44
HS
610static int cb_pcidas_caldac_insn_write(struct comedi_device *dev,
611 struct comedi_subdevice *s,
612 struct comedi_insn *insn,
613 unsigned int *data)
59c7dd3d 614{
f52e5e44
HS
615 unsigned int chan = CR_CHAN(insn->chanspec);
616
617 if (insn->n) {
618 unsigned int val = data[insn->n - 1];
619
3f5ced0d 620 if (s->readback[chan] != val) {
f52e5e44 621 caldac_8800_write(dev, chan, val);
3f5ced0d 622 s->readback[chan] = val;
f52e5e44
HS
623 }
624 }
59c7dd3d 625
f52e5e44 626 return insn->n;
59c7dd3d
IM
627}
628
59c7dd3d 629/* 1602/16 pregain offset */
ac55ca32 630static void dac08_write(struct comedi_device *dev, unsigned int value)
59c7dd3d 631{
82d8c74d
HS
632 struct cb_pcidas_private *devpriv = dev->private;
633
9c034da1
HS
634 value &= 0xff;
635 value |= cal_enable_bits(dev);
59c7dd3d 636
9c034da1
HS
637 /* latch the new value into the caldac */
638 outw(value, devpriv->control_status + CALIBRATION_REG);
639 udelay(1);
640 outw(value | SELECT_DAC08_BIT,
641 devpriv->control_status + CALIBRATION_REG);
642 udelay(1);
643 outw(value, devpriv->control_status + CALIBRATION_REG);
644 udelay(1);
59c7dd3d
IM
645}
646
9c034da1
HS
647static int cb_pcidas_dac08_insn_write(struct comedi_device *dev,
648 struct comedi_subdevice *s,
649 struct comedi_insn *insn,
650 unsigned int *data)
59c7dd3d 651{
e42151f9 652 unsigned int chan = CR_CHAN(insn->chanspec);
9c034da1
HS
653
654 if (insn->n) {
655 unsigned int val = data[insn->n - 1];
ac55ca32 656
e42151f9 657 if (s->readback[chan] != val) {
9c034da1 658 dac08_write(dev, val);
e42151f9 659 s->readback[chan] = val;
9c034da1
HS
660 }
661 }
ac55ca32
HS
662
663 return insn->n;
59c7dd3d
IM
664}
665
20535c1f
HS
666static int trimpot_7376_write(struct comedi_device *dev, uint8_t value)
667{
82d8c74d 668 struct cb_pcidas_private *devpriv = dev->private;
20535c1f
HS
669 static const int bitstream_length = 7;
670 unsigned int bitstream = value & 0x7f;
671 unsigned int register_bits;
672 static const int ad7376_udelay = 1;
673
674 register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
675 udelay(ad7376_udelay);
676 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
677
678 write_calibration_bitstream(dev, register_bits, bitstream,
679 bitstream_length);
680
681 udelay(ad7376_udelay);
682 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
683
684 return 0;
685}
686
687/* For 1602/16 only
688 * ch 0 : adc gain
689 * ch 1 : adc postgain offset */
690static int trimpot_8402_write(struct comedi_device *dev, unsigned int channel,
691 uint8_t value)
692{
82d8c74d 693 struct cb_pcidas_private *devpriv = dev->private;
20535c1f
HS
694 static const int bitstream_length = 10;
695 unsigned int bitstream = ((channel & 0x3) << 8) | (value & 0xff);
696 unsigned int register_bits;
697 static const int ad8402_udelay = 1;
698
699 register_bits = cal_enable_bits(dev) | SELECT_TRIMPOT_BIT;
700 udelay(ad8402_udelay);
701 outw(register_bits, devpriv->control_status + CALIBRATION_REG);
702
703 write_calibration_bitstream(dev, register_bits, bitstream,
704 bitstream_length);
705
706 udelay(ad8402_udelay);
707 outw(cal_enable_bits(dev), devpriv->control_status + CALIBRATION_REG);
708
709 return 0;
710}
711
7a82a2c4
HS
712static void cb_pcidas_trimpot_write(struct comedi_device *dev,
713 unsigned int chan, unsigned int val)
59c7dd3d 714{
fa8e8c8b 715 const struct cb_pcidas_board *thisboard = dev->board_ptr;
59c7dd3d 716
59c7dd3d
IM
717 switch (thisboard->trimpot) {
718 case AD7376:
7a82a2c4 719 trimpot_7376_write(dev, val);
59c7dd3d
IM
720 break;
721 case AD8402:
7a82a2c4 722 trimpot_8402_write(dev, chan, val);
59c7dd3d
IM
723 break;
724 default:
7ef28904 725 dev_err(dev->class_dev, "driver bug?\n");
7a82a2c4 726 break;
59c7dd3d 727 }
59c7dd3d
IM
728}
729
7a82a2c4
HS
730static int cb_pcidas_trimpot_insn_write(struct comedi_device *dev,
731 struct comedi_subdevice *s,
732 struct comedi_insn *insn,
733 unsigned int *data)
59c7dd3d 734{
7a82a2c4
HS
735 unsigned int chan = CR_CHAN(insn->chanspec);
736
737 if (insn->n) {
738 unsigned int val = data[insn->n - 1];
739
a1c76758 740 if (s->readback[chan] != val) {
7a82a2c4 741 cb_pcidas_trimpot_write(dev, chan, val);
a1c76758 742 s->readback[chan] = val;
7a82a2c4
HS
743 }
744 }
59c7dd3d 745
7a82a2c4 746 return insn->n;
59c7dd3d
IM
747}
748
e74592e0
HS
749static int cb_pcidas_ai_check_chanlist(struct comedi_device *dev,
750 struct comedi_subdevice *s,
751 struct comedi_cmd *cmd)
752{
753 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
754 unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
755 int i;
756
757 for (i = 1; i < cmd->chanlist_len; i++) {
758 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
759 unsigned int range = CR_RANGE(cmd->chanlist[i]);
760
761 if (chan != (chan0 + i) % s->n_chan) {
762 dev_dbg(dev->class_dev,
763 "entries in chanlist must be consecutive channels, counting upwards\n");
764 return -EINVAL;
765 }
766
767 if (range != range0) {
768 dev_dbg(dev->class_dev,
769 "entries in chanlist must all have the same gain\n");
770 return -EINVAL;
771 }
772 }
773 return 0;
774}
775
0a85b6f0
MT
776static int cb_pcidas_ai_cmdtest(struct comedi_device *dev,
777 struct comedi_subdevice *s,
778 struct comedi_cmd *cmd)
59c7dd3d 779{
fa8e8c8b 780 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 781 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d 782 int err = 0;
815bb5b5 783 unsigned int arg;
59c7dd3d 784
27020ffe 785 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 786
27020ffe
HS
787 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
788 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
789 TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT);
790 err |= cfc_check_trigger_src(&cmd->convert_src,
791 TRIG_TIMER | TRIG_NOW | TRIG_EXT);
792 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
793 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
794
795 if (err)
796 return 1;
797
27020ffe 798 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 799
27020ffe
HS
800 err |= cfc_check_trigger_is_unique(cmd->start_src);
801 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
802 err |= cfc_check_trigger_is_unique(cmd->convert_src);
803 err |= cfc_check_trigger_is_unique(cmd->stop_src);
804
805 /* Step 2b : and mutually compatible */
59c7dd3d 806
59c7dd3d 807 if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
27020ffe 808 err |= -EINVAL;
59c7dd3d 809 if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
27020ffe 810 err |= -EINVAL;
59c7dd3d 811 if (cmd->start_src == TRIG_EXT &&
0a85b6f0 812 (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT))
27020ffe 813 err |= -EINVAL;
59c7dd3d
IM
814
815 if (err)
816 return 2;
817
96997b0e 818 /* Step 3: check if arguments are trivially valid */
59c7dd3d 819
f1bc4343 820 switch (cmd->start_src) {
96997b0e
HS
821 case TRIG_NOW:
822 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
823 break;
f1bc4343
BD
824 case TRIG_EXT:
825 /* External trigger, only CR_EDGE and CR_INVERT flags allowed */
826 if ((cmd->start_arg
827 & (CR_FLAGS_MASK & ~(CR_EDGE | CR_INVERT))) != 0) {
00d9c8cb
HS
828 cmd->start_arg &= ~(CR_FLAGS_MASK &
829 ~(CR_EDGE | CR_INVERT));
830 err |= -EINVAL;
f1bc4343 831 }
23e3cce3 832 if (!thisboard->is_1602 && (cmd->start_arg & CR_INVERT)) {
f1bc4343 833 cmd->start_arg &= (CR_FLAGS_MASK & ~CR_INVERT);
00d9c8cb 834 err |= -EINVAL;
f1bc4343
BD
835 }
836 break;
59c7dd3d
IM
837 }
838
00d9c8cb
HS
839 if (cmd->scan_begin_src == TRIG_TIMER)
840 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
841 thisboard->ai_speed * cmd->chanlist_len);
59c7dd3d 842
00d9c8cb
HS
843 if (cmd->convert_src == TRIG_TIMER)
844 err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
845 thisboard->ai_speed);
846
847 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
848
c5d9973b
HS
849 if (cmd->stop_src == TRIG_COUNT)
850 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
851 else /* TRIG_NONE */
00d9c8cb 852 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
853
854 if (err)
855 return 3;
856
857 /* step 4: fix up any arguments */
858
859 if (cmd->scan_begin_src == TRIG_TIMER) {
815bb5b5 860 arg = cmd->scan_begin_arg;
cb9cfd7e
HS
861 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
862 &devpriv->divisor1,
863 &devpriv->divisor2,
815bb5b5
HS
864 &arg, cmd->flags);
865 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
59c7dd3d
IM
866 }
867 if (cmd->convert_src == TRIG_TIMER) {
815bb5b5 868 arg = cmd->convert_arg;
cb9cfd7e
HS
869 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
870 &devpriv->divisor1,
871 &devpriv->divisor2,
815bb5b5
HS
872 &arg, cmd->flags);
873 err |= cfc_check_trigger_arg_is(&cmd->convert_arg, arg);
59c7dd3d
IM
874 }
875
876 if (err)
877 return 4;
878
e74592e0
HS
879 /* Step 5: check channel list if it exists */
880 if (cmd->chanlist && cmd->chanlist_len > 0)
881 err |= cb_pcidas_ai_check_chanlist(dev, s, cmd);
59c7dd3d
IM
882
883 if (err)
884 return 5;
885
886 return 0;
887}
888
33eafb77 889static void cb_pcidas_ai_load_counters(struct comedi_device *dev)
bb036943 890{
82d8c74d 891 struct cb_pcidas_private *devpriv = dev->private;
3a94180c 892 unsigned long timer_base = dev->iobase + ADC8254;
82d8c74d 893
f513b63f
HS
894 i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
895 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
bb036943 896
f513b63f
HS
897 i8254_write(timer_base, 0, 1, devpriv->divisor1);
898 i8254_write(timer_base, 0, 2, devpriv->divisor2);
bb036943
HS
899}
900
0a85b6f0
MT
901static int cb_pcidas_ai_cmd(struct comedi_device *dev,
902 struct comedi_subdevice *s)
59c7dd3d 903{
fa8e8c8b 904 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 905 struct cb_pcidas_private *devpriv = dev->private;
d163679c 906 struct comedi_async *async = s->async;
ea6d0d4c 907 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
908 unsigned int bits;
909 unsigned long flags;
910
cf530aa4 911 /* make sure CAL_EN_BIT is disabled */
59c7dd3d 912 outw(0, devpriv->control_status + CALIBRATION_REG);
cf530aa4 913 /* initialize before settings pacer source and count values */
59c7dd3d 914 outw(0, devpriv->control_status + TRIG_CONTSTAT);
cf530aa4 915 /* clear fifo */
59c7dd3d
IM
916 outw(0, devpriv->adc_fifo + ADCFIFOCLR);
917
cf530aa4 918 /* set mux limits, gain and pacer source */
59c7dd3d 919 bits = BEGIN_SCAN(CR_CHAN(cmd->chanlist[0])) |
0a85b6f0
MT
920 END_SCAN(CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1])) |
921 GAIN_BITS(CR_RANGE(cmd->chanlist[0]));
cf530aa4 922 /* set unipolar/bipolar */
59c7dd3d
IM
923 if (CR_RANGE(cmd->chanlist[0]) & IS_UNIPOLAR)
924 bits |= UNIP;
cf530aa4 925 /* set singleended/differential */
59c7dd3d
IM
926 if (CR_AREF(cmd->chanlist[0]) != AREF_DIFF)
927 bits |= SE;
cf530aa4 928 /* set pacer source */
59c7dd3d
IM
929 if (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)
930 bits |= PACER_EXT_RISE;
931 else
932 bits |= PACER_INT;
933 outw(bits, devpriv->control_status + ADCMUX_CONT);
934
cf530aa4 935 /* load counters */
f513b63f 936 if (cmd->scan_begin_src == TRIG_TIMER || cmd->convert_src == TRIG_TIMER)
33eafb77 937 cb_pcidas_ai_load_counters(dev);
59c7dd3d 938
cf530aa4 939 /* enable interrupts */
5f74ea14 940 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
941 devpriv->adc_fifo_bits |= INTE;
942 devpriv->adc_fifo_bits &= ~INT_MASK;
07b2eb0e 943 if (cmd->flags & CMDF_WAKE_EOS) {
55acaf2d
HS
944 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1) {
945 /* interrupt end of burst */
946 devpriv->adc_fifo_bits |= INT_EOS;
947 } else {
948 /* interrupt fifo not empty */
949 devpriv->adc_fifo_bits |= INT_FNE;
950 }
59c7dd3d 951 } else {
55acaf2d
HS
952 /* interrupt fifo half full */
953 devpriv->adc_fifo_bits |= INT_FHF;
59c7dd3d 954 }
193debd1 955
cf530aa4 956 /* enable (and clear) interrupts */
59c7dd3d 957 outw(devpriv->adc_fifo_bits | EOAI | INT | LADFUL,
0a85b6f0 958 devpriv->control_status + INT_ADCFIFO);
5f74ea14 959 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 960
cf530aa4 961 /* set start trigger and burst mode */
59c7dd3d 962 bits = 0;
8abc7287 963 if (cmd->start_src == TRIG_NOW) {
59c7dd3d 964 bits |= SW_TRIGGER;
8abc7287 965 } else { /* TRIG_EXT */
59c7dd3d 966 bits |= EXT_TRIGGER | TGEN | XTRCL;
23e3cce3 967 if (thisboard->is_1602) {
93c58378 968 if (cmd->start_arg & CR_INVERT)
23e3cce3
HS
969 bits |= TGPOL;
970 if (cmd->start_arg & CR_EDGE)
971 bits |= TGSEL;
972 }
59c7dd3d
IM
973 }
974 if (cmd->convert_src == TRIG_NOW && cmd->chanlist_len > 1)
975 bits |= BURSTE;
976 outw(bits, devpriv->control_status + TRIG_CONTSTAT);
59c7dd3d
IM
977
978 return 0;
979}
980
e74592e0
HS
981static int cb_pcidas_ao_check_chanlist(struct comedi_device *dev,
982 struct comedi_subdevice *s,
983 struct comedi_cmd *cmd)
984{
985 unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
986
987 if (cmd->chanlist_len > 1) {
988 unsigned int chan1 = CR_CHAN(cmd->chanlist[1]);
989
990 if (chan0 != 0 || chan1 != 1) {
991 dev_dbg(dev->class_dev,
992 "channels must be ordered channel 0, channel 1 in chanlist\n");
993 return -EINVAL;
994 }
995 }
996
997 return 0;
998}
999
0a85b6f0
MT
1000static int cb_pcidas_ao_cmdtest(struct comedi_device *dev,
1001 struct comedi_subdevice *s,
1002 struct comedi_cmd *cmd)
59c7dd3d 1003{
fa8e8c8b 1004 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 1005 struct cb_pcidas_private *devpriv = dev->private;
59c7dd3d 1006 int err = 0;
815bb5b5 1007 unsigned int arg;
59c7dd3d 1008
27020ffe 1009 /* Step 1 : check if triggers are trivially valid */
59c7dd3d 1010
27020ffe
HS
1011 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
1012 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
1013 TRIG_TIMER | TRIG_EXT);
1014 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
1015 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
1016 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
59c7dd3d
IM
1017
1018 if (err)
1019 return 1;
1020
27020ffe 1021 /* Step 2a : make sure trigger sources are unique */
59c7dd3d 1022
27020ffe
HS
1023 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
1024 err |= cfc_check_trigger_is_unique(cmd->stop_src);
1025
1026 /* Step 2b : and mutually compatible */
59c7dd3d
IM
1027
1028 if (err)
1029 return 2;
1030
00d9c8cb 1031 /* Step 3: check if arguments are trivially valid */
59c7dd3d 1032
00d9c8cb 1033 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
59c7dd3d 1034
00d9c8cb
HS
1035 if (cmd->scan_begin_src == TRIG_TIMER)
1036 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
1037 thisboard->ao_scan_speed);
59c7dd3d 1038
00d9c8cb
HS
1039 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
1040
c5d9973b
HS
1041 if (cmd->stop_src == TRIG_COUNT)
1042 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
1043 else /* TRIG_NONE */
00d9c8cb 1044 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
59c7dd3d
IM
1045
1046 if (err)
1047 return 3;
1048
1049 /* step 4: fix up any arguments */
1050
1051 if (cmd->scan_begin_src == TRIG_TIMER) {
815bb5b5 1052 arg = cmd->scan_begin_arg;
cb9cfd7e
HS
1053 i8253_cascade_ns_to_timer(I8254_OSC_BASE_10MHZ,
1054 &devpriv->ao_divisor1,
1055 &devpriv->ao_divisor2,
815bb5b5
HS
1056 &arg, cmd->flags);
1057 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
59c7dd3d
IM
1058 }
1059
1060 if (err)
1061 return 4;
1062
e74592e0
HS
1063 /* Step 5: check channel list if it exists */
1064 if (cmd->chanlist && cmd->chanlist_len > 0)
1065 err |= cb_pcidas_ao_check_chanlist(dev, s, cmd);
59c7dd3d
IM
1066
1067 if (err)
1068 return 5;
1069
1070 return 0;
1071}
1072
9a0f7631
HS
1073/* cancel analog input command */
1074static int cb_pcidas_cancel(struct comedi_device *dev,
1075 struct comedi_subdevice *s)
1076{
82d8c74d 1077 struct cb_pcidas_private *devpriv = dev->private;
9a0f7631
HS
1078 unsigned long flags;
1079
1080 spin_lock_irqsave(&dev->spinlock, flags);
1081 /* disable interrupts */
1082 devpriv->adc_fifo_bits &= ~INTE & ~EOAIE;
1083 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1084 spin_unlock_irqrestore(&dev->spinlock, flags);
1085
1086 /* disable start trigger source and burst mode */
1087 outw(0, devpriv->control_status + TRIG_CONTSTAT);
1088 /* software pacer source */
1089 outw(0, devpriv->control_status + ADCMUX_CONT);
1090
1091 return 0;
1092}
1093
2cc9854c
HS
1094static void cb_pcidas_ao_load_fifo(struct comedi_device *dev,
1095 struct comedi_subdevice *s,
1096 unsigned int nsamples)
1097{
1098 struct cb_pcidas_private *devpriv = dev->private;
2cc9854c
HS
1099 unsigned int nbytes;
1100
9e4d755c 1101 nsamples = comedi_nsamples_left(s, nsamples);
2cc9854c 1102 nbytes = comedi_buf_read_samples(s, devpriv->ao_buffer, nsamples);
2cc9854c 1103
9e4d755c 1104 nsamples = comedi_bytes_to_samples(s, nbytes);
2cc9854c
HS
1105 outsw(devpriv->ao_registers + DACDATA, devpriv->ao_buffer, nsamples);
1106}
1107
1706fcc1
HS
1108static int cb_pcidas_ao_inttrig(struct comedi_device *dev,
1109 struct comedi_subdevice *s,
1110 unsigned int trig_num)
1111{
fa8e8c8b 1112 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 1113 struct cb_pcidas_private *devpriv = dev->private;
1706fcc1 1114 struct comedi_async *async = s->async;
2cc9854c 1115 struct comedi_cmd *cmd = &async->cmd;
1706fcc1
HS
1116 unsigned long flags;
1117
384e483f 1118 if (trig_num != cmd->start_arg)
1706fcc1
HS
1119 return -EINVAL;
1120
2cc9854c 1121 cb_pcidas_ao_load_fifo(dev, s, thisboard->fifo_size);
1706fcc1
HS
1122
1123 /* enable dac half-full and empty interrupts */
1124 spin_lock_irqsave(&dev->spinlock, flags);
1125 devpriv->adc_fifo_bits |= DAEMIE | DAHFIE;
193debd1 1126
1706fcc1
HS
1127 /* enable and clear interrupts */
1128 outw(devpriv->adc_fifo_bits | DAEMI | DAHFI,
1129 devpriv->control_status + INT_ADCFIFO);
1130
1131 /* start dac */
1132 devpriv->ao_control_bits |= DAC_START | DACEN | DAC_EMPTY;
1133 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
193debd1 1134
1706fcc1
HS
1135 spin_unlock_irqrestore(&dev->spinlock, flags);
1136
1137 async->inttrig = NULL;
1138
1139 return 0;
1140}
1141
33eafb77
HS
1142static void cb_pcidas_ao_load_counters(struct comedi_device *dev)
1143{
1144 struct cb_pcidas_private *devpriv = dev->private;
3a94180c 1145 unsigned long timer_base = dev->iobase + DAC8254;
33eafb77
HS
1146
1147 i8254_set_mode(timer_base, 0, 1, I8254_MODE2 | I8254_BINARY);
1148 i8254_set_mode(timer_base, 0, 2, I8254_MODE2 | I8254_BINARY);
1149
1150 i8254_write(timer_base, 0, 1, devpriv->ao_divisor1);
1151 i8254_write(timer_base, 0, 2, devpriv->ao_divisor2);
1152}
1153
0a85b6f0
MT
1154static int cb_pcidas_ao_cmd(struct comedi_device *dev,
1155 struct comedi_subdevice *s)
59c7dd3d 1156{
82d8c74d 1157 struct cb_pcidas_private *devpriv = dev->private;
d163679c 1158 struct comedi_async *async = s->async;
ea6d0d4c 1159 struct comedi_cmd *cmd = &async->cmd;
59c7dd3d
IM
1160 unsigned int i;
1161 unsigned long flags;
1162
cf530aa4 1163 /* set channel limits, gain */
5f74ea14 1164 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1165 for (i = 0; i < cmd->chanlist_len; i++) {
cf530aa4 1166 /* enable channel */
59c7dd3d 1167 devpriv->ao_control_bits |=
0a85b6f0 1168 DAC_CHAN_EN(CR_CHAN(cmd->chanlist[i]));
cf530aa4 1169 /* set range */
59c7dd3d 1170 devpriv->ao_control_bits |= DAC_RANGE(CR_CHAN(cmd->chanlist[i]),
0a85b6f0
MT
1171 CR_RANGE(cmd->
1172 chanlist[i]));
59c7dd3d
IM
1173 }
1174
cf530aa4 1175 /* disable analog out before settings pacer source and count values */
59c7dd3d 1176 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
5f74ea14 1177 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1178
cf530aa4 1179 /* clear fifo */
59c7dd3d
IM
1180 outw(0, devpriv->ao_registers + DACFIFOCLR);
1181
cf530aa4 1182 /* load counters */
33eafb77
HS
1183 if (cmd->scan_begin_src == TRIG_TIMER)
1184 cb_pcidas_ao_load_counters(dev);
59c7dd3d 1185
cf530aa4 1186 /* set pacer source */
5f74ea14 1187 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d
IM
1188 switch (cmd->scan_begin_src) {
1189 case TRIG_TIMER:
1190 devpriv->ao_control_bits |= DAC_PACER_INT;
1191 break;
1192 case TRIG_EXT:
1193 devpriv->ao_control_bits |= DAC_PACER_EXT_RISE;
1194 break;
1195 default:
5f74ea14 1196 spin_unlock_irqrestore(&dev->spinlock, flags);
7ef28904 1197 dev_err(dev->class_dev, "error setting dac pacer source\n");
59c7dd3d 1198 return -1;
59c7dd3d 1199 }
5f74ea14 1200 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d
IM
1201
1202 async->inttrig = cb_pcidas_ao_inttrig;
1203
1204 return 0;
1205}
1206
0aa20304
HS
1207/* cancel analog output command */
1208static int cb_pcidas_ao_cancel(struct comedi_device *dev,
1209 struct comedi_subdevice *s)
1210{
82d8c74d 1211 struct cb_pcidas_private *devpriv = dev->private;
0aa20304
HS
1212 unsigned long flags;
1213
1214 spin_lock_irqsave(&dev->spinlock, flags);
1215 /* disable interrupts */
1216 devpriv->adc_fifo_bits &= ~DAHFIE & ~DAEMIE;
1217 outw(devpriv->adc_fifo_bits, devpriv->control_status + INT_ADCFIFO);
1218
1219 /* disable output */
1220 devpriv->ao_control_bits &= ~DACEN & ~DAC_PACER_MASK;
1221 outw(devpriv->ao_control_bits, devpriv->control_status + DAC_CSR);
1222 spin_unlock_irqrestore(&dev->spinlock, flags);
1223
1224 return 0;
1225}
1226
9e11d05f
HS
1227static void handle_ao_interrupt(struct comedi_device *dev, unsigned int status)
1228{
fa8e8c8b 1229 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 1230 struct cb_pcidas_private *devpriv = dev->private;
9e11d05f
HS
1231 struct comedi_subdevice *s = dev->write_subdev;
1232 struct comedi_async *async = s->async;
1233 struct comedi_cmd *cmd = &async->cmd;
9e11d05f
HS
1234 unsigned long flags;
1235
9e11d05f
HS
1236 if (status & DAEMI) {
1237 /* clear dac empty interrupt latch */
1238 spin_lock_irqsave(&dev->spinlock, flags);
1239 outw(devpriv->adc_fifo_bits | DAEMI,
1240 devpriv->control_status + INT_ADCFIFO);
1241 spin_unlock_irqrestore(&dev->spinlock, flags);
1242 if (inw(devpriv->ao_registers + DAC_CSR) & DAC_EMPTY) {
9e4d755c
HS
1243 if (cmd->stop_src == TRIG_COUNT &&
1244 async->scans_done >= cmd->stop_arg) {
1245 async->events |= COMEDI_CB_EOA;
1246 } else {
7ef28904 1247 dev_err(dev->class_dev, "dac fifo underflow\n");
9e11d05f
HS
1248 async->events |= COMEDI_CB_ERROR;
1249 }
9e11d05f
HS
1250 }
1251 } else if (status & DAHFI) {
2cc9854c
HS
1252 cb_pcidas_ao_load_fifo(dev, s, thisboard->fifo_size / 2);
1253
9e11d05f
HS
1254 /* clear half-full interrupt latch */
1255 spin_lock_irqsave(&dev->spinlock, flags);
1256 outw(devpriv->adc_fifo_bits | DAHFI,
1257 devpriv->control_status + INT_ADCFIFO);
1258 spin_unlock_irqrestore(&dev->spinlock, flags);
1259 }
1260
f923f780 1261 comedi_handle_events(dev, s);
9e11d05f
HS
1262}
1263
70265d24 1264static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
59c7dd3d 1265{
0a85b6f0 1266 struct comedi_device *dev = (struct comedi_device *)d;
fa8e8c8b 1267 const struct cb_pcidas_board *thisboard = dev->board_ptr;
82d8c74d 1268 struct cb_pcidas_private *devpriv = dev->private;
34c43922 1269 struct comedi_subdevice *s = dev->read_subdev;
d163679c 1270 struct comedi_async *async;
bedd62fc 1271 struct comedi_cmd *cmd;
59c7dd3d
IM
1272 int status, s5933_status;
1273 int half_fifo = thisboard->fifo_size / 2;
1274 unsigned int num_samples, i;
1275 static const int timeout = 10000;
1276 unsigned long flags;
1277
a7401cdd 1278 if (!dev->attached)
59c7dd3d 1279 return IRQ_NONE;
59c7dd3d
IM
1280
1281 async = s->async;
bedd62fc 1282 cmd = &async->cmd;
59c7dd3d
IM
1283
1284 s5933_status = inl(devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1285
1286 if ((INTCSR_INTR_ASSERTED & s5933_status) == 0)
1287 return IRQ_NONE;
1288
cf530aa4 1289 /* make sure mailbox 4 is empty */
59c7dd3d 1290 inl_p(devpriv->s5933_config + AMCC_OP_REG_IMB4);
cf530aa4 1291 /* clear interrupt on amcc s5933 */
59c7dd3d 1292 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
0a85b6f0 1293 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
59c7dd3d
IM
1294
1295 status = inw(devpriv->control_status + INT_ADCFIFO);
59c7dd3d 1296
cf530aa4 1297 /* check for analog output interrupt */
2d238b29 1298 if (status & (DAHFI | DAEMI))
59c7dd3d 1299 handle_ao_interrupt(dev, status);
cf530aa4
BP
1300 /* check for analog input interrupts */
1301 /* if fifo half-full */
59c7dd3d 1302 if (status & ADHFI) {
cf530aa4 1303 /* read data */
f9f98382 1304 num_samples = comedi_nsamples_left(s, half_fifo);
59c7dd3d 1305 insw(devpriv->adc_fifo + ADCDATA, devpriv->ai_buffer,
0a85b6f0 1306 num_samples);
8d47c085 1307 comedi_buf_write_samples(s, devpriv->ai_buffer, num_samples);
f9f98382
HS
1308
1309 if (cmd->stop_src == TRIG_COUNT &&
1310 async->scans_done >= cmd->stop_arg)
59c7dd3d 1311 async->events |= COMEDI_CB_EOA;
f9f98382 1312
cf530aa4 1313 /* clear half-full interrupt latch */
5f74ea14 1314 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1315 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1316 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1317 spin_unlock_irqrestore(&dev->spinlock, flags);
cf530aa4 1318 /* else if fifo not empty */
59c7dd3d
IM
1319 } else if (status & (ADNEI | EOBI)) {
1320 for (i = 0; i < timeout; i++) {
8d47c085
HS
1321 unsigned short val;
1322
cf530aa4 1323 /* break if fifo is empty */
59c7dd3d 1324 if ((ADNE & inw(devpriv->control_status +
0a85b6f0 1325 INT_ADCFIFO)) == 0)
59c7dd3d 1326 break;
8d47c085
HS
1327 val = inw(devpriv->adc_fifo);
1328 comedi_buf_write_samples(s, &val, 1);
f9f98382 1329
bedd62fc 1330 if (cmd->stop_src == TRIG_COUNT &&
f9f98382 1331 async->scans_done >= cmd->stop_arg) {
59c7dd3d
IM
1332 async->events |= COMEDI_CB_EOA;
1333 break;
1334 }
1335 }
cf530aa4 1336 /* clear not-empty interrupt latch */
5f74ea14 1337 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1338 outw(devpriv->adc_fifo_bits | INT,
0a85b6f0 1339 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1340 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1341 } else if (status & EOAI) {
7ef28904
HS
1342 dev_err(dev->class_dev,
1343 "bug! encountered end of acquisition interrupt?\n");
cf530aa4 1344 /* clear EOA interrupt latch */
5f74ea14 1345 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1346 outw(devpriv->adc_fifo_bits | EOAI,
0a85b6f0 1347 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1348 spin_unlock_irqrestore(&dev->spinlock, flags);
59c7dd3d 1349 }
cf530aa4 1350 /* check for fifo overflow */
59c7dd3d 1351 if (status & LADFUL) {
7ef28904 1352 dev_err(dev->class_dev, "fifo overflow\n");
cf530aa4 1353 /* clear overflow interrupt latch */
5f74ea14 1354 spin_lock_irqsave(&dev->spinlock, flags);
59c7dd3d 1355 outw(devpriv->adc_fifo_bits | LADFUL,
0a85b6f0 1356 devpriv->control_status + INT_ADCFIFO);
5f74ea14 1357 spin_unlock_irqrestore(&dev->spinlock, flags);
3e6cb74f 1358 async->events |= COMEDI_CB_ERROR;
59c7dd3d
IM
1359 }
1360
f923f780 1361 comedi_handle_events(dev, s);
59c7dd3d
IM
1362
1363 return IRQ_HANDLED;
1364}
1365
a690b7e5 1366static int cb_pcidas_auto_attach(struct comedi_device *dev,
9b315bcb 1367 unsigned long context)
327be979 1368{
750af5e5 1369 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
9b315bcb 1370 const struct cb_pcidas_board *thisboard = NULL;
327be979
HS
1371 struct cb_pcidas_private *devpriv;
1372 struct comedi_subdevice *s;
1373 int i;
1374 int ret;
e74f209c 1375
9b315bcb
HS
1376 if (context < ARRAY_SIZE(cb_pcidas_boards))
1377 thisboard = &cb_pcidas_boards[context];
3b96f250
HS
1378 if (!thisboard)
1379 return -ENODEV;
1380 dev->board_ptr = thisboard;
1381 dev->board_name = thisboard->name;
1382
0bdab509 1383 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
c34fa261
HS
1384 if (!devpriv)
1385 return -ENOMEM;
3b96f250 1386
818f569f 1387 ret = comedi_pci_enable(dev);
3b96f250
HS
1388 if (ret)
1389 return ret;
7302abef 1390
ba36b9ba
HS
1391 devpriv->s5933_config = pci_resource_start(pcidev, 0);
1392 devpriv->control_status = pci_resource_start(pcidev, 1);
1393 devpriv->adc_fifo = pci_resource_start(pcidev, 2);
3a94180c 1394 dev->iobase = pci_resource_start(pcidev, 3);
7302abef 1395 if (thisboard->ao_nchan)
ba36b9ba 1396 devpriv->ao_registers = pci_resource_start(pcidev, 4);
7302abef 1397
e74f209c
HS
1398 /* disable and clear interrupts on amcc s5933 */
1399 outl(INTCSR_INBOX_INTR_STATUS,
1400 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1401
71e06874
HS
1402 ret = request_irq(pcidev->irq, cb_pcidas_interrupt, IRQF_SHARED,
1403 dev->board_name, dev);
1404 if (ret) {
e74f209c 1405 dev_dbg(dev->class_dev, "unable to allocate irq %d\n",
ba36b9ba 1406 pcidev->irq);
71e06874 1407 return ret;
e74f209c 1408 }
ba36b9ba 1409 dev->irq = pcidev->irq;
e74f209c 1410
e74f209c
HS
1411 ret = comedi_alloc_subdevices(dev, 7);
1412 if (ret)
1413 return ret;
1414
e89c61b9 1415 s = &dev->subdevices[0];
e74f209c
HS
1416 /* analog input subdevice */
1417 dev->read_subdev = s;
1418 s->type = COMEDI_SUBD_AI;
1419 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF | SDF_CMD_READ;
1420 /* WARNING: Number of inputs in differential mode is ignored */
8f608fc8
HS
1421 s->n_chan = thisboard->ai_nchan;
1422 s->len_chanlist = thisboard->ai_nchan;
e74f209c
HS
1423 s->maxdata = (1 << thisboard->ai_bits) - 1;
1424 s->range_table = thisboard->ranges;
1425 s->insn_read = cb_pcidas_ai_rinsn;
1426 s->insn_config = ai_config_insn;
1427 s->do_cmd = cb_pcidas_ai_cmd;
1428 s->do_cmdtest = cb_pcidas_ai_cmdtest;
1429 s->cancel = cb_pcidas_cancel;
1430
1431 /* analog output subdevice */
e89c61b9 1432 s = &dev->subdevices[1];
e74f209c
HS
1433 if (thisboard->ao_nchan) {
1434 s->type = COMEDI_SUBD_AO;
1435 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND;
1436 s->n_chan = thisboard->ao_nchan;
55acaf2d
HS
1437 /*
1438 * analog out resolution is the same as
1439 * analog input resolution, so use ai_bits
1440 */
e74f209c
HS
1441 s->maxdata = (1 << thisboard->ai_bits) - 1;
1442 s->range_table = &cb_pcidas_ao_ranges;
46da1c8f
HS
1443 /* default to no fifo (*insn_write) */
1444 s->insn_write = cb_pcidas_ao_nofifo_winsn;
46da1c8f
HS
1445
1446 ret = comedi_alloc_subdev_readback(s);
1447 if (ret)
1448 return ret;
1449
e74f209c
HS
1450 if (thisboard->has_ao_fifo) {
1451 dev->write_subdev = s;
1452 s->subdev_flags |= SDF_CMD_WRITE;
46da1c8f 1453 /* use fifo (*insn_write) instead */
e74f209c
HS
1454 s->insn_write = cb_pcidas_ao_fifo_winsn;
1455 s->do_cmdtest = cb_pcidas_ao_cmdtest;
1456 s->do_cmd = cb_pcidas_ao_cmd;
1457 s->cancel = cb_pcidas_ao_cancel;
e74f209c
HS
1458 }
1459 } else {
1460 s->type = COMEDI_SUBD_UNUSED;
1461 }
1462
1463 /* 8255 */
e89c61b9 1464 s = &dev->subdevices[2];
4085e93b 1465 ret = subdev_8255_init(dev, s, NULL, DIO_8255);
4f0036ef
HS
1466 if (ret)
1467 return ret;
e74f209c
HS
1468
1469 /* serial EEPROM, */
e89c61b9 1470 s = &dev->subdevices[3];
e74f209c
HS
1471 s->type = COMEDI_SUBD_MEMORY;
1472 s->subdev_flags = SDF_READABLE | SDF_INTERNAL;
1473 s->n_chan = 256;
1474 s->maxdata = 0xff;
1475 s->insn_read = eeprom_read_insn;
1476
1477 /* 8800 caldac */
e89c61b9 1478 s = &dev->subdevices[4];
e74f209c
HS
1479 s->type = COMEDI_SUBD_CALIB;
1480 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1481 s->n_chan = NUM_CHANNELS_8800;
1482 s->maxdata = 0xff;
f52e5e44 1483 s->insn_write = cb_pcidas_caldac_insn_write;
3f5ced0d
HS
1484
1485 ret = comedi_alloc_subdev_readback(s);
1486 if (ret)
1487 return ret;
1488
f52e5e44 1489 for (i = 0; i < s->n_chan; i++) {
e74f209c 1490 caldac_8800_write(dev, i, s->maxdata / 2);
3f5ced0d 1491 s->readback[i] = s->maxdata / 2;
f52e5e44 1492 }
e74f209c
HS
1493
1494 /* trim potentiometer */
e89c61b9 1495 s = &dev->subdevices[5];
e74f209c
HS
1496 s->type = COMEDI_SUBD_CALIB;
1497 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1498 if (thisboard->trimpot == AD7376) {
1499 s->n_chan = NUM_CHANNELS_7376;
1500 s->maxdata = 0x7f;
1501 } else {
1502 s->n_chan = NUM_CHANNELS_8402;
1503 s->maxdata = 0xff;
1504 }
7a82a2c4 1505 s->insn_write = cb_pcidas_trimpot_insn_write;
a1c76758
HS
1506
1507 ret = comedi_alloc_subdev_readback(s);
1508 if (ret)
1509 return ret;
1510
7a82a2c4 1511 for (i = 0; i < s->n_chan; i++) {
e74f209c 1512 cb_pcidas_trimpot_write(dev, i, s->maxdata / 2);
a1c76758 1513 s->readback[i] = s->maxdata / 2;
7a82a2c4 1514 }
e74f209c
HS
1515
1516 /* dac08 caldac */
e89c61b9 1517 s = &dev->subdevices[6];
e74f209c
HS
1518 if (thisboard->has_dac08) {
1519 s->type = COMEDI_SUBD_CALIB;
1520 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL;
1521 s->n_chan = NUM_CHANNELS_DAC08;
e74f209c 1522 s->maxdata = 0xff;
e42151f9
HS
1523 s->insn_write = cb_pcidas_dac08_insn_write;
1524
1525 ret = comedi_alloc_subdev_readback(s);
1526 if (ret)
1527 return ret;
1528
1529 for (i = 0; i < s->n_chan; i++) {
1530 dac08_write(dev, s->maxdata / 2);
1531 s->readback[i] = s->maxdata / 2;
1532 }
e74f209c
HS
1533 } else
1534 s->type = COMEDI_SUBD_UNUSED;
1535
1536 /* make sure mailbox 4 is empty */
1537 inl(devpriv->s5933_config + AMCC_OP_REG_IMB4);
1538 /* Set bits to enable incoming mailbox interrupts on amcc s5933. */
1539 devpriv->s5933_intcsr_bits =
1540 INTCSR_INBOX_BYTE(3) | INTCSR_INBOX_SELECT(3) |
1541 INTCSR_INBOX_FULL_INT;
1542 /* clear and enable interrupt on amcc s5933 */
1543 outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS,
1544 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
1545
3b96f250 1546 return 0;
e74f209c
HS
1547}
1548
1549static void cb_pcidas_detach(struct comedi_device *dev)
1550{
82d8c74d
HS
1551 struct cb_pcidas_private *devpriv = dev->private;
1552
aac307f9
HS
1553 if (devpriv && devpriv->s5933_config) {
1554 outl(INTCSR_INBOX_INTR_STATUS,
1555 devpriv->s5933_config + AMCC_OP_REG_INTCSR);
e74f209c 1556 }
aac307f9 1557 comedi_pci_detach(dev);
e74f209c
HS
1558}
1559
715b2284
HS
1560static struct comedi_driver cb_pcidas_driver = {
1561 .driver_name = "cb_pcidas",
1562 .module = THIS_MODULE,
750af5e5 1563 .auto_attach = cb_pcidas_auto_attach,
715b2284
HS
1564 .detach = cb_pcidas_detach,
1565};
1566
a690b7e5 1567static int cb_pcidas_pci_probe(struct pci_dev *dev,
b8f4ac23 1568 const struct pci_device_id *id)
727b286b 1569{
b8f4ac23
HS
1570 return comedi_pci_auto_config(dev, &cb_pcidas_driver,
1571 id->driver_data);
727b286b
AT
1572}
1573
41e043fc 1574static const struct pci_device_id cb_pcidas_pci_table[] = {
9b315bcb
HS
1575 { PCI_VDEVICE(CB, 0x0001), BOARD_PCIDAS1602_16 },
1576 { PCI_VDEVICE(CB, 0x000f), BOARD_PCIDAS1200 },
1577 { PCI_VDEVICE(CB, 0x0010), BOARD_PCIDAS1602_12 },
1578 { PCI_VDEVICE(CB, 0x0019), BOARD_PCIDAS1200_JR },
1579 { PCI_VDEVICE(CB, 0x001c), BOARD_PCIDAS1602_16_JR },
1580 { PCI_VDEVICE(CB, 0x004c), BOARD_PCIDAS1000 },
1581 { PCI_VDEVICE(CB, 0x001a), BOARD_PCIDAS1001 },
1582 { PCI_VDEVICE(CB, 0x001b), BOARD_PCIDAS1002 },
715b2284 1583 { 0 }
727b286b 1584};
715b2284 1585MODULE_DEVICE_TABLE(pci, cb_pcidas_pci_table);
727b286b 1586
715b2284
HS
1587static struct pci_driver cb_pcidas_pci_driver = {
1588 .name = "cb_pcidas",
1589 .id_table = cb_pcidas_pci_table,
1590 .probe = cb_pcidas_pci_probe,
9901a4d7 1591 .remove = comedi_pci_auto_unconfig,
715b2284
HS
1592};
1593module_comedi_pci_driver(cb_pcidas_driver, cb_pcidas_pci_driver);
90f703d3
AT
1594
1595MODULE_AUTHOR("Comedi http://www.comedi.org");
1596MODULE_DESCRIPTION("Comedi low-level driver");
1597MODULE_LICENSE("GPL");
This page took 0.817158 seconds and 5 git commands to generate.