xref: /openbmc/linux/drivers/comedi/drivers/das16.c (revision ee8ed014)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * das16.c
4  * DAS16 driver
5  *
6  * COMEDI - Linux Control and Measurement Device Interface
7  * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
8  * Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
9  * Copyright (C) 2001,2002 Frank Mori Hess <fmhess@users.sourceforge.net>
10  */
11 
12 /*
13  * Driver: das16
14  * Description: DAS16 compatible boards
15  * Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
16  * Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
17  *   DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
18  *   DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
19  *   DAS-1602 (das-1602),
20  *   [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
21  *   PC104-DAS16JR/16 (pc104-das16jr/16), CIO-DAS16 (cio-das16),
22  *   CIO-DAS16F (cio-das16/f), CIO-DAS16/JR (cio-das16/jr),
23  *   CIO-DAS16JR/16 (cio-das16jr/16), CIO-DAS1401/12 (cio-das1401/12),
24  *   CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
25  *   CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
26  *   CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
27  * Status: works
28  * Updated: 2003-10-12
29  *
30  * A rewrite of the das16 and das1600 drivers.
31  *
32  * Options:
33  *	[0] - base io address
34  *	[1] - irq (does nothing, irq is not used anymore)
35  *	[2] - dma channel (optional, required for comedi_command support)
36  *	[3] - master clock speed in MHz (optional, 1 or 10, ignored if
37  *		board can probe clock, defaults to 1)
38  *	[4] - analog input range lowest voltage in microvolts (optional,
39  *		only useful if your board does not have software
40  *		programmable gain)
41  *	[5] - analog input range highest voltage in microvolts (optional,
42  *		only useful if board does not have software programmable
43  *		gain)
44  *	[6] - analog output range lowest voltage in microvolts (optional)
45  *	[7] - analog output range highest voltage in microvolts (optional)
46  *
47  * Passing a zero for an option is the same as leaving it unspecified.
48  */
49 
50 /*
51  * Testing and debugging help provided by Daniel Koch.
52  *
53  * Keithley Manuals:
54  *	2309.PDF (das16)
55  *	4919.PDF (das1400, 1600)
56  *	4922.PDF (das-1400)
57  *	4923.PDF (das1200, 1400, 1600)
58  *
59  * Computer boards manuals also available from their website
60  * www.measurementcomputing.com
61  */
62 
63 #include <linux/module.h>
64 #include <linux/slab.h>
65 #include <linux/interrupt.h>
66 #include <linux/comedi/comedidev.h>
67 #include <linux/comedi/comedi_8255.h>
68 #include <linux/comedi/comedi_8254.h>
69 #include <linux/comedi/comedi_isadma.h>
70 
71 #define DAS16_DMA_SIZE 0xff00	/*  size in bytes of allocated dma buffer */
72 
73 /*
74  * Register I/O map
75  */
76 #define DAS16_TRIG_REG			0x00
77 #define DAS16_AI_LSB_REG		0x00
78 #define DAS16_AI_MSB_REG		0x01
79 #define DAS16_MUX_REG			0x02
80 #define DAS16_DIO_REG			0x03
81 #define DAS16_AO_LSB_REG(x)		((x) ? 0x06 : 0x04)
82 #define DAS16_AO_MSB_REG(x)		((x) ? 0x07 : 0x05)
83 #define DAS16_STATUS_REG		0x08
84 #define DAS16_STATUS_BUSY		BIT(7)
85 #define DAS16_STATUS_UNIPOLAR		BIT(6)
86 #define DAS16_STATUS_MUXBIT		BIT(5)
87 #define DAS16_STATUS_INT		BIT(4)
88 #define DAS16_CTRL_REG			0x09
89 #define DAS16_CTRL_INTE			BIT(7)
90 #define DAS16_CTRL_IRQ(x)		(((x) & 0x7) << 4)
91 #define DAS16_CTRL_DMAE			BIT(2)
92 #define DAS16_CTRL_PACING_MASK		(3 << 0)
93 #define DAS16_CTRL_INT_PACER		(3 << 0)
94 #define DAS16_CTRL_EXT_PACER		(2 << 0)
95 #define DAS16_CTRL_SOFT_PACER		(0 << 0)
96 #define DAS16_PACER_REG			0x0a
97 #define DAS16_PACER_BURST_LEN(x)	(((x) & 0xf) << 4)
98 #define DAS16_PACER_CTR0		BIT(1)
99 #define DAS16_PACER_TRIG0		BIT(0)
100 #define DAS16_GAIN_REG			0x0b
101 #define DAS16_TIMER_BASE_REG		0x0c	/* to 0x0f */
102 
103 #define DAS1600_CONV_REG		0x404
104 #define DAS1600_CONV_DISABLE		BIT(6)
105 #define DAS1600_BURST_REG		0x405
106 #define DAS1600_BURST_VAL		BIT(6)
107 #define DAS1600_ENABLE_REG		0x406
108 #define DAS1600_ENABLE_VAL		BIT(6)
109 #define DAS1600_STATUS_REG		0x407
110 #define DAS1600_STATUS_BME		BIT(6)
111 #define DAS1600_STATUS_ME		BIT(5)
112 #define DAS1600_STATUS_CD		BIT(4)
113 #define DAS1600_STATUS_WS		BIT(1)
114 #define DAS1600_STATUS_CLK_10MHZ	BIT(0)
115 
116 static const struct comedi_lrange range_das1x01_bip = {
117 	4, {
118 		BIP_RANGE(10),
119 		BIP_RANGE(1),
120 		BIP_RANGE(0.1),
121 		BIP_RANGE(0.01)
122 	}
123 };
124 
125 static const struct comedi_lrange range_das1x01_unip = {
126 	4, {
127 		UNI_RANGE(10),
128 		UNI_RANGE(1),
129 		UNI_RANGE(0.1),
130 		UNI_RANGE(0.01)
131 	}
132 };
133 
134 static const struct comedi_lrange range_das1x02_bip = {
135 	4, {
136 		BIP_RANGE(10),
137 		BIP_RANGE(5),
138 		BIP_RANGE(2.5),
139 		BIP_RANGE(1.25)
140 	}
141 };
142 
143 static const struct comedi_lrange range_das1x02_unip = {
144 	4, {
145 		UNI_RANGE(10),
146 		UNI_RANGE(5),
147 		UNI_RANGE(2.5),
148 		UNI_RANGE(1.25)
149 	}
150 };
151 
152 static const struct comedi_lrange range_das16jr = {
153 	9, {
154 		BIP_RANGE(10),
155 		BIP_RANGE(5),
156 		BIP_RANGE(2.5),
157 		BIP_RANGE(1.25),
158 		BIP_RANGE(0.625),
159 		UNI_RANGE(10),
160 		UNI_RANGE(5),
161 		UNI_RANGE(2.5),
162 		UNI_RANGE(1.25)
163 	}
164 };
165 
166 static const struct comedi_lrange range_das16jr_16 = {
167 	8, {
168 		BIP_RANGE(10),
169 		BIP_RANGE(5),
170 		BIP_RANGE(2.5),
171 		BIP_RANGE(1.25),
172 		UNI_RANGE(10),
173 		UNI_RANGE(5),
174 		UNI_RANGE(2.5),
175 		UNI_RANGE(1.25)
176 	}
177 };
178 
179 static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
180 static const int das16jr_16_gainlist[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
181 static const int das1600_gainlist[] = { 0, 1, 2, 3 };
182 
183 enum {
184 	das16_pg_none = 0,
185 	das16_pg_16jr,
186 	das16_pg_16jr_16,
187 	das16_pg_1601,
188 	das16_pg_1602,
189 };
190 
191 static const int *const das16_gainlists[] = {
192 	NULL,
193 	das16jr_gainlist,
194 	das16jr_16_gainlist,
195 	das1600_gainlist,
196 	das1600_gainlist,
197 };
198 
199 static const struct comedi_lrange *const das16_ai_uni_lranges[] = {
200 	&range_unknown,
201 	&range_das16jr,
202 	&range_das16jr_16,
203 	&range_das1x01_unip,
204 	&range_das1x02_unip,
205 };
206 
207 static const struct comedi_lrange *const das16_ai_bip_lranges[] = {
208 	&range_unknown,
209 	&range_das16jr,
210 	&range_das16jr_16,
211 	&range_das1x01_bip,
212 	&range_das1x02_bip,
213 };
214 
215 struct das16_board {
216 	const char *name;
217 	unsigned int ai_maxdata;
218 	unsigned int ai_speed;	/*  max conversion speed in nanosec */
219 	unsigned int ai_pg;
220 	unsigned int has_ao:1;
221 	unsigned int has_8255:1;
222 
223 	unsigned int i8255_offset;
224 
225 	unsigned int size;
226 	unsigned int id;
227 };
228 
229 static const struct das16_board das16_boards[] = {
230 	{
231 		.name		= "das-16",
232 		.ai_maxdata	= 0x0fff,
233 		.ai_speed	= 15000,
234 		.ai_pg		= das16_pg_none,
235 		.has_ao		= 1,
236 		.has_8255	= 1,
237 		.i8255_offset	= 0x10,
238 		.size		= 0x14,
239 		.id		= 0x00,
240 	}, {
241 		.name		= "das-16g",
242 		.ai_maxdata	= 0x0fff,
243 		.ai_speed	= 15000,
244 		.ai_pg		= das16_pg_none,
245 		.has_ao		= 1,
246 		.has_8255	= 1,
247 		.i8255_offset	= 0x10,
248 		.size		= 0x14,
249 		.id		= 0x00,
250 	}, {
251 		.name		= "das-16f",
252 		.ai_maxdata	= 0x0fff,
253 		.ai_speed	= 8500,
254 		.ai_pg		= das16_pg_none,
255 		.has_ao		= 1,
256 		.has_8255	= 1,
257 		.i8255_offset	= 0x10,
258 		.size		= 0x14,
259 		.id		= 0x00,
260 	}, {
261 		.name		= "cio-das16",
262 		.ai_maxdata	= 0x0fff,
263 		.ai_speed	= 20000,
264 		.ai_pg		= das16_pg_none,
265 		.has_ao		= 1,
266 		.has_8255	= 1,
267 		.i8255_offset	= 0x10,
268 		.size		= 0x14,
269 		.id		= 0x80,
270 	}, {
271 		.name		= "cio-das16/f",
272 		.ai_maxdata	= 0x0fff,
273 		.ai_speed	= 10000,
274 		.ai_pg		= das16_pg_none,
275 		.has_ao		= 1,
276 		.has_8255	= 1,
277 		.i8255_offset	= 0x10,
278 		.size		= 0x14,
279 		.id		= 0x80,
280 	}, {
281 		.name		= "cio-das16/jr",
282 		.ai_maxdata	= 0x0fff,
283 		.ai_speed	= 7692,
284 		.ai_pg		= das16_pg_16jr,
285 		.size		= 0x10,
286 		.id		= 0x00,
287 	}, {
288 		.name		= "pc104-das16jr",
289 		.ai_maxdata	= 0x0fff,
290 		.ai_speed	= 3300,
291 		.ai_pg		= das16_pg_16jr,
292 		.size		= 0x10,
293 		.id		= 0x00,
294 	}, {
295 		.name		= "cio-das16jr/16",
296 		.ai_maxdata	= 0xffff,
297 		.ai_speed	= 10000,
298 		.ai_pg		= das16_pg_16jr_16,
299 		.size		= 0x10,
300 		.id		= 0x00,
301 	}, {
302 		.name		= "pc104-das16jr/16",
303 		.ai_maxdata	= 0xffff,
304 		.ai_speed	= 10000,
305 		.ai_pg		= das16_pg_16jr_16,
306 		.size		= 0x10,
307 		.id		= 0x00,
308 	}, {
309 		.name		= "das-1201",
310 		.ai_maxdata	= 0x0fff,
311 		.ai_speed	= 20000,
312 		.ai_pg		= das16_pg_none,
313 		.has_8255	= 1,
314 		.i8255_offset	= 0x400,
315 		.size		= 0x408,
316 		.id		= 0x20,
317 	}, {
318 		.name		= "das-1202",
319 		.ai_maxdata	= 0x0fff,
320 		.ai_speed	= 10000,
321 		.ai_pg		= das16_pg_none,
322 		.has_8255	= 1,
323 		.i8255_offset	= 0x400,
324 		.size		= 0x408,
325 		.id		= 0x20,
326 	}, {
327 		.name		= "das-1401",
328 		.ai_maxdata	= 0x0fff,
329 		.ai_speed	= 10000,
330 		.ai_pg		= das16_pg_1601,
331 		.size		= 0x408,
332 		.id		= 0xc0,
333 	}, {
334 		.name		= "das-1402",
335 		.ai_maxdata	= 0x0fff,
336 		.ai_speed	= 10000,
337 		.ai_pg		= das16_pg_1602,
338 		.size		= 0x408,
339 		.id		= 0xc0,
340 	}, {
341 		.name		= "das-1601",
342 		.ai_maxdata	= 0x0fff,
343 		.ai_speed	= 10000,
344 		.ai_pg		= das16_pg_1601,
345 		.has_ao		= 1,
346 		.has_8255	= 1,
347 		.i8255_offset	= 0x400,
348 		.size		= 0x408,
349 		.id		= 0xc0,
350 	}, {
351 		.name		= "das-1602",
352 		.ai_maxdata	= 0x0fff,
353 		.ai_speed	= 10000,
354 		.ai_pg		= das16_pg_1602,
355 		.has_ao		= 1,
356 		.has_8255	= 1,
357 		.i8255_offset	= 0x400,
358 		.size		= 0x408,
359 		.id		= 0xc0,
360 	}, {
361 		.name		= "cio-das1401/12",
362 		.ai_maxdata	= 0x0fff,
363 		.ai_speed	= 6250,
364 		.ai_pg		= das16_pg_1601,
365 		.size		= 0x408,
366 		.id		= 0xc0,
367 	}, {
368 		.name		= "cio-das1402/12",
369 		.ai_maxdata	= 0x0fff,
370 		.ai_speed	= 6250,
371 		.ai_pg		= das16_pg_1602,
372 		.size		= 0x408,
373 		.id		= 0xc0,
374 	}, {
375 		.name		= "cio-das1402/16",
376 		.ai_maxdata	= 0xffff,
377 		.ai_speed	= 10000,
378 		.ai_pg		= das16_pg_1602,
379 		.size		= 0x408,
380 		.id		= 0xc0,
381 	}, {
382 		.name		= "cio-das1601/12",
383 		.ai_maxdata	= 0x0fff,
384 		.ai_speed	= 6250,
385 		.ai_pg		= das16_pg_1601,
386 		.has_ao		= 1,
387 		.has_8255	= 1,
388 		.i8255_offset	= 0x400,
389 		.size		= 0x408,
390 		.id		= 0xc0,
391 	}, {
392 		.name		= "cio-das1602/12",
393 		.ai_maxdata	= 0x0fff,
394 		.ai_speed	= 10000,
395 		.ai_pg		= das16_pg_1602,
396 		.has_ao		= 1,
397 		.has_8255	= 1,
398 		.i8255_offset	= 0x400,
399 		.size		= 0x408,
400 		.id		= 0xc0,
401 	}, {
402 		.name		= "cio-das1602/16",
403 		.ai_maxdata	= 0xffff,
404 		.ai_speed	= 10000,
405 		.ai_pg		= das16_pg_1602,
406 		.has_ao		= 1,
407 		.has_8255	= 1,
408 		.i8255_offset	= 0x400,
409 		.size		= 0x408,
410 		.id		= 0xc0,
411 	}, {
412 		.name		= "cio-das16/330",
413 		.ai_maxdata	= 0x0fff,
414 		.ai_speed	= 3030,
415 		.ai_pg		= das16_pg_16jr,
416 		.size		= 0x14,
417 		.id		= 0xf0,
418 	},
419 };
420 
421 /*
422  * Period for timer interrupt in jiffies.  It's a function
423  * to deal with possibility of dynamic HZ patches
424  */
timer_period(void)425 static inline int timer_period(void)
426 {
427 	return HZ / 20;
428 }
429 
430 struct das16_private_struct {
431 	struct comedi_isadma	*dma;
432 	struct comedi_device	*dev;
433 	unsigned int		clockbase;
434 	unsigned int		ctrl_reg;
435 	unsigned int		divisor1;
436 	unsigned int		divisor2;
437 	struct timer_list	timer;
438 	unsigned long		extra_iobase;
439 	unsigned int		can_burst:1;
440 	unsigned int		timer_running:1;
441 };
442 
das16_ai_setup_dma(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int unread_samples)443 static void das16_ai_setup_dma(struct comedi_device *dev,
444 			       struct comedi_subdevice *s,
445 			       unsigned int unread_samples)
446 {
447 	struct das16_private_struct *devpriv = dev->private;
448 	struct comedi_isadma *dma = devpriv->dma;
449 	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
450 	unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
451 	unsigned int nsamples;
452 
453 	/*
454 	 * Determine dma size based on the buffer size plus the number of
455 	 * unread samples and the number of samples remaining in the command.
456 	 */
457 	nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
458 	if (nsamples > unread_samples) {
459 		nsamples -= unread_samples;
460 		desc->size = comedi_samples_to_bytes(s, nsamples);
461 		comedi_isadma_program(desc);
462 	}
463 }
464 
das16_interrupt(struct comedi_device * dev)465 static void das16_interrupt(struct comedi_device *dev)
466 {
467 	struct das16_private_struct *devpriv = dev->private;
468 	struct comedi_subdevice *s = dev->read_subdev;
469 	struct comedi_async *async = s->async;
470 	struct comedi_cmd *cmd = &async->cmd;
471 	struct comedi_isadma *dma = devpriv->dma;
472 	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
473 	unsigned long spin_flags;
474 	unsigned int residue;
475 	unsigned int nbytes;
476 	unsigned int nsamples;
477 
478 	spin_lock_irqsave(&dev->spinlock, spin_flags);
479 	if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) {
480 		spin_unlock_irqrestore(&dev->spinlock, spin_flags);
481 		return;
482 	}
483 
484 	/*
485 	 * The pc104-das16jr (at least) has problems if the dma
486 	 * transfer is interrupted in the middle of transferring
487 	 * a 16 bit sample.
488 	 */
489 	residue = comedi_isadma_disable_on_sample(desc->chan,
490 						  comedi_bytes_per_sample(s));
491 
492 	/* figure out how many samples to read */
493 	if (residue > desc->size) {
494 		dev_err(dev->class_dev, "residue > transfer size!\n");
495 		async->events |= COMEDI_CB_ERROR;
496 		nbytes = 0;
497 	} else {
498 		nbytes = desc->size - residue;
499 	}
500 	nsamples = comedi_bytes_to_samples(s, nbytes);
501 
502 	/* restart DMA if more samples are needed */
503 	if (nsamples) {
504 		dma->cur_dma = 1 - dma->cur_dma;
505 		das16_ai_setup_dma(dev, s, nsamples);
506 	}
507 
508 	spin_unlock_irqrestore(&dev->spinlock, spin_flags);
509 
510 	comedi_buf_write_samples(s, desc->virt_addr, nsamples);
511 
512 	if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
513 		async->events |= COMEDI_CB_EOA;
514 
515 	comedi_handle_events(dev, s);
516 }
517 
das16_timer_interrupt(struct timer_list * t)518 static void das16_timer_interrupt(struct timer_list *t)
519 {
520 	struct das16_private_struct *devpriv = from_timer(devpriv, t, timer);
521 	struct comedi_device *dev = devpriv->dev;
522 	unsigned long flags;
523 
524 	das16_interrupt(dev);
525 
526 	spin_lock_irqsave(&dev->spinlock, flags);
527 	if (devpriv->timer_running)
528 		mod_timer(&devpriv->timer, jiffies + timer_period());
529 	spin_unlock_irqrestore(&dev->spinlock, flags);
530 }
531 
das16_ai_set_mux_range(struct comedi_device * dev,unsigned int first_chan,unsigned int last_chan,unsigned int range)532 static void das16_ai_set_mux_range(struct comedi_device *dev,
533 				   unsigned int first_chan,
534 				   unsigned int last_chan,
535 				   unsigned int range)
536 {
537 	const struct das16_board *board = dev->board_ptr;
538 
539 	/* set multiplexer */
540 	outb(first_chan | (last_chan << 4), dev->iobase + DAS16_MUX_REG);
541 
542 	/* some boards do not have programmable gain */
543 	if (board->ai_pg == das16_pg_none)
544 		return;
545 
546 	/*
547 	 * Set gain (this is also burst rate register but according to
548 	 * computer boards manual, burst rate does nothing, even on
549 	 * keithley cards).
550 	 */
551 	outb((das16_gainlists[board->ai_pg])[range],
552 	     dev->iobase + DAS16_GAIN_REG);
553 }
554 
das16_ai_check_chanlist(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)555 static int das16_ai_check_chanlist(struct comedi_device *dev,
556 				   struct comedi_subdevice *s,
557 				   struct comedi_cmd *cmd)
558 {
559 	unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
560 	unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
561 	int i;
562 
563 	for (i = 1; i < cmd->chanlist_len; i++) {
564 		unsigned int chan = CR_CHAN(cmd->chanlist[i]);
565 		unsigned int range = CR_RANGE(cmd->chanlist[i]);
566 
567 		if (chan != ((chan0 + i) % s->n_chan)) {
568 			dev_dbg(dev->class_dev,
569 				"entries in chanlist must be consecutive channels, counting upwards\n");
570 			return -EINVAL;
571 		}
572 
573 		if (range != range0) {
574 			dev_dbg(dev->class_dev,
575 				"entries in chanlist must all have the same gain\n");
576 			return -EINVAL;
577 		}
578 	}
579 
580 	return 0;
581 }
582 
das16_cmd_test(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)583 static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s,
584 			  struct comedi_cmd *cmd)
585 {
586 	const struct das16_board *board = dev->board_ptr;
587 	struct das16_private_struct *devpriv = dev->private;
588 	int err = 0;
589 	unsigned int trig_mask;
590 	unsigned int arg;
591 
592 	/* Step 1 : check if triggers are trivially valid */
593 
594 	err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
595 
596 	trig_mask = TRIG_FOLLOW;
597 	if (devpriv->can_burst)
598 		trig_mask |= TRIG_TIMER | TRIG_EXT;
599 	err |= comedi_check_trigger_src(&cmd->scan_begin_src, trig_mask);
600 
601 	trig_mask = TRIG_TIMER | TRIG_EXT;
602 	if (devpriv->can_burst)
603 		trig_mask |= TRIG_NOW;
604 	err |= comedi_check_trigger_src(&cmd->convert_src, trig_mask);
605 
606 	err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
607 	err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
608 
609 	if (err)
610 		return 1;
611 
612 	/* Step 2a : make sure trigger sources are unique */
613 
614 	err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
615 	err |= comedi_check_trigger_is_unique(cmd->convert_src);
616 	err |= comedi_check_trigger_is_unique(cmd->stop_src);
617 
618 	/* Step 2b : and mutually compatible */
619 
620 	/*  make sure scan_begin_src and convert_src don't conflict */
621 	if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW)
622 		err |= -EINVAL;
623 	if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW)
624 		err |= -EINVAL;
625 
626 	if (err)
627 		return 2;
628 
629 	/* Step 3: check if arguments are trivially valid */
630 
631 	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
632 
633 	if (cmd->scan_begin_src == TRIG_FOLLOW)	/* internal trigger */
634 		err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
635 
636 	err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
637 					   cmd->chanlist_len);
638 
639 	/* check against maximum frequency */
640 	if (cmd->scan_begin_src == TRIG_TIMER) {
641 		err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg,
642 						    board->ai_speed *
643 						    cmd->chanlist_len);
644 	}
645 
646 	if (cmd->convert_src == TRIG_TIMER) {
647 		err |= comedi_check_trigger_arg_min(&cmd->convert_arg,
648 						    board->ai_speed);
649 	}
650 
651 	if (cmd->stop_src == TRIG_COUNT)
652 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
653 	else	/* TRIG_NONE */
654 		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
655 
656 	if (err)
657 		return 3;
658 
659 	/*  step 4: fix up arguments */
660 	if (cmd->scan_begin_src == TRIG_TIMER) {
661 		arg = cmd->scan_begin_arg;
662 		comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
663 		err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
664 	}
665 	if (cmd->convert_src == TRIG_TIMER) {
666 		arg = cmd->convert_arg;
667 		comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
668 		err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
669 	}
670 	if (err)
671 		return 4;
672 
673 	/* Step 5: check channel list if it exists */
674 	if (cmd->chanlist && cmd->chanlist_len > 0)
675 		err |= das16_ai_check_chanlist(dev, s, cmd);
676 
677 	if (err)
678 		return 5;
679 
680 	return 0;
681 }
682 
das16_set_pacer(struct comedi_device * dev,unsigned int ns,unsigned int flags)683 static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
684 				    unsigned int flags)
685 {
686 	comedi_8254_cascade_ns_to_timer(dev->pacer, &ns, flags);
687 	comedi_8254_update_divisors(dev->pacer);
688 	comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
689 
690 	return ns;
691 }
692 
das16_cmd_exec(struct comedi_device * dev,struct comedi_subdevice * s)693 static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
694 {
695 	struct das16_private_struct *devpriv = dev->private;
696 	struct comedi_isadma *dma = devpriv->dma;
697 	struct comedi_async *async = s->async;
698 	struct comedi_cmd *cmd = &async->cmd;
699 	unsigned int first_chan = CR_CHAN(cmd->chanlist[0]);
700 	unsigned int last_chan = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
701 	unsigned int range = CR_RANGE(cmd->chanlist[0]);
702 	unsigned int byte;
703 	unsigned long flags;
704 
705 	if (cmd->flags & CMDF_PRIORITY) {
706 		dev_err(dev->class_dev,
707 			"isa dma transfers cannot be performed with CMDF_PRIORITY, aborting\n");
708 		return -1;
709 	}
710 
711 	if (devpriv->can_burst)
712 		outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
713 
714 	/* set mux and range for chanlist scan */
715 	das16_ai_set_mux_range(dev, first_chan, last_chan, range);
716 
717 	/* set counter mode and counts */
718 	cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags);
719 
720 	/* enable counters */
721 	byte = 0;
722 	if (devpriv->can_burst) {
723 		if (cmd->convert_src == TRIG_NOW) {
724 			outb(DAS1600_BURST_VAL,
725 			     dev->iobase + DAS1600_BURST_REG);
726 			/*  set burst length */
727 			byte |= DAS16_PACER_BURST_LEN(cmd->chanlist_len - 1);
728 		} else {
729 			outb(0, dev->iobase + DAS1600_BURST_REG);
730 		}
731 	}
732 	outb(byte, dev->iobase + DAS16_PACER_REG);
733 
734 	/* set up dma transfer */
735 	dma->cur_dma = 0;
736 	das16_ai_setup_dma(dev, s, 0);
737 
738 	/*  set up timer */
739 	spin_lock_irqsave(&dev->spinlock, flags);
740 	devpriv->timer_running = 1;
741 	devpriv->timer.expires = jiffies + timer_period();
742 	add_timer(&devpriv->timer);
743 
744 	/* enable DMA interrupt with external or internal pacing */
745 	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_PACING_MASK);
746 	devpriv->ctrl_reg |= DAS16_CTRL_DMAE;
747 	if (cmd->convert_src == TRIG_EXT)
748 		devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
749 	else
750 		devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
751 	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
752 
753 	if (devpriv->can_burst)
754 		outb(0, dev->iobase + DAS1600_CONV_REG);
755 	spin_unlock_irqrestore(&dev->spinlock, flags);
756 
757 	return 0;
758 }
759 
das16_cancel(struct comedi_device * dev,struct comedi_subdevice * s)760 static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
761 {
762 	struct das16_private_struct *devpriv = dev->private;
763 	struct comedi_isadma *dma = devpriv->dma;
764 	unsigned long flags;
765 
766 	spin_lock_irqsave(&dev->spinlock, flags);
767 
768 	/* disable interrupts, dma and pacer clocked conversions */
769 	devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_DMAE |
770 			       DAS16_CTRL_PACING_MASK);
771 	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
772 
773 	comedi_isadma_disable(dma->chan);
774 
775 	/*  disable SW timer */
776 	if (devpriv->timer_running) {
777 		devpriv->timer_running = 0;
778 		del_timer(&devpriv->timer);
779 	}
780 
781 	if (devpriv->can_burst)
782 		outb(0, dev->iobase + DAS1600_BURST_REG);
783 
784 	spin_unlock_irqrestore(&dev->spinlock, flags);
785 
786 	return 0;
787 }
788 
das16_ai_munge(struct comedi_device * dev,struct comedi_subdevice * s,void * array,unsigned int num_bytes,unsigned int start_chan_index)789 static void das16_ai_munge(struct comedi_device *dev,
790 			   struct comedi_subdevice *s, void *array,
791 			   unsigned int num_bytes,
792 			   unsigned int start_chan_index)
793 {
794 	unsigned short *data = array;
795 	unsigned int num_samples = comedi_bytes_to_samples(s, num_bytes);
796 	unsigned int i;
797 	__le16 *buf = array;
798 
799 	for (i = 0; i < num_samples; i++) {
800 		data[i] = le16_to_cpu(buf[i]);
801 		if (s->maxdata == 0x0fff)
802 			data[i] >>= 4;
803 		data[i] &= s->maxdata;
804 	}
805 }
806 
das16_ai_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)807 static int das16_ai_eoc(struct comedi_device *dev,
808 			struct comedi_subdevice *s,
809 			struct comedi_insn *insn,
810 			unsigned long context)
811 {
812 	unsigned int status;
813 
814 	status = inb(dev->iobase + DAS16_STATUS_REG);
815 	if ((status & DAS16_STATUS_BUSY) == 0)
816 		return 0;
817 	return -EBUSY;
818 }
819 
das16_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)820 static int das16_ai_insn_read(struct comedi_device *dev,
821 			      struct comedi_subdevice *s,
822 			      struct comedi_insn *insn,
823 			      unsigned int *data)
824 {
825 	unsigned int chan = CR_CHAN(insn->chanspec);
826 	unsigned int range = CR_RANGE(insn->chanspec);
827 	unsigned int val;
828 	int ret;
829 	int i;
830 
831 	/* set mux and range for single channel */
832 	das16_ai_set_mux_range(dev, chan, chan, range);
833 
834 	for (i = 0; i < insn->n; i++) {
835 		/* trigger conversion */
836 		outb_p(0, dev->iobase + DAS16_TRIG_REG);
837 
838 		ret = comedi_timeout(dev, s, insn, das16_ai_eoc, 0);
839 		if (ret)
840 			return ret;
841 
842 		val = inb(dev->iobase + DAS16_AI_MSB_REG) << 8;
843 		val |= inb(dev->iobase + DAS16_AI_LSB_REG);
844 		if (s->maxdata == 0x0fff)
845 			val >>= 4;
846 		val &= s->maxdata;
847 
848 		data[i] = val;
849 	}
850 
851 	return insn->n;
852 }
853 
das16_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)854 static int das16_ao_insn_write(struct comedi_device *dev,
855 			       struct comedi_subdevice *s,
856 			       struct comedi_insn *insn,
857 			       unsigned int *data)
858 {
859 	unsigned int chan = CR_CHAN(insn->chanspec);
860 	int i;
861 
862 	for (i = 0; i < insn->n; i++) {
863 		unsigned int val = data[i];
864 
865 		s->readback[chan] = val;
866 
867 		val <<= 4;
868 
869 		outb(val & 0xff, dev->iobase + DAS16_AO_LSB_REG(chan));
870 		outb((val >> 8) & 0xff, dev->iobase + DAS16_AO_MSB_REG(chan));
871 	}
872 
873 	return insn->n;
874 }
875 
das16_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)876 static int das16_di_insn_bits(struct comedi_device *dev,
877 			      struct comedi_subdevice *s,
878 			      struct comedi_insn *insn,
879 			      unsigned int *data)
880 {
881 	data[1] = inb(dev->iobase + DAS16_DIO_REG) & 0xf;
882 
883 	return insn->n;
884 }
885 
das16_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)886 static int das16_do_insn_bits(struct comedi_device *dev,
887 			      struct comedi_subdevice *s,
888 			      struct comedi_insn *insn,
889 			      unsigned int *data)
890 {
891 	if (comedi_dio_update_state(s, data))
892 		outb(s->state, dev->iobase + DAS16_DIO_REG);
893 
894 	data[1] = s->state;
895 
896 	return insn->n;
897 }
898 
das16_probe(struct comedi_device * dev,struct comedi_devconfig * it)899 static int das16_probe(struct comedi_device *dev, struct comedi_devconfig *it)
900 {
901 	const struct das16_board *board = dev->board_ptr;
902 	int diobits;
903 
904 	/* diobits indicates boards */
905 	diobits = inb(dev->iobase + DAS16_DIO_REG) & 0xf0;
906 	if (board->id != diobits) {
907 		dev_err(dev->class_dev,
908 			"requested board's id bits are incorrect (0x%x != 0x%x)\n",
909 			board->id, diobits);
910 		return -EINVAL;
911 	}
912 
913 	return 0;
914 }
915 
das16_reset(struct comedi_device * dev)916 static void das16_reset(struct comedi_device *dev)
917 {
918 	outb(0, dev->iobase + DAS16_STATUS_REG);
919 	outb(0, dev->iobase + DAS16_CTRL_REG);
920 	outb(0, dev->iobase + DAS16_PACER_REG);
921 }
922 
das16_alloc_dma(struct comedi_device * dev,unsigned int dma_chan)923 static void das16_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
924 {
925 	struct das16_private_struct *devpriv = dev->private;
926 
927 	timer_setup(&devpriv->timer, das16_timer_interrupt, 0);
928 
929 	/* only DMA channels 3 and 1 are valid */
930 	if (!(dma_chan == 1 || dma_chan == 3))
931 		return;
932 
933 	/* DMA uses two buffers */
934 	devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
935 					   DAS16_DMA_SIZE, COMEDI_ISADMA_READ);
936 }
937 
das16_free_dma(struct comedi_device * dev)938 static void das16_free_dma(struct comedi_device *dev)
939 {
940 	struct das16_private_struct *devpriv = dev->private;
941 
942 	if (devpriv) {
943 		del_timer_sync(&devpriv->timer);
944 		comedi_isadma_free(devpriv->dma);
945 	}
946 }
947 
das16_ai_range(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_devconfig * it,unsigned int pg_type,unsigned int status)948 static const struct comedi_lrange *das16_ai_range(struct comedi_device *dev,
949 						  struct comedi_subdevice *s,
950 						  struct comedi_devconfig *it,
951 						  unsigned int pg_type,
952 						  unsigned int status)
953 {
954 	unsigned int min = it->options[4];
955 	unsigned int max = it->options[5];
956 
957 	/* get any user-defined input range */
958 	if (pg_type == das16_pg_none && (min || max)) {
959 		struct comedi_lrange *lrange;
960 		struct comedi_krange *krange;
961 
962 		/* allocate single-range range table */
963 		lrange = comedi_alloc_spriv(s,
964 					    struct_size(lrange, range, 1));
965 		if (!lrange)
966 			return &range_unknown;
967 
968 		/* initialize ai range */
969 		lrange->length = 1;
970 		krange = lrange->range;
971 		krange->min = min;
972 		krange->max = max;
973 		krange->flags = UNIT_volt;
974 
975 		return lrange;
976 	}
977 
978 	/* use software programmable range */
979 	if (status & DAS16_STATUS_UNIPOLAR)
980 		return das16_ai_uni_lranges[pg_type];
981 	return das16_ai_bip_lranges[pg_type];
982 }
983 
das16_ao_range(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_devconfig * it)984 static const struct comedi_lrange *das16_ao_range(struct comedi_device *dev,
985 						  struct comedi_subdevice *s,
986 						  struct comedi_devconfig *it)
987 {
988 	unsigned int min = it->options[6];
989 	unsigned int max = it->options[7];
990 
991 	/* get any user-defined output range */
992 	if (min || max) {
993 		struct comedi_lrange *lrange;
994 		struct comedi_krange *krange;
995 
996 		/* allocate single-range range table */
997 		lrange = comedi_alloc_spriv(s,
998 					    struct_size(lrange, range, 1));
999 		if (!lrange)
1000 			return &range_unknown;
1001 
1002 		/* initialize ao range */
1003 		lrange->length = 1;
1004 		krange = lrange->range;
1005 		krange->min = min;
1006 		krange->max = max;
1007 		krange->flags = UNIT_volt;
1008 
1009 		return lrange;
1010 	}
1011 
1012 	return &range_unknown;
1013 }
1014 
das16_attach(struct comedi_device * dev,struct comedi_devconfig * it)1015 static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1016 {
1017 	const struct das16_board *board = dev->board_ptr;
1018 	struct das16_private_struct *devpriv;
1019 	struct comedi_subdevice *s;
1020 	unsigned int osc_base;
1021 	unsigned int status;
1022 	int ret;
1023 
1024 	/*  check that clock setting is valid */
1025 	if (it->options[3]) {
1026 		if (it->options[3] != 1 && it->options[3] != 10) {
1027 			dev_err(dev->class_dev,
1028 				"Invalid option. Master clock must be set to 1 or 10 (MHz)\n");
1029 			return -EINVAL;
1030 		}
1031 	}
1032 
1033 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1034 	if (!devpriv)
1035 		return -ENOMEM;
1036 	devpriv->dev = dev;
1037 
1038 	if (board->size < 0x400) {
1039 		ret = comedi_request_region(dev, it->options[0], board->size);
1040 		if (ret)
1041 			return ret;
1042 	} else {
1043 		ret = comedi_request_region(dev, it->options[0], 0x10);
1044 		if (ret)
1045 			return ret;
1046 		/* Request an additional region for the 8255 */
1047 		ret = __comedi_request_region(dev, dev->iobase + 0x400,
1048 					      board->size & 0x3ff);
1049 		if (ret)
1050 			return ret;
1051 		devpriv->extra_iobase = dev->iobase + 0x400;
1052 		devpriv->can_burst = 1;
1053 	}
1054 
1055 	/*  probe id bits to make sure they are consistent */
1056 	if (das16_probe(dev, it))
1057 		return -EINVAL;
1058 
1059 	/*  get master clock speed */
1060 	osc_base = I8254_OSC_BASE_1MHZ;
1061 	if (devpriv->can_burst) {
1062 		status = inb(dev->iobase + DAS1600_STATUS_REG);
1063 		if (status & DAS1600_STATUS_CLK_10MHZ)
1064 			osc_base = I8254_OSC_BASE_10MHZ;
1065 	} else {
1066 		if (it->options[3])
1067 			osc_base = I8254_OSC_BASE_1MHZ / it->options[3];
1068 	}
1069 
1070 	dev->pacer = comedi_8254_init(dev->iobase + DAS16_TIMER_BASE_REG,
1071 				      osc_base, I8254_IO8, 0);
1072 	if (!dev->pacer)
1073 		return -ENOMEM;
1074 
1075 	das16_alloc_dma(dev, it->options[2]);
1076 
1077 	ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
1078 	if (ret)
1079 		return ret;
1080 
1081 	status = inb(dev->iobase + DAS16_STATUS_REG);
1082 
1083 	/* Analog Input subdevice */
1084 	s = &dev->subdevices[0];
1085 	s->type		= COMEDI_SUBD_AI;
1086 	s->subdev_flags	= SDF_READABLE;
1087 	if (status & DAS16_STATUS_MUXBIT) {
1088 		s->subdev_flags	|= SDF_GROUND;
1089 		s->n_chan	= 16;
1090 	} else {
1091 		s->subdev_flags	|= SDF_DIFF;
1092 		s->n_chan	= 8;
1093 	}
1094 	s->len_chanlist	= s->n_chan;
1095 	s->maxdata	= board->ai_maxdata;
1096 	s->range_table	= das16_ai_range(dev, s, it, board->ai_pg, status);
1097 	s->insn_read	= das16_ai_insn_read;
1098 	if (devpriv->dma) {
1099 		dev->read_subdev = s;
1100 		s->subdev_flags	|= SDF_CMD_READ;
1101 		s->do_cmdtest	= das16_cmd_test;
1102 		s->do_cmd	= das16_cmd_exec;
1103 		s->cancel	= das16_cancel;
1104 		s->munge	= das16_ai_munge;
1105 	}
1106 
1107 	/* Analog Output subdevice */
1108 	s = &dev->subdevices[1];
1109 	if (board->has_ao) {
1110 		s->type		= COMEDI_SUBD_AO;
1111 		s->subdev_flags	= SDF_WRITABLE;
1112 		s->n_chan	= 2;
1113 		s->maxdata	= 0x0fff;
1114 		s->range_table	= das16_ao_range(dev, s, it);
1115 		s->insn_write	= das16_ao_insn_write;
1116 
1117 		ret = comedi_alloc_subdev_readback(s);
1118 		if (ret)
1119 			return ret;
1120 	} else {
1121 		s->type		= COMEDI_SUBD_UNUSED;
1122 	}
1123 
1124 	/* Digital Input subdevice */
1125 	s = &dev->subdevices[2];
1126 	s->type		= COMEDI_SUBD_DI;
1127 	s->subdev_flags	= SDF_READABLE;
1128 	s->n_chan	= 4;
1129 	s->maxdata	= 1;
1130 	s->range_table	= &range_digital;
1131 	s->insn_bits	= das16_di_insn_bits;
1132 
1133 	/* Digital Output subdevice */
1134 	s = &dev->subdevices[3];
1135 	s->type		= COMEDI_SUBD_DO;
1136 	s->subdev_flags	= SDF_WRITABLE;
1137 	s->n_chan	= 4;
1138 	s->maxdata	= 1;
1139 	s->range_table	= &range_digital;
1140 	s->insn_bits	= das16_do_insn_bits;
1141 
1142 	/* initialize digital output lines */
1143 	outb(s->state, dev->iobase + DAS16_DIO_REG);
1144 
1145 	/* 8255 Digital I/O subdevice */
1146 	if (board->has_8255) {
1147 		s = &dev->subdevices[4];
1148 		ret = subdev_8255_init(dev, s, NULL, board->i8255_offset);
1149 		if (ret)
1150 			return ret;
1151 	}
1152 
1153 	das16_reset(dev);
1154 	/* set the interrupt level */
1155 	devpriv->ctrl_reg = DAS16_CTRL_IRQ(dev->irq);
1156 	outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
1157 
1158 	if (devpriv->can_burst) {
1159 		outb(DAS1600_ENABLE_VAL, dev->iobase + DAS1600_ENABLE_REG);
1160 		outb(0, dev->iobase + DAS1600_CONV_REG);
1161 		outb(0, dev->iobase + DAS1600_BURST_REG);
1162 	}
1163 
1164 	return 0;
1165 }
1166 
das16_detach(struct comedi_device * dev)1167 static void das16_detach(struct comedi_device *dev)
1168 {
1169 	const struct das16_board *board = dev->board_ptr;
1170 	struct das16_private_struct *devpriv = dev->private;
1171 
1172 	if (devpriv) {
1173 		if (dev->iobase)
1174 			das16_reset(dev);
1175 		das16_free_dma(dev);
1176 
1177 		if (devpriv->extra_iobase)
1178 			release_region(devpriv->extra_iobase,
1179 				       board->size & 0x3ff);
1180 	}
1181 
1182 	comedi_legacy_detach(dev);
1183 }
1184 
1185 static struct comedi_driver das16_driver = {
1186 	.driver_name	= "das16",
1187 	.module		= THIS_MODULE,
1188 	.attach		= das16_attach,
1189 	.detach		= das16_detach,
1190 	.board_name	= &das16_boards[0].name,
1191 	.num_names	= ARRAY_SIZE(das16_boards),
1192 	.offset		= sizeof(das16_boards[0]),
1193 };
1194 module_comedi_driver(das16_driver);
1195 
1196 MODULE_AUTHOR("Comedi https://www.comedi.org");
1197 MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards");
1198 MODULE_LICENSE("GPL");
1199