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