3 * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
4 * Project manager: Eric Stolz
9 * Tel: +19(0)7223/9493-0
10 * Fax: +49(0)7223/9493-92
11 * http://www.addi-data.com
14 * This program is free software; you can redistribute it and/or modify it
15 * under the terms of the GNU General Public License as published by the
16 * Free Software Foundation; either version 2 of the License, or (at your
17 * option) any later version.
19 * This program is distributed in the hope that it will be useful, but WITHOUT
20 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
25 #include <linux/module.h>
26 #include <linux/interrupt.h>
27 #include <linux/sched.h>
29 #include "../comedi_pci.h"
30 #include "amcc_s5933.h"
33 * PCI bar 1 register I/O map
35 #define APCI3501_AO_CTRL_STATUS_REG 0x00
36 #define APCI3501_AO_CTRL_BIPOLAR (1 << 0)
37 #define APCI3501_AO_STATUS_READY (1 << 8)
38 #define APCI3501_AO_DATA_REG 0x04
39 #define APCI3501_AO_DATA_CHAN(x) ((x) << 0)
40 #define APCI3501_AO_DATA_VAL(x) ((x) << 8)
41 #define APCI3501_AO_DATA_BIPOLAR (1 << 31)
42 #define APCI3501_AO_TRIG_SCS_REG 0x08
43 #define APCI3501_TIMER_SYNC_REG 0x20
44 #define APCI3501_TIMER_RELOAD_REG 0x24
45 #define APCI3501_TIMER_TIMEBASE_REG 0x28
46 #define APCI3501_TIMER_CTRL_REG 0x2c
47 #define APCI3501_TIMER_STATUS_REG 0x30
48 #define APCI3501_TIMER_IRQ_REG 0x34
49 #define APCI3501_TIMER_WARN_RELOAD_REG 0x38
50 #define APCI3501_TIMER_WARN_TIMEBASE_REG 0x3c
51 #define APCI3501_DO_REG 0x40
52 #define APCI3501_DI_REG 0x50
57 #define NVRAM_USER_DATA_START 0x100
59 #define NVCMD_BEGIN_READ (0x7 << 5)
60 #define NVCMD_LOAD_LOW (0x4 << 5)
61 #define NVCMD_LOAD_HIGH (0x5 << 5)
64 * Function types stored in the eeprom
66 #define EEPROM_DIGITALINPUT 0
67 #define EEPROM_DIGITALOUTPUT 1
68 #define EEPROM_ANALOGINPUT 2
69 #define EEPROM_ANALOGOUTPUT 3
70 #define EEPROM_TIMER 4
71 #define EEPROM_WATCHDOG 5
72 #define EEPROM_TIMER_WATCHDOG_COUNTER 10
74 struct apci3501_private
{
76 struct task_struct
*tsk_Current
;
77 unsigned char b_TimerSelectMode
;
80 static struct comedi_lrange apci3501_ao_range
= {
87 static int apci3501_wait_for_dac(struct comedi_device
*dev
)
92 status
= inl(dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
93 } while (!(status
& APCI3501_AO_STATUS_READY
));
98 static int apci3501_ao_insn_write(struct comedi_device
*dev
,
99 struct comedi_subdevice
*s
,
100 struct comedi_insn
*insn
,
103 unsigned int chan
= CR_CHAN(insn
->chanspec
);
104 unsigned int range
= CR_RANGE(insn
->chanspec
);
105 unsigned int cfg
= APCI3501_AO_DATA_CHAN(chan
);
110 * All analog output channels have the same output range.
111 * 14-bit bipolar: 0-10V
112 * 13-bit unipolar: +/-10V
113 * Changing the range of one channel changes all of them!
116 outl(0, dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
118 cfg
|= APCI3501_AO_DATA_BIPOLAR
;
119 outl(APCI3501_AO_CTRL_BIPOLAR
,
120 dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
123 for (i
= 0; i
< insn
->n
; i
++) {
124 unsigned int val
= data
[i
];
127 if (data
[i
] > 0x1fff) {
128 dev_err(dev
->class_dev
,
129 "Unipolar resolution is only 13-bits\n");
134 ret
= apci3501_wait_for_dac(dev
);
138 outl(cfg
| APCI3501_AO_DATA_VAL(val
),
139 dev
->iobase
+ APCI3501_AO_DATA_REG
);
141 s
->readback
[chan
] = val
;
147 #include "addi-data/hwdrv_apci3501.c"
149 static int apci3501_di_insn_bits(struct comedi_device
*dev
,
150 struct comedi_subdevice
*s
,
151 struct comedi_insn
*insn
,
154 data
[1] = inl(dev
->iobase
+ APCI3501_DI_REG
) & 0x3;
159 static int apci3501_do_insn_bits(struct comedi_device
*dev
,
160 struct comedi_subdevice
*s
,
161 struct comedi_insn
*insn
,
164 s
->state
= inl(dev
->iobase
+ APCI3501_DO_REG
);
166 if (comedi_dio_update_state(s
, data
))
167 outl(s
->state
, dev
->iobase
+ APCI3501_DO_REG
);
174 static void apci3501_eeprom_wait(unsigned long iobase
)
179 val
= inb(iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
180 } while (val
& 0x80);
183 static unsigned short apci3501_eeprom_readw(unsigned long iobase
,
186 unsigned short val
= 0;
190 /* Add the offset to the start of the user data */
191 addr
+= NVRAM_USER_DATA_START
;
193 for (i
= 0; i
< 2; i
++) {
194 /* Load the low 8 bit address */
195 outb(NVCMD_LOAD_LOW
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
196 apci3501_eeprom_wait(iobase
);
197 outb((addr
+ i
) & 0xff, iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
198 apci3501_eeprom_wait(iobase
);
200 /* Load the high 8 bit address */
201 outb(NVCMD_LOAD_HIGH
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
202 apci3501_eeprom_wait(iobase
);
203 outb(((addr
+ i
) >> 8) & 0xff,
204 iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
205 apci3501_eeprom_wait(iobase
);
207 /* Read the eeprom data byte */
208 outb(NVCMD_BEGIN_READ
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
209 apci3501_eeprom_wait(iobase
);
210 tmp
= inb(iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
211 apci3501_eeprom_wait(iobase
);
222 static int apci3501_eeprom_get_ao_n_chan(struct comedi_device
*dev
)
224 struct apci3501_private
*devpriv
= dev
->private;
225 unsigned long iobase
= devpriv
->i_IobaseAmcc
;
226 unsigned char nfuncs
;
229 nfuncs
= apci3501_eeprom_readw(iobase
, 10) & 0xff;
231 /* Read functionality details */
232 for (i
= 0; i
< nfuncs
; i
++) {
233 unsigned short offset
= i
* 4;
238 func
= apci3501_eeprom_readw(iobase
, 12 + offset
) & 0x3f;
239 addr
= apci3501_eeprom_readw(iobase
, 14 + offset
);
241 if (func
== EEPROM_ANALOGOUTPUT
) {
242 val
= apci3501_eeprom_readw(iobase
, addr
+ 10);
243 return (val
>> 4) & 0x3ff;
249 static int apci3501_eeprom_insn_read(struct comedi_device
*dev
,
250 struct comedi_subdevice
*s
,
251 struct comedi_insn
*insn
,
254 struct apci3501_private
*devpriv
= dev
->private;
255 unsigned short addr
= CR_CHAN(insn
->chanspec
);
257 data
[0] = apci3501_eeprom_readw(devpriv
->i_IobaseAmcc
, 2 * addr
);
262 static irqreturn_t
apci3501_interrupt(int irq
, void *d
)
264 struct comedi_device
*dev
= d
;
265 struct apci3501_private
*devpriv
= dev
->private;
266 unsigned int ui_Timer_AOWatchdog
;
267 unsigned long ul_Command1
;
269 /* Disable Interrupt */
270 ul_Command1
= inl(dev
->iobase
+ APCI3501_TIMER_CTRL_REG
);
271 ul_Command1
= ul_Command1
& 0xFFFFF9FDul
;
272 outl(ul_Command1
, dev
->iobase
+ APCI3501_TIMER_CTRL_REG
);
274 ui_Timer_AOWatchdog
= inl(dev
->iobase
+ APCI3501_TIMER_IRQ_REG
) & 0x1;
275 if ((!ui_Timer_AOWatchdog
)) {
276 dev_err(dev
->class_dev
, "IRQ from unknown source\n");
280 /* Enable Interrupt Send a signal to from kernel to user space */
281 send_sig(SIGIO
, devpriv
->tsk_Current
, 0);
282 ul_Command1
= inl(dev
->iobase
+ APCI3501_TIMER_CTRL_REG
);
283 ul_Command1
= (ul_Command1
& 0xFFFFF9FDul
) | 1 << 1;
284 outl(ul_Command1
, dev
->iobase
+ APCI3501_TIMER_CTRL_REG
);
285 inl(dev
->iobase
+ APCI3501_TIMER_STATUS_REG
);
290 static int apci3501_reset(struct comedi_device
*dev
)
296 /* Reset all digital outputs to "0" */
297 outl(0x0, dev
->iobase
+ APCI3501_DO_REG
);
299 /* Default all analog outputs to 0V (bipolar) */
300 outl(APCI3501_AO_CTRL_BIPOLAR
,
301 dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
302 val
= APCI3501_AO_DATA_BIPOLAR
| APCI3501_AO_DATA_VAL(0);
304 /* Set all analog output channels */
305 for (chan
= 0; chan
< 8; chan
++) {
306 ret
= apci3501_wait_for_dac(dev
);
308 dev_warn(dev
->class_dev
,
309 "%s: DAC not-ready for channel %i\n",
312 outl(val
| APCI3501_AO_DATA_CHAN(chan
),
313 dev
->iobase
+ APCI3501_AO_DATA_REG
);
320 static int apci3501_auto_attach(struct comedi_device
*dev
,
321 unsigned long context_unused
)
323 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
324 struct apci3501_private
*devpriv
;
325 struct comedi_subdevice
*s
;
329 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
333 ret
= comedi_pci_enable(dev
);
337 dev
->iobase
= pci_resource_start(pcidev
, 1);
338 devpriv
->i_IobaseAmcc
= pci_resource_start(pcidev
, 0);
340 ao_n_chan
= apci3501_eeprom_get_ao_n_chan(dev
);
342 if (pcidev
->irq
> 0) {
343 ret
= request_irq(pcidev
->irq
, apci3501_interrupt
, IRQF_SHARED
,
344 dev
->board_name
, dev
);
346 dev
->irq
= pcidev
->irq
;
349 ret
= comedi_alloc_subdevices(dev
, 5);
353 /* Initialize the analog output subdevice */
354 s
= &dev
->subdevices
[0];
356 s
->type
= COMEDI_SUBD_AO
;
357 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
358 s
->n_chan
= ao_n_chan
;
360 s
->range_table
= &apci3501_ao_range
;
361 s
->insn_write
= apci3501_ao_insn_write
;
363 ret
= comedi_alloc_subdev_readback(s
);
367 s
->type
= COMEDI_SUBD_UNUSED
;
370 /* Initialize the digital input subdevice */
371 s
= &dev
->subdevices
[1];
372 s
->type
= COMEDI_SUBD_DI
;
373 s
->subdev_flags
= SDF_READABLE
;
376 s
->range_table
= &range_digital
;
377 s
->insn_bits
= apci3501_di_insn_bits
;
379 /* Initialize the digital output subdevice */
380 s
= &dev
->subdevices
[2];
381 s
->type
= COMEDI_SUBD_DO
;
382 s
->subdev_flags
= SDF_WRITABLE
;
385 s
->range_table
= &range_digital
;
386 s
->insn_bits
= apci3501_do_insn_bits
;
388 /* Initialize the timer/watchdog subdevice */
389 s
= &dev
->subdevices
[3];
390 s
->type
= COMEDI_SUBD_TIMER
;
391 s
->subdev_flags
= SDF_WRITABLE
;
395 s
->range_table
= &range_digital
;
396 s
->insn_write
= apci3501_write_insn_timer
;
397 s
->insn_read
= apci3501_read_insn_timer
;
398 s
->insn_config
= apci3501_config_insn_timer
;
400 /* Initialize the eeprom subdevice */
401 s
= &dev
->subdevices
[4];
402 s
->type
= COMEDI_SUBD_MEMORY
;
403 s
->subdev_flags
= SDF_READABLE
| SDF_INTERNAL
;
406 s
->insn_read
= apci3501_eeprom_insn_read
;
412 static void apci3501_detach(struct comedi_device
*dev
)
416 comedi_pci_detach(dev
);
419 static struct comedi_driver apci3501_driver
= {
420 .driver_name
= "addi_apci_3501",
421 .module
= THIS_MODULE
,
422 .auto_attach
= apci3501_auto_attach
,
423 .detach
= apci3501_detach
,
426 static int apci3501_pci_probe(struct pci_dev
*dev
,
427 const struct pci_device_id
*id
)
429 return comedi_pci_auto_config(dev
, &apci3501_driver
, id
->driver_data
);
432 static const struct pci_device_id apci3501_pci_table
[] = {
433 { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA
, 0x3001) },
436 MODULE_DEVICE_TABLE(pci
, apci3501_pci_table
);
438 static struct pci_driver apci3501_pci_driver
= {
439 .name
= "addi_apci_3501",
440 .id_table
= apci3501_pci_table
,
441 .probe
= apci3501_pci_probe
,
442 .remove
= comedi_pci_auto_unconfig
,
444 module_comedi_pci_driver(apci3501_driver
, apci3501_pci_driver
);
446 MODULE_DESCRIPTION("ADDI-DATA APCI-3501 Analog output board");
447 MODULE_AUTHOR("Comedi http://www.comedi.org");
448 MODULE_LICENSE("GPL");