Staging: comedi: Remove lsampl_t and sampl_t typedefs
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / staging / comedi / drivers / s526.c
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
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
85 static 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
115 typedef struct {
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 } counter_mode_register_t;
128
129 union {
130 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! */
138 typedef 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 */
149 typedef 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 */
159 typedef 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
170 static 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 comedi_device struct. */
194 typedef 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 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 */
218 static int s526_attach(comedi_device * dev, comedi_devconfig * it);
219 static int s526_detach(comedi_device * dev);
220 static 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
248 static int s526_gpct_rinsn(comedi_device * dev, comedi_subdevice * s,
249 comedi_insn * insn, unsigned int * data);
250 static int s526_gpct_insn_config(comedi_device * dev, comedi_subdevice * s,
251 comedi_insn * insn, unsigned int * data);
252 static int s526_gpct_winsn(comedi_device * dev, comedi_subdevice * s,
253 comedi_insn * insn, unsigned int * data);
254 static int s526_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
255 comedi_insn * insn, unsigned int * data);
256 static int s526_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
257 comedi_insn * insn, unsigned int * data);
258 static int s526_ao_winsn(comedi_device * dev, comedi_subdevice * s,
259 comedi_insn * insn, unsigned int * data);
260 static int s526_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
261 comedi_insn * insn, unsigned int * data);
262 static int s526_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
263 comedi_insn * insn, unsigned int * data);
264 static int s526_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
265 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 */
273 static int s526_attach(comedi_device * dev, comedi_devconfig * it)
274 {
275 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 */
469 static int s526_detach(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
479 static int s526_gpct_rinsn(comedi_device * dev, comedi_subdevice * s,
480 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
503 static int s526_gpct_insn_config(comedi_device * dev, comedi_subdevice * s,
504 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
728 static int s526_gpct_winsn(comedi_device * dev, comedi_subdevice * s,
729 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
787 static int s526_ai_insn_config(comedi_device * dev, comedi_subdevice * s,
788 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 */
820 static int s526_ai_rinsn(comedi_device * dev, comedi_subdevice * s,
821 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
870 static int s526_ao_winsn(comedi_device * dev, comedi_subdevice * s,
871 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. */
899 static int s526_ao_rinsn(comedi_device * dev, comedi_subdevice * s,
900 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 */
916 static int s526_dio_insn_bits(comedi_device * dev, comedi_subdevice * s,
917 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
941 static int s526_dio_insn_config(comedi_device * dev, comedi_subdevice * s,
942 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 */
975 COMEDI_INITCLEANUP(driver_s526);