xref: /openbmc/linux/drivers/comedi/drivers/das6402.c (revision 44fb7aff)
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * das6402.c
4  * Comedi driver for DAS6402 compatible boards
5  * Copyright(c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
6  *
7  * Rewrite of an experimental driver by:
8  * Copyright (C) 1999 Oystein Svendsen <svendsen@pvv.org>
9  */
10 
11 /*
12  * Driver: das6402
13  * Description: Keithley Metrabyte DAS6402 (& compatibles)
14  * Devices: [Keithley Metrabyte] DAS6402-12 (das6402-12),
15  *   DAS6402-16 (das6402-16)
16  * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
17  * Updated: Fri, 14 Mar 2014 10:18:43 -0700
18  * Status: unknown
19  *
20  * Configuration Options:
21  *   [0] - I/O base address
22  *   [1] - IRQ (optional, needed for async command support)
23  */
24 
25 #include <linux/module.h>
26 #include <linux/interrupt.h>
27 #include <linux/comedi/comedidev.h>
28 #include <linux/comedi/comedi_8254.h>
29 
30 /*
31  * Register I/O map
32  */
33 #define DAS6402_AI_DATA_REG		0x00
34 #define DAS6402_AI_MUX_REG		0x02
35 #define DAS6402_AI_MUX_LO(x)		(((x) & 0x3f) << 0)
36 #define DAS6402_AI_MUX_HI(x)		(((x) & 0x3f) << 8)
37 #define DAS6402_DI_DO_REG		0x03
38 #define DAS6402_AO_DATA_REG(x)		(0x04 + ((x) * 2))
39 #define DAS6402_AO_LSB_REG(x)		(0x04 + ((x) * 2))
40 #define DAS6402_AO_MSB_REG(x)		(0x05 + ((x) * 2))
41 #define DAS6402_STATUS_REG		0x08
42 #define DAS6402_STATUS_FFNE		BIT(0)
43 #define DAS6402_STATUS_FHALF		BIT(1)
44 #define DAS6402_STATUS_FFULL		BIT(2)
45 #define DAS6402_STATUS_XINT		BIT(3)
46 #define DAS6402_STATUS_INT		BIT(4)
47 #define DAS6402_STATUS_XTRIG		BIT(5)
48 #define DAS6402_STATUS_INDGT		BIT(6)
49 #define DAS6402_STATUS_10MHZ		BIT(7)
50 #define DAS6402_STATUS_W_CLRINT		BIT(0)
51 #define DAS6402_STATUS_W_CLRXTR		BIT(1)
52 #define DAS6402_STATUS_W_CLRXIN		BIT(2)
53 #define DAS6402_STATUS_W_EXTEND		BIT(4)
54 #define DAS6402_STATUS_W_ARMED		BIT(5)
55 #define DAS6402_STATUS_W_POSTMODE	BIT(6)
56 #define DAS6402_STATUS_W_10MHZ		BIT(7)
57 #define DAS6402_CTRL_REG		0x09
58 #define DAS6402_CTRL_TRIG(x)		((x) << 0)
59 #define DAS6402_CTRL_SOFT_TRIG		DAS6402_CTRL_TRIG(0)
60 #define DAS6402_CTRL_EXT_FALL_TRIG	DAS6402_CTRL_TRIG(1)
61 #define DAS6402_CTRL_EXT_RISE_TRIG	DAS6402_CTRL_TRIG(2)
62 #define DAS6402_CTRL_PACER_TRIG		DAS6402_CTRL_TRIG(3)
63 #define DAS6402_CTRL_BURSTEN		BIT(2)
64 #define DAS6402_CTRL_XINTE		BIT(3)
65 #define DAS6402_CTRL_IRQ(x)		((x) << 4)
66 #define DAS6402_CTRL_INTE		BIT(7)
67 #define DAS6402_TRIG_REG		0x0a
68 #define DAS6402_TRIG_TGEN		BIT(0)
69 #define DAS6402_TRIG_TGSEL		BIT(1)
70 #define DAS6402_TRIG_TGPOL		BIT(2)
71 #define DAS6402_TRIG_PRETRIG		BIT(3)
72 #define DAS6402_AO_RANGE(_chan, _range)	((_range) << ((_chan) ? 6 : 4))
73 #define DAS6402_AO_RANGE_MASK(_chan)	(3 << ((_chan) ? 6 : 4))
74 #define DAS6402_MODE_REG		0x0b
75 #define DAS6402_MODE_RANGE(x)		((x) << 2)
76 #define DAS6402_MODE_POLLED		DAS6402_MODE_RANGE(0)
77 #define DAS6402_MODE_FIFONEPTY		DAS6402_MODE_RANGE(1)
78 #define DAS6402_MODE_FIFOHFULL		DAS6402_MODE_RANGE(2)
79 #define DAS6402_MODE_EOB		DAS6402_MODE_RANGE(3)
80 #define DAS6402_MODE_ENHANCED		BIT(4)
81 #define DAS6402_MODE_SE			BIT(5)
82 #define DAS6402_MODE_UNI		BIT(6)
83 #define DAS6402_MODE_DMA(x)		((x) << 7)
84 #define DAS6402_MODE_DMA1		DAS6402_MODE_DMA(0)
85 #define DAS6402_MODE_DMA3		DAS6402_MODE_DMA(1)
86 #define DAS6402_TIMER_BASE		0x0c
87 
88 static const struct comedi_lrange das6402_ai_ranges = {
89 	8, {
90 		BIP_RANGE(10),
91 		BIP_RANGE(5),
92 		BIP_RANGE(2.5),
93 		BIP_RANGE(1.25),
94 		UNI_RANGE(10),
95 		UNI_RANGE(5),
96 		UNI_RANGE(2.5),
97 		UNI_RANGE(1.25)
98 	}
99 };
100 
101 /*
102  * Analog output ranges are programmable on the DAS6402/12.
103  * For the DAS6402/16 the range bits have no function, the
104  * DAC ranges are selected by switches on the board.
105  */
106 static const struct comedi_lrange das6402_ao_ranges = {
107 	4, {
108 		BIP_RANGE(5),
109 		BIP_RANGE(10),
110 		UNI_RANGE(5),
111 		UNI_RANGE(10)
112 	}
113 };
114 
115 struct das6402_boardinfo {
116 	const char *name;
117 	unsigned int maxdata;
118 };
119 
120 static struct das6402_boardinfo das6402_boards[] = {
121 	{
122 		.name		= "das6402-12",
123 		.maxdata	= 0x0fff,
124 	}, {
125 		.name		= "das6402-16",
126 		.maxdata	= 0xffff,
127 	},
128 };
129 
130 struct das6402_private {
131 	unsigned int irq;
132 	unsigned int ao_range;
133 };
134 
das6402_set_mode(struct comedi_device * dev,unsigned int mode)135 static void das6402_set_mode(struct comedi_device *dev,
136 			     unsigned int mode)
137 {
138 	outb(DAS6402_MODE_ENHANCED | mode, dev->iobase + DAS6402_MODE_REG);
139 }
140 
das6402_set_extended(struct comedi_device * dev,unsigned int val)141 static void das6402_set_extended(struct comedi_device *dev,
142 				 unsigned int val)
143 {
144 	outb(DAS6402_STATUS_W_EXTEND, dev->iobase + DAS6402_STATUS_REG);
145 	outb(DAS6402_STATUS_W_EXTEND | val, dev->iobase + DAS6402_STATUS_REG);
146 	outb(val, dev->iobase + DAS6402_STATUS_REG);
147 }
148 
das6402_clear_all_interrupts(struct comedi_device * dev)149 static void das6402_clear_all_interrupts(struct comedi_device *dev)
150 {
151 	outb(DAS6402_STATUS_W_CLRINT |
152 	     DAS6402_STATUS_W_CLRXTR |
153 	     DAS6402_STATUS_W_CLRXIN, dev->iobase + DAS6402_STATUS_REG);
154 }
155 
das6402_ai_clear_eoc(struct comedi_device * dev)156 static void das6402_ai_clear_eoc(struct comedi_device *dev)
157 {
158 	outb(DAS6402_STATUS_W_CLRINT, dev->iobase + DAS6402_STATUS_REG);
159 }
160 
das6402_ai_read_sample(struct comedi_device * dev,struct comedi_subdevice * s)161 static unsigned int das6402_ai_read_sample(struct comedi_device *dev,
162 					   struct comedi_subdevice *s)
163 {
164 	unsigned int val;
165 
166 	val = inw(dev->iobase + DAS6402_AI_DATA_REG);
167 	if (s->maxdata == 0x0fff)
168 		val >>= 4;
169 	return val;
170 }
171 
das6402_interrupt(int irq,void * d)172 static irqreturn_t das6402_interrupt(int irq, void *d)
173 {
174 	struct comedi_device *dev = d;
175 	struct comedi_subdevice *s = dev->read_subdev;
176 	struct comedi_async *async = s->async;
177 	struct comedi_cmd *cmd = &async->cmd;
178 	unsigned int status;
179 
180 	status = inb(dev->iobase + DAS6402_STATUS_REG);
181 	if ((status & DAS6402_STATUS_INT) == 0)
182 		return IRQ_NONE;
183 
184 	if (status & DAS6402_STATUS_FFULL) {
185 		async->events |= COMEDI_CB_OVERFLOW;
186 	} else if (status & DAS6402_STATUS_FFNE) {
187 		unsigned short val;
188 
189 		val = das6402_ai_read_sample(dev, s);
190 		comedi_buf_write_samples(s, &val, 1);
191 
192 		if (cmd->stop_src == TRIG_COUNT &&
193 		    async->scans_done >= cmd->stop_arg)
194 			async->events |= COMEDI_CB_EOA;
195 	}
196 
197 	das6402_clear_all_interrupts(dev);
198 
199 	comedi_handle_events(dev, s);
200 
201 	return IRQ_HANDLED;
202 }
203 
das6402_ai_set_mode(struct comedi_device * dev,struct comedi_subdevice * s,unsigned int chanspec,unsigned int mode)204 static void das6402_ai_set_mode(struct comedi_device *dev,
205 				struct comedi_subdevice *s,
206 				unsigned int chanspec,
207 				unsigned int mode)
208 {
209 	unsigned int range = CR_RANGE(chanspec);
210 	unsigned int aref = CR_AREF(chanspec);
211 
212 	mode |= DAS6402_MODE_RANGE(range);
213 	if (aref == AREF_GROUND)
214 		mode |= DAS6402_MODE_SE;
215 	if (comedi_range_is_unipolar(s, range))
216 		mode |= DAS6402_MODE_UNI;
217 
218 	das6402_set_mode(dev, mode);
219 }
220 
das6402_ai_cmd(struct comedi_device * dev,struct comedi_subdevice * s)221 static int das6402_ai_cmd(struct comedi_device *dev,
222 			  struct comedi_subdevice *s)
223 {
224 	struct das6402_private *devpriv = dev->private;
225 	struct comedi_cmd *cmd = &s->async->cmd;
226 	unsigned int chan_lo = CR_CHAN(cmd->chanlist[0]);
227 	unsigned int chan_hi = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
228 
229 	das6402_ai_set_mode(dev, s, cmd->chanlist[0], DAS6402_MODE_FIFONEPTY);
230 
231 	/* load the mux for chanlist conversion */
232 	outw(DAS6402_AI_MUX_HI(chan_hi) | DAS6402_AI_MUX_LO(chan_lo),
233 	     dev->iobase + DAS6402_AI_MUX_REG);
234 
235 	comedi_8254_update_divisors(dev->pacer);
236 	comedi_8254_pacer_enable(dev->pacer, 1, 2, true);
237 
238 	/* enable interrupt and pacer trigger */
239 	outb(DAS6402_CTRL_INTE |
240 	     DAS6402_CTRL_IRQ(devpriv->irq) |
241 	     DAS6402_CTRL_PACER_TRIG, dev->iobase + DAS6402_CTRL_REG);
242 
243 	return 0;
244 }
245 
das6402_ai_check_chanlist(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)246 static int das6402_ai_check_chanlist(struct comedi_device *dev,
247 				     struct comedi_subdevice *s,
248 				     struct comedi_cmd *cmd)
249 {
250 	unsigned int chan0 = CR_CHAN(cmd->chanlist[0]);
251 	unsigned int range0 = CR_RANGE(cmd->chanlist[0]);
252 	unsigned int aref0 = CR_AREF(cmd->chanlist[0]);
253 	int i;
254 
255 	for (i = 1; i < cmd->chanlist_len; i++) {
256 		unsigned int chan = CR_CHAN(cmd->chanlist[i]);
257 		unsigned int range = CR_RANGE(cmd->chanlist[i]);
258 		unsigned int aref = CR_AREF(cmd->chanlist[i]);
259 
260 		if (chan != chan0 + i) {
261 			dev_dbg(dev->class_dev,
262 				"chanlist must be consecutive\n");
263 			return -EINVAL;
264 		}
265 
266 		if (range != range0) {
267 			dev_dbg(dev->class_dev,
268 				"chanlist must have the same range\n");
269 			return -EINVAL;
270 		}
271 
272 		if (aref != aref0) {
273 			dev_dbg(dev->class_dev,
274 				"chanlist must have the same reference\n");
275 			return -EINVAL;
276 		}
277 
278 		if (aref0 == AREF_DIFF && chan > (s->n_chan / 2)) {
279 			dev_dbg(dev->class_dev,
280 				"chanlist differential channel too large\n");
281 			return -EINVAL;
282 		}
283 	}
284 	return 0;
285 }
286 
das6402_ai_cmdtest(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_cmd * cmd)287 static int das6402_ai_cmdtest(struct comedi_device *dev,
288 			      struct comedi_subdevice *s,
289 			      struct comedi_cmd *cmd)
290 {
291 	int err = 0;
292 	unsigned int arg;
293 
294 	/* Step 1 : check if triggers are trivially valid */
295 
296 	err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
297 	err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW);
298 	err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
299 	err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
300 	err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
301 
302 	if (err)
303 		return 1;
304 
305 	/* Step 2a : make sure trigger sources are unique */
306 
307 	err |= comedi_check_trigger_is_unique(cmd->stop_src);
308 
309 	/* Step 2b : and mutually compatible */
310 
311 	if (err)
312 		return 2;
313 
314 	/* Step 3: check if arguments are trivially valid */
315 
316 	err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
317 	err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
318 	err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 10000);
319 	err |= comedi_check_trigger_arg_min(&cmd->chanlist_len, 1);
320 	err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
321 					   cmd->chanlist_len);
322 
323 	if (cmd->stop_src == TRIG_COUNT)
324 		err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
325 	else	/* TRIG_NONE */
326 		err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
327 
328 	if (err)
329 		return 3;
330 
331 	/* step 4: fix up any arguments */
332 
333 	arg = cmd->convert_arg;
334 	comedi_8254_cascade_ns_to_timer(dev->pacer, &arg, cmd->flags);
335 	err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
336 
337 	if (err)
338 		return 4;
339 
340 	/* Step 5: check channel list if it exists */
341 	if (cmd->chanlist && cmd->chanlist_len > 0)
342 		err |= das6402_ai_check_chanlist(dev, s, cmd);
343 
344 	if (err)
345 		return 5;
346 
347 	return 0;
348 }
349 
das6402_ai_cancel(struct comedi_device * dev,struct comedi_subdevice * s)350 static int das6402_ai_cancel(struct comedi_device *dev,
351 			     struct comedi_subdevice *s)
352 {
353 	outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
354 
355 	return 0;
356 }
357 
das6402_ai_soft_trig(struct comedi_device * dev)358 static void das6402_ai_soft_trig(struct comedi_device *dev)
359 {
360 	outw(0, dev->iobase + DAS6402_AI_DATA_REG);
361 }
362 
das6402_ai_eoc(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned long context)363 static int das6402_ai_eoc(struct comedi_device *dev,
364 			  struct comedi_subdevice *s,
365 			  struct comedi_insn *insn,
366 			  unsigned long context)
367 {
368 	unsigned int status;
369 
370 	status = inb(dev->iobase + DAS6402_STATUS_REG);
371 	if (status & DAS6402_STATUS_FFNE)
372 		return 0;
373 	return -EBUSY;
374 }
375 
das6402_ai_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)376 static int das6402_ai_insn_read(struct comedi_device *dev,
377 				struct comedi_subdevice *s,
378 				struct comedi_insn *insn,
379 				unsigned int *data)
380 {
381 	unsigned int chan = CR_CHAN(insn->chanspec);
382 	unsigned int aref = CR_AREF(insn->chanspec);
383 	int ret;
384 	int i;
385 
386 	if (aref == AREF_DIFF && chan > (s->n_chan / 2))
387 		return -EINVAL;
388 
389 	/* enable software conversion trigger */
390 	outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
391 
392 	das6402_ai_set_mode(dev, s, insn->chanspec, DAS6402_MODE_POLLED);
393 
394 	/* load the mux for single channel conversion */
395 	outw(DAS6402_AI_MUX_HI(chan) | DAS6402_AI_MUX_LO(chan),
396 	     dev->iobase + DAS6402_AI_MUX_REG);
397 
398 	for (i = 0; i < insn->n; i++) {
399 		das6402_ai_clear_eoc(dev);
400 		das6402_ai_soft_trig(dev);
401 
402 		ret = comedi_timeout(dev, s, insn, das6402_ai_eoc, 0);
403 		if (ret)
404 			break;
405 
406 		data[i] = das6402_ai_read_sample(dev, s);
407 	}
408 
409 	das6402_ai_clear_eoc(dev);
410 
411 	return insn->n;
412 }
413 
das6402_ao_insn_write(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)414 static int das6402_ao_insn_write(struct comedi_device *dev,
415 				 struct comedi_subdevice *s,
416 				 struct comedi_insn *insn,
417 				 unsigned int *data)
418 {
419 	struct das6402_private *devpriv = dev->private;
420 	unsigned int chan = CR_CHAN(insn->chanspec);
421 	unsigned int range = CR_RANGE(insn->chanspec);
422 	unsigned int val;
423 	int i;
424 
425 	/* set the range for this channel */
426 	val = devpriv->ao_range;
427 	val &= ~DAS6402_AO_RANGE_MASK(chan);
428 	val |= DAS6402_AO_RANGE(chan, range);
429 	if (val != devpriv->ao_range) {
430 		devpriv->ao_range = val;
431 		outb(val, dev->iobase + DAS6402_TRIG_REG);
432 	}
433 
434 	/*
435 	 * The DAS6402/16 has a jumper to select either individual
436 	 * update (UPDATE) or simultaneous updating (XFER) of both
437 	 * DAC's. In UPDATE mode, when the MSB is written, that DAC
438 	 * is updated. In XFER mode, after both DAC's are loaded,
439 	 * a read cycle of any DAC register will update both DAC's
440 	 * simultaneously.
441 	 *
442 	 * If you have XFER mode enabled a (*insn_read) will need
443 	 * to be performed in order to update the DAC's with the
444 	 * last value written.
445 	 */
446 	for (i = 0; i < insn->n; i++) {
447 		val = data[i];
448 
449 		s->readback[chan] = val;
450 
451 		if (s->maxdata == 0x0fff) {
452 			/*
453 			 * DAS6402/12 has the two 8-bit DAC registers, left
454 			 * justified (the 4 LSB bits are don't care). Data
455 			 * can be written as one word.
456 			 */
457 			val <<= 4;
458 			outw(val, dev->iobase + DAS6402_AO_DATA_REG(chan));
459 		} else {
460 			/*
461 			 * DAS6402/16 uses both 8-bit DAC registers and needs
462 			 * to be written LSB then MSB.
463 			 */
464 			outb(val & 0xff,
465 			     dev->iobase + DAS6402_AO_LSB_REG(chan));
466 			outb((val >> 8) & 0xff,
467 			     dev->iobase + DAS6402_AO_LSB_REG(chan));
468 		}
469 	}
470 
471 	return insn->n;
472 }
473 
das6402_ao_insn_read(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)474 static int das6402_ao_insn_read(struct comedi_device *dev,
475 				struct comedi_subdevice *s,
476 				struct comedi_insn *insn,
477 				unsigned int *data)
478 {
479 	unsigned int chan = CR_CHAN(insn->chanspec);
480 
481 	/*
482 	 * If XFER mode is enabled, reading any DAC register
483 	 * will update both DAC's simultaneously.
484 	 */
485 	inw(dev->iobase + DAS6402_AO_LSB_REG(chan));
486 
487 	return comedi_readback_insn_read(dev, s, insn, data);
488 }
489 
das6402_di_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)490 static int das6402_di_insn_bits(struct comedi_device *dev,
491 				struct comedi_subdevice *s,
492 				struct comedi_insn *insn,
493 				unsigned int *data)
494 {
495 	data[1] = inb(dev->iobase + DAS6402_DI_DO_REG);
496 
497 	return insn->n;
498 }
499 
das6402_do_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)500 static int das6402_do_insn_bits(struct comedi_device *dev,
501 				struct comedi_subdevice *s,
502 				struct comedi_insn *insn,
503 				unsigned int *data)
504 {
505 	if (comedi_dio_update_state(s, data))
506 		outb(s->state, dev->iobase + DAS6402_DI_DO_REG);
507 
508 	data[1] = s->state;
509 
510 	return insn->n;
511 }
512 
das6402_reset(struct comedi_device * dev)513 static void das6402_reset(struct comedi_device *dev)
514 {
515 	struct das6402_private *devpriv = dev->private;
516 
517 	/* enable "Enhanced" mode */
518 	outb(DAS6402_MODE_ENHANCED, dev->iobase + DAS6402_MODE_REG);
519 
520 	/* enable 10MHz pacer clock */
521 	das6402_set_extended(dev, DAS6402_STATUS_W_10MHZ);
522 
523 	/* enable software conversion trigger */
524 	outb(DAS6402_CTRL_SOFT_TRIG, dev->iobase + DAS6402_CTRL_REG);
525 
526 	/* default ADC to single-ended unipolar 10V inputs */
527 	das6402_set_mode(dev, DAS6402_MODE_RANGE(0) |
528 			      DAS6402_MODE_POLLED |
529 			      DAS6402_MODE_SE |
530 			      DAS6402_MODE_UNI);
531 
532 	/* default mux for single channel conversion (channel 0) */
533 	outw(DAS6402_AI_MUX_HI(0) | DAS6402_AI_MUX_LO(0),
534 	     dev->iobase + DAS6402_AI_MUX_REG);
535 
536 	/* set both DAC's for unipolar 5V output range */
537 	devpriv->ao_range = DAS6402_AO_RANGE(0, 2) | DAS6402_AO_RANGE(1, 2);
538 	outb(devpriv->ao_range, dev->iobase + DAS6402_TRIG_REG);
539 
540 	/* set both DAC's to 0V */
541 	outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
542 	outw(0, dev->iobase + DAS6402_AO_DATA_REG(0));
543 	inw(dev->iobase + DAS6402_AO_LSB_REG(0));
544 
545 	/* set all digital outputs low */
546 	outb(0, dev->iobase + DAS6402_DI_DO_REG);
547 
548 	das6402_clear_all_interrupts(dev);
549 }
550 
das6402_attach(struct comedi_device * dev,struct comedi_devconfig * it)551 static int das6402_attach(struct comedi_device *dev,
552 			  struct comedi_devconfig *it)
553 {
554 	const struct das6402_boardinfo *board = dev->board_ptr;
555 	struct das6402_private *devpriv;
556 	struct comedi_subdevice *s;
557 	int ret;
558 
559 	devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
560 	if (!devpriv)
561 		return -ENOMEM;
562 
563 	ret = comedi_request_region(dev, it->options[0], 0x10);
564 	if (ret)
565 		return ret;
566 
567 	das6402_reset(dev);
568 
569 	/* IRQs 2,3,5,6,7, 10,11,15 are valid for "enhanced" mode */
570 	if ((1 << it->options[1]) & 0x8cec) {
571 		ret = request_irq(it->options[1], das6402_interrupt, 0,
572 				  dev->board_name, dev);
573 		if (ret == 0) {
574 			dev->irq = it->options[1];
575 
576 			switch (dev->irq) {
577 			case 10:
578 				devpriv->irq = 4;
579 				break;
580 			case 11:
581 				devpriv->irq = 1;
582 				break;
583 			case 15:
584 				devpriv->irq = 6;
585 				break;
586 			default:
587 				devpriv->irq = dev->irq;
588 				break;
589 			}
590 		}
591 	}
592 
593 	dev->pacer = comedi_8254_init(dev->iobase + DAS6402_TIMER_BASE,
594 				      I8254_OSC_BASE_10MHZ, I8254_IO8, 0);
595 	if (!dev->pacer)
596 		return -ENOMEM;
597 
598 	ret = comedi_alloc_subdevices(dev, 4);
599 	if (ret)
600 		return ret;
601 
602 	/* Analog Input subdevice */
603 	s = &dev->subdevices[0];
604 	s->type		= COMEDI_SUBD_AI;
605 	s->subdev_flags	= SDF_READABLE | SDF_GROUND | SDF_DIFF;
606 	s->n_chan	= 64;
607 	s->maxdata	= board->maxdata;
608 	s->range_table	= &das6402_ai_ranges;
609 	s->insn_read	= das6402_ai_insn_read;
610 	if (dev->irq) {
611 		dev->read_subdev = s;
612 		s->subdev_flags	|= SDF_CMD_READ;
613 		s->len_chanlist	= s->n_chan;
614 		s->do_cmdtest	= das6402_ai_cmdtest;
615 		s->do_cmd	= das6402_ai_cmd;
616 		s->cancel	= das6402_ai_cancel;
617 	}
618 
619 	/* Analog Output subdevice */
620 	s = &dev->subdevices[1];
621 	s->type		= COMEDI_SUBD_AO;
622 	s->subdev_flags	= SDF_WRITABLE;
623 	s->n_chan	= 2;
624 	s->maxdata	= board->maxdata;
625 	s->range_table	= &das6402_ao_ranges;
626 	s->insn_write	= das6402_ao_insn_write;
627 	s->insn_read	= das6402_ao_insn_read;
628 
629 	ret = comedi_alloc_subdev_readback(s);
630 	if (ret)
631 		return ret;
632 
633 	/* Digital Input subdevice */
634 	s = &dev->subdevices[2];
635 	s->type		= COMEDI_SUBD_DI;
636 	s->subdev_flags	= SDF_READABLE;
637 	s->n_chan	= 8;
638 	s->maxdata	= 1;
639 	s->range_table	= &range_digital;
640 	s->insn_bits	= das6402_di_insn_bits;
641 
642 	/* Digital Input subdevice */
643 	s = &dev->subdevices[3];
644 	s->type		= COMEDI_SUBD_DO;
645 	s->subdev_flags	= SDF_WRITABLE;
646 	s->n_chan	= 8;
647 	s->maxdata	= 1;
648 	s->range_table	= &range_digital;
649 	s->insn_bits	= das6402_do_insn_bits;
650 
651 	return 0;
652 }
653 
654 static struct comedi_driver das6402_driver = {
655 	.driver_name	= "das6402",
656 	.module		= THIS_MODULE,
657 	.attach		= das6402_attach,
658 	.detach		= comedi_legacy_detach,
659 	.board_name	= &das6402_boards[0].name,
660 	.num_names	= ARRAY_SIZE(das6402_boards),
661 	.offset		= sizeof(struct das6402_boardinfo),
662 };
663 module_comedi_driver(das6402_driver)
664 
665 MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
666 MODULE_DESCRIPTION("Comedi driver for DAS6402 compatible boards");
667 MODULE_LICENSE("GPL");
668