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 /*
24 Driver: s526
25 Description: Sensoray 526 driver
26 Devices: [Sensoray] 526 (s526)
27 Author: Richie
28 	Everett Wang <everett.wang@everteq.com>
29 Updated: Thu, 14 Sep. 2006
30 Status: experimental
31 
32 Encoder works
33 Analog input works
34 Analog output works
35 PWM output works
36 Commands are not supported yet.
37 
38 Configuration Options:
39 
40 comedi_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 
86 static 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 
116 struct 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 
146 union 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! */
155 enum 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 */
166 struct 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  */
176 struct 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 
187 static 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 */
213 struct 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  */
239 static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it);
240 static int s526_detach(struct comedi_device *dev);
241 static 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 
269 static int s526_gpct_rinsn(struct comedi_device *dev,
270 			   struct comedi_subdevice *s, struct comedi_insn *insn,
271 			   unsigned int *data);
272 static int s526_gpct_insn_config(struct comedi_device *dev,
273 				 struct comedi_subdevice *s,
274 				 struct comedi_insn *insn, unsigned int *data);
275 static int s526_gpct_winsn(struct comedi_device *dev,
276 			   struct comedi_subdevice *s, struct comedi_insn *insn,
277 			   unsigned int *data);
278 static int s526_ai_insn_config(struct comedi_device *dev,
279 			       struct comedi_subdevice *s,
280 			       struct comedi_insn *insn, unsigned int *data);
281 static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
282 			 struct comedi_insn *insn, unsigned int *data);
283 static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
284 			 struct comedi_insn *insn, unsigned int *data);
285 static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
286 			 struct comedi_insn *insn, unsigned int *data);
287 static int s526_dio_insn_bits(struct comedi_device *dev,
288 			      struct comedi_subdevice *s,
289 			      struct comedi_insn *insn, unsigned int *data);
290 static 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  */
s526_attach(struct comedi_device * dev,struct comedi_devconfig * it)300 static 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  */
s526_detach(struct comedi_device * dev)504 static 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 
s526_gpct_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)514 static 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 
s526_gpct_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)540 static 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 
s526_gpct_winsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)766 static 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
s526_ai_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)830 static 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  */
s526_ai_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)864 static 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 
s526_ao_winsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)914 static 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. */
s526_ao_rinsn(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)946 static 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 */
s526_dio_insn_bits(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)963 static 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 
s526_dio_insn_config(struct comedi_device * dev,struct comedi_subdevice * s,struct comedi_insn * insn,unsigned int * data)989 static 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  */
driver_s526_init_module(void)1030 static int __init driver_s526_init_module(void)
1031 {
1032 	return comedi_driver_register(&driver_s526);
1033 }
1034 
driver_s526_cleanup_module(void)1035 static void __exit driver_s526_cleanup_module(void)
1036 {
1037 	comedi_driver_unregister(&driver_s526);
1038 }
1039 
1040 module_init(driver_s526_init_module);
1041 module_exit(driver_s526_cleanup_module);
1042 
1043 MODULE_AUTHOR("Comedi http://www.comedi.org");
1044 MODULE_DESCRIPTION("Comedi low-level driver");
1045 MODULE_LICENSE("GPL");
1046