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