Merge branch 'staging-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
[pandora-kernel.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 #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  */
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  */
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
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
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
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
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  */
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
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. */
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 */
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
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  */
1030 static int __init driver_s526_init_module(void)
1031 {
1032         return comedi_driver_register(&driver_s526);
1033 }
1034
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");