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
116static 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
125static 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
134static 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
143static 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
152static 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
166static 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
179static const int das16jr_gainlist[] = { 8, 0, 1, 2, 3, 4, 5, 6, 7 };
180static const int das16jr_16_gainlist[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
181static const int das1600_gainlist[] = { 0, 1, 2, 3 };
182
183enum {
184	das16_pg_none = 0,
185	das16_pg_16jr,
186	das16_pg_16jr_16,
187	das16_pg_1601,
188	das16_pg_1602,
189};
190
191static const int *const das16_gainlists[] = {
192	NULL,
193	das16jr_gainlist,
194	das16jr_16_gainlist,
195	das1600_gainlist,
196	das1600_gainlist,
197};
198
199static 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
207static 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
215struct 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
229static 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 */
425static inline int timer_period(void)
426{
427	return HZ / 20;
428}
429
430struct 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
443static 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
465static 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
518static 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
532static 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
555static 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
583static 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
683static 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
693static 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
760static 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
789static 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
807static 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
820static 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
854static 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
876static 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
886static 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
899static 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
916static 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
923static 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
938static 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
948static 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
984static 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
1015static 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_io_alloc(dev->iobase + DAS16_TIMER_BASE_REG,
1071					  osc_base, I8254_IO8, 0);
1072	if (IS_ERR(dev->pacer))
1073		return PTR_ERR(dev->pacer);
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_io_init(dev, s, 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
1167static 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
1185static 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};
1194module_comedi_driver(das16_driver);
1195
1196MODULE_AUTHOR("Comedi https://www.comedi.org");
1197MODULE_DESCRIPTION("Comedi driver for DAS16 compatible boards");
1198MODULE_LICENSE("GPL");
1199