1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * dt282x.c
4  * Comedi driver for Data Translation DT2821 series
5  *
6  * COMEDI - Linux Control and Measurement Device Interface
7  * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
8  */
9 
10 /*
11  * Driver: dt282x
12  * Description: Data Translation DT2821 series (including DT-EZ)
13  * Author: ds
14  * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
15  *   DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
16  *   DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
17  *   DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
18  *   DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
19  *   DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
20  * Status: complete
21  * Updated: Wed, 22 Aug 2001 17:11:34 -0700
22  *
23  * Configuration options:
24  *   [0] - I/O port base address
25  *   [1] - IRQ (optional, required for async command support)
26  *   [2] - DMA 1 (optional, required for async command support)
27  *   [3] - DMA 2 (optional, required for async command support)
28  *   [4] - AI jumpered for 0=single ended, 1=differential
29  *   [5] - AI jumpered for 0=straight binary, 1=2's complement
30  *   [6] - AO 0 data format (deprecated, see below)
31  *   [7] - AO 1 data format (deprecated, see below)
32  *   [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
33  *   [9] - AO channel 0 range (deprecated, see below)
34  *   [10]- AO channel 1 range (deprecated, see below)
35  *
36  * Notes:
37  *   - AO commands might be broken.
38  *   - If you try to run a command on both the AI and AO subdevices
39  *     simultaneously, bad things will happen.  The driver needs to
40  *     be fixed to check for this situation and return an error.
41  *   - AO range is not programmable. The AO subdevice has a range_table
42  *     containing all the possible analog output ranges. Use the range
43  *     that matches your board configuration to convert between data
44  *     values and physical units. The format of the data written to the
45  *     board is handled automatically based on the unipolar/bipolar
46  *     range that is selected.
47  */
48 
49 #include <linux/module.h>
50 #include <linux/delay.h>
51 #include <linux/gfp.h>
52 #include <linux/interrupt.h>
53 #include <linux/io.h>
54 
55 #include "../comedidev.h"
56 
57 #include "comedi_isadma.h"
58 
59 /*
60  * Register map
61  */
62 #define DT2821_ADCSR_REG		0x00
63 #define DT2821_ADCSR_ADERR		BIT(15)
64 #define DT2821_ADCSR_ADCLK		BIT(9)
65 #define DT2821_ADCSR_MUXBUSY		BIT(8)
66 #define DT2821_ADCSR_ADDONE		BIT(7)
67 #define DT2821_ADCSR_IADDONE		BIT(6)
68 #define DT2821_ADCSR_GS(x)		(((x) & 0x3) << 4)
69 #define DT2821_ADCSR_CHAN(x)		(((x) & 0xf) << 0)
70 #define DT2821_CHANCSR_REG		0x02
71 #define DT2821_CHANCSR_LLE		BIT(15)
72 #define DT2821_CHANCSR_TO_PRESLA(x)	(((x) >> 8) & 0xf)
73 #define DT2821_CHANCSR_NUMB(x)		((((x) - 1) & 0xf) << 0)
74 #define DT2821_ADDAT_REG		0x04
75 #define DT2821_DACSR_REG		0x06
76 #define DT2821_DACSR_DAERR		BIT(15)
77 #define DT2821_DACSR_YSEL(x)		((x) << 9)
78 #define DT2821_DACSR_SSEL		BIT(8)
79 #define DT2821_DACSR_DACRDY		BIT(7)
80 #define DT2821_DACSR_IDARDY		BIT(6)
81 #define DT2821_DACSR_DACLK		BIT(5)
82 #define DT2821_DACSR_HBOE		BIT(1)
83 #define DT2821_DACSR_LBOE		BIT(0)
84 #define DT2821_DADAT_REG		0x08
85 #define DT2821_DIODAT_REG		0x0a
86 #define DT2821_SUPCSR_REG		0x0c
87 #define DT2821_SUPCSR_DMAD		BIT(15)
88 #define DT2821_SUPCSR_ERRINTEN		BIT(14)
89 #define DT2821_SUPCSR_CLRDMADNE		BIT(13)
90 #define DT2821_SUPCSR_DDMA		BIT(12)
91 #define DT2821_SUPCSR_DS(x)		(((x) & 0x3) << 10)
92 #define DT2821_SUPCSR_DS_PIO		DT2821_SUPCSR_DS(0)
93 #define DT2821_SUPCSR_DS_AD_CLK		DT2821_SUPCSR_DS(1)
94 #define DT2821_SUPCSR_DS_DA_CLK		DT2821_SUPCSR_DS(2)
95 #define DT2821_SUPCSR_DS_AD_TRIG	DT2821_SUPCSR_DS(3)
96 #define DT2821_SUPCSR_BUFFB		BIT(9)
97 #define DT2821_SUPCSR_SCDN		BIT(8)
98 #define DT2821_SUPCSR_DACON		BIT(7)
99 #define DT2821_SUPCSR_ADCINIT		BIT(6)
100 #define DT2821_SUPCSR_DACINIT		BIT(5)
101 #define DT2821_SUPCSR_PRLD		BIT(4)
102 #define DT2821_SUPCSR_STRIG		BIT(3)
103 #define DT2821_SUPCSR_XTRIG		BIT(2)
104 #define DT2821_SUPCSR_XCLK		BIT(1)
105 #define DT2821_SUPCSR_BDINIT		BIT(0)
106 #define DT2821_TMRCTR_REG		0x0e
107 #define DT2821_TMRCTR_PRESCALE(x)	(((x) & 0xf) << 8)
108 #define DT2821_TMRCTR_DIVIDER(x)	((255 - ((x) & 0xff)) << 0)
109 
110 /* Pacer Clock */
111 #define DT2821_OSC_BASE		250	/* 4 MHz (in nanoseconds) */
112 #define DT2821_PRESCALE(x)	BIT(x)
113 #define DT2821_PRESCALE_MAX	15
114 #define DT2821_DIVIDER_MAX	255
115 #define DT2821_OSC_MAX		(DT2821_OSC_BASE *			\
116 				 DT2821_PRESCALE(DT2821_PRESCALE_MAX) *	\
117 				 DT2821_DIVIDER_MAX)
118 
119 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
120 	4, {
121 		BIP_RANGE(10),
122 		BIP_RANGE(5),
123 		BIP_RANGE(2.5),
124 		BIP_RANGE(1.25)
125 	}
126 };
127 
128 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
129 	4, {
130 		UNI_RANGE(10),
131 		UNI_RANGE(5),
132 		UNI_RANGE(2.5),
133 		UNI_RANGE(1.25)
134 	}
135 };
136 
137 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
138 	4, {
139 		BIP_RANGE(5),
140 		BIP_RANGE(2.5),
141 		BIP_RANGE(1.25),
142 		BIP_RANGE(0.625)
143 	}
144 };
145 
146 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
147 	4, {
148 		UNI_RANGE(5),
149 		UNI_RANGE(2.5),
150 		UNI_RANGE(1.25),
151 		UNI_RANGE(0.625)
152 	}
153 };
154 
155 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
156 	4, {
157 		BIP_RANGE(10),
158 		BIP_RANGE(1),
159 		BIP_RANGE(0.1),
160 		BIP_RANGE(0.02)
161 	}
162 };
163 
164 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
165 	4, {
166 		UNI_RANGE(10),
167 		UNI_RANGE(1),
168 		UNI_RANGE(0.1),
169 		UNI_RANGE(0.02)
170 	}
171 };
172 
173 /*
174  * The Analog Output range is set per-channel using jumpers on the board.
175  * All of these ranges may not be available on some DT2821 series boards.
176  * The default jumper setting has both channels set for +/-10V output.
177  */
178 static const struct comedi_lrange dt282x_ao_range = {
179 	5, {
180 		BIP_RANGE(10),
181 		BIP_RANGE(5),
182 		BIP_RANGE(2.5),
183 		UNI_RANGE(10),
184 		UNI_RANGE(5),
185 	}
186 };
187 
188 struct dt282x_board {
189 	const char *name;
190 	unsigned int ai_maxdata;
191 	int adchan_se;
192 	int adchan_di;
193 	int ai_speed;
194 	int ispgl;
195 	int dachan;
196 	unsigned int ao_maxdata;
197 };
198 
199 static const struct dt282x_board boardtypes[] = {
200 	{
201 		.name		= "dt2821",
202 		.ai_maxdata	= 0x0fff,
203 		.adchan_se	= 16,
204 		.adchan_di	= 8,
205 		.ai_speed	= 20000,
206 		.dachan		= 2,
207 		.ao_maxdata	= 0x0fff,
208 	}, {
209 		.name		= "dt2821-f",
210 		.ai_maxdata	= 0x0fff,
211 		.adchan_se	= 16,
212 		.adchan_di	= 8,
213 		.ai_speed	= 6500,
214 		.dachan		= 2,
215 		.ao_maxdata	= 0x0fff,
216 	}, {
217 		.name		= "dt2821-g",
218 		.ai_maxdata	= 0x0fff,
219 		.adchan_se	= 16,
220 		.adchan_di	= 8,
221 		.ai_speed	= 4000,
222 		.dachan		= 2,
223 		.ao_maxdata	= 0x0fff,
224 	}, {
225 		.name		= "dt2823",
226 		.ai_maxdata	= 0xffff,
227 		.adchan_di	= 4,
228 		.ai_speed	= 10000,
229 		.dachan		= 2,
230 		.ao_maxdata	= 0xffff,
231 	}, {
232 		.name		= "dt2824-pgh",
233 		.ai_maxdata	= 0x0fff,
234 		.adchan_se	= 16,
235 		.adchan_di	= 8,
236 		.ai_speed	= 20000,
237 	}, {
238 		.name		= "dt2824-pgl",
239 		.ai_maxdata	= 0x0fff,
240 		.adchan_se	= 16,
241 		.adchan_di	= 8,
242 		.ai_speed	= 20000,
243 		.ispgl		= 1,
244 	}, {
245 		.name		= "dt2825",
246 		.ai_maxdata	= 0x0fff,
247 		.adchan_se	= 16,
248 		.adchan_di	= 8,
249 		.ai_speed	= 20000,
250 		.ispgl		= 1,
251 		.dachan		= 2,
252 		.ao_maxdata	= 0x0fff,
253 	}, {
254 		.name		= "dt2827",
255 		.ai_maxdata	= 0xffff,
256 		.adchan_di	= 4,
257 		.ai_speed	= 10000,
258 		.dachan		= 2,
259 		.ao_maxdata	= 0x0fff,
260 	}, {
261 		.name		= "dt2828",
262 		.ai_maxdata	= 0x0fff,
263 		.adchan_se	= 4,
264 		.ai_speed	= 10000,
265 		.dachan		= 2,
266 		.ao_maxdata	= 0x0fff,
267 	}, {
268 		.name		= "dt2829",
269 		.ai_maxdata	= 0xffff,
270 		.adchan_se	= 8,
271 		.ai_speed	= 33250,
272 		.dachan		= 2,
273 		.ao_maxdata	= 0xffff,
274 	}, {
275 		.name		= "dt21-ez",
276 		.ai_maxdata	= 0x0fff,
277 		.adchan_se	= 16,
278 		.adchan_di	= 8,
279 		.ai_speed	= 10000,
280 		.dachan		= 2,
281 		.ao_maxdata	= 0x0fff,
282 	}, {
283 		.name		= "dt23-ez",
284 		.ai_maxdata	= 0xffff,
285 		.adchan_se	= 16,
286 		.adchan_di	= 8,
287 		.ai_speed	= 10000,
288 	}, {
289 		.name		= "dt24-ez",
290 		.ai_maxdata	= 0x0fff,
291 		.adchan_se	= 16,
292 		.adchan_di	= 8,
293 		.ai_speed	= 10000,
294 	}, {
295 		.name		= "dt24-ez-pgl",
296 		.ai_maxdata	= 0x0fff,
297 		.adchan_se	= 16,
298 		.adchan_di	= 8,
299 		.ai_speed	= 10000,
300 		.ispgl		= 1,
301 	},
302 };
303 
304 struct dt282x_private {
305 	struct comedi_isadma *dma;
306 	unsigned int ad_2scomp:1;
307 	unsigned int divisor;
308 	int dacsr;	/* software copies of registers */
309 	int adcsr;
310 	int supcsr;
311 	int ntrig;
312 	int nread;
313 	int dma_dir;
314 };
315 
dt282x_prep_ai_dma(struct comedi_device * dev,int dma_index,int n)316 static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
317 {
318 	struct dt282x_private *devpriv = dev->private;
319 	struct comedi_isadma *dma = devpriv->dma;
320 	struct comedi_isadma_desc *desc = &dma->desc[dma_index];
321 
322 	if (!devpriv->ntrig)
323 		return 0;
324 
325 	if (n == 0)
326 		n = desc->maxsize;
327 	if (n > devpriv->ntrig * 2)
328 		n = devpriv->ntrig * 2;
329 	devpriv->ntrig -= n / 2;
330 
331 	desc->size = n;
332 	comedi_isadma_set_mode(desc, devpriv->dma_dir);
333 
334 	comedi_isadma_program(desc);
335 
336 	return n;
337 }
338 
dt282x_prep_ao_dma(struct comedi_device * dev,int dma_index,int n)339 static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
340 {
341 	struct dt282x_private *devpriv = dev->private;
342 	struct comedi_isadma *dma = devpriv->dma;
343 	struct comedi_isadma_desc *desc = &dma->desc[dma_index];
344 
345 	desc->size = n;
346 	comedi_isadma_set_mode(desc, devpriv->dma_dir);
347 
348 	comedi_isadma_program(desc);
349 
350 	return n;
351 }
352 
dt282x_disable_dma(struct comedi_device * dev)353 static void dt282x_disable_dma(struct comedi_device *dev)
354 {
355 	struct dt282x_private *devpriv = dev->private;
356 	struct comedi_isadma *dma = devpriv->dma;
357 	struct comedi_isadma_desc *desc;
358 	int i;
359 
360 	for (i = 0; i < 2; i++) {
361 		desc = &dma->desc[i];
362 		comedi_isadma_disable(desc->chan);
363 	}
364 }
365 
dt282x_ns_to_timer(unsigned int * ns,unsigned int flags)366 static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
367 {
368 	unsigned int prescale, base, divider;
369 
370 	for (prescale = 0; prescale <= DT2821_PRESCALE_MAX; prescale++) {
371 		if (prescale == 1)	/* 0 and 1 are both divide by 1 */
372 			continue;
373 		base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
374 		switch (flags & CMDF_ROUND_MASK) {
375 		case CMDF_ROUND_NEAREST:
376 		default:
377 			divider = DIV_ROUND_CLOSEST(*ns, base);
378 			break;
379 		case CMDF_ROUND_DOWN:
380 			divider = (*ns) / base;
381 			break;
382 		case CMDF_ROUND_UP:
383 			divider = DIV_ROUND_UP(*ns, base);
384 			break;
385 		}
386 		if (divider <= DT2821_DIVIDER_MAX)
387 			break;
388 	}
389 	if (divider > DT2821_DIVIDER_MAX) {
390 		prescale = DT2821_PRESCALE_MAX;
391 		divider = DT2821_DIVIDER_MAX;
392 		base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
393 	}
394 	*ns = divider * base;
395 	return DT2821_TMRCTR_PRESCALE(prescale) |
396 	       DT2821_TMRCTR_DIVIDER(divider);
397 }
398 
dt282x_munge(struct comedi_device * dev,struct comedi_subdevice * s,unsigned short * buf,unsigned int nbytes)399 static void dt282x_munge(struct comedi_device *dev,
400 			 struct comedi_subdevice *s,
401 			 unsigned short *buf,
402 			 unsigned int nbytes)
403 {
404 	struct dt282x_private *devpriv = dev->private;
405 	unsigned int val;
406 	int i;
407 
408 	if (nbytes % 2)
409 		dev_err(dev->class_dev,
410 			"bug! odd number of bytes from dma xfer\n");
411 
412 	for (i = 0; i < nbytes / 2; i++) {
413 		val = buf[i];
414 		val &= s->maxdata;
415 		if (devpriv->ad_2scomp)
416 			val = comedi_offset_munge(s, val);
417 
418 		buf[i] = val;
419 	}
420 }
421 
dt282x_ao_setup_dma(struct comedi_device * dev,struct comedi_subdevice * s,int cur_dma)422 static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
423 					struct comedi_subdevice *s,
424 					int cur_dma)
425 {
426 	struct dt282x_private *devpriv = dev->private;
427 	struct comedi_isadma *dma = devpriv->dma;
428 	struct comedi_isadma_desc *desc = &dma->desc[cur_dma];
429 	unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize);
430 	unsigned int nbytes;
431 
432 	nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples);
433 	if (nbytes)
434 		dt282x_prep_ao_dma(dev, cur_dma, nbytes);
435 	else
436 		dev_err(dev->class_dev, "AO underrun\n");
437 
438 	return nbytes;
439 }
440 
dt282x_ao_dma_interrupt(struct comedi_device * dev,struct comedi_subdevice * s)441 static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
442 				    struct comedi_subdevice *s)
443 {
444 	struct dt282x_private *devpriv = dev->private;
445 	struct comedi_isadma *dma = devpriv->dma;
446 	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
447 
448 	outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
449 	     dev->iobase + DT2821_SUPCSR_REG);
450 
451 	comedi_isadma_disable(desc->chan);
452 
453 	if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma))
454 		s->async->events |= COMEDI_CB_OVERFLOW;
455 
456 	dma->cur_dma = 1 - dma->cur_dma;
457 }
458 
dt282x_ai_dma_interrupt(struct comedi_device * dev,struct comedi_subdevice * s)459 static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
460 				    struct comedi_subdevice *s)
461 {
462 	struct dt282x_private *devpriv = dev->private;
463 	struct comedi_isadma *dma = devpriv->dma;
464 	struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
465 	unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
466 	int ret;
467 
468 	outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
469 	     dev->iobase + DT2821_SUPCSR_REG);
470 
471 	comedi_isadma_disable(desc->chan);
472 
473 	dt282x_munge(dev, s, desc->virt_addr, desc->size);
474 	ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples);
475 	if (ret != desc->size)
476 		return;
477 
478 	devpriv->nread -= nsamples;
479 	if (devpriv->nread < 0) {
480 		dev_info(dev->class_dev, "nread off by one\n");
481 		devpriv->nread = 0;
482 	}
483 	if (!devpriv->nread) {
484 		s->async->events |= COMEDI_CB_EOA;
485 		return;
486 	}
487 
488 	/* restart the channel */
489 	dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
490 
491 	dma->cur_dma = 1 - dma->cur_dma;
492 }
493 
dt282x_interrupt(int irq,void * d)494 static irqreturn_t dt282x_interrupt(int irq, void *d)
495 {
496 	struct comedi_device *dev = d;
497 	struct dt282x_private *devpriv = dev->private;
498 	struct comedi_subdevice *s = dev->read_subdev;
499 	struct comedi_subdevice *s_ao = dev->write_subdev;
500 	unsigned int supcsr, adcsr, dacsr;
501 	int handled = 0;
502 
503 	if (!dev->attached) {
504 		dev_err(dev->class_dev, "spurious interrupt\n");
505 		return IRQ_HANDLED;
506 	}
507 
508 	adcsr = inw(dev->iobase + DT2821_ADCSR_REG);
509 	dacsr = inw(dev->iobase + DT2821_DACSR_REG);
510 	supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
511 	if (supcsr & DT2821_SUPCSR_DMAD) {
512 		if (devpriv->dma_dir == COMEDI_ISADMA_READ)
513 			dt282x_ai_dma_interrupt(dev, s);
514 		else
515 			dt282x_ao_dma_interrupt(dev, s_ao);
516 		handled = 1;
517 	}
518 	if (adcsr & DT2821_ADCSR_ADERR) {
519 		if (devpriv->nread != 0) {
520 			dev_err(dev->class_dev, "A/D error\n");
521 			s->async->events |= COMEDI_CB_ERROR;
522 		}
523 		handled = 1;
524 	}
525 	if (dacsr & DT2821_DACSR_DAERR) {
526 		dev_err(dev->class_dev, "D/A error\n");
527 		s_ao->async->events |= COMEDI_CB_ERROR;
528 		handled = 1;
529 	}
530 
531 	comedi_handle_events(dev, s);
532 	if (s_ao)
533 		comedi_handle_events(dev, s_ao);
534 
535 	return IRQ_RETVAL(handled);
536 }
537 
dt282x_load_changain(struct comedi_device * dev,int n,unsigned int * chanlist)538 static void dt282x_load_changain(struct comedi_device *dev, int n,
539 				 unsigned int *chanlist)
540 {
541 	struct dt282x_private *devpriv = dev->private;
542 	int i;
543 
544 	outw(DT2821_CHANCSR_LLE | DT2821_CHANCSR_NUMB(n),
545 	     dev->iobase + DT2821_CHANCSR_REG);
546 	for (i = 0; i < n; i++) {
547 		unsigned int chan = CR_CHAN(chanlist[i]);
548 		unsigned int range = CR_RANGE(chanlist[i]);
549 
550 		outw(devpriv->adcsr |
551 		     DT2821_ADCSR_GS(range) |
552 		     DT2821_ADCSR_CHAN(chan),
553 		     dev->iobase + DT2821_ADCSR_REG);
554 	}
555 	outw(DT2821_CHANCSR_NUMB(n), dev->iobase + DT2821_CHANCSR_REG);
556 }
557 
dt282x_ai_timeout(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)558 static int dt282x_ai_timeout(struct comedi_device *dev,
559 			     struct comedi_subdevice *s,
560 			     struct comedi_insn *insn,
561 			     unsigned long context)
562 {
563 	unsigned int status;
564 
565 	status = inw(dev->iobase + DT2821_ADCSR_REG);
566 	switch (context) {
567 	case DT2821_ADCSR_MUXBUSY:
568 		if ((status & DT2821_ADCSR_MUXBUSY) == 0)
569 			return 0;
570 		break;
571 	case DT2821_ADCSR_ADDONE:
572 		if (status & DT2821_ADCSR_ADDONE)
573 			return 0;
574 		break;
575 	default:
576 		return -EINVAL;
577 	}
578 	return -EBUSY;
579 }
580 
581 /*
582  *    Performs a single A/D conversion.
583  *      - Put channel/gain into channel-gain list
584  *      - preload multiplexer
585  *      - trigger conversion and wait for it to finish
586  */
dt282x_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)587 static int dt282x_ai_insn_read(struct comedi_device *dev,
588 			       struct comedi_subdevice *s,
589 			       struct comedi_insn *insn,
590 			       unsigned int *data)
591 {
592 	struct dt282x_private *devpriv = dev->private;
593 	unsigned int val;
594 	int ret;
595 	int i;
596 
597 	/* XXX should we really be enabling the ad clock here? */
598 	devpriv->adcsr = DT2821_ADCSR_ADCLK;
599 	outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
600 
601 	dt282x_load_changain(dev, 1, &insn->chanspec);
602 
603 	outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
604 	     dev->iobase + DT2821_SUPCSR_REG);
605 	ret = comedi_timeout(dev, s, insn,
606 			     dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
607 	if (ret)
608 		return ret;
609 
610 	for (i = 0; i < insn->n; i++) {
611 		outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
612 		     dev->iobase + DT2821_SUPCSR_REG);
613 
614 		ret = comedi_timeout(dev, s, insn,
615 				     dt282x_ai_timeout, DT2821_ADCSR_ADDONE);
616 		if (ret)
617 			return ret;
618 
619 		val = inw(dev->iobase + DT2821_ADDAT_REG);
620 		val &= s->maxdata;
621 		if (devpriv->ad_2scomp)
622 			val = comedi_offset_munge(s, val);
623 
624 		data[i] = val;
625 	}
626 
627 	return i;
628 }
629 
dt282x_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)630 static int dt282x_ai_cmdtest(struct comedi_device *dev,
631 			     struct comedi_subdevice *s,
632 			     struct comedi_cmd *cmd)
633 {
634 	const struct dt282x_board *board = dev->board_ptr;
635 	struct dt282x_private *devpriv = dev->private;
636 	int err = 0;
637 	unsigned int arg;
638 
639 	/* Step 1 : check if triggers are trivially valid */
640 
641 	err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
642 	err |= comedi_check_trigger_src(&cmd->scan_begin_src,
643 					TRIG_FOLLOW | TRIG_EXT);
644 	err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
645 	err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
646 	err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
647 
648 	if (err)
649 		return 1;
650 
651 	/* Step 2a : make sure trigger sources are unique */
652 
653 	err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
654 	err |= comedi_check_trigger_is_unique(cmd->stop_src);
655 
656 	/* Step 2b : and mutually compatible */
657 
658 	if (err)
659 		return 2;
660 
661 	/* Step 3: check if arguments are trivially valid */
662 
663 	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
664 	err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
665 	err |= comedi_check_trigger_arg_max(&cmd->convert_arg, DT2821_OSC_MAX);
666 	err |= comedi_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
667 	err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
668 					   cmd->chanlist_len);
669 
670 	if (cmd->stop_src == TRIG_COUNT)
671 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
672 	else	/* TRIG_EXT | TRIG_NONE */
673 		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
674 
675 	if (err)
676 		return 3;
677 
678 	/* step 4: fix up any arguments */
679 
680 	arg = cmd->convert_arg;
681 	devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
682 	err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
683 
684 	if (err)
685 		return 4;
686 
687 	return 0;
688 }
689 
dt282x_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)690 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
691 {
692 	struct dt282x_private *devpriv = dev->private;
693 	struct comedi_isadma *dma = devpriv->dma;
694 	struct comedi_cmd *cmd = &s->async->cmd;
695 	int ret;
696 
697 	dt282x_disable_dma(dev);
698 
699 	outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
700 
701 	devpriv->supcsr = DT2821_SUPCSR_ERRINTEN;
702 	if (cmd->scan_begin_src == TRIG_FOLLOW)
703 		devpriv->supcsr = DT2821_SUPCSR_DS_AD_CLK;
704 	else
705 		devpriv->supcsr = DT2821_SUPCSR_DS_AD_TRIG;
706 	outw(devpriv->supcsr |
707 	     DT2821_SUPCSR_CLRDMADNE |
708 	     DT2821_SUPCSR_BUFFB |
709 	     DT2821_SUPCSR_ADCINIT,
710 	     dev->iobase + DT2821_SUPCSR_REG);
711 
712 	devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
713 	devpriv->nread = devpriv->ntrig;
714 
715 	devpriv->dma_dir = COMEDI_ISADMA_READ;
716 	dma->cur_dma = 0;
717 	dt282x_prep_ai_dma(dev, 0, 0);
718 	if (devpriv->ntrig) {
719 		dt282x_prep_ai_dma(dev, 1, 0);
720 		devpriv->supcsr |= DT2821_SUPCSR_DDMA;
721 		outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
722 	}
723 
724 	devpriv->adcsr = 0;
725 
726 	dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
727 
728 	devpriv->adcsr = DT2821_ADCSR_ADCLK | DT2821_ADCSR_IADDONE;
729 	outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
730 
731 	outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
732 	     dev->iobase + DT2821_SUPCSR_REG);
733 	ret = comedi_timeout(dev, s, NULL,
734 			     dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
735 	if (ret)
736 		return ret;
737 
738 	if (cmd->scan_begin_src == TRIG_FOLLOW) {
739 		outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
740 		     dev->iobase + DT2821_SUPCSR_REG);
741 	} else {
742 		devpriv->supcsr |= DT2821_SUPCSR_XTRIG;
743 		outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
744 	}
745 
746 	return 0;
747 }
748 
dt282x_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)749 static int dt282x_ai_cancel(struct comedi_device *dev,
750 			    struct comedi_subdevice *s)
751 {
752 	struct dt282x_private *devpriv = dev->private;
753 
754 	dt282x_disable_dma(dev);
755 
756 	devpriv->adcsr = 0;
757 	outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
758 
759 	devpriv->supcsr = 0;
760 	outw(devpriv->supcsr | DT2821_SUPCSR_ADCINIT,
761 	     dev->iobase + DT2821_SUPCSR_REG);
762 
763 	return 0;
764 }
765 
dt282x_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)766 static int dt282x_ao_insn_write(struct comedi_device *dev,
767 				struct comedi_subdevice *s,
768 				struct comedi_insn *insn,
769 				unsigned int *data)
770 {
771 	struct dt282x_private *devpriv = dev->private;
772 	unsigned int chan = CR_CHAN(insn->chanspec);
773 	unsigned int range = CR_RANGE(insn->chanspec);
774 	int i;
775 
776 	devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
777 
778 	for (i = 0; i < insn->n; i++) {
779 		unsigned int val = data[i];
780 
781 		s->readback[chan] = val;
782 
783 		if (comedi_range_is_bipolar(s, range))
784 			val = comedi_offset_munge(s, val);
785 
786 		outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
787 
788 		outw(val, dev->iobase + DT2821_DADAT_REG);
789 
790 		outw(devpriv->supcsr | DT2821_SUPCSR_DACON,
791 		     dev->iobase + DT2821_SUPCSR_REG);
792 	}
793 
794 	return insn->n;
795 }
796 
dt282x_ao_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)797 static int dt282x_ao_cmdtest(struct comedi_device *dev,
798 			     struct comedi_subdevice *s,
799 			     struct comedi_cmd *cmd)
800 {
801 	struct dt282x_private *devpriv = dev->private;
802 	int err = 0;
803 	unsigned int arg;
804 
805 	/* Step 1 : check if triggers are trivially valid */
806 
807 	err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
808 	err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
809 	err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
810 	err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
811 	err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
812 
813 	if (err)
814 		return 1;
815 
816 	/* Step 2a : make sure trigger sources are unique */
817 
818 	err |= comedi_check_trigger_is_unique(cmd->stop_src);
819 
820 	/* Step 2b : and mutually compatible */
821 
822 	if (err)
823 		return 2;
824 
825 	/* Step 3: check if arguments are trivially valid */
826 
827 	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
828 	err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
829 	err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
830 	err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
831 					   cmd->chanlist_len);
832 
833 	if (cmd->stop_src == TRIG_COUNT)
834 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
835 	else	/* TRIG_EXT | TRIG_NONE */
836 		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
837 
838 	if (err)
839 		return 3;
840 
841 	/* step 4: fix up any arguments */
842 
843 	arg = cmd->scan_begin_arg;
844 	devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
845 	err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
846 
847 	if (err)
848 		return 4;
849 
850 	return 0;
851 }
852 
dt282x_ao_inttrig(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int trig_num)853 static int dt282x_ao_inttrig(struct comedi_device *dev,
854 			     struct comedi_subdevice *s,
855 			     unsigned int trig_num)
856 {
857 	struct dt282x_private *devpriv = dev->private;
858 	struct comedi_cmd *cmd = &s->async->cmd;
859 
860 	if (trig_num != cmd->start_src)
861 		return -EINVAL;
862 
863 	if (!dt282x_ao_setup_dma(dev, s, 0))
864 		return -EPIPE;
865 
866 	if (!dt282x_ao_setup_dma(dev, s, 1))
867 		return -EPIPE;
868 
869 	outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
870 	     dev->iobase + DT2821_SUPCSR_REG);
871 	s->async->inttrig = NULL;
872 
873 	return 1;
874 }
875 
dt282x_ao_cmd(struct comedi_device * dev,struct comedi_subdevice * s)876 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
877 {
878 	struct dt282x_private *devpriv = dev->private;
879 	struct comedi_isadma *dma = devpriv->dma;
880 	struct comedi_cmd *cmd = &s->async->cmd;
881 
882 	dt282x_disable_dma(dev);
883 
884 	devpriv->supcsr = DT2821_SUPCSR_ERRINTEN |
885 			  DT2821_SUPCSR_DS_DA_CLK |
886 			  DT2821_SUPCSR_DDMA;
887 	outw(devpriv->supcsr |
888 	     DT2821_SUPCSR_CLRDMADNE |
889 	     DT2821_SUPCSR_BUFFB |
890 	     DT2821_SUPCSR_DACINIT,
891 	     dev->iobase + DT2821_SUPCSR_REG);
892 
893 	devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
894 	devpriv->nread = devpriv->ntrig;
895 
896 	devpriv->dma_dir = COMEDI_ISADMA_WRITE;
897 	dma->cur_dma = 0;
898 
899 	outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
900 
901 	/* clear all bits but the DIO direction bits */
902 	devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
903 
904 	devpriv->dacsr |= (DT2821_DACSR_SSEL |
905 			   DT2821_DACSR_DACLK |
906 			   DT2821_DACSR_IDARDY);
907 	outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
908 
909 	s->async->inttrig = dt282x_ao_inttrig;
910 
911 	return 0;
912 }
913 
dt282x_ao_cancel(struct comedi_device * dev,struct comedi_subdevice * s)914 static int dt282x_ao_cancel(struct comedi_device *dev,
915 			    struct comedi_subdevice *s)
916 {
917 	struct dt282x_private *devpriv = dev->private;
918 
919 	dt282x_disable_dma(dev);
920 
921 	/* clear all bits but the DIO direction bits */
922 	devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
923 
924 	outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
925 
926 	devpriv->supcsr = 0;
927 	outw(devpriv->supcsr | DT2821_SUPCSR_DACINIT,
928 	     dev->iobase + DT2821_SUPCSR_REG);
929 
930 	return 0;
931 }
932 
dt282x_dio_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)933 static int dt282x_dio_insn_bits(struct comedi_device *dev,
934 				struct comedi_subdevice *s,
935 				struct comedi_insn *insn,
936 				unsigned int *data)
937 {
938 	if (comedi_dio_update_state(s, data))
939 		outw(s->state, dev->iobase + DT2821_DIODAT_REG);
940 
941 	data[1] = inw(dev->iobase + DT2821_DIODAT_REG);
942 
943 	return insn->n;
944 }
945 
dt282x_dio_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)946 static int dt282x_dio_insn_config(struct comedi_device *dev,
947 				  struct comedi_subdevice *s,
948 				  struct comedi_insn *insn,
949 				  unsigned int *data)
950 {
951 	struct dt282x_private *devpriv = dev->private;
952 	unsigned int chan = CR_CHAN(insn->chanspec);
953 	unsigned int mask;
954 	int ret;
955 
956 	if (chan < 8)
957 		mask = 0x00ff;
958 	else
959 		mask = 0xff00;
960 
961 	ret = comedi_dio_insn_config(dev, s, insn, data, mask);
962 	if (ret)
963 		return ret;
964 
965 	devpriv->dacsr &= ~(DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
966 	if (s->io_bits & 0x00ff)
967 		devpriv->dacsr |= DT2821_DACSR_LBOE;
968 	if (s->io_bits & 0xff00)
969 		devpriv->dacsr |= DT2821_DACSR_HBOE;
970 
971 	outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
972 
973 	return insn->n;
974 }
975 
976 static const struct comedi_lrange *const ai_range_table[] = {
977 	&range_dt282x_ai_lo_bipolar,
978 	&range_dt282x_ai_lo_unipolar,
979 	&range_dt282x_ai_5_bipolar,
980 	&range_dt282x_ai_5_unipolar
981 };
982 
983 static const struct comedi_lrange *const ai_range_pgl_table[] = {
984 	&range_dt282x_ai_hi_bipolar,
985 	&range_dt282x_ai_hi_unipolar
986 };
987 
opt_ai_range_lkup(int ispgl,int x)988 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
989 {
990 	if (ispgl) {
991 		if (x < 0 || x >= 2)
992 			x = 0;
993 		return ai_range_pgl_table[x];
994 	}
995 
996 	if (x < 0 || x >= 4)
997 		x = 0;
998 	return ai_range_table[x];
999 }
1000 
dt282x_alloc_dma(struct comedi_device * dev,struct comedi_devconfig * it)1001 static void dt282x_alloc_dma(struct comedi_device *dev,
1002 			     struct comedi_devconfig *it)
1003 {
1004 	struct dt282x_private *devpriv = dev->private;
1005 	unsigned int irq_num = it->options[1];
1006 	unsigned int dma_chan[2];
1007 
1008 	if (it->options[2] < it->options[3]) {
1009 		dma_chan[0] = it->options[2];
1010 		dma_chan[1] = it->options[3];
1011 	} else {
1012 		dma_chan[0] = it->options[3];
1013 		dma_chan[1] = it->options[2];
1014 	}
1015 
1016 	if (!irq_num || dma_chan[0] == dma_chan[1] ||
1017 	    dma_chan[0] < 5 || dma_chan[0] > 7 ||
1018 	    dma_chan[1] < 5 || dma_chan[1] > 7)
1019 		return;
1020 
1021 	if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev))
1022 		return;
1023 
1024 	/* DMA uses two 4K buffers with separate DMA channels */
1025 	devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1],
1026 					   PAGE_SIZE, 0);
1027 	if (!devpriv->dma)
1028 		free_irq(irq_num, dev);
1029 	else
1030 		dev->irq = irq_num;
1031 }
1032 
dt282x_free_dma(struct comedi_device * dev)1033 static void dt282x_free_dma(struct comedi_device *dev)
1034 {
1035 	struct dt282x_private *devpriv = dev->private;
1036 
1037 	if (devpriv)
1038 		comedi_isadma_free(devpriv->dma);
1039 }
1040 
dt282x_initialize(struct comedi_device * dev)1041 static int dt282x_initialize(struct comedi_device *dev)
1042 {
1043 	/* Initialize board */
1044 	outw(DT2821_SUPCSR_BDINIT, dev->iobase + DT2821_SUPCSR_REG);
1045 	inw(dev->iobase + DT2821_ADCSR_REG);
1046 
1047 	/*
1048 	 * At power up, some registers are in a well-known state.
1049 	 * Check them to see if a DT2821 series board is present.
1050 	 */
1051 	if (((inw(dev->iobase + DT2821_ADCSR_REG) & 0xfff0) != 0x7c00) ||
1052 	    ((inw(dev->iobase + DT2821_CHANCSR_REG) & 0xf0f0) != 0x70f0) ||
1053 	    ((inw(dev->iobase + DT2821_DACSR_REG) & 0x7c93) != 0x7c90) ||
1054 	    ((inw(dev->iobase + DT2821_SUPCSR_REG) & 0xf8ff) != 0x0000) ||
1055 	    ((inw(dev->iobase + DT2821_TMRCTR_REG) & 0xff00) != 0xf000)) {
1056 		dev_err(dev->class_dev, "board not found\n");
1057 		return -EIO;
1058 	}
1059 	return 0;
1060 }
1061 
dt282x_attach(struct comedi_device * dev,struct comedi_devconfig * it)1062 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1063 {
1064 	const struct dt282x_board *board = dev->board_ptr;
1065 	struct dt282x_private *devpriv;
1066 	struct comedi_subdevice *s;
1067 	int ret;
1068 
1069 	ret = comedi_request_region(dev, it->options[0], 0x10);
1070 	if (ret)
1071 		return ret;
1072 
1073 	ret = dt282x_initialize(dev);
1074 	if (ret)
1075 		return ret;
1076 
1077 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1078 	if (!devpriv)
1079 		return -ENOMEM;
1080 
1081 	/* an IRQ and 2 DMA channels are required for async command support */
1082 	dt282x_alloc_dma(dev, it);
1083 
1084 	ret = comedi_alloc_subdevices(dev, 3);
1085 	if (ret)
1086 		return ret;
1087 
1088 	/* Analog Input subdevice */
1089 	s = &dev->subdevices[0];
1090 	s->type		= COMEDI_SUBD_AI;
1091 	s->subdev_flags	= SDF_READABLE;
1092 	if ((it->options[4] && board->adchan_di) || board->adchan_se == 0) {
1093 		s->subdev_flags	|= SDF_DIFF;
1094 		s->n_chan	= board->adchan_di;
1095 	} else {
1096 		s->subdev_flags	|= SDF_COMMON;
1097 		s->n_chan	= board->adchan_se;
1098 	}
1099 	s->maxdata	= board->ai_maxdata;
1100 
1101 	s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]);
1102 	devpriv->ad_2scomp = it->options[5] ? 1 : 0;
1103 
1104 	s->insn_read	= dt282x_ai_insn_read;
1105 	if (dev->irq) {
1106 		dev->read_subdev = s;
1107 		s->subdev_flags	|= SDF_CMD_READ;
1108 		s->len_chanlist	= s->n_chan;
1109 		s->do_cmdtest	= dt282x_ai_cmdtest;
1110 		s->do_cmd	= dt282x_ai_cmd;
1111 		s->cancel	= dt282x_ai_cancel;
1112 	}
1113 
1114 	/* Analog Output subdevice */
1115 	s = &dev->subdevices[1];
1116 	if (board->dachan) {
1117 		s->type		= COMEDI_SUBD_AO;
1118 		s->subdev_flags	= SDF_WRITABLE;
1119 		s->n_chan	= board->dachan;
1120 		s->maxdata	= board->ao_maxdata;
1121 		/* ranges are per-channel, set by jumpers on the board */
1122 		s->range_table	= &dt282x_ao_range;
1123 		s->insn_write	= dt282x_ao_insn_write;
1124 		if (dev->irq) {
1125 			dev->write_subdev = s;
1126 			s->subdev_flags	|= SDF_CMD_WRITE;
1127 			s->len_chanlist	= s->n_chan;
1128 			s->do_cmdtest	= dt282x_ao_cmdtest;
1129 			s->do_cmd	= dt282x_ao_cmd;
1130 			s->cancel	= dt282x_ao_cancel;
1131 		}
1132 
1133 		ret = comedi_alloc_subdev_readback(s);
1134 		if (ret)
1135 			return ret;
1136 	} else {
1137 		s->type		= COMEDI_SUBD_UNUSED;
1138 	}
1139 
1140 	/* Digital I/O subdevice */
1141 	s = &dev->subdevices[2];
1142 	s->type		= COMEDI_SUBD_DIO;
1143 	s->subdev_flags	= SDF_READABLE | SDF_WRITABLE;
1144 	s->n_chan	= 16;
1145 	s->maxdata	= 1;
1146 	s->range_table	= &range_digital;
1147 	s->insn_bits	= dt282x_dio_insn_bits;
1148 	s->insn_config	= dt282x_dio_insn_config;
1149 
1150 	return 0;
1151 }
1152 
dt282x_detach(struct comedi_device * dev)1153 static void dt282x_detach(struct comedi_device *dev)
1154 {
1155 	dt282x_free_dma(dev);
1156 	comedi_legacy_detach(dev);
1157 }
1158 
1159 static struct comedi_driver dt282x_driver = {
1160 	.driver_name	= "dt282x",
1161 	.module		= THIS_MODULE,
1162 	.attach		= dt282x_attach,
1163 	.detach		= dt282x_detach,
1164 	.board_name	= &boardtypes[0].name,
1165 	.num_names	= ARRAY_SIZE(boardtypes),
1166 	.offset		= sizeof(struct dt282x_board),
1167 };
1168 module_comedi_driver(dt282x_driver);
1169 
1170 MODULE_AUTHOR("Comedi https://www.comedi.org");
1171 MODULE_DESCRIPTION("Comedi driver for Data Translation DT2821 series");
1172 MODULE_LICENSE("GPL");
1173