These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / staging / comedi / drivers / amplc_dio200_common.c
1 /*
2  * comedi/drivers/amplc_dio200_common.c
3  *
4  * Common support code for "amplc_dio200" and "amplc_dio200_pci".
5  *
6  * Copyright (C) 2005-2013 MEV Ltd. <http://www.mev.co.uk/>
7  *
8  * COMEDI - Linux Control and Measurement Device Interface
9  * Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  */
21
22 #include <linux/module.h>
23 #include <linux/interrupt.h>
24
25 #include "../comedidev.h"
26
27 #include "amplc_dio200.h"
28 #include "comedi_8254.h"
29 #include "8255.h"               /* only for register defines */
30
31 /* 200 series registers */
32 #define DIO200_IO_SIZE          0x20
33 #define DIO200_PCIE_IO_SIZE     0x4000
34 #define DIO200_CLK_SCE(x)       (0x18 + (x))    /* Group X/Y/Z clock sel reg */
35 #define DIO200_GAT_SCE(x)       (0x1b + (x))    /* Group X/Y/Z gate sel reg */
36 #define DIO200_INT_SCE          0x1e    /* Interrupt enable/status register */
37 /* Extra registers for new PCIe boards */
38 #define DIO200_ENHANCE          0x20    /* 1 to enable enhanced features */
39 #define DIO200_VERSION          0x24    /* Hardware version register */
40 #define DIO200_TS_CONFIG        0x600   /* Timestamp timer config register */
41 #define DIO200_TS_COUNT         0x602   /* Timestamp timer count register */
42
43 /*
44  * Functions for constructing value for DIO_200_?CLK_SCE and
45  * DIO_200_?GAT_SCE registers:
46  *
47  * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
48  * 'chan' is the channel: 0, 1 or 2.
49  * 'source' is the signal source: 0 to 7, or 0 to 31 for "enhanced" boards.
50  */
51 static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
52                                  unsigned int source)
53 {
54         return (which << 5) | (chan << 3) |
55                ((source & 030) << 3) | (source & 007);
56 }
57
58 static unsigned char clk_sce(unsigned int which, unsigned int chan,
59                              unsigned int source)
60 {
61         return clk_gat_sce(which, chan, source);
62 }
63
64 static unsigned char gat_sce(unsigned int which, unsigned int chan,
65                              unsigned int source)
66 {
67         return clk_gat_sce(which, chan, source);
68 }
69
70 /*
71  * Periods of the internal clock sources in nanoseconds.
72  */
73 static const unsigned int clock_period[32] = {
74         [1] = 100,              /* 10 MHz */
75         [2] = 1000,             /* 1 MHz */
76         [3] = 10000,            /* 100 kHz */
77         [4] = 100000,           /* 10 kHz */
78         [5] = 1000000,          /* 1 kHz */
79         [11] = 50,              /* 20 MHz (enhanced boards) */
80         /* clock sources 12 and later reserved for enhanced boards */
81 };
82
83 /*
84  * Timestamp timer configuration register (for new PCIe boards).
85  */
86 #define TS_CONFIG_RESET         0x100   /* Reset counter to zero. */
87 #define TS_CONFIG_CLK_SRC_MASK  0x0FF   /* Clock source. */
88 #define TS_CONFIG_MAX_CLK_SRC   2       /* Maximum clock source value. */
89
90 /*
91  * Periods of the timestamp timer clock sources in nanoseconds.
92  */
93 static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
94         1,                      /* 1 nanosecond (but with 20 ns granularity). */
95         1000,                   /* 1 microsecond. */
96         1000000,                /* 1 millisecond. */
97 };
98
99 struct dio200_subdev_8255 {
100         unsigned int ofs;               /* DIO base offset */
101 };
102
103 struct dio200_subdev_intr {
104         spinlock_t spinlock;
105         unsigned int ofs;
106         unsigned int valid_isns;
107         unsigned int enabled_isns;
108         bool active:1;
109 };
110
111 static unsigned char dio200_read8(struct comedi_device *dev,
112                                   unsigned int offset)
113 {
114         const struct dio200_board *board = dev->board_ptr;
115
116         if (board->is_pcie)
117                 offset <<= 3;
118
119         if (dev->mmio)
120                 return readb(dev->mmio + offset);
121         return inb(dev->iobase + offset);
122 }
123
124 static void dio200_write8(struct comedi_device *dev,
125                           unsigned int offset, unsigned char val)
126 {
127         const struct dio200_board *board = dev->board_ptr;
128
129         if (board->is_pcie)
130                 offset <<= 3;
131
132         if (dev->mmio)
133                 writeb(val, dev->mmio + offset);
134         else
135                 outb(val, dev->iobase + offset);
136 }
137
138 static unsigned int dio200_read32(struct comedi_device *dev,
139                                   unsigned int offset)
140 {
141         const struct dio200_board *board = dev->board_ptr;
142
143         if (board->is_pcie)
144                 offset <<= 3;
145
146         if (dev->mmio)
147                 return readl(dev->mmio + offset);
148         return inl(dev->iobase + offset);
149 }
150
151 static void dio200_write32(struct comedi_device *dev,
152                            unsigned int offset, unsigned int val)
153 {
154         const struct dio200_board *board = dev->board_ptr;
155
156         if (board->is_pcie)
157                 offset <<= 3;
158
159         if (dev->mmio)
160                 writel(val, dev->mmio + offset);
161         else
162                 outl(val, dev->iobase + offset);
163 }
164
165 static unsigned int dio200_subdev_8254_offset(struct comedi_device *dev,
166                                               struct comedi_subdevice *s)
167 {
168         const struct dio200_board *board = dev->board_ptr;
169         struct comedi_8254 *i8254 = s->private;
170         unsigned int offset;
171
172         /* get the offset that was passed to comedi_8254_*_init() */
173         if (dev->mmio)
174                 offset = i8254->mmio - dev->mmio;
175         else
176                 offset = i8254->iobase - dev->iobase;
177
178         /* remove the shift that was added for PCIe boards */
179         if (board->is_pcie)
180                 offset >>= 3;
181
182         /* this offset now works for the dio200_{read,write} helpers */
183         return offset;
184 }
185
186 static int dio200_subdev_intr_insn_bits(struct comedi_device *dev,
187                                         struct comedi_subdevice *s,
188                                         struct comedi_insn *insn,
189                                         unsigned int *data)
190 {
191         const struct dio200_board *board = dev->board_ptr;
192         struct dio200_subdev_intr *subpriv = s->private;
193
194         if (board->has_int_sce) {
195                 /* Just read the interrupt status register.  */
196                 data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns;
197         } else {
198                 /* No interrupt status register. */
199                 data[0] = 0;
200         }
201
202         return insn->n;
203 }
204
205 static void dio200_stop_intr(struct comedi_device *dev,
206                              struct comedi_subdevice *s)
207 {
208         const struct dio200_board *board = dev->board_ptr;
209         struct dio200_subdev_intr *subpriv = s->private;
210
211         subpriv->active = false;
212         subpriv->enabled_isns = 0;
213         if (board->has_int_sce)
214                 dio200_write8(dev, subpriv->ofs, 0);
215 }
216
217 static void dio200_start_intr(struct comedi_device *dev,
218                               struct comedi_subdevice *s)
219 {
220         const struct dio200_board *board = dev->board_ptr;
221         struct dio200_subdev_intr *subpriv = s->private;
222         struct comedi_cmd *cmd = &s->async->cmd;
223         unsigned int n;
224         unsigned isn_bits;
225
226         /* Determine interrupt sources to enable. */
227         isn_bits = 0;
228         if (cmd->chanlist) {
229                 for (n = 0; n < cmd->chanlist_len; n++)
230                         isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
231         }
232         isn_bits &= subpriv->valid_isns;
233         /* Enable interrupt sources. */
234         subpriv->enabled_isns = isn_bits;
235         if (board->has_int_sce)
236                 dio200_write8(dev, subpriv->ofs, isn_bits);
237 }
238
239 static int dio200_inttrig_start_intr(struct comedi_device *dev,
240                                      struct comedi_subdevice *s,
241                                      unsigned int trig_num)
242 {
243         struct dio200_subdev_intr *subpriv = s->private;
244         struct comedi_cmd *cmd = &s->async->cmd;
245         unsigned long flags;
246
247         if (trig_num != cmd->start_arg)
248                 return -EINVAL;
249
250         spin_lock_irqsave(&subpriv->spinlock, flags);
251         s->async->inttrig = NULL;
252         if (subpriv->active)
253                 dio200_start_intr(dev, s);
254
255         spin_unlock_irqrestore(&subpriv->spinlock, flags);
256
257         return 1;
258 }
259
260 static void dio200_read_scan_intr(struct comedi_device *dev,
261                                   struct comedi_subdevice *s,
262                                   unsigned int triggered)
263 {
264         struct comedi_cmd *cmd = &s->async->cmd;
265         unsigned short val;
266         unsigned int n, ch;
267
268         val = 0;
269         for (n = 0; n < cmd->chanlist_len; n++) {
270                 ch = CR_CHAN(cmd->chanlist[n]);
271                 if (triggered & (1U << ch))
272                         val |= (1U << n);
273         }
274
275         comedi_buf_write_samples(s, &val, 1);
276
277         if (cmd->stop_src == TRIG_COUNT &&
278             s->async->scans_done >= cmd->stop_arg)
279                 s->async->events |= COMEDI_CB_EOA;
280 }
281
282 static int dio200_handle_read_intr(struct comedi_device *dev,
283                                    struct comedi_subdevice *s)
284 {
285         const struct dio200_board *board = dev->board_ptr;
286         struct dio200_subdev_intr *subpriv = s->private;
287         unsigned triggered;
288         unsigned intstat;
289         unsigned cur_enabled;
290         unsigned long flags;
291
292         triggered = 0;
293
294         spin_lock_irqsave(&subpriv->spinlock, flags);
295         if (board->has_int_sce) {
296                 /*
297                  * Collect interrupt sources that have triggered and disable
298                  * them temporarily.  Loop around until no extra interrupt
299                  * sources have triggered, at which point, the valid part of
300                  * the interrupt status register will read zero, clearing the
301                  * cause of the interrupt.
302                  *
303                  * Mask off interrupt sources already seen to avoid infinite
304                  * loop in case of misconfiguration.
305                  */
306                 cur_enabled = subpriv->enabled_isns;
307                 while ((intstat = (dio200_read8(dev, subpriv->ofs) &
308                                    subpriv->valid_isns & ~triggered)) != 0) {
309                         triggered |= intstat;
310                         cur_enabled &= ~triggered;
311                         dio200_write8(dev, subpriv->ofs, cur_enabled);
312                 }
313         } else {
314                 /*
315                  * No interrupt status register.  Assume the single interrupt
316                  * source has triggered.
317                  */
318                 triggered = subpriv->enabled_isns;
319         }
320
321         if (triggered) {
322                 /*
323                  * Some interrupt sources have triggered and have been
324                  * temporarily disabled to clear the cause of the interrupt.
325                  *
326                  * Reenable them NOW to minimize the time they are disabled.
327                  */
328                 cur_enabled = subpriv->enabled_isns;
329                 if (board->has_int_sce)
330                         dio200_write8(dev, subpriv->ofs, cur_enabled);
331
332                 if (subpriv->active) {
333                         /*
334                          * The command is still active.
335                          *
336                          * Ignore interrupt sources that the command isn't
337                          * interested in (just in case there's a race
338                          * condition).
339                          */
340                         if (triggered & subpriv->enabled_isns) {
341                                 /* Collect scan data. */
342                                 dio200_read_scan_intr(dev, s, triggered);
343                         }
344                 }
345         }
346         spin_unlock_irqrestore(&subpriv->spinlock, flags);
347
348         comedi_handle_events(dev, s);
349
350         return (triggered != 0);
351 }
352
353 static int dio200_subdev_intr_cancel(struct comedi_device *dev,
354                                      struct comedi_subdevice *s)
355 {
356         struct dio200_subdev_intr *subpriv = s->private;
357         unsigned long flags;
358
359         spin_lock_irqsave(&subpriv->spinlock, flags);
360         if (subpriv->active)
361                 dio200_stop_intr(dev, s);
362
363         spin_unlock_irqrestore(&subpriv->spinlock, flags);
364
365         return 0;
366 }
367
368 static int dio200_subdev_intr_cmdtest(struct comedi_device *dev,
369                                       struct comedi_subdevice *s,
370                                       struct comedi_cmd *cmd)
371 {
372         int err = 0;
373
374         /* Step 1 : check if triggers are trivially valid */
375
376         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
377         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
378         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
379         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
380         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
381
382         if (err)
383                 return 1;
384
385         /* Step 2a : make sure trigger sources are unique */
386
387         err |= comedi_check_trigger_is_unique(cmd->start_src);
388         err |= comedi_check_trigger_is_unique(cmd->stop_src);
389
390         /* Step 2b : and mutually compatible */
391
392         if (err)
393                 return 2;
394
395         /* Step 3: check if arguments are trivially valid */
396
397         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
398         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
399         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
400         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
401                                            cmd->chanlist_len);
402
403         if (cmd->stop_src == TRIG_COUNT)
404                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
405         else    /* TRIG_NONE */
406                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
407
408         if (err)
409                 return 3;
410
411         /* step 4: fix up any arguments */
412
413         /* if (err) return 4; */
414
415         return 0;
416 }
417
418 static int dio200_subdev_intr_cmd(struct comedi_device *dev,
419                                   struct comedi_subdevice *s)
420 {
421         struct comedi_cmd *cmd = &s->async->cmd;
422         struct dio200_subdev_intr *subpriv = s->private;
423         unsigned long flags;
424
425         spin_lock_irqsave(&subpriv->spinlock, flags);
426
427         subpriv->active = true;
428
429         if (cmd->start_src == TRIG_INT)
430                 s->async->inttrig = dio200_inttrig_start_intr;
431         else    /* TRIG_NOW */
432                 dio200_start_intr(dev, s);
433
434         spin_unlock_irqrestore(&subpriv->spinlock, flags);
435
436         return 0;
437 }
438
439 static int dio200_subdev_intr_init(struct comedi_device *dev,
440                                    struct comedi_subdevice *s,
441                                    unsigned int offset,
442                                    unsigned valid_isns)
443 {
444         const struct dio200_board *board = dev->board_ptr;
445         struct dio200_subdev_intr *subpriv;
446
447         subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
448         if (!subpriv)
449                 return -ENOMEM;
450
451         subpriv->ofs = offset;
452         subpriv->valid_isns = valid_isns;
453         spin_lock_init(&subpriv->spinlock);
454
455         if (board->has_int_sce)
456                 /* Disable interrupt sources. */
457                 dio200_write8(dev, subpriv->ofs, 0);
458
459         s->type = COMEDI_SUBD_DI;
460         s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_PACKED;
461         if (board->has_int_sce) {
462                 s->n_chan = DIO200_MAX_ISNS;
463                 s->len_chanlist = DIO200_MAX_ISNS;
464         } else {
465                 /* No interrupt source register.  Support single channel. */
466                 s->n_chan = 1;
467                 s->len_chanlist = 1;
468         }
469         s->range_table = &range_digital;
470         s->maxdata = 1;
471         s->insn_bits = dio200_subdev_intr_insn_bits;
472         s->do_cmdtest = dio200_subdev_intr_cmdtest;
473         s->do_cmd = dio200_subdev_intr_cmd;
474         s->cancel = dio200_subdev_intr_cancel;
475
476         return 0;
477 }
478
479 static irqreturn_t dio200_interrupt(int irq, void *d)
480 {
481         struct comedi_device *dev = d;
482         struct comedi_subdevice *s = dev->read_subdev;
483         int handled;
484
485         if (!dev->attached)
486                 return IRQ_NONE;
487
488         handled = dio200_handle_read_intr(dev, s);
489
490         return IRQ_RETVAL(handled);
491 }
492
493 static void dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
494                                             struct comedi_subdevice *s,
495                                             unsigned int chan,
496                                             unsigned int src)
497 {
498         unsigned int offset = dio200_subdev_8254_offset(dev, s);
499
500         dio200_write8(dev, DIO200_GAT_SCE(offset >> 3),
501                       gat_sce((offset >> 2) & 1, chan, src));
502 }
503
504 static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
505                                              struct comedi_subdevice *s,
506                                              unsigned int chan,
507                                              unsigned int src)
508 {
509         unsigned int offset = dio200_subdev_8254_offset(dev, s);
510
511         dio200_write8(dev, DIO200_CLK_SCE(offset >> 3),
512                       clk_sce((offset >> 2) & 1, chan, src));
513 }
514
515 static int dio200_subdev_8254_config(struct comedi_device *dev,
516                                      struct comedi_subdevice *s,
517                                      struct comedi_insn *insn,
518                                      unsigned int *data)
519 {
520         const struct dio200_board *board = dev->board_ptr;
521         struct comedi_8254 *i8254 = s->private;
522         unsigned int chan = CR_CHAN(insn->chanspec);
523         unsigned int max_src = board->is_pcie ? 31 : 7;
524         unsigned int src;
525
526         if (!board->has_clk_gat_sce)
527                 return -EINVAL;
528
529         switch (data[0]) {
530         case INSN_CONFIG_SET_GATE_SRC:
531                 src = data[2];
532                 if (src > max_src)
533                         return -EINVAL;
534
535                 dio200_subdev_8254_set_gate_src(dev, s, chan, src);
536                 i8254->gate_src[chan] = src;
537                 break;
538         case INSN_CONFIG_GET_GATE_SRC:
539                 data[2] = i8254->gate_src[chan];
540                 break;
541         case INSN_CONFIG_SET_CLOCK_SRC:
542                 src = data[1];
543                 if (src > max_src)
544                         return -EINVAL;
545
546                 dio200_subdev_8254_set_clock_src(dev, s, chan, src);
547                 i8254->clock_src[chan] = src;
548                 break;
549         case INSN_CONFIG_GET_CLOCK_SRC:
550                 data[1] = i8254->clock_src[chan];
551                 data[2] = clock_period[i8254->clock_src[chan]];
552                 break;
553         default:
554                 return -EINVAL;
555         }
556
557         return insn->n;
558 }
559
560 static int dio200_subdev_8254_init(struct comedi_device *dev,
561                                    struct comedi_subdevice *s,
562                                    unsigned int offset)
563 {
564         const struct dio200_board *board = dev->board_ptr;
565         struct comedi_8254 *i8254;
566         unsigned int regshift;
567         int chan;
568
569         /*
570          * PCIe boards need the offset shifted in order to get the
571          * correct base address of the timer.
572          */
573         if (board->is_pcie) {
574                 offset <<= 3;
575                 regshift = 3;
576         } else {
577                 regshift = 0;
578         }
579
580         if (dev->mmio) {
581                 i8254 = comedi_8254_mm_init(dev->mmio + offset,
582                                             0, I8254_IO8, regshift);
583         } else {
584                 i8254 = comedi_8254_init(dev->iobase + offset,
585                                          0, I8254_IO8, regshift);
586         }
587         if (!i8254)
588                 return -ENOMEM;
589
590         comedi_8254_subdevice_init(s, i8254);
591
592         i8254->insn_config = dio200_subdev_8254_config;
593
594         /*
595          * There could be multiple timers so this driver does not
596          * use dev->pacer to save the i8254 pointer. Instead,
597          * comedi_8254_subdevice_init() saved the i8254 pointer in
598          * s->private.  Mark the subdevice as having private data
599          * to be automatically freed when the device is detached.
600          */
601         comedi_set_spriv_auto_free(s);
602
603         /* Initialize channels. */
604         if (board->has_clk_gat_sce) {
605                 for (chan = 0; chan < 3; chan++) {
606                         /* Gate source 0 is VCC (logic 1). */
607                         dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
608                         /* Clock source 0 is the dedicated clock input. */
609                         dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
610                 }
611         }
612
613         return 0;
614 }
615
616 static void dio200_subdev_8255_set_dir(struct comedi_device *dev,
617                                        struct comedi_subdevice *s)
618 {
619         struct dio200_subdev_8255 *subpriv = s->private;
620         int config;
621
622         config = I8255_CTRL_CW;
623         /* 1 in io_bits indicates output, 1 in config indicates input */
624         if (!(s->io_bits & 0x0000ff))
625                 config |= I8255_CTRL_A_IO;
626         if (!(s->io_bits & 0x00ff00))
627                 config |= I8255_CTRL_B_IO;
628         if (!(s->io_bits & 0x0f0000))
629                 config |= I8255_CTRL_C_LO_IO;
630         if (!(s->io_bits & 0xf00000))
631                 config |= I8255_CTRL_C_HI_IO;
632         dio200_write8(dev, subpriv->ofs + I8255_CTRL_REG, config);
633 }
634
635 static int dio200_subdev_8255_bits(struct comedi_device *dev,
636                                    struct comedi_subdevice *s,
637                                    struct comedi_insn *insn,
638                                    unsigned int *data)
639 {
640         struct dio200_subdev_8255 *subpriv = s->private;
641         unsigned int mask;
642         unsigned int val;
643
644         mask = comedi_dio_update_state(s, data);
645         if (mask) {
646                 if (mask & 0xff) {
647                         dio200_write8(dev, subpriv->ofs + I8255_DATA_A_REG,
648                                       s->state & 0xff);
649                 }
650                 if (mask & 0xff00) {
651                         dio200_write8(dev, subpriv->ofs + I8255_DATA_B_REG,
652                                       (s->state >> 8) & 0xff);
653                 }
654                 if (mask & 0xff0000) {
655                         dio200_write8(dev, subpriv->ofs + I8255_DATA_C_REG,
656                                       (s->state >> 16) & 0xff);
657                 }
658         }
659
660         val = dio200_read8(dev, subpriv->ofs + I8255_DATA_A_REG);
661         val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_B_REG) << 8;
662         val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_C_REG) << 16;
663
664         data[1] = val;
665
666         return insn->n;
667 }
668
669 static int dio200_subdev_8255_config(struct comedi_device *dev,
670                                      struct comedi_subdevice *s,
671                                      struct comedi_insn *insn,
672                                      unsigned int *data)
673 {
674         unsigned int chan = CR_CHAN(insn->chanspec);
675         unsigned int mask;
676         int ret;
677
678         if (chan < 8)
679                 mask = 0x0000ff;
680         else if (chan < 16)
681                 mask = 0x00ff00;
682         else if (chan < 20)
683                 mask = 0x0f0000;
684         else
685                 mask = 0xf00000;
686
687         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
688         if (ret)
689                 return ret;
690
691         dio200_subdev_8255_set_dir(dev, s);
692
693         return insn->n;
694 }
695
696 static int dio200_subdev_8255_init(struct comedi_device *dev,
697                                    struct comedi_subdevice *s,
698                                    unsigned int offset)
699 {
700         struct dio200_subdev_8255 *subpriv;
701
702         subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
703         if (!subpriv)
704                 return -ENOMEM;
705
706         subpriv->ofs = offset;
707
708         s->type = COMEDI_SUBD_DIO;
709         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
710         s->n_chan = 24;
711         s->range_table = &range_digital;
712         s->maxdata = 1;
713         s->insn_bits = dio200_subdev_8255_bits;
714         s->insn_config = dio200_subdev_8255_config;
715         dio200_subdev_8255_set_dir(dev, s);
716         return 0;
717 }
718
719 static int dio200_subdev_timer_read(struct comedi_device *dev,
720                                     struct comedi_subdevice *s,
721                                     struct comedi_insn *insn,
722                                     unsigned int *data)
723 {
724         unsigned int n;
725
726         for (n = 0; n < insn->n; n++)
727                 data[n] = dio200_read32(dev, DIO200_TS_COUNT);
728         return n;
729 }
730
731 static void dio200_subdev_timer_reset(struct comedi_device *dev,
732                                       struct comedi_subdevice *s)
733 {
734         unsigned int clock;
735
736         clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
737         dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
738         dio200_write32(dev, DIO200_TS_CONFIG, clock);
739 }
740
741 static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
742                                               struct comedi_subdevice *s,
743                                               unsigned int *src,
744                                               unsigned int *period)
745 {
746         unsigned int clk;
747
748         clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
749         *src = clk;
750         *period = (clk < ARRAY_SIZE(ts_clock_period)) ?
751                   ts_clock_period[clk] : 0;
752 }
753
754 static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
755                                              struct comedi_subdevice *s,
756                                              unsigned int src)
757 {
758         if (src > TS_CONFIG_MAX_CLK_SRC)
759                 return -EINVAL;
760         dio200_write32(dev, DIO200_TS_CONFIG, src);
761         return 0;
762 }
763
764 static int dio200_subdev_timer_config(struct comedi_device *dev,
765                                       struct comedi_subdevice *s,
766                                       struct comedi_insn *insn,
767                                       unsigned int *data)
768 {
769         int ret = 0;
770
771         switch (data[0]) {
772         case INSN_CONFIG_RESET:
773                 dio200_subdev_timer_reset(dev, s);
774                 break;
775         case INSN_CONFIG_SET_CLOCK_SRC:
776                 ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
777                 if (ret < 0)
778                         ret = -EINVAL;
779                 break;
780         case INSN_CONFIG_GET_CLOCK_SRC:
781                 dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
782                 break;
783         default:
784                 ret = -EINVAL;
785                 break;
786         }
787         return ret < 0 ? ret : insn->n;
788 }
789
790 void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val)
791 {
792         dio200_write8(dev, DIO200_ENHANCE, val);
793 }
794 EXPORT_SYMBOL_GPL(amplc_dio200_set_enhance);
795
796 int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
797                                unsigned long req_irq_flags)
798 {
799         const struct dio200_board *board = dev->board_ptr;
800         struct comedi_subdevice *s;
801         unsigned int n;
802         int ret;
803
804         ret = comedi_alloc_subdevices(dev, board->n_subdevs);
805         if (ret)
806                 return ret;
807
808         for (n = 0; n < dev->n_subdevices; n++) {
809                 s = &dev->subdevices[n];
810                 switch (board->sdtype[n]) {
811                 case sd_8254:
812                         /* counter subdevice (8254) */
813                         ret = dio200_subdev_8254_init(dev, s,
814                                                       board->sdinfo[n]);
815                         if (ret < 0)
816                                 return ret;
817                         break;
818                 case sd_8255:
819                         /* digital i/o subdevice (8255) */
820                         ret = dio200_subdev_8255_init(dev, s,
821                                                       board->sdinfo[n]);
822                         if (ret < 0)
823                                 return ret;
824                         break;
825                 case sd_intr:
826                         /* 'INTERRUPT' subdevice */
827                         if (irq && !dev->read_subdev) {
828                                 ret = dio200_subdev_intr_init(dev, s,
829                                                               DIO200_INT_SCE,
830                                                               board->sdinfo[n]);
831                                 if (ret < 0)
832                                         return ret;
833                                 dev->read_subdev = s;
834                         } else {
835                                 s->type = COMEDI_SUBD_UNUSED;
836                         }
837                         break;
838                 case sd_timer:
839                         s->type         = COMEDI_SUBD_TIMER;
840                         s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
841                         s->n_chan       = 1;
842                         s->maxdata      = 0xffffffff;
843                         s->insn_read    = dio200_subdev_timer_read;
844                         s->insn_config  = dio200_subdev_timer_config;
845                         break;
846                 default:
847                         s->type = COMEDI_SUBD_UNUSED;
848                         break;
849                 }
850         }
851
852         if (irq && dev->read_subdev) {
853                 if (request_irq(irq, dio200_interrupt, req_irq_flags,
854                                 dev->board_name, dev) >= 0) {
855                         dev->irq = irq;
856                 } else {
857                         dev_warn(dev->class_dev,
858                                  "warning! irq %u unavailable!\n", irq);
859                 }
860         }
861
862         return 0;
863 }
864 EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
865
866 static int __init amplc_dio200_common_init(void)
867 {
868         return 0;
869 }
870 module_init(amplc_dio200_common_init);
871
872 static void __exit amplc_dio200_common_exit(void)
873 {
874 }
875 module_exit(amplc_dio200_common_exit);
876
877 MODULE_AUTHOR("Comedi http://www.comedi.org");
878 MODULE_DESCRIPTION("Comedi helper for amplc_dio200 and amplc_dio200_pci");
879 MODULE_LICENSE("GPL");