xref: /openbmc/linux/drivers/comedi/drivers/daqboard2000.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * comedi/drivers/daqboard2000.c
4  * hardware driver for IOtech DAQboard/2000
5  *
6  * COMEDI - Linux Control and Measurement Device Interface
7  * Copyright (C) 1999 Anders Blomdell <anders.blomdell@control.lth.se>
8  */
9 /*
10  * Driver: daqboard2000
11  * Description: IOTech DAQBoard/2000
12  * Author: Anders Blomdell <anders.blomdell@control.lth.se>
13  * Status: works
14  * Updated: Mon, 14 Apr 2008 15:28:52 +0100
15  * Devices: [IOTech] DAQBoard/2000 (daqboard2000)
16  *
17  * Much of the functionality of this driver was determined from reading
18  * the source code for the Windows driver.
19  *
20  * The FPGA on the board requires firmware, which is available from
21  * https://www.comedi.org in the comedi_nonfree_firmware tarball.
22  *
23  * Configuration options: not applicable, uses PCI auto config
24  */
25 /*
26  * This card was obviously never intended to leave the Windows world,
27  * since it lacked all kind of hardware documentation (except for cable
28  * pinouts, plug and pray has something to catch up with yet).
29  *
30  * With some help from our swedish distributor, we got the Windows sourcecode
31  * for the card, and here are the findings so far.
32  *
33  * 1. A good document that describes the PCI interface chip is 9080db-106.pdf
34  *    available from http://www.plxtech.com/products/io/pci9080
35  *
36  * 2. The initialization done so far is:
37  *      a. program the FPGA (windows code sans a lot of error messages)
38  *      b.
39  *
40  * 3. Analog out seems to work OK with DAC's disabled, if DAC's are enabled,
41  *    you have to output values to all enabled DAC's until result appears, I
42  *    guess that it has something to do with pacer clocks, but the source
43  *    gives me no clues. I'll keep it simple so far.
44  *
45  * 4. Analog in.
46  *    Each channel in the scanlist seems to be controlled by four
47  *    control words:
48  *
49  *	Word0:
50  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51  *	  ! | | | ! | | | ! | | | ! | | | !
52  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
53  *
54  *	Word1:
55  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56  *	  ! | | | ! | | | ! | | | ! | | | !
57  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58  *	   |             |       | | | | |
59  *	   +------+------+       | | | | +-- Digital input (??)
60  *		  |		 | | | +---- 10 us settling time
61  *		  |		 | | +------ Suspend acquisition (last to scan)
62  *		  |		 | +-------- Simultaneous sample and hold
63  *		  |		 +---------- Signed data format
64  *		  +------------------------- Correction offset low
65  *
66  *	Word2:
67  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
68  *	  ! | | | ! | | | ! | | | ! | | | !
69  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
70  *	   |     | |     | | | | | |     |
71  *	   +-----+ +--+--+ +++ +++ +--+--+
72  *	      |       |     |   |     +----- Expansion channel
73  *	      |       |     |   +----------- Expansion gain
74  *	      |       |     +--------------- Channel (low)
75  *	      |       +--------------------- Correction offset high
76  *	      +----------------------------- Correction gain low
77  *	Word3:
78  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
79  *	  ! | | | ! | | | ! | | | ! | | | !
80  *	  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
81  *	   |             | | | |   | | | |
82  *	   +------+------+ | | +-+-+ | | +-- Low bank enable
83  *		  |	   | |   |   | +---- High bank enable
84  *		  |	   | |   |   +------ Hi/low select
85  *		  |	   | |   +---------- Gain (1,?,2,4,8,16,32,64)
86  *		  |	   | +-------------- differential/single ended
87  *		  |	   +---------------- Unipolar
88  *		  +------------------------- Correction gain high
89  *
90  * 999. The card seems to have an incredible amount of capabilities, but
91  *      trying to reverse engineer them from the Windows source is beyond my
92  *      patience.
93  *
94  */
95 
96 #include <linux/module.h>
97 #include <linux/delay.h>
98 #include <linux/interrupt.h>
99 #include <linux/comedi/comedi_pci.h>
100 #include <linux/comedi/comedi_8255.h>
101 
102 #include "plx9080.h"
103 
104 #define DB2K_FIRMWARE		"daqboard2000_firmware.bin"
105 
106 static const struct comedi_lrange db2k_ai_range = {
107 	13, {
108 		BIP_RANGE(10),
109 		BIP_RANGE(5),
110 		BIP_RANGE(2.5),
111 		BIP_RANGE(1.25),
112 		BIP_RANGE(0.625),
113 		BIP_RANGE(0.3125),
114 		BIP_RANGE(0.156),
115 		UNI_RANGE(10),
116 		UNI_RANGE(5),
117 		UNI_RANGE(2.5),
118 		UNI_RANGE(1.25),
119 		UNI_RANGE(0.625),
120 		UNI_RANGE(0.3125)
121 	}
122 };
123 
124 /*
125  * Register Memory Map
126  */
127 #define DB2K_REG_ACQ_CONTROL			0x00		/* u16 (w) */
128 #define DB2K_REG_ACQ_STATUS			0x00		/* u16 (r) */
129 #define DB2K_REG_ACQ_SCAN_LIST_FIFO		0x02		/* u16 */
130 #define DB2K_REG_ACQ_PACER_CLOCK_DIV_LOW	0x04		/* u32 */
131 #define DB2K_REG_ACQ_SCAN_COUNTER		0x08		/* u16 */
132 #define DB2K_REG_ACQ_PACER_CLOCK_DIV_HIGH	0x0a		/* u16 */
133 #define DB2K_REG_ACQ_TRIGGER_COUNT		0x0c		/* u16 */
134 #define DB2K_REG_ACQ_RESULTS_FIFO		0x10		/* u16 */
135 #define DB2K_REG_ACQ_RESULTS_SHADOW		0x14		/* u16 */
136 #define DB2K_REG_ACQ_ADC_RESULT			0x18		/* u16 */
137 #define DB2K_REG_DAC_SCAN_COUNTER		0x1c		/* u16 */
138 #define DB2K_REG_DAC_CONTROL			0x20		/* u16 (w) */
139 #define DB2K_REG_DAC_STATUS			0x20		/* u16 (r) */
140 #define DB2K_REG_DAC_FIFO			0x24		/* s16 */
141 #define DB2K_REG_DAC_PACER_CLOCK_DIV		0x2a		/* u16 */
142 #define DB2K_REG_REF_DACS			0x2c		/* u16 */
143 #define DB2K_REG_DIO_CONTROL			0x30		/* u16 */
144 #define DB2K_REG_P3_HSIO_DATA			0x32		/* s16 */
145 #define DB2K_REG_P3_CONTROL			0x34		/* u16 */
146 #define DB2K_REG_CAL_EEPROM_CONTROL		0x36		/* u16 */
147 #define DB2K_REG_DAC_SETTING(x)			(0x38 + (x) * 2) /* s16 */
148 #define DB2K_REG_DIO_P2_EXP_IO_8_BIT		0x40		/* s16 */
149 #define DB2K_REG_COUNTER_TIMER_CONTROL		0x80		/* u16 */
150 #define DB2K_REG_COUNTER_INPUT(x)		(0x88 + (x) * 2) /* s16 */
151 #define DB2K_REG_TIMER_DIV(x)			(0xa0 + (x) * 2) /* u16 */
152 #define DB2K_REG_DMA_CONTROL			0xb0		/* u16 */
153 #define DB2K_REG_TRIG_CONTROL			0xb2		/* u16 */
154 #define DB2K_REG_CAL_EEPROM			0xb8		/* u16 */
155 #define DB2K_REG_ACQ_DIGITAL_MARK		0xba		/* u16 */
156 #define DB2K_REG_TRIG_DACS			0xbc		/* u16 */
157 #define DB2K_REG_DIO_P2_EXP_IO_16_BIT(x)	(0xc0 + (x) * 2) /* s16 */
158 
159 /* CPLD registers */
160 #define DB2K_REG_CPLD_STATUS			0x1000		/* u16 (r) */
161 #define DB2K_REG_CPLD_WDATA			0x1000		/* u16 (w) */
162 
163 /* Scan Sequencer programming */
164 #define DB2K_ACQ_CONTROL_SEQ_START_SCAN_LIST		0x0011
165 #define DB2K_ACQ_CONTROL_SEQ_STOP_SCAN_LIST		0x0010
166 
167 /* Prepare for acquisition */
168 #define DB2K_ACQ_CONTROL_RESET_SCAN_LIST_FIFO		0x0004
169 #define DB2K_ACQ_CONTROL_RESET_RESULTS_FIFO		0x0002
170 #define DB2K_ACQ_CONTROL_RESET_CONFIG_PIPE		0x0001
171 
172 /* Pacer Clock Control */
173 #define DB2K_ACQ_CONTROL_ADC_PACER_INTERNAL		0x0030
174 #define DB2K_ACQ_CONTROL_ADC_PACER_EXTERNAL		0x0032
175 #define DB2K_ACQ_CONTROL_ADC_PACER_ENABLE		0x0031
176 #define DB2K_ACQ_CONTROL_ADC_PACER_ENABLE_DAC_PACER	0x0034
177 #define DB2K_ACQ_CONTROL_ADC_PACER_DISABLE		0x0030
178 #define DB2K_ACQ_CONTROL_ADC_PACER_NORMAL_MODE		0x0060
179 #define DB2K_ACQ_CONTROL_ADC_PACER_COMPATIBILITY_MODE	0x0061
180 #define DB2K_ACQ_CONTROL_ADC_PACER_INTERNAL_OUT_ENABLE	0x0008
181 #define DB2K_ACQ_CONTROL_ADC_PACER_EXTERNAL_RISING	0x0100
182 
183 /* Acquisition status bits */
184 #define DB2K_ACQ_STATUS_RESULTS_FIFO_MORE_1_SAMPLE	0x0001
185 #define DB2K_ACQ_STATUS_RESULTS_FIFO_HAS_DATA		0x0002
186 #define DB2K_ACQ_STATUS_RESULTS_FIFO_OVERRUN		0x0004
187 #define DB2K_ACQ_STATUS_LOGIC_SCANNING			0x0008
188 #define DB2K_ACQ_STATUS_CONFIG_PIPE_FULL		0x0010
189 #define DB2K_ACQ_STATUS_SCAN_LIST_FIFO_EMPTY		0x0020
190 #define DB2K_ACQ_STATUS_ADC_NOT_READY			0x0040
191 #define DB2K_ACQ_STATUS_ARBITRATION_FAILURE		0x0080
192 #define DB2K_ACQ_STATUS_ADC_PACER_OVERRUN		0x0100
193 #define DB2K_ACQ_STATUS_DAC_PACER_OVERRUN		0x0200
194 
195 /* DAC status */
196 #define DB2K_DAC_STATUS_DAC_FULL			0x0001
197 #define DB2K_DAC_STATUS_REF_BUSY			0x0002
198 #define DB2K_DAC_STATUS_TRIG_BUSY			0x0004
199 #define DB2K_DAC_STATUS_CAL_BUSY			0x0008
200 #define DB2K_DAC_STATUS_DAC_BUSY(x)			(0x0010 << (x))
201 
202 /* DAC control */
203 #define DB2K_DAC_CONTROL_ENABLE_BIT			0x0001
204 #define DB2K_DAC_CONTROL_DATA_IS_SIGNED			0x0002
205 #define DB2K_DAC_CONTROL_RESET_FIFO			0x0004
206 #define DB2K_DAC_CONTROL_DAC_DISABLE(x)			(0x0020 + ((x) << 4))
207 #define DB2K_DAC_CONTROL_DAC_ENABLE(x)			(0x0021 + ((x) << 4))
208 #define DB2K_DAC_CONTROL_PATTERN_DISABLE		0x0060
209 #define DB2K_DAC_CONTROL_PATTERN_ENABLE			0x0061
210 
211 /* Trigger Control */
212 #define DB2K_TRIG_CONTROL_TYPE_ANALOG			0x0000
213 #define DB2K_TRIG_CONTROL_TYPE_TTL			0x0010
214 #define DB2K_TRIG_CONTROL_EDGE_HI_LO			0x0004
215 #define DB2K_TRIG_CONTROL_EDGE_LO_HI			0x0000
216 #define DB2K_TRIG_CONTROL_LEVEL_ABOVE			0x0000
217 #define DB2K_TRIG_CONTROL_LEVEL_BELOW			0x0004
218 #define DB2K_TRIG_CONTROL_SENSE_LEVEL			0x0002
219 #define DB2K_TRIG_CONTROL_SENSE_EDGE			0x0000
220 #define DB2K_TRIG_CONTROL_ENABLE			0x0001
221 #define DB2K_TRIG_CONTROL_DISABLE			0x0000
222 
223 /* Reference Dac Selection */
224 #define DB2K_REF_DACS_SET				0x0080
225 #define DB2K_REF_DACS_SELECT_POS_REF			0x0100
226 #define DB2K_REF_DACS_SELECT_NEG_REF			0x0000
227 
228 /* CPLD status bits */
229 #define DB2K_CPLD_STATUS_INIT				0x0002
230 #define DB2K_CPLD_STATUS_TXREADY			0x0004
231 #define DB2K_CPLD_VERSION_MASK				0xf000
232 /* "New CPLD" signature. */
233 #define DB2K_CPLD_VERSION_NEW				0x5000
234 
235 enum db2k_boardid {
236 	BOARD_DAQBOARD2000,
237 	BOARD_DAQBOARD2001
238 };
239 
240 struct db2k_boardtype {
241 	const char *name;
242 	unsigned int has_2_ao:1;/* false: 4 AO chans; true: 2 AO chans */
243 };
244 
245 static const struct db2k_boardtype db2k_boardtypes[] = {
246 	[BOARD_DAQBOARD2000] = {
247 		.name		= "daqboard2000",
248 		.has_2_ao	= true,
249 	},
250 	[BOARD_DAQBOARD2001] = {
251 		.name		= "daqboard2001",
252 	},
253 };
254 
255 struct db2k_private {
256 	void __iomem *plx;
257 };
258 
db2k_write_acq_scan_list_entry(struct comedi_device * dev,u16 entry)259 static void db2k_write_acq_scan_list_entry(struct comedi_device *dev, u16 entry)
260 {
261 	writew(entry & 0x00ff, dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO);
262 	writew((entry >> 8) & 0x00ff,
263 	       dev->mmio + DB2K_REG_ACQ_SCAN_LIST_FIFO);
264 }
265 
db2k_setup_sampling(struct comedi_device * dev,int chan,int gain)266 static void db2k_setup_sampling(struct comedi_device *dev, int chan, int gain)
267 {
268 	u16 word0, word1, word2, word3;
269 
270 	/* Channel 0-7 diff, channel 8-23 single ended */
271 	word0 = 0;
272 	word1 = 0x0004;		/* Last scan */
273 	word2 = (chan << 6) & 0x00c0;
274 	switch (chan / 4) {
275 	case 0:
276 		word3 = 0x0001;
277 		break;
278 	case 1:
279 		word3 = 0x0002;
280 		break;
281 	case 2:
282 		word3 = 0x0005;
283 		break;
284 	case 3:
285 		word3 = 0x0006;
286 		break;
287 	case 4:
288 		word3 = 0x0041;
289 		break;
290 	case 5:
291 		word3 = 0x0042;
292 		break;
293 	default:
294 		word3 = 0;
295 		break;
296 	}
297 	/* These should be read from EEPROM */
298 	word2 |= 0x0800;	/* offset */
299 	word3 |= 0xc000;	/* gain */
300 	db2k_write_acq_scan_list_entry(dev, word0);
301 	db2k_write_acq_scan_list_entry(dev, word1);
302 	db2k_write_acq_scan_list_entry(dev, word2);
303 	db2k_write_acq_scan_list_entry(dev, word3);
304 }
305 
db2k_ai_status(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)306 static int db2k_ai_status(struct comedi_device *dev, struct comedi_subdevice *s,
307 			  struct comedi_insn *insn, unsigned long context)
308 {
309 	unsigned int status;
310 
311 	status = readw(dev->mmio + DB2K_REG_ACQ_STATUS);
312 	if (status & context)
313 		return 0;
314 	return -EBUSY;
315 }
316 
db2k_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)317 static int db2k_ai_insn_read(struct comedi_device *dev,
318 			     struct comedi_subdevice *s,
319 			     struct comedi_insn *insn, unsigned int *data)
320 {
321 	int gain, chan;
322 	int ret;
323 	int i;
324 
325 	writew(DB2K_ACQ_CONTROL_RESET_SCAN_LIST_FIFO |
326 	       DB2K_ACQ_CONTROL_RESET_RESULTS_FIFO |
327 	       DB2K_ACQ_CONTROL_RESET_CONFIG_PIPE,
328 	       dev->mmio + DB2K_REG_ACQ_CONTROL);
329 
330 	/*
331 	 * If pacer clock is not set to some high value (> 10 us), we
332 	 * risk multiple samples to be put into the result FIFO.
333 	 */
334 	/* 1 second, should be long enough */
335 	writel(1000000, dev->mmio + DB2K_REG_ACQ_PACER_CLOCK_DIV_LOW);
336 	writew(0, dev->mmio + DB2K_REG_ACQ_PACER_CLOCK_DIV_HIGH);
337 
338 	gain = CR_RANGE(insn->chanspec);
339 	chan = CR_CHAN(insn->chanspec);
340 
341 	/*
342 	 * This doesn't look efficient.  I decided to take the conservative
343 	 * approach when I did the insn conversion.  Perhaps it would be
344 	 * better to have broken it completely, then someone would have been
345 	 * forced to fix it.  --ds
346 	 */
347 	for (i = 0; i < insn->n; i++) {
348 		db2k_setup_sampling(dev, chan, gain);
349 		/* Enable reading from the scanlist FIFO */
350 		writew(DB2K_ACQ_CONTROL_SEQ_START_SCAN_LIST,
351 		       dev->mmio + DB2K_REG_ACQ_CONTROL);
352 
353 		ret = comedi_timeout(dev, s, insn, db2k_ai_status,
354 				     DB2K_ACQ_STATUS_CONFIG_PIPE_FULL);
355 		if (ret)
356 			return ret;
357 
358 		writew(DB2K_ACQ_CONTROL_ADC_PACER_ENABLE,
359 		       dev->mmio + DB2K_REG_ACQ_CONTROL);
360 
361 		ret = comedi_timeout(dev, s, insn, db2k_ai_status,
362 				     DB2K_ACQ_STATUS_LOGIC_SCANNING);
363 		if (ret)
364 			return ret;
365 
366 		ret =
367 		comedi_timeout(dev, s, insn, db2k_ai_status,
368 			       DB2K_ACQ_STATUS_RESULTS_FIFO_HAS_DATA);
369 		if (ret)
370 			return ret;
371 
372 		data[i] = readw(dev->mmio + DB2K_REG_ACQ_RESULTS_FIFO);
373 		writew(DB2K_ACQ_CONTROL_ADC_PACER_DISABLE,
374 		       dev->mmio + DB2K_REG_ACQ_CONTROL);
375 		writew(DB2K_ACQ_CONTROL_SEQ_STOP_SCAN_LIST,
376 		       dev->mmio + DB2K_REG_ACQ_CONTROL);
377 	}
378 
379 	return i;
380 }
381 
db2k_ao_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)382 static int db2k_ao_eoc(struct comedi_device *dev, struct comedi_subdevice *s,
383 		       struct comedi_insn *insn, unsigned long context)
384 {
385 	unsigned int chan = CR_CHAN(insn->chanspec);
386 	unsigned int status;
387 
388 	status = readw(dev->mmio + DB2K_REG_DAC_STATUS);
389 	if ((status & DB2K_DAC_STATUS_DAC_BUSY(chan)) == 0)
390 		return 0;
391 	return -EBUSY;
392 }
393 
db2k_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)394 static int db2k_ao_insn_write(struct comedi_device *dev,
395 			      struct comedi_subdevice *s,
396 			      struct comedi_insn *insn, unsigned int *data)
397 {
398 	unsigned int chan = CR_CHAN(insn->chanspec);
399 	int i;
400 
401 	for (i = 0; i < insn->n; i++) {
402 		unsigned int val = data[i];
403 		int ret;
404 
405 		writew(val, dev->mmio + DB2K_REG_DAC_SETTING(chan));
406 
407 		ret = comedi_timeout(dev, s, insn, db2k_ao_eoc, 0);
408 		if (ret)
409 			return ret;
410 
411 		s->readback[chan] = val;
412 	}
413 
414 	return insn->n;
415 }
416 
db2k_reset_local_bus(struct comedi_device * dev)417 static void db2k_reset_local_bus(struct comedi_device *dev)
418 {
419 	struct db2k_private *devpriv = dev->private;
420 	u32 cntrl;
421 
422 	cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
423 	cntrl |= PLX_CNTRL_RESET;
424 	writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
425 	mdelay(10);
426 	cntrl &= ~PLX_CNTRL_RESET;
427 	writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
428 	mdelay(10);
429 }
430 
db2k_reload_plx(struct comedi_device * dev)431 static void db2k_reload_plx(struct comedi_device *dev)
432 {
433 	struct db2k_private *devpriv = dev->private;
434 	u32 cntrl;
435 
436 	cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
437 	cntrl &= ~PLX_CNTRL_EERELOAD;
438 	writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
439 	mdelay(10);
440 	cntrl |= PLX_CNTRL_EERELOAD;
441 	writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
442 	mdelay(10);
443 	cntrl &= ~PLX_CNTRL_EERELOAD;
444 	writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
445 	mdelay(10);
446 }
447 
db2k_pulse_prog_pin(struct comedi_device * dev)448 static void db2k_pulse_prog_pin(struct comedi_device *dev)
449 {
450 	struct db2k_private *devpriv = dev->private;
451 	u32 cntrl;
452 
453 	cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
454 	cntrl |= PLX_CNTRL_USERO;
455 	writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
456 	mdelay(10);
457 	cntrl &= ~PLX_CNTRL_USERO;
458 	writel(cntrl, devpriv->plx + PLX_REG_CNTRL);
459 	mdelay(10);	/* Not in the original code, but I like symmetry... */
460 }
461 
db2k_wait_cpld_init(struct comedi_device * dev)462 static int db2k_wait_cpld_init(struct comedi_device *dev)
463 {
464 	int result = -ETIMEDOUT;
465 	int i;
466 	u16 cpld;
467 
468 	/* timeout after 50 tries -> 5ms */
469 	for (i = 0; i < 50; i++) {
470 		cpld = readw(dev->mmio + DB2K_REG_CPLD_STATUS);
471 		if (cpld & DB2K_CPLD_STATUS_INIT) {
472 			result = 0;
473 			break;
474 		}
475 		usleep_range(100, 1000);
476 	}
477 	udelay(5);
478 	return result;
479 }
480 
db2k_wait_cpld_txready(struct comedi_device * dev)481 static int db2k_wait_cpld_txready(struct comedi_device *dev)
482 {
483 	int i;
484 
485 	for (i = 0; i < 100; i++) {
486 		if (readw(dev->mmio + DB2K_REG_CPLD_STATUS) &
487 		    DB2K_CPLD_STATUS_TXREADY) {
488 			return 0;
489 		}
490 		udelay(1);
491 	}
492 	return -ETIMEDOUT;
493 }
494 
db2k_write_cpld(struct comedi_device * dev,u16 data,bool new_cpld)495 static int db2k_write_cpld(struct comedi_device *dev, u16 data, bool new_cpld)
496 {
497 	int result = 0;
498 
499 	if (new_cpld) {
500 		result = db2k_wait_cpld_txready(dev);
501 		if (result)
502 			return result;
503 	} else {
504 		usleep_range(10, 20);
505 	}
506 	writew(data, dev->mmio + DB2K_REG_CPLD_WDATA);
507 	if (!(readw(dev->mmio + DB2K_REG_CPLD_STATUS) & DB2K_CPLD_STATUS_INIT))
508 		result = -EIO;
509 
510 	return result;
511 }
512 
db2k_wait_fpga_programmed(struct comedi_device * dev)513 static int db2k_wait_fpga_programmed(struct comedi_device *dev)
514 {
515 	struct db2k_private *devpriv = dev->private;
516 	int i;
517 
518 	/* Time out after 200 tries -> 20ms */
519 	for (i = 0; i < 200; i++) {
520 		u32 cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
521 		/* General Purpose Input (USERI) set on FPGA "DONE". */
522 		if (cntrl & PLX_CNTRL_USERI)
523 			return 0;
524 
525 		usleep_range(100, 1000);
526 	}
527 	return -ETIMEDOUT;
528 }
529 
db2k_load_firmware(struct comedi_device * dev,const u8 * cpld_array,size_t len,unsigned long context)530 static int db2k_load_firmware(struct comedi_device *dev, const u8 *cpld_array,
531 			      size_t len, unsigned long context)
532 {
533 	struct db2k_private *devpriv = dev->private;
534 	int result = -EIO;
535 	u32 cntrl;
536 	int retry;
537 	size_t i;
538 	bool new_cpld;
539 
540 	/* Look for FPGA start sequence in firmware. */
541 	for (i = 0; i + 1 < len; i++) {
542 		if (cpld_array[i] == 0xff && cpld_array[i + 1] == 0x20)
543 			break;
544 	}
545 	if (i + 1 >= len) {
546 		dev_err(dev->class_dev, "bad firmware - no start sequence\n");
547 		return -EINVAL;
548 	}
549 	/* Check length is even. */
550 	if ((len - i) & 1) {
551 		dev_err(dev->class_dev,
552 			"bad firmware - odd length (%zu = %zu - %zu)\n",
553 			len - i, len, i);
554 		return -EINVAL;
555 	}
556 	/* Strip firmware header. */
557 	cpld_array += i;
558 	len -= i;
559 
560 	/* Check to make sure the serial eeprom is present on the board */
561 	cntrl = readl(devpriv->plx + PLX_REG_CNTRL);
562 	if (!(cntrl & PLX_CNTRL_EEPRESENT))
563 		return -EIO;
564 
565 	for (retry = 0; retry < 3; retry++) {
566 		db2k_reset_local_bus(dev);
567 		db2k_reload_plx(dev);
568 		db2k_pulse_prog_pin(dev);
569 		result = db2k_wait_cpld_init(dev);
570 		if (result)
571 			continue;
572 
573 		new_cpld = (readw(dev->mmio + DB2K_REG_CPLD_STATUS) &
574 			    DB2K_CPLD_VERSION_MASK) == DB2K_CPLD_VERSION_NEW;
575 		for (; i < len; i += 2) {
576 			u16 data = (cpld_array[i] << 8) + cpld_array[i + 1];
577 
578 			result = db2k_write_cpld(dev, data, new_cpld);
579 			if (result)
580 				break;
581 		}
582 		if (result == 0)
583 			result = db2k_wait_fpga_programmed(dev);
584 		if (result == 0) {
585 			db2k_reset_local_bus(dev);
586 			db2k_reload_plx(dev);
587 			break;
588 		}
589 	}
590 	return result;
591 }
592 
db2k_adc_stop_dma_transfer(struct comedi_device * dev)593 static void db2k_adc_stop_dma_transfer(struct comedi_device *dev)
594 {
595 }
596 
db2k_adc_disarm(struct comedi_device * dev)597 static void db2k_adc_disarm(struct comedi_device *dev)
598 {
599 	/* Disable hardware triggers */
600 	udelay(2);
601 	writew(DB2K_TRIG_CONTROL_TYPE_ANALOG | DB2K_TRIG_CONTROL_DISABLE,
602 	       dev->mmio + DB2K_REG_TRIG_CONTROL);
603 	udelay(2);
604 	writew(DB2K_TRIG_CONTROL_TYPE_TTL | DB2K_TRIG_CONTROL_DISABLE,
605 	       dev->mmio + DB2K_REG_TRIG_CONTROL);
606 
607 	/* Stop the scan list FIFO from loading the configuration pipe */
608 	udelay(2);
609 	writew(DB2K_ACQ_CONTROL_SEQ_STOP_SCAN_LIST,
610 	       dev->mmio + DB2K_REG_ACQ_CONTROL);
611 
612 	/* Stop the pacer clock */
613 	udelay(2);
614 	writew(DB2K_ACQ_CONTROL_ADC_PACER_DISABLE,
615 	       dev->mmio + DB2K_REG_ACQ_CONTROL);
616 
617 	/* Stop the input dma (abort channel 1) */
618 	db2k_adc_stop_dma_transfer(dev);
619 }
620 
db2k_activate_reference_dacs(struct comedi_device * dev)621 static void db2k_activate_reference_dacs(struct comedi_device *dev)
622 {
623 	unsigned int val;
624 	int timeout;
625 
626 	/*  Set the + reference dac value in the FPGA */
627 	writew(DB2K_REF_DACS_SET | DB2K_REF_DACS_SELECT_POS_REF,
628 	       dev->mmio + DB2K_REG_REF_DACS);
629 	for (timeout = 0; timeout < 20; timeout++) {
630 		val = readw(dev->mmio + DB2K_REG_DAC_STATUS);
631 		if ((val & DB2K_DAC_STATUS_REF_BUSY) == 0)
632 			break;
633 		udelay(2);
634 	}
635 
636 	/*  Set the - reference dac value in the FPGA */
637 	writew(DB2K_REF_DACS_SET | DB2K_REF_DACS_SELECT_NEG_REF,
638 	       dev->mmio + DB2K_REG_REF_DACS);
639 	for (timeout = 0; timeout < 20; timeout++) {
640 		val = readw(dev->mmio + DB2K_REG_DAC_STATUS);
641 		if ((val & DB2K_DAC_STATUS_REF_BUSY) == 0)
642 			break;
643 		udelay(2);
644 	}
645 }
646 
db2k_initialize_ctrs(struct comedi_device * dev)647 static void db2k_initialize_ctrs(struct comedi_device *dev)
648 {
649 }
650 
db2k_initialize_tmrs(struct comedi_device * dev)651 static void db2k_initialize_tmrs(struct comedi_device *dev)
652 {
653 }
654 
db2k_dac_disarm(struct comedi_device * dev)655 static void db2k_dac_disarm(struct comedi_device *dev)
656 {
657 }
658 
db2k_initialize_adc(struct comedi_device * dev)659 static void db2k_initialize_adc(struct comedi_device *dev)
660 {
661 	db2k_adc_disarm(dev);
662 	db2k_activate_reference_dacs(dev);
663 	db2k_initialize_ctrs(dev);
664 	db2k_initialize_tmrs(dev);
665 }
666 
db2k_8255_cb(struct comedi_device * dev,int dir,int port,int data,unsigned long iobase)667 static int db2k_8255_cb(struct comedi_device *dev, int dir, int port, int data,
668 			unsigned long iobase)
669 {
670 	if (dir) {
671 		writew(data, dev->mmio + iobase + port * 2);
672 		return 0;
673 	}
674 	return readw(dev->mmio + iobase + port * 2);
675 }
676 
db2k_auto_attach(struct comedi_device * dev,unsigned long context)677 static int db2k_auto_attach(struct comedi_device *dev, unsigned long context)
678 {
679 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
680 	const struct db2k_boardtype *board;
681 	struct db2k_private *devpriv;
682 	struct comedi_subdevice *s;
683 	int result;
684 
685 	if (context >= ARRAY_SIZE(db2k_boardtypes))
686 		return -ENODEV;
687 	board = &db2k_boardtypes[context];
688 	if (!board->name)
689 		return -ENODEV;
690 	dev->board_ptr = board;
691 	dev->board_name = board->name;
692 
693 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
694 	if (!devpriv)
695 		return -ENOMEM;
696 
697 	result = comedi_pci_enable(dev);
698 	if (result)
699 		return result;
700 
701 	devpriv->plx = pci_ioremap_bar(pcidev, 0);
702 	dev->mmio = pci_ioremap_bar(pcidev, 2);
703 	if (!devpriv->plx || !dev->mmio)
704 		return -ENOMEM;
705 
706 	result = comedi_alloc_subdevices(dev, 3);
707 	if (result)
708 		return result;
709 
710 	result = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev,
711 				      DB2K_FIRMWARE, db2k_load_firmware, 0);
712 	if (result < 0)
713 		return result;
714 
715 	db2k_initialize_adc(dev);
716 	db2k_dac_disarm(dev);
717 
718 	s = &dev->subdevices[0];
719 	/* ai subdevice */
720 	s->type = COMEDI_SUBD_AI;
721 	s->subdev_flags = SDF_READABLE | SDF_GROUND;
722 	s->n_chan = 24;
723 	s->maxdata = 0xffff;
724 	s->insn_read = db2k_ai_insn_read;
725 	s->range_table = &db2k_ai_range;
726 
727 	s = &dev->subdevices[1];
728 	/* ao subdevice */
729 	s->type = COMEDI_SUBD_AO;
730 	s->subdev_flags = SDF_WRITABLE;
731 	s->n_chan = board->has_2_ao ? 2 : 4;
732 	s->maxdata = 0xffff;
733 	s->insn_write = db2k_ao_insn_write;
734 	s->range_table = &range_bipolar10;
735 
736 	result = comedi_alloc_subdev_readback(s);
737 	if (result)
738 		return result;
739 
740 	s = &dev->subdevices[2];
741 	return subdev_8255_init(dev, s, db2k_8255_cb,
742 				DB2K_REG_DIO_P2_EXP_IO_8_BIT);
743 }
744 
db2k_detach(struct comedi_device * dev)745 static void db2k_detach(struct comedi_device *dev)
746 {
747 	struct db2k_private *devpriv = dev->private;
748 
749 	if (devpriv && devpriv->plx)
750 		iounmap(devpriv->plx);
751 	comedi_pci_detach(dev);
752 }
753 
754 static struct comedi_driver db2k_driver = {
755 	.driver_name	= "daqboard2000",
756 	.module		= THIS_MODULE,
757 	.auto_attach	= db2k_auto_attach,
758 	.detach		= db2k_detach,
759 };
760 
db2k_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)761 static int db2k_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
762 {
763 	return comedi_pci_auto_config(dev, &db2k_driver, id->driver_data);
764 }
765 
766 static const struct pci_device_id db2k_pci_table[] = {
767 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_IOTECH, 0x0409, PCI_VENDOR_ID_IOTECH,
768 			 0x0002), .driver_data = BOARD_DAQBOARD2000, },
769 	{ PCI_DEVICE_SUB(PCI_VENDOR_ID_IOTECH, 0x0409, PCI_VENDOR_ID_IOTECH,
770 			 0x0004), .driver_data = BOARD_DAQBOARD2001, },
771 	{ 0 }
772 };
773 MODULE_DEVICE_TABLE(pci, db2k_pci_table);
774 
775 static struct pci_driver db2k_pci_driver = {
776 	.name		= "daqboard2000",
777 	.id_table	= db2k_pci_table,
778 	.probe		= db2k_pci_probe,
779 	.remove		= comedi_pci_auto_unconfig,
780 };
781 module_comedi_pci_driver(db2k_driver, db2k_pci_driver);
782 
783 MODULE_AUTHOR("Comedi https://www.comedi.org");
784 MODULE_DESCRIPTION("Comedi low-level driver");
785 MODULE_LICENSE("GPL");
786 MODULE_FIRMWARE(DB2K_FIRMWARE);
787