GNU Linux-libre 4.19.207-gnu1
[releases.git] / drivers / staging / comedi / drivers / dt282x.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * dt282x.c
4  * Comedi driver for Data Translation DT2821 series
5  *
6  * COMEDI - Linux Control and Measurement Device Interface
7  * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
8  */
9
10 /*
11  * Driver: dt282x
12  * Description: Data Translation DT2821 series (including DT-EZ)
13  * Author: ds
14  * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
15  *   DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
16  *   DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
17  *   DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
18  *   DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
19  *   DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
20  * Status: complete
21  * Updated: Wed, 22 Aug 2001 17:11:34 -0700
22  *
23  * Configuration options:
24  *   [0] - I/O port base address
25  *   [1] - IRQ (optional, required for async command support)
26  *   [2] - DMA 1 (optional, required for async command support)
27  *   [3] - DMA 2 (optional, required for async command support)
28  *   [4] - AI jumpered for 0=single ended, 1=differential
29  *   [5] - AI jumpered for 0=straight binary, 1=2's complement
30  *   [6] - AO 0 data format (deprecated, see below)
31  *   [7] - AO 1 data format (deprecated, see below)
32  *   [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
33  *   [9] - AO channel 0 range (deprecated, see below)
34  *   [10]- AO channel 1 range (deprecated, see below)
35  *
36  * Notes:
37  *   - AO commands might be broken.
38  *   - If you try to run a command on both the AI and AO subdevices
39  *     simultaneously, bad things will happen.  The driver needs to
40  *     be fixed to check for this situation and return an error.
41  *   - AO range is not programmable. The AO subdevice has a range_table
42  *     containing all the possible analog output ranges. Use the range
43  *     that matches your board configuration to convert between data
44  *     values and physical units. The format of the data written to the
45  *     board is handled automatically based on the unipolar/bipolar
46  *     range that is selected.
47  */
48
49 #include <linux/module.h>
50 #include <linux/delay.h>
51 #include <linux/gfp.h>
52 #include <linux/interrupt.h>
53 #include <linux/io.h>
54
55 #include "../comedidev.h"
56
57 #include "comedi_isadma.h"
58
59 /*
60  * Register map
61  */
62 #define DT2821_ADCSR_REG                0x00
63 #define DT2821_ADCSR_ADERR              BIT(15)
64 #define DT2821_ADCSR_ADCLK              BIT(9)
65 #define DT2821_ADCSR_MUXBUSY            BIT(8)
66 #define DT2821_ADCSR_ADDONE             BIT(7)
67 #define DT2821_ADCSR_IADDONE            BIT(6)
68 #define DT2821_ADCSR_GS(x)              (((x) & 0x3) << 4)
69 #define DT2821_ADCSR_CHAN(x)            (((x) & 0xf) << 0)
70 #define DT2821_CHANCSR_REG              0x02
71 #define DT2821_CHANCSR_LLE              BIT(15)
72 #define DT2821_CHANCSR_TO_PRESLA(x)     (((x) >> 8) & 0xf)
73 #define DT2821_CHANCSR_NUMB(x)          ((((x) - 1) & 0xf) << 0)
74 #define DT2821_ADDAT_REG                0x04
75 #define DT2821_DACSR_REG                0x06
76 #define DT2821_DACSR_DAERR              BIT(15)
77 #define DT2821_DACSR_YSEL(x)            ((x) << 9)
78 #define DT2821_DACSR_SSEL               BIT(8)
79 #define DT2821_DACSR_DACRDY             BIT(7)
80 #define DT2821_DACSR_IDARDY             BIT(6)
81 #define DT2821_DACSR_DACLK              BIT(5)
82 #define DT2821_DACSR_HBOE               BIT(1)
83 #define DT2821_DACSR_LBOE               BIT(0)
84 #define DT2821_DADAT_REG                0x08
85 #define DT2821_DIODAT_REG               0x0a
86 #define DT2821_SUPCSR_REG               0x0c
87 #define DT2821_SUPCSR_DMAD              BIT(15)
88 #define DT2821_SUPCSR_ERRINTEN          BIT(14)
89 #define DT2821_SUPCSR_CLRDMADNE         BIT(13)
90 #define DT2821_SUPCSR_DDMA              BIT(12)
91 #define DT2821_SUPCSR_DS(x)             (((x) & 0x3) << 10)
92 #define DT2821_SUPCSR_DS_PIO            DT2821_SUPCSR_DS(0)
93 #define DT2821_SUPCSR_DS_AD_CLK         DT2821_SUPCSR_DS(1)
94 #define DT2821_SUPCSR_DS_DA_CLK         DT2821_SUPCSR_DS(2)
95 #define DT2821_SUPCSR_DS_AD_TRIG        DT2821_SUPCSR_DS(3)
96 #define DT2821_SUPCSR_BUFFB             BIT(9)
97 #define DT2821_SUPCSR_SCDN              BIT(8)
98 #define DT2821_SUPCSR_DACON             BIT(7)
99 #define DT2821_SUPCSR_ADCINIT           BIT(6)
100 #define DT2821_SUPCSR_DACINIT           BIT(5)
101 #define DT2821_SUPCSR_PRLD              BIT(4)
102 #define DT2821_SUPCSR_STRIG             BIT(3)
103 #define DT2821_SUPCSR_XTRIG             BIT(2)
104 #define DT2821_SUPCSR_XCLK              BIT(1)
105 #define DT2821_SUPCSR_BDINIT            BIT(0)
106 #define DT2821_TMRCTR_REG               0x0e
107 #define DT2821_TMRCTR_PRESCALE(x)       (((x) & 0xf) << 8)
108 #define DT2821_TMRCTR_DIVIDER(x)        ((255 - ((x) & 0xff)) << 0)
109
110 /* Pacer Clock */
111 #define DT2821_OSC_BASE         250     /* 4 MHz (in nanoseconds) */
112 #define DT2821_PRESCALE(x)      BIT(x)
113 #define DT2821_PRESCALE_MAX     15
114 #define DT2821_DIVIDER_MAX      255
115 #define DT2821_OSC_MAX          (DT2821_OSC_BASE *                      \
116                                  DT2821_PRESCALE(DT2821_PRESCALE_MAX) * \
117                                  DT2821_DIVIDER_MAX)
118
119 static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
120         4, {
121                 BIP_RANGE(10),
122                 BIP_RANGE(5),
123                 BIP_RANGE(2.5),
124                 BIP_RANGE(1.25)
125         }
126 };
127
128 static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
129         4, {
130                 UNI_RANGE(10),
131                 UNI_RANGE(5),
132                 UNI_RANGE(2.5),
133                 UNI_RANGE(1.25)
134         }
135 };
136
137 static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
138         4, {
139                 BIP_RANGE(5),
140                 BIP_RANGE(2.5),
141                 BIP_RANGE(1.25),
142                 BIP_RANGE(0.625)
143         }
144 };
145
146 static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
147         4, {
148                 UNI_RANGE(5),
149                 UNI_RANGE(2.5),
150                 UNI_RANGE(1.25),
151                 UNI_RANGE(0.625)
152         }
153 };
154
155 static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
156         4, {
157                 BIP_RANGE(10),
158                 BIP_RANGE(1),
159                 BIP_RANGE(0.1),
160                 BIP_RANGE(0.02)
161         }
162 };
163
164 static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
165         4, {
166                 UNI_RANGE(10),
167                 UNI_RANGE(1),
168                 UNI_RANGE(0.1),
169                 UNI_RANGE(0.02)
170         }
171 };
172
173 /*
174  * The Analog Output range is set per-channel using jumpers on the board.
175  * All of these ranges may not be available on some DT2821 series boards.
176  * The default jumper setting has both channels set for +/-10V output.
177  */
178 static const struct comedi_lrange dt282x_ao_range = {
179         5, {
180                 BIP_RANGE(10),
181                 BIP_RANGE(5),
182                 BIP_RANGE(2.5),
183                 UNI_RANGE(10),
184                 UNI_RANGE(5),
185         }
186 };
187
188 struct dt282x_board {
189         const char *name;
190         unsigned int ai_maxdata;
191         int adchan_se;
192         int adchan_di;
193         int ai_speed;
194         int ispgl;
195         int dachan;
196         unsigned int ao_maxdata;
197 };
198
199 static const struct dt282x_board boardtypes[] = {
200         {
201                 .name           = "dt2821",
202                 .ai_maxdata     = 0x0fff,
203                 .adchan_se      = 16,
204                 .adchan_di      = 8,
205                 .ai_speed       = 20000,
206                 .dachan         = 2,
207                 .ao_maxdata     = 0x0fff,
208         }, {
209                 .name           = "dt2821-f",
210                 .ai_maxdata     = 0x0fff,
211                 .adchan_se      = 16,
212                 .adchan_di      = 8,
213                 .ai_speed       = 6500,
214                 .dachan         = 2,
215                 .ao_maxdata     = 0x0fff,
216         }, {
217                 .name           = "dt2821-g",
218                 .ai_maxdata     = 0x0fff,
219                 .adchan_se      = 16,
220                 .adchan_di      = 8,
221                 .ai_speed       = 4000,
222                 .dachan         = 2,
223                 .ao_maxdata     = 0x0fff,
224         }, {
225                 .name           = "dt2823",
226                 .ai_maxdata     = 0xffff,
227                 .adchan_di      = 4,
228                 .ai_speed       = 10000,
229                 .dachan         = 2,
230                 .ao_maxdata     = 0xffff,
231         }, {
232                 .name           = "dt2824-pgh",
233                 .ai_maxdata     = 0x0fff,
234                 .adchan_se      = 16,
235                 .adchan_di      = 8,
236                 .ai_speed       = 20000,
237         }, {
238                 .name           = "dt2824-pgl",
239                 .ai_maxdata     = 0x0fff,
240                 .adchan_se      = 16,
241                 .adchan_di      = 8,
242                 .ai_speed       = 20000,
243                 .ispgl          = 1,
244         }, {
245                 .name           = "dt2825",
246                 .ai_maxdata     = 0x0fff,
247                 .adchan_se      = 16,
248                 .adchan_di      = 8,
249                 .ai_speed       = 20000,
250                 .ispgl          = 1,
251                 .dachan         = 2,
252                 .ao_maxdata     = 0x0fff,
253         }, {
254                 .name           = "dt2827",
255                 .ai_maxdata     = 0xffff,
256                 .adchan_di      = 4,
257                 .ai_speed       = 10000,
258                 .dachan         = 2,
259                 .ao_maxdata     = 0x0fff,
260         }, {
261                 .name           = "dt2828",
262                 .ai_maxdata     = 0x0fff,
263                 .adchan_se      = 4,
264                 .ai_speed       = 10000,
265                 .dachan         = 2,
266                 .ao_maxdata     = 0x0fff,
267         }, {
268                 .name           = "dt2829",
269                 .ai_maxdata     = 0xffff,
270                 .adchan_se      = 8,
271                 .ai_speed       = 33250,
272                 .dachan         = 2,
273                 .ao_maxdata     = 0xffff,
274         }, {
275                 .name           = "dt21-ez",
276                 .ai_maxdata     = 0x0fff,
277                 .adchan_se      = 16,
278                 .adchan_di      = 8,
279                 .ai_speed       = 10000,
280                 .dachan         = 2,
281                 .ao_maxdata     = 0x0fff,
282         }, {
283                 .name           = "dt23-ez",
284                 .ai_maxdata     = 0xffff,
285                 .adchan_se      = 16,
286                 .adchan_di      = 8,
287                 .ai_speed       = 10000,
288         }, {
289                 .name           = "dt24-ez",
290                 .ai_maxdata     = 0x0fff,
291                 .adchan_se      = 16,
292                 .adchan_di      = 8,
293                 .ai_speed       = 10000,
294         }, {
295                 .name           = "dt24-ez-pgl",
296                 .ai_maxdata     = 0x0fff,
297                 .adchan_se      = 16,
298                 .adchan_di      = 8,
299                 .ai_speed       = 10000,
300                 .ispgl          = 1,
301         },
302 };
303
304 struct dt282x_private {
305         struct comedi_isadma *dma;
306         unsigned int ad_2scomp:1;
307         unsigned int divisor;
308         int dacsr;      /* software copies of registers */
309         int adcsr;
310         int supcsr;
311         int ntrig;
312         int nread;
313         int dma_dir;
314 };
315
316 static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
317 {
318         struct dt282x_private *devpriv = dev->private;
319         struct comedi_isadma *dma = devpriv->dma;
320         struct comedi_isadma_desc *desc = &dma->desc[dma_index];
321
322         if (!devpriv->ntrig)
323                 return 0;
324
325         if (n == 0)
326                 n = desc->maxsize;
327         if (n > devpriv->ntrig * 2)
328                 n = devpriv->ntrig * 2;
329         devpriv->ntrig -= n / 2;
330
331         desc->size = n;
332         comedi_isadma_set_mode(desc, devpriv->dma_dir);
333
334         comedi_isadma_program(desc);
335
336         return n;
337 }
338
339 static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
340 {
341         struct dt282x_private *devpriv = dev->private;
342         struct comedi_isadma *dma = devpriv->dma;
343         struct comedi_isadma_desc *desc = &dma->desc[dma_index];
344
345         desc->size = n;
346         comedi_isadma_set_mode(desc, devpriv->dma_dir);
347
348         comedi_isadma_program(desc);
349
350         return n;
351 }
352
353 static void dt282x_disable_dma(struct comedi_device *dev)
354 {
355         struct dt282x_private *devpriv = dev->private;
356         struct comedi_isadma *dma = devpriv->dma;
357         struct comedi_isadma_desc *desc;
358         int i;
359
360         for (i = 0; i < 2; i++) {
361                 desc = &dma->desc[i];
362                 comedi_isadma_disable(desc->chan);
363         }
364 }
365
366 static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
367 {
368         unsigned int prescale, base, divider;
369
370         for (prescale = 0; prescale <= DT2821_PRESCALE_MAX; prescale++) {
371                 if (prescale == 1)      /* 0 and 1 are both divide by 1 */
372                         continue;
373                 base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
374                 switch (flags & CMDF_ROUND_MASK) {
375                 case CMDF_ROUND_NEAREST:
376                 default:
377                         divider = DIV_ROUND_CLOSEST(*ns, base);
378                         break;
379                 case CMDF_ROUND_DOWN:
380                         divider = (*ns) / base;
381                         break;
382                 case CMDF_ROUND_UP:
383                         divider = DIV_ROUND_UP(*ns, base);
384                         break;
385                 }
386                 if (divider <= DT2821_DIVIDER_MAX)
387                         break;
388         }
389         if (divider > DT2821_DIVIDER_MAX) {
390                 prescale = DT2821_PRESCALE_MAX;
391                 divider = DT2821_DIVIDER_MAX;
392                 base = DT2821_OSC_BASE * DT2821_PRESCALE(prescale);
393         }
394         *ns = divider * base;
395         return DT2821_TMRCTR_PRESCALE(prescale) |
396                DT2821_TMRCTR_DIVIDER(divider);
397 }
398
399 static void dt282x_munge(struct comedi_device *dev,
400                          struct comedi_subdevice *s,
401                          unsigned short *buf,
402                          unsigned int nbytes)
403 {
404         struct dt282x_private *devpriv = dev->private;
405         unsigned int val;
406         int i;
407
408         if (nbytes % 2)
409                 dev_err(dev->class_dev,
410                         "bug! odd number of bytes from dma xfer\n");
411
412         for (i = 0; i < nbytes / 2; i++) {
413                 val = buf[i];
414                 val &= s->maxdata;
415                 if (devpriv->ad_2scomp)
416                         val = comedi_offset_munge(s, val);
417
418                 buf[i] = val;
419         }
420 }
421
422 static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
423                                         struct comedi_subdevice *s,
424                                         int cur_dma)
425 {
426         struct dt282x_private *devpriv = dev->private;
427         struct comedi_isadma *dma = devpriv->dma;
428         struct comedi_isadma_desc *desc = &dma->desc[cur_dma];
429         unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize);
430         unsigned int nbytes;
431
432         nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples);
433         if (nbytes)
434                 dt282x_prep_ao_dma(dev, cur_dma, nbytes);
435         else
436                 dev_err(dev->class_dev, "AO underrun\n");
437
438         return nbytes;
439 }
440
441 static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
442                                     struct comedi_subdevice *s)
443 {
444         struct dt282x_private *devpriv = dev->private;
445         struct comedi_isadma *dma = devpriv->dma;
446         struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
447
448         outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
449              dev->iobase + DT2821_SUPCSR_REG);
450
451         comedi_isadma_disable(desc->chan);
452
453         if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma))
454                 s->async->events |= COMEDI_CB_OVERFLOW;
455
456         dma->cur_dma = 1 - dma->cur_dma;
457 }
458
459 static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
460                                     struct comedi_subdevice *s)
461 {
462         struct dt282x_private *devpriv = dev->private;
463         struct comedi_isadma *dma = devpriv->dma;
464         struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
465         unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
466         int ret;
467
468         outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
469              dev->iobase + DT2821_SUPCSR_REG);
470
471         comedi_isadma_disable(desc->chan);
472
473         dt282x_munge(dev, s, desc->virt_addr, desc->size);
474         ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples);
475         if (ret != desc->size)
476                 return;
477
478         devpriv->nread -= nsamples;
479         if (devpriv->nread < 0) {
480                 dev_info(dev->class_dev, "nread off by one\n");
481                 devpriv->nread = 0;
482         }
483         if (!devpriv->nread) {
484                 s->async->events |= COMEDI_CB_EOA;
485                 return;
486         }
487 #if 0
488         /* clear the dual dma flag, making this the last dma segment */
489         /* XXX probably wrong */
490         if (!devpriv->ntrig) {
491                 devpriv->supcsr &= ~DT2821_SUPCSR_DDMA;
492                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
493         }
494 #endif
495         /* restart the channel */
496         dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
497
498         dma->cur_dma = 1 - dma->cur_dma;
499 }
500
501 static irqreturn_t dt282x_interrupt(int irq, void *d)
502 {
503         struct comedi_device *dev = d;
504         struct dt282x_private *devpriv = dev->private;
505         struct comedi_subdevice *s = dev->read_subdev;
506         struct comedi_subdevice *s_ao = dev->write_subdev;
507         unsigned int supcsr, adcsr, dacsr;
508         int handled = 0;
509
510         if (!dev->attached) {
511                 dev_err(dev->class_dev, "spurious interrupt\n");
512                 return IRQ_HANDLED;
513         }
514
515         adcsr = inw(dev->iobase + DT2821_ADCSR_REG);
516         dacsr = inw(dev->iobase + DT2821_DACSR_REG);
517         supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
518         if (supcsr & DT2821_SUPCSR_DMAD) {
519                 if (devpriv->dma_dir == COMEDI_ISADMA_READ)
520                         dt282x_ai_dma_interrupt(dev, s);
521                 else
522                         dt282x_ao_dma_interrupt(dev, s_ao);
523                 handled = 1;
524         }
525         if (adcsr & DT2821_ADCSR_ADERR) {
526                 if (devpriv->nread != 0) {
527                         dev_err(dev->class_dev, "A/D error\n");
528                         s->async->events |= COMEDI_CB_ERROR;
529                 }
530                 handled = 1;
531         }
532         if (dacsr & DT2821_DACSR_DAERR) {
533                 dev_err(dev->class_dev, "D/A error\n");
534                 s_ao->async->events |= COMEDI_CB_ERROR;
535                 handled = 1;
536         }
537 #if 0
538         if (adcsr & DT2821_ADCSR_ADDONE) {
539                 unsigned short data;
540
541                 data = inw(dev->iobase + DT2821_ADDAT_REG);
542                 data &= s->maxdata;
543                 if (devpriv->ad_2scomp)
544                         data = comedi_offset_munge(s, data);
545
546                 comedi_buf_write_samples(s, &data, 1);
547
548                 devpriv->nread--;
549                 if (!devpriv->nread) {
550                         s->async->events |= COMEDI_CB_EOA;
551                 } else {
552                         if (supcsr & DT2821_SUPCSR_SCDN)
553                                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
554                                      dev->iobase + DT2821_SUPCSR_REG);
555                 }
556                 handled = 1;
557         }
558 #endif
559         comedi_handle_events(dev, s);
560         if (s_ao)
561                 comedi_handle_events(dev, s_ao);
562
563         return IRQ_RETVAL(handled);
564 }
565
566 static void dt282x_load_changain(struct comedi_device *dev, int n,
567                                  unsigned int *chanlist)
568 {
569         struct dt282x_private *devpriv = dev->private;
570         int i;
571
572         outw(DT2821_CHANCSR_LLE | DT2821_CHANCSR_NUMB(n),
573              dev->iobase + DT2821_CHANCSR_REG);
574         for (i = 0; i < n; i++) {
575                 unsigned int chan = CR_CHAN(chanlist[i]);
576                 unsigned int range = CR_RANGE(chanlist[i]);
577
578                 outw(devpriv->adcsr |
579                      DT2821_ADCSR_GS(range) |
580                      DT2821_ADCSR_CHAN(chan),
581                      dev->iobase + DT2821_ADCSR_REG);
582         }
583         outw(DT2821_CHANCSR_NUMB(n), dev->iobase + DT2821_CHANCSR_REG);
584 }
585
586 static int dt282x_ai_timeout(struct comedi_device *dev,
587                              struct comedi_subdevice *s,
588                              struct comedi_insn *insn,
589                              unsigned long context)
590 {
591         unsigned int status;
592
593         status = inw(dev->iobase + DT2821_ADCSR_REG);
594         switch (context) {
595         case DT2821_ADCSR_MUXBUSY:
596                 if ((status & DT2821_ADCSR_MUXBUSY) == 0)
597                         return 0;
598                 break;
599         case DT2821_ADCSR_ADDONE:
600                 if (status & DT2821_ADCSR_ADDONE)
601                         return 0;
602                 break;
603         default:
604                 return -EINVAL;
605         }
606         return -EBUSY;
607 }
608
609 /*
610  *    Performs a single A/D conversion.
611  *      - Put channel/gain into channel-gain list
612  *      - preload multiplexer
613  *      - trigger conversion and wait for it to finish
614  */
615 static int dt282x_ai_insn_read(struct comedi_device *dev,
616                                struct comedi_subdevice *s,
617                                struct comedi_insn *insn,
618                                unsigned int *data)
619 {
620         struct dt282x_private *devpriv = dev->private;
621         unsigned int val;
622         int ret;
623         int i;
624
625         /* XXX should we really be enabling the ad clock here? */
626         devpriv->adcsr = DT2821_ADCSR_ADCLK;
627         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
628
629         dt282x_load_changain(dev, 1, &insn->chanspec);
630
631         outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
632              dev->iobase + DT2821_SUPCSR_REG);
633         ret = comedi_timeout(dev, s, insn,
634                              dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
635         if (ret)
636                 return ret;
637
638         for (i = 0; i < insn->n; i++) {
639                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
640                      dev->iobase + DT2821_SUPCSR_REG);
641
642                 ret = comedi_timeout(dev, s, insn,
643                                      dt282x_ai_timeout, DT2821_ADCSR_ADDONE);
644                 if (ret)
645                         return ret;
646
647                 val = inw(dev->iobase + DT2821_ADDAT_REG);
648                 val &= s->maxdata;
649                 if (devpriv->ad_2scomp)
650                         val = comedi_offset_munge(s, val);
651
652                 data[i] = val;
653         }
654
655         return i;
656 }
657
658 static int dt282x_ai_cmdtest(struct comedi_device *dev,
659                              struct comedi_subdevice *s,
660                              struct comedi_cmd *cmd)
661 {
662         const struct dt282x_board *board = dev->board_ptr;
663         struct dt282x_private *devpriv = dev->private;
664         int err = 0;
665         unsigned int arg;
666
667         /* Step 1 : check if triggers are trivially valid */
668
669         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
670         err |= comedi_check_trigger_src(&cmd->scan_begin_src,
671                                         TRIG_FOLLOW | TRIG_EXT);
672         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
673         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
674         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
675
676         if (err)
677                 return 1;
678
679         /* Step 2a : make sure trigger sources are unique */
680
681         err |= comedi_check_trigger_is_unique(cmd->scan_begin_src);
682         err |= comedi_check_trigger_is_unique(cmd->stop_src);
683
684         /* Step 2b : and mutually compatible */
685
686         if (err)
687                 return 2;
688
689         /* Step 3: check if arguments are trivially valid */
690
691         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
692         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
693         err |= comedi_check_trigger_arg_max(&cmd->convert_arg, DT2821_OSC_MAX);
694         err |= comedi_check_trigger_arg_min(&cmd->convert_arg, board->ai_speed);
695         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
696                                            cmd->chanlist_len);
697
698         if (cmd->stop_src == TRIG_COUNT)
699                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
700         else    /* TRIG_EXT | TRIG_NONE */
701                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
702
703         if (err)
704                 return 3;
705
706         /* step 4: fix up any arguments */
707
708         arg = cmd->convert_arg;
709         devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
710         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg);
711
712         if (err)
713                 return 4;
714
715         return 0;
716 }
717
718 static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
719 {
720         struct dt282x_private *devpriv = dev->private;
721         struct comedi_isadma *dma = devpriv->dma;
722         struct comedi_cmd *cmd = &s->async->cmd;
723         int ret;
724
725         dt282x_disable_dma(dev);
726
727         outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
728
729         devpriv->supcsr = DT2821_SUPCSR_ERRINTEN;
730         if (cmd->scan_begin_src == TRIG_FOLLOW)
731                 devpriv->supcsr = DT2821_SUPCSR_DS_AD_CLK;
732         else
733                 devpriv->supcsr = DT2821_SUPCSR_DS_AD_TRIG;
734         outw(devpriv->supcsr |
735              DT2821_SUPCSR_CLRDMADNE |
736              DT2821_SUPCSR_BUFFB |
737              DT2821_SUPCSR_ADCINIT,
738              dev->iobase + DT2821_SUPCSR_REG);
739
740         devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
741         devpriv->nread = devpriv->ntrig;
742
743         devpriv->dma_dir = COMEDI_ISADMA_READ;
744         dma->cur_dma = 0;
745         dt282x_prep_ai_dma(dev, 0, 0);
746         if (devpriv->ntrig) {
747                 dt282x_prep_ai_dma(dev, 1, 0);
748                 devpriv->supcsr |= DT2821_SUPCSR_DDMA;
749                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
750         }
751
752         devpriv->adcsr = 0;
753
754         dt282x_load_changain(dev, cmd->chanlist_len, cmd->chanlist);
755
756         devpriv->adcsr = DT2821_ADCSR_ADCLK | DT2821_ADCSR_IADDONE;
757         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
758
759         outw(devpriv->supcsr | DT2821_SUPCSR_PRLD,
760              dev->iobase + DT2821_SUPCSR_REG);
761         ret = comedi_timeout(dev, s, NULL,
762                              dt282x_ai_timeout, DT2821_ADCSR_MUXBUSY);
763         if (ret)
764                 return ret;
765
766         if (cmd->scan_begin_src == TRIG_FOLLOW) {
767                 outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
768                      dev->iobase + DT2821_SUPCSR_REG);
769         } else {
770                 devpriv->supcsr |= DT2821_SUPCSR_XTRIG;
771                 outw(devpriv->supcsr, dev->iobase + DT2821_SUPCSR_REG);
772         }
773
774         return 0;
775 }
776
777 static int dt282x_ai_cancel(struct comedi_device *dev,
778                             struct comedi_subdevice *s)
779 {
780         struct dt282x_private *devpriv = dev->private;
781
782         dt282x_disable_dma(dev);
783
784         devpriv->adcsr = 0;
785         outw(devpriv->adcsr, dev->iobase + DT2821_ADCSR_REG);
786
787         devpriv->supcsr = 0;
788         outw(devpriv->supcsr | DT2821_SUPCSR_ADCINIT,
789              dev->iobase + DT2821_SUPCSR_REG);
790
791         return 0;
792 }
793
794 static int dt282x_ao_insn_write(struct comedi_device *dev,
795                                 struct comedi_subdevice *s,
796                                 struct comedi_insn *insn,
797                                 unsigned int *data)
798 {
799         struct dt282x_private *devpriv = dev->private;
800         unsigned int chan = CR_CHAN(insn->chanspec);
801         unsigned int range = CR_RANGE(insn->chanspec);
802         int i;
803
804         devpriv->dacsr |= DT2821_DACSR_SSEL | DT2821_DACSR_YSEL(chan);
805
806         for (i = 0; i < insn->n; i++) {
807                 unsigned int val = data[i];
808
809                 s->readback[chan] = val;
810
811                 if (comedi_range_is_bipolar(s, range))
812                         val = comedi_offset_munge(s, val);
813
814                 outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
815
816                 outw(val, dev->iobase + DT2821_DADAT_REG);
817
818                 outw(devpriv->supcsr | DT2821_SUPCSR_DACON,
819                      dev->iobase + DT2821_SUPCSR_REG);
820         }
821
822         return insn->n;
823 }
824
825 static int dt282x_ao_cmdtest(struct comedi_device *dev,
826                              struct comedi_subdevice *s,
827                              struct comedi_cmd *cmd)
828 {
829         struct dt282x_private *devpriv = dev->private;
830         int err = 0;
831         unsigned int arg;
832
833         /* Step 1 : check if triggers are trivially valid */
834
835         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_INT);
836         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER);
837         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
838         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
839         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
840
841         if (err)
842                 return 1;
843
844         /* Step 2a : make sure trigger sources are unique */
845
846         err |= comedi_check_trigger_is_unique(cmd->stop_src);
847
848         /* Step 2b : and mutually compatible */
849
850         if (err)
851                 return 2;
852
853         /* Step 3: check if arguments are trivially valid */
854
855         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
856         err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 5000);
857         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
858         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
859                                            cmd->chanlist_len);
860
861         if (cmd->stop_src == TRIG_COUNT)
862                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
863         else    /* TRIG_EXT | TRIG_NONE */
864                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
865
866         if (err)
867                 return 3;
868
869         /* step 4: fix up any arguments */
870
871         arg = cmd->scan_begin_arg;
872         devpriv->divisor = dt282x_ns_to_timer(&arg, cmd->flags);
873         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg);
874
875         if (err)
876                 return 4;
877
878         return 0;
879 }
880
881 static int dt282x_ao_inttrig(struct comedi_device *dev,
882                              struct comedi_subdevice *s,
883                              unsigned int trig_num)
884 {
885         struct dt282x_private *devpriv = dev->private;
886         struct comedi_cmd *cmd = &s->async->cmd;
887
888         if (trig_num != cmd->start_src)
889                 return -EINVAL;
890
891         if (!dt282x_ao_setup_dma(dev, s, 0))
892                 return -EPIPE;
893
894         if (!dt282x_ao_setup_dma(dev, s, 1))
895                 return -EPIPE;
896
897         outw(devpriv->supcsr | DT2821_SUPCSR_STRIG,
898              dev->iobase + DT2821_SUPCSR_REG);
899         s->async->inttrig = NULL;
900
901         return 1;
902 }
903
904 static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
905 {
906         struct dt282x_private *devpriv = dev->private;
907         struct comedi_isadma *dma = devpriv->dma;
908         struct comedi_cmd *cmd = &s->async->cmd;
909
910         dt282x_disable_dma(dev);
911
912         devpriv->supcsr = DT2821_SUPCSR_ERRINTEN |
913                           DT2821_SUPCSR_DS_DA_CLK |
914                           DT2821_SUPCSR_DDMA;
915         outw(devpriv->supcsr |
916              DT2821_SUPCSR_CLRDMADNE |
917              DT2821_SUPCSR_BUFFB |
918              DT2821_SUPCSR_DACINIT,
919              dev->iobase + DT2821_SUPCSR_REG);
920
921         devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
922         devpriv->nread = devpriv->ntrig;
923
924         devpriv->dma_dir = COMEDI_ISADMA_WRITE;
925         dma->cur_dma = 0;
926
927         outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
928
929         /* clear all bits but the DIO direction bits */
930         devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
931
932         devpriv->dacsr |= (DT2821_DACSR_SSEL |
933                            DT2821_DACSR_DACLK |
934                            DT2821_DACSR_IDARDY);
935         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
936
937         s->async->inttrig = dt282x_ao_inttrig;
938
939         return 0;
940 }
941
942 static int dt282x_ao_cancel(struct comedi_device *dev,
943                             struct comedi_subdevice *s)
944 {
945         struct dt282x_private *devpriv = dev->private;
946
947         dt282x_disable_dma(dev);
948
949         /* clear all bits but the DIO direction bits */
950         devpriv->dacsr &= (DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
951
952         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
953
954         devpriv->supcsr = 0;
955         outw(devpriv->supcsr | DT2821_SUPCSR_DACINIT,
956              dev->iobase + DT2821_SUPCSR_REG);
957
958         return 0;
959 }
960
961 static int dt282x_dio_insn_bits(struct comedi_device *dev,
962                                 struct comedi_subdevice *s,
963                                 struct comedi_insn *insn,
964                                 unsigned int *data)
965 {
966         if (comedi_dio_update_state(s, data))
967                 outw(s->state, dev->iobase + DT2821_DIODAT_REG);
968
969         data[1] = inw(dev->iobase + DT2821_DIODAT_REG);
970
971         return insn->n;
972 }
973
974 static int dt282x_dio_insn_config(struct comedi_device *dev,
975                                   struct comedi_subdevice *s,
976                                   struct comedi_insn *insn,
977                                   unsigned int *data)
978 {
979         struct dt282x_private *devpriv = dev->private;
980         unsigned int chan = CR_CHAN(insn->chanspec);
981         unsigned int mask;
982         int ret;
983
984         if (chan < 8)
985                 mask = 0x00ff;
986         else
987                 mask = 0xff00;
988
989         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
990         if (ret)
991                 return ret;
992
993         devpriv->dacsr &= ~(DT2821_DACSR_LBOE | DT2821_DACSR_HBOE);
994         if (s->io_bits & 0x00ff)
995                 devpriv->dacsr |= DT2821_DACSR_LBOE;
996         if (s->io_bits & 0xff00)
997                 devpriv->dacsr |= DT2821_DACSR_HBOE;
998
999         outw(devpriv->dacsr, dev->iobase + DT2821_DACSR_REG);
1000
1001         return insn->n;
1002 }
1003
1004 static const struct comedi_lrange *const ai_range_table[] = {
1005         &range_dt282x_ai_lo_bipolar,
1006         &range_dt282x_ai_lo_unipolar,
1007         &range_dt282x_ai_5_bipolar,
1008         &range_dt282x_ai_5_unipolar
1009 };
1010
1011 static const struct comedi_lrange *const ai_range_pgl_table[] = {
1012         &range_dt282x_ai_hi_bipolar,
1013         &range_dt282x_ai_hi_unipolar
1014 };
1015
1016 static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
1017 {
1018         if (ispgl) {
1019                 if (x < 0 || x >= 2)
1020                         x = 0;
1021                 return ai_range_pgl_table[x];
1022         }
1023
1024         if (x < 0 || x >= 4)
1025                 x = 0;
1026         return ai_range_table[x];
1027 }
1028
1029 static void dt282x_alloc_dma(struct comedi_device *dev,
1030                              struct comedi_devconfig *it)
1031 {
1032         struct dt282x_private *devpriv = dev->private;
1033         unsigned int irq_num = it->options[1];
1034         unsigned int dma_chan[2];
1035
1036         if (it->options[2] < it->options[3]) {
1037                 dma_chan[0] = it->options[2];
1038                 dma_chan[1] = it->options[3];
1039         } else {
1040                 dma_chan[0] = it->options[3];
1041                 dma_chan[1] = it->options[2];
1042         }
1043
1044         if (!irq_num || dma_chan[0] == dma_chan[1] ||
1045             dma_chan[0] < 5 || dma_chan[0] > 7 ||
1046             dma_chan[1] < 5 || dma_chan[1] > 7)
1047                 return;
1048
1049         if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev))
1050                 return;
1051
1052         /* DMA uses two 4K buffers with separate DMA channels */
1053         devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1],
1054                                            PAGE_SIZE, 0);
1055         if (!devpriv->dma)
1056                 free_irq(irq_num, dev);
1057         else
1058                 dev->irq = irq_num;
1059 }
1060
1061 static void dt282x_free_dma(struct comedi_device *dev)
1062 {
1063         struct dt282x_private *devpriv = dev->private;
1064
1065         if (devpriv)
1066                 comedi_isadma_free(devpriv->dma);
1067 }
1068
1069 static int dt282x_initialize(struct comedi_device *dev)
1070 {
1071         /* Initialize board */
1072         outw(DT2821_SUPCSR_BDINIT, dev->iobase + DT2821_SUPCSR_REG);
1073         inw(dev->iobase + DT2821_ADCSR_REG);
1074
1075         /*
1076          * At power up, some registers are in a well-known state.
1077          * Check them to see if a DT2821 series board is present.
1078          */
1079         if (((inw(dev->iobase + DT2821_ADCSR_REG) & 0xfff0) != 0x7c00) ||
1080             ((inw(dev->iobase + DT2821_CHANCSR_REG) & 0xf0f0) != 0x70f0) ||
1081             ((inw(dev->iobase + DT2821_DACSR_REG) & 0x7c93) != 0x7c90) ||
1082             ((inw(dev->iobase + DT2821_SUPCSR_REG) & 0xf8ff) != 0x0000) ||
1083             ((inw(dev->iobase + DT2821_TMRCTR_REG) & 0xff00) != 0xf000)) {
1084                 dev_err(dev->class_dev, "board not found\n");
1085                 return -EIO;
1086         }
1087         return 0;
1088 }
1089
1090 static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
1091 {
1092         const struct dt282x_board *board = dev->board_ptr;
1093         struct dt282x_private *devpriv;
1094         struct comedi_subdevice *s;
1095         int ret;
1096
1097         ret = comedi_request_region(dev, it->options[0], 0x10);
1098         if (ret)
1099                 return ret;
1100
1101         ret = dt282x_initialize(dev);
1102         if (ret)
1103                 return ret;
1104
1105         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
1106         if (!devpriv)
1107                 return -ENOMEM;
1108
1109         /* an IRQ and 2 DMA channels are required for async command support */
1110         dt282x_alloc_dma(dev, it);
1111
1112         ret = comedi_alloc_subdevices(dev, 3);
1113         if (ret)
1114                 return ret;
1115
1116         /* Analog Input subdevice */
1117         s = &dev->subdevices[0];
1118         s->type         = COMEDI_SUBD_AI;
1119         s->subdev_flags = SDF_READABLE;
1120         if ((it->options[4] && board->adchan_di) || board->adchan_se == 0) {
1121                 s->subdev_flags |= SDF_DIFF;
1122                 s->n_chan       = board->adchan_di;
1123         } else {
1124                 s->subdev_flags |= SDF_COMMON;
1125                 s->n_chan       = board->adchan_se;
1126         }
1127         s->maxdata      = board->ai_maxdata;
1128
1129         s->range_table = opt_ai_range_lkup(board->ispgl, it->options[8]);
1130         devpriv->ad_2scomp = it->options[5] ? 1 : 0;
1131
1132         s->insn_read    = dt282x_ai_insn_read;
1133         if (dev->irq) {
1134                 dev->read_subdev = s;
1135                 s->subdev_flags |= SDF_CMD_READ;
1136                 s->len_chanlist = s->n_chan;
1137                 s->do_cmdtest   = dt282x_ai_cmdtest;
1138                 s->do_cmd       = dt282x_ai_cmd;
1139                 s->cancel       = dt282x_ai_cancel;
1140         }
1141
1142         /* Analog Output subdevice */
1143         s = &dev->subdevices[1];
1144         if (board->dachan) {
1145                 s->type         = COMEDI_SUBD_AO;
1146                 s->subdev_flags = SDF_WRITABLE;
1147                 s->n_chan       = board->dachan;
1148                 s->maxdata      = board->ao_maxdata;
1149                 /* ranges are per-channel, set by jumpers on the board */
1150                 s->range_table  = &dt282x_ao_range;
1151                 s->insn_write   = dt282x_ao_insn_write;
1152                 if (dev->irq) {
1153                         dev->write_subdev = s;
1154                         s->subdev_flags |= SDF_CMD_WRITE;
1155                         s->len_chanlist = s->n_chan;
1156                         s->do_cmdtest   = dt282x_ao_cmdtest;
1157                         s->do_cmd       = dt282x_ao_cmd;
1158                         s->cancel       = dt282x_ao_cancel;
1159                 }
1160
1161                 ret = comedi_alloc_subdev_readback(s);
1162                 if (ret)
1163                         return ret;
1164         } else {
1165                 s->type         = COMEDI_SUBD_UNUSED;
1166         }
1167
1168         /* Digital I/O subdevice */
1169         s = &dev->subdevices[2];
1170         s->type         = COMEDI_SUBD_DIO;
1171         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1172         s->n_chan       = 16;
1173         s->maxdata      = 1;
1174         s->range_table  = &range_digital;
1175         s->insn_bits    = dt282x_dio_insn_bits;
1176         s->insn_config  = dt282x_dio_insn_config;
1177
1178         return 0;
1179 }
1180
1181 static void dt282x_detach(struct comedi_device *dev)
1182 {
1183         dt282x_free_dma(dev);
1184         comedi_legacy_detach(dev);
1185 }
1186
1187 static struct comedi_driver dt282x_driver = {
1188         .driver_name    = "dt282x",
1189         .module         = THIS_MODULE,
1190         .attach         = dt282x_attach,
1191         .detach         = dt282x_detach,
1192         .board_name     = &boardtypes[0].name,
1193         .num_names      = ARRAY_SIZE(boardtypes),
1194         .offset         = sizeof(struct dt282x_board),
1195 };
1196 module_comedi_driver(dt282x_driver);
1197
1198 MODULE_AUTHOR("Comedi http://www.comedi.org");
1199 MODULE_DESCRIPTION("Comedi driver for Data Translation DT2821 series");
1200 MODULE_LICENSE("GPL");