s526.c revision 39f7666080909466c0ed6d5fa48cce3403033ced
1/*
2    comedi/drivers/s526.c
3    Sensoray s526 Comedi driver
4
5    COMEDI - Linux Control and Measurement Device Interface
6    Copyright (C) 2000 David A. Schleef <ds@schleef.org>
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
22*/
23/*
24Driver: s526
25Description: Sensoray 526 driver
26Devices: [Sensoray] 526 (s526)
27Author: Richie
28	Everett Wang <everett.wang@everteq.com>
29Updated: Thu, 14 Sep. 2006
30Status: experimental
31
32Encoder works
33Analog input works
34Analog output works
35PWM output works
36Commands are not supported yet.
37
38Configuration Options:
39
40comedi_config /dev/comedi0 s526 0x2C0,0x3
41
42*/
43
44#include "../comedidev.h"
45#include <linux/ioport.h>
46
47#define S526_SIZE 64
48
49#define S526_START_AI_CONV	0
50#define S526_AI_READ		0
51
52/* Ports */
53#define S526_IOSIZE 0x40
54#define S526_NUM_PORTS 27
55
56/* registers */
57#define REG_TCR 0x00
58#define REG_WDC 0x02
59#define REG_DAC 0x04
60#define REG_ADC 0x06
61#define REG_ADD 0x08
62#define REG_DIO 0x0A
63#define REG_IER 0x0C
64#define REG_ISR 0x0E
65#define REG_MSC 0x10
66#define REG_C0L 0x12
67#define REG_C0H 0x14
68#define REG_C0M 0x16
69#define REG_C0C 0x18
70#define REG_C1L 0x1A
71#define REG_C1H 0x1C
72#define REG_C1M 0x1E
73#define REG_C1C 0x20
74#define REG_C2L 0x22
75#define REG_C2H 0x24
76#define REG_C2M 0x26
77#define REG_C2C 0x28
78#define REG_C3L 0x2A
79#define REG_C3H 0x2C
80#define REG_C3M 0x2E
81#define REG_C3C 0x30
82#define REG_EED 0x32
83#define REG_EEC 0x34
84
85static const int s526_ports[] = {
86	REG_TCR,
87	REG_WDC,
88	REG_DAC,
89	REG_ADC,
90	REG_ADD,
91	REG_DIO,
92	REG_IER,
93	REG_ISR,
94	REG_MSC,
95	REG_C0L,
96	REG_C0H,
97	REG_C0M,
98	REG_C0C,
99	REG_C1L,
100	REG_C1H,
101	REG_C1M,
102	REG_C1C,
103	REG_C2L,
104	REG_C2H,
105	REG_C2M,
106	REG_C2C,
107	REG_C3L,
108	REG_C3H,
109	REG_C3M,
110	REG_C3C,
111	REG_EED,
112	REG_EEC
113};
114
115struct counter_mode_register_t {
116	unsigned short coutSource:1;
117	unsigned short coutPolarity:1;
118	unsigned short autoLoadResetRcap:3;
119	unsigned short hwCtEnableSource:2;
120	unsigned short ctEnableCtrl:2;
121	unsigned short clockSource:2;
122	unsigned short countDir:1;
123	unsigned short countDirCtrl:1;
124	unsigned short outputRegLatchCtrl:1;
125	unsigned short preloadRegSel:1;
126	unsigned short reserved:1;
127};
128
129union {
130	struct counter_mode_register_t reg;
131	unsigned short value;
132} cmReg;
133
134#define MAX_GPCT_CONFIG_DATA 6
135
136/* Different Application Classes for GPCT Subdevices */
137/* The list is not exhaustive and needs discussion! */
138enum S526_GPCT_APP_CLASS {
139	CountingAndTimeMeasurement,
140	SinglePulseGeneration,
141	PulseTrainGeneration,
142	PositionMeasurement,
143	Miscellaneous
144};
145
146/* Config struct for different GPCT subdevice Application Classes and
147   their options
148*/
149struct s526GPCTConfig {
150	enum S526_GPCT_APP_CLASS app;
151	int data[MAX_GPCT_CONFIG_DATA];
152};
153
154/*
155 * Board descriptions for two imaginary boards.  Describing the
156 * boards in this way is optional, and completely driver-dependent.
157 * Some drivers use arrays such as this, other do not.
158 */
159typedef struct s526_board_struct {
160	const char *name;
161	int gpct_chans;
162	int gpct_bits;
163	int ad_chans;
164	int ad_bits;
165	int da_chans;
166	int da_bits;
167	int have_dio;
168} s526_board;
169
170static const s526_board s526_boards[] = {
171	{
172	      name:	"s526",
173	      gpct_chans:4,
174	      gpct_bits:24,
175	      ad_chans:8,
176	      ad_bits:	16,
177	      da_chans:4,
178	      da_bits:	16,
179	      have_dio:1,
180		}
181};
182
183#define ADDR_REG(reg) (dev->iobase + (reg))
184#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8)
185
186/*
187 * Useful for shorthand access to the particular board structure
188 */
189#define thisboard ((const s526_board *)dev->board_ptr)
190
191/* this structure is for data unique to this hardware driver.  If
192   several hardware drivers keep similar information in this structure,
193   feel free to suggest moving the variable to the struct comedi_device struct.  */
194struct s526_private {
195
196	int data;
197
198	/* would be useful for a PCI device */
199	struct pci_dev *pci_dev;
200
201	/* Used for AO readback */
202	unsigned int ao_readback[2];
203
204	struct s526GPCTConfig s526_gpct_config[4];
205	unsigned short s526_ai_config;
206};
207
208/*
209 * most drivers define the following macro to make it easy to
210 * access the private structure.
211 */
212#define devpriv ((struct s526_private *)dev->private)
213
214/*
215 * The struct comedi_driver structure tells the Comedi core module
216 * which functions to call to configure/deconfigure (attach/detach)
217 * the board, and also about the kernel module that contains
218 * the device code.
219 */
220static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it);
221static int s526_detach(struct comedi_device * dev);
222static struct comedi_driver driver_s526 = {
223      driver_name:"s526",
224      module:THIS_MODULE,
225      attach:s526_attach,
226      detach:s526_detach,
227/* It is not necessary to implement the following members if you are
228 * writing a driver for a ISA PnP or PCI card */
229	/* Most drivers will support multiple types of boards by
230	 * having an array of board structures.  These were defined
231	 * in s526_boards[] above.  Note that the element 'name'
232	 * was first in the structure -- Comedi uses this fact to
233	 * extract the name of the board without knowing any details
234	 * about the structure except for its length.
235	 * When a device is attached (by comedi_config), the name
236	 * of the device is given to Comedi, and Comedi tries to
237	 * match it by going through the list of board names.  If
238	 * there is a match, the address of the pointer is put
239	 * into dev->board_ptr and driver->attach() is called.
240	 *
241	 * Note that these are not necessary if you can determine
242	 * the type of board in software.  ISA PnP, PCI, and PCMCIA
243	 * devices are such boards.
244	 */
245      board_name:&s526_boards[0].name,
246      offset:sizeof(s526_board),
247      num_names:sizeof(s526_boards) / sizeof(s526_board),
248};
249
250static int s526_gpct_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
251	struct comedi_insn * insn, unsigned int * data);
252static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
253	struct comedi_insn * insn, unsigned int * data);
254static int s526_gpct_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
255	struct comedi_insn * insn, unsigned int * data);
256static int s526_ai_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
257	struct comedi_insn * insn, unsigned int * data);
258static int s526_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
259	struct comedi_insn * insn, unsigned int * data);
260static int s526_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
261	struct comedi_insn * insn, unsigned int * data);
262static int s526_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
263	struct comedi_insn * insn, unsigned int * data);
264static int s526_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
265	struct comedi_insn * insn, unsigned int * data);
266static int s526_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
267	struct comedi_insn * insn, unsigned int * data);
268
269/*
270 * Attach is called by the Comedi core to configure the driver
271 * for a particular board.  If you specified a board_name array
272 * in the driver structure, dev->board_ptr contains that
273 * address.
274 */
275static int s526_attach(struct comedi_device * dev, struct comedi_devconfig * it)
276{
277	struct comedi_subdevice *s;
278	int iobase;
279	int i, n;
280//      short value;
281//      int subdev_channel = 0;
282
283	printk("comedi%d: s526: ", dev->minor);
284
285	iobase = it->options[0];
286	if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) {
287		comedi_error(dev, "I/O port conflict");
288		return -EIO;
289	}
290	dev->iobase = iobase;
291
292	printk("iobase=0x%lx\n", dev->iobase);
293
294	/*** make it a little quieter, exw, 8/29/06
295	for (i = 0; i < S526_NUM_PORTS; i++) {
296		printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i])));
297	}
298	***/
299
300/*
301 * Initialize dev->board_name.  Note that we can use the "thisboard"
302 * macro now, since we just initialized it in the last line.
303 */
304	dev->board_ptr = &s526_boards[0];
305
306	dev->board_name = thisboard->name;
307
308/*
309 * Allocate the private structure area.  alloc_private() is a
310 * convenient macro defined in comedidev.h.
311 */
312	if (alloc_private(dev, sizeof(struct s526_private)) < 0)
313		return -ENOMEM;
314
315/*
316 * Allocate the subdevice structures.  alloc_subdevice() is a
317 * convenient macro defined in comedidev.h.
318 */
319	dev->n_subdevices = 4;
320	if (alloc_subdevices(dev, dev->n_subdevices) < 0)
321		return -ENOMEM;
322
323	s = dev->subdevices + 0;
324	/* GENERAL-PURPOSE COUNTER/TIME (GPCT) */
325	s->type = COMEDI_SUBD_COUNTER;
326	s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL;
327	/* KG: What does SDF_LSAMPL (see multiq3.c) mean? */
328	s->n_chan = thisboard->gpct_chans;
329	s->maxdata = 0x00ffffff;	/* 24 bit counter */
330	s->insn_read = s526_gpct_rinsn;
331	s->insn_config = s526_gpct_insn_config;
332	s->insn_write = s526_gpct_winsn;
333
334	/* Command are not implemented yet, however they are necessary to
335	   allocate the necessary memory for the comedi_async struct (used
336	   to trigger the GPCT in case of pulsegenerator function */
337	//s->do_cmd = s526_gpct_cmd;
338	//s->do_cmdtest = s526_gpct_cmdtest;
339	//s->cancel = s526_gpct_cancel;
340
341	s = dev->subdevices + 1;
342	//dev->read_subdev=s;
343	/* analog input subdevice */
344	s->type = COMEDI_SUBD_AI;
345	/* we support differential */
346	s->subdev_flags = SDF_READABLE | SDF_DIFF;
347	/* channels 0 to 7 are the regular differential inputs */
348	/* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */
349	s->n_chan = 10;
350	s->maxdata = 0xffff;
351	s->range_table = &range_bipolar10;
352	s->len_chanlist = 16;	/* This is the maximum chanlist length that
353				   the board can handle */
354	s->insn_read = s526_ai_rinsn;
355	s->insn_config = s526_ai_insn_config;
356
357	s = dev->subdevices + 2;
358	/* analog output subdevice */
359	s->type = COMEDI_SUBD_AO;
360	s->subdev_flags = SDF_WRITABLE;
361	s->n_chan = 4;
362	s->maxdata = 0xffff;
363	s->range_table = &range_bipolar10;
364	s->insn_write = s526_ao_winsn;
365	s->insn_read = s526_ao_rinsn;
366
367	s = dev->subdevices + 3;
368	/* digital i/o subdevice */
369	if (thisboard->have_dio) {
370		s->type = COMEDI_SUBD_DIO;
371		s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
372		s->n_chan = 2;
373		s->maxdata = 1;
374		s->range_table = &range_digital;
375		s->insn_bits = s526_dio_insn_bits;
376		s->insn_config = s526_dio_insn_config;
377	} else {
378		s->type = COMEDI_SUBD_UNUSED;
379	}
380
381	printk("attached\n");
382
383	return 1;
384
385#if 0
386	// Example of Counter Application
387	//One-shot (software trigger)
388	cmReg.reg.coutSource = 0;	// out RCAP
389	cmReg.reg.coutPolarity = 1;	// Polarity inverted
390	cmReg.reg.autoLoadResetRcap = 1;	// Auto load 0:disabled, 1:enabled
391	cmReg.reg.hwCtEnableSource = 3;	// NOT RCAP
392	cmReg.reg.ctEnableCtrl = 2;	// Hardware
393	cmReg.reg.clockSource = 2;	// Internal
394	cmReg.reg.countDir = 1;	// Down
395	cmReg.reg.countDirCtrl = 1;	// Software
396	cmReg.reg.outputRegLatchCtrl = 0;	// latch on read
397	cmReg.reg.preloadRegSel = 0;	// PR0
398	cmReg.reg.reserved = 0;
399
400	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
401
402	outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
403	outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
404
405	outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Reset the counter
406	outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Load the counter from PR0
407
408	outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Reset RCAP (fires one-shot)
409
410#else
411
412	// Set Counter Mode Register
413	cmReg.reg.coutSource = 0;	// out RCAP
414	cmReg.reg.coutPolarity = 0;	// Polarity inverted
415	cmReg.reg.autoLoadResetRcap = 0;	// Auto load disabled
416	cmReg.reg.hwCtEnableSource = 2;	// NOT RCAP
417	cmReg.reg.ctEnableCtrl = 1;	// 1: Software,  >1 : Hardware
418	cmReg.reg.clockSource = 3;	// x4
419	cmReg.reg.countDir = 0;	// up
420	cmReg.reg.countDirCtrl = 0;	// quadrature
421	cmReg.reg.outputRegLatchCtrl = 0;	// latch on read
422	cmReg.reg.preloadRegSel = 0;	// PR0
423	cmReg.reg.reserved = 0;
424
425	n = 0;
426	printk("Mode reg=0x%04x, 0x%04lx\n", cmReg.value, ADDR_CHAN_REG(REG_C0M,
427			n));
428	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
429	udelay(1000);
430	printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
431
432	// Load the pre-laod register high word
433//                      value = (short) (0x55);
434//                      outw(value, ADDR_CHAN_REG(REG_C0H, n));
435
436	// Load the pre-laod register low word
437//                      value = (short)(0xaa55);
438//                      outw(value, ADDR_CHAN_REG(REG_C0L, n));
439
440	// Write the Counter Control Register
441//                      outw(value, ADDR_CHAN_REG(REG_C0C, 0));
442
443	// Reset the counter if it is software preload
444	if (cmReg.reg.autoLoadResetRcap == 0) {
445		outw(0x8000, ADDR_CHAN_REG(REG_C0C, n));	// Reset the counter
446		outw(0x4000, ADDR_CHAN_REG(REG_C0C, n));	// Load the counter from PR0
447	}
448
449	outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n));
450	udelay(1000);
451	printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n)));
452
453#endif
454	printk("Current registres:\n");
455
456	for (i = 0; i < S526_NUM_PORTS; i++) {
457		printk("0x%02lx: 0x%04x\n", ADDR_REG(s526_ports[i]),
458			inw(ADDR_REG(s526_ports[i])));
459	}
460	return 1;
461}
462
463/*
464 * _detach is called to deconfigure a device.  It should deallocate
465 * resources.
466 * This function is also called when _attach() fails, so it should be
467 * careful not to release resources that were not necessarily
468 * allocated by _attach().  dev->private and dev->subdevices are
469 * deallocated automatically by the core.
470 */
471static int s526_detach(struct comedi_device * dev)
472{
473	printk("comedi%d: s526: remove\n", dev->minor);
474
475	if (dev->iobase > 0)
476		release_region(dev->iobase, S526_IOSIZE);
477
478	return 0;
479}
480
481static int s526_gpct_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
482	struct comedi_insn * insn, unsigned int * data)
483{
484	int i;			// counts the Data
485	int counter_channel = CR_CHAN(insn->chanspec);
486	unsigned short datalow;
487	unsigned short datahigh;
488
489	// Check if (n > 0)
490	if (insn->n <= 0) {
491		printk("s526: INSN_READ: n should be > 0\n");
492		return -EINVAL;
493	}
494	// Read the low word first
495	for (i = 0; i < insn->n; i++) {
496		datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel));
497		datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel));
498		data[i] = (int)(datahigh & 0x00FF);
499		data[i] = (data[i] << 16) | (datalow & 0xFFFF);
500//              printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow);
501	}
502	return i;
503}
504
505static int s526_gpct_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
506	struct comedi_insn * insn, unsigned int * data)
507{
508	int subdev_channel = CR_CHAN(insn->chanspec);	// Unpack chanspec
509	int i;
510	short value;
511
512//        printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel);
513
514	for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) {
515		devpriv->s526_gpct_config[subdev_channel].data[i] =
516			insn->data[i];
517//              printk("data[%d]=%x\n", i, insn->data[i]);
518	}
519
520	// Check what type of Counter the user requested, data[0] contains
521	// the Application type
522	switch (insn->data[0]) {
523	case INSN_CONFIG_GPCT_QUADRATURE_ENCODER:
524		/*
525		   data[0]: Application Type
526		   data[1]: Counter Mode Register Value
527		   data[2]: Pre-load Register Value
528		   data[3]: Conter Control Register
529		 */
530		printk("s526: GPCT_INSN_CONFIG: Configuring Encoder\n");
531		devpriv->s526_gpct_config[subdev_channel].app =
532			PositionMeasurement;
533
534/*
535			// Example of Counter Application
536			//One-shot (software trigger)
537			cmReg.reg.coutSource		= 0; // out RCAP
538			cmReg.reg.coutPolarity		= 1; // Polarity inverted
539			cmReg.reg.autoLoadResetRcap	= 0; // Auto load disabled
540			cmReg.reg.hwCtEnableSource	= 3; // NOT RCAP
541			cmReg.reg.ctEnableCtrl		= 2; // Hardware
542			cmReg.reg.clockSource		= 2; // Internal
543			cmReg.reg.countDir		= 1; // Down
544			cmReg.reg.countDirCtrl		= 1; // Software
545			cmReg.reg.outputRegLatchCtrl	= 0; // latch on read
546			cmReg.reg.preloadRegSel		= 0; // PR0
547			cmReg.reg.reserved		= 0;
548
549			outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
550
551			outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel));
552			outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel));
553
554			outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Reset the counter
555			outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Load the counter from PR0
556
557			outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel));  // Reset RCAP (fires one-shot)
558
559*/
560
561#if 1
562		// Set Counter Mode Register
563		cmReg.reg.coutSource = 0;	// out RCAP
564		cmReg.reg.coutPolarity = 0;	// Polarity inverted
565		cmReg.reg.autoLoadResetRcap = 0;	// Auto load disabled
566		cmReg.reg.hwCtEnableSource = 2;	// NOT RCAP
567		cmReg.reg.ctEnableCtrl = 1;	// 1: Software,  >1 : Hardware
568		cmReg.reg.clockSource = 3;	// x4
569		cmReg.reg.countDir = 0;	// up
570		cmReg.reg.countDirCtrl = 0;	// quadrature
571		cmReg.reg.outputRegLatchCtrl = 0;	// latch on read
572		cmReg.reg.preloadRegSel = 0;	// PR0
573		cmReg.reg.reserved = 0;
574
575		// Set Counter Mode Register
576//                      printk("s526: Counter Mode register=%x\n", cmReg.value);
577		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
578
579		// Reset the counter if it is software preload
580		if (cmReg.reg.autoLoadResetRcap == 0) {
581			outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Reset the counter
582//                              outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));   // Load the counter from PR0
583		}
584#else
585		cmReg.reg.countDirCtrl = 0;	// 0 quadrature, 1 software control
586
587		// data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4
588		if (insn->data[1] == GPCT_X2) {
589			cmReg.reg.clockSource = 1;
590		} else if (insn->data[1] == GPCT_X4) {
591			cmReg.reg.clockSource = 2;
592		} else {
593			cmReg.reg.clockSource = 0;
594		}
595
596		// When to take into account the indexpulse:
597		if (insn->data[2] == GPCT_IndexPhaseLowLow) {
598		} else if (insn->data[2] == GPCT_IndexPhaseLowHigh) {
599		} else if (insn->data[2] == GPCT_IndexPhaseHighLow) {
600		} else if (insn->data[2] == GPCT_IndexPhaseHighHigh) {
601		}
602		// Take into account the index pulse?
603		if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX)
604			cmReg.reg.autoLoadResetRcap = 4;	// Auto load with INDEX^
605
606		// Set Counter Mode Register
607		cmReg.value = (short) (insn->data[1] & 0xFFFF);
608		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
609
610		// Load the pre-laod register high word
611		value = (short) ((insn->data[2] >> 16) & 0xFFFF);
612		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
613
614		// Load the pre-laod register low word
615		value = (short) (insn->data[2] & 0xFFFF);
616		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
617
618		// Write the Counter Control Register
619		if (insn->data[3] != 0) {
620			value = (short) (insn->data[3] & 0xFFFF);
621			outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
622		}
623		// Reset the counter if it is software preload
624		if (cmReg.reg.autoLoadResetRcap == 0) {
625			outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Reset the counter
626			outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel));	// Load the counter from PR0
627		}
628#endif
629		break;
630
631	case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR:
632		/*
633		   data[0]: Application Type
634		   data[1]: Counter Mode Register Value
635		   data[2]: Pre-load Register 0 Value
636		   data[3]: Pre-load Register 1 Value
637		   data[4]: Conter Control Register
638		 */
639		printk("s526: GPCT_INSN_CONFIG: Configuring SPG\n");
640		devpriv->s526_gpct_config[subdev_channel].app =
641			SinglePulseGeneration;
642
643		// Set Counter Mode Register
644		cmReg.value = (short) (insn->data[1] & 0xFFFF);
645		cmReg.reg.preloadRegSel = 0;	// PR0
646		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
647
648		// Load the pre-laod register 0 high word
649		value = (short) ((insn->data[2] >> 16) & 0xFFFF);
650		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
651
652		// Load the pre-laod register 0 low word
653		value = (short) (insn->data[2] & 0xFFFF);
654		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
655
656		// Set Counter Mode Register
657		cmReg.value = (short) (insn->data[1] & 0xFFFF);
658		cmReg.reg.preloadRegSel = 1;	// PR1
659		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
660
661		// Load the pre-laod register 1 high word
662		value = (short) ((insn->data[3] >> 16) & 0xFFFF);
663		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
664
665		// Load the pre-laod register 1 low word
666		value = (short) (insn->data[3] & 0xFFFF);
667		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
668
669		// Write the Counter Control Register
670		if (insn->data[3] != 0) {
671			value = (short) (insn->data[3] & 0xFFFF);
672			outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
673		}
674		break;
675
676	case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR:
677		/*
678		   data[0]: Application Type
679		   data[1]: Counter Mode Register Value
680		   data[2]: Pre-load Register 0 Value
681		   data[3]: Pre-load Register 1 Value
682		   data[4]: Conter Control Register
683		 */
684		printk("s526: GPCT_INSN_CONFIG: Configuring PTG\n");
685		devpriv->s526_gpct_config[subdev_channel].app =
686			PulseTrainGeneration;
687
688		// Set Counter Mode Register
689		cmReg.value = (short) (insn->data[1] & 0xFFFF);
690		cmReg.reg.preloadRegSel = 0;	// PR0
691		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
692
693		// Load the pre-laod register 0 high word
694		value = (short) ((insn->data[2] >> 16) & 0xFFFF);
695		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
696
697		// Load the pre-laod register 0 low word
698		value = (short) (insn->data[2] & 0xFFFF);
699		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
700
701		// Set Counter Mode Register
702		cmReg.value = (short) (insn->data[1] & 0xFFFF);
703		cmReg.reg.preloadRegSel = 1;	// PR1
704		outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel));
705
706		// Load the pre-laod register 1 high word
707		value = (short) ((insn->data[3] >> 16) & 0xFFFF);
708		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
709
710		// Load the pre-laod register 1 low word
711		value = (short) (insn->data[3] & 0xFFFF);
712		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
713
714		// Write the Counter Control Register
715		if (insn->data[3] != 0) {
716			value = (short) (insn->data[3] & 0xFFFF);
717			outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel));
718		}
719		break;
720
721	default:
722		printk("s526: unsupported GPCT_insn_config\n");
723		return -EINVAL;
724		break;
725	}
726
727	return insn->n;
728}
729
730static int s526_gpct_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
731	struct comedi_insn * insn, unsigned int * data)
732{
733	int subdev_channel = CR_CHAN(insn->chanspec);	// Unpack chanspec
734	short value;
735
736	printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel);
737	cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel));
738	printk("s526: Counter Mode Register: %x\n", cmReg.value);
739	// Check what Application of Counter this channel is configured for
740	switch (devpriv->s526_gpct_config[subdev_channel].app) {
741	case PositionMeasurement:
742		printk("S526: INSN_WRITE: PM\n");
743		outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
744				subdev_channel));
745		outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
746		break;
747
748	case SinglePulseGeneration:
749		printk("S526: INSN_WRITE: SPG\n");
750		outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H,
751				subdev_channel));
752		outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel));
753		break;
754
755	case PulseTrainGeneration:
756		/* data[0] contains the PULSE_WIDTH
757		   data[1] contains the PULSE_PERIOD
758		   @pre PULSE_PERIOD > PULSE_WIDTH > 0
759		   The above periods must be expressed as a multiple of the
760		   pulse frequency on the selected source
761		 */
762		printk("S526: INSN_WRITE: PTG\n");
763		if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) {
764			(devpriv->s526_gpct_config[subdev_channel]).data[0] =
765				insn->data[0];
766			(devpriv->s526_gpct_config[subdev_channel]).data[1] =
767				insn->data[1];
768		} else {
769			printk("%d \t %d\n", insn->data[1], insn->data[2]);
770			printk("s526: INSN_WRITE: PTG: Problem with Pulse params\n");
771			return -EINVAL;
772		}
773
774		value = (short) ((*data >> 16) & 0xFFFF);
775		outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel));
776		value = (short) (*data & 0xFFFF);
777		outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel));
778		break;
779	default:		// Impossible
780		printk("s526: INSN_WRITE: Functionality %d not implemented yet\n", devpriv->s526_gpct_config[subdev_channel].app);
781		return -EINVAL;
782		break;
783	}
784	// return the number of samples written
785	return insn->n;
786}
787
788#define ISR_ADC_DONE 0x4
789static int s526_ai_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
790	struct comedi_insn * insn, unsigned int * data)
791{
792	int result = -EINVAL;
793
794	if (insn->n < 1)
795		return result;
796
797	result = insn->n;
798
799	/* data[0] : channels was set in relevant bits.
800	   data[1] : delay
801	 */
802	/* COMMENT: abbotti 2008-07-24: I don't know why you'd want to
803	 * enable channels here.  The channel should be enabled in the
804	 * INSN_READ handler. */
805
806	// Enable ADC interrupt
807	outw(ISR_ADC_DONE, ADDR_REG(REG_IER));
808//      printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC)));
809	devpriv->s526_ai_config = (data[0] & 0x3FF) << 5;
810	if (data[1] > 0)
811		devpriv->s526_ai_config |= 0x8000;	//set the delay
812
813	devpriv->s526_ai_config |= 0x0001;	// ADC start bit.
814
815	return result;
816}
817
818/*
819 * "instructions" read/write data in "one-shot" or "software-triggered"
820 * mode.
821 */
822static int s526_ai_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
823	struct comedi_insn * insn, unsigned int * data)
824{
825	int n, i;
826	int chan = CR_CHAN(insn->chanspec);
827	unsigned short value;
828	unsigned int d;
829	unsigned int status;
830
831	/* Set configured delay, enable channel for this channel only,
832	 * select "ADC read" channel, set "ADC start" bit. */
833	value = (devpriv->s526_ai_config & 0x8000) |
834		((1 << 5) << chan) | (chan << 1) | 0x0001;
835
836	/* convert n samples */
837	for (n = 0; n < insn->n; n++) {
838		/* trigger conversion */
839		outw(value, ADDR_REG(REG_ADC));
840//              printk("s526: Wrote 0x%04x to ADC\n", value);
841//              printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC)));
842
843#define TIMEOUT 100
844		/* wait for conversion to end */
845		for (i = 0; i < TIMEOUT; i++) {
846			status = inw(ADDR_REG(REG_ISR));
847			if (status & ISR_ADC_DONE) {
848				outw(ISR_ADC_DONE, ADDR_REG(REG_ISR));
849				break;
850			}
851		}
852		if (i == TIMEOUT) {
853			/* rt_printk() should be used instead of printk()
854			 * whenever the code can be called from real-time. */
855			rt_printk("s526: ADC(0x%04x) timeout\n",
856				inw(ADDR_REG(REG_ISR)));
857			return -ETIMEDOUT;
858		}
859
860		/* read data */
861		d = inw(ADDR_REG(REG_ADD));
862//              printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF));
863
864		/* munge data */
865		data[n] = d ^ 0x8000;
866	}
867
868	/* return the number of samples read/written */
869	return n;
870}
871
872static int s526_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s,
873	struct comedi_insn * insn, unsigned int * data)
874{
875	int i;
876	int chan = CR_CHAN(insn->chanspec);
877	unsigned short val;
878
879//      printk("s526_ao_winsn\n");
880	val = chan << 1;
881//      outw(val, dev->iobase + REG_DAC);
882	outw(val, ADDR_REG(REG_DAC));
883
884	/* Writing a list of values to an AO channel is probably not
885	 * very useful, but that's how the interface is defined. */
886	for (i = 0; i < insn->n; i++) {
887		/* a typical programming sequence */
888//              outw(data[i], dev->iobase + REG_ADD);  // write the data to preload register
889		outw(data[i], ADDR_REG(REG_ADD));	// write the data to preload register
890		devpriv->ao_readback[chan] = data[i];
891//              outw(val + 1, dev->iobase + REG_DAC); // starts the D/A conversion.
892		outw(val + 1, ADDR_REG(REG_DAC));	// starts the D/A conversion.
893	}
894
895	/* return the number of samples read/written */
896	return i;
897}
898
899/* AO subdevices should have a read insn as well as a write insn.
900 * Usually this means copying a value stored in devpriv. */
901static int s526_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s,
902	struct comedi_insn * insn, unsigned int * data)
903{
904	int i;
905	int chan = CR_CHAN(insn->chanspec);
906
907	for (i = 0; i < insn->n; i++)
908		data[i] = devpriv->ao_readback[chan];
909
910	return i;
911}
912
913/* DIO devices are slightly special.  Although it is possible to
914 * implement the insn_read/insn_write interface, it is much more
915 * useful to applications if you implement the insn_bits interface.
916 * This allows packed reading/writing of the DIO channels.  The
917 * comedi core can convert between insn_bits and insn_read/write */
918static int s526_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s,
919	struct comedi_insn * insn, unsigned int * data)
920{
921	if (insn->n != 2)
922		return -EINVAL;
923
924	/* The insn data is a mask in data[0] and the new data
925	 * in data[1], each channel cooresponding to a bit. */
926	if (data[0]) {
927		s->state &= ~data[0];
928		s->state |= data[0] & data[1];
929		/* Write out the new digital output lines */
930		outw(s->state, ADDR_REG(REG_DIO));
931	}
932
933	/* on return, data[1] contains the value of the digital
934	 * input and output lines. */
935	data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF;	// low 8 bits are the data
936	/* or we could just return the software copy of the output values if
937	 * it was a purely digital output subdevice */
938	//data[1]=s->state;
939
940	return 2;
941}
942
943static int s526_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s,
944	struct comedi_insn * insn, unsigned int * data)
945{
946	int chan = CR_CHAN(insn->chanspec);
947	short value;
948
949	printk("S526 DIO insn_config\n");
950
951	if (insn->n != 1)
952		return -EINVAL;
953
954	value = inw(ADDR_REG(REG_DIO));
955
956	/* The input or output configuration of each digital line is
957	 * configured by a special insn_config instruction.  chanspec
958	 * contains the channel to be changed, and data[0] contains the
959	 * value COMEDI_INPUT or COMEDI_OUTPUT. */
960
961	if (data[0] == COMEDI_OUTPUT) {
962		value |= 1 << (chan + 10);	// bit 10/11 set the group 1/2's mode
963		s->io_bits |= (0xF << chan);
964	} else {
965		value &= ~(1 << (chan + 10));	// 1 is output, 0 is input.
966		s->io_bits &= ~(0xF << chan);
967	}
968	outw(value, ADDR_REG(REG_DIO));
969
970	return 1;
971}
972
973/*
974 * A convenient macro that defines init_module() and cleanup_module(),
975 * as necessary.
976 */
977COMEDI_INITCLEANUP(driver_s526);
978