3 * Driver for Intelligent Instruments PCI-20001C carrier board and modules.
5 * Copyright (C) 2000 Markus Kempf <kempf@matsci.uni-sb.de>
6 * with suggestions from David Schleef 16.06.2000
11 * Description: Intelligent Instruments PCI-20001C carrier board
12 * Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc)
13 * Author: Markus Kempf <kempf@matsci.uni-sb.de>
16 * Supports the PCI-20001C-1a and PCI-20001C-2a carrier boards. The
17 * -2a version has 32 on-board DIO channels. Three add-on modules
18 * can be added to the carrier board for additional functionality.
20 * Supported add-on modules:
21 * PCI-20006M-1 1 channel, 16-bit analog output module
22 * PCI-20006M-2 2 channel, 16-bit analog output module
23 * PCI-20341M-1A 4 channel, 16-bit analog input module
26 * 0 Board base address
30 #include <linux/module.h>
32 #include "../comedidev.h"
37 #define II20K_SIZE 0x400
38 #define II20K_MOD_OFFSET 0x100
39 #define II20K_ID_REG 0x00
40 #define II20K_ID_MOD1_EMPTY (1 << 7)
41 #define II20K_ID_MOD2_EMPTY (1 << 6)
42 #define II20K_ID_MOD3_EMPTY (1 << 5)
43 #define II20K_ID_MASK 0x1f
44 #define II20K_ID_PCI20001C_1A 0x1b /* no on-board DIO */
45 #define II20K_ID_PCI20001C_2A 0x1d /* on-board DIO */
46 #define II20K_MOD_STATUS_REG 0x40
47 #define II20K_MOD_STATUS_IRQ_MOD1 (1 << 7)
48 #define II20K_MOD_STATUS_IRQ_MOD2 (1 << 6)
49 #define II20K_MOD_STATUS_IRQ_MOD3 (1 << 5)
50 #define II20K_DIO0_REG 0x80
51 #define II20K_DIO1_REG 0x81
52 #define II20K_DIR_ENA_REG 0x82
53 #define II20K_DIR_DIO3_OUT (1 << 7)
54 #define II20K_DIR_DIO2_OUT (1 << 6)
55 #define II20K_BUF_DISAB_DIO3 (1 << 5)
56 #define II20K_BUF_DISAB_DIO2 (1 << 4)
57 #define II20K_DIR_DIO1_OUT (1 << 3)
58 #define II20K_DIR_DIO0_OUT (1 << 2)
59 #define II20K_BUF_DISAB_DIO1 (1 << 1)
60 #define II20K_BUF_DISAB_DIO0 (1 << 0)
61 #define II20K_CTRL01_REG 0x83
62 #define II20K_CTRL01_SET (1 << 7)
63 #define II20K_CTRL01_DIO0_IN (1 << 4)
64 #define II20K_CTRL01_DIO1_IN (1 << 1)
65 #define II20K_DIO2_REG 0xc0
66 #define II20K_DIO3_REG 0xc1
67 #define II20K_CTRL23_REG 0xc3
68 #define II20K_CTRL23_SET (1 << 7)
69 #define II20K_CTRL23_DIO2_IN (1 << 4)
70 #define II20K_CTRL23_DIO3_IN (1 << 1)
72 #define II20K_ID_PCI20006M_1 0xe2 /* 1 AO channels */
73 #define II20K_ID_PCI20006M_2 0xe3 /* 2 AO channels */
74 #define II20K_AO_STRB_REG(x) (0x0b + ((x) * 0x08))
75 #define II20K_AO_LSB_REG(x) (0x0d + ((x) * 0x08))
76 #define II20K_AO_MSB_REG(x) (0x0e + ((x) * 0x08))
77 #define II20K_AO_STRB_BOTH_REG 0x1b
79 #define II20K_ID_PCI20341M_1 0x77 /* 4 AI channels */
80 #define II20K_AI_STATUS_CMD_REG 0x01
81 #define II20K_AI_STATUS_CMD_BUSY (1 << 7)
82 #define II20K_AI_STATUS_CMD_HW_ENA (1 << 1)
83 #define II20K_AI_STATUS_CMD_EXT_START (1 << 0)
84 #define II20K_AI_LSB_REG 0x02
85 #define II20K_AI_MSB_REG 0x03
86 #define II20K_AI_PACER_RESET_REG 0x04
87 #define II20K_AI_16BIT_DATA_REG 0x06
88 #define II20K_AI_CONF_REG 0x10
89 #define II20K_AI_CONF_ENA (1 << 2)
90 #define II20K_AI_OPT_REG 0x11
91 #define II20K_AI_OPT_TRIG_ENA (1 << 5)
92 #define II20K_AI_OPT_TRIG_INV (1 << 4)
93 #define II20K_AI_OPT_TIMEBASE(x) (((x) & 0x3) << 1)
94 #define II20K_AI_OPT_BURST_MODE (1 << 0)
95 #define II20K_AI_STATUS_REG 0x12
96 #define II20K_AI_STATUS_INT (1 << 7)
97 #define II20K_AI_STATUS_TRIG (1 << 6)
98 #define II20K_AI_STATUS_TRIG_ENA (1 << 5)
99 #define II20K_AI_STATUS_PACER_ERR (1 << 2)
100 #define II20K_AI_STATUS_DATA_ERR (1 << 1)
101 #define II20K_AI_STATUS_SET_TIME_ERR (1 << 0)
102 #define II20K_AI_LAST_CHAN_ADDR_REG 0x13
103 #define II20K_AI_CUR_ADDR_REG 0x14
104 #define II20K_AI_SET_TIME_REG 0x15
105 #define II20K_AI_DELAY_LSB_REG 0x16
106 #define II20K_AI_DELAY_MSB_REG 0x17
107 #define II20K_AI_CHAN_ADV_REG 0x18
108 #define II20K_AI_CHAN_RESET_REG 0x19
109 #define II20K_AI_START_TRIG_REG 0x1a
110 #define II20K_AI_COUNT_RESET_REG 0x1b
111 #define II20K_AI_CHANLIST_REG 0x80
112 #define II20K_AI_CHANLIST_ONBOARD_ONLY (1 << 5)
113 #define II20K_AI_CHANLIST_GAIN(x) (((x) & 0x3) << 3)
114 #define II20K_AI_CHANLIST_MUX_ENA (1 << 2)
115 #define II20K_AI_CHANLIST_CHAN(x) (((x) & 0x3) << 0)
116 #define II20K_AI_CHANLIST_LEN 0x80
118 /* the AO range is set by jumpers on the 20006M module */
119 static const struct comedi_lrange ii20k_ao_ranges
= {
121 BIP_RANGE(5), /* Chan 0 - W1/W3 in Chan 1 - W2/W4 in */
122 UNI_RANGE(10), /* Chan 0 - W1/W3 out Chan 1 - W2/W4 in */
123 BIP_RANGE(10) /* Chan 0 - W1/W3 in Chan 1 - W2/W4 out */
127 static const struct comedi_lrange ii20k_ai_ranges
= {
129 BIP_RANGE(5), /* gain 1 */
130 BIP_RANGE(0.5), /* gain 10 */
131 BIP_RANGE(0.05), /* gain 100 */
132 BIP_RANGE(0.025) /* gain 200 */
136 static void __iomem
*ii20k_module_iobase(struct comedi_device
*dev
,
137 struct comedi_subdevice
*s
)
139 return dev
->mmio
+ (s
->index
+ 1) * II20K_MOD_OFFSET
;
142 static int ii20k_ao_insn_write(struct comedi_device
*dev
,
143 struct comedi_subdevice
*s
,
144 struct comedi_insn
*insn
,
147 void __iomem
*iobase
= ii20k_module_iobase(dev
, s
);
148 unsigned int chan
= CR_CHAN(insn
->chanspec
);
151 for (i
= 0; i
< insn
->n
; i
++) {
152 unsigned int val
= data
[i
];
154 s
->readback
[chan
] = val
;
157 val
+= ((s
->maxdata
+ 1) >> 1);
160 writeb(val
& 0xff, iobase
+ II20K_AO_LSB_REG(chan
));
161 writeb((val
>> 8) & 0xff, iobase
+ II20K_AO_MSB_REG(chan
));
162 writeb(0x00, iobase
+ II20K_AO_STRB_REG(chan
));
168 static int ii20k_ai_eoc(struct comedi_device
*dev
,
169 struct comedi_subdevice
*s
,
170 struct comedi_insn
*insn
,
171 unsigned long context
)
173 void __iomem
*iobase
= ii20k_module_iobase(dev
, s
);
174 unsigned char status
;
176 status
= readb(iobase
+ II20K_AI_STATUS_REG
);
177 if ((status
& II20K_AI_STATUS_INT
) == 0)
182 static void ii20k_ai_setup(struct comedi_device
*dev
,
183 struct comedi_subdevice
*s
,
184 unsigned int chanspec
)
186 void __iomem
*iobase
= ii20k_module_iobase(dev
, s
);
187 unsigned int chan
= CR_CHAN(chanspec
);
188 unsigned int range
= CR_RANGE(chanspec
);
191 /* initialize module */
192 writeb(II20K_AI_CONF_ENA
, iobase
+ II20K_AI_CONF_REG
);
194 /* software conversion */
195 writeb(0, iobase
+ II20K_AI_STATUS_CMD_REG
);
197 /* set the time base for the settling time counter based on the gain */
198 val
= (range
< 3) ? II20K_AI_OPT_TIMEBASE(0) : II20K_AI_OPT_TIMEBASE(2);
199 writeb(val
, iobase
+ II20K_AI_OPT_REG
);
201 /* set the settling time counter based on the gain */
202 val
= (range
< 2) ? 0x58 : (range
< 3) ? 0x93 : 0x99;
203 writeb(val
, iobase
+ II20K_AI_SET_TIME_REG
);
205 /* set number of input channels */
206 writeb(1, iobase
+ II20K_AI_LAST_CHAN_ADDR_REG
);
208 /* set the channel list byte */
209 val
= II20K_AI_CHANLIST_ONBOARD_ONLY
|
210 II20K_AI_CHANLIST_MUX_ENA
|
211 II20K_AI_CHANLIST_GAIN(range
) |
212 II20K_AI_CHANLIST_CHAN(chan
);
213 writeb(val
, iobase
+ II20K_AI_CHANLIST_REG
);
215 /* reset settling time counter and trigger delay counter */
216 writeb(0, iobase
+ II20K_AI_COUNT_RESET_REG
);
218 /* reset channel scanner */
219 writeb(0, iobase
+ II20K_AI_CHAN_RESET_REG
);
222 static int ii20k_ai_insn_read(struct comedi_device
*dev
,
223 struct comedi_subdevice
*s
,
224 struct comedi_insn
*insn
,
227 void __iomem
*iobase
= ii20k_module_iobase(dev
, s
);
231 ii20k_ai_setup(dev
, s
, insn
->chanspec
);
233 for (i
= 0; i
< insn
->n
; i
++) {
236 /* generate a software start convert signal */
237 readb(iobase
+ II20K_AI_PACER_RESET_REG
);
239 ret
= comedi_timeout(dev
, s
, insn
, ii20k_ai_eoc
, 0);
243 val
= readb(iobase
+ II20K_AI_LSB_REG
);
244 val
|= (readb(iobase
+ II20K_AI_MSB_REG
) << 8);
246 /* munge two's complement data */
247 val
+= ((s
->maxdata
+ 1) >> 1);
256 static void ii20k_dio_config(struct comedi_device
*dev
,
257 struct comedi_subdevice
*s
)
259 unsigned char ctrl01
= 0;
260 unsigned char ctrl23
= 0;
261 unsigned char dir_ena
= 0;
263 /* port 0 - channels 0-7 */
264 if (s
->io_bits
& 0x000000ff) {
266 ctrl01
&= ~II20K_CTRL01_DIO0_IN
;
267 dir_ena
&= ~II20K_BUF_DISAB_DIO0
;
268 dir_ena
|= II20K_DIR_DIO0_OUT
;
271 ctrl01
|= II20K_CTRL01_DIO0_IN
;
272 dir_ena
&= ~II20K_DIR_DIO0_OUT
;
275 /* port 1 - channels 8-15 */
276 if (s
->io_bits
& 0x0000ff00) {
278 ctrl01
&= ~II20K_CTRL01_DIO1_IN
;
279 dir_ena
&= ~II20K_BUF_DISAB_DIO1
;
280 dir_ena
|= II20K_DIR_DIO1_OUT
;
283 ctrl01
|= II20K_CTRL01_DIO1_IN
;
284 dir_ena
&= ~II20K_DIR_DIO1_OUT
;
287 /* port 2 - channels 16-23 */
288 if (s
->io_bits
& 0x00ff0000) {
290 ctrl23
&= ~II20K_CTRL23_DIO2_IN
;
291 dir_ena
&= ~II20K_BUF_DISAB_DIO2
;
292 dir_ena
|= II20K_DIR_DIO2_OUT
;
295 ctrl23
|= II20K_CTRL23_DIO2_IN
;
296 dir_ena
&= ~II20K_DIR_DIO2_OUT
;
299 /* port 3 - channels 24-31 */
300 if (s
->io_bits
& 0xff000000) {
302 ctrl23
&= ~II20K_CTRL23_DIO3_IN
;
303 dir_ena
&= ~II20K_BUF_DISAB_DIO3
;
304 dir_ena
|= II20K_DIR_DIO3_OUT
;
307 ctrl23
|= II20K_CTRL23_DIO3_IN
;
308 dir_ena
&= ~II20K_DIR_DIO3_OUT
;
311 ctrl23
|= II20K_CTRL01_SET
;
312 ctrl23
|= II20K_CTRL23_SET
;
314 /* order is important */
315 writeb(ctrl01
, dev
->mmio
+ II20K_CTRL01_REG
);
316 writeb(ctrl23
, dev
->mmio
+ II20K_CTRL23_REG
);
317 writeb(dir_ena
, dev
->mmio
+ II20K_DIR_ENA_REG
);
320 static int ii20k_dio_insn_config(struct comedi_device
*dev
,
321 struct comedi_subdevice
*s
,
322 struct comedi_insn
*insn
,
325 unsigned int chan
= CR_CHAN(insn
->chanspec
);
338 ret
= comedi_dio_insn_config(dev
, s
, insn
, data
, mask
);
342 ii20k_dio_config(dev
, s
);
347 static int ii20k_dio_insn_bits(struct comedi_device
*dev
,
348 struct comedi_subdevice
*s
,
349 struct comedi_insn
*insn
,
354 mask
= comedi_dio_update_state(s
, data
);
356 if (mask
& 0x000000ff)
357 writeb((s
->state
>> 0) & 0xff,
358 dev
->mmio
+ II20K_DIO0_REG
);
359 if (mask
& 0x0000ff00)
360 writeb((s
->state
>> 8) & 0xff,
361 dev
->mmio
+ II20K_DIO1_REG
);
362 if (mask
& 0x00ff0000)
363 writeb((s
->state
>> 16) & 0xff,
364 dev
->mmio
+ II20K_DIO2_REG
);
365 if (mask
& 0xff000000)
366 writeb((s
->state
>> 24) & 0xff,
367 dev
->mmio
+ II20K_DIO3_REG
);
370 data
[1] = readb(dev
->mmio
+ II20K_DIO0_REG
);
371 data
[1] |= readb(dev
->mmio
+ II20K_DIO1_REG
) << 8;
372 data
[1] |= readb(dev
->mmio
+ II20K_DIO2_REG
) << 16;
373 data
[1] |= readb(dev
->mmio
+ II20K_DIO3_REG
) << 24;
378 static int ii20k_init_module(struct comedi_device
*dev
,
379 struct comedi_subdevice
*s
)
381 void __iomem
*iobase
= ii20k_module_iobase(dev
, s
);
385 id
= readb(iobase
+ II20K_ID_REG
);
387 case II20K_ID_PCI20006M_1
:
388 case II20K_ID_PCI20006M_2
:
389 /* Analog Output subdevice */
390 s
->type
= COMEDI_SUBD_AO
;
391 s
->subdev_flags
= SDF_WRITABLE
;
392 s
->n_chan
= (id
== II20K_ID_PCI20006M_2
) ? 2 : 1;
394 s
->range_table
= &ii20k_ao_ranges
;
395 s
->insn_write
= ii20k_ao_insn_write
;
397 ret
= comedi_alloc_subdev_readback(s
);
401 case II20K_ID_PCI20341M_1
:
402 /* Analog Input subdevice */
403 s
->type
= COMEDI_SUBD_AI
;
404 s
->subdev_flags
= SDF_READABLE
| SDF_DIFF
;
407 s
->range_table
= &ii20k_ai_ranges
;
408 s
->insn_read
= ii20k_ai_insn_read
;
411 s
->type
= COMEDI_SUBD_UNUSED
;
418 static int ii20k_attach(struct comedi_device
*dev
,
419 struct comedi_devconfig
*it
)
421 struct comedi_subdevice
*s
;
422 unsigned int membase
;
427 membase
= it
->options
[0];
428 if (!membase
|| (membase
& ~(0x100000 - II20K_SIZE
))) {
429 dev_warn(dev
->class_dev
,
430 "%s: invalid memory address specified\n",
435 if (!request_mem_region(membase
, II20K_SIZE
, dev
->board_name
)) {
436 dev_warn(dev
->class_dev
, "%s: I/O mem conflict (%#x,%u)\n",
437 dev
->board_name
, membase
, II20K_SIZE
);
440 dev
->iobase
= membase
; /* actually, a memory address */
442 dev
->mmio
= ioremap(membase
, II20K_SIZE
);
446 id
= readb(dev
->mmio
+ II20K_ID_REG
);
447 switch (id
& II20K_ID_MASK
) {
448 case II20K_ID_PCI20001C_1A
:
451 case II20K_ID_PCI20001C_2A
:
458 ret
= comedi_alloc_subdevices(dev
, 4);
462 s
= &dev
->subdevices
[0];
463 if (id
& II20K_ID_MOD1_EMPTY
) {
464 s
->type
= COMEDI_SUBD_UNUSED
;
466 ret
= ii20k_init_module(dev
, s
);
471 s
= &dev
->subdevices
[1];
472 if (id
& II20K_ID_MOD2_EMPTY
) {
473 s
->type
= COMEDI_SUBD_UNUSED
;
475 ret
= ii20k_init_module(dev
, s
);
480 s
= &dev
->subdevices
[2];
481 if (id
& II20K_ID_MOD3_EMPTY
) {
482 s
->type
= COMEDI_SUBD_UNUSED
;
484 ret
= ii20k_init_module(dev
, s
);
489 /* Digital I/O subdevice */
490 s
= &dev
->subdevices
[3];
492 s
->type
= COMEDI_SUBD_DIO
;
493 s
->subdev_flags
= SDF_READABLE
| SDF_WRITABLE
;
496 s
->range_table
= &range_digital
;
497 s
->insn_bits
= ii20k_dio_insn_bits
;
498 s
->insn_config
= ii20k_dio_insn_config
;
500 /* default all channels to input */
501 ii20k_dio_config(dev
, s
);
503 s
->type
= COMEDI_SUBD_UNUSED
;
509 static void ii20k_detach(struct comedi_device
*dev
)
513 if (dev
->iobase
) /* actually, a memory address */
514 release_mem_region(dev
->iobase
, II20K_SIZE
);
517 static struct comedi_driver ii20k_driver
= {
518 .driver_name
= "ii_pci20kc",
519 .module
= THIS_MODULE
,
520 .attach
= ii20k_attach
,
521 .detach
= ii20k_detach
,
523 module_comedi_driver(ii20k_driver
);
525 MODULE_AUTHOR("Comedi http://www.comedi.org");
526 MODULE_DESCRIPTION("Comedi low-level driver");
527 MODULE_LICENSE("GPL");