4108cbfaf29bee128c61b27ace17cf4ab083e9c6
[pandora-kernel.git] / drivers / staging / comedi / drivers / ni_atmio16d.c
1 /*
2    comedi/drivers/ni_atmio16d.c
3    Hardware driver for National Instruments AT-MIO16D board
4    Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com>
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20  */
21 /*
22 Driver: ni_atmio16d
23 Description: National Instruments AT-MIO-16D
24 Author: Chris R. Baugher <baugher@enteract.com>
25 Status: unknown
26 Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d)
27 */
28 /*
29  * I must give credit here to Michal Dobes <dobes@tesnet.cz> who
30  * wrote the driver for Advantec's pcl812 boards. I used the interrupt
31  * handling code from his driver as an example for this one.
32  *
33  * Chris Baugher
34  * 5/1/2000
35  *
36  */
37
38 #include <linux/interrupt.h>
39 #include "../comedidev.h"
40
41 #include <linux/ioport.h>
42
43 #include "8255.h"
44
45 /* Configuration and Status Registers */
46 #define COM_REG_1       0x00    /* wo 16 */
47 #define STAT_REG        0x00    /* ro 16 */
48 #define COM_REG_2       0x02    /* wo 16 */
49 /* Event Strobe Registers */
50 #define START_CONVERT_REG       0x08    /* wo 16 */
51 #define START_DAQ_REG           0x0A    /* wo 16 */
52 #define AD_CLEAR_REG            0x0C    /* wo 16 */
53 #define EXT_STROBE_REG          0x0E    /* wo 16 */
54 /* Analog Output Registers */
55 #define DAC0_REG                0x10    /* wo 16 */
56 #define DAC1_REG                0x12    /* wo 16 */
57 #define INT2CLR_REG             0x14    /* wo 16 */
58 /* Analog Input Registers */
59 #define MUX_CNTR_REG            0x04    /* wo 16 */
60 #define MUX_GAIN_REG            0x06    /* wo 16 */
61 #define AD_FIFO_REG             0x16    /* ro 16 */
62 #define DMA_TC_INT_CLR_REG      0x16    /* wo 16 */
63 /* AM9513A Counter/Timer Registers */
64 #define AM9513A_DATA_REG        0x18    /* rw 16 */
65 #define AM9513A_COM_REG         0x1A    /* wo 16 */
66 #define AM9513A_STAT_REG        0x1A    /* ro 16 */
67 /* MIO-16 Digital I/O Registers */
68 #define MIO_16_DIG_IN_REG       0x1C    /* ro 16 */
69 #define MIO_16_DIG_OUT_REG      0x1C    /* wo 16 */
70 /* RTSI Switch Registers */
71 #define RTSI_SW_SHIFT_REG       0x1E    /* wo 8 */
72 #define RTSI_SW_STROBE_REG      0x1F    /* wo 8 */
73 /* DIO-24 Registers */
74 #define DIO_24_PORTA_REG        0x00    /* rw 8 */
75 #define DIO_24_PORTB_REG        0x01    /* rw 8 */
76 #define DIO_24_PORTC_REG        0x02    /* rw 8 */
77 #define DIO_24_CNFG_REG         0x03    /* wo 8 */
78
79 /* Command Register bits */
80 #define COMREG1_2SCADC          0x0001
81 #define COMREG1_1632CNT         0x0002
82 #define COMREG1_SCANEN          0x0008
83 #define COMREG1_DAQEN           0x0010
84 #define COMREG1_DMAEN           0x0020
85 #define COMREG1_CONVINTEN       0x0080
86 #define COMREG2_SCN2            0x0010
87 #define COMREG2_INTEN           0x0080
88 #define COMREG2_DOUTEN0         0x0100
89 #define COMREG2_DOUTEN1         0x0200
90 /* Status Register bits */
91 #define STAT_AD_OVERRUN         0x0100
92 #define STAT_AD_OVERFLOW        0x0200
93 #define STAT_AD_DAQPROG         0x0800
94 #define STAT_AD_CONVAVAIL       0x2000
95 #define STAT_AD_DAQSTOPINT      0x4000
96 /* AM9513A Counter/Timer defines */
97 #define CLOCK_1_MHZ             0x8B25
98 #define CLOCK_100_KHZ   0x8C25
99 #define CLOCK_10_KHZ    0x8D25
100 #define CLOCK_1_KHZ             0x8E25
101 #define CLOCK_100_HZ    0x8F25
102 /* Other miscellaneous defines */
103 #define ATMIO16D_SIZE   32      /* bus address range */
104 #define devpriv ((struct atmio16d_private *)dev->private)
105 #define ATMIO16D_TIMEOUT 10
106
107 struct atmio16_board_t {
108
109         const char *name;
110         int has_8255;
111 };
112
113 /* range structs */
114 static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 4, {
115                                                                        BIP_RANGE
116                                                                        (10),
117                                                                        BIP_RANGE
118                                                                        (1),
119                                                                        BIP_RANGE
120                                                                        (0.1),
121                                                                        BIP_RANGE
122                                                                        (0.02)
123                                                                        }
124 };
125
126 static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { 4, {
127                                                                       BIP_RANGE
128                                                                       (5),
129                                                                       BIP_RANGE
130                                                                       (0.5),
131                                                                       BIP_RANGE
132                                                                       (0.05),
133                                                                       BIP_RANGE
134                                                                       (0.01)
135                                                                       }
136 };
137
138 static const struct comedi_lrange range_atmio16d_ai_unipolar = { 4, {
139                                                                      UNI_RANGE
140                                                                      (10),
141                                                                      UNI_RANGE
142                                                                      (1),
143                                                                      UNI_RANGE
144                                                                      (0.1),
145                                                                      UNI_RANGE
146                                                                      (0.02)
147                                                                      }
148 };
149
150 /* private data struct */
151 struct atmio16d_private {
152         enum { adc_diff, adc_singleended } adc_mux;
153         enum { adc_bipolar10, adc_bipolar5, adc_unipolar10 } adc_range;
154         enum { adc_2comp, adc_straight } adc_coding;
155         enum { dac_bipolar, dac_unipolar } dac0_range, dac1_range;
156         enum { dac_internal, dac_external } dac0_reference, dac1_reference;
157         enum { dac_2comp, dac_straight } dac0_coding, dac1_coding;
158         const struct comedi_lrange *ao_range_type_list[2];
159         unsigned int ao_readback[2];
160         unsigned int com_reg_1_state; /* current state of command register 1 */
161         unsigned int com_reg_2_state; /* current state of command register 2 */
162 };
163
164 static void reset_counters(struct comedi_device *dev)
165 {
166         /* Counter 2 */
167         outw(0xFFC2, dev->iobase + AM9513A_COM_REG);
168         outw(0xFF02, dev->iobase + AM9513A_COM_REG);
169         outw(0x4, dev->iobase + AM9513A_DATA_REG);
170         outw(0xFF0A, dev->iobase + AM9513A_COM_REG);
171         outw(0x3, dev->iobase + AM9513A_DATA_REG);
172         outw(0xFF42, dev->iobase + AM9513A_COM_REG);
173         outw(0xFF42, dev->iobase + AM9513A_COM_REG);
174         /* Counter 3 */
175         outw(0xFFC4, dev->iobase + AM9513A_COM_REG);
176         outw(0xFF03, dev->iobase + AM9513A_COM_REG);
177         outw(0x4, dev->iobase + AM9513A_DATA_REG);
178         outw(0xFF0B, dev->iobase + AM9513A_COM_REG);
179         outw(0x3, dev->iobase + AM9513A_DATA_REG);
180         outw(0xFF44, dev->iobase + AM9513A_COM_REG);
181         outw(0xFF44, dev->iobase + AM9513A_COM_REG);
182         /* Counter 4 */
183         outw(0xFFC8, dev->iobase + AM9513A_COM_REG);
184         outw(0xFF04, dev->iobase + AM9513A_COM_REG);
185         outw(0x4, dev->iobase + AM9513A_DATA_REG);
186         outw(0xFF0C, dev->iobase + AM9513A_COM_REG);
187         outw(0x3, dev->iobase + AM9513A_DATA_REG);
188         outw(0xFF48, dev->iobase + AM9513A_COM_REG);
189         outw(0xFF48, dev->iobase + AM9513A_COM_REG);
190         /* Counter 5 */
191         outw(0xFFD0, dev->iobase + AM9513A_COM_REG);
192         outw(0xFF05, dev->iobase + AM9513A_COM_REG);
193         outw(0x4, dev->iobase + AM9513A_DATA_REG);
194         outw(0xFF0D, dev->iobase + AM9513A_COM_REG);
195         outw(0x3, dev->iobase + AM9513A_DATA_REG);
196         outw(0xFF50, dev->iobase + AM9513A_COM_REG);
197         outw(0xFF50, dev->iobase + AM9513A_COM_REG);
198
199         outw(0, dev->iobase + AD_CLEAR_REG);
200 }
201
202 static void reset_atmio16d(struct comedi_device *dev)
203 {
204         int i;
205
206         /* now we need to initialize the board */
207         outw(0, dev->iobase + COM_REG_1);
208         outw(0, dev->iobase + COM_REG_2);
209         outw(0, dev->iobase + MUX_GAIN_REG);
210         /* init AM9513A timer */
211         outw(0xFFFF, dev->iobase + AM9513A_COM_REG);
212         outw(0xFFEF, dev->iobase + AM9513A_COM_REG);
213         outw(0xFF17, dev->iobase + AM9513A_COM_REG);
214         outw(0xF000, dev->iobase + AM9513A_DATA_REG);
215         for (i = 1; i <= 5; ++i) {
216                 outw(0xFF00 + i, dev->iobase + AM9513A_COM_REG);
217                 outw(0x0004, dev->iobase + AM9513A_DATA_REG);
218                 outw(0xFF08 + i, dev->iobase + AM9513A_COM_REG);
219                 outw(0x3, dev->iobase + AM9513A_DATA_REG);
220         }
221         outw(0xFF5F, dev->iobase + AM9513A_COM_REG);
222         /* timer init done */
223         outw(0, dev->iobase + AD_CLEAR_REG);
224         outw(0, dev->iobase + INT2CLR_REG);
225         /* select straight binary mode for Analog Input */
226         devpriv->com_reg_1_state |= 1;
227         outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
228         devpriv->adc_coding = adc_straight;
229         /* zero the analog outputs */
230         outw(2048, dev->iobase + DAC0_REG);
231         outw(2048, dev->iobase + DAC1_REG);
232 }
233
234 static irqreturn_t atmio16d_interrupt(int irq, void *d)
235 {
236         struct comedi_device *dev = d;
237         struct comedi_subdevice *s = &dev->subdevices[0];
238
239         comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG));
240
241         comedi_event(dev, s);
242         return IRQ_HANDLED;
243 }
244
245 static int atmio16d_ai_cmdtest(struct comedi_device *dev,
246                                struct comedi_subdevice *s,
247                                struct comedi_cmd *cmd)
248 {
249         int err = 0, tmp;
250
251         /* make sure triggers are valid */
252         tmp = cmd->start_src;
253         cmd->start_src &= TRIG_NOW;
254         if (!cmd->start_src || tmp != cmd->start_src)
255                 err++;
256
257         tmp = cmd->scan_begin_src;
258         cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER;
259         if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
260                 err++;
261
262         tmp = cmd->convert_src;
263         cmd->convert_src &= TRIG_TIMER;
264         if (!cmd->convert_src || tmp != cmd->convert_src)
265                 err++;
266
267         tmp = cmd->scan_end_src;
268         cmd->scan_end_src &= TRIG_COUNT;
269         if (!cmd->scan_end_src || tmp != cmd->scan_end_src)
270                 err++;
271
272         tmp = cmd->stop_src;
273         cmd->stop_src &= TRIG_COUNT | TRIG_NONE;
274         if (!cmd->stop_src || tmp != cmd->stop_src)
275                 err++;
276
277         if (err)
278                 return 1;
279
280         /* step 2: make sure trigger sources are unique & mutually compatible */
281         /* note that mutual compatibility is not an issue here */
282         if (cmd->scan_begin_src != TRIG_FOLLOW &&
283             cmd->scan_begin_src != TRIG_EXT &&
284             cmd->scan_begin_src != TRIG_TIMER)
285                 err++;
286         if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE)
287                 err++;
288
289         if (err)
290                 return 2;
291
292         /* step 3: make sure arguments are trivially compatible */
293
294         if (cmd->start_arg != 0) {
295                 cmd->start_arg = 0;
296                 err++;
297         }
298         if (cmd->scan_begin_src == TRIG_FOLLOW) {
299                 /* internal trigger */
300                 if (cmd->scan_begin_arg != 0) {
301                         cmd->scan_begin_arg = 0;
302                         err++;
303                 }
304         } else {
305 #if 0
306                 /* external trigger */
307                 /* should be level/edge, hi/lo specification here */
308                 if (cmd->scan_begin_arg != 0) {
309                         cmd->scan_begin_arg = 0;
310                         err++;
311                 }
312 #endif
313         }
314
315         if (cmd->convert_arg < 10000) {
316                 cmd->convert_arg = 10000;
317                 err++;
318         }
319 #if 0
320         if (cmd->convert_arg > SLOWEST_TIMER) {
321                 cmd->convert_arg = SLOWEST_TIMER;
322                 err++;
323         }
324 #endif
325         if (cmd->scan_end_arg != cmd->chanlist_len) {
326                 cmd->scan_end_arg = cmd->chanlist_len;
327                 err++;
328         }
329         if (cmd->stop_src == TRIG_COUNT) {
330                 /* any count is allowed */
331         } else {
332                 /* TRIG_NONE */
333                 if (cmd->stop_arg != 0) {
334                         cmd->stop_arg = 0;
335                         err++;
336                 }
337         }
338
339         if (err)
340                 return 3;
341
342         return 0;
343 }
344
345 static int atmio16d_ai_cmd(struct comedi_device *dev,
346                            struct comedi_subdevice *s)
347 {
348         struct comedi_cmd *cmd = &s->async->cmd;
349         unsigned int timer, base_clock;
350         unsigned int sample_count, tmp, chan, gain;
351         int i;
352
353         /* This is slowly becoming a working command interface. *
354          * It is still uber-experimental */
355
356         reset_counters(dev);
357         s->async->cur_chan = 0;
358
359         /* check if scanning multiple channels */
360         if (cmd->chanlist_len < 2) {
361                 devpriv->com_reg_1_state &= ~COMREG1_SCANEN;
362                 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
363         } else {
364                 devpriv->com_reg_1_state |= COMREG1_SCANEN;
365                 devpriv->com_reg_2_state |= COMREG2_SCN2;
366                 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
367                 outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
368         }
369
370         /* Setup the Mux-Gain Counter */
371         for (i = 0; i < cmd->chanlist_len; ++i) {
372                 chan = CR_CHAN(cmd->chanlist[i]);
373                 gain = CR_RANGE(cmd->chanlist[i]);
374                 outw(i, dev->iobase + MUX_CNTR_REG);
375                 tmp = chan | (gain << 6);
376                 if (i == cmd->scan_end_arg - 1)
377                         tmp |= 0x0010;  /* set LASTONE bit */
378                 outw(tmp, dev->iobase + MUX_GAIN_REG);
379         }
380
381         /* Now program the sample interval timer */
382         /* Figure out which clock to use then get an
383          * appropriate timer value */
384         if (cmd->convert_arg < 65536000) {
385                 base_clock = CLOCK_1_MHZ;
386                 timer = cmd->convert_arg / 1000;
387         } else if (cmd->convert_arg < 655360000) {
388                 base_clock = CLOCK_100_KHZ;
389                 timer = cmd->convert_arg / 10000;
390         } else if (cmd->convert_arg <= 0xffffffff /* 6553600000 */) {
391                 base_clock = CLOCK_10_KHZ;
392                 timer = cmd->convert_arg / 100000;
393         } else if (cmd->convert_arg <= 0xffffffff /* 65536000000 */) {
394                 base_clock = CLOCK_1_KHZ;
395                 timer = cmd->convert_arg / 1000000;
396         }
397         outw(0xFF03, dev->iobase + AM9513A_COM_REG);
398         outw(base_clock, dev->iobase + AM9513A_DATA_REG);
399         outw(0xFF0B, dev->iobase + AM9513A_COM_REG);
400         outw(0x2, dev->iobase + AM9513A_DATA_REG);
401         outw(0xFF44, dev->iobase + AM9513A_COM_REG);
402         outw(0xFFF3, dev->iobase + AM9513A_COM_REG);
403         outw(timer, dev->iobase + AM9513A_DATA_REG);
404         outw(0xFF24, dev->iobase + AM9513A_COM_REG);
405
406         /* Now figure out how many samples to get */
407         /* and program the sample counter */
408         sample_count = cmd->stop_arg * cmd->scan_end_arg;
409         outw(0xFF04, dev->iobase + AM9513A_COM_REG);
410         outw(0x1025, dev->iobase + AM9513A_DATA_REG);
411         outw(0xFF0C, dev->iobase + AM9513A_COM_REG);
412         if (sample_count < 65536) {
413                 /* use only Counter 4 */
414                 outw(sample_count, dev->iobase + AM9513A_DATA_REG);
415                 outw(0xFF48, dev->iobase + AM9513A_COM_REG);
416                 outw(0xFFF4, dev->iobase + AM9513A_COM_REG);
417                 outw(0xFF28, dev->iobase + AM9513A_COM_REG);
418                 devpriv->com_reg_1_state &= ~COMREG1_1632CNT;
419                 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
420         } else {
421                 /* Counter 4 and 5 are needed */
422
423                 tmp = sample_count & 0xFFFF;
424                 if (tmp)
425                         outw(tmp - 1, dev->iobase + AM9513A_DATA_REG);
426                 else
427                         outw(0xFFFF, dev->iobase + AM9513A_DATA_REG);
428
429                 outw(0xFF48, dev->iobase + AM9513A_COM_REG);
430                 outw(0, dev->iobase + AM9513A_DATA_REG);
431                 outw(0xFF28, dev->iobase + AM9513A_COM_REG);
432                 outw(0xFF05, dev->iobase + AM9513A_COM_REG);
433                 outw(0x25, dev->iobase + AM9513A_DATA_REG);
434                 outw(0xFF0D, dev->iobase + AM9513A_COM_REG);
435                 tmp = sample_count & 0xFFFF;
436                 if ((tmp == 0) || (tmp == 1)) {
437                         outw((sample_count >> 16) & 0xFFFF,
438                              dev->iobase + AM9513A_DATA_REG);
439                 } else {
440                         outw(((sample_count >> 16) & 0xFFFF) + 1,
441                              dev->iobase + AM9513A_DATA_REG);
442                 }
443                 outw(0xFF70, dev->iobase + AM9513A_COM_REG);
444                 devpriv->com_reg_1_state |= COMREG1_1632CNT;
445                 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
446         }
447
448         /* Program the scan interval timer ONLY IF SCANNING IS ENABLED */
449         /* Figure out which clock to use then get an
450          * appropriate timer value */
451         if (cmd->chanlist_len > 1) {
452                 if (cmd->scan_begin_arg < 65536000) {
453                         base_clock = CLOCK_1_MHZ;
454                         timer = cmd->scan_begin_arg / 1000;
455                 } else if (cmd->scan_begin_arg < 655360000) {
456                         base_clock = CLOCK_100_KHZ;
457                         timer = cmd->scan_begin_arg / 10000;
458                 } else if (cmd->scan_begin_arg < 0xffffffff /* 6553600000 */) {
459                         base_clock = CLOCK_10_KHZ;
460                         timer = cmd->scan_begin_arg / 100000;
461                 } else if (cmd->scan_begin_arg < 0xffffffff /* 65536000000 */) {
462                         base_clock = CLOCK_1_KHZ;
463                         timer = cmd->scan_begin_arg / 1000000;
464                 }
465                 outw(0xFF02, dev->iobase + AM9513A_COM_REG);
466                 outw(base_clock, dev->iobase + AM9513A_DATA_REG);
467                 outw(0xFF0A, dev->iobase + AM9513A_COM_REG);
468                 outw(0x2, dev->iobase + AM9513A_DATA_REG);
469                 outw(0xFF42, dev->iobase + AM9513A_COM_REG);
470                 outw(0xFFF2, dev->iobase + AM9513A_COM_REG);
471                 outw(timer, dev->iobase + AM9513A_DATA_REG);
472                 outw(0xFF22, dev->iobase + AM9513A_COM_REG);
473         }
474
475         /* Clear the A/D FIFO and reset the MUX counter */
476         outw(0, dev->iobase + AD_CLEAR_REG);
477         outw(0, dev->iobase + MUX_CNTR_REG);
478         outw(0, dev->iobase + INT2CLR_REG);
479         /* enable this acquisition operation */
480         devpriv->com_reg_1_state |= COMREG1_DAQEN;
481         outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
482         /* enable interrupts for conversion completion */
483         devpriv->com_reg_1_state |= COMREG1_CONVINTEN;
484         devpriv->com_reg_2_state |= COMREG2_INTEN;
485         outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1);
486         outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
487         /* apply a trigger. this starts the counters! */
488         outw(0, dev->iobase + START_DAQ_REG);
489
490         return 0;
491 }
492
493 /* This will cancel a running acquisition operation */
494 static int atmio16d_ai_cancel(struct comedi_device *dev,
495                               struct comedi_subdevice *s)
496 {
497         reset_atmio16d(dev);
498
499         return 0;
500 }
501
502 /* Mode 0 is used to get a single conversion on demand */
503 static int atmio16d_ai_insn_read(struct comedi_device *dev,
504                                  struct comedi_subdevice *s,
505                                  struct comedi_insn *insn, unsigned int *data)
506 {
507         int i, t;
508         int chan;
509         int gain;
510         int status;
511
512         chan = CR_CHAN(insn->chanspec);
513         gain = CR_RANGE(insn->chanspec);
514
515         /* reset the Analog input circuitry */
516         /* outw( 0, dev->iobase+AD_CLEAR_REG ); */
517         /* reset the Analog Input MUX Counter to 0 */
518         /* outw( 0, dev->iobase+MUX_CNTR_REG ); */
519
520         /* set the Input MUX gain */
521         outw(chan | (gain << 6), dev->iobase + MUX_GAIN_REG);
522
523         for (i = 0; i < insn->n; i++) {
524                 /* start the conversion */
525                 outw(0, dev->iobase + START_CONVERT_REG);
526                 /* wait for it to finish */
527                 for (t = 0; t < ATMIO16D_TIMEOUT; t++) {
528                         /* check conversion status */
529                         status = inw(dev->iobase + STAT_REG);
530                         if (status & STAT_AD_CONVAVAIL) {
531                                 /* read the data now */
532                                 data[i] = inw(dev->iobase + AD_FIFO_REG);
533                                 /* change to two's complement if need be */
534                                 if (devpriv->adc_coding == adc_2comp)
535                                         data[i] ^= 0x800;
536                                 break;
537                         }
538                         if (status & STAT_AD_OVERFLOW) {
539                                 printk(KERN_INFO "atmio16d: a/d FIFO overflow\n");
540                                 outw(0, dev->iobase + AD_CLEAR_REG);
541
542                                 return -ETIME;
543                         }
544                 }
545                 /* end waiting, now check if it timed out */
546                 if (t == ATMIO16D_TIMEOUT) {
547                         printk(KERN_INFO "atmio16d: timeout\n");
548
549                         return -ETIME;
550                 }
551         }
552
553         return i;
554 }
555
556 static int atmio16d_ao_insn_read(struct comedi_device *dev,
557                                  struct comedi_subdevice *s,
558                                  struct comedi_insn *insn, unsigned int *data)
559 {
560         int i;
561
562         for (i = 0; i < insn->n; i++)
563                 data[i] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
564         return i;
565 }
566
567 static int atmio16d_ao_insn_write(struct comedi_device *dev,
568                                   struct comedi_subdevice *s,
569                                   struct comedi_insn *insn, unsigned int *data)
570 {
571         int i;
572         int chan;
573         int d;
574
575         chan = CR_CHAN(insn->chanspec);
576
577         for (i = 0; i < insn->n; i++) {
578                 d = data[i];
579                 switch (chan) {
580                 case 0:
581                         if (devpriv->dac0_coding == dac_2comp)
582                                 d ^= 0x800;
583                         outw(d, dev->iobase + DAC0_REG);
584                         break;
585                 case 1:
586                         if (devpriv->dac1_coding == dac_2comp)
587                                 d ^= 0x800;
588                         outw(d, dev->iobase + DAC1_REG);
589                         break;
590                 default:
591                         return -EINVAL;
592                 }
593                 devpriv->ao_readback[chan] = data[i];
594         }
595         return i;
596 }
597
598 static int atmio16d_dio_insn_bits(struct comedi_device *dev,
599                                   struct comedi_subdevice *s,
600                                   struct comedi_insn *insn, unsigned int *data)
601 {
602         if (data[0]) {
603                 s->state &= ~data[0];
604                 s->state |= (data[0] | data[1]);
605                 outw(s->state, dev->iobase + MIO_16_DIG_OUT_REG);
606         }
607         data[1] = inw(dev->iobase + MIO_16_DIG_IN_REG);
608
609         return insn->n;
610 }
611
612 static int atmio16d_dio_insn_config(struct comedi_device *dev,
613                                     struct comedi_subdevice *s,
614                                     struct comedi_insn *insn,
615                                     unsigned int *data)
616 {
617         int i;
618         int mask;
619
620         for (i = 0; i < insn->n; i++) {
621                 mask = (CR_CHAN(insn->chanspec) < 4) ? 0x0f : 0xf0;
622                 s->io_bits &= ~mask;
623                 if (data[i])
624                         s->io_bits |= mask;
625         }
626         devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0 | COMREG2_DOUTEN1);
627         if (s->io_bits & 0x0f)
628                 devpriv->com_reg_2_state |= COMREG2_DOUTEN0;
629         if (s->io_bits & 0xf0)
630                 devpriv->com_reg_2_state |= COMREG2_DOUTEN1;
631         outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2);
632
633         return i;
634 }
635
636 /*
637    options[0] - I/O port
638    options[1] - MIO irq
639                 0 == no irq
640                 N == irq N {3,4,5,6,7,9,10,11,12,14,15}
641    options[2] - DIO irq
642                 0 == no irq
643                 N == irq N {3,4,5,6,7,9}
644    options[3] - DMA1 channel
645                 0 == no DMA
646                 N == DMA N {5,6,7}
647    options[4] - DMA2 channel
648                 0 == no DMA
649                 N == DMA N {5,6,7}
650
651    options[5] - a/d mux
652         0=differential, 1=single
653    options[6] - a/d range
654         0=bipolar10, 1=bipolar5, 2=unipolar10
655
656    options[7] - dac0 range
657         0=bipolar, 1=unipolar
658    options[8] - dac0 reference
659         0=internal, 1=external
660    options[9] - dac0 coding
661         0=2's comp, 1=straight binary
662
663    options[10] - dac1 range
664    options[11] - dac1 reference
665    options[12] - dac1 coding
666  */
667
668 static int atmio16d_attach(struct comedi_device *dev,
669                            struct comedi_devconfig *it)
670 {
671         const struct atmio16_board_t *board = comedi_board(dev);
672         unsigned int irq;
673         unsigned long iobase;
674         int ret;
675
676         struct comedi_subdevice *s;
677
678         /* make sure the address range is free and allocate it */
679         iobase = it->options[0];
680         printk(KERN_INFO "comedi%d: atmio16d: 0x%04lx ", dev->minor, iobase);
681         if (!request_region(iobase, ATMIO16D_SIZE, "ni_atmio16d")) {
682                 printk("I/O port conflict\n");
683                 return -EIO;
684         }
685         dev->iobase = iobase;
686
687         dev->board_name = board->name;
688
689         ret = comedi_alloc_subdevices(dev, 4);
690         if (ret)
691                 return ret;
692
693         ret = alloc_private(dev, sizeof(struct atmio16d_private));
694         if (ret < 0)
695                 return ret;
696
697         /* reset the atmio16d hardware */
698         reset_atmio16d(dev);
699
700         /* check if our interrupt is available and get it */
701         irq = it->options[1];
702         if (irq) {
703
704                 ret = request_irq(irq, atmio16d_interrupt, 0, "atmio16d", dev);
705                 if (ret < 0) {
706                         printk(KERN_INFO "failed to allocate irq %u\n", irq);
707                         return ret;
708                 }
709                 dev->irq = irq;
710                 printk(KERN_INFO "( irq = %u )\n", irq);
711         } else {
712                 printk(KERN_INFO "( no irq )");
713         }
714
715         /* set device options */
716         devpriv->adc_mux = it->options[5];
717         devpriv->adc_range = it->options[6];
718
719         devpriv->dac0_range = it->options[7];
720         devpriv->dac0_reference = it->options[8];
721         devpriv->dac0_coding = it->options[9];
722         devpriv->dac1_range = it->options[10];
723         devpriv->dac1_reference = it->options[11];
724         devpriv->dac1_coding = it->options[12];
725
726         /* setup sub-devices */
727         s = &dev->subdevices[0];
728         dev->read_subdev = s;
729         /* ai subdevice */
730         s->type = COMEDI_SUBD_AI;
731         s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ;
732         s->n_chan = (devpriv->adc_mux ? 16 : 8);
733         s->len_chanlist = 16;
734         s->insn_read = atmio16d_ai_insn_read;
735         s->do_cmdtest = atmio16d_ai_cmdtest;
736         s->do_cmd = atmio16d_ai_cmd;
737         s->cancel = atmio16d_ai_cancel;
738         s->maxdata = 0xfff;     /* 4095 decimal */
739         switch (devpriv->adc_range) {
740         case adc_bipolar10:
741                 s->range_table = &range_atmio16d_ai_10_bipolar;
742                 break;
743         case adc_bipolar5:
744                 s->range_table = &range_atmio16d_ai_5_bipolar;
745                 break;
746         case adc_unipolar10:
747                 s->range_table = &range_atmio16d_ai_unipolar;
748                 break;
749         }
750
751         /* ao subdevice */
752         s = &dev->subdevices[1];
753         s->type = COMEDI_SUBD_AO;
754         s->subdev_flags = SDF_WRITABLE;
755         s->n_chan = 2;
756         s->insn_read = atmio16d_ao_insn_read;
757         s->insn_write = atmio16d_ao_insn_write;
758         s->maxdata = 0xfff;     /* 4095 decimal */
759         s->range_table_list = devpriv->ao_range_type_list;
760         switch (devpriv->dac0_range) {
761         case dac_bipolar:
762                 devpriv->ao_range_type_list[0] = &range_bipolar10;
763                 break;
764         case dac_unipolar:
765                 devpriv->ao_range_type_list[0] = &range_unipolar10;
766                 break;
767         }
768         switch (devpriv->dac1_range) {
769         case dac_bipolar:
770                 devpriv->ao_range_type_list[1] = &range_bipolar10;
771                 break;
772         case dac_unipolar:
773                 devpriv->ao_range_type_list[1] = &range_unipolar10;
774                 break;
775         }
776
777         /* Digital I/O */
778         s = &dev->subdevices[2];
779         s->type = COMEDI_SUBD_DIO;
780         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
781         s->n_chan = 8;
782         s->insn_bits = atmio16d_dio_insn_bits;
783         s->insn_config = atmio16d_dio_insn_config;
784         s->maxdata = 1;
785         s->range_table = &range_digital;
786
787         /* 8255 subdevice */
788         s = &dev->subdevices[3];
789         if (board->has_8255)
790                 subdev_8255_init(dev, s, NULL, dev->iobase);
791         else
792                 s->type = COMEDI_SUBD_UNUSED;
793
794 /* don't yet know how to deal with counter/timers */
795 #if 0
796         s = &dev->subdevices[4];
797         /* do */
798         s->type = COMEDI_SUBD_TIMER;
799         s->n_chan = 0;
800         s->maxdata = 0
801 #endif
802             printk("\n");
803
804         return 0;
805 }
806
807 static void atmio16d_detach(struct comedi_device *dev)
808 {
809         const struct atmio16_board_t *board = comedi_board(dev);
810         struct comedi_subdevice *s;
811
812         if (dev->subdevices && board->has_8255) {
813                 s = &dev->subdevices[3];
814                 subdev_8255_cleanup(dev, s);
815         }
816         if (dev->irq)
817                 free_irq(dev->irq, dev);
818         reset_atmio16d(dev);
819         if (dev->iobase)
820                 release_region(dev->iobase, ATMIO16D_SIZE);
821 }
822
823 static const struct atmio16_board_t atmio16_boards[] = {
824         {
825                 .name           = "atmio16",
826                 .has_8255       = 0,
827         }, {
828                 .name           = "atmio16d",
829                 .has_8255       = 1,
830         },
831 };
832
833 static struct comedi_driver atmio16d_driver = {
834         .driver_name    = "atmio16",
835         .module         = THIS_MODULE,
836         .attach         = atmio16d_attach,
837         .detach         = atmio16d_detach,
838         .board_name     = &atmio16_boards[0].name,
839         .num_names      = ARRAY_SIZE(atmio16_boards),
840         .offset         = sizeof(struct atmio16_board_t),
841 };
842 module_comedi_driver(atmio16d_driver);
843
844 MODULE_AUTHOR("Comedi http://www.comedi.org");
845 MODULE_DESCRIPTION("Comedi low-level driver");
846 MODULE_LICENSE("GPL");