Linux-libre 5.7.6-gnu
[librecmc/linux-libre.git] / drivers / staging / comedi / drivers / addi_apci_1032.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * addi_apci_1032.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 /*
17  * Driver: addi_apci_1032
18  * Description: ADDI-DATA APCI-1032 Digital Input Board
19  * Author: ADDI-DATA GmbH <info@addi-data.com>,
20  *   H Hartley Sweeten <hsweeten@visionengravers.com>
21  * Status: untested
22  * Devices: [ADDI-DATA] APCI-1032 (addi_apci_1032)
23  *
24  * Configuration options:
25  *   None; devices are configured automatically.
26  *
27  * This driver models the APCI-1032 as a 32-channel, digital input subdevice
28  * plus an additional digital input subdevice to handle change-of-state (COS)
29  * interrupts (if an interrupt handler can be set up successfully).
30  *
31  * The COS subdevice supports comedi asynchronous read commands.
32  *
33  * Change-Of-State (COS) interrupt configuration:
34  *
35  * Channels 0 to 15 are interruptible. These channels can be configured
36  * to generate interrupts based on AND/OR logic for the desired channels.
37  *
38  *   OR logic:
39  *   - reacts to rising or falling edges
40  *   - interrupt is generated when any enabled channel meets the desired
41  *     interrupt condition
42  *
43  *   AND logic:
44  *   - reacts to changes in level of the selected inputs
45  *   - interrupt is generated when all enabled channels meet the desired
46  *     interrupt condition
47  *   - after an interrupt, a change in level must occur on the selected
48  *     inputs to release the IRQ logic
49  *
50  * The COS subdevice must be configured before setting up a comedi
51  * asynchronous command:
52  *
53  *   data[0] : INSN_CONFIG_DIGITAL_TRIG
54  *   data[1] : trigger number (= 0)
55  *   data[2] : configuration operation:
56  *             - COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
57  *             - COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts
58  *             - COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts
59  *   data[3] : left-shift for data[4] and data[5]
60  *   data[4] : rising-edge/high level channels
61  *   data[5] : falling-edge/low level channels
62  */
63
64 #include <linux/module.h>
65 #include <linux/interrupt.h>
66
67 #include "../comedi_pci.h"
68 #include "amcc_s5933.h"
69
70 /*
71  * I/O Register Map
72  */
73 #define APCI1032_DI_REG                 0x00
74 #define APCI1032_MODE1_REG              0x04
75 #define APCI1032_MODE2_REG              0x08
76 #define APCI1032_STATUS_REG             0x0c
77 #define APCI1032_CTRL_REG               0x10
78 #define APCI1032_CTRL_INT_MODE(x)       (((x) & 0x1) << 1)
79 #define APCI1032_CTRL_INT_OR            APCI1032_CTRL_INT_MODE(0)
80 #define APCI1032_CTRL_INT_AND           APCI1032_CTRL_INT_MODE(1)
81 #define APCI1032_CTRL_INT_ENA           BIT(2)
82
83 struct apci1032_private {
84         unsigned long amcc_iobase;      /* base of AMCC I/O registers */
85         unsigned int mode1;     /* rising-edge/high level channels */
86         unsigned int mode2;     /* falling-edge/low level channels */
87         unsigned int ctrl;      /* interrupt mode OR (edge) . AND (level) */
88 };
89
90 static int apci1032_reset(struct comedi_device *dev)
91 {
92         /* disable the interrupts */
93         outl(0x0, dev->iobase + APCI1032_CTRL_REG);
94         /* Reset the interrupt status register */
95         inl(dev->iobase + APCI1032_STATUS_REG);
96         /* Disable the and/or interrupt */
97         outl(0x0, dev->iobase + APCI1032_MODE1_REG);
98         outl(0x0, dev->iobase + APCI1032_MODE2_REG);
99
100         return 0;
101 }
102
103 static int apci1032_cos_insn_config(struct comedi_device *dev,
104                                     struct comedi_subdevice *s,
105                                     struct comedi_insn *insn,
106                                     unsigned int *data)
107 {
108         struct apci1032_private *devpriv = dev->private;
109         unsigned int shift, oldmask;
110
111         switch (data[0]) {
112         case INSN_CONFIG_DIGITAL_TRIG:
113                 if (data[1] != 0)
114                         return -EINVAL;
115                 shift = data[3];
116                 oldmask = (1U << shift) - 1;
117                 switch (data[2]) {
118                 case COMEDI_DIGITAL_TRIG_DISABLE:
119                         devpriv->ctrl = 0;
120                         devpriv->mode1 = 0;
121                         devpriv->mode2 = 0;
122                         apci1032_reset(dev);
123                         break;
124                 case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
125                         if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA |
126                                               APCI1032_CTRL_INT_OR)) {
127                                 /* switching to 'OR' mode */
128                                 devpriv->ctrl = APCI1032_CTRL_INT_ENA |
129                                                 APCI1032_CTRL_INT_OR;
130                                 /* wipe old channels */
131                                 devpriv->mode1 = 0;
132                                 devpriv->mode2 = 0;
133                         } else {
134                                 /* preserve unspecified channels */
135                                 devpriv->mode1 &= oldmask;
136                                 devpriv->mode2 &= oldmask;
137                         }
138                         /* configure specified channels */
139                         devpriv->mode1 |= data[4] << shift;
140                         devpriv->mode2 |= data[5] << shift;
141                         break;
142                 case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
143                         if (devpriv->ctrl != (APCI1032_CTRL_INT_ENA |
144                                               APCI1032_CTRL_INT_AND)) {
145                                 /* switching to 'AND' mode */
146                                 devpriv->ctrl = APCI1032_CTRL_INT_ENA |
147                                                 APCI1032_CTRL_INT_AND;
148                                 /* wipe old channels */
149                                 devpriv->mode1 = 0;
150                                 devpriv->mode2 = 0;
151                         } else {
152                                 /* preserve unspecified channels */
153                                 devpriv->mode1 &= oldmask;
154                                 devpriv->mode2 &= oldmask;
155                         }
156                         /* configure specified channels */
157                         devpriv->mode1 |= data[4] << shift;
158                         devpriv->mode2 |= data[5] << shift;
159                         break;
160                 default:
161                         return -EINVAL;
162                 }
163                 break;
164         default:
165                 return -EINVAL;
166         }
167
168         return insn->n;
169 }
170
171 static int apci1032_cos_insn_bits(struct comedi_device *dev,
172                                   struct comedi_subdevice *s,
173                                   struct comedi_insn *insn,
174                                   unsigned int *data)
175 {
176         data[1] = s->state;
177
178         return 0;
179 }
180
181 static int apci1032_cos_cmdtest(struct comedi_device *dev,
182                                 struct comedi_subdevice *s,
183                                 struct comedi_cmd *cmd)
184 {
185         int err = 0;
186
187         /* Step 1 : check if triggers are trivially valid */
188
189         err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW);
190         err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
191         err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
192         err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
193         err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_NONE);
194
195         if (err)
196                 return 1;
197
198         /* Step 2a : make sure trigger sources are unique */
199         /* Step 2b : and mutually compatible */
200
201         /* Step 3: check if arguments are trivially valid */
202
203         err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0);
204         err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
205         err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0);
206         err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg,
207                                            cmd->chanlist_len);
208         err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0);
209
210         if (err)
211                 return 3;
212
213         /* Step 4: fix up any arguments */
214
215         /* Step 5: check channel list if it exists */
216
217         return 0;
218 }
219
220 /*
221  * Change-Of-State (COS) 'do_cmd' operation
222  *
223  * Enable the COS interrupt as configured by apci1032_cos_insn_config().
224  */
225 static int apci1032_cos_cmd(struct comedi_device *dev,
226                             struct comedi_subdevice *s)
227 {
228         struct apci1032_private *devpriv = dev->private;
229
230         if (!devpriv->ctrl) {
231                 dev_warn(dev->class_dev,
232                          "Interrupts disabled due to mode configuration!\n");
233                 return -EINVAL;
234         }
235
236         outl(devpriv->mode1, dev->iobase + APCI1032_MODE1_REG);
237         outl(devpriv->mode2, dev->iobase + APCI1032_MODE2_REG);
238         outl(devpriv->ctrl, dev->iobase + APCI1032_CTRL_REG);
239
240         return 0;
241 }
242
243 static int apci1032_cos_cancel(struct comedi_device *dev,
244                                struct comedi_subdevice *s)
245 {
246         return apci1032_reset(dev);
247 }
248
249 static irqreturn_t apci1032_interrupt(int irq, void *d)
250 {
251         struct comedi_device *dev = d;
252         struct apci1032_private *devpriv = dev->private;
253         struct comedi_subdevice *s = dev->read_subdev;
254         unsigned int ctrl;
255
256         /* check interrupt is from this device */
257         if ((inl(devpriv->amcc_iobase + AMCC_OP_REG_INTCSR) &
258              INTCSR_INTR_ASSERTED) == 0)
259                 return IRQ_NONE;
260
261         /* check interrupt is enabled */
262         ctrl = inl(dev->iobase + APCI1032_CTRL_REG);
263         if ((ctrl & APCI1032_CTRL_INT_ENA) == 0)
264                 return IRQ_HANDLED;
265
266         /* disable the interrupt */
267         outl(ctrl & ~APCI1032_CTRL_INT_ENA, dev->iobase + APCI1032_CTRL_REG);
268
269         s->state = inl(dev->iobase + APCI1032_STATUS_REG) & 0xffff;
270         comedi_buf_write_samples(s, &s->state, 1);
271         comedi_handle_events(dev, s);
272
273         /* enable the interrupt */
274         outl(ctrl, dev->iobase + APCI1032_CTRL_REG);
275
276         return IRQ_HANDLED;
277 }
278
279 static int apci1032_di_insn_bits(struct comedi_device *dev,
280                                  struct comedi_subdevice *s,
281                                  struct comedi_insn *insn,
282                                  unsigned int *data)
283 {
284         data[1] = inl(dev->iobase + APCI1032_DI_REG);
285
286         return insn->n;
287 }
288
289 static int apci1032_auto_attach(struct comedi_device *dev,
290                                 unsigned long context_unused)
291 {
292         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
293         struct apci1032_private *devpriv;
294         struct comedi_subdevice *s;
295         int ret;
296
297         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
298         if (!devpriv)
299                 return -ENOMEM;
300
301         ret = comedi_pci_enable(dev);
302         if (ret)
303                 return ret;
304
305         devpriv->amcc_iobase = pci_resource_start(pcidev, 0);
306         dev->iobase = pci_resource_start(pcidev, 1);
307         apci1032_reset(dev);
308         if (pcidev->irq > 0) {
309                 ret = request_irq(pcidev->irq, apci1032_interrupt, IRQF_SHARED,
310                                   dev->board_name, dev);
311                 if (ret == 0)
312                         dev->irq = pcidev->irq;
313         }
314
315         ret = comedi_alloc_subdevices(dev, 2);
316         if (ret)
317                 return ret;
318
319         /*  Allocate and Initialise DI Subdevice Structures */
320         s = &dev->subdevices[0];
321         s->type         = COMEDI_SUBD_DI;
322         s->subdev_flags = SDF_READABLE;
323         s->n_chan       = 32;
324         s->maxdata      = 1;
325         s->range_table  = &range_digital;
326         s->insn_bits    = apci1032_di_insn_bits;
327
328         /* Change-Of-State (COS) interrupt subdevice */
329         s = &dev->subdevices[1];
330         if (dev->irq) {
331                 dev->read_subdev = s;
332                 s->type         = COMEDI_SUBD_DI;
333                 s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
334                 s->n_chan       = 1;
335                 s->maxdata      = 1;
336                 s->range_table  = &range_digital;
337                 s->insn_config  = apci1032_cos_insn_config;
338                 s->insn_bits    = apci1032_cos_insn_bits;
339                 s->len_chanlist = 1;
340                 s->do_cmdtest   = apci1032_cos_cmdtest;
341                 s->do_cmd       = apci1032_cos_cmd;
342                 s->cancel       = apci1032_cos_cancel;
343         } else {
344                 s->type         = COMEDI_SUBD_UNUSED;
345         }
346
347         return 0;
348 }
349
350 static void apci1032_detach(struct comedi_device *dev)
351 {
352         if (dev->iobase)
353                 apci1032_reset(dev);
354         comedi_pci_detach(dev);
355 }
356
357 static struct comedi_driver apci1032_driver = {
358         .driver_name    = "addi_apci_1032",
359         .module         = THIS_MODULE,
360         .auto_attach    = apci1032_auto_attach,
361         .detach         = apci1032_detach,
362 };
363
364 static int apci1032_pci_probe(struct pci_dev *dev,
365                               const struct pci_device_id *id)
366 {
367         return comedi_pci_auto_config(dev, &apci1032_driver, id->driver_data);
368 }
369
370 static const struct pci_device_id apci1032_pci_table[] = {
371         { PCI_DEVICE(PCI_VENDOR_ID_ADDIDATA, 0x1003) },
372         { 0 }
373 };
374 MODULE_DEVICE_TABLE(pci, apci1032_pci_table);
375
376 static struct pci_driver apci1032_pci_driver = {
377         .name           = "addi_apci_1032",
378         .id_table       = apci1032_pci_table,
379         .probe          = apci1032_pci_probe,
380         .remove         = comedi_pci_auto_unconfig,
381 };
382 module_comedi_pci_driver(apci1032_driver, apci1032_pci_driver);
383
384 MODULE_AUTHOR("Comedi http://www.comedi.org");
385 MODULE_DESCRIPTION("ADDI-DATA APCI-1032, 32 channel DI boards");
386 MODULE_LICENSE("GPL");