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