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