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