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