Add the rt linux 4.1.3-rt3 as base
[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         spin_unlock_irqrestore(&subpriv->spinlock, flags);
346
347         comedi_handle_events(dev, s);
348
349         return (triggered != 0);
350 }
351
352 static int dio200_subdev_intr_cancel(struct comedi_device *dev,
353                                      struct comedi_subdevice *s)
354 {
355         struct dio200_subdev_intr *subpriv = s->private;
356         unsigned long flags;
357
358         spin_lock_irqsave(&subpriv->spinlock, flags);
359         if (subpriv->active)
360                 dio200_stop_intr(dev, s);
361
362         spin_unlock_irqrestore(&subpriv->spinlock, flags);
363
364         return 0;
365 }
366
367 static int dio200_subdev_intr_cmdtest(struct comedi_device *dev,
368                                       struct comedi_subdevice *s,
369                                       struct comedi_cmd *cmd)
370 {
371         int err = 0;
372
373         /* Step 1 : check if triggers are trivially valid */
374
375         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
376         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
377         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_NOW);
378         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
379         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
380
381         if (err)
382                 return 1;
383
384         /* Step 2a : make sure trigger sources are unique */
385
386         err |= comedi_check_trigger_is_unique(cmd->start_src);
387         err |= comedi_check_trigger_is_unique(cmd->stop_src);
388
389         /* Step 2b : and mutually compatible */
390
391         if (err)
392                 return 2;
393
394         /* Step 3: check if arguments are trivially valid */
395
396         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
397         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
398         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
399         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
400                                            cmd->chanlist_len);
401
402         if (cmd->stop_src == TRIG_COUNT)
403                 err |= comedi_check_trigger_arg_min(&cmd->stop_arg, 1);
404         else    /* TRIG_NONE */
405                 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
406
407         if (err)
408                 return 3;
409
410         /* step 4: fix up any arguments */
411
412         /* if (err) return 4; */
413
414         return 0;
415 }
416
417 static int dio200_subdev_intr_cmd(struct comedi_device *dev,
418                                   struct comedi_subdevice *s)
419 {
420         struct comedi_cmd *cmd = &s->async->cmd;
421         struct dio200_subdev_intr *subpriv = s->private;
422         unsigned long flags;
423
424         spin_lock_irqsave(&subpriv->spinlock, flags);
425
426         subpriv->active = true;
427
428         if (cmd->start_src == TRIG_INT)
429                 s->async->inttrig = dio200_inttrig_start_intr;
430         else    /* TRIG_NOW */
431                 dio200_start_intr(dev, s);
432
433         spin_unlock_irqrestore(&subpriv->spinlock, flags);
434
435         return 0;
436 }
437
438 static int dio200_subdev_intr_init(struct comedi_device *dev,
439                                    struct comedi_subdevice *s,
440                                    unsigned int offset,
441                                    unsigned valid_isns)
442 {
443         const struct dio200_board *board = dev->board_ptr;
444         struct dio200_subdev_intr *subpriv;
445
446         subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
447         if (!subpriv)
448                 return -ENOMEM;
449
450         subpriv->ofs = offset;
451         subpriv->valid_isns = valid_isns;
452         spin_lock_init(&subpriv->spinlock);
453
454         if (board->has_int_sce)
455                 /* Disable interrupt sources. */
456                 dio200_write8(dev, subpriv->ofs, 0);
457
458         s->type = COMEDI_SUBD_DI;
459         s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_PACKED;
460         if (board->has_int_sce) {
461                 s->n_chan = DIO200_MAX_ISNS;
462                 s->len_chanlist = DIO200_MAX_ISNS;
463         } else {
464                 /* No interrupt source register.  Support single channel. */
465                 s->n_chan = 1;
466                 s->len_chanlist = 1;
467         }
468         s->range_table = &range_digital;
469         s->maxdata = 1;
470         s->insn_bits = dio200_subdev_intr_insn_bits;
471         s->do_cmdtest = dio200_subdev_intr_cmdtest;
472         s->do_cmd = dio200_subdev_intr_cmd;
473         s->cancel = dio200_subdev_intr_cancel;
474
475         return 0;
476 }
477
478 static irqreturn_t dio200_interrupt(int irq, void *d)
479 {
480         struct comedi_device *dev = d;
481         struct comedi_subdevice *s = dev->read_subdev;
482         int handled;
483
484         if (!dev->attached)
485                 return IRQ_NONE;
486
487         handled = dio200_handle_read_intr(dev, s);
488
489         return IRQ_RETVAL(handled);
490 }
491
492 static void dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
493                                             struct comedi_subdevice *s,
494                                             unsigned int chan,
495                                             unsigned int src)
496 {
497         unsigned int offset = dio200_subdev_8254_offset(dev, s);
498
499         dio200_write8(dev, DIO200_GAT_SCE(offset >> 3),
500                       gat_sce((offset >> 2) & 1, chan, src));
501 }
502
503 static void dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
504                                              struct comedi_subdevice *s,
505                                              unsigned int chan,
506                                              unsigned int src)
507 {
508         unsigned int offset = dio200_subdev_8254_offset(dev, s);
509
510         dio200_write8(dev, DIO200_CLK_SCE(offset >> 3),
511                       clk_sce((offset >> 2) & 1, chan, src));
512 }
513
514 static int dio200_subdev_8254_config(struct comedi_device *dev,
515                                      struct comedi_subdevice *s,
516                                      struct comedi_insn *insn,
517                                      unsigned int *data)
518 {
519         const struct dio200_board *board = dev->board_ptr;
520         struct comedi_8254 *i8254 = s->private;
521         unsigned int chan = CR_CHAN(insn->chanspec);
522         unsigned int max_src = board->is_pcie ? 31 : 7;
523         unsigned int src;
524
525         if (!board->has_clk_gat_sce)
526                 return -EINVAL;
527
528         switch (data[0]) {
529         case INSN_CONFIG_SET_GATE_SRC:
530                 src = data[2];
531                 if (src > max_src)
532                         return -EINVAL;
533
534                 dio200_subdev_8254_set_gate_src(dev, s, chan, src);
535                 i8254->gate_src[chan] = src;
536                 break;
537         case INSN_CONFIG_GET_GATE_SRC:
538                 data[2] = i8254->gate_src[chan];
539                 break;
540         case INSN_CONFIG_SET_CLOCK_SRC:
541                 src = data[1];
542                 if (src > max_src)
543                         return -EINVAL;
544
545                 dio200_subdev_8254_set_clock_src(dev, s, chan, src);
546                 i8254->clock_src[chan] = src;
547                 break;
548         case INSN_CONFIG_GET_CLOCK_SRC:
549                 data[1] = i8254->clock_src[chan];
550                 data[2] = clock_period[i8254->clock_src[chan]];
551                 break;
552         default:
553                 return -EINVAL;
554         }
555
556         return insn->n;
557 }
558
559 static int dio200_subdev_8254_init(struct comedi_device *dev,
560                                    struct comedi_subdevice *s,
561                                    unsigned int offset)
562 {
563         const struct dio200_board *board = dev->board_ptr;
564         struct comedi_8254 *i8254;
565         unsigned int regshift;
566         int chan;
567
568         /*
569          * PCIe boards need the offset shifted in order to get the
570          * correct base address of the timer.
571          */
572         if (board->is_pcie) {
573                 offset <<= 3;
574                 regshift = 3;
575         } else {
576                 regshift = 0;
577         }
578
579         if (dev->mmio)
580                 i8254 = comedi_8254_mm_init(dev->mmio + offset,
581                                             0, I8254_IO8, regshift);
582         else
583                 i8254 = comedi_8254_init(dev->iobase + offset,
584                                          0, I8254_IO8, regshift);
585         if (!i8254)
586                 return -ENOMEM;
587
588         comedi_8254_subdevice_init(s, i8254);
589
590         i8254->insn_config = dio200_subdev_8254_config;
591
592         /*
593          * There could be multiple timers so this driver does not
594          * use dev->pacer to save the i8254 pointer. Instead,
595          * comedi_8254_subdevice_init() saved the i8254 pointer in
596          * s->private. Set the runflag bit so that the core will
597          * automatically free it when the driver is detached.
598          */
599         s->runflags |= COMEDI_SRF_FREE_SPRIV;
600
601         /* Initialize channels. */
602         if (board->has_clk_gat_sce) {
603                 for (chan = 0; chan < 3; chan++) {
604                         /* Gate source 0 is VCC (logic 1). */
605                         dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
606                         /* Clock source 0 is the dedicated clock input. */
607                         dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
608                 }
609         }
610
611         return 0;
612 }
613
614 static void dio200_subdev_8255_set_dir(struct comedi_device *dev,
615                                        struct comedi_subdevice *s)
616 {
617         struct dio200_subdev_8255 *subpriv = s->private;
618         int config;
619
620         config = I8255_CTRL_CW;
621         /* 1 in io_bits indicates output, 1 in config indicates input */
622         if (!(s->io_bits & 0x0000ff))
623                 config |= I8255_CTRL_A_IO;
624         if (!(s->io_bits & 0x00ff00))
625                 config |= I8255_CTRL_B_IO;
626         if (!(s->io_bits & 0x0f0000))
627                 config |= I8255_CTRL_C_LO_IO;
628         if (!(s->io_bits & 0xf00000))
629                 config |= I8255_CTRL_C_HI_IO;
630         dio200_write8(dev, subpriv->ofs + I8255_CTRL_REG, config);
631 }
632
633 static int dio200_subdev_8255_bits(struct comedi_device *dev,
634                                    struct comedi_subdevice *s,
635                                    struct comedi_insn *insn,
636                                    unsigned int *data)
637 {
638         struct dio200_subdev_8255 *subpriv = s->private;
639         unsigned int mask;
640         unsigned int val;
641
642         mask = comedi_dio_update_state(s, data);
643         if (mask) {
644                 if (mask & 0xff)
645                         dio200_write8(dev, subpriv->ofs + I8255_DATA_A_REG,
646                                       s->state & 0xff);
647                 if (mask & 0xff00)
648                         dio200_write8(dev, subpriv->ofs + I8255_DATA_B_REG,
649                                       (s->state >> 8) & 0xff);
650                 if (mask & 0xff0000)
651                         dio200_write8(dev, subpriv->ofs + I8255_DATA_C_REG,
652                                       (s->state >> 16) & 0xff);
653         }
654
655         val = dio200_read8(dev, subpriv->ofs + I8255_DATA_A_REG);
656         val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_B_REG) << 8;
657         val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_C_REG) << 16;
658
659         data[1] = val;
660
661         return insn->n;
662 }
663
664 static int dio200_subdev_8255_config(struct comedi_device *dev,
665                                      struct comedi_subdevice *s,
666                                      struct comedi_insn *insn,
667                                      unsigned int *data)
668 {
669         unsigned int chan = CR_CHAN(insn->chanspec);
670         unsigned int mask;
671         int ret;
672
673         if (chan < 8)
674                 mask = 0x0000ff;
675         else if (chan < 16)
676                 mask = 0x00ff00;
677         else if (chan < 20)
678                 mask = 0x0f0000;
679         else
680                 mask = 0xf00000;
681
682         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
683         if (ret)
684                 return ret;
685
686         dio200_subdev_8255_set_dir(dev, s);
687
688         return insn->n;
689 }
690
691 static int dio200_subdev_8255_init(struct comedi_device *dev,
692                                    struct comedi_subdevice *s,
693                                    unsigned int offset)
694 {
695         struct dio200_subdev_8255 *subpriv;
696
697         subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
698         if (!subpriv)
699                 return -ENOMEM;
700
701         subpriv->ofs = offset;
702
703         s->type = COMEDI_SUBD_DIO;
704         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
705         s->n_chan = 24;
706         s->range_table = &range_digital;
707         s->maxdata = 1;
708         s->insn_bits = dio200_subdev_8255_bits;
709         s->insn_config = dio200_subdev_8255_config;
710         dio200_subdev_8255_set_dir(dev, s);
711         return 0;
712 }
713
714 static int dio200_subdev_timer_read(struct comedi_device *dev,
715                                     struct comedi_subdevice *s,
716                                     struct comedi_insn *insn,
717                                     unsigned int *data)
718 {
719         unsigned int n;
720
721         for (n = 0; n < insn->n; n++)
722                 data[n] = dio200_read32(dev, DIO200_TS_COUNT);
723         return n;
724 }
725
726 static void dio200_subdev_timer_reset(struct comedi_device *dev,
727                                       struct comedi_subdevice *s)
728 {
729         unsigned int clock;
730
731         clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
732         dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
733         dio200_write32(dev, DIO200_TS_CONFIG, clock);
734 }
735
736 static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
737                                               struct comedi_subdevice *s,
738                                               unsigned int *src,
739                                               unsigned int *period)
740 {
741         unsigned int clk;
742
743         clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
744         *src = clk;
745         *period = (clk < ARRAY_SIZE(ts_clock_period)) ?
746                   ts_clock_period[clk] : 0;
747 }
748
749 static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
750                                              struct comedi_subdevice *s,
751                                              unsigned int src)
752 {
753         if (src > TS_CONFIG_MAX_CLK_SRC)
754                 return -EINVAL;
755         dio200_write32(dev, DIO200_TS_CONFIG, src);
756         return 0;
757 }
758
759 static int dio200_subdev_timer_config(struct comedi_device *dev,
760                                       struct comedi_subdevice *s,
761                                       struct comedi_insn *insn,
762                                       unsigned int *data)
763 {
764         int ret = 0;
765
766         switch (data[0]) {
767         case INSN_CONFIG_RESET:
768                 dio200_subdev_timer_reset(dev, s);
769                 break;
770         case INSN_CONFIG_SET_CLOCK_SRC:
771                 ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
772                 if (ret < 0)
773                         ret = -EINVAL;
774                 break;
775         case INSN_CONFIG_GET_CLOCK_SRC:
776                 dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
777                 break;
778         default:
779                 ret = -EINVAL;
780                 break;
781         }
782         return ret < 0 ? ret : insn->n;
783 }
784
785 void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val)
786 {
787         dio200_write8(dev, DIO200_ENHANCE, val);
788 }
789 EXPORT_SYMBOL_GPL(amplc_dio200_set_enhance);
790
791 int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
792                                unsigned long req_irq_flags)
793 {
794         const struct dio200_board *board = dev->board_ptr;
795         struct comedi_subdevice *s;
796         unsigned int n;
797         int ret;
798
799         ret = comedi_alloc_subdevices(dev, board->n_subdevs);
800         if (ret)
801                 return ret;
802
803         for (n = 0; n < dev->n_subdevices; n++) {
804                 s = &dev->subdevices[n];
805                 switch (board->sdtype[n]) {
806                 case sd_8254:
807                         /* counter subdevice (8254) */
808                         ret = dio200_subdev_8254_init(dev, s,
809                                                       board->sdinfo[n]);
810                         if (ret < 0)
811                                 return ret;
812                         break;
813                 case sd_8255:
814                         /* digital i/o subdevice (8255) */
815                         ret = dio200_subdev_8255_init(dev, s,
816                                                       board->sdinfo[n]);
817                         if (ret < 0)
818                                 return ret;
819                         break;
820                 case sd_intr:
821                         /* 'INTERRUPT' subdevice */
822                         if (irq && !dev->read_subdev) {
823                                 ret = dio200_subdev_intr_init(dev, s,
824                                                               DIO200_INT_SCE,
825                                                               board->sdinfo[n]);
826                                 if (ret < 0)
827                                         return ret;
828                                 dev->read_subdev = s;
829                         } else {
830                                 s->type = COMEDI_SUBD_UNUSED;
831                         }
832                         break;
833                 case sd_timer:
834                         s->type         = COMEDI_SUBD_TIMER;
835                         s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
836                         s->n_chan       = 1;
837                         s->maxdata      = 0xffffffff;
838                         s->insn_read    = dio200_subdev_timer_read;
839                         s->insn_config  = dio200_subdev_timer_config;
840                         break;
841                 default:
842                         s->type = COMEDI_SUBD_UNUSED;
843                         break;
844                 }
845         }
846
847         if (irq && dev->read_subdev) {
848                 if (request_irq(irq, dio200_interrupt, req_irq_flags,
849                                 dev->board_name, dev) >= 0) {
850                         dev->irq = irq;
851                 } else {
852                         dev_warn(dev->class_dev,
853                                  "warning! irq %u unavailable!\n", irq);
854                 }
855         }
856
857         return 0;
858 }
859 EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
860
861 static int __init amplc_dio200_common_init(void)
862 {
863         return 0;
864 }
865 module_init(amplc_dio200_common_init);
866
867 static void __exit amplc_dio200_common_exit(void)
868 {
869 }
870 module_exit(amplc_dio200_common_exit);
871
872 MODULE_AUTHOR("Comedi http://www.comedi.org");
873 MODULE_DESCRIPTION("Comedi helper for amplc_dio200 and amplc_dio200_pci");
874 MODULE_LICENSE("GPL");