]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/comedi/drivers/ni_6527.c
Merge branch 'next' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[karo-tx-linux.git] / drivers / staging / comedi / drivers / ni_6527.c
1 /*
2     comedi/drivers/ni_6527.c
3     driver for National Instruments PCI-6527
4
5     COMEDI - Linux Control and Measurement Device Interface
6     Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.org>
7
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 */
18 /*
19 Driver: ni_6527
20 Description: National Instruments 6527
21 Author: ds
22 Status: works
23 Devices: [National Instruments] PCI-6527 (ni6527), PXI-6527
24 Updated: Sat, 25 Jan 2003 13:24:40 -0800
25
26
27 */
28
29 /*
30    Manuals (available from ftp://ftp.natinst.com/support/manuals)
31
32         370106b.pdf     6527 Register Level Programmer Manual
33
34  */
35
36 #define DEBUG 1
37 #define DEBUG_FLAGS
38
39 #include <linux/module.h>
40 #include <linux/pci.h>
41 #include <linux/interrupt.h>
42
43 #include "../comedidev.h"
44
45 #include "comedi_fc.h"
46 #include "mite.h"
47
48 #define DRIVER_NAME "ni_6527"
49
50 #define NI6527_DIO_SIZE 4096
51 #define NI6527_MITE_SIZE 4096
52
53 #define Port_Register(x)                        (0x00+(x))
54 #define ID_Register                             0x06
55
56 #define Clear_Register                          0x07
57 #define ClrEdge                         0x08
58 #define ClrOverflow                     0x04
59 #define ClrFilter                       0x02
60 #define ClrInterval                     0x01
61
62 #define Filter_Interval(x)                      (0x08+(x))
63 #define Filter_Enable(x)                        (0x0c+(x))
64
65 #define Change_Status                           0x14
66 #define MasterInterruptStatus           0x04
67 #define Overflow                        0x02
68 #define EdgeStatus                      0x01
69
70 #define Master_Interrupt_Control                0x15
71 #define FallingEdgeIntEnable            0x10
72 #define RisingEdgeIntEnable             0x08
73 #define MasterInterruptEnable           0x04
74 #define OverflowIntEnable               0x02
75 #define EdgeIntEnable                   0x01
76
77 #define Rising_Edge_Detection_Enable(x)         (0x018+(x))
78 #define Falling_Edge_Detection_Enable(x)        (0x020+(x))
79
80 enum ni6527_boardid {
81         BOARD_PCI6527,
82         BOARD_PXI6527,
83 };
84
85 struct ni6527_board {
86         const char *name;
87 };
88
89 static const struct ni6527_board ni6527_boards[] = {
90         [BOARD_PCI6527] = {
91                 .name           = "pci-6527",
92         },
93         [BOARD_PXI6527] = {
94                 .name           = "pxi-6527",
95         },
96 };
97
98 struct ni6527_private {
99         struct mite_struct *mite;
100         unsigned int filter_interval;
101         unsigned int filter_enable;
102 };
103
104 static int ni6527_di_insn_config(struct comedi_device *dev,
105                                  struct comedi_subdevice *s,
106                                  struct comedi_insn *insn, unsigned int *data)
107 {
108         struct ni6527_private *devpriv = dev->private;
109         int chan = CR_CHAN(insn->chanspec);
110         unsigned int interval;
111
112         if (insn->n != 2)
113                 return -EINVAL;
114
115         if (data[0] != INSN_CONFIG_FILTER)
116                 return -EINVAL;
117
118         if (data[1]) {
119                 interval = (data[1] + 100) / 200;
120                 data[1] = interval * 200;
121
122                 if (interval != devpriv->filter_interval) {
123                         writeb(interval & 0xff,
124                                devpriv->mite->daq_io_addr + Filter_Interval(0));
125                         writeb((interval >> 8) & 0xff,
126                                devpriv->mite->daq_io_addr + Filter_Interval(1));
127                         writeb((interval >> 16) & 0x0f,
128                                devpriv->mite->daq_io_addr + Filter_Interval(2));
129
130                         writeb(ClrInterval,
131                                devpriv->mite->daq_io_addr + Clear_Register);
132
133                         devpriv->filter_interval = interval;
134                 }
135
136                 devpriv->filter_enable |= 1 << chan;
137         } else {
138                 devpriv->filter_enable &= ~(1 << chan);
139         }
140
141         writeb(devpriv->filter_enable,
142                devpriv->mite->daq_io_addr + Filter_Enable(0));
143         writeb(devpriv->filter_enable >> 8,
144                devpriv->mite->daq_io_addr + Filter_Enable(1));
145         writeb(devpriv->filter_enable >> 16,
146                devpriv->mite->daq_io_addr + Filter_Enable(2));
147
148         return 2;
149 }
150
151 static int ni6527_di_insn_bits(struct comedi_device *dev,
152                                struct comedi_subdevice *s,
153                                struct comedi_insn *insn, unsigned int *data)
154 {
155         struct ni6527_private *devpriv = dev->private;
156
157         data[1] = readb(devpriv->mite->daq_io_addr + Port_Register(0));
158         data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(1)) << 8;
159         data[1] |= readb(devpriv->mite->daq_io_addr + Port_Register(2)) << 16;
160
161         return insn->n;
162 }
163
164 static int ni6527_do_insn_bits(struct comedi_device *dev,
165                                struct comedi_subdevice *s,
166                                struct comedi_insn *insn, unsigned int *data)
167 {
168         struct ni6527_private *devpriv = dev->private;
169
170         if (data[0]) {
171                 s->state &= ~data[0];
172                 s->state |= (data[0] & data[1]);
173
174                 /* The open relay state on the board cooresponds to 1,
175                  * but in Comedi, it is represented by 0. */
176                 if (data[0] & 0x0000ff) {
177                         writeb((s->state ^ 0xff),
178                                devpriv->mite->daq_io_addr + Port_Register(3));
179                 }
180                 if (data[0] & 0x00ff00) {
181                         writeb((s->state >> 8) ^ 0xff,
182                                devpriv->mite->daq_io_addr + Port_Register(4));
183                 }
184                 if (data[0] & 0xff0000) {
185                         writeb((s->state >> 16) ^ 0xff,
186                                devpriv->mite->daq_io_addr + Port_Register(5));
187                 }
188         }
189         data[1] = s->state;
190
191         return insn->n;
192 }
193
194 static irqreturn_t ni6527_interrupt(int irq, void *d)
195 {
196         struct comedi_device *dev = d;
197         struct ni6527_private *devpriv = dev->private;
198         struct comedi_subdevice *s = &dev->subdevices[2];
199         unsigned int status;
200
201         status = readb(devpriv->mite->daq_io_addr + Change_Status);
202         if ((status & MasterInterruptStatus) == 0)
203                 return IRQ_NONE;
204         if ((status & EdgeStatus) == 0)
205                 return IRQ_NONE;
206
207         writeb(ClrEdge | ClrOverflow,
208                devpriv->mite->daq_io_addr + Clear_Register);
209
210         comedi_buf_put(s->async, 0);
211         s->async->events |= COMEDI_CB_EOS;
212         comedi_event(dev, s);
213         return IRQ_HANDLED;
214 }
215
216 static int ni6527_intr_cmdtest(struct comedi_device *dev,
217                                struct comedi_subdevice *s,
218                                struct comedi_cmd *cmd)
219 {
220         int err = 0;
221
222         /* Step 1 : check if triggers are trivially valid */
223
224         err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
225         err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER);
226         err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
227         err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
228         err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT);
229
230         if (err)
231                 return 1;
232
233         /* Step 2a : make sure trigger sources are unique */
234         /* Step 2b : and mutually compatible */
235
236         if (err)
237                 return 2;
238
239         /* Step 3: check if arguments are trivially valid */
240
241         err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
242         err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
243         err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
244         err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, 1);
245         err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
246
247         if (err)
248                 return 3;
249
250         /* step 4: fix up any arguments */
251
252         if (err)
253                 return 4;
254
255         return 0;
256 }
257
258 static int ni6527_intr_cmd(struct comedi_device *dev,
259                            struct comedi_subdevice *s)
260 {
261         struct ni6527_private *devpriv = dev->private;
262         /* struct comedi_cmd *cmd = &s->async->cmd; */
263
264         writeb(ClrEdge | ClrOverflow,
265                devpriv->mite->daq_io_addr + Clear_Register);
266         writeb(FallingEdgeIntEnable | RisingEdgeIntEnable |
267                MasterInterruptEnable | EdgeIntEnable,
268                devpriv->mite->daq_io_addr + Master_Interrupt_Control);
269
270         return 0;
271 }
272
273 static int ni6527_intr_cancel(struct comedi_device *dev,
274                               struct comedi_subdevice *s)
275 {
276         struct ni6527_private *devpriv = dev->private;
277
278         writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
279
280         return 0;
281 }
282
283 static int ni6527_intr_insn_bits(struct comedi_device *dev,
284                                  struct comedi_subdevice *s,
285                                  struct comedi_insn *insn, unsigned int *data)
286 {
287         data[1] = 0;
288         return insn->n;
289 }
290
291 static int ni6527_intr_insn_config(struct comedi_device *dev,
292                                    struct comedi_subdevice *s,
293                                    struct comedi_insn *insn, unsigned int *data)
294 {
295         struct ni6527_private *devpriv = dev->private;
296
297         if (insn->n < 1)
298                 return -EINVAL;
299         if (data[0] != INSN_CONFIG_CHANGE_NOTIFY)
300                 return -EINVAL;
301
302         writeb(data[1],
303                devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(0));
304         writeb(data[1] >> 8,
305                devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(1));
306         writeb(data[1] >> 16,
307                devpriv->mite->daq_io_addr + Rising_Edge_Detection_Enable(2));
308
309         writeb(data[2],
310                devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(0));
311         writeb(data[2] >> 8,
312                devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(1));
313         writeb(data[2] >> 16,
314                devpriv->mite->daq_io_addr + Falling_Edge_Detection_Enable(2));
315
316         return 2;
317 }
318
319 static int ni6527_auto_attach(struct comedi_device *dev,
320                               unsigned long context)
321 {
322         struct pci_dev *pcidev = comedi_to_pci_dev(dev);
323         const struct ni6527_board *board = NULL;
324         struct ni6527_private *devpriv;
325         struct comedi_subdevice *s;
326         int ret;
327
328         if (context < ARRAY_SIZE(ni6527_boards))
329                 board = &ni6527_boards[context];
330         if (!board)
331                 return -ENODEV;
332         dev->board_ptr = board;
333         dev->board_name = board->name;
334
335         ret = comedi_pci_enable(dev);
336         if (ret)
337                 return ret;
338
339         devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
340         if (!devpriv)
341                 return -ENOMEM;
342
343         devpriv->mite = mite_alloc(pcidev);
344         if (!devpriv->mite)
345                 return -ENOMEM;
346
347         ret = mite_setup(devpriv->mite);
348         if (ret < 0) {
349                 dev_err(dev->class_dev, "error setting up mite\n");
350                 return ret;
351         }
352
353         dev_info(dev->class_dev, "board: %s, ID=0x%02x\n", dev->board_name,
354                  readb(devpriv->mite->daq_io_addr + ID_Register));
355
356         ret = comedi_alloc_subdevices(dev, 3);
357         if (ret)
358                 return ret;
359
360         s = &dev->subdevices[0];
361         s->type = COMEDI_SUBD_DI;
362         s->subdev_flags = SDF_READABLE;
363         s->n_chan = 24;
364         s->range_table = &range_digital;
365         s->maxdata = 1;
366         s->insn_config = ni6527_di_insn_config;
367         s->insn_bits = ni6527_di_insn_bits;
368
369         s = &dev->subdevices[1];
370         s->type = COMEDI_SUBD_DO;
371         s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
372         s->n_chan = 24;
373         s->range_table = &range_unknown;  /* FIXME: actually conductance */
374         s->maxdata = 1;
375         s->insn_bits = ni6527_do_insn_bits;
376
377         s = &dev->subdevices[2];
378         dev->read_subdev = s;
379         s->type = COMEDI_SUBD_DI;
380         s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
381         s->n_chan = 1;
382         s->range_table = &range_unknown;
383         s->maxdata = 1;
384         s->do_cmdtest = ni6527_intr_cmdtest;
385         s->do_cmd = ni6527_intr_cmd;
386         s->cancel = ni6527_intr_cancel;
387         s->insn_bits = ni6527_intr_insn_bits;
388         s->insn_config = ni6527_intr_insn_config;
389
390         writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(0));
391         writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(1));
392         writeb(0x00, devpriv->mite->daq_io_addr + Filter_Enable(2));
393
394         writeb(ClrEdge | ClrOverflow | ClrFilter | ClrInterval,
395                devpriv->mite->daq_io_addr + Clear_Register);
396         writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control);
397
398         ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt,
399                           IRQF_SHARED, DRIVER_NAME, dev);
400         if (ret < 0)
401                 dev_warn(dev->class_dev, "irq not available\n");
402         else
403                 dev->irq = mite_irq(devpriv->mite);
404
405         return 0;
406 }
407
408 static void ni6527_detach(struct comedi_device *dev)
409 {
410         struct ni6527_private *devpriv = dev->private;
411
412         if (devpriv && devpriv->mite && devpriv->mite->daq_io_addr)
413                 writeb(0x00,
414                        devpriv->mite->daq_io_addr + Master_Interrupt_Control);
415         if (dev->irq)
416                 free_irq(dev->irq, dev);
417         if (devpriv && devpriv->mite) {
418                 mite_unsetup(devpriv->mite);
419                 mite_free(devpriv->mite);
420         }
421         comedi_pci_disable(dev);
422 }
423
424 static struct comedi_driver ni6527_driver = {
425         .driver_name = DRIVER_NAME,
426         .module = THIS_MODULE,
427         .auto_attach = ni6527_auto_attach,
428         .detach = ni6527_detach,
429 };
430
431 static int ni6527_pci_probe(struct pci_dev *dev,
432                             const struct pci_device_id *id)
433 {
434         return comedi_pci_auto_config(dev, &ni6527_driver, id->driver_data);
435 }
436
437 static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = {
438         { PCI_VDEVICE(NI, 0x2b10), BOARD_PXI6527 },
439         { PCI_VDEVICE(NI, 0x2b20), BOARD_PCI6527 },
440         { 0 }
441 };
442 MODULE_DEVICE_TABLE(pci, ni6527_pci_table);
443
444 static struct pci_driver ni6527_pci_driver = {
445         .name           = DRIVER_NAME,
446         .id_table       = ni6527_pci_table,
447         .probe          = ni6527_pci_probe,
448         .remove         = comedi_pci_auto_unconfig,
449 };
450 module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver);
451
452 MODULE_AUTHOR("Comedi http://www.comedi.org");
453 MODULE_DESCRIPTION("Comedi low-level driver");
454 MODULE_LICENSE("GPL");