1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
5 * Project manager: Eric Stolz
10 * Tel: +19(0)7223/9493-0
11 * Fax: +49(0)7223/9493-92
12 * http://www.addi-data.com
17 * Driver: addi_apci_3501
18 * Description: ADDI-DATA APCI-3501 Analog output board
19 * Devices: [ADDI-DATA] APCI-3501 (addi_apci_3501)
20 * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
21 * Updated: Mon, 20 Jun 2016 10:57:01 -0700
24 * Configuration Options: not applicable, uses comedi PCI auto config
26 * This board has the following features:
27 * - 4 or 8 analog output channels
28 * - 2 optically isolated digital inputs
29 * - 2 optically isolated digital outputs
30 * - 1 12-bit watchdog/timer
32 * There are 2 versions of the APCI-3501:
33 * - APCI-3501-4 4 analog output channels
34 * - APCI-3501-8 8 analog output channels
36 * These boards use the same PCI Vendor/Device IDs. The number of output
37 * channels used by this driver is determined by reading the EEPROM on
40 * The watchdog/timer subdevice is not currently supported.
43 #include <linux/module.h>
45 #include "../comedi_pci.h"
46 #include "amcc_s5933.h"
49 * PCI bar 1 register I/O map
51 #define APCI3501_AO_CTRL_STATUS_REG 0x00
52 #define APCI3501_AO_CTRL_BIPOLAR BIT(0)
53 #define APCI3501_AO_STATUS_READY BIT(8)
54 #define APCI3501_AO_DATA_REG 0x04
55 #define APCI3501_AO_DATA_CHAN(x) ((x) << 0)
56 #define APCI3501_AO_DATA_VAL(x) ((x) << 8)
57 #define APCI3501_AO_DATA_BIPOLAR BIT(31)
58 #define APCI3501_AO_TRIG_SCS_REG 0x08
59 #define APCI3501_TIMER_BASE 0x20
60 #define APCI3501_DO_REG 0x40
61 #define APCI3501_DI_REG 0x50
66 #define NVRAM_USER_DATA_START 0x100
68 #define NVCMD_BEGIN_READ (0x7 << 5)
69 #define NVCMD_LOAD_LOW (0x4 << 5)
70 #define NVCMD_LOAD_HIGH (0x5 << 5)
73 * Function types stored in the eeprom
75 #define EEPROM_DIGITALINPUT 0
76 #define EEPROM_DIGITALOUTPUT 1
77 #define EEPROM_ANALOGINPUT 2
78 #define EEPROM_ANALOGOUTPUT 3
79 #define EEPROM_TIMER 4
80 #define EEPROM_WATCHDOG 5
81 #define EEPROM_TIMER_WATCHDOG_COUNTER 10
83 struct apci3501_private
{
85 unsigned char timer_mode
;
88 static const struct comedi_lrange apci3501_ao_range
= {
95 static int apci3501_wait_for_dac(struct comedi_device
*dev
)
100 status
= inl(dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
101 } while (!(status
& APCI3501_AO_STATUS_READY
));
106 static int apci3501_ao_insn_write(struct comedi_device
*dev
,
107 struct comedi_subdevice
*s
,
108 struct comedi_insn
*insn
,
111 unsigned int chan
= CR_CHAN(insn
->chanspec
);
112 unsigned int range
= CR_RANGE(insn
->chanspec
);
113 unsigned int cfg
= APCI3501_AO_DATA_CHAN(chan
);
118 * All analog output channels have the same output range.
119 * 14-bit bipolar: 0-10V
120 * 13-bit unipolar: +/-10V
121 * Changing the range of one channel changes all of them!
124 outl(0, dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
126 cfg
|= APCI3501_AO_DATA_BIPOLAR
;
127 outl(APCI3501_AO_CTRL_BIPOLAR
,
128 dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
131 for (i
= 0; i
< insn
->n
; i
++) {
132 unsigned int val
= data
[i
];
135 if (data
[i
] > 0x1fff) {
136 dev_err(dev
->class_dev
,
137 "Unipolar resolution is only 13-bits\n");
142 ret
= apci3501_wait_for_dac(dev
);
146 outl(cfg
| APCI3501_AO_DATA_VAL(val
),
147 dev
->iobase
+ APCI3501_AO_DATA_REG
);
149 s
->readback
[chan
] = val
;
155 static int apci3501_di_insn_bits(struct comedi_device
*dev
,
156 struct comedi_subdevice
*s
,
157 struct comedi_insn
*insn
,
160 data
[1] = inl(dev
->iobase
+ APCI3501_DI_REG
) & 0x3;
165 static int apci3501_do_insn_bits(struct comedi_device
*dev
,
166 struct comedi_subdevice
*s
,
167 struct comedi_insn
*insn
,
170 s
->state
= inl(dev
->iobase
+ APCI3501_DO_REG
);
172 if (comedi_dio_update_state(s
, data
))
173 outl(s
->state
, dev
->iobase
+ APCI3501_DO_REG
);
180 static void apci3501_eeprom_wait(unsigned long iobase
)
185 val
= inb(iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
186 } while (val
& 0x80);
189 static unsigned short apci3501_eeprom_readw(unsigned long iobase
,
192 unsigned short val
= 0;
196 /* Add the offset to the start of the user data */
197 addr
+= NVRAM_USER_DATA_START
;
199 for (i
= 0; i
< 2; i
++) {
200 /* Load the low 8 bit address */
201 outb(NVCMD_LOAD_LOW
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
202 apci3501_eeprom_wait(iobase
);
203 outb((addr
+ i
) & 0xff, iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
204 apci3501_eeprom_wait(iobase
);
206 /* Load the high 8 bit address */
207 outb(NVCMD_LOAD_HIGH
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
208 apci3501_eeprom_wait(iobase
);
209 outb(((addr
+ i
) >> 8) & 0xff,
210 iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
211 apci3501_eeprom_wait(iobase
);
213 /* Read the eeprom data byte */
214 outb(NVCMD_BEGIN_READ
, iobase
+ AMCC_OP_REG_MCSR_NVCMD
);
215 apci3501_eeprom_wait(iobase
);
216 tmp
= inb(iobase
+ AMCC_OP_REG_MCSR_NVDATA
);
217 apci3501_eeprom_wait(iobase
);
228 static int apci3501_eeprom_get_ao_n_chan(struct comedi_device
*dev
)
230 struct apci3501_private
*devpriv
= dev
->private;
231 unsigned char nfuncs
;
234 nfuncs
= apci3501_eeprom_readw(devpriv
->amcc
, 10) & 0xff;
236 /* Read functionality details */
237 for (i
= 0; i
< nfuncs
; i
++) {
238 unsigned short offset
= i
* 4;
243 func
= apci3501_eeprom_readw(devpriv
->amcc
, 12 + offset
) & 0x3f;
244 addr
= apci3501_eeprom_readw(devpriv
->amcc
, 14 + offset
);
246 if (func
== EEPROM_ANALOGOUTPUT
) {
247 val
= apci3501_eeprom_readw(devpriv
->amcc
, addr
+ 10);
248 return (val
>> 4) & 0x3ff;
254 static int apci3501_eeprom_insn_read(struct comedi_device
*dev
,
255 struct comedi_subdevice
*s
,
256 struct comedi_insn
*insn
,
259 struct apci3501_private
*devpriv
= dev
->private;
260 unsigned short addr
= CR_CHAN(insn
->chanspec
);
265 /* No point reading the same EEPROM location more than once. */
266 val
= apci3501_eeprom_readw(devpriv
->amcc
, 2 * addr
);
267 for (i
= 0; i
< insn
->n
; i
++)
274 static int apci3501_reset(struct comedi_device
*dev
)
280 /* Reset all digital outputs to "0" */
281 outl(0x0, dev
->iobase
+ APCI3501_DO_REG
);
283 /* Default all analog outputs to 0V (bipolar) */
284 outl(APCI3501_AO_CTRL_BIPOLAR
,
285 dev
->iobase
+ APCI3501_AO_CTRL_STATUS_REG
);
286 val
= APCI3501_AO_DATA_BIPOLAR
| APCI3501_AO_DATA_VAL(0);
288 /* Set all analog output channels */
289 for (chan
= 0; chan
< 8; chan
++) {
290 ret
= apci3501_wait_for_dac(dev
);
292 dev_warn(dev
->class_dev
,
293 "%s: DAC not-ready for channel %i\n",
296 outl(val
| APCI3501_AO_DATA_CHAN(chan
),
297 dev
->iobase
+ APCI3501_AO_DATA_REG
);
304 static int apci3501_auto_attach(struct comedi_device
*dev
,
305 unsigned long context_unused
)
307 struct pci_dev
*pcidev
= comedi_to_pci_dev(dev
);
308 struct apci3501_private
*devpriv
;
309 struct comedi_subdevice
*s
;
313 devpriv
= comedi_alloc_devpriv(dev
, sizeof(*devpriv
));
317 ret
= comedi_pci_enable(dev
);
321 devpriv
->amcc
= pci_resource_start(pcidev
, 0);
322 dev
->iobase
= pci_resource_start(pcidev
, 1);
324 ao_n_chan
= apci3501_eeprom_get_ao_n_chan(dev
);
326 ret
= comedi_alloc_subdevices(dev
, 5);
330 /* Initialize the analog output subdevice */
331 s
= &dev
->subdevices
[0];
333 s
->type
= COMEDI_SUBD_AO
;
334 s
->subdev_flags
= SDF_WRITABLE
| SDF_GROUND
| SDF_COMMON
;
335 s
->n_chan
= ao_n_chan
;
337 s
->range_table
= &apci3501_ao_range
;
338 s
->insn_write
= apci3501_ao_insn_write
;
340 ret
= comedi_alloc_subdev_readback(s
);
344 s
->type
= COMEDI_SUBD_UNUSED
;
347 /* Initialize the digital input subdevice */
348 s
= &dev
->subdevices
[1];
349 s
->type
= COMEDI_SUBD_DI
;
350 s
->subdev_flags
= SDF_READABLE
;
353 s
->range_table
= &range_digital
;
354 s
->insn_bits
= apci3501_di_insn_bits
;
356 /* Initialize the digital output subdevice */
357 s
= &dev
->subdevices
[2];
358 s
->type
= COMEDI_SUBD_DO
;
359 s
->subdev_flags
= SDF_WRITABLE
;
362 s
->range_table
= &range_digital
;
363 s
->insn_bits
= apci3501_do_insn_bits
;
365 /* Timer/Watchdog subdevice */
366 s
= &dev
->subdevices
[3];
367 s
->type
= COMEDI_SUBD_UNUSED
;
369 /* Initialize the eeprom subdevice */
370 s
= &dev
->subdevices
[4];
371 s
->type
= COMEDI_SUBD_MEMORY
;
372 s
->subdev_flags
= SDF_READABLE
| SDF_INTERNAL
;
375 s
->insn_read
= apci3501_eeprom_insn_read
;
381 static void apci3501_detach(struct comedi_device
*dev
)
385 comedi_pci_detach(dev
);
388 static struct comedi_driver apci3501_driver
= {
389 .driver_name
= "addi_apci_3501",
390 .module
= THIS_MODULE
,
391 .auto_attach
= apci3501_auto_attach
,
392 .detach
= apci3501_detach
,
395 static int apci3501_pci_probe(struct pci_dev
*dev
,
396 const struct pci_device_id
*id
)
398 return comedi_pci_auto_config(dev
, &apci3501_driver
, id
->driver_data
);
401 static const struct pci_device_id apci3501_pci_table
[] = {
402 { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA
, 0x3001) },
405 MODULE_DEVICE_TABLE(pci
, apci3501_pci_table
);
407 static struct pci_driver apci3501_pci_driver
= {
408 .name
= "addi_apci_3501",
409 .id_table
= apci3501_pci_table
,
410 .probe
= apci3501_pci_probe
,
411 .remove
= comedi_pci_auto_unconfig
,
413 module_comedi_pci_driver(apci3501_driver
, apci3501_pci_driver
);
415 MODULE_DESCRIPTION("ADDI-DATA APCI-3501 Analog output board");
416 MODULE_AUTHOR("Comedi https://www.comedi.org");
417 MODULE_LICENSE("GPL");