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