1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * addi_apci_2200.c |
4 | * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. |
5 | * Project manager: Eric Stolz |
6 | * |
7 | * ADDI-DATA GmbH |
8 | * Dieselstrasse 3 |
9 | * D-77833 Ottersweier |
10 | * Tel: +19(0)7223/9493-0 |
11 | * Fax: +49(0)7223/9493-92 |
12 | * http://www.addi-data.com |
13 | * info@addi-data.com |
14 | */ |
15 | |
16 | #include <linux/module.h> |
17 | #include <linux/comedi/comedi_pci.h> |
18 | |
19 | #include "addi_watchdog.h" |
20 | |
21 | /* |
22 | * I/O Register Map |
23 | */ |
24 | #define APCI2200_DI_REG 0x00 |
25 | #define APCI2200_DO_REG 0x04 |
26 | #define APCI2200_WDOG_REG 0x08 |
27 | |
28 | static int apci2200_di_insn_bits(struct comedi_device *dev, |
29 | struct comedi_subdevice *s, |
30 | struct comedi_insn *insn, |
31 | unsigned int *data) |
32 | { |
33 | data[1] = inw(port: dev->iobase + APCI2200_DI_REG); |
34 | |
35 | return insn->n; |
36 | } |
37 | |
38 | static int apci2200_do_insn_bits(struct comedi_device *dev, |
39 | struct comedi_subdevice *s, |
40 | struct comedi_insn *insn, |
41 | unsigned int *data) |
42 | { |
43 | s->state = inw(port: dev->iobase + APCI2200_DO_REG); |
44 | |
45 | if (comedi_dio_update_state(s, data)) |
46 | outw(value: s->state, port: dev->iobase + APCI2200_DO_REG); |
47 | |
48 | data[1] = s->state; |
49 | |
50 | return insn->n; |
51 | } |
52 | |
53 | static int apci2200_reset(struct comedi_device *dev) |
54 | { |
55 | outw(value: 0x0, port: dev->iobase + APCI2200_DO_REG); |
56 | |
57 | addi_watchdog_reset(iobase: dev->iobase + APCI2200_WDOG_REG); |
58 | |
59 | return 0; |
60 | } |
61 | |
62 | static int apci2200_auto_attach(struct comedi_device *dev, |
63 | unsigned long context_unused) |
64 | { |
65 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
66 | struct comedi_subdevice *s; |
67 | int ret; |
68 | |
69 | ret = comedi_pci_enable(dev); |
70 | if (ret) |
71 | return ret; |
72 | |
73 | dev->iobase = pci_resource_start(pcidev, 1); |
74 | |
75 | ret = comedi_alloc_subdevices(dev, num_subdevices: 3); |
76 | if (ret) |
77 | return ret; |
78 | |
79 | /* Initialize the digital input subdevice */ |
80 | s = &dev->subdevices[0]; |
81 | s->type = COMEDI_SUBD_DI; |
82 | s->subdev_flags = SDF_READABLE; |
83 | s->n_chan = 8; |
84 | s->maxdata = 1; |
85 | s->range_table = &range_digital; |
86 | s->insn_bits = apci2200_di_insn_bits; |
87 | |
88 | /* Initialize the digital output subdevice */ |
89 | s = &dev->subdevices[1]; |
90 | s->type = COMEDI_SUBD_DO; |
91 | s->subdev_flags = SDF_WRITABLE; |
92 | s->n_chan = 16; |
93 | s->maxdata = 1; |
94 | s->range_table = &range_digital; |
95 | s->insn_bits = apci2200_do_insn_bits; |
96 | |
97 | /* Initialize the watchdog subdevice */ |
98 | s = &dev->subdevices[2]; |
99 | ret = addi_watchdog_init(s, iobase: dev->iobase + APCI2200_WDOG_REG); |
100 | if (ret) |
101 | return ret; |
102 | |
103 | apci2200_reset(dev); |
104 | return 0; |
105 | } |
106 | |
107 | static void apci2200_detach(struct comedi_device *dev) |
108 | { |
109 | if (dev->iobase) |
110 | apci2200_reset(dev); |
111 | comedi_pci_detach(dev); |
112 | } |
113 | |
114 | static struct comedi_driver apci2200_driver = { |
115 | .driver_name = "addi_apci_2200" , |
116 | .module = THIS_MODULE, |
117 | .auto_attach = apci2200_auto_attach, |
118 | .detach = apci2200_detach, |
119 | }; |
120 | |
121 | static int apci2200_pci_probe(struct pci_dev *dev, |
122 | const struct pci_device_id *id) |
123 | { |
124 | return comedi_pci_auto_config(pcidev: dev, driver: &apci2200_driver, context: id->driver_data); |
125 | } |
126 | |
127 | static const struct pci_device_id apci2200_pci_table[] = { |
128 | { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1005) }, |
129 | { 0 } |
130 | }; |
131 | MODULE_DEVICE_TABLE(pci, apci2200_pci_table); |
132 | |
133 | static struct pci_driver apci2200_pci_driver = { |
134 | .name = "addi_apci_2200" , |
135 | .id_table = apci2200_pci_table, |
136 | .probe = apci2200_pci_probe, |
137 | .remove = comedi_pci_auto_unconfig, |
138 | }; |
139 | module_comedi_pci_driver(apci2200_driver, apci2200_pci_driver); |
140 | |
141 | MODULE_DESCRIPTION("ADDI-DATA APCI-2200 Relay board, optically isolated" ); |
142 | MODULE_AUTHOR("Comedi https://www.comedi.org" ); |
143 | MODULE_LICENSE("GPL" ); |
144 | |