1 /*
2  * adv_pci1710.c
3  * Comedi driver for Advantech PCI-1710 series boards
4  * Author: Michal Dobes <dobes@tesnet.cz>
5  *
6  * Thanks to ZhenGang Shang <ZhenGang.Shang@Advantech.com.cn>
7  * for testing and information.
8  */
9 
10 /*
11  * Driver: adv_pci1710
12  * Description: Comedi driver for Advantech PCI-1710 series boards
13  * Devices: [Advantech] PCI-1710 (adv_pci1710), PCI-1710HG, PCI-1711,
14  *   PCI-1713, PCI-1720, PCI-1731
15  * Author: Michal Dobes <dobes@tesnet.cz>
16  * Status: works
17  *
18  * Configuration options: not applicable, uses PCI auto config
19  *
20  * This driver supports AI, AO, DI and DO subdevices.
21  * AI subdevice supports cmd and insn interface,
22  * other subdevices support only insn interface.
23  *
24  * The PCI-1710 and PCI-1710HG have the same PCI device ID, so the
25  * driver cannot distinguish between them, as would be normal for a
26  * PCI driver.
27  */
28 
29 #include <linux/module.h>
30 #include <linux/interrupt.h>
31 
32 #include "../comedi_pci.h"
33 
34 #include "comedi_8254.h"
35 #include "amcc_s5933.h"
36 
37 /*
38  * PCI BAR2 Register map (dev->iobase)
39  */
40 #define PCI171X_AD_DATA_REG	0x00	/* R:   A/D data */
41 #define PCI171X_SOFTTRG_REG	0x00	/* W:   soft trigger for A/D */
42 #define PCI171X_RANGE_REG	0x02	/* W:   A/D gain/range register */
43 #define PCI171X_MUX_REG		0x04	/* W:   A/D multiplexor control */
44 #define PCI171X_STATUS_REG	0x06	/* R:   status register */
45 #define PCI171X_STATUS_IRQ	BIT(11)	/* 1=IRQ occurred */
46 #define PCI171X_STATUS_FF	BIT(10)	/* 1=FIFO is full, fatal error */
47 #define PCI171X_STATUS_FH	BIT(9)	/* 1=FIFO is half full */
48 #define PCI171X_STATUS_FE	BIT(8)	/* 1=FIFO is empty */
49 #define PCI171X_CTRL_REG	0x06	/* W:   control register */
50 #define PCI171X_CTRL_CNT0	BIT(6)	/* 1=ext. clk, 0=int. 100kHz clk */
51 #define PCI171X_CTRL_ONEFH	BIT(5)	/* 1=on FIFO half full, 0=on sample */
52 #define PCI171X_CTRL_IRQEN	BIT(4)	/* 1=enable IRQ */
53 #define PCI171X_CTRL_GATE	BIT(3)	/* 1=enable ext. trigger GATE (8254?) */
54 #define PCI171X_CTRL_EXT	BIT(2)	/* 1=enable ext. trigger source */
55 #define PCI171X_CTRL_PACER	BIT(1)	/* 1=enable int. 8254 trigger source */
56 #define PCI171X_CTRL_SW		BIT(0)	/* 1=enable software trigger source */
57 #define PCI171X_CLRINT_REG	0x08	/* W:   clear interrupts request */
58 #define PCI171X_CLRFIFO_REG	0x09	/* W:   clear FIFO */
59 #define PCI171X_DA_REG(x)	(0x0a + ((x) * 2)) /* W:   D/A register */
60 #define PCI171X_DAREF_REG	0x0e	/* W:   D/A reference control */
61 #define PCI171X_DI_REG		0x10	/* R:   digital inputs */
62 #define PCI171X_DO_REG		0x10	/* W:   digital outputs */
63 #define PCI171X_TIMER_BASE	0x18	/* R/W: 8254 timer */
64 
65 /*
66  * PCI-1720 only has analog outputs and has a different
67  * register map (dev->iobase)
68  */
69 #define PCI1720_DA_REG(x)	(0x00 + ((x) * 2)) /* W:   D/A registers */
70 #define PCI1720_RANGE_REG	0x08	/* R/W: D/A range register */
71 #define PCI1720_SYNC_REG	0x09	/* W:   D/A synchronized output */
72 #define PCI1720_SYNC_CTRL_REG	0x0f	/* R/W: D/A synchronized control */
73 #define PCI1720_SYNC_CTRL_SC0	BIT(0)	/* set synchronous output mode */
74 
75 static const struct comedi_lrange range_pci1710_3 = {
76 	9, {
77 		BIP_RANGE(5),
78 		BIP_RANGE(2.5),
79 		BIP_RANGE(1.25),
80 		BIP_RANGE(0.625),
81 		BIP_RANGE(10),
82 		UNI_RANGE(10),
83 		UNI_RANGE(5),
84 		UNI_RANGE(2.5),
85 		UNI_RANGE(1.25)
86 	}
87 };
88 
89 static const char range_codes_pci1710_3[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
90 					      0x10, 0x11, 0x12, 0x13 };
91 
92 static const struct comedi_lrange range_pci1710hg = {
93 	12, {
94 		BIP_RANGE(5),
95 		BIP_RANGE(0.5),
96 		BIP_RANGE(0.05),
97 		BIP_RANGE(0.005),
98 		BIP_RANGE(10),
99 		BIP_RANGE(1),
100 		BIP_RANGE(0.1),
101 		BIP_RANGE(0.01),
102 		UNI_RANGE(10),
103 		UNI_RANGE(1),
104 		UNI_RANGE(0.1),
105 		UNI_RANGE(0.01)
106 	}
107 };
108 
109 static const char range_codes_pci1710hg[] = { 0x00, 0x01, 0x02, 0x03, 0x04,
110 					      0x05, 0x06, 0x07, 0x10, 0x11,
111 					      0x12, 0x13 };
112 
113 static const struct comedi_lrange range_pci17x1 = {
114 	5, {
115 		BIP_RANGE(10),
116 		BIP_RANGE(5),
117 		BIP_RANGE(2.5),
118 		BIP_RANGE(1.25),
119 		BIP_RANGE(0.625)
120 	}
121 };
122 
123 static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
124 
125 static const struct comedi_lrange pci1720_ao_range = {
126 	4, {
127 		UNI_RANGE(5),
128 		UNI_RANGE(10),
129 		BIP_RANGE(5),
130 		BIP_RANGE(10)
131 	}
132 };
133 
134 static const struct comedi_lrange pci171x_ao_range = {
135 	2, {
136 		UNI_RANGE(5),
137 		UNI_RANGE(10)
138 	}
139 };
140 
141 enum pci1710_boardid {
142 	BOARD_PCI1710,
143 	BOARD_PCI1710HG,
144 	BOARD_PCI1711,
145 	BOARD_PCI1713,
146 	BOARD_PCI1720,
147 	BOARD_PCI1731,
148 };
149 
150 struct boardtype {
151 	const char *name;	/*  board name */
152 	int n_aichan;		/*  num of A/D chans */
153 	const struct comedi_lrange *rangelist_ai;	/*  rangelist for A/D */
154 	const char *rangecode_ai;	/*  range codes for programming */
155 	unsigned int is_pci1713:1;
156 	unsigned int is_pci1720:1;
157 	unsigned int has_irq:1;
158 	unsigned int has_large_fifo:1;	/* 4K or 1K FIFO */
159 	unsigned int has_diff_ai:1;
160 	unsigned int has_ao:1;
161 	unsigned int has_di_do:1;
162 	unsigned int has_counter:1;
163 };
164 
165 static const struct boardtype boardtypes[] = {
166 	[BOARD_PCI1710] = {
167 		.name		= "pci1710",
168 		.n_aichan	= 16,
169 		.rangelist_ai	= &range_pci1710_3,
170 		.rangecode_ai	= range_codes_pci1710_3,
171 		.has_irq	= 1,
172 		.has_large_fifo	= 1,
173 		.has_diff_ai	= 1,
174 		.has_ao		= 1,
175 		.has_di_do	= 1,
176 		.has_counter	= 1,
177 	},
178 	[BOARD_PCI1710HG] = {
179 		.name		= "pci1710hg",
180 		.n_aichan	= 16,
181 		.rangelist_ai	= &range_pci1710hg,
182 		.rangecode_ai	= range_codes_pci1710hg,
183 		.has_irq	= 1,
184 		.has_large_fifo	= 1,
185 		.has_diff_ai	= 1,
186 		.has_ao		= 1,
187 		.has_di_do	= 1,
188 		.has_counter	= 1,
189 	},
190 	[BOARD_PCI1711] = {
191 		.name		= "pci1711",
192 		.n_aichan	= 16,
193 		.rangelist_ai	= &range_pci17x1,
194 		.rangecode_ai	= range_codes_pci17x1,
195 		.has_irq	= 1,
196 		.has_ao		= 1,
197 		.has_di_do	= 1,
198 		.has_counter	= 1,
199 	},
200 	[BOARD_PCI1713] = {
201 		.name		= "pci1713",
202 		.n_aichan	= 32,
203 		.rangelist_ai	= &range_pci1710_3,
204 		.rangecode_ai	= range_codes_pci1710_3,
205 		.is_pci1713	= 1,
206 		.has_irq	= 1,
207 		.has_large_fifo	= 1,
208 		.has_diff_ai	= 1,
209 	},
210 	[BOARD_PCI1720] = {
211 		.name		= "pci1720",
212 		.is_pci1720	= 1,
213 		.has_ao		= 1,
214 	},
215 	[BOARD_PCI1731] = {
216 		.name		= "pci1731",
217 		.n_aichan	= 16,
218 		.rangelist_ai	= &range_pci17x1,
219 		.rangecode_ai	= range_codes_pci17x1,
220 		.has_irq	= 1,
221 		.has_di_do	= 1,
222 	},
223 };
224 
225 struct pci1710_private {
226 	unsigned int max_samples;
227 	unsigned int ctrl;	/* control register value */
228 	unsigned int ctrl_ext;	/* used to switch from TRIG_EXT to TRIG_xxx */
229 	unsigned int mux_ext;	/* used to set the channel interval to scan */
230 	unsigned char ai_et;
231 	unsigned int act_chanlist[32];	/*  list of scanned channel */
232 	unsigned char saved_seglen;	/* len of the non-repeating chanlist */
233 	unsigned char da_ranges;	/*  copy of D/A outpit range register */
234 };
235 
pci171x_ai_check_chanlist(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)236 static int pci171x_ai_check_chanlist(struct comedi_device *dev,
237 				     struct comedi_subdevice *s,
238 				     struct comedi_cmd *cmd)
239 {
240 	struct pci1710_private *devpriv = dev->private;
241 	unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
242 	unsigned int last_aref = CR_AREF(cmd->chanlist[0]);
243 	unsigned int next_chan = (chan0 + 1) % s->n_chan;
244 	unsigned int chansegment[32];
245 	unsigned int seglen;
246 	int i;
247 
248 	if (cmd->chanlist_len == 1) {
249 		devpriv->saved_seglen = cmd->chanlist_len;
250 		return 0;
251 	}
252 
253 	/* first channel is always ok */
254 	chansegment[0] = cmd->chanlist[0];
255 
256 	for (i = 1; i < cmd->chanlist_len; i++) {
257 		unsigned int chan = CR_CHAN(cmd->chanlist[i]);
258 		unsigned int aref = CR_AREF(cmd->chanlist[i]);
259 
260 		if (cmd->chanlist[0] == cmd->chanlist[i])
261 			break;	/*  we detected a loop, stop */
262 
263 		if (aref == AREF_DIFF && (chan & 1)) {
264 			dev_err(dev->class_dev,
265 				"Odd channel cannot be differential input!\n");
266 			return -EINVAL;
267 		}
268 
269 		if (last_aref == AREF_DIFF)
270 			next_chan = (next_chan + 1) % s->n_chan;
271 		if (chan != next_chan) {
272 			dev_err(dev->class_dev,
273 				"channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
274 				i, chan, next_chan, chan0);
275 			return -EINVAL;
276 		}
277 
278 		/* next correct channel in list */
279 		chansegment[i] = cmd->chanlist[i];
280 		last_aref = aref;
281 	}
282 	seglen = i;
283 
284 	for (i = 0; i < cmd->chanlist_len; i++) {
285 		if (cmd->chanlist[i] != chansegment[i % seglen]) {
286 			dev_err(dev->class_dev,
287 				"bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n",
288 				i, CR_CHAN(chansegment[i]),
289 				CR_RANGE(chansegment[i]),
290 				CR_AREF(chansegment[i]),
291 				CR_CHAN(cmd->chanlist[i % seglen]),
292 				CR_RANGE(cmd->chanlist[i % seglen]),
293 				CR_AREF(chansegment[i % seglen]));
294 			return -EINVAL;
295 		}
296 	}
297 	devpriv->saved_seglen = seglen;
298 
299 	return 0;
300 }
301 
pci171x_ai_setup_chanlist(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int * chanlist,unsigned int n_chan,unsigned int seglen)302 static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
303 				      struct comedi_subdevice *s,
304 				      unsigned int *chanlist,
305 				      unsigned int n_chan,
306 				      unsigned int seglen)
307 {
308 	const struct boardtype *board = dev->board_ptr;
309 	struct pci1710_private *devpriv = dev->private;
310 	unsigned int first_chan = CR_CHAN(chanlist[0]);
311 	unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
312 	unsigned int i;
313 
314 	for (i = 0; i < seglen; i++) {	/*  store range list to card */
315 		unsigned int chan = CR_CHAN(chanlist[i]);
316 		unsigned int range = CR_RANGE(chanlist[i]);
317 		unsigned int aref = CR_AREF(chanlist[i]);
318 		unsigned int rangeval;
319 
320 		rangeval = board->rangecode_ai[range];
321 		if (aref == AREF_DIFF)
322 			rangeval |= 0x0020;
323 
324 		/* select channel and set range */
325 		outw(chan | (chan << 8), dev->iobase + PCI171X_MUX_REG);
326 		outw(rangeval, dev->iobase + PCI171X_RANGE_REG);
327 
328 		devpriv->act_chanlist[i] = chan;
329 	}
330 	for ( ; i < n_chan; i++)	/* store remainder of channel list */
331 		devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
332 
333 	/* select channel interval to scan */
334 	devpriv->mux_ext = first_chan | (last_chan << 8);
335 	outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG);
336 }
337 
pci171x_ai_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)338 static int pci171x_ai_eoc(struct comedi_device *dev,
339 			  struct comedi_subdevice *s,
340 			  struct comedi_insn *insn,
341 			  unsigned long context)
342 {
343 	unsigned int status;
344 
345 	status = inw(dev->iobase + PCI171X_STATUS_REG);
346 	if ((status & PCI171X_STATUS_FE) == 0)
347 		return 0;
348 	return -EBUSY;
349 }
350 
pci171x_ai_read_sample(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int cur_chan,unsigned int * val)351 static int pci171x_ai_read_sample(struct comedi_device *dev,
352 				  struct comedi_subdevice *s,
353 				  unsigned int cur_chan,
354 				  unsigned int *val)
355 {
356 	const struct boardtype *board = dev->board_ptr;
357 	struct pci1710_private *devpriv = dev->private;
358 	unsigned int sample;
359 	unsigned int chan;
360 
361 	sample = inw(dev->iobase + PCI171X_AD_DATA_REG);
362 	if (!board->is_pci1713) {
363 		/*
364 		 * The upper 4 bits of the 16-bit sample are the channel number
365 		 * that the sample was acquired from. Verify that this channel
366 		 * number matches the expected channel number.
367 		 */
368 		chan = sample >> 12;
369 		if (chan != devpriv->act_chanlist[cur_chan]) {
370 			dev_err(dev->class_dev,
371 				"A/D data droput: received from channel %d, expected %d\n",
372 				chan, devpriv->act_chanlist[cur_chan]);
373 			return -ENODATA;
374 		}
375 	}
376 	*val = sample & s->maxdata;
377 	return 0;
378 }
379 
pci171x_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)380 static int pci171x_ai_insn_read(struct comedi_device *dev,
381 				struct comedi_subdevice *s,
382 				struct comedi_insn *insn,
383 				unsigned int *data)
384 {
385 	struct pci1710_private *devpriv = dev->private;
386 	int ret = 0;
387 	int i;
388 
389 	devpriv->ctrl &= PCI171X_CTRL_CNT0;
390 	devpriv->ctrl |= PCI171X_CTRL_SW;	/*  set software trigger */
391 	outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
392 	outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
393 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
394 
395 	pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
396 
397 	for (i = 0; i < insn->n; i++) {
398 		unsigned int val;
399 
400 		/* start conversion */
401 		outw(0, dev->iobase + PCI171X_SOFTTRG_REG);
402 
403 		ret = comedi_timeout(dev, s, insn, pci171x_ai_eoc, 0);
404 		if (ret)
405 			break;
406 
407 		ret = pci171x_ai_read_sample(dev, s, 0, &val);
408 		if (ret)
409 			break;
410 
411 		data[i] = val;
412 	}
413 
414 	outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
415 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
416 
417 	return ret ? ret : insn->n;
418 }
419 
pci171x_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)420 static int pci171x_ao_insn_write(struct comedi_device *dev,
421 				 struct comedi_subdevice *s,
422 				 struct comedi_insn *insn,
423 				 unsigned int *data)
424 {
425 	struct pci1710_private *devpriv = dev->private;
426 	unsigned int chan = CR_CHAN(insn->chanspec);
427 	unsigned int range = CR_RANGE(insn->chanspec);
428 	unsigned int val = s->readback[chan];
429 	int i;
430 
431 	devpriv->da_ranges &= ~(1 << (chan << 1));
432 	devpriv->da_ranges |= (range << (chan << 1));
433 	outw(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG);
434 
435 	for (i = 0; i < insn->n; i++) {
436 		val = data[i];
437 		outw(val, dev->iobase + PCI171X_DA_REG(chan));
438 	}
439 
440 	s->readback[chan] = val;
441 
442 	return insn->n;
443 }
444 
pci171x_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)445 static int pci171x_di_insn_bits(struct comedi_device *dev,
446 				struct comedi_subdevice *s,
447 				struct comedi_insn *insn,
448 				unsigned int *data)
449 {
450 	data[1] = inw(dev->iobase + PCI171X_DI_REG);
451 
452 	return insn->n;
453 }
454 
pci171x_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)455 static int pci171x_do_insn_bits(struct comedi_device *dev,
456 				struct comedi_subdevice *s,
457 				struct comedi_insn *insn,
458 				unsigned int *data)
459 {
460 	if (comedi_dio_update_state(s, data))
461 		outw(s->state, dev->iobase + PCI171X_DO_REG);
462 
463 	data[1] = s->state;
464 
465 	return insn->n;
466 }
467 
pci1720_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)468 static int pci1720_ao_insn_write(struct comedi_device *dev,
469 				 struct comedi_subdevice *s,
470 				 struct comedi_insn *insn,
471 				 unsigned int *data)
472 {
473 	struct pci1710_private *devpriv = dev->private;
474 	unsigned int chan = CR_CHAN(insn->chanspec);
475 	unsigned int range = CR_RANGE(insn->chanspec);
476 	unsigned int val;
477 	int i;
478 
479 	val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
480 	val |= (range << (chan << 1));
481 	if (val != devpriv->da_ranges) {
482 		outb(val, dev->iobase + PCI1720_RANGE_REG);
483 		devpriv->da_ranges = val;
484 	}
485 
486 	val = s->readback[chan];
487 	for (i = 0; i < insn->n; i++) {
488 		val = data[i];
489 		outw(val, dev->iobase + PCI1720_DA_REG(chan));
490 		outb(0, dev->iobase + PCI1720_SYNC_REG); /* update outputs */
491 	}
492 
493 	s->readback[chan] = val;
494 
495 	return insn->n;
496 }
497 
pci171x_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)498 static int pci171x_ai_cancel(struct comedi_device *dev,
499 			     struct comedi_subdevice *s)
500 {
501 	struct pci1710_private *devpriv = dev->private;
502 
503 	devpriv->ctrl &= PCI171X_CTRL_CNT0;
504 	devpriv->ctrl |= PCI171X_CTRL_SW;
505 	/* reset any operations */
506 	outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
507 	comedi_8254_pacer_enable(dev->pacer, 1, 2, false);
508 	outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
509 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
510 
511 	return 0;
512 }
513 
pci1710_handle_every_sample(struct comedi_device * dev,struct comedi_subdevice * s)514 static void pci1710_handle_every_sample(struct comedi_device *dev,
515 					struct comedi_subdevice *s)
516 {
517 	struct comedi_cmd *cmd = &s->async->cmd;
518 	unsigned int status;
519 	unsigned int val;
520 	int ret;
521 
522 	status = inw(dev->iobase + PCI171X_STATUS_REG);
523 	if (status & PCI171X_STATUS_FE) {
524 		dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
525 		s->async->events |= COMEDI_CB_ERROR;
526 		return;
527 	}
528 	if (status & PCI171X_STATUS_FF) {
529 		dev_dbg(dev->class_dev,
530 			"A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
531 		s->async->events |= COMEDI_CB_ERROR;
532 		return;
533 	}
534 
535 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
536 
537 	for (; !(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_FE);) {
538 		ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
539 		if (ret) {
540 			s->async->events |= COMEDI_CB_ERROR;
541 			break;
542 		}
543 
544 		comedi_buf_write_samples(s, &val, 1);
545 
546 		if (cmd->stop_src == TRIG_COUNT &&
547 		    s->async->scans_done >= cmd->stop_arg) {
548 			s->async->events |= COMEDI_CB_EOA;
549 			break;
550 		}
551 	}
552 
553 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
554 }
555 
pci1710_handle_fifo(struct comedi_device * dev,struct comedi_subdevice * s)556 static void pci1710_handle_fifo(struct comedi_device *dev,
557 				struct comedi_subdevice *s)
558 {
559 	struct pci1710_private *devpriv = dev->private;
560 	struct comedi_async *async = s->async;
561 	struct comedi_cmd *cmd = &async->cmd;
562 	unsigned int status;
563 	int i;
564 
565 	status = inw(dev->iobase + PCI171X_STATUS_REG);
566 	if (!(status & PCI171X_STATUS_FH)) {
567 		dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
568 		async->events |= COMEDI_CB_ERROR;
569 		return;
570 	}
571 	if (status & PCI171X_STATUS_FF) {
572 		dev_dbg(dev->class_dev,
573 			"A/D FIFO Full status (Fatal Error!)\n");
574 		async->events |= COMEDI_CB_ERROR;
575 		return;
576 	}
577 
578 	for (i = 0; i < devpriv->max_samples; i++) {
579 		unsigned int val;
580 		int ret;
581 
582 		ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
583 		if (ret) {
584 			s->async->events |= COMEDI_CB_ERROR;
585 			break;
586 		}
587 
588 		if (!comedi_buf_write_samples(s, &val, 1))
589 			break;
590 
591 		if (cmd->stop_src == TRIG_COUNT &&
592 		    async->scans_done >= cmd->stop_arg) {
593 			async->events |= COMEDI_CB_EOA;
594 			break;
595 		}
596 	}
597 
598 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
599 }
600 
interrupt_service_pci1710(int irq,void * d)601 static irqreturn_t interrupt_service_pci1710(int irq, void *d)
602 {
603 	struct comedi_device *dev = d;
604 	struct pci1710_private *devpriv = dev->private;
605 	struct comedi_subdevice *s;
606 	struct comedi_cmd *cmd;
607 
608 	if (!dev->attached)	/*  is device attached? */
609 		return IRQ_NONE;	/*  no, exit */
610 
611 	s = dev->read_subdev;
612 	cmd = &s->async->cmd;
613 
614 	/*  is this interrupt from our board? */
615 	if (!(inw(dev->iobase + PCI171X_STATUS_REG) & PCI171X_STATUS_IRQ))
616 		return IRQ_NONE;	/*  no, exit */
617 
618 	if (devpriv->ai_et) {	/*  Switch from initial TRIG_EXT to TRIG_xxx. */
619 		devpriv->ai_et = 0;
620 		devpriv->ctrl &= PCI171X_CTRL_CNT0;
621 		devpriv->ctrl |= PCI171X_CTRL_SW; /* set software trigger */
622 		outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
623 		devpriv->ctrl = devpriv->ctrl_ext;
624 		outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
625 		outb(0, dev->iobase + PCI171X_CLRINT_REG);
626 		/* no sample on this interrupt; reset the channel interval */
627 		outw(devpriv->mux_ext, dev->iobase + PCI171X_MUX_REG);
628 		outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
629 		comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
630 		return IRQ_HANDLED;
631 	}
632 
633 	if (cmd->flags & CMDF_WAKE_EOS)
634 		pci1710_handle_every_sample(dev, s);
635 	else
636 		pci1710_handle_fifo(dev, s);
637 
638 	comedi_handle_events(dev, s);
639 
640 	return IRQ_HANDLED;
641 }
642 
pci171x_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)643 static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
644 {
645 	struct pci1710_private *devpriv = dev->private;
646 	struct comedi_cmd *cmd = &s->async->cmd;
647 
648 	pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
649 				  devpriv->saved_seglen);
650 
651 	outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
652 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
653 
654 	devpriv->ctrl &= PCI171X_CTRL_CNT0;
655 	if ((cmd->flags & CMDF_WAKE_EOS) == 0)
656 		devpriv->ctrl |= PCI171X_CTRL_ONEFH;
657 
658 	if (cmd->convert_src == TRIG_TIMER) {
659 		comedi_8254_update_divisors(dev->pacer);
660 
661 		devpriv->ctrl |= PCI171X_CTRL_PACER | PCI171X_CTRL_IRQEN;
662 		if (cmd->start_src == TRIG_EXT) {
663 			devpriv->ctrl_ext = devpriv->ctrl;
664 			devpriv->ctrl &= ~(PCI171X_CTRL_PACER |
665 					   PCI171X_CTRL_ONEFH |
666 					   PCI171X_CTRL_GATE);
667 			devpriv->ctrl |= PCI171X_CTRL_EXT;
668 			devpriv->ai_et = 1;
669 		} else {	/* TRIG_NOW */
670 			devpriv->ai_et = 0;
671 		}
672 		outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
673 
674 		if (cmd->start_src == TRIG_NOW)
675 			comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
676 	} else {	/* TRIG_EXT */
677 		devpriv->ctrl |= PCI171X_CTRL_EXT | PCI171X_CTRL_IRQEN;
678 		outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
679 	}
680 
681 	return 0;
682 }
683 
pci171x_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)684 static int pci171x_ai_cmdtest(struct comedi_device *dev,
685 			      struct comedi_subdevice *s,
686 			      struct comedi_cmd *cmd)
687 {
688 	int err = 0;
689 
690 	/* Step 1 : check if triggers are trivially valid */
691 
692 	err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
693 	err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
694 	err |= comedi_check_trigger_src(&cmd->convert_src,
695 					TRIG_TIMER | TRIG_EXT);
696 	err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
697 	err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
698 
699 	if (err)
700 		return 1;
701 
702 	/* step 2a: make sure trigger sources are unique */
703 
704 	err |= comedi_check_trigger_is_unique(cmd->start_src);
705 	err |= comedi_check_trigger_is_unique(cmd->convert_src);
706 	err |= comedi_check_trigger_is_unique(cmd->stop_src);
707 
708 	/* step 2b: and mutually compatible */
709 
710 	if (err)
711 		return 2;
712 
713 	/* Step 3: check if arguments are trivially valid */
714 
715 	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
716 	err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
717 
718 	if (cmd->convert_src == TRIG_TIMER)
719 		err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000);
720 	else	/* TRIG_FOLLOW */
721 		err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
722 
723 	err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
724 					   cmd->chanlist_len);
725 
726 	if (cmd->stop_src == TRIG_COUNT)
727 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
728 	else	/* TRIG_NONE */
729 		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
730 
731 	if (err)
732 		return 3;
733 
734 	/* step 4: fix up any arguments */
735 
736 	if (cmd->convert_src == TRIG_TIMER) {
737 		unsigned int arg = cmd->convert_arg;
738 
739 		comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
740 		err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
741 	}
742 
743 	if (err)
744 		return 4;
745 
746 	/* Step 5: check channel list */
747 
748 	err |= pci171x_ai_check_chanlist(dev, s, cmd);
749 
750 	if (err)
751 		return 5;
752 
753 	return 0;
754 }
755 
pci171x_insn_counter_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)756 static int pci171x_insn_counter_config(struct comedi_device *dev,
757 				       struct comedi_subdevice *s,
758 				       struct comedi_insn *insn,
759 				       unsigned int *data)
760 {
761 	struct pci1710_private *devpriv = dev->private;
762 
763 	switch (data[0]) {
764 	case INSN_CONFIG_SET_CLOCK_SRC:
765 		switch (data[1]) {
766 		case 0:	/* internal */
767 			devpriv->ctrl_ext &= ~PCI171X_CTRL_CNT0;
768 			break;
769 		case 1:	/* external */
770 			devpriv->ctrl_ext |= PCI171X_CTRL_CNT0;
771 			break;
772 		default:
773 			return -EINVAL;
774 		}
775 		outw(devpriv->ctrl_ext, dev->iobase + PCI171X_CTRL_REG);
776 		break;
777 	case INSN_CONFIG_GET_CLOCK_SRC:
778 		if (devpriv->ctrl_ext & PCI171X_CTRL_CNT0) {
779 			data[1] = 1;
780 			data[2] = 0;
781 		} else {
782 			data[1] = 0;
783 			data[2] = I8254_OSC_BASE_10MHZ;
784 		}
785 		break;
786 	default:
787 		return -EINVAL;
788 	}
789 
790 	return insn->n;
791 }
792 
pci171x_reset(struct comedi_device * dev)793 static int pci171x_reset(struct comedi_device *dev)
794 {
795 	const struct boardtype *board = dev->board_ptr;
796 	struct pci1710_private *devpriv = dev->private;
797 
798 	/* Software trigger, CNT0=external */
799 	devpriv->ctrl = PCI171X_CTRL_SW | PCI171X_CTRL_CNT0;
800 	/* reset any operations */
801 	outw(devpriv->ctrl, dev->iobase + PCI171X_CTRL_REG);
802 	outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
803 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
804 	devpriv->da_ranges = 0;
805 	if (board->has_ao) {
806 		/* set DACs to 0..5V and outputs to 0V */
807 		outb(devpriv->da_ranges, dev->iobase + PCI171X_DAREF_REG);
808 		outw(0, dev->iobase + PCI171X_DA_REG(0));
809 		outw(0, dev->iobase + PCI171X_DA_REG(1));
810 	}
811 	outw(0, dev->iobase + PCI171X_DO_REG);	/*  digital outputs to 0 */
812 	outb(0, dev->iobase + PCI171X_CLRFIFO_REG);
813 	outb(0, dev->iobase + PCI171X_CLRINT_REG);
814 
815 	return 0;
816 }
817 
pci1720_reset(struct comedi_device * dev)818 static int pci1720_reset(struct comedi_device *dev)
819 {
820 	struct pci1710_private *devpriv = dev->private;
821 	/* set synchronous output mode */
822 	outb(PCI1720_SYNC_CTRL_SC0, dev->iobase + PCI1720_SYNC_CTRL_REG);
823 	devpriv->da_ranges = 0xAA;
824 	/* set all ranges to +/-5V and outputs to 0V */
825 	outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE_REG);
826 	outw(0x0800, dev->iobase + PCI1720_DA_REG(0));
827 	outw(0x0800, dev->iobase + PCI1720_DA_REG(1));
828 	outw(0x0800, dev->iobase + PCI1720_DA_REG(2));
829 	outw(0x0800, dev->iobase + PCI1720_DA_REG(3));
830 	outb(0, dev->iobase + PCI1720_SYNC_REG);	/* update outputs */
831 
832 	return 0;
833 }
834 
pci1710_reset(struct comedi_device * dev)835 static int pci1710_reset(struct comedi_device *dev)
836 {
837 	const struct boardtype *board = dev->board_ptr;
838 
839 	if (board->is_pci1720)
840 		return pci1720_reset(dev);
841 
842 	return pci171x_reset(dev);
843 }
844 
pci1710_auto_attach(struct comedi_device * dev,unsigned long context)845 static int pci1710_auto_attach(struct comedi_device *dev,
846 			       unsigned long context)
847 {
848 	struct pci_dev *pcidev = comedi_to_pci_dev(dev);
849 	const struct boardtype *board = NULL;
850 	struct pci1710_private *devpriv;
851 	struct comedi_subdevice *s;
852 	int ret, subdev, n_subdevices;
853 
854 	if (context < ARRAY_SIZE(boardtypes))
855 		board = &boardtypes[context];
856 	if (!board)
857 		return -ENODEV;
858 	dev->board_ptr = board;
859 	dev->board_name = board->name;
860 
861 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
862 	if (!devpriv)
863 		return -ENOMEM;
864 
865 	ret = comedi_pci_enable(dev);
866 	if (ret)
867 		return ret;
868 	dev->iobase = pci_resource_start(pcidev, 2);
869 
870 	dev->pacer = comedi_8254_init(dev->iobase + PCI171X_TIMER_BASE,
871 				      I8254_OSC_BASE_10MHZ, I8254_IO16, 0);
872 	if (!dev->pacer)
873 		return -ENOMEM;
874 
875 	n_subdevices = 0;
876 	if (board->n_aichan)
877 		n_subdevices++;
878 	if (board->has_ao)
879 		n_subdevices++;
880 	if (board->has_di_do)
881 		n_subdevices += 2;
882 	if (board->has_counter)
883 		n_subdevices++;
884 
885 	ret = comedi_alloc_subdevices(dev, n_subdevices);
886 	if (ret)
887 		return ret;
888 
889 	pci1710_reset(dev);
890 
891 	if (board->has_irq && pcidev->irq) {
892 		ret = request_irq(pcidev->irq, interrupt_service_pci1710,
893 				  IRQF_SHARED, dev->board_name, dev);
894 		if (ret == 0)
895 			dev->irq = pcidev->irq;
896 	}
897 
898 	subdev = 0;
899 
900 	if (board->n_aichan) {
901 		s = &dev->subdevices[subdev];
902 		s->type		= COMEDI_SUBD_AI;
903 		s->subdev_flags	= SDF_READABLE | SDF_COMMON | SDF_GROUND;
904 		if (board->has_diff_ai)
905 			s->subdev_flags	|= SDF_DIFF;
906 		s->n_chan	= board->n_aichan;
907 		s->maxdata	= 0x0fff;
908 		s->range_table	= board->rangelist_ai;
909 		s->insn_read	= pci171x_ai_insn_read;
910 		if (dev->irq) {
911 			dev->read_subdev = s;
912 			s->subdev_flags	|= SDF_CMD_READ;
913 			s->len_chanlist	= s->n_chan;
914 			s->do_cmdtest	= pci171x_ai_cmdtest;
915 			s->do_cmd	= pci171x_ai_cmd;
916 			s->cancel	= pci171x_ai_cancel;
917 		}
918 		subdev++;
919 	}
920 
921 	if (board->has_ao) {
922 		s = &dev->subdevices[subdev];
923 		s->type		= COMEDI_SUBD_AO;
924 		s->subdev_flags	= SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
925 		s->maxdata	= 0x0fff;
926 		if (board->is_pci1720) {
927 			s->n_chan	= 4;
928 			s->range_table	= &pci1720_ao_range;
929 			s->insn_write	= pci1720_ao_insn_write;
930 		} else {
931 			s->n_chan	= 2;
932 			s->range_table	= &pci171x_ao_range;
933 			s->insn_write	= pci171x_ao_insn_write;
934 		}
935 
936 		ret = comedi_alloc_subdev_readback(s);
937 		if (ret)
938 			return ret;
939 
940 		/* initialize the readback values to match the board reset */
941 		if (board->is_pci1720) {
942 			int i;
943 
944 			for (i = 0; i < s->n_chan; i++)
945 				s->readback[i] = 0x0800;
946 		}
947 
948 		subdev++;
949 	}
950 
951 	if (board->has_di_do) {
952 		s = &dev->subdevices[subdev];
953 		s->type		= COMEDI_SUBD_DI;
954 		s->subdev_flags	= SDF_READABLE;
955 		s->n_chan	= 16;
956 		s->maxdata	= 1;
957 		s->range_table	= &range_digital;
958 		s->insn_bits	= pci171x_di_insn_bits;
959 		subdev++;
960 
961 		s = &dev->subdevices[subdev];
962 		s->type		= COMEDI_SUBD_DO;
963 		s->subdev_flags	= SDF_WRITABLE;
964 		s->n_chan	= 16;
965 		s->maxdata	= 1;
966 		s->range_table	= &range_digital;
967 		s->insn_bits	= pci171x_do_insn_bits;
968 		subdev++;
969 	}
970 
971 	/* Counter subdevice (8254) */
972 	if (board->has_counter) {
973 		s = &dev->subdevices[subdev];
974 		comedi_8254_subdevice_init(s, dev->pacer);
975 
976 		dev->pacer->insn_config = pci171x_insn_counter_config;
977 
978 		/* counters 1 and 2 are used internally for the pacer */
979 		comedi_8254_set_busy(dev->pacer, 1, true);
980 		comedi_8254_set_busy(dev->pacer, 2, true);
981 
982 		subdev++;
983 	}
984 
985 	/* max_samples is half the FIFO size (2 bytes/sample) */
986 	devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
987 
988 	return 0;
989 }
990 
pci1710_detach(struct comedi_device * dev)991 static void pci1710_detach(struct comedi_device *dev)
992 {
993 	if (dev->iobase)
994 		pci1710_reset(dev);
995 	comedi_pci_detach(dev);
996 }
997 
998 static struct comedi_driver adv_pci1710_driver = {
999 	.driver_name	= "adv_pci1710",
1000 	.module		= THIS_MODULE,
1001 	.auto_attach	= pci1710_auto_attach,
1002 	.detach		= pci1710_detach,
1003 };
1004 
adv_pci1710_pci_probe(struct pci_dev * dev,const struct pci_device_id * id)1005 static int adv_pci1710_pci_probe(struct pci_dev *dev,
1006 				 const struct pci_device_id *id)
1007 {
1008 	return comedi_pci_auto_config(dev, &adv_pci1710_driver,
1009 				      id->driver_data);
1010 }
1011 
1012 static const struct pci_device_id adv_pci1710_pci_table[] = {
1013 	{
1014 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1015 			       PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050),
1016 		.driver_data = BOARD_PCI1710,
1017 	}, {
1018 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1019 			       PCI_VENDOR_ID_ADVANTECH, 0x0000),
1020 		.driver_data = BOARD_PCI1710,
1021 	}, {
1022 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1023 			       PCI_VENDOR_ID_ADVANTECH, 0xb100),
1024 		.driver_data = BOARD_PCI1710,
1025 	}, {
1026 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1027 			       PCI_VENDOR_ID_ADVANTECH, 0xb200),
1028 		.driver_data = BOARD_PCI1710,
1029 	}, {
1030 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1031 			       PCI_VENDOR_ID_ADVANTECH, 0xc100),
1032 		.driver_data = BOARD_PCI1710,
1033 	}, {
1034 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1035 			       PCI_VENDOR_ID_ADVANTECH, 0xc200),
1036 		.driver_data = BOARD_PCI1710,
1037 	}, {
1038 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd100),
1039 		.driver_data = BOARD_PCI1710,
1040 	}, {
1041 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1042 			       PCI_VENDOR_ID_ADVANTECH, 0x0002),
1043 		.driver_data = BOARD_PCI1710HG,
1044 	}, {
1045 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1046 			       PCI_VENDOR_ID_ADVANTECH, 0xb102),
1047 		.driver_data = BOARD_PCI1710HG,
1048 	}, {
1049 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1050 			       PCI_VENDOR_ID_ADVANTECH, 0xb202),
1051 		.driver_data = BOARD_PCI1710HG,
1052 	}, {
1053 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1054 			       PCI_VENDOR_ID_ADVANTECH, 0xc102),
1055 		.driver_data = BOARD_PCI1710HG,
1056 	}, {
1057 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710,
1058 			       PCI_VENDOR_ID_ADVANTECH, 0xc202),
1059 		.driver_data = BOARD_PCI1710HG,
1060 	}, {
1061 		PCI_DEVICE_SUB(PCI_VENDOR_ID_ADVANTECH, 0x1710, 0x1000, 0xd102),
1062 		.driver_data = BOARD_PCI1710HG,
1063 	},
1064 	{ PCI_VDEVICE(ADVANTECH, 0x1711), BOARD_PCI1711 },
1065 	{ PCI_VDEVICE(ADVANTECH, 0x1713), BOARD_PCI1713 },
1066 	{ PCI_VDEVICE(ADVANTECH, 0x1720), BOARD_PCI1720 },
1067 	{ PCI_VDEVICE(ADVANTECH, 0x1731), BOARD_PCI1731 },
1068 	{ 0 }
1069 };
1070 MODULE_DEVICE_TABLE(pci, adv_pci1710_pci_table);
1071 
1072 static struct pci_driver adv_pci1710_pci_driver = {
1073 	.name		= "adv_pci1710",
1074 	.id_table	= adv_pci1710_pci_table,
1075 	.probe		= adv_pci1710_pci_probe,
1076 	.remove		= comedi_pci_auto_unconfig,
1077 };
1078 module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
1079 
1080 MODULE_AUTHOR("Comedi http://www.comedi.org");
1081 MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
1082 MODULE_LICENSE("GPL");
1083