staging: comedi: icp_multi: remove ranglist_ao from boardinfo
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / staging / comedi / drivers / icp_multi.c
1 /*
2     comedi/drivers/icp_multi.c
3
4     COMEDI - Linux Control and Measurement Device Interface
5     Copyright (C) 1997-2002 David A. Schleef <ds@schleef.org>
6
7     This program is free software; you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation; either version 2 of the License, or
10     (at your option) any later version.
11
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16
17     You should have received a copy of the GNU General Public License
18     along with this program; if not, write to the Free Software
19     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20
21 */
22
23 /*
24 Driver: icp_multi
25 Description: Inova ICP_MULTI
26 Author: Anne Smorthit <anne.smorthit@sfwte.ch>
27 Devices: [Inova] ICP_MULTI (icp_multi)
28 Status: works
29
30 The driver works for analog input and output and digital input and output.
31 It does not work with interrupts or with the counters.  Currently no support
32 for DMA.
33
34 It has 16 single-ended or 8 differential Analogue Input channels with 12-bit
35 resolution.  Ranges : 5V, 10V, +/-5V, +/-10V, 0..20mA and 4..20mA.  Input
36 ranges can be individually programmed for each channel.  Voltage or current
37 measurement is selected by jumper.
38
39 There are 4 x 12-bit Analogue Outputs.  Ranges : 5V, 10V, +/-5V, +/-10V
40
41 16 x Digital Inputs, 24V
42
43 8 x Digital Outputs, 24V, 1A
44
45 4 x 16-bit counters
46
47 Options:
48  [0] - PCI bus number - if bus number and slot number are 0,
49                         then driver search for first unused card
50  [1] - PCI slot number
51 */
52
53 #include <linux/interrupt.h>
54 #include "../comedidev.h"
55
56 #include <linux/delay.h>
57 #include <linux/pci.h>
58
59 #include "icp_multi.h"
60
61 #define PCI_DEVICE_ID_ICP_MULTI 0x8000
62
63 /*  Hardware types of the cards */
64 #define TYPE_ICP_MULTI  0
65
66 #define IORANGE_ICP_MULTI       32
67
68 #define ICP_MULTI_ADC_CSR       0       /* R/W: ADC command/status register */
69 #define ICP_MULTI_AI            2       /* R:   Analogue input data */
70 #define ICP_MULTI_DAC_CSR       4       /* R/W: DAC command/status register */
71 #define ICP_MULTI_AO            6       /* R/W: Analogue output data */
72 #define ICP_MULTI_DI            8       /* R/W: Digital inouts */
73 #define ICP_MULTI_DO            0x0A    /* R/W: Digital outputs */
74 #define ICP_MULTI_INT_EN        0x0C    /* R/W: Interrupt enable register */
75 #define ICP_MULTI_INT_STAT      0x0E    /* R/W: Interrupt status register */
76 #define ICP_MULTI_CNTR0         0x10    /* R/W: Counter 0 */
77 #define ICP_MULTI_CNTR1         0x12    /* R/W: counter 1 */
78 #define ICP_MULTI_CNTR2         0x14    /* R/W: Counter 2 */
79 #define ICP_MULTI_CNTR3         0x16    /* R/W: Counter 3 */
80
81 #define ICP_MULTI_SIZE          0x20    /* 32 bytes */
82
83 /*  Define bits from ADC command/status register */
84 #define ADC_ST          0x0001  /* Start ADC */
85 #define ADC_BSY         0x0001  /* ADC busy */
86 #define ADC_BI          0x0010  /* Bipolar input range 1 = bipolar */
87 #define ADC_RA          0x0020  /* Input range 0 = 5V, 1 = 10V */
88 #define ADC_DI          0x0040  /* Differential input mode 1 = differential */
89
90 /*  Define bits from DAC command/status register */
91 #define DAC_ST          0x0001  /* Start DAC */
92 #define DAC_BSY         0x0001  /* DAC busy */
93 #define DAC_BI          0x0010  /* Bipolar input range 1 = bipolar */
94 #define DAC_RA          0x0020  /* Input range 0 = 5V, 1 = 10V */
95
96 /*  Define bits from interrupt enable/status registers */
97 #define ADC_READY       0x0001  /* A/d conversion ready interrupt */
98 #define DAC_READY       0x0002  /* D/a conversion ready interrupt */
99 #define DOUT_ERROR      0x0004  /* Digital output error interrupt */
100 #define DIN_STATUS      0x0008  /* Digital input status change interrupt */
101 #define CIE0            0x0010  /* Counter 0 overrun interrupt */
102 #define CIE1            0x0020  /* Counter 1 overrun interrupt */
103 #define CIE2            0x0040  /* Counter 2 overrun interrupt */
104 #define CIE3            0x0080  /* Counter 3 overrun interrupt */
105
106 /*  Useful definitions */
107 #define Status_IRQ      0x00ff  /*  All interrupts */
108
109 /*  Define analogue range */
110 static const struct comedi_lrange range_analog = { 4, {
111                                                        UNI_RANGE(5),
112                                                        UNI_RANGE(10),
113                                                        BIP_RANGE(5),
114                                                        BIP_RANGE(10)
115                                                        }
116 };
117
118 static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 };
119
120 /*
121 ==============================================================================
122         Data & Structure declarations
123 ==============================================================================
124 */
125 static unsigned short pci_list_builded; /*>0 list of card is known */
126
127 struct boardtype {
128         const char *name;       /*  driver name */
129         int device_id;
130         int iorange;            /*  I/O range len */
131         char have_irq;          /*  1=card support IRQ */
132         char cardtype;          /*  0=ICP Multi */
133         const struct comedi_lrange *rangelist_ai;       /*  rangelist for A/D */
134         const char *rangecode;  /*  range codes for programming */
135 };
136
137 struct icp_multi_private {
138         struct pcilst_struct *card;     /*  pointer to card */
139         char valid;             /*  card is usable */
140         void __iomem *io_addr;          /*  Pointer to mapped io address */
141         resource_size_t phys_iobase;    /*  Physical io address */
142         unsigned int AdcCmdStatus;      /*  ADC Command/Status register */
143         unsigned int DacCmdStatus;      /*  DAC Command/Status register */
144         unsigned int IntEnable; /*  Interrupt Enable register */
145         unsigned int IntStatus; /*  Interrupt Status register */
146         unsigned int act_chanlist[32];  /*  list of scaned channel */
147         unsigned char act_chanlist_len; /*  len of scanlist */
148         unsigned char act_chanlist_pos; /*  actual position in MUX list */
149         unsigned int *ai_chanlist;      /*  actaul chanlist */
150         short *ai_data;         /*  data buffer */
151         short ao_data[4];       /*  data output buffer */
152         short di_data;          /*  Digital input data */
153         unsigned int do_data;   /*  Remember digital output data */
154 };
155
156 #define devpriv ((struct icp_multi_private *)dev->private)
157 #define this_board ((const struct boardtype *)dev->board_ptr)
158
159 /*
160 ==============================================================================
161
162 Name:   setup_channel_list
163
164 Description:
165         This function sets the appropriate channel selection,
166         differential input mode and range bits in the ADC Command/
167         Status register.
168
169 Parameters:
170         struct comedi_device *dev       Pointer to current service structure
171         struct comedi_subdevice *s      Pointer to current subdevice structure
172         unsigned int *chanlist  Pointer to packed channel list
173         unsigned int n_chan     Number of channels to scan
174
175 Returns:Void
176
177 ==============================================================================
178 */
179 static void setup_channel_list(struct comedi_device *dev,
180                                struct comedi_subdevice *s,
181                                unsigned int *chanlist, unsigned int n_chan)
182 {
183         unsigned int i, range, chanprog;
184         unsigned int diff;
185
186         devpriv->act_chanlist_len = n_chan;
187         devpriv->act_chanlist_pos = 0;
188
189         for (i = 0; i < n_chan; i++) {
190                 /*  Get channel */
191                 chanprog = CR_CHAN(chanlist[i]);
192
193                 /*  Determine if it is a differential channel (Bit 15  = 1) */
194                 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
195                         diff = 1;
196                         chanprog &= 0x0007;
197                 } else {
198                         diff = 0;
199                         chanprog &= 0x000f;
200                 }
201
202                 /*  Clear channel, range and input mode bits
203                  *  in A/D command/status register */
204                 devpriv->AdcCmdStatus &= 0xf00f;
205
206                 /*  Set channel number and differential mode status bit */
207                 if (diff) {
208                         /*  Set channel number, bits 9-11 & mode, bit 6 */
209                         devpriv->AdcCmdStatus |= (chanprog << 9);
210                         devpriv->AdcCmdStatus |= ADC_DI;
211                 } else
212                         /*  Set channel number, bits 8-11 */
213                         devpriv->AdcCmdStatus |= (chanprog << 8);
214
215                 /*  Get range for current channel */
216                 range = this_board->rangecode[CR_RANGE(chanlist[i])];
217                 /*  Set range. bits 4-5 */
218                 devpriv->AdcCmdStatus |= range;
219
220                 /* Output channel, range, mode to ICP Multi */
221                 writew(devpriv->AdcCmdStatus,
222                        devpriv->io_addr + ICP_MULTI_ADC_CSR);
223         }
224 }
225
226 /*
227 ==============================================================================
228
229 Name:   icp_multi_insn_read_ai
230
231 Description:
232         This function reads a single analogue input.
233
234 Parameters:
235         struct comedi_device *dev       Pointer to current device structure
236         struct comedi_subdevice *s      Pointer to current subdevice structure
237         struct comedi_insn *insn        Pointer to current comedi instruction
238         unsigned int *data              Pointer to analogue input data
239
240 Returns:int                     Nmuber of instructions executed
241
242 ==============================================================================
243 */
244 static int icp_multi_insn_read_ai(struct comedi_device *dev,
245                                   struct comedi_subdevice *s,
246                                   struct comedi_insn *insn, unsigned int *data)
247 {
248         int n, timeout;
249
250         /*  Disable A/D conversion ready interrupt */
251         devpriv->IntEnable &= ~ADC_READY;
252         writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
253
254         /*  Clear interrupt status */
255         devpriv->IntStatus |= ADC_READY;
256         writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
257
258         /*  Set up appropriate channel, mode and range data, for specified ch */
259         setup_channel_list(dev, s, &insn->chanspec, 1);
260
261         for (n = 0; n < insn->n; n++) {
262                 /*  Set start ADC bit */
263                 devpriv->AdcCmdStatus |= ADC_ST;
264                 writew(devpriv->AdcCmdStatus,
265                        devpriv->io_addr + ICP_MULTI_ADC_CSR);
266                 devpriv->AdcCmdStatus &= ~ADC_ST;
267
268                 udelay(1);
269
270                 /*  Wait for conversion to complete, or get fed up waiting */
271                 timeout = 100;
272                 while (timeout--) {
273                         if (!(readw(devpriv->io_addr +
274                                     ICP_MULTI_ADC_CSR) & ADC_BSY))
275                                 goto conv_finish;
276
277                         udelay(1);
278                 }
279
280                 /*  If we reach here, a timeout has occurred */
281                 comedi_error(dev, "A/D insn timeout");
282
283                 /*  Disable interrupt */
284                 devpriv->IntEnable &= ~ADC_READY;
285                 writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
286
287                 /*  Clear interrupt status */
288                 devpriv->IntStatus |= ADC_READY;
289                 writew(devpriv->IntStatus,
290                        devpriv->io_addr + ICP_MULTI_INT_STAT);
291
292                 /*  Clear data received */
293                 data[n] = 0;
294
295                 return -ETIME;
296
297 conv_finish:
298                 data[n] =
299                     (readw(devpriv->io_addr + ICP_MULTI_AI) >> 4) & 0x0fff;
300         }
301
302         /*  Disable interrupt */
303         devpriv->IntEnable &= ~ADC_READY;
304         writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
305
306         /*  Clear interrupt status */
307         devpriv->IntStatus |= ADC_READY;
308         writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
309
310         return n;
311 }
312
313 /*
314 ==============================================================================
315
316 Name:   icp_multi_insn_write_ao
317
318 Description:
319         This function writes a single analogue output.
320
321 Parameters:
322         struct comedi_device *dev       Pointer to current device structure
323         struct comedi_subdevice *s      Pointer to current subdevice structure
324         struct comedi_insn *insn        Pointer to current comedi instruction
325         unsigned int *data              Pointer to analogue output data
326
327 Returns:int                     Nmuber of instructions executed
328
329 ==============================================================================
330 */
331 static int icp_multi_insn_write_ao(struct comedi_device *dev,
332                                    struct comedi_subdevice *s,
333                                    struct comedi_insn *insn, unsigned int *data)
334 {
335         int n, chan, range, timeout;
336
337         /*  Disable D/A conversion ready interrupt */
338         devpriv->IntEnable &= ~DAC_READY;
339         writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
340
341         /*  Clear interrupt status */
342         devpriv->IntStatus |= DAC_READY;
343         writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT);
344
345         /*  Get channel number and range */
346         chan = CR_CHAN(insn->chanspec);
347         range = CR_RANGE(insn->chanspec);
348
349         /*  Set up range and channel data */
350         /*  Bit 4 = 1 : Bipolar */
351         /*  Bit 5 = 0 : 5V */
352         /*  Bit 5 = 1 : 10V */
353         /*  Bits 8-9 : Channel number */
354         devpriv->DacCmdStatus &= 0xfccf;
355         devpriv->DacCmdStatus |= this_board->rangecode[range];
356         devpriv->DacCmdStatus |= (chan << 8);
357
358         writew(devpriv->DacCmdStatus, devpriv->io_addr + ICP_MULTI_DAC_CSR);
359
360         for (n = 0; n < insn->n; n++) {
361                 /*  Wait for analogue output data register to be
362                  *  ready for new data, or get fed up waiting */
363                 timeout = 100;
364                 while (timeout--) {
365                         if (!(readw(devpriv->io_addr +
366                                     ICP_MULTI_DAC_CSR) & DAC_BSY))
367                                 goto dac_ready;
368
369                         udelay(1);
370                 }
371
372                 /*  If we reach here, a timeout has occurred */
373                 comedi_error(dev, "D/A insn timeout");
374
375                 /*  Disable interrupt */
376                 devpriv->IntEnable &= ~DAC_READY;
377                 writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN);
378
379                 /*  Clear interrupt status */
380                 devpriv->IntStatus |= DAC_READY;
381                 writew(devpriv->IntStatus,
382                        devpriv->io_addr + ICP_MULTI_INT_STAT);
383
384                 /*  Clear data received */
385                 devpriv->ao_data[chan] = 0;
386
387                 return -ETIME;
388
389 dac_ready:
390                 /*  Write data to analogue output data register */
391                 writew(data[n], devpriv->io_addr + ICP_MULTI_AO);
392
393                 /*  Set DAC_ST bit to write the data to selected channel */
394                 devpriv->DacCmdStatus |= DAC_ST;
395                 writew(devpriv->DacCmdStatus,
396                        devpriv->io_addr + ICP_MULTI_DAC_CSR);
397                 devpriv->DacCmdStatus &= ~DAC_ST;
398
399                 /*  Save analogue output data */
400                 devpriv->ao_data[chan] = data[n];
401         }
402
403         return n;
404 }
405
406 /*
407 ==============================================================================
408
409 Name:   icp_multi_insn_read_ao
410
411 Description:
412         This function reads a single analogue output.
413
414 Parameters:
415         struct comedi_device *dev       Pointer to current device structure
416         struct comedi_subdevice *s      Pointer to current subdevice structure
417         struct comedi_insn *insn        Pointer to current comedi instruction
418         unsigned int *data              Pointer to analogue output data
419
420 Returns:int                     Nmuber of instructions executed
421
422 ==============================================================================
423 */
424 static int icp_multi_insn_read_ao(struct comedi_device *dev,
425                                   struct comedi_subdevice *s,
426                                   struct comedi_insn *insn, unsigned int *data)
427 {
428         int n, chan;
429
430         /*  Get channel number */
431         chan = CR_CHAN(insn->chanspec);
432
433         /*  Read analogue outputs */
434         for (n = 0; n < insn->n; n++)
435                 data[n] = devpriv->ao_data[chan];
436
437         return n;
438 }
439
440 /*
441 ==============================================================================
442
443 Name:   icp_multi_insn_bits_di
444
445 Description:
446         This function reads the digital inputs.
447
448 Parameters:
449         struct comedi_device *dev       Pointer to current device structure
450         struct comedi_subdevice *s      Pointer to current subdevice structure
451         struct comedi_insn *insn        Pointer to current comedi instruction
452         unsigned int *data              Pointer to analogue output data
453
454 Returns:int                     Nmuber of instructions executed
455
456 ==============================================================================
457 */
458 static int icp_multi_insn_bits_di(struct comedi_device *dev,
459                                   struct comedi_subdevice *s,
460                                   struct comedi_insn *insn, unsigned int *data)
461 {
462         data[1] = readw(devpriv->io_addr + ICP_MULTI_DI);
463
464         return insn->n;
465 }
466
467 /*
468 ==============================================================================
469
470 Name:   icp_multi_insn_bits_do
471
472 Description:
473         This function writes the appropriate digital outputs.
474
475 Parameters:
476         struct comedi_device *dev       Pointer to current device structure
477         struct comedi_subdevice *s      Pointer to current subdevice structure
478         struct comedi_insn *insn        Pointer to current comedi instruction
479         unsigned int *data              Pointer to analogue output data
480
481 Returns:int                     Nmuber of instructions executed
482
483 ==============================================================================
484 */
485 static int icp_multi_insn_bits_do(struct comedi_device *dev,
486                                   struct comedi_subdevice *s,
487                                   struct comedi_insn *insn, unsigned int *data)
488 {
489         if (data[0]) {
490                 s->state &= ~data[0];
491                 s->state |= (data[0] & data[1]);
492
493                 printk(KERN_DEBUG "Digital outputs = %4x \n", s->state);
494
495                 writew(s->state, devpriv->io_addr + ICP_MULTI_DO);
496         }
497
498         data[1] = readw(devpriv->io_addr + ICP_MULTI_DI);
499
500         return insn->n;
501 }
502
503 /*
504 ==============================================================================
505
506 Name:   icp_multi_insn_read_ctr
507
508 Description:
509         This function reads the specified counter.
510
511 Parameters:
512         struct comedi_device *dev       Pointer to current device structure
513         struct comedi_subdevice *s      Pointer to current subdevice structure
514         struct comedi_insn *insn        Pointer to current comedi instruction
515         unsigned int *data              Pointer to counter data
516
517 Returns:int                     Nmuber of instructions executed
518
519 ==============================================================================
520 */
521 static int icp_multi_insn_read_ctr(struct comedi_device *dev,
522                                    struct comedi_subdevice *s,
523                                    struct comedi_insn *insn, unsigned int *data)
524 {
525         return 0;
526 }
527
528 /*
529 ==============================================================================
530
531 Name:   icp_multi_insn_write_ctr
532
533 Description:
534         This function write to the specified counter.
535
536 Parameters:
537         struct comedi_device *dev       Pointer to current device structure
538         struct comedi_subdevice *s      Pointer to current subdevice structure
539         struct comedi_insn *insn        Pointer to current comedi instruction
540         unsigned int *data              Pointer to counter data
541
542 Returns:int                     Nmuber of instructions executed
543
544 ==============================================================================
545 */
546 static int icp_multi_insn_write_ctr(struct comedi_device *dev,
547                                     struct comedi_subdevice *s,
548                                     struct comedi_insn *insn,
549                                     unsigned int *data)
550 {
551         return 0;
552 }
553
554 /*
555 ==============================================================================
556
557 Name:   interrupt_service_icp_multi
558
559 Description:
560         This function is the interrupt service routine for all
561         interrupts generated by the icp multi board.
562
563 Parameters:
564         int irq
565         void *d                 Pointer to current device
566
567 ==============================================================================
568 */
569 static irqreturn_t interrupt_service_icp_multi(int irq, void *d)
570 {
571         struct comedi_device *dev = d;
572         int int_no;
573
574         /*  Is this interrupt from our board? */
575         int_no = readw(devpriv->io_addr + ICP_MULTI_INT_STAT) & Status_IRQ;
576         if (!int_no)
577                 /*  No, exit */
578                 return IRQ_NONE;
579
580         /*  Determine which interrupt is active & handle it */
581         switch (int_no) {
582         case ADC_READY:
583                 break;
584         case DAC_READY:
585                 break;
586         case DOUT_ERROR:
587                 break;
588         case DIN_STATUS:
589                 break;
590         case CIE0:
591                 break;
592         case CIE1:
593                 break;
594         case CIE2:
595                 break;
596         case CIE3:
597                 break;
598         default:
599                 break;
600
601         }
602
603         return IRQ_HANDLED;
604 }
605
606 #if 0
607 /*
608 ==============================================================================
609
610 Name:   check_channel_list
611
612 Description:
613         This function checks if the channel list, provided by user
614         is built correctly
615
616 Parameters:
617         struct comedi_device *dev       Pointer to current service structure
618         struct comedi_subdevice *s      Pointer to current subdevice structure
619         unsigned int *chanlist  Pointer to packed channel list
620         unsigned int n_chan     Number of channels to scan
621
622 Returns:int 0 = failure
623             1 = success
624
625 ==============================================================================
626 */
627 static int check_channel_list(struct comedi_device *dev,
628                               struct comedi_subdevice *s,
629                               unsigned int *chanlist, unsigned int n_chan)
630 {
631         unsigned int i;
632
633         /*  Check that we at least have one channel to check */
634         if (n_chan < 1) {
635                 comedi_error(dev, "range/channel list is empty!");
636                 return 0;
637         }
638         /*  Check all channels */
639         for (i = 0; i < n_chan; i++) {
640                 /*  Check that channel number is < maximum */
641                 if (CR_AREF(chanlist[i]) == AREF_DIFF) {
642                         if (CR_CHAN(chanlist[i]) > (s->nchan / 2)) {
643                                 comedi_error(dev,
644                                              "Incorrect differential ai ch-nr");
645                                 return 0;
646                         }
647                 } else {
648                         if (CR_CHAN(chanlist[i]) > s->n_chan) {
649                                 comedi_error(dev,
650                                              "Incorrect ai channel number");
651                                 return 0;
652                         }
653                 }
654         }
655         return 1;
656 }
657 #endif
658
659 /*
660 ==============================================================================
661
662 Name:   icp_multi_reset
663
664 Description:
665         This function resets the icp multi device to a 'safe' state
666
667 Parameters:
668         struct comedi_device *dev       Pointer to current service structure
669
670 Returns:int     0 = success
671
672 ==============================================================================
673 */
674 static int icp_multi_reset(struct comedi_device *dev)
675 {
676         unsigned int i;
677
678         /*  Clear INT enables and requests */
679         writew(0, devpriv->io_addr + ICP_MULTI_INT_EN);
680         writew(0x00ff, devpriv->io_addr + ICP_MULTI_INT_STAT);
681
682         /* Set DACs to 0..5V range and 0V output */
683         for (i = 0; i < 4; i++) {
684                 devpriv->DacCmdStatus &= 0xfcce;
685
686                 /*  Set channel number */
687                 devpriv->DacCmdStatus |= (i << 8);
688
689                 /*  Output 0V */
690                 writew(0, devpriv->io_addr + ICP_MULTI_AO);
691
692                 /*  Set start conversion bit */
693                 devpriv->DacCmdStatus |= DAC_ST;
694
695                 /*  Output to command / status register */
696                 writew(devpriv->DacCmdStatus,
697                         devpriv->io_addr + ICP_MULTI_DAC_CSR);
698
699                 /*  Delay to allow DAC time to recover */
700                 udelay(1);
701         }
702
703         /* Digital outputs to 0 */
704         writew(0, devpriv->io_addr + ICP_MULTI_DO);
705
706         return 0;
707 }
708
709 static int icp_multi_attach(struct comedi_device *dev,
710                             struct comedi_devconfig *it)
711 {
712         struct comedi_subdevice *s;
713         int ret, subdev, n_subdevices;
714         unsigned int irq;
715         struct pcilst_struct *card = NULL;
716         resource_size_t io_addr[5], iobase;
717         unsigned char pci_bus, pci_slot, pci_func;
718
719         printk(KERN_WARNING
720                "icp_multi EDBG: BGN: icp_multi_attach(...)\n");
721
722         /*  Allocate private data storage space */
723         ret = alloc_private(dev, sizeof(struct icp_multi_private));
724         if (ret < 0)
725                 return ret;
726
727         /*  Initialise list of PCI cards in system, if not already done so */
728         if (pci_list_builded++ == 0)
729                 pci_card_list_init(PCI_VENDOR_ID_ICP, 0);
730
731         printk(KERN_WARNING
732                "Anne's comedi%d: icp_multi: board=%s", dev->minor,
733                this_board->name);
734
735         card = select_and_alloc_pci_card(PCI_VENDOR_ID_ICP,
736                                          this_board->device_id, it->options[0],
737                                          it->options[1]);
738
739         if (card == NULL)
740                 return -EIO;
741
742         devpriv->card = card;
743
744         if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0],
745                            &irq)) < 0) {
746                 printk(KERN_WARNING " - Can't get configuration data!\n");
747                 return -EIO;
748         }
749
750         iobase = io_addr[2];
751         devpriv->phys_iobase = iobase;
752
753         printk(KERN_WARNING
754                ", b:s:f=%d:%d:%d, io=0x%8llx \n", pci_bus, pci_slot, pci_func,
755                (unsigned long long)iobase);
756
757         devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE);
758
759         if (devpriv->io_addr == NULL) {
760                 printk(KERN_WARNING "ioremap failed.\n");
761                 return -ENOMEM;
762         }
763
764         dev->board_name = this_board->name;
765
766         n_subdevices = 0;
767         n_subdevices++;
768         n_subdevices++;
769         n_subdevices++;
770         n_subdevices++;
771         n_subdevices++;
772
773         ret = comedi_alloc_subdevices(dev, n_subdevices);
774         if (ret)
775                 return ret;
776
777         icp_multi_reset(dev);
778
779         if (this_board->have_irq) {
780                 if (irq) {
781                         if (request_irq(irq, interrupt_service_icp_multi,
782                                         IRQF_SHARED, "Inova Icp Multi", dev)) {
783                                 printk(KERN_WARNING
784                                     "unable to allocate IRQ %u, DISABLING IT",
785                                      irq);
786                                 irq = 0;        /* Can't use IRQ */
787                         } else
788                                 printk(KERN_WARNING ", irq=%u", irq);
789                 } else
790                         printk(KERN_WARNING ", IRQ disabled");
791         } else
792                 irq = 0;
793
794         dev->irq = irq;
795
796         printk(KERN_WARNING ".\n");
797
798         subdev = 0;
799
800         s = &dev->subdevices[subdev];
801         dev->read_subdev = s;
802         s->type = COMEDI_SUBD_AI;
803         s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF;
804         s->n_chan = 16;
805         s->maxdata = 0x0fff;
806         s->len_chanlist = 16;
807         s->range_table = this_board->rangelist_ai;
808         s->insn_read = icp_multi_insn_read_ai;
809         subdev++;
810
811         s = &dev->subdevices[subdev];
812         s->type = COMEDI_SUBD_AO;
813         s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
814         s->n_chan = 4;
815         s->maxdata = 0x0fff;
816         s->len_chanlist = 4;
817         s->range_table = &range_analog;
818         s->insn_write = icp_multi_insn_write_ao;
819         s->insn_read = icp_multi_insn_read_ao;
820         subdev++;
821
822         s = &dev->subdevices[subdev];
823         s->type = COMEDI_SUBD_DI;
824         s->subdev_flags = SDF_READABLE;
825         s->n_chan = 16;
826         s->maxdata = 1;
827         s->len_chanlist = 16;
828         s->range_table = &range_digital;
829         s->io_bits = 0;
830         s->insn_bits = icp_multi_insn_bits_di;
831         subdev++;
832
833         s = &dev->subdevices[subdev];
834         s->type = COMEDI_SUBD_DO;
835         s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
836         s->n_chan = 8;
837         s->maxdata = 1;
838         s->len_chanlist = 8;
839         s->range_table = &range_digital;
840         s->io_bits = 0xff;
841         s->state = 0;
842         s->insn_bits = icp_multi_insn_bits_do;
843         subdev++;
844
845         s = &dev->subdevices[subdev];
846         s->type = COMEDI_SUBD_COUNTER;
847         s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
848         s->n_chan = 4;
849         s->maxdata = 0xffff;
850         s->len_chanlist = 4;
851         s->state = 0;
852         s->insn_read = icp_multi_insn_read_ctr;
853         s->insn_write = icp_multi_insn_write_ctr;
854         subdev++;
855
856         devpriv->valid = 1;
857
858         return 0;
859 }
860
861 static void icp_multi_detach(struct comedi_device *dev)
862 {
863         if (dev->private)
864                 if (devpriv->valid)
865                         icp_multi_reset(dev);
866         if (dev->irq)
867                 free_irq(dev->irq, dev);
868         if (dev->private && devpriv->io_addr)
869                 iounmap(devpriv->io_addr);
870         if (dev->private && devpriv->card)
871                 pci_card_free(devpriv->card);
872         if (--pci_list_builded == 0)
873                 pci_card_list_cleanup(PCI_VENDOR_ID_ICP);
874 }
875
876 static const struct boardtype boardtypes[] = {
877         {
878                 .name           = "icp_multi",
879                 .device_id      = PCI_DEVICE_ID_ICP_MULTI,
880                 .iorange        = IORANGE_ICP_MULTI,
881                 .have_irq       = 1,
882                 .cardtype       = TYPE_ICP_MULTI,
883                 .rangelist_ai   = &range_analog,
884                 .rangecode      = range_codes_analog,
885         },
886 };
887
888 static struct comedi_driver icp_multi_driver = {
889         .driver_name    = "icp_multi",
890         .module         = THIS_MODULE,
891         .attach         = icp_multi_attach,
892         .detach         = icp_multi_detach,
893         .num_names      = ARRAY_SIZE(boardtypes),
894         .board_name     = &boardtypes[0].name,
895         .offset         = sizeof(struct boardtype),
896 };
897
898 static int __devinit icp_multi_pci_probe(struct pci_dev *dev,
899                                            const struct pci_device_id *ent)
900 {
901         return comedi_pci_auto_config(dev, &icp_multi_driver);
902 }
903
904 static void __devexit icp_multi_pci_remove(struct pci_dev *dev)
905 {
906         comedi_pci_auto_unconfig(dev);
907 }
908
909 static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = {
910         { PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) },
911         { 0 }
912 };
913 MODULE_DEVICE_TABLE(pci, icp_multi_pci_table);
914
915 static struct pci_driver icp_multi_pci_driver = {
916         .name           = "icp_multi",
917         .id_table       = icp_multi_pci_table,
918         .probe          = icp_multi_pci_probe,
919         .remove         = __devexit_p(icp_multi_pci_remove),
920 };
921 module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver);
922
923 MODULE_AUTHOR("Comedi http://www.comedi.org");
924 MODULE_DESCRIPTION("Comedi low-level driver");
925 MODULE_LICENSE("GPL");