1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* |
3 | * COMEDI driver for generic PCI based 8255 digital i/o boards |
4 | * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> |
5 | * |
6 | * Based on the tested adl_pci7296 driver written by: |
7 | * Jon Grierson <jd@renko.co.uk> |
8 | * and the experimental cb_pcidio driver written by: |
9 | * Yoshiya Matsuzaka |
10 | * |
11 | * COMEDI - Linux Control and Measurement Device Interface |
12 | * Copyright (C) 2000 David A. Schleef <ds@schleef.org> |
13 | */ |
14 | |
15 | /* |
16 | * Driver: 8255_pci |
17 | * Description: Generic PCI based 8255 Digital I/O boards |
18 | * Devices: [ADLink] PCI-7224 (adl_pci-7224), PCI-7248 (adl_pci-7248), |
19 | * PCI-7296 (adl_pci-7296), |
20 | * [Measurement Computing] PCI-DIO24 (cb_pci-dio24), |
21 | * PCI-DIO24H (cb_pci-dio24h), PCI-DIO48H (cb_pci-dio48h), |
22 | * PCI-DIO96H (cb_pci-dio96h), |
23 | * [National Instruments] PCI-DIO-96 (ni_pci-dio-96), |
24 | * PCI-DIO-96B (ni_pci-dio-96b), PXI-6508 (ni_pxi-6508), |
25 | * PCI-6503 (ni_pci-6503), PCI-6503B (ni_pci-6503b), |
26 | * PCI-6503X (ni_pci-6503x), PXI-6503 (ni_pxi-6503) |
27 | * Author: H Hartley Sweeten <hsweeten@visionengravers.com> |
28 | * Updated: Wed, 12 Sep 2012 11:52:01 -0700 |
29 | * Status: untested |
30 | * |
31 | * These boards have one or more 8255 digital I/O chips, each of which |
32 | * is supported as a separate 24-channel DIO subdevice. |
33 | * |
34 | * Boards with 24 DIO channels (1 DIO subdevice): |
35 | * |
36 | * PCI-7224, PCI-DIO24, PCI-DIO24H, PCI-6503, PCI-6503B, PCI-6503X, |
37 | * PXI-6503 |
38 | * |
39 | * Boards with 48 DIO channels (2 DIO subdevices): |
40 | * |
41 | * PCI-7248, PCI-DIO48H |
42 | * |
43 | * Boards with 96 DIO channels (4 DIO subdevices): |
44 | * |
45 | * PCI-7296, PCI-DIO96H, PCI-DIO-96, PCI-DIO-96B, PXI-6508 |
46 | * |
47 | * Some of these boards also have an 8254 programmable timer/counter |
48 | * chip. This chip is not currently supported by this driver. |
49 | * |
50 | * Interrupt support for these boards is also not currently supported. |
51 | * |
52 | * Configuration Options: not applicable, uses PCI auto config. |
53 | */ |
54 | |
55 | #include <linux/module.h> |
56 | #include <linux/comedi/comedi_pci.h> |
57 | #include <linux/comedi/comedi_8255.h> |
58 | |
59 | enum pci_8255_boardid { |
60 | #ifdef CONFIG_HAS_IOPORT |
61 | BOARD_ADLINK_PCI7224, |
62 | BOARD_ADLINK_PCI7248, |
63 | BOARD_ADLINK_PCI7296, |
64 | BOARD_CB_PCIDIO24, |
65 | BOARD_CB_PCIDIO24H, |
66 | BOARD_CB_PCIDIO48H_OLD, |
67 | BOARD_CB_PCIDIO48H_NEW, |
68 | BOARD_CB_PCIDIO96H, |
69 | #endif /* CONFIG_HAS_IOPORT */ |
70 | BOARD_NI_PCIDIO96, |
71 | BOARD_NI_PCIDIO96B, |
72 | BOARD_NI_PXI6508, |
73 | BOARD_NI_PCI6503, |
74 | BOARD_NI_PCI6503B, |
75 | BOARD_NI_PCI6503X, |
76 | BOARD_NI_PXI_6503, |
77 | }; |
78 | |
79 | struct pci_8255_boardinfo { |
80 | const char *name; |
81 | int dio_badr; |
82 | int n_8255; |
83 | unsigned int has_mite:1; |
84 | }; |
85 | |
86 | static const struct pci_8255_boardinfo pci_8255_boards[] = { |
87 | #ifdef CONFIG_HAS_IOPORT |
88 | [BOARD_ADLINK_PCI7224] = { |
89 | .name = "adl_pci-7224" , |
90 | .dio_badr = 2, |
91 | .n_8255 = 1, |
92 | }, |
93 | [BOARD_ADLINK_PCI7248] = { |
94 | .name = "adl_pci-7248" , |
95 | .dio_badr = 2, |
96 | .n_8255 = 2, |
97 | }, |
98 | [BOARD_ADLINK_PCI7296] = { |
99 | .name = "adl_pci-7296" , |
100 | .dio_badr = 2, |
101 | .n_8255 = 4, |
102 | }, |
103 | [BOARD_CB_PCIDIO24] = { |
104 | .name = "cb_pci-dio24" , |
105 | .dio_badr = 2, |
106 | .n_8255 = 1, |
107 | }, |
108 | [BOARD_CB_PCIDIO24H] = { |
109 | .name = "cb_pci-dio24h" , |
110 | .dio_badr = 2, |
111 | .n_8255 = 1, |
112 | }, |
113 | [BOARD_CB_PCIDIO48H_OLD] = { |
114 | .name = "cb_pci-dio48h" , |
115 | .dio_badr = 1, |
116 | .n_8255 = 2, |
117 | }, |
118 | [BOARD_CB_PCIDIO48H_NEW] = { |
119 | .name = "cb_pci-dio48h" , |
120 | .dio_badr = 2, |
121 | .n_8255 = 2, |
122 | }, |
123 | [BOARD_CB_PCIDIO96H] = { |
124 | .name = "cb_pci-dio96h" , |
125 | .dio_badr = 2, |
126 | .n_8255 = 4, |
127 | }, |
128 | #endif /* CONFIG_HAS_IOPORT */ |
129 | [BOARD_NI_PCIDIO96] = { |
130 | .name = "ni_pci-dio-96" , |
131 | .dio_badr = 1, |
132 | .n_8255 = 4, |
133 | .has_mite = 1, |
134 | }, |
135 | [BOARD_NI_PCIDIO96B] = { |
136 | .name = "ni_pci-dio-96b" , |
137 | .dio_badr = 1, |
138 | .n_8255 = 4, |
139 | .has_mite = 1, |
140 | }, |
141 | [BOARD_NI_PXI6508] = { |
142 | .name = "ni_pxi-6508" , |
143 | .dio_badr = 1, |
144 | .n_8255 = 4, |
145 | .has_mite = 1, |
146 | }, |
147 | [BOARD_NI_PCI6503] = { |
148 | .name = "ni_pci-6503" , |
149 | .dio_badr = 1, |
150 | .n_8255 = 1, |
151 | .has_mite = 1, |
152 | }, |
153 | [BOARD_NI_PCI6503B] = { |
154 | .name = "ni_pci-6503b" , |
155 | .dio_badr = 1, |
156 | .n_8255 = 1, |
157 | .has_mite = 1, |
158 | }, |
159 | [BOARD_NI_PCI6503X] = { |
160 | .name = "ni_pci-6503x" , |
161 | .dio_badr = 1, |
162 | .n_8255 = 1, |
163 | .has_mite = 1, |
164 | }, |
165 | [BOARD_NI_PXI_6503] = { |
166 | .name = "ni_pxi-6503" , |
167 | .dio_badr = 1, |
168 | .n_8255 = 1, |
169 | .has_mite = 1, |
170 | }, |
171 | }; |
172 | |
173 | /* ripped from mite.h and mite_setup2() to avoid mite dependency */ |
174 | #define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */ |
175 | #define WENAB BIT(7) /* window enable */ |
176 | |
177 | static int pci_8255_mite_init(struct pci_dev *pcidev) |
178 | { |
179 | void __iomem *mite_base; |
180 | u32 main_phys_addr; |
181 | |
182 | /* ioremap the MITE registers (BAR 0) temporarily */ |
183 | mite_base = pci_ioremap_bar(pdev: pcidev, bar: 0); |
184 | if (!mite_base) |
185 | return -ENOMEM; |
186 | |
187 | /* set data window to main registers (BAR 1) */ |
188 | main_phys_addr = pci_resource_start(pcidev, 1); |
189 | writel(val: main_phys_addr | WENAB, addr: mite_base + MITE_IODWBSR); |
190 | |
191 | /* finished with MITE registers */ |
192 | iounmap(addr: mite_base); |
193 | return 0; |
194 | } |
195 | |
196 | static int pci_8255_auto_attach(struct comedi_device *dev, |
197 | unsigned long context) |
198 | { |
199 | struct pci_dev *pcidev = comedi_to_pci_dev(dev); |
200 | const struct pci_8255_boardinfo *board = NULL; |
201 | struct comedi_subdevice *s; |
202 | int ret; |
203 | int i; |
204 | |
205 | if (context < ARRAY_SIZE(pci_8255_boards)) |
206 | board = &pci_8255_boards[context]; |
207 | if (!board) |
208 | return -ENODEV; |
209 | dev->board_ptr = board; |
210 | dev->board_name = board->name; |
211 | |
212 | ret = comedi_pci_enable(dev); |
213 | if (ret) |
214 | return ret; |
215 | |
216 | if (board->has_mite) { |
217 | ret = pci_8255_mite_init(pcidev); |
218 | if (ret) |
219 | return ret; |
220 | } |
221 | |
222 | if ((pci_resource_flags(pcidev, board->dio_badr) & IORESOURCE_MEM)) { |
223 | dev->mmio = pci_ioremap_bar(pdev: pcidev, bar: board->dio_badr); |
224 | if (!dev->mmio) |
225 | return -ENOMEM; |
226 | } else if (IS_ENABLED(CONFIG_HAS_IOPORT)) { |
227 | dev->iobase = pci_resource_start(pcidev, board->dio_badr); |
228 | } else { |
229 | dev_err(dev->class_dev, "error! need I/O port support\n" ); |
230 | return -ENXIO; |
231 | } |
232 | |
233 | /* |
234 | * One, two, or four subdevices are setup by this driver depending |
235 | * on the number of channels provided by the board. Each subdevice |
236 | * has 24 channels supported by the 8255 module. |
237 | */ |
238 | ret = comedi_alloc_subdevices(dev, num_subdevices: board->n_8255); |
239 | if (ret) |
240 | return ret; |
241 | |
242 | for (i = 0; i < board->n_8255; i++) { |
243 | s = &dev->subdevices[i]; |
244 | if (dev->mmio) |
245 | ret = subdev_8255_mm_init(dev, s, regbase: i * I8255_SIZE); |
246 | else |
247 | ret = subdev_8255_io_init(dev, s, regbase: i * I8255_SIZE); |
248 | if (ret) |
249 | return ret; |
250 | } |
251 | |
252 | return 0; |
253 | } |
254 | |
255 | static struct comedi_driver pci_8255_driver = { |
256 | .driver_name = "8255_pci" , |
257 | .module = THIS_MODULE, |
258 | .auto_attach = pci_8255_auto_attach, |
259 | .detach = comedi_pci_detach, |
260 | }; |
261 | |
262 | static int pci_8255_pci_probe(struct pci_dev *dev, |
263 | const struct pci_device_id *id) |
264 | { |
265 | return comedi_pci_auto_config(pcidev: dev, driver: &pci_8255_driver, context: id->driver_data); |
266 | } |
267 | |
268 | static const struct pci_device_id pci_8255_pci_table[] = { |
269 | #ifdef CONFIG_HAS_IOPORT |
270 | { PCI_VDEVICE(ADLINK, 0x7224), BOARD_ADLINK_PCI7224 }, |
271 | { PCI_VDEVICE(ADLINK, 0x7248), BOARD_ADLINK_PCI7248 }, |
272 | { PCI_VDEVICE(ADLINK, 0x7296), BOARD_ADLINK_PCI7296 }, |
273 | { PCI_VDEVICE(CB, 0x0028), BOARD_CB_PCIDIO24 }, |
274 | { PCI_VDEVICE(CB, 0x0014), BOARD_CB_PCIDIO24H }, |
275 | { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, 0x0000, 0x0000), |
276 | .driver_data = BOARD_CB_PCIDIO48H_OLD }, |
277 | { PCI_DEVICE_SUB(PCI_VENDOR_ID_CB, 0x000b, PCI_VENDOR_ID_CB, 0x000b), |
278 | .driver_data = BOARD_CB_PCIDIO48H_NEW }, |
279 | { PCI_VDEVICE(CB, 0x0017), BOARD_CB_PCIDIO96H }, |
280 | #endif /* CONFIG_HAS_IOPORT */ |
281 | { PCI_VDEVICE(NI, 0x0160), BOARD_NI_PCIDIO96 }, |
282 | { PCI_VDEVICE(NI, 0x1630), BOARD_NI_PCIDIO96B }, |
283 | { PCI_VDEVICE(NI, 0x13c0), BOARD_NI_PXI6508 }, |
284 | { PCI_VDEVICE(NI, 0x0400), BOARD_NI_PCI6503 }, |
285 | { PCI_VDEVICE(NI, 0x1250), BOARD_NI_PCI6503B }, |
286 | { PCI_VDEVICE(NI, 0x17d0), BOARD_NI_PCI6503X }, |
287 | { PCI_VDEVICE(NI, 0x1800), BOARD_NI_PXI_6503 }, |
288 | { 0 } |
289 | }; |
290 | MODULE_DEVICE_TABLE(pci, pci_8255_pci_table); |
291 | |
292 | static struct pci_driver pci_8255_pci_driver = { |
293 | .name = "8255_pci" , |
294 | .id_table = pci_8255_pci_table, |
295 | .probe = pci_8255_pci_probe, |
296 | .remove = comedi_pci_auto_unconfig, |
297 | }; |
298 | module_comedi_pci_driver(pci_8255_driver, pci_8255_pci_driver); |
299 | |
300 | MODULE_DESCRIPTION("COMEDI - Generic PCI based 8255 Digital I/O boards" ); |
301 | MODULE_AUTHOR("Comedi https://www.comedi.org" ); |
302 | MODULE_LICENSE("GPL" ); |
303 | |