1/*
2  comedi/drivers/ni_tiocmd.c
3  Command support for NI general purpose counters
4
5  Copyright (C) 2006 Frank Mori Hess <fmhess@users.sourceforge.net>
6
7  This program is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation; either version 2 of the License, or
10  (at your option) any later version.
11
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  GNU General Public License for more details.
16*/
17
18/*
19Driver: ni_tiocmd
20Description: National Instruments general purpose counters command support
21Devices:
22Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
23	Herman.Bruyninckx@mech.kuleuven.ac.be,
24	Wim.Meeussen@mech.kuleuven.ac.be,
25	Klaas.Gadeyne@mech.kuleuven.ac.be,
26	Frank Mori Hess <fmhess@users.sourceforge.net>
27Updated: Fri, 11 Apr 2008 12:32:35 +0100
28Status: works
29
30This module is not used directly by end-users.  Rather, it
31is used by other drivers (for example ni_660x and ni_pcimio)
32to provide command support for NI's general purpose counters.
33It was originally split out of ni_tio.c to stop the 'ni_tio'
34module depending on the 'mite' module.
35
36References:
37DAQ 660x Register-Level Programmer Manual  (NI 370505A-01)
38DAQ 6601/6602 User Manual (NI 322137B-01)
39340934b.pdf  DAQ-STC reference manual
40
41*/
42/*
43TODO:
44	Support use of both banks X and Y
45*/
46
47#include <linux/module.h>
48#include "comedi_fc.h"
49#include "ni_tio_internal.h"
50#include "mite.h"
51
52static void ni_tio_configure_dma(struct ni_gpct *counter,
53				 bool enable, bool read)
54{
55	struct ni_gpct_device *counter_dev = counter->counter_dev;
56	unsigned cidx = counter->counter_index;
57	unsigned mask;
58	unsigned bits;
59
60	mask = GI_READ_ACKS_IRQ | GI_WRITE_ACKS_IRQ;
61	bits = 0;
62
63	if (enable) {
64		if (read)
65			bits |= GI_READ_ACKS_IRQ;
66		else
67			bits |= GI_WRITE_ACKS_IRQ;
68	}
69	ni_tio_set_bits(counter, NITIO_INPUT_SEL_REG(cidx), mask, bits);
70
71	switch (counter_dev->variant) {
72	case ni_gpct_variant_e_series:
73		break;
74	case ni_gpct_variant_m_series:
75	case ni_gpct_variant_660x:
76		mask = GI_DMA_ENABLE | GI_DMA_INT_ENA | GI_DMA_WRITE;
77		bits = 0;
78
79		if (enable)
80			bits |= GI_DMA_ENABLE | GI_DMA_INT_ENA;
81		if (!read)
82			bits |= GI_DMA_WRITE;
83		ni_tio_set_bits(counter, NITIO_DMA_CFG_REG(cidx), mask, bits);
84		break;
85	}
86}
87
88static int ni_tio_input_inttrig(struct comedi_device *dev,
89				struct comedi_subdevice *s,
90				unsigned int trig_num)
91{
92	struct ni_gpct *counter = s->private;
93	struct comedi_cmd *cmd = &s->async->cmd;
94	unsigned long flags;
95	int ret = 0;
96
97	if (trig_num != cmd->start_src)
98		return -EINVAL;
99
100	spin_lock_irqsave(&counter->lock, flags);
101	if (counter->mite_chan)
102		mite_dma_arm(counter->mite_chan);
103	else
104		ret = -EIO;
105	spin_unlock_irqrestore(&counter->lock, flags);
106	if (ret < 0)
107		return ret;
108	ret = ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
109	s->async->inttrig = NULL;
110
111	return ret;
112}
113
114static int ni_tio_input_cmd(struct comedi_subdevice *s)
115{
116	struct ni_gpct *counter = s->private;
117	struct ni_gpct_device *counter_dev = counter->counter_dev;
118	unsigned cidx = counter->counter_index;
119	struct comedi_async *async = s->async;
120	struct comedi_cmd *cmd = &async->cmd;
121	int ret = 0;
122
123	/* write alloc the entire buffer */
124	comedi_buf_write_alloc(s, async->prealloc_bufsz);
125	counter->mite_chan->dir = COMEDI_INPUT;
126	switch (counter_dev->variant) {
127	case ni_gpct_variant_m_series:
128	case ni_gpct_variant_660x:
129		mite_prep_dma(counter->mite_chan, 32, 32);
130		break;
131	case ni_gpct_variant_e_series:
132		mite_prep_dma(counter->mite_chan, 16, 32);
133		break;
134	default:
135		BUG();
136		break;
137	}
138	ni_tio_set_bits(counter, NITIO_CMD_REG(cidx), GI_SAVE_TRACE, 0);
139	ni_tio_configure_dma(counter, true, true);
140
141	if (cmd->start_src == TRIG_INT) {
142		async->inttrig = &ni_tio_input_inttrig;
143	} else {	/* TRIG_NOW || TRIG_EXT || TRIG_OTHER */
144		async->inttrig = NULL;
145		mite_dma_arm(counter->mite_chan);
146
147		if (cmd->start_src == TRIG_NOW)
148			ret = ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
149		else if (cmd->start_src == TRIG_EXT)
150			ret = ni_tio_arm(counter, 1, cmd->start_arg);
151	}
152	return ret;
153}
154
155static int ni_tio_output_cmd(struct comedi_subdevice *s)
156{
157	struct ni_gpct *counter = s->private;
158
159	dev_err(counter->counter_dev->dev->class_dev,
160		"output commands not yet implemented.\n");
161	return -ENOTSUPP;
162
163	counter->mite_chan->dir = COMEDI_OUTPUT;
164	mite_prep_dma(counter->mite_chan, 32, 32);
165	ni_tio_configure_dma(counter, true, false);
166	mite_dma_arm(counter->mite_chan);
167	return ni_tio_arm(counter, 1, NI_GPCT_ARM_IMMEDIATE);
168}
169
170static int ni_tio_cmd_setup(struct comedi_subdevice *s)
171{
172	struct comedi_cmd *cmd = &s->async->cmd;
173	struct ni_gpct *counter = s->private;
174	unsigned cidx = counter->counter_index;
175	int set_gate_source = 0;
176	unsigned gate_source;
177	int retval = 0;
178
179	if (cmd->scan_begin_src == TRIG_EXT) {
180		set_gate_source = 1;
181		gate_source = cmd->scan_begin_arg;
182	} else if (cmd->convert_src == TRIG_EXT) {
183		set_gate_source = 1;
184		gate_source = cmd->convert_arg;
185	}
186	if (set_gate_source)
187		retval = ni_tio_set_gate_src(counter, 0, gate_source);
188	if (cmd->flags & CMDF_WAKE_EOS) {
189		ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
190				GI_GATE_INTERRUPT_ENABLE(cidx),
191				GI_GATE_INTERRUPT_ENABLE(cidx));
192	}
193	return retval;
194}
195
196int ni_tio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
197{
198	struct ni_gpct *counter = s->private;
199	struct comedi_async *async = s->async;
200	struct comedi_cmd *cmd = &async->cmd;
201	int retval = 0;
202	unsigned long flags;
203
204	spin_lock_irqsave(&counter->lock, flags);
205	if (counter->mite_chan == NULL) {
206		dev_err(counter->counter_dev->dev->class_dev,
207			"commands only supported with DMA.  ");
208		dev_err(counter->counter_dev->dev->class_dev,
209			"Interrupt-driven commands not yet implemented.\n");
210		retval = -EIO;
211	} else {
212		retval = ni_tio_cmd_setup(s);
213		if (retval == 0) {
214			if (cmd->flags & CMDF_WRITE)
215				retval = ni_tio_output_cmd(s);
216			else
217				retval = ni_tio_input_cmd(s);
218		}
219	}
220	spin_unlock_irqrestore(&counter->lock, flags);
221	return retval;
222}
223EXPORT_SYMBOL_GPL(ni_tio_cmd);
224
225int ni_tio_cmdtest(struct comedi_device *dev,
226		   struct comedi_subdevice *s,
227		   struct comedi_cmd *cmd)
228{
229	struct ni_gpct *counter = s->private;
230	int err = 0;
231	unsigned int sources;
232
233	/* Step 1 : check if triggers are trivially valid */
234
235	sources = TRIG_NOW | TRIG_INT | TRIG_OTHER;
236	if (ni_tio_counting_mode_registers_present(counter->counter_dev))
237		sources |= TRIG_EXT;
238	err |= cfc_check_trigger_src(&cmd->start_src, sources);
239
240	err |= cfc_check_trigger_src(&cmd->scan_begin_src,
241					TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER);
242	err |= cfc_check_trigger_src(&cmd->convert_src,
243					TRIG_NOW | TRIG_EXT | TRIG_OTHER);
244	err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
245	err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
246
247	if (err)
248		return 1;
249
250	/* Step 2a : make sure trigger sources are unique */
251
252	err |= cfc_check_trigger_is_unique(cmd->start_src);
253	err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
254	err |= cfc_check_trigger_is_unique(cmd->convert_src);
255
256	/* Step 2b : and mutually compatible */
257
258	if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW)
259		err |= -EINVAL;
260
261	if (err)
262		return 2;
263
264	/* Step 3: check if arguments are trivially valid */
265
266	switch (cmd->start_src) {
267	case TRIG_NOW:
268	case TRIG_INT:
269	case TRIG_OTHER:
270		err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
271		break;
272	case TRIG_EXT:
273		/* start_arg is the start_trigger passed to ni_tio_arm() */
274		break;
275	}
276
277	if (cmd->scan_begin_src != TRIG_EXT)
278		err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
279
280	if (cmd->convert_src != TRIG_EXT)
281		err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
282
283	err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
284	err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
285
286	if (err)
287		return 3;
288
289	/* Step 4: fix up any arguments */
290
291	/* Step 5: check channel list if it exists */
292
293	return 0;
294}
295EXPORT_SYMBOL_GPL(ni_tio_cmdtest);
296
297int ni_tio_cancel(struct ni_gpct *counter)
298{
299	unsigned cidx = counter->counter_index;
300	unsigned long flags;
301
302	ni_tio_arm(counter, 0, 0);
303	spin_lock_irqsave(&counter->lock, flags);
304	if (counter->mite_chan)
305		mite_dma_disarm(counter->mite_chan);
306	spin_unlock_irqrestore(&counter->lock, flags);
307	ni_tio_configure_dma(counter, false, false);
308
309	ni_tio_set_bits(counter, NITIO_INT_ENA_REG(cidx),
310			GI_GATE_INTERRUPT_ENABLE(cidx), 0x0);
311	return 0;
312}
313EXPORT_SYMBOL_GPL(ni_tio_cancel);
314
315	/* During buffered input counter operation for e-series, the gate
316	   interrupt is acked automatically by the dma controller, due to the
317	   Gi_Read/Write_Acknowledges_IRQ bits in the input select register.  */
318static int should_ack_gate(struct ni_gpct *counter)
319{
320	unsigned long flags;
321	int retval = 0;
322
323	switch (counter->counter_dev->variant) {
324	case ni_gpct_variant_m_series:
325	/*  not sure if 660x really supports gate
326	    interrupts (the bits are not listed
327	    in register-level manual) */
328	case ni_gpct_variant_660x:
329		return 1;
330	case ni_gpct_variant_e_series:
331		spin_lock_irqsave(&counter->lock, flags);
332		{
333			if (counter->mite_chan == NULL ||
334			    counter->mite_chan->dir != COMEDI_INPUT ||
335			    (mite_done(counter->mite_chan))) {
336				retval = 1;
337			}
338		}
339		spin_unlock_irqrestore(&counter->lock, flags);
340		break;
341	}
342	return retval;
343}
344
345static void ni_tio_acknowledge_and_confirm(struct ni_gpct *counter,
346					   int *gate_error,
347					   int *tc_error,
348					   int *perm_stale_data,
349					   int *stale_data)
350{
351	unsigned cidx = counter->counter_index;
352	const unsigned short gxx_status = read_register(counter,
353						NITIO_SHARED_STATUS_REG(cidx));
354	const unsigned short gi_status = read_register(counter,
355						NITIO_STATUS_REG(cidx));
356	unsigned ack = 0;
357
358	if (gate_error)
359		*gate_error = 0;
360	if (tc_error)
361		*tc_error = 0;
362	if (perm_stale_data)
363		*perm_stale_data = 0;
364	if (stale_data)
365		*stale_data = 0;
366
367	if (gxx_status & GI_GATE_ERROR(cidx)) {
368		ack |= GI_GATE_ERROR_CONFIRM(cidx);
369		if (gate_error) {
370			/*660x don't support automatic acknowledgement
371			  of gate interrupt via dma read/write
372			   and report bogus gate errors */
373			if (counter->counter_dev->variant !=
374			    ni_gpct_variant_660x) {
375				*gate_error = 1;
376			}
377		}
378	}
379	if (gxx_status & GI_TC_ERROR(cidx)) {
380		ack |= GI_TC_ERROR_CONFIRM(cidx);
381		if (tc_error)
382			*tc_error = 1;
383	}
384	if (gi_status & GI_TC)
385		ack |= GI_TC_INTERRUPT_ACK;
386	if (gi_status & GI_GATE_INTERRUPT) {
387		if (should_ack_gate(counter))
388			ack |= GI_GATE_INTERRUPT_ACK;
389	}
390	if (ack)
391		write_register(counter, ack, NITIO_INT_ACK_REG(cidx));
392	if (ni_tio_get_soft_copy(counter, NITIO_MODE_REG(cidx)) &
393	    GI_LOADING_ON_GATE) {
394		if (gxx_status & GI_STALE_DATA(cidx)) {
395			if (stale_data)
396				*stale_data = 1;
397		}
398		if (read_register(counter, NITIO_STATUS2_REG(cidx)) &
399		    GI_PERMANENT_STALE(cidx)) {
400			dev_info(counter->counter_dev->dev->class_dev,
401				 "%s: Gi_Permanent_Stale_Data detected.\n",
402				 __func__);
403			if (perm_stale_data)
404				*perm_stale_data = 1;
405		}
406	}
407}
408
409void ni_tio_acknowledge(struct ni_gpct *counter)
410{
411	ni_tio_acknowledge_and_confirm(counter, NULL, NULL, NULL, NULL);
412}
413EXPORT_SYMBOL_GPL(ni_tio_acknowledge);
414
415void ni_tio_handle_interrupt(struct ni_gpct *counter,
416			     struct comedi_subdevice *s)
417{
418	unsigned cidx = counter->counter_index;
419	unsigned gpct_mite_status;
420	unsigned long flags;
421	int gate_error;
422	int tc_error;
423	int perm_stale_data;
424
425	ni_tio_acknowledge_and_confirm(counter, &gate_error, &tc_error,
426				       &perm_stale_data, NULL);
427	if (gate_error) {
428		dev_notice(counter->counter_dev->dev->class_dev,
429			   "%s: Gi_Gate_Error detected.\n", __func__);
430		s->async->events |= COMEDI_CB_OVERFLOW;
431	}
432	if (perm_stale_data)
433		s->async->events |= COMEDI_CB_ERROR;
434	switch (counter->counter_dev->variant) {
435	case ni_gpct_variant_m_series:
436	case ni_gpct_variant_660x:
437		if (read_register(counter, NITIO_DMA_STATUS_REG(cidx)) &
438		    GI_DRQ_ERROR) {
439			dev_notice(counter->counter_dev->dev->class_dev,
440				   "%s: Gi_DRQ_Error detected.\n", __func__);
441			s->async->events |= COMEDI_CB_OVERFLOW;
442		}
443		break;
444	case ni_gpct_variant_e_series:
445		break;
446	}
447	spin_lock_irqsave(&counter->lock, flags);
448	if (counter->mite_chan == NULL) {
449		spin_unlock_irqrestore(&counter->lock, flags);
450		return;
451	}
452	gpct_mite_status = mite_get_status(counter->mite_chan);
453	if (gpct_mite_status & CHSR_LINKC) {
454		writel(CHOR_CLRLC,
455		       counter->mite_chan->mite->mite_io_addr +
456		       MITE_CHOR(counter->mite_chan->channel));
457	}
458	mite_sync_input_dma(counter->mite_chan, s);
459	spin_unlock_irqrestore(&counter->lock, flags);
460}
461EXPORT_SYMBOL_GPL(ni_tio_handle_interrupt);
462
463void ni_tio_set_mite_channel(struct ni_gpct *counter,
464			     struct mite_channel *mite_chan)
465{
466	unsigned long flags;
467
468	spin_lock_irqsave(&counter->lock, flags);
469	counter->mite_chan = mite_chan;
470	spin_unlock_irqrestore(&counter->lock, flags);
471}
472EXPORT_SYMBOL_GPL(ni_tio_set_mite_channel);
473
474static int __init ni_tiocmd_init_module(void)
475{
476	return 0;
477}
478module_init(ni_tiocmd_init_module);
479
480static void __exit ni_tiocmd_cleanup_module(void)
481{
482}
483module_exit(ni_tiocmd_cleanup_module);
484
485MODULE_AUTHOR("Comedi <comedi@comedi.org>");
486MODULE_DESCRIPTION("Comedi command support for NI general-purpose counters");
487MODULE_LICENSE("GPL");
488