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