staging: comedi: addi_apci_3120: move DMA init code to apci3120_init_dma()
[cascardo/linux.git] / drivers / staging / comedi / drivers / addi-data / hwdrv_apci3120.c
1 /**
2 @verbatim
3
4 Copyright (C) 2004,2005  ADDI-DATA GmbH for the source code of this module.
5
6         ADDI-DATA GmbH
7         Dieselstrasse 3
8         D-77833 Ottersweier
9         Tel: +19(0)7223/9493-0
10         Fax: +49(0)7223/9493-92
11         http://www.addi-data.com
12         info@addi-data.com
13
14 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17
18 @endverbatim
19 */
20 /*
21   +-----------------------------------------------------------------------+
22   | (C) ADDI-DATA GmbH          Dieselstrasse 3      D-77833 Ottersweier  |
23   +-----------------------------------------------------------------------+
24   | Tel : +49 (0) 7223/9493-0     | email    : info@addi-data.com         |
25   | Fax : +49 (0) 7223/9493-92    | Internet : http://www.addi-data.com   |
26   +-----------------------------------------------------------------------+
27   | Project     : APCI-3120       | Compiler   : GCC                      |
28   | Module name : hwdrv_apci3120.c| Version    : 2.96                     |
29   +-------------------------------+---------------------------------------+
30   | Project manager: Eric Stolz   | Date       :  02/12/2002              |
31   +-----------------------------------------------------------------------+
32   | Description :APCI3120 Module.  Hardware abstraction Layer for APCI3120|
33   +-----------------------------------------------------------------------+
34   |                             UPDATE'S                                  |
35   +-----------------------------------------------------------------------+
36   |   Date   |   Author  |          Description of updates                |
37   +----------+-----------+------------------------------------------------+
38   |          |           |                                                |
39   |          |           |                                                |
40   +----------+-----------+------------------------------------------------+
41 */
42
43 #define APCI3120_START                  1
44 #define APCI3120_STOP                   0
45
46 #define APCI3120_RD_FIFO                0x00
47
48 /* software trigger dummy register */
49 #define APCI3120_START_CONVERSION       0x02
50
51 /* TIMER DEFINE */
52 #define APCI3120_QUARTZ_A               70
53 #define APCI3120_QUARTZ_B               50
54 #define APCI3120_TIMER                  1
55 #define APCI3120_WATCHDOG               2
56 #define APCI3120_TIMER_DISABLE          0
57 #define APCI3120_TIMER_ENABLE           1
58
59 #define APCI3120_COUNTER                3
60
61 static void apci3120_addon_write(struct comedi_device *dev,
62                                  unsigned int val, unsigned int reg)
63 {
64         struct apci3120_private *devpriv = dev->private;
65
66         /* 16-bit interface for AMCC add-on registers */
67
68         outw(reg, devpriv->addon + APCI3120_ADDON_ADDR_REG);
69         outw(val & 0xffff, devpriv->addon + APCI3120_ADDON_DATA_REG);
70
71         outw(reg + 2, devpriv->addon + APCI3120_ADDON_ADDR_REG);
72         outw((val >> 16) & 0xffff, devpriv->addon + APCI3120_ADDON_DATA_REG);
73 }
74
75 static int apci3120_reset(struct comedi_device *dev)
76 {
77         struct apci3120_private *devpriv = dev->private;
78
79         /*  variables used in timer subdevice */
80         devpriv->b_Timer2Mode = 0;
81         devpriv->b_Timer2Interrupt = 0;
82
83         /* Disable all interrupts, watchdog for the anolog output */
84         devpriv->mode = 0;
85         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
86
87         /* disable all counters, ext trigger, and reset scan */
88         devpriv->ctrl = 0;
89         outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG);
90
91         inw(dev->iobase + APCI3120_STATUS_REG);
92
93         return 0;
94 }
95
96 static int apci3120_cancel(struct comedi_device *dev,
97                            struct comedi_subdevice *s)
98 {
99         struct apci3120_private *devpriv = dev->private;
100
101         /* Add-On - disable DMA */
102         outw(0, devpriv->addon + 4);
103
104         /* Add-On - disable bus master */
105         apci3120_addon_write(dev, 0, AMCC_OP_REG_AGCSTS);
106
107         /* AMCC - disable bus master */
108         outl(0, devpriv->amcc + AMCC_OP_REG_MCSR);
109
110         /* disable all counters, ext trigger, and reset scan */
111         devpriv->ctrl = 0;
112         outw(devpriv->ctrl, dev->iobase + APCI3120_CTRL_REG);
113
114         /* DISABLE_ALL_INTERRUPT */
115         devpriv->mode = 0;
116         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
117
118         inw(dev->iobase + APCI3120_STATUS_REG);
119         devpriv->ui_DmaActualBuffer = 0;
120
121         return 0;
122 }
123
124 static int apci3120_ai_cmdtest(struct comedi_device *dev,
125                                struct comedi_subdevice *s,
126                                struct comedi_cmd *cmd)
127 {
128         int err = 0;
129
130         /* Step 1 : check if triggers are trivially valid */
131
132         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT);
133         err |= cfc_check_trigger_src(&cmd->scan_begin_src,
134                                         TRIG_TIMER | TRIG_FOLLOW);
135         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER);
136         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
137         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
138
139         if (err)
140                 return 1;
141
142         /* Step 2a : make sure trigger sources are unique */
143
144         err |= cfc_check_trigger_is_unique(cmd->start_src);
145         err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
146         err |= cfc_check_trigger_is_unique(cmd->stop_src);
147
148         /* Step 2b : and mutually compatible */
149
150         if (err)
151                 return 2;
152
153         /* Step 3: check if arguments are trivially valid */
154
155         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
156
157         if (cmd->scan_begin_src == TRIG_TIMER)  /* Test Delay timing */
158                 err |= cfc_check_trigger_arg_min(&cmd->scan_begin_arg, 100000);
159
160         if (cmd->scan_begin_src == TRIG_TIMER) {
161                 if (cmd->convert_arg)
162                         err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
163                                                          10000);
164         } else {
165                 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
166         }
167
168         err |= cfc_check_trigger_arg_min(&cmd->chanlist_len, 1);
169         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
170
171         if (cmd->stop_src == TRIG_COUNT)
172                 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1);
173         else    /*  TRIG_NONE */
174                 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
175
176         if (err)
177                 return 3;
178
179         /*  step 4: fix up any arguments */
180
181         if (cmd->scan_begin_src == TRIG_TIMER &&
182             cmd->scan_begin_arg < cmd->convert_arg * cmd->scan_end_arg) {
183                 cmd->scan_begin_arg = cmd->convert_arg * cmd->scan_end_arg;
184                 err |= -EINVAL;
185         }
186
187         if (err)
188                 return 4;
189
190         return 0;
191 }
192
193 static void apci3120_init_dma(struct comedi_device *dev,
194                               struct apci3120_dmabuf *dmabuf)
195 {
196         struct apci3120_private *devpriv = dev->private;
197
198         /* AMCC - enable transfer count and reset A2P FIFO */
199         outl(AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
200              devpriv->amcc + AMCC_OP_REG_AGCSTS);
201
202         /* Add-On - enable transfer count and reset A2P FIFO */
203         apci3120_addon_write(dev, AGCSTS_TC_ENABLE | AGCSTS_RESET_A2P_FIFO,
204                              AMCC_OP_REG_AGCSTS);
205
206         /* AMCC - enable transfers and reset A2P flags */
207         outl(RESET_A2P_FLAGS | EN_A2P_TRANSFERS,
208              devpriv->amcc + AMCC_OP_REG_MCSR);
209
210         /* Add-On - DMA start address */
211         apci3120_addon_write(dev, dmabuf->hw, AMCC_OP_REG_AMWAR);
212
213         /* Add-On - Number of acquisitions */
214         apci3120_addon_write(dev, dmabuf->use_size, AMCC_OP_REG_AMWTC);
215
216         /* AMCC - enable write complete (DMA) and set FIFO advance */
217         outl(APCI3120_FIFO_ADVANCE_ON_BYTE_2 | AINT_WRITE_COMPL,
218              devpriv->amcc + AMCC_OP_REG_INTCSR);
219
220         /* Add-On - enable DMA */
221         outw(APCI3120_ADDON_CTRL_AMWEN_ENA | APCI3120_ADDON_CTRL_A2P_FIFO_ENA,
222              devpriv->addon + APCI3120_ADDON_CTRL_REG);
223 }
224
225 static void apci3120_setup_dma(struct comedi_device *dev,
226                                struct comedi_subdevice *s)
227 {
228         struct apci3120_private *devpriv = dev->private;
229         struct comedi_cmd *cmd = &s->async->cmd;
230         struct apci3120_dmabuf *dmabuf0 = &devpriv->dmabuf[0];
231         struct apci3120_dmabuf *dmabuf1 = &devpriv->dmabuf[1];
232         unsigned int dmalen0 = dmabuf0->size;
233         unsigned int dmalen1 = dmabuf1->size;
234         unsigned int scan_bytes;
235
236         scan_bytes = comedi_samples_to_bytes(s, cmd->scan_end_arg);
237
238         if (cmd->stop_src == TRIG_COUNT) {
239                 /*
240                  * Must we fill full first buffer? And must we fill
241                  * full second buffer when first is once filled?
242                  */
243                 if (dmalen0 > (cmd->stop_arg * scan_bytes))
244                         dmalen0 = cmd->stop_arg * scan_bytes;
245                 else if (dmalen1 > (cmd->stop_arg * scan_bytes - dmalen0))
246                         dmalen1 = cmd->stop_arg * scan_bytes - dmalen0;
247         }
248
249         if (cmd->flags & CMDF_WAKE_EOS) {
250                 /* don't we want wake up every scan? */
251                 if (dmalen0 > scan_bytes) {
252                         dmalen0 = scan_bytes;
253                         if (cmd->scan_end_arg & 1)
254                                 dmalen0 += 2;
255                 }
256                 if (dmalen1 > scan_bytes) {
257                         dmalen1 = scan_bytes;
258                         if (cmd->scan_end_arg & 1)
259                                 dmalen1 -= 2;
260                         if (dmalen1 < 4)
261                                 dmalen1 = 4;
262                 }
263         } else {
264                 /* isn't output buff smaller that our DMA buff? */
265                 if (dmalen0 > s->async->prealloc_bufsz)
266                         dmalen0 = s->async->prealloc_bufsz;
267                 if (dmalen1 > s->async->prealloc_bufsz)
268                         dmalen1 = s->async->prealloc_bufsz;
269         }
270         dmabuf0->use_size = dmalen0;
271         dmabuf1->use_size = dmalen1;
272
273         apci3120_init_dma(dev, dmabuf0);
274 }
275
276 static int apci3120_ai_cmd(struct comedi_device *dev,
277                            struct comedi_subdevice *s)
278 {
279         struct apci3120_private *devpriv = dev->private;
280         struct comedi_cmd *cmd = &s->async->cmd;
281         unsigned int divisor;
282
283         /* set default mode bits */
284         devpriv->mode = APCI3120_MODE_TIMER2_CLK_OSC |
285                         APCI3120_MODE_TIMER2_AS_TIMER;
286
287         /* AMCC- Clear write complete interrupt (DMA) */
288         outl(AINT_WT_COMPLETE, devpriv->amcc + AMCC_OP_REG_INTCSR);
289
290         devpriv->ui_DmaActualBuffer = 0;
291
292         /* load chanlist for command scan */
293         apci3120_set_chanlist(dev, s, cmd->chanlist_len, cmd->chanlist);
294
295         if (cmd->start_src == TRIG_EXT)
296                 apci3120_exttrig_enable(dev, true);
297
298         if (cmd->scan_begin_src == TRIG_TIMER) {
299                 /*
300                  * Timer 1 is used in MODE2 (rate generator) to set the
301                  * start time for each scan.
302                  */
303                 divisor = apci3120_ns_to_timer(dev, 1, cmd->scan_begin_arg,
304                                                cmd->flags);
305                 apci3120_timer_set_mode(dev, 1, APCI3120_TIMER_MODE2);
306                 apci3120_timer_write(dev, 1, divisor);
307         }
308
309         /*
310          * Timer 0 is used in MODE2 (rate generator) to set the conversion
311          * time for each acquisition.
312          */
313         divisor = apci3120_ns_to_timer(dev, 0, cmd->convert_arg, cmd->flags);
314         apci3120_timer_set_mode(dev, 0, APCI3120_TIMER_MODE2);
315         apci3120_timer_write(dev, 0, divisor);
316
317         if (devpriv->us_UseDma) {
318                 apci3120_setup_dma(dev, s);
319         } else {
320                 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
321
322                 if (cmd->stop_src == TRIG_COUNT) {
323                         /*
324                          * Timer 2 is used in MODE0 (hardware retriggerable
325                          * one-shot) to count the number of scans.
326                          *
327                          * NOTE: not sure about the -2 value
328                          */
329                         apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE0);
330                         apci3120_timer_write(dev, 2, cmd->stop_arg - 2);
331
332                         apci3120_clr_timer2_interrupt(dev);
333
334                         apci3120_timer_enable(dev, 2, true);
335
336                         /* configure Timer 2 For counting EOS */
337                         devpriv->mode |= APCI3120_MODE_TIMER2_AS_COUNTER |
338                                          APCI3120_MODE_TIMER2_CLK_EOS |
339                                          APCI3120_MODE_TIMER2_IRQ_ENA;
340
341                         devpriv->b_Timer2Mode = APCI3120_COUNTER;
342                         devpriv->b_Timer2Interrupt = 1;
343                 }
344         }
345
346         /* set mode to enable acquisition */
347         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
348
349         if (cmd->scan_begin_src == TRIG_TIMER)
350                 apci3120_timer_enable(dev, 1, true);
351         apci3120_timer_enable(dev, 0, true);
352
353         return 0;
354 }
355
356 /*
357  * This is a handler for the DMA interrupt.
358  * This function copies the data to Comedi Buffer.
359  * For continuous DMA it reinitializes the DMA operation.
360  * For single mode DMA it stop the acquisition.
361  */
362 static void apci3120_interrupt_dma(int irq, void *d)
363 {
364         struct comedi_device *dev = d;
365         struct apci3120_private *devpriv = dev->private;
366         struct comedi_subdevice *s = dev->read_subdev;
367         struct comedi_cmd *cmd = &s->async->cmd;
368         struct apci3120_dmabuf *dmabuf;
369         unsigned int samplesinbuf;
370
371         dmabuf = &devpriv->dmabuf[devpriv->ui_DmaActualBuffer];
372
373         samplesinbuf = dmabuf->use_size - inl(devpriv->amcc + AMCC_OP_REG_MWTC);
374
375         if (samplesinbuf < dmabuf->use_size)
376                 dev_err(dev->class_dev, "Interrupted DMA transfer!\n");
377         if (samplesinbuf & 1) {
378                 dev_err(dev->class_dev, "Odd count of bytes in DMA ring!\n");
379                 apci3120_cancel(dev, s);
380                 return;
381         }
382         samplesinbuf = samplesinbuf >> 1;       /*  number of received samples */
383
384         if (devpriv->b_DmaDoubleBuffer) {
385                 struct apci3120_dmabuf *next_dmabuf;
386
387                 next_dmabuf = &devpriv->dmabuf[1 - devpriv->ui_DmaActualBuffer];
388
389                 /* start DMA on next buffer */
390                 apci3120_init_dma(dev, next_dmabuf);
391         }
392
393         if (samplesinbuf) {
394                 comedi_buf_write_samples(s, dmabuf->virt, samplesinbuf);
395
396                 if (!(cmd->flags & CMDF_WAKE_EOS))
397                         s->async->events |= COMEDI_CB_EOS;
398         }
399         if (cmd->stop_src == TRIG_COUNT &&
400             s->async->scans_done >= cmd->stop_arg) {
401                 s->async->events |= COMEDI_CB_EOA;
402                 return;
403         }
404
405         if (devpriv->b_DmaDoubleBuffer) {
406                 /* switch dma buffers for next interrupt */
407                 devpriv->ui_DmaActualBuffer = 1 - devpriv->ui_DmaActualBuffer;
408         } else {
409                 /* restart DMA if is not using double buffering */
410                 apci3120_init_dma(dev, dmabuf);
411         }
412 }
413
414 static irqreturn_t apci3120_interrupt(int irq, void *d)
415 {
416         struct comedi_device *dev = d;
417         struct apci3120_private *devpriv = dev->private;
418         struct comedi_subdevice *s = dev->read_subdev;
419         struct comedi_cmd *cmd = &s->async->cmd;
420         unsigned int status;
421         unsigned int int_amcc;
422
423         status = inw(dev->iobase + APCI3120_STATUS_REG);
424         int_amcc = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
425
426         if (!(status & APCI3120_STATUS_INT_MASK) &&
427             !(int_amcc & ANY_S593X_INT)) {
428                 dev_err(dev->class_dev, "IRQ from unknown source\n");
429                 return IRQ_NONE;
430         }
431
432         outl(int_amcc | AINT_INT_MASK, devpriv->amcc + AMCC_OP_REG_INTCSR);
433
434         if (devpriv->ctrl & APCI3120_CTRL_EXT_TRIG)
435                 apci3120_exttrig_enable(dev, false);
436
437         apci3120_clr_timer2_interrupt(dev);
438
439         if (int_amcc & MASTER_ABORT_INT)
440                 dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
441         if (int_amcc & TARGET_ABORT_INT)
442                 dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
443
444         if ((status & APCI3120_STATUS_EOC_INT) == 0 &&
445             (devpriv->mode & APCI3120_MODE_EOC_IRQ_ENA)) {
446                 /* nothing to do... EOC mode is not currently used */
447         }
448
449         if ((status & APCI3120_STATUS_EOS_INT) &&
450             (devpriv->mode & APCI3120_MODE_EOS_IRQ_ENA)) {
451                 unsigned short val;
452                 int i;
453
454                 for (i = 0; i < cmd->chanlist_len; i++) {
455                         val = inw(dev->iobase + 0);
456                         comedi_buf_write_samples(s, &val, 1);
457                 }
458
459                 devpriv->mode |= APCI3120_MODE_EOS_IRQ_ENA;
460                 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
461         }
462
463         if (status & APCI3120_STATUS_TIMER2_INT) {
464                 switch (devpriv->b_Timer2Mode) {
465                 case APCI3120_COUNTER:
466                         devpriv->mode &= ~APCI3120_MODE_EOS_IRQ_ENA;
467                         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
468
469                         s->async->events |= COMEDI_CB_EOA;
470                         break;
471
472                 case APCI3120_TIMER:
473
474                         /* Send a signal to from kernel to user space */
475                         send_sig(SIGIO, devpriv->tsk_Current, 0);
476                         break;
477
478                 case APCI3120_WATCHDOG:
479
480                         /* Send a signal to from kernel to user space */
481                         send_sig(SIGIO, devpriv->tsk_Current, 0);
482                         break;
483
484                 default:
485                         /*  disable Timer Interrupt */
486                         devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
487                         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
488                 }
489
490                 apci3120_clr_timer2_interrupt(dev);
491         }
492
493         if (status & APCI3120_STATUS_AMCC_INT) {
494                 /* AMCC- Clear write complete interrupt (DMA) */
495                 outl(AINT_WT_COMPLETE, devpriv->amcc + AMCC_OP_REG_INTCSR);
496
497                 apci3120_clr_timer2_interrupt(dev);
498
499                 /* do some data transfer */
500                 apci3120_interrupt_dma(irq, d);
501         }
502         comedi_handle_events(dev, s);
503
504         return IRQ_HANDLED;
505 }
506
507 /*
508  * Configure Timer 2
509  *
510  * data[0] = TIMER configure as timer
511  *         = WATCHDOG configure as watchdog
512  * data[1] = Timer constant
513  * data[2] = Timer2 interrupt (1)enable or(0) disable
514  */
515 static int apci3120_config_insn_timer(struct comedi_device *dev,
516                                       struct comedi_subdevice *s,
517                                       struct comedi_insn *insn,
518                                       unsigned int *data)
519 {
520         struct apci3120_private *devpriv = dev->private;
521         unsigned int divisor;
522
523         if (!data[1])
524                 dev_err(dev->class_dev, "No timer constant!\n");
525
526         devpriv->b_Timer2Interrupt = (unsigned char) data[2];   /*  save info whether to enable or disable interrupt */
527
528         divisor = apci3120_ns_to_timer(dev, 2, data[1], CMDF_ROUND_DOWN);
529
530         apci3120_timer_enable(dev, 2, false);
531
532         /* disable timer 2 interrupt and reset operation mode (timer) */
533         devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
534                          ~APCI3120_MODE_TIMER2_AS_MASK;
535
536         /*  Disable Eoc and Eos Interrupts */
537         devpriv->mode &= ~APCI3120_MODE_EOC_IRQ_ENA &
538                          ~APCI3120_MODE_EOS_IRQ_ENA;
539         outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
540
541         if (data[0] == APCI3120_TIMER) {        /* initialize timer */
542                 /* Set the Timer 2 in mode 2(Timer) */
543                 apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE2);
544
545                 /* Set timer 2 delay */
546                 apci3120_timer_write(dev, 2, divisor);
547
548                 /*  timer2 in Timer mode enabled */
549                 devpriv->b_Timer2Mode = APCI3120_TIMER;
550         } else {                        /*  Initialize Watch dog */
551                 /* Set the Timer 2 in mode 5(Watchdog) */
552                 apci3120_timer_set_mode(dev, 2, APCI3120_TIMER_MODE5);
553
554                 /* Set timer 2 delay */
555                 apci3120_timer_write(dev, 2, divisor);
556
557                 /* watchdog enabled */
558                 devpriv->b_Timer2Mode = APCI3120_WATCHDOG;
559
560         }
561
562         return insn->n;
563
564 }
565
566 /*
567  * To start and stop the timer
568  *
569  * data[0] = 1 (start)
570  *         = 0 (stop)
571  *         = 2 (write new value)
572  * data[1] = new value
573  *
574  * devpriv->b_Timer2Mode = 0 DISABLE
575  *                       = 1 Timer
576  *                       = 2 Watch dog
577  */
578 static int apci3120_write_insn_timer(struct comedi_device *dev,
579                                      struct comedi_subdevice *s,
580                                      struct comedi_insn *insn,
581                                      unsigned int *data)
582 {
583         struct apci3120_private *devpriv = dev->private;
584         unsigned int divisor;
585
586         if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
587                 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
588                 dev_err(dev->class_dev, "timer2 not configured\n");
589                 return -EINVAL;
590         }
591
592         if (data[0] == 2) {     /*  write new value */
593                 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
594                         dev_err(dev->class_dev,
595                                 "timer2 not configured in TIMER MODE\n");
596                         return -EINVAL;
597                 }
598         }
599
600         switch (data[0]) {
601         case APCI3120_START:
602                 apci3120_clr_timer2_interrupt(dev);
603
604                 if (devpriv->b_Timer2Mode == APCI3120_TIMER) {  /* start timer */
605                         /* Enable Timer */
606                         devpriv->mode &= 0x0b;
607                         devpriv->mode |= APCI3120_MODE_TIMER2_AS_TIMER;
608                 } else {                /* start watch dog */
609                         /* Enable WatchDog */
610                         devpriv->mode &= 0x0b;
611                         devpriv->mode |= APCI3120_MODE_TIMER2_AS_WDOG;
612                 }
613
614                 /* enable disable interrupt */
615                 if (devpriv->b_Timer2Interrupt) {
616                         devpriv->mode |= APCI3120_MODE_TIMER2_IRQ_ENA;
617
618                         /*  save the task structure to pass info to user */
619                         devpriv->tsk_Current = current;
620                 } else {
621                         devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA;
622                 }
623                 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
624
625                 /* start timer */
626                 if (devpriv->b_Timer2Mode == APCI3120_TIMER)
627                         apci3120_timer_enable(dev, 2, true);
628                 break;
629
630         case APCI3120_STOP:
631                 /* disable timer 2 interrupt and reset operation mode (timer) */
632                 devpriv->mode &= ~APCI3120_MODE_TIMER2_IRQ_ENA &
633                                  ~APCI3120_MODE_TIMER2_AS_MASK;
634                 outb(devpriv->mode, dev->iobase + APCI3120_MODE_REG);
635
636                 apci3120_timer_enable(dev, 2, false);
637
638                 apci3120_clr_timer2_interrupt(dev);
639                 break;
640
641         case 2:         /* write new value to Timer */
642                 if (devpriv->b_Timer2Mode != APCI3120_TIMER) {
643                         dev_err(dev->class_dev,
644                                 "timer2 not configured in TIMER MODE\n");
645                         return -EINVAL;
646                 }
647
648                 divisor = apci3120_ns_to_timer(dev, 2, data[1],
649                                                CMDF_ROUND_DOWN);
650
651                 /* Set timer 2 delay */
652                 apci3120_timer_write(dev, 2, divisor);
653                 break;
654         default:
655                 return -EINVAL; /*  Not a valid input */
656         }
657
658         return insn->n;
659 }
660
661 /*
662  * Read the Timer value
663  *
664  * for Timer: data[0]= Timer constant
665  *
666  * for watchdog: data[0] = 0 (still running)
667  *                       = 1 (run down)
668  */
669 static int apci3120_read_insn_timer(struct comedi_device *dev,
670                                     struct comedi_subdevice *s,
671                                     struct comedi_insn *insn,
672                                     unsigned int *data)
673 {
674         struct apci3120_private *devpriv = dev->private;
675         unsigned int status;
676
677         if ((devpriv->b_Timer2Mode != APCI3120_WATCHDOG)
678                 && (devpriv->b_Timer2Mode != APCI3120_TIMER)) {
679                 dev_err(dev->class_dev, "timer2 not configured\n");
680         }
681         if (devpriv->b_Timer2Mode == APCI3120_TIMER) {
682                 data[0] = apci3120_timer_read(dev, 2);
683         } else {
684                 /* Read watch dog status */
685                 status = inw(dev->iobase + APCI3120_STATUS_REG);
686                 if (status & APCI3120_STATUS_TIMER2_INT) {
687                         apci3120_clr_timer2_interrupt(dev);
688                         data[0] = 1;
689                 } else {
690                         data[0] = 0;
691                 }
692         }
693         return insn->n;
694 }