Merge tag 'mac80211-next-for-davem-2015-02-03' of git://git.kernel.org/pub/scm/linux...
[firefly-linux-kernel-4.4.55.git] / 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_fc.h"
29 #include "8253.h"
30 #include "8255.h"               /* only for register defines */
31
32 /* 200 series registers */
33 #define DIO200_IO_SIZE          0x20
34 #define DIO200_PCIE_IO_SIZE     0x4000
35 #define DIO200_XCLK_SCE         0x18    /* Group X clock selection register */
36 #define DIO200_YCLK_SCE         0x19    /* Group Y clock selection register */
37 #define DIO200_ZCLK_SCE         0x1a    /* Group Z clock selection register */
38 #define DIO200_XGAT_SCE         0x1b    /* Group X gate selection register */
39 #define DIO200_YGAT_SCE         0x1c    /* Group Y gate selection register */
40 #define DIO200_ZGAT_SCE         0x1d    /* Group Z gate selection register */
41 #define DIO200_INT_SCE          0x1e    /* Interrupt enable/status register */
42 /* Extra registers for new PCIe boards */
43 #define DIO200_ENHANCE          0x20    /* 1 to enable enhanced features */
44 #define DIO200_VERSION          0x24    /* Hardware version register */
45 #define DIO200_TS_CONFIG        0x600   /* Timestamp timer config register */
46 #define DIO200_TS_COUNT         0x602   /* Timestamp timer count register */
47
48 /*
49  * Functions for constructing value for DIO_200_?CLK_SCE and
50  * DIO_200_?GAT_SCE registers:
51  *
52  * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
53  * 'chan' is the channel: 0, 1 or 2.
54  * 'source' is the signal source: 0 to 7, or 0 to 31 for "enhanced" boards.
55  */
56 static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
57                                  unsigned int source)
58 {
59         return (which << 5) | (chan << 3) |
60                ((source & 030) << 3) | (source & 007);
61 }
62
63 static unsigned char clk_sce(unsigned int which, unsigned int chan,
64                              unsigned int source)
65 {
66         return clk_gat_sce(which, chan, source);
67 }
68
69 static unsigned char gat_sce(unsigned int which, unsigned int chan,
70                              unsigned int source)
71 {
72         return clk_gat_sce(which, chan, source);
73 }
74
75 /*
76  * Periods of the internal clock sources in nanoseconds.
77  */
78 static const unsigned int clock_period[32] = {
79         [1] = 100,              /* 10 MHz */
80         [2] = 1000,             /* 1 MHz */
81         [3] = 10000,            /* 100 kHz */
82         [4] = 100000,           /* 10 kHz */
83         [5] = 1000000,          /* 1 kHz */
84         [11] = 50,              /* 20 MHz (enhanced boards) */
85         /* clock sources 12 and later reserved for enhanced boards */
86 };
87
88 /*
89  * Timestamp timer configuration register (for new PCIe boards).
90  */
91 #define TS_CONFIG_RESET         0x100   /* Reset counter to zero. */
92 #define TS_CONFIG_CLK_SRC_MASK  0x0FF   /* Clock source. */
93 #define TS_CONFIG_MAX_CLK_SRC   2       /* Maximum clock source value. */
94
95 /*
96  * Periods of the timestamp timer clock sources in nanoseconds.
97  */
98 static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
99         1,                      /* 1 nanosecond (but with 20 ns granularity). */
100         1000,                   /* 1 microsecond. */
101         1000000,                /* 1 millisecond. */
102 };
103
104 struct dio200_subdev_8254 {
105         unsigned int ofs;               /* Counter base offset */
106         unsigned int clk_sce_ofs;       /* CLK_SCE base address */
107         unsigned int gat_sce_ofs;       /* GAT_SCE base address */
108         int which;                      /* Bit 5 of CLK_SCE or GAT_SCE */
109         unsigned int clock_src[3];      /* Current clock sources */
110         unsigned int gate_src[3];       /* Current gate sources */
111         spinlock_t spinlock;
112 };
113
114 struct dio200_subdev_8255 {
115         unsigned int ofs;               /* DIO base offset */
116 };
117
118 struct dio200_subdev_intr {
119         spinlock_t spinlock;
120         unsigned int ofs;
121         unsigned int valid_isns;
122         unsigned int enabled_isns;
123         bool active:1;
124 };
125
126 static unsigned char dio200_read8(struct comedi_device *dev,
127                                   unsigned int offset)
128 {
129         const struct dio200_board *board = dev->board_ptr;
130
131         if (board->is_pcie)
132                 offset <<= 3;
133
134         if (dev->mmio)
135                 return readb(dev->mmio + offset);
136         return inb(dev->iobase + offset);
137 }
138
139 static void dio200_write8(struct comedi_device *dev,
140                           unsigned int offset, unsigned char val)
141 {
142         const struct dio200_board *board = dev->board_ptr;
143
144         if (board->is_pcie)
145                 offset <<= 3;
146
147         if (dev->mmio)
148                 writeb(val, dev->mmio + offset);
149         else
150                 outb(val, dev->iobase + offset);
151 }
152
153 static unsigned int dio200_read32(struct comedi_device *dev,
154                                   unsigned int offset)
155 {
156         const struct dio200_board *board = dev->board_ptr;
157
158         if (board->is_pcie)
159                 offset <<= 3;
160
161         if (dev->mmio)
162                 return readl(dev->mmio + offset);
163         return inl(dev->iobase + offset);
164 }
165
166 static void dio200_write32(struct comedi_device *dev,
167                            unsigned int offset, unsigned int val)
168 {
169         const struct dio200_board *board = dev->board_ptr;
170
171         if (board->is_pcie)
172                 offset <<= 3;
173
174         if (dev->mmio)
175                 writel(val, dev->mmio + offset);
176         else
177                 outl(val, dev->iobase + offset);
178 }
179
180 static int dio200_subdev_intr_insn_bits(struct comedi_device *dev,
181                                         struct comedi_subdevice *s,
182                                         struct comedi_insn *insn,
183                                         unsigned int *data)
184 {
185         const struct dio200_board *board = dev->board_ptr;
186         struct dio200_subdev_intr *subpriv = s->private;
187
188         if (board->has_int_sce) {
189                 /* Just read the interrupt status register.  */
190                 data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns;
191         } else {
192                 /* No interrupt status register. */
193                 data[0] = 0;
194         }
195
196         return insn->n;
197 }
198
199 static void dio200_stop_intr(struct comedi_device *dev,
200                              struct comedi_subdevice *s)
201 {
202         const struct dio200_board *board = dev->board_ptr;
203         struct dio200_subdev_intr *subpriv = s->private;
204
205         subpriv->active = false;
206         subpriv->enabled_isns = 0;
207         if (board->has_int_sce)
208                 dio200_write8(dev, subpriv->ofs, 0);
209 }
210
211 static void dio200_start_intr(struct comedi_device *dev,
212                               struct comedi_subdevice *s)
213 {
214         const struct dio200_board *board = dev->board_ptr;
215         struct dio200_subdev_intr *subpriv = s->private;
216         struct comedi_cmd *cmd = &s->async->cmd;
217         unsigned int n;
218         unsigned isn_bits;
219
220         /* Determine interrupt sources to enable. */
221         isn_bits = 0;
222         if (cmd->chanlist) {
223                 for (n = 0; n < cmd->chanlist_len; n++)
224                         isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
225         }
226         isn_bits &= subpriv->valid_isns;
227         /* Enable interrupt sources. */
228         subpriv->enabled_isns = isn_bits;
229         if (board->has_int_sce)
230                 dio200_write8(dev, subpriv->ofs, isn_bits);
231 }
232
233 static int dio200_inttrig_start_intr(struct comedi_device *dev,
234                                      struct comedi_subdevice *s,
235                                      unsigned int trig_num)
236 {
237         struct dio200_subdev_intr *subpriv = s->private;
238         struct comedi_cmd *cmd = &s->async->cmd;
239         unsigned long flags;
240
241         if (trig_num != cmd->start_arg)
242                 return -EINVAL;
243
244         spin_lock_irqsave(&subpriv->spinlock, flags);
245         s->async->inttrig = NULL;
246         if (subpriv->active)
247                 dio200_start_intr(dev, s);
248
249         spin_unlock_irqrestore(&subpriv->spinlock, flags);
250
251         return 1;
252 }
253
254 static void dio200_read_scan_intr(struct comedi_device *dev,
255                                   struct comedi_subdevice *s,
256                                   unsigned int triggered)
257 {
258         struct comedi_cmd *cmd = &s->async->cmd;
259         unsigned short val;
260         unsigned int n, ch;
261
262         val = 0;
263         for (n = 0; n < cmd->chanlist_len; n++) {
264                 ch = CR_CHAN(cmd->chanlist[n]);
265                 if (triggered & (1U << ch))
266                         val |= (1U << n);
267         }
268
269         comedi_buf_write_samples(s, &val, 1);
270
271         if (cmd->stop_src == TRIG_COUNT &&
272             s->async->scans_done >= cmd->stop_arg)
273                 s->async->events |= COMEDI_CB_EOA;
274 }
275
276 static int dio200_handle_read_intr(struct comedi_device *dev,
277                                    struct comedi_subdevice *s)
278 {
279         const struct dio200_board *board = dev->board_ptr;
280         struct dio200_subdev_intr *subpriv = s->private;
281         unsigned triggered;
282         unsigned intstat;
283         unsigned cur_enabled;
284         unsigned long flags;
285
286         triggered = 0;
287
288         spin_lock_irqsave(&subpriv->spinlock, flags);
289         if (board->has_int_sce) {
290                 /*
291                  * Collect interrupt sources that have triggered and disable
292                  * them temporarily.  Loop around until no extra interrupt
293                  * sources have triggered, at which point, the valid part of
294                  * the interrupt status register will read zero, clearing the
295                  * cause of the interrupt.
296                  *
297                  * Mask off interrupt sources already seen to avoid infinite
298                  * loop in case of misconfiguration.
299                  */
300                 cur_enabled = subpriv->enabled_isns;
301                 while ((intstat = (dio200_read8(dev, subpriv->ofs) &
302                                    subpriv->valid_isns & ~triggered)) != 0) {
303                         triggered |= intstat;
304                         cur_enabled &= ~triggered;
305                         dio200_write8(dev, subpriv->ofs, cur_enabled);
306                 }
307         } else {
308                 /*
309                  * No interrupt status register.  Assume the single interrupt
310                  * source has triggered.
311                  */
312                 triggered = subpriv->enabled_isns;
313         }
314
315         if (triggered) {
316                 /*
317                  * Some interrupt sources have triggered and have been
318                  * temporarily disabled to clear the cause of the interrupt.
319                  *
320                  * Reenable them NOW to minimize the time they are disabled.
321                  */
322                 cur_enabled = subpriv->enabled_isns;
323                 if (board->has_int_sce)
324                         dio200_write8(dev, subpriv->ofs, cur_enabled);
325
326                 if (subpriv->active) {
327                         /*
328                          * The command is still active.
329                          *
330                          * Ignore interrupt sources that the command isn't
331                          * interested in (just in case there's a race
332                          * condition).
333                          */
334                         if (triggered & subpriv->enabled_isns)
335                                 /* Collect scan data. */
336                                 dio200_read_scan_intr(dev, s, triggered);
337                 }
338         }
339         spin_unlock_irqrestore(&subpriv->spinlock, flags);
340
341         comedi_handle_events(dev, s);
342
343         return (triggered != 0);
344 }
345
346 static int dio200_subdev_intr_cancel(struct comedi_device *dev,
347                                      struct comedi_subdevice *s)
348 {
349         struct dio200_subdev_intr *subpriv = s->private;
350         unsigned long flags;
351
352         spin_lock_irqsave(&subpriv->spinlock, flags);
353         if (subpriv->active)
354                 dio200_stop_intr(dev, s);
355
356         spin_unlock_irqrestore(&subpriv->spinlock, flags);
357
358         return 0;
359 }
360
361 static int dio200_subdev_intr_cmdtest(struct comedi_device *dev,
362                                       struct comedi_subdevice *s,
363                                       struct comedi_cmd *cmd)
364 {
365         int err = 0;
366
367         /* Step 1 : check if triggers are trivially valid */
368
369         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
370         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
371         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
372         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
373         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
374
375         if (err)
376                 return 1;
377
378         /* Step 2a : make sure trigger sources are unique */
379
380         err |= cfc_check_trigger_is_unique(cmd->start_src);
381         err |= cfc_check_trigger_is_unique(cmd->stop_src);
382
383         /* Step 2b : and mutually compatible */
384
385         if (err)
386                 return 2;
387
388         /* Step 3: check if arguments are trivially valid */
389
390         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
391         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
392         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
393         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
394
395         if (cmd->stop_src == TRIG_COUNT)
396                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
397         else    /* TRIG_NONE */
398                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
399
400         if (err)
401                 return 3;
402
403         /* step 4: fix up any arguments */
404
405         /* if (err) return 4; */
406
407         return 0;
408 }
409
410 static int dio200_subdev_intr_cmd(struct comedi_device *dev,
411                                   struct comedi_subdevice *s)
412 {
413         struct comedi_cmd *cmd = &s->async->cmd;
414         struct dio200_subdev_intr *subpriv = s->private;
415         unsigned long flags;
416
417         spin_lock_irqsave(&subpriv->spinlock, flags);
418
419         subpriv->active = true;
420
421         if (cmd->start_src == TRIG_INT)
422                 s->async->inttrig = dio200_inttrig_start_intr;
423         else    /* TRIG_NOW */
424                 dio200_start_intr(dev, s);
425
426         spin_unlock_irqrestore(&subpriv->spinlock, flags);
427
428         return 0;
429 }
430
431 static int dio200_subdev_intr_init(struct comedi_device *dev,
432                                    struct comedi_subdevice *s,
433                                    unsigned int offset,
434                                    unsigned valid_isns)
435 {
436         const struct dio200_board *board = dev->board_ptr;
437         struct dio200_subdev_intr *subpriv;
438
439         subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
440         if (!subpriv)
441                 return -ENOMEM;
442
443         subpriv->ofs = offset;
444         subpriv->valid_isns = valid_isns;
445         spin_lock_init(&subpriv->spinlock);
446
447         if (board->has_int_sce)
448                 /* Disable interrupt sources. */
449                 dio200_write8(dev, subpriv->ofs, 0);
450
451         s->type = COMEDI_SUBD_DI;
452         s->subdev_flags = SDF_READABLE | SDF_CMD_READ | SDF_PACKED;
453         if (board->has_int_sce) {
454                 s->n_chan = DIO200_MAX_ISNS;
455                 s->len_chanlist = DIO200_MAX_ISNS;
456         } else {
457                 /* No interrupt source register.  Support single channel. */
458                 s->n_chan = 1;
459                 s->len_chanlist = 1;
460         }
461         s->range_table = &range_digital;
462         s->maxdata = 1;
463         s->insn_bits = dio200_subdev_intr_insn_bits;
464         s->do_cmdtest = dio200_subdev_intr_cmdtest;
465         s->do_cmd = dio200_subdev_intr_cmd;
466         s->cancel = dio200_subdev_intr_cancel;
467
468         return 0;
469 }
470
471 static irqreturn_t dio200_interrupt(int irq, void *d)
472 {
473         struct comedi_device *dev = d;
474         struct comedi_subdevice *s = dev->read_subdev;
475         int handled;
476
477         if (!dev->attached)
478                 return IRQ_NONE;
479
480         handled = dio200_handle_read_intr(dev, s);
481
482         return IRQ_RETVAL(handled);
483 }
484
485 static unsigned int dio200_subdev_8254_read_chan(struct comedi_device *dev,
486                                                  struct comedi_subdevice *s,
487                                                  unsigned int chan)
488 {
489         struct dio200_subdev_8254 *subpriv = s->private;
490         unsigned int val;
491
492         /* latch counter */
493         val = chan << 6;
494         dio200_write8(dev, subpriv->ofs + i8254_control_reg, val);
495         /* read lsb, msb */
496         val = dio200_read8(dev, subpriv->ofs + chan);
497         val += dio200_read8(dev, subpriv->ofs + chan) << 8;
498         return val;
499 }
500
501 static void dio200_subdev_8254_write_chan(struct comedi_device *dev,
502                                           struct comedi_subdevice *s,
503                                           unsigned int chan,
504                                           unsigned int count)
505 {
506         struct dio200_subdev_8254 *subpriv = s->private;
507
508         /* write lsb, msb */
509         dio200_write8(dev, subpriv->ofs + chan, count & 0xff);
510         dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
511 }
512
513 static void dio200_subdev_8254_set_mode(struct comedi_device *dev,
514                                         struct comedi_subdevice *s,
515                                         unsigned int chan,
516                                         unsigned int mode)
517 {
518         struct dio200_subdev_8254 *subpriv = s->private;
519         unsigned int byte;
520
521         byte = chan << 6;
522         byte |= 0x30;           /* access order: lsb, msb */
523         byte |= (mode & 0xf);   /* counter mode and BCD|binary */
524         dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
525 }
526
527 static unsigned int dio200_subdev_8254_status(struct comedi_device *dev,
528                                               struct comedi_subdevice *s,
529                                               unsigned int chan)
530 {
531         struct dio200_subdev_8254 *subpriv = s->private;
532
533         /* latch status */
534         dio200_write8(dev, subpriv->ofs + i8254_control_reg,
535                       0xe0 | (2 << chan));
536         /* read status */
537         return dio200_read8(dev, subpriv->ofs + chan);
538 }
539
540 static int dio200_subdev_8254_read(struct comedi_device *dev,
541                                    struct comedi_subdevice *s,
542                                    struct comedi_insn *insn,
543                                    unsigned int *data)
544 {
545         struct dio200_subdev_8254 *subpriv = s->private;
546         int chan = CR_CHAN(insn->chanspec);
547         unsigned int n;
548         unsigned long flags;
549
550         for (n = 0; n < insn->n; n++) {
551                 spin_lock_irqsave(&subpriv->spinlock, flags);
552                 data[n] = dio200_subdev_8254_read_chan(dev, s, chan);
553                 spin_unlock_irqrestore(&subpriv->spinlock, flags);
554         }
555         return insn->n;
556 }
557
558 static int dio200_subdev_8254_write(struct comedi_device *dev,
559                                     struct comedi_subdevice *s,
560                                     struct comedi_insn *insn,
561                                     unsigned int *data)
562 {
563         struct dio200_subdev_8254 *subpriv = s->private;
564         int chan = CR_CHAN(insn->chanspec);
565         unsigned int n;
566         unsigned long flags;
567
568         for (n = 0; n < insn->n; n++) {
569                 spin_lock_irqsave(&subpriv->spinlock, flags);
570                 dio200_subdev_8254_write_chan(dev, s, chan, data[n]);
571                 spin_unlock_irqrestore(&subpriv->spinlock, flags);
572         }
573         return insn->n;
574 }
575
576 static int dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
577                                            struct comedi_subdevice *s,
578                                            unsigned int counter_number,
579                                            unsigned int gate_src)
580 {
581         const struct dio200_board *board = dev->board_ptr;
582         struct dio200_subdev_8254 *subpriv = s->private;
583         unsigned char byte;
584
585         if (!board->has_clk_gat_sce)
586                 return -1;
587         if (counter_number > 2)
588                 return -1;
589         if (gate_src > (board->is_pcie ? 31 : 7))
590                 return -1;
591
592         subpriv->gate_src[counter_number] = gate_src;
593         byte = gat_sce(subpriv->which, counter_number, gate_src);
594         dio200_write8(dev, subpriv->gat_sce_ofs, byte);
595
596         return 0;
597 }
598
599 static int dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
600                                            struct comedi_subdevice *s,
601                                            unsigned int counter_number)
602 {
603         const struct dio200_board *board = dev->board_ptr;
604         struct dio200_subdev_8254 *subpriv = s->private;
605
606         if (!board->has_clk_gat_sce)
607                 return -1;
608         if (counter_number > 2)
609                 return -1;
610
611         return subpriv->gate_src[counter_number];
612 }
613
614 static int dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
615                                             struct comedi_subdevice *s,
616                                             unsigned int counter_number,
617                                             unsigned int clock_src)
618 {
619         const struct dio200_board *board = dev->board_ptr;
620         struct dio200_subdev_8254 *subpriv = s->private;
621         unsigned char byte;
622
623         if (!board->has_clk_gat_sce)
624                 return -1;
625         if (counter_number > 2)
626                 return -1;
627         if (clock_src > (board->is_pcie ? 31 : 7))
628                 return -1;
629
630         subpriv->clock_src[counter_number] = clock_src;
631         byte = clk_sce(subpriv->which, counter_number, clock_src);
632         dio200_write8(dev, subpriv->clk_sce_ofs, byte);
633
634         return 0;
635 }
636
637 static int dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
638                                             struct comedi_subdevice *s,
639                                             unsigned int counter_number,
640                                             unsigned int *period_ns)
641 {
642         const struct dio200_board *board = dev->board_ptr;
643         struct dio200_subdev_8254 *subpriv = s->private;
644         unsigned clock_src;
645
646         if (!board->has_clk_gat_sce)
647                 return -1;
648         if (counter_number > 2)
649                 return -1;
650
651         clock_src = subpriv->clock_src[counter_number];
652         *period_ns = clock_period[clock_src];
653         return clock_src;
654 }
655
656 static int dio200_subdev_8254_config(struct comedi_device *dev,
657                                      struct comedi_subdevice *s,
658                                      struct comedi_insn *insn,
659                                      unsigned int *data)
660 {
661         struct dio200_subdev_8254 *subpriv = s->private;
662         int ret = 0;
663         int chan = CR_CHAN(insn->chanspec);
664         unsigned long flags;
665
666         spin_lock_irqsave(&subpriv->spinlock, flags);
667         switch (data[0]) {
668         case INSN_CONFIG_SET_COUNTER_MODE:
669                 if (data[1] > (I8254_MODE5 | I8254_BCD))
670                         ret = -EINVAL;
671                 else
672                         dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
673                 break;
674         case INSN_CONFIG_8254_READ_STATUS:
675                 data[1] = dio200_subdev_8254_status(dev, s, chan);
676                 break;
677         case INSN_CONFIG_SET_GATE_SRC:
678                 ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
679                 if (ret < 0)
680                         ret = -EINVAL;
681                 break;
682         case INSN_CONFIG_GET_GATE_SRC:
683                 ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
684                 if (ret < 0) {
685                         ret = -EINVAL;
686                         break;
687                 }
688                 data[2] = ret;
689                 break;
690         case INSN_CONFIG_SET_CLOCK_SRC:
691                 ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
692                 if (ret < 0)
693                         ret = -EINVAL;
694                 break;
695         case INSN_CONFIG_GET_CLOCK_SRC:
696                 ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
697                 if (ret < 0) {
698                         ret = -EINVAL;
699                         break;
700                 }
701                 data[1] = ret;
702                 break;
703         default:
704                 ret = -EINVAL;
705                 break;
706         }
707         spin_unlock_irqrestore(&subpriv->spinlock, flags);
708         return ret < 0 ? ret : insn->n;
709 }
710
711 static int dio200_subdev_8254_init(struct comedi_device *dev,
712                                    struct comedi_subdevice *s,
713                                    unsigned int offset)
714 {
715         const struct dio200_board *board = dev->board_ptr;
716         struct dio200_subdev_8254 *subpriv;
717         unsigned int chan;
718
719         subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
720         if (!subpriv)
721                 return -ENOMEM;
722
723         s->type = COMEDI_SUBD_COUNTER;
724         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
725         s->n_chan = 3;
726         s->maxdata = 0xFFFF;
727         s->insn_read = dio200_subdev_8254_read;
728         s->insn_write = dio200_subdev_8254_write;
729         s->insn_config = dio200_subdev_8254_config;
730
731         spin_lock_init(&subpriv->spinlock);
732         subpriv->ofs = offset;
733         if (board->has_clk_gat_sce) {
734                 /* Derive CLK_SCE and GAT_SCE register offsets from
735                  * 8254 offset. */
736                 subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3);
737                 subpriv->gat_sce_ofs = DIO200_XGAT_SCE + (offset >> 3);
738                 subpriv->which = (offset >> 2) & 1;
739         }
740
741         /* Initialize channels. */
742         for (chan = 0; chan < 3; chan++) {
743                 dio200_subdev_8254_set_mode(dev, s, chan,
744                                             I8254_MODE0 | I8254_BINARY);
745                 if (board->has_clk_gat_sce) {
746                         /* Gate source 0 is VCC (logic 1). */
747                         dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
748                         /* Clock source 0 is the dedicated clock input. */
749                         dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
750                 }
751         }
752
753         return 0;
754 }
755
756 static void dio200_subdev_8255_set_dir(struct comedi_device *dev,
757                                        struct comedi_subdevice *s)
758 {
759         struct dio200_subdev_8255 *subpriv = s->private;
760         int config;
761
762         config = I8255_CTRL_CW;
763         /* 1 in io_bits indicates output, 1 in config indicates input */
764         if (!(s->io_bits & 0x0000ff))
765                 config |= I8255_CTRL_A_IO;
766         if (!(s->io_bits & 0x00ff00))
767                 config |= I8255_CTRL_B_IO;
768         if (!(s->io_bits & 0x0f0000))
769                 config |= I8255_CTRL_C_LO_IO;
770         if (!(s->io_bits & 0xf00000))
771                 config |= I8255_CTRL_C_HI_IO;
772         dio200_write8(dev, subpriv->ofs + I8255_CTRL_REG, config);
773 }
774
775 static int dio200_subdev_8255_bits(struct comedi_device *dev,
776                                    struct comedi_subdevice *s,
777                                    struct comedi_insn *insn,
778                                    unsigned int *data)
779 {
780         struct dio200_subdev_8255 *subpriv = s->private;
781         unsigned int mask;
782         unsigned int val;
783
784         mask = comedi_dio_update_state(s, data);
785         if (mask) {
786                 if (mask & 0xff)
787                         dio200_write8(dev, subpriv->ofs + I8255_DATA_A_REG,
788                                       s->state & 0xff);
789                 if (mask & 0xff00)
790                         dio200_write8(dev, subpriv->ofs + I8255_DATA_B_REG,
791                                       (s->state >> 8) & 0xff);
792                 if (mask & 0xff0000)
793                         dio200_write8(dev, subpriv->ofs + I8255_DATA_C_REG,
794                                       (s->state >> 16) & 0xff);
795         }
796
797         val = dio200_read8(dev, subpriv->ofs + I8255_DATA_A_REG);
798         val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_B_REG) << 8;
799         val |= dio200_read8(dev, subpriv->ofs + I8255_DATA_C_REG) << 16;
800
801         data[1] = val;
802
803         return insn->n;
804 }
805
806 static int dio200_subdev_8255_config(struct comedi_device *dev,
807                                      struct comedi_subdevice *s,
808                                      struct comedi_insn *insn,
809                                      unsigned int *data)
810 {
811         unsigned int chan = CR_CHAN(insn->chanspec);
812         unsigned int mask;
813         int ret;
814
815         if (chan < 8)
816                 mask = 0x0000ff;
817         else if (chan < 16)
818                 mask = 0x00ff00;
819         else if (chan < 20)
820                 mask = 0x0f0000;
821         else
822                 mask = 0xf00000;
823
824         ret = comedi_dio_insn_config(dev, s, insn, data, mask);
825         if (ret)
826                 return ret;
827
828         dio200_subdev_8255_set_dir(dev, s);
829
830         return insn->n;
831 }
832
833 static int dio200_subdev_8255_init(struct comedi_device *dev,
834                                    struct comedi_subdevice *s,
835                                    unsigned int offset)
836 {
837         struct dio200_subdev_8255 *subpriv;
838
839         subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
840         if (!subpriv)
841                 return -ENOMEM;
842
843         subpriv->ofs = offset;
844
845         s->type = COMEDI_SUBD_DIO;
846         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
847         s->n_chan = 24;
848         s->range_table = &range_digital;
849         s->maxdata = 1;
850         s->insn_bits = dio200_subdev_8255_bits;
851         s->insn_config = dio200_subdev_8255_config;
852         dio200_subdev_8255_set_dir(dev, s);
853         return 0;
854 }
855
856 static int dio200_subdev_timer_read(struct comedi_device *dev,
857                                     struct comedi_subdevice *s,
858                                     struct comedi_insn *insn,
859                                     unsigned int *data)
860 {
861         unsigned int n;
862
863         for (n = 0; n < insn->n; n++)
864                 data[n] = dio200_read32(dev, DIO200_TS_COUNT);
865         return n;
866 }
867
868 static void dio200_subdev_timer_reset(struct comedi_device *dev,
869                                       struct comedi_subdevice *s)
870 {
871         unsigned int clock;
872
873         clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
874         dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
875         dio200_write32(dev, DIO200_TS_CONFIG, clock);
876 }
877
878 static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
879                                               struct comedi_subdevice *s,
880                                               unsigned int *src,
881                                               unsigned int *period)
882 {
883         unsigned int clk;
884
885         clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
886         *src = clk;
887         *period = (clk < ARRAY_SIZE(ts_clock_period)) ?
888                   ts_clock_period[clk] : 0;
889 }
890
891 static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
892                                              struct comedi_subdevice *s,
893                                              unsigned int src)
894 {
895         if (src > TS_CONFIG_MAX_CLK_SRC)
896                 return -EINVAL;
897         dio200_write32(dev, DIO200_TS_CONFIG, src);
898         return 0;
899 }
900
901 static int dio200_subdev_timer_config(struct comedi_device *dev,
902                                       struct comedi_subdevice *s,
903                                       struct comedi_insn *insn,
904                                       unsigned int *data)
905 {
906         int ret = 0;
907
908         switch (data[0]) {
909         case INSN_CONFIG_RESET:
910                 dio200_subdev_timer_reset(dev, s);
911                 break;
912         case INSN_CONFIG_SET_CLOCK_SRC:
913                 ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
914                 if (ret < 0)
915                         ret = -EINVAL;
916                 break;
917         case INSN_CONFIG_GET_CLOCK_SRC:
918                 dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
919                 break;
920         default:
921                 ret = -EINVAL;
922                 break;
923         }
924         return ret < 0 ? ret : insn->n;
925 }
926
927 void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val)
928 {
929         dio200_write8(dev, DIO200_ENHANCE, val);
930 }
931 EXPORT_SYMBOL_GPL(amplc_dio200_set_enhance);
932
933 int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
934                                unsigned long req_irq_flags)
935 {
936         const struct dio200_board *board = dev->board_ptr;
937         struct comedi_subdevice *s;
938         unsigned int n;
939         int ret;
940
941         ret = comedi_alloc_subdevices(dev, board->n_subdevs);
942         if (ret)
943                 return ret;
944
945         for (n = 0; n < dev->n_subdevices; n++) {
946                 s = &dev->subdevices[n];
947                 switch (board->sdtype[n]) {
948                 case sd_8254:
949                         /* counter subdevice (8254) */
950                         ret = dio200_subdev_8254_init(dev, s,
951                                                       board->sdinfo[n]);
952                         if (ret < 0)
953                                 return ret;
954                         break;
955                 case sd_8255:
956                         /* digital i/o subdevice (8255) */
957                         ret = dio200_subdev_8255_init(dev, s,
958                                                       board->sdinfo[n]);
959                         if (ret < 0)
960                                 return ret;
961                         break;
962                 case sd_intr:
963                         /* 'INTERRUPT' subdevice */
964                         if (irq && !dev->read_subdev) {
965                                 ret = dio200_subdev_intr_init(dev, s,
966                                                               DIO200_INT_SCE,
967                                                               board->sdinfo[n]);
968                                 if (ret < 0)
969                                         return ret;
970                                 dev->read_subdev = s;
971                         } else {
972                                 s->type = COMEDI_SUBD_UNUSED;
973                         }
974                         break;
975                 case sd_timer:
976                         s->type         = COMEDI_SUBD_TIMER;
977                         s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
978                         s->n_chan       = 1;
979                         s->maxdata      = 0xffffffff;
980                         s->insn_read    = dio200_subdev_timer_read;
981                         s->insn_config  = dio200_subdev_timer_config;
982                         break;
983                 default:
984                         s->type = COMEDI_SUBD_UNUSED;
985                         break;
986                 }
987         }
988
989         if (irq && dev->read_subdev) {
990                 if (request_irq(irq, dio200_interrupt, req_irq_flags,
991                                 dev->board_name, dev) >= 0) {
992                         dev->irq = irq;
993                 } else {
994                         dev_warn(dev->class_dev,
995                                  "warning! irq %u unavailable!\n", irq);
996                 }
997         }
998
999         return 0;
1000 }
1001 EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
1002
1003 static int __init amplc_dio200_common_init(void)
1004 {
1005         return 0;
1006 }
1007 module_init(amplc_dio200_common_init);
1008
1009 static void __exit amplc_dio200_common_exit(void)
1010 {
1011 }
1012 module_exit(amplc_dio200_common_exit);
1013
1014 MODULE_AUTHOR("Comedi http://www.comedi.org");
1015 MODULE_DESCRIPTION("Comedi helper for amplc_dio200 and amplc_dio200_pci");
1016 MODULE_LICENSE("GPL");