GNU Linux-libre 6.7.9-gnu
[releases.git] / drivers / comedi / drivers / pcmmio.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * pcmmio.c
4  * Driver for Winsystems PC-104 based multifunction IO board.
5  *
6  * COMEDI - Linux Control and Measurement Device Interface
7  * Copyright (C) 2007 Calin A. Culianu <calin@ajvar.org>
8  */
9
10 /*
11  * Driver: pcmmio
12  * Description: A driver for the PCM-MIO multifunction board
13  * Devices: [Winsystems] PCM-MIO (pcmmio)
14  * Author: Calin Culianu <calin@ajvar.org>
15  * Updated: Wed, May 16 2007 16:21:10 -0500
16  * Status: works
17  *
18  * A driver for the PCM-MIO multifunction board from Winsystems. This
19  * is a PC-104 based I/O board. It contains four subdevices:
20  *
21  *      subdevice 0 - 16 channels of 16-bit AI
22  *      subdevice 1 - 8 channels of 16-bit AO
23  *      subdevice 2 - first 24 channels of the 48 channel of DIO
24  *                      (with edge-triggered interrupt support)
25  *      subdevice 3 - last 24 channels of the 48 channel DIO
26  *                      (no interrupt support for this bank of channels)
27  *
28  * Some notes:
29  *
30  * Synchronous reads and writes are the only things implemented for analog
31  * input and output. The hardware itself can do streaming acquisition, etc.
32  *
33  * Asynchronous I/O for the DIO subdevices *is* implemented, however! They
34  * are basically edge-triggered interrupts for any configuration of the
35  * channels in subdevice 2.
36  *
37  * Also note that this interrupt support is untested.
38  *
39  * A few words about edge-detection IRQ support (commands on DIO):
40  *
41  * To use edge-detection IRQ support for the DIO subdevice, pass the IRQ
42  * of the board to the comedi_config command. The board IRQ is not jumpered
43  * but rather configured through software, so any IRQ from 1-15 is OK.
44  *
45  * Due to the genericity of the comedi API, you need to create a special
46  * comedi_command in order to use edge-triggered interrupts for DIO.
47  *
48  * Use comedi_commands with TRIG_NOW.  Your callback will be called each
49  * time an edge is detected on the specified DIO line(s), and the data
50  * values will be two sample_t's, which should be concatenated to form
51  * one 32-bit unsigned int. This value is the mask of channels that had
52  * edges detected from your channel list. Note that the bits positions
53  * in the mask correspond to positions in your chanlist when you
54  * specified the command and *not* channel id's!
55  *
56  * To set the polarity of the edge-detection interrupts pass a nonzero value
57  * for either CR_RANGE or CR_AREF for edge-up polarity, or a zero
58  * value for both CR_RANGE and CR_AREF if you want edge-down polarity.
59  *
60  * Configuration Options:
61  *   [0] - I/O port base address
62  *   [1] - IRQ (optional -- for edge-detect interrupt support only,
63  *              leave out if you don't need this feature)
64  */
65
66 #include <linux/module.h>
67 #include <linux/interrupt.h>
68 #include <linux/slab.h>
69 #include <linux/comedi/comedidev.h>
70
71 /*
72  * Register I/O map
73  */
74 #define PCMMIO_AI_LSB_REG                       0x00
75 #define PCMMIO_AI_MSB_REG                       0x01
76 #define PCMMIO_AI_CMD_REG                       0x02
77 #define PCMMIO_AI_CMD_SE                        BIT(7)
78 #define PCMMIO_AI_CMD_ODD_CHAN                  BIT(6)
79 #define PCMMIO_AI_CMD_CHAN_SEL(x)               (((x) & 0x3) << 4)
80 #define PCMMIO_AI_CMD_RANGE(x)                  (((x) & 0x3) << 2)
81 #define PCMMIO_RESOURCE_REG                     0x02
82 #define PCMMIO_RESOURCE_IRQ(x)                  (((x) & 0xf) << 0)
83 #define PCMMIO_AI_STATUS_REG                    0x03
84 #define PCMMIO_AI_STATUS_DATA_READY             BIT(7)
85 #define PCMMIO_AI_STATUS_DATA_DMA_PEND          BIT(6)
86 #define PCMMIO_AI_STATUS_CMD_DMA_PEND           BIT(5)
87 #define PCMMIO_AI_STATUS_IRQ_PEND               BIT(4)
88 #define PCMMIO_AI_STATUS_DATA_DRQ_ENA           BIT(2)
89 #define PCMMIO_AI_STATUS_REG_SEL                BIT(3)
90 #define PCMMIO_AI_STATUS_CMD_DRQ_ENA            BIT(1)
91 #define PCMMIO_AI_STATUS_IRQ_ENA                BIT(0)
92 #define PCMMIO_AI_RES_ENA_REG                   0x03
93 #define PCMMIO_AI_RES_ENA_CMD_REG_ACCESS        (0 << 3)
94 #define PCMMIO_AI_RES_ENA_AI_RES_ACCESS         BIT(3)
95 #define PCMMIO_AI_RES_ENA_DIO_RES_ACCESS        BIT(4)
96 #define PCMMIO_AI_2ND_ADC_OFFSET                0x04
97
98 #define PCMMIO_AO_LSB_REG                       0x08
99 #define PCMMIO_AO_LSB_SPAN(x)                   (((x) & 0xf) << 0)
100 #define PCMMIO_AO_MSB_REG                       0x09
101 #define PCMMIO_AO_CMD_REG                       0x0a
102 #define PCMMIO_AO_CMD_WR_SPAN                   (0x2 << 4)
103 #define PCMMIO_AO_CMD_WR_CODE                   (0x3 << 4)
104 #define PCMMIO_AO_CMD_UPDATE                    (0x4 << 4)
105 #define PCMMIO_AO_CMD_UPDATE_ALL                (0x5 << 4)
106 #define PCMMIO_AO_CMD_WR_SPAN_UPDATE            (0x6 << 4)
107 #define PCMMIO_AO_CMD_WR_CODE_UPDATE            (0x7 << 4)
108 #define PCMMIO_AO_CMD_WR_SPAN_UPDATE_ALL        (0x8 << 4)
109 #define PCMMIO_AO_CMD_WR_CODE_UPDATE_ALL        (0x9 << 4)
110 #define PCMMIO_AO_CMD_RD_B1_SPAN                (0xa << 4)
111 #define PCMMIO_AO_CMD_RD_B1_CODE                (0xb << 4)
112 #define PCMMIO_AO_CMD_RD_B2_SPAN                (0xc << 4)
113 #define PCMMIO_AO_CMD_RD_B2_CODE                (0xd << 4)
114 #define PCMMIO_AO_CMD_NOP                       (0xf << 4)
115 #define PCMMIO_AO_CMD_CHAN_SEL(x)               (((x) & 0x03) << 1)
116 #define PCMMIO_AO_CMD_CHAN_SEL_ALL              (0x0f << 0)
117 #define PCMMIO_AO_STATUS_REG                    0x0b
118 #define PCMMIO_AO_STATUS_DATA_READY             BIT(7)
119 #define PCMMIO_AO_STATUS_DATA_DMA_PEND          BIT(6)
120 #define PCMMIO_AO_STATUS_CMD_DMA_PEND           BIT(5)
121 #define PCMMIO_AO_STATUS_IRQ_PEND               BIT(4)
122 #define PCMMIO_AO_STATUS_DATA_DRQ_ENA           BIT(2)
123 #define PCMMIO_AO_STATUS_REG_SEL                BIT(3)
124 #define PCMMIO_AO_STATUS_CMD_DRQ_ENA            BIT(1)
125 #define PCMMIO_AO_STATUS_IRQ_ENA                BIT(0)
126 #define PCMMIO_AO_RESOURCE_ENA_REG              0x0b
127 #define PCMMIO_AO_2ND_DAC_OFFSET                0x04
128
129 /*
130  * WinSystems WS16C48
131  *
132  * Offset    Page 0       Page 1       Page 2       Page 3
133  * ------  -----------  -----------  -----------  -----------
134  *  0x10   Port 0 I/O   Port 0 I/O   Port 0 I/O   Port 0 I/O
135  *  0x11   Port 1 I/O   Port 1 I/O   Port 1 I/O   Port 1 I/O
136  *  0x12   Port 2 I/O   Port 2 I/O   Port 2 I/O   Port 2 I/O
137  *  0x13   Port 3 I/O   Port 3 I/O   Port 3 I/O   Port 3 I/O
138  *  0x14   Port 4 I/O   Port 4 I/O   Port 4 I/O   Port 4 I/O
139  *  0x15   Port 5 I/O   Port 5 I/O   Port 5 I/O   Port 5 I/O
140  *  0x16   INT_PENDING  INT_PENDING  INT_PENDING  INT_PENDING
141  *  0x17    Page/Lock    Page/Lock    Page/Lock    Page/Lock
142  *  0x18       N/A         POL_0       ENAB_0       INT_ID0
143  *  0x19       N/A         POL_1       ENAB_1       INT_ID1
144  *  0x1a       N/A         POL_2       ENAB_2       INT_ID2
145  */
146 #define PCMMIO_PORT_REG(x)                      (0x10 + (x))
147 #define PCMMIO_INT_PENDING_REG                  0x16
148 #define PCMMIO_PAGE_LOCK_REG                    0x17
149 #define PCMMIO_LOCK_PORT(x)                     ((1 << (x)) & 0x3f)
150 #define PCMMIO_PAGE(x)                          (((x) & 0x3) << 6)
151 #define PCMMIO_PAGE_MASK                        PCMUIO_PAGE(3)
152 #define PCMMIO_PAGE_POL                         1
153 #define PCMMIO_PAGE_ENAB                        2
154 #define PCMMIO_PAGE_INT_ID                      3
155 #define PCMMIO_PAGE_REG(x)                      (0x18 + (x))
156
157 static const struct comedi_lrange pcmmio_ai_ranges = {
158         4, {
159                 BIP_RANGE(5),
160                 BIP_RANGE(10),
161                 UNI_RANGE(5),
162                 UNI_RANGE(10)
163         }
164 };
165
166 static const struct comedi_lrange pcmmio_ao_ranges = {
167         6, {
168                 UNI_RANGE(5),
169                 UNI_RANGE(10),
170                 BIP_RANGE(5),
171                 BIP_RANGE(10),
172                 BIP_RANGE(2.5),
173                 RANGE(-2.5, 7.5)
174         }
175 };
176
177 struct pcmmio_private {
178         spinlock_t pagelock;    /* protects the page registers */
179         spinlock_t spinlock;    /* protects the member variables */
180         unsigned int enabled_mask;
181         unsigned int active:1;
182 };
183
184 static void pcmmio_dio_write(struct comedi_device *dev, unsigned int val,
185                              int page, int port)
186 {
187         struct pcmmio_private *devpriv = dev->private;
188         unsigned long iobase = dev->iobase;
189         unsigned long flags;
190
191         spin_lock_irqsave(&devpriv->pagelock, flags);
192         if (page == 0) {
193                 /* Port registers are valid for any page */
194                 outb(val & 0xff, iobase + PCMMIO_PORT_REG(port + 0));
195                 outb((val >> 8) & 0xff, iobase + PCMMIO_PORT_REG(port + 1));
196                 outb((val >> 16) & 0xff, iobase + PCMMIO_PORT_REG(port + 2));
197         } else {
198                 outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG);
199                 outb(val & 0xff, iobase + PCMMIO_PAGE_REG(0));
200                 outb((val >> 8) & 0xff, iobase + PCMMIO_PAGE_REG(1));
201                 outb((val >> 16) & 0xff, iobase + PCMMIO_PAGE_REG(2));
202         }
203         spin_unlock_irqrestore(&devpriv->pagelock, flags);
204 }
205
206 static unsigned int pcmmio_dio_read(struct comedi_device *dev,
207                                     int page, int port)
208 {
209         struct pcmmio_private *devpriv = dev->private;
210         unsigned long iobase = dev->iobase;
211         unsigned long flags;
212         unsigned int val;
213
214         spin_lock_irqsave(&devpriv->pagelock, flags);
215         if (page == 0) {
216                 /* Port registers are valid for any page */
217                 val = inb(iobase + PCMMIO_PORT_REG(port + 0));
218                 val |= (inb(iobase + PCMMIO_PORT_REG(port + 1)) << 8);
219                 val |= (inb(iobase + PCMMIO_PORT_REG(port + 2)) << 16);
220         } else {
221                 outb(PCMMIO_PAGE(page), iobase + PCMMIO_PAGE_LOCK_REG);
222                 val = inb(iobase + PCMMIO_PAGE_REG(0));
223                 val |= (inb(iobase + PCMMIO_PAGE_REG(1)) << 8);
224                 val |= (inb(iobase + PCMMIO_PAGE_REG(2)) << 16);
225         }
226         spin_unlock_irqrestore(&devpriv->pagelock, flags);
227
228         return val;
229 }
230
231 /*
232  * Each channel can be individually programmed for input or output.
233  * Writing a '0' to a channel causes the corresponding output pin
234  * to go to a high-z state (pulled high by an external 10K resistor).
235  * This allows it to be used as an input. When used in the input mode,
236  * a read reflects the inverted state of the I/O pin, such that a
237  * high on the pin will read as a '0' in the register. Writing a '1'
238  * to a bit position causes the pin to sink current (up to 12mA),
239  * effectively pulling it low.
240  */
241 static int pcmmio_dio_insn_bits(struct comedi_device *dev,
242                                 struct comedi_subdevice *s,
243                                 struct comedi_insn *insn,
244                                 unsigned int *data)
245 {
246         /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */
247         int port = s->index == 2 ? 0 : 3;
248         unsigned int chanmask = (1 << s->n_chan) - 1;
249         unsigned int mask;
250         unsigned int val;
251
252         mask = comedi_dio_update_state(s, data);
253         if (mask) {
254                 /*
255                  * Outputs are inverted, invert the state and
256                  * update the channels.
257                  *
258                  * The s->io_bits mask makes sure the input channels
259                  * are '0' so that the outputs pins stay in a high
260                  * z-state.
261                  */
262                 val = ~s->state & chanmask;
263                 val &= s->io_bits;
264                 pcmmio_dio_write(dev, val, 0, port);
265         }
266
267         /* get inverted state of the channels from the port */
268         val = pcmmio_dio_read(dev, 0, port);
269
270         /* return the true state of the channels */
271         data[1] = ~val & chanmask;
272
273         return insn->n;
274 }
275
276 static int pcmmio_dio_insn_config(struct comedi_device *dev,
277                                   struct comedi_subdevice *s,
278                                   struct comedi_insn *insn,
279                                   unsigned int *data)
280 {
281         /* subdevice 2 uses ports 0-2, subdevice 3 uses ports 3-5 */
282         int port = s->index == 2 ? 0 : 3;
283         int ret;
284
285         ret = comedi_dio_insn_config(dev, s, insn, data, 0);
286         if (ret)
287                 return ret;
288
289         if (data[0] == INSN_CONFIG_DIO_INPUT)
290                 pcmmio_dio_write(dev, s->io_bits, 0, port);
291
292         return insn->n;
293 }
294
295 static void pcmmio_reset(struct comedi_device *dev)
296 {
297         /* Clear all the DIO port bits */
298         pcmmio_dio_write(dev, 0, 0, 0);
299         pcmmio_dio_write(dev, 0, 0, 3);
300
301         /* Clear all the paged registers */
302         pcmmio_dio_write(dev, 0, PCMMIO_PAGE_POL, 0);
303         pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0);
304         pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0);
305 }
306
307 /* devpriv->spinlock is already locked */
308 static void pcmmio_stop_intr(struct comedi_device *dev,
309                              struct comedi_subdevice *s)
310 {
311         struct pcmmio_private *devpriv = dev->private;
312
313         devpriv->enabled_mask = 0;
314         devpriv->active = 0;
315         s->async->inttrig = NULL;
316
317         /* disable all dio interrupts */
318         pcmmio_dio_write(dev, 0, PCMMIO_PAGE_ENAB, 0);
319 }
320
321 static void pcmmio_handle_dio_intr(struct comedi_device *dev,
322                                    struct comedi_subdevice *s,
323                                    unsigned int triggered)
324 {
325         struct pcmmio_private *devpriv = dev->private;
326         struct comedi_cmd *cmd = &s->async->cmd;
327         unsigned int val = 0;
328         unsigned long flags;
329         int i;
330
331         spin_lock_irqsave(&devpriv->spinlock, flags);
332
333         if (!devpriv->active)
334                 goto done;
335
336         if (!(triggered & devpriv->enabled_mask))
337                 goto done;
338
339         for (i = 0; i < cmd->chanlist_len; i++) {
340                 unsigned int chan = CR_CHAN(cmd->chanlist[i]);
341
342                 if (triggered & (1 << chan))
343                         val |= (1 << i);
344         }
345
346         comedi_buf_write_samples(s, &val, 1);
347
348         if (cmd->stop_src == TRIG_COUNT &&
349             s->async->scans_done >= cmd->stop_arg)
350                 s->async->events |= COMEDI_CB_EOA;
351
352 done:
353         spin_unlock_irqrestore(&devpriv->spinlock, flags);
354
355         comedi_handle_events(dev, s);
356 }
357
358 static irqreturn_t interrupt_pcmmio(int irq, void *d)
359 {
360         struct comedi_device *dev = d;
361         struct comedi_subdevice *s = dev->read_subdev;
362         unsigned int triggered;
363         unsigned char int_pend;
364
365         /* are there any interrupts pending */
366         int_pend = inb(dev->iobase + PCMMIO_INT_PENDING_REG) & 0x07;
367         if (!int_pend)
368                 return IRQ_NONE;
369
370         /* get, and clear, the pending interrupts */
371         triggered = pcmmio_dio_read(dev, PCMMIO_PAGE_INT_ID, 0);
372         pcmmio_dio_write(dev, 0, PCMMIO_PAGE_INT_ID, 0);
373
374         pcmmio_handle_dio_intr(dev, s, triggered);
375
376         return IRQ_HANDLED;
377 }
378
379 /* devpriv->spinlock is already locked */
380 static void pcmmio_start_intr(struct comedi_device *dev,
381                               struct comedi_subdevice *s)
382 {
383         struct pcmmio_private *devpriv = dev->private;
384         struct comedi_cmd *cmd = &s->async->cmd;
385         unsigned int bits = 0;
386         unsigned int pol_bits = 0;
387         int i;
388
389         devpriv->enabled_mask = 0;
390         devpriv->active = 1;
391         if (cmd->chanlist) {
392                 for (i = 0; i < cmd->chanlist_len; i++) {
393                         unsigned int chanspec = cmd->chanlist[i];
394                         unsigned int chan = CR_CHAN(chanspec);
395                         unsigned int range = CR_RANGE(chanspec);
396                         unsigned int aref = CR_AREF(chanspec);
397
398                         bits |= (1 << chan);
399                         pol_bits |= (((aref || range) ? 1 : 0) << chan);
400                 }
401         }
402         bits &= ((1 << s->n_chan) - 1);
403         devpriv->enabled_mask = bits;
404
405         /* set polarity and enable interrupts */
406         pcmmio_dio_write(dev, pol_bits, PCMMIO_PAGE_POL, 0);
407         pcmmio_dio_write(dev, bits, PCMMIO_PAGE_ENAB, 0);
408 }
409
410 static int pcmmio_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
411 {
412         struct pcmmio_private *devpriv = dev->private;
413         unsigned long flags;
414
415         spin_lock_irqsave(&devpriv->spinlock, flags);
416         if (devpriv->active)
417                 pcmmio_stop_intr(dev, s);
418         spin_unlock_irqrestore(&devpriv->spinlock, flags);
419
420         return 0;
421 }
422
423 static int pcmmio_inttrig_start_intr(struct comedi_device *dev,
424                                      struct comedi_subdevice *s,
425                                      unsigned int trig_num)
426 {
427         struct pcmmio_private *devpriv = dev->private;
428         struct comedi_cmd *cmd = &s->async->cmd;
429         unsigned long flags;
430
431         if (trig_num != cmd->start_arg)
432                 return -EINVAL;
433
434         spin_lock_irqsave(&devpriv->spinlock, flags);
435         s->async->inttrig = NULL;
436         if (devpriv->active)
437                 pcmmio_start_intr(dev, s);
438         spin_unlock_irqrestore(&devpriv->spinlock, flags);
439
440         return 1;
441 }
442
443 /*
444  * 'do_cmd' function for an 'INTERRUPT' subdevice.
445  */
446 static int pcmmio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
447 {
448         struct pcmmio_private *devpriv = dev->private;
449         struct comedi_cmd *cmd = &s->async->cmd;
450         unsigned long flags;
451
452         spin_lock_irqsave(&devpriv->spinlock, flags);
453         devpriv->active = 1;
454
455         /* Set up start of acquisition. */
456         if (cmd->start_src == TRIG_INT)
457                 s->async->inttrig = pcmmio_inttrig_start_intr;
458         else    /* TRIG_NOW */
459                 pcmmio_start_intr(dev, s);
460
461         spin_unlock_irqrestore(&devpriv->spinlock, flags);
462
463         return 0;
464 }
465
466 static int pcmmio_cmdtest(struct comedi_device *dev,
467                           struct comedi_subdevice *s,
468                           struct comedi_cmd *cmd)
469 {
470         int err = 0;
471
472         /* Step 1 : check if triggers are trivially valid */
473
474         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
475         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
476         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
477         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
478         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
479
480         if (err)
481                 return 1;
482
483         /* Step 2a : make sure trigger sources are unique */
484
485         err |= comedi_check_trigger_is_unique(cmd->start_src);
486         err |= comedi_check_trigger_is_unique(cmd->stop_src);
487
488         /* Step 2b : and mutually compatible */
489
490         if (err)
491                 return 2;
492
493         /* Step 3: check if arguments are trivially valid */
494
495         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
496         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
497         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
498         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
499                                            cmd->chanlist_len);
500
501         if (cmd->stop_src == TRIG_COUNT)
502                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
503         else    /* TRIG_NONE */
504                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
505
506         if (err)
507                 return 3;
508
509         /* step 4: fix up any arguments */
510
511         /* if (err) return 4; */
512
513         return 0;
514 }
515
516 static int pcmmio_ai_eoc(struct comedi_device *dev,
517                          struct comedi_subdevice *s,
518                          struct comedi_insn *insn,
519                          unsigned long context)
520 {
521         unsigned char status;
522
523         status = inb(dev->iobase + PCMMIO_AI_STATUS_REG);
524         if (status & PCMMIO_AI_STATUS_DATA_READY)
525                 return 0;
526         return -EBUSY;
527 }
528
529 static int pcmmio_ai_insn_read(struct comedi_device *dev,
530                                struct comedi_subdevice *s,
531                                struct comedi_insn *insn,
532                                unsigned int *data)
533 {
534         unsigned long iobase = dev->iobase;
535         unsigned int chan = CR_CHAN(insn->chanspec);
536         unsigned int range = CR_RANGE(insn->chanspec);
537         unsigned int aref = CR_AREF(insn->chanspec);
538         unsigned char cmd = 0;
539         unsigned int val;
540         int ret;
541         int i;
542
543         /*
544          * The PCM-MIO uses two Linear Tech LTC1859CG 8-channel A/D converters.
545          * The devices use a full duplex serial interface which transmits and
546          * receives data simultaneously. An 8-bit command is shifted into the
547          * ADC interface to configure it for the next conversion. At the same
548          * time, the data from the previous conversion is shifted out of the
549          * device. Consequently, the conversion result is delayed by one
550          * conversion from the command word.
551          *
552          * Setup the cmd for the conversions then do a dummy conversion to
553          * flush the junk data. Then do each conversion requested by the
554          * comedi_insn. Note that the last conversion will leave junk data
555          * in ADC which will get flushed on the next comedi_insn.
556          */
557
558         if (chan > 7) {
559                 chan -= 8;
560                 iobase += PCMMIO_AI_2ND_ADC_OFFSET;
561         }
562
563         if (aref == AREF_GROUND)
564                 cmd |= PCMMIO_AI_CMD_SE;
565         if (chan % 2)
566                 cmd |= PCMMIO_AI_CMD_ODD_CHAN;
567         cmd |= PCMMIO_AI_CMD_CHAN_SEL(chan / 2);
568         cmd |= PCMMIO_AI_CMD_RANGE(range);
569
570         outb(cmd, iobase + PCMMIO_AI_CMD_REG);
571
572         ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
573         if (ret)
574                 return ret;
575
576         val = inb(iobase + PCMMIO_AI_LSB_REG);
577         val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8;
578
579         for (i = 0; i < insn->n; i++) {
580                 outb(cmd, iobase + PCMMIO_AI_CMD_REG);
581
582                 ret = comedi_timeout(dev, s, insn, pcmmio_ai_eoc, 0);
583                 if (ret)
584                         return ret;
585
586                 val = inb(iobase + PCMMIO_AI_LSB_REG);
587                 val |= inb(iobase + PCMMIO_AI_MSB_REG) << 8;
588
589                 /* bipolar data is two's complement */
590                 if (comedi_range_is_bipolar(s, range))
591                         val = comedi_offset_munge(s, val);
592
593                 data[i] = val;
594         }
595
596         return insn->n;
597 }
598
599 static int pcmmio_ao_eoc(struct comedi_device *dev,
600                          struct comedi_subdevice *s,
601                          struct comedi_insn *insn,
602                          unsigned long context)
603 {
604         unsigned char status;
605
606         status = inb(dev->iobase + PCMMIO_AO_STATUS_REG);
607         if (status & PCMMIO_AO_STATUS_DATA_READY)
608                 return 0;
609         return -EBUSY;
610 }
611
612 static int pcmmio_ao_insn_write(struct comedi_device *dev,
613                                 struct comedi_subdevice *s,
614                                 struct comedi_insn *insn,
615                                 unsigned int *data)
616 {
617         unsigned long iobase = dev->iobase;
618         unsigned int chan = CR_CHAN(insn->chanspec);
619         unsigned int range = CR_RANGE(insn->chanspec);
620         unsigned char cmd = 0;
621         int ret;
622         int i;
623
624         /*
625          * The PCM-MIO has two Linear Tech LTC2704 DAC devices. Each device
626          * is a 4-channel converter with software-selectable output range.
627          */
628
629         if (chan > 3) {
630                 cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan - 4);
631                 iobase += PCMMIO_AO_2ND_DAC_OFFSET;
632         } else {
633                 cmd |= PCMMIO_AO_CMD_CHAN_SEL(chan);
634         }
635
636         /* set the range for the channel */
637         outb(PCMMIO_AO_LSB_SPAN(range), iobase + PCMMIO_AO_LSB_REG);
638         outb(0, iobase + PCMMIO_AO_MSB_REG);
639         outb(cmd | PCMMIO_AO_CMD_WR_SPAN_UPDATE, iobase + PCMMIO_AO_CMD_REG);
640
641         ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
642         if (ret)
643                 return ret;
644
645         for (i = 0; i < insn->n; i++) {
646                 unsigned int val = data[i];
647
648                 /* write the data to the channel */
649                 outb(val & 0xff, iobase + PCMMIO_AO_LSB_REG);
650                 outb((val >> 8) & 0xff, iobase + PCMMIO_AO_MSB_REG);
651                 outb(cmd | PCMMIO_AO_CMD_WR_CODE_UPDATE,
652                      iobase + PCMMIO_AO_CMD_REG);
653
654                 ret = comedi_timeout(dev, s, insn, pcmmio_ao_eoc, 0);
655                 if (ret)
656                         return ret;
657
658                 s->readback[chan] = val;
659         }
660
661         return insn->n;
662 }
663
664 static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
665 {
666         struct pcmmio_private *devpriv;
667         struct comedi_subdevice *s;
668         int ret;
669
670         ret = comedi_request_region(dev, it->options[0], 32);
671         if (ret)
672                 return ret;
673
674         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
675         if (!devpriv)
676                 return -ENOMEM;
677
678         spin_lock_init(&devpriv->pagelock);
679         spin_lock_init(&devpriv->spinlock);
680
681         pcmmio_reset(dev);
682
683         if (it->options[1]) {
684                 ret = request_irq(it->options[1], interrupt_pcmmio, 0,
685                                   dev->board_name, dev);
686                 if (ret == 0) {
687                         dev->irq = it->options[1];
688
689                         /* configure the interrupt routing on the board */
690                         outb(PCMMIO_AI_RES_ENA_DIO_RES_ACCESS,
691                              dev->iobase + PCMMIO_AI_RES_ENA_REG);
692                         outb(PCMMIO_RESOURCE_IRQ(dev->irq),
693                              dev->iobase + PCMMIO_RESOURCE_REG);
694                 }
695         }
696
697         ret = comedi_alloc_subdevices(dev, 4);
698         if (ret)
699                 return ret;
700
701         /* Analog Input subdevice */
702         s = &dev->subdevices[0];
703         s->type         = COMEDI_SUBD_AI;
704         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF;
705         s->n_chan       = 16;
706         s->maxdata      = 0xffff;
707         s->range_table  = &pcmmio_ai_ranges;
708         s->insn_read    = pcmmio_ai_insn_read;
709
710         /* initialize the resource enable register by clearing it */
711         outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS,
712              dev->iobase + PCMMIO_AI_RES_ENA_REG);
713         outb(PCMMIO_AI_RES_ENA_CMD_REG_ACCESS,
714              dev->iobase + PCMMIO_AI_RES_ENA_REG + PCMMIO_AI_2ND_ADC_OFFSET);
715
716         /* Analog Output subdevice */
717         s = &dev->subdevices[1];
718         s->type         = COMEDI_SUBD_AO;
719         s->subdev_flags = SDF_READABLE;
720         s->n_chan       = 8;
721         s->maxdata      = 0xffff;
722         s->range_table  = &pcmmio_ao_ranges;
723         s->insn_write   = pcmmio_ao_insn_write;
724
725         ret = comedi_alloc_subdev_readback(s);
726         if (ret)
727                 return ret;
728
729         /* initialize the resource enable register by clearing it */
730         outb(0, dev->iobase + PCMMIO_AO_RESOURCE_ENA_REG);
731         outb(0, dev->iobase + PCMMIO_AO_2ND_DAC_OFFSET +
732                 PCMMIO_AO_RESOURCE_ENA_REG);
733
734         /* Digital I/O subdevice with interrupt support */
735         s = &dev->subdevices[2];
736         s->type         = COMEDI_SUBD_DIO;
737         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
738         s->n_chan       = 24;
739         s->maxdata      = 1;
740         s->len_chanlist = 1;
741         s->range_table  = &range_digital;
742         s->insn_bits    = pcmmio_dio_insn_bits;
743         s->insn_config  = pcmmio_dio_insn_config;
744         if (dev->irq) {
745                 dev->read_subdev = s;
746                 s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL | SDF_PACKED;
747                 s->len_chanlist = s->n_chan;
748                 s->cancel       = pcmmio_cancel;
749                 s->do_cmd       = pcmmio_cmd;
750                 s->do_cmdtest   = pcmmio_cmdtest;
751         }
752
753         /* Digital I/O subdevice */
754         s = &dev->subdevices[3];
755         s->type         = COMEDI_SUBD_DIO;
756         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
757         s->n_chan       = 24;
758         s->maxdata      = 1;
759         s->range_table  = &range_digital;
760         s->insn_bits    = pcmmio_dio_insn_bits;
761         s->insn_config  = pcmmio_dio_insn_config;
762
763         return 0;
764 }
765
766 static struct comedi_driver pcmmio_driver = {
767         .driver_name    = "pcmmio",
768         .module         = THIS_MODULE,
769         .attach         = pcmmio_attach,
770         .detach         = comedi_legacy_detach,
771 };
772 module_comedi_driver(pcmmio_driver);
773
774 MODULE_AUTHOR("Comedi https://www.comedi.org");
775 MODULE_DESCRIPTION("Comedi driver for Winsystems PCM-MIO PC/104 board");
776 MODULE_LICENSE("GPL");