Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mason/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / staging / comedi / drivers / adl_pci8164.c
index d06b83f38653ba3a981559c98977be386acc027b..b3ec60afe3a040f9b55fa6667e2a870e5f0a0108 100644 (file)
 /*
-    comedi/drivers/adl_pci8164.c
-
-    Hardware comedi driver fot PCI-8164 Adlink card
-    Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program; if not, write to the Free Software
-    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * comedi/drivers/adl_pci8164.c
+ *
+ * Hardware comedi driver for PCI-8164 Adlink card
+ * Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
-*/
 /*
-Driver: adl_pci8164
-Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
-Devices: [ADLink] PCI-8164 (adl_pci8164)
-Author: Michel Lachaine <mike@mikelachaine.ca>
-Status: experimental
-Updated: Mon, 14 Apr 2008 15:10:32 +0100
-
-Configuration Options: not applicable, uses PCI auto config
-*/
+ * Driver: adl_pci8164
+ * Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
+ * Devices: (ADLink) PCI-8164 [adl_pci8164]
+ * Author: Michel Lachaine <mike@mikelachaine.ca>
+ * Status: experimental
+ * Updated: Mon, 14 Apr 2008 15:10:32 +0100
+ *
+ * Configuration Options: not applicable, uses PCI auto config
+ */
 
 #include <linux/kernel.h>
 #include <linux/pci.h>
-#include <linux/delay.h>
 
 #include "../comedidev.h"
-#include "comedi_fc.h"
-#include "8253.h"
-
-#define PCI8164_AXIS_X  0x00
-#define PCI8164_AXIS_Y  0x08
-#define PCI8164_AXIS_Z  0x10
-#define PCI8164_AXIS_U  0x18
 
-#define PCI8164_MSTS   0x00
-#define PCI8164_SSTS    0x02
-#define PCI8164_BUF0    0x04
-#define PCI8164_BUF1    0x06
-
-#define PCI8164_CMD     0x00
-#define PCI8164_OTP     0x02
-
-#define PCI_DEVICE_ID_PCI8164 0x8164
-
-/*
- all the read commands are the same except for the addition a constant
- * const to the data for inw()
- */
-static void adl_pci8164_insn_read(struct comedi_device *dev,
-                                 struct comedi_subdevice *s,
-                                 struct comedi_insn *insn,
-                                 unsigned int *data,
-                                 char *action, unsigned short offset)
-{
-       int axis, axis_reg;
-       char axisname;
-
-       axis = CR_CHAN(insn->chanspec);
-
-       switch (axis) {
-       case 0:
-               axis_reg = PCI8164_AXIS_X;
-               axisname = 'X';
-               break;
-       case 1:
-               axis_reg = PCI8164_AXIS_Y;
-               axisname = 'Y';
-               break;
-       case 2:
-               axis_reg = PCI8164_AXIS_Z;
-               axisname = 'Z';
-               break;
-       case 3:
-               axis_reg = PCI8164_AXIS_U;
-               axisname = 'U';
-               break;
-       default:
-               axis_reg = PCI8164_AXIS_X;
-               axisname = 'X';
-       }
-
-       data[0] = inw(dev->iobase + axis_reg + offset);
-       dev_dbg(dev->class_dev,
-               "pci8164 %s read -> %04X:%04X on axis %c\n",
-               action, data[0], data[1], axisname);
-}
-
-static int adl_pci8164_insn_read_msts(struct comedi_device *dev,
-                                     struct comedi_subdevice *s,
-                                     struct comedi_insn *insn,
-                                     unsigned int *data)
-{
-       adl_pci8164_insn_read(dev, s, insn, data, "MSTS", PCI8164_MSTS);
-       return 2;
-}
-
-static int adl_pci8164_insn_read_ssts(struct comedi_device *dev,
-                                     struct comedi_subdevice *s,
-                                     struct comedi_insn *insn,
-                                     unsigned int *data)
-{
-       adl_pci8164_insn_read(dev, s, insn, data, "SSTS", PCI8164_SSTS);
-       return 2;
-}
-
-static int adl_pci8164_insn_read_buf0(struct comedi_device *dev,
-                                     struct comedi_subdevice *s,
-                                     struct comedi_insn *insn,
-                                     unsigned int *data)
-{
-       adl_pci8164_insn_read(dev, s, insn, data, "BUF0", PCI8164_BUF0);
-       return 2;
-}
+#define PCI8164_AXIS(x)                ((x) * 0x08)
+#define PCI8164_CMD_MSTS_REG   0x00
+#define PCI8164_OTP_SSTS_REG   0x02
+#define PCI8164_BUF0_REG       0x04
+#define PCI8164_BUF1_REG       0x06
 
-static int adl_pci8164_insn_read_buf1(struct comedi_device *dev,
-                                     struct comedi_subdevice *s,
-                                     struct comedi_insn *insn,
-                                     unsigned int *data)
-{
-       adl_pci8164_insn_read(dev, s, insn, data, "BUF1", PCI8164_BUF1);
-       return 2;
-}
-
-/*
- all the write commands are the same except for the addition a constant
- * const to the data for outw()
- */
-static void adl_pci8164_insn_out(struct comedi_device *dev,
+static int adl_pci8164_insn_read(struct comedi_device *dev,
                                 struct comedi_subdevice *s,
                                 struct comedi_insn *insn,
-                                unsigned int *data,
-                                char *action, unsigned short offset)
+                                unsigned int *data)
 {
-       unsigned int axis, axis_reg;
-
-       char axisname;
-
-       axis = CR_CHAN(insn->chanspec);
+       unsigned long offset = (unsigned long)s->private;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       int i;
 
-       switch (axis) {
-       case 0:
-               axis_reg = PCI8164_AXIS_X;
-               axisname = 'X';
-               break;
-       case 1:
-               axis_reg = PCI8164_AXIS_Y;
-               axisname = 'Y';
-               break;
-       case 2:
-               axis_reg = PCI8164_AXIS_Z;
-               axisname = 'Z';
-               break;
-       case 3:
-               axis_reg = PCI8164_AXIS_U;
-               axisname = 'U';
-               break;
-       default:
-               axis_reg = PCI8164_AXIS_X;
-               axisname = 'X';
-       }
-
-       outw(data[0], dev->iobase + axis_reg + offset);
-
-       dev_dbg(dev->class_dev,
-               "pci8164 %s write -> %04X:%04X on axis %c\n",
-               action, data[0], data[1], axisname);
+       for (i = 0; i < insn->n; i++)
+               data[i] = inw(dev->iobase + PCI8164_AXIS(chan) + offset);
 
+       return insn->n;
 }
 
-static int adl_pci8164_insn_write_cmd(struct comedi_device *dev,
-                                     struct comedi_subdevice *s,
-                                     struct comedi_insn *insn,
-                                     unsigned int *data)
-{
-       adl_pci8164_insn_out(dev, s, insn, data, "CMD", PCI8164_CMD);
-       return 2;
-}
-
-static int adl_pci8164_insn_write_otp(struct comedi_device *dev,
-                                     struct comedi_subdevice *s,
-                                     struct comedi_insn *insn,
-                                     unsigned int *data)
+static int adl_pci8164_insn_write(struct comedi_device *dev,
+                                 struct comedi_subdevice *s,
+                                 struct comedi_insn *insn,
+                                 unsigned int *data)
 {
-       adl_pci8164_insn_out(dev, s, insn, data, "OTP", PCI8164_OTP);
-       return 2;
-}
+       unsigned long offset = (unsigned long)s->private;
+       unsigned int chan = CR_CHAN(insn->chanspec);
+       int i;
 
-static int adl_pci8164_insn_write_buf0(struct comedi_device *dev,
-                                      struct comedi_subdevice *s,
-                                      struct comedi_insn *insn,
-                                      unsigned int *data)
-{
-       adl_pci8164_insn_out(dev, s, insn, data, "BUF0", PCI8164_BUF0);
-       return 2;
-}
+       for (i = 0; i < insn->n; i++)
+               outw(data[i], dev->iobase + PCI8164_AXIS(chan) + offset);
 
-static int adl_pci8164_insn_write_buf1(struct comedi_device *dev,
-                                      struct comedi_subdevice *s,
-                                      struct comedi_insn *insn,
-                                      unsigned int *data)
-{
-       adl_pci8164_insn_out(dev, s, insn, data, "BUF1", PCI8164_BUF1);
-       return 2;
+       return insn->n;
 }
 
 static int adl_pci8164_auto_attach(struct comedi_device *dev,
@@ -221,9 +78,7 @@ static int adl_pci8164_auto_attach(struct comedi_device *dev,
        struct comedi_subdevice *s;
        int ret;
 
-       dev->board_name = dev->driver->driver_name;
-
-       ret = comedi_pci_enable(pcidev, dev->board_name);
+       ret = comedi_pci_enable(dev);
        if (ret)
                return ret;
        dev->iobase = pci_resource_start(pcidev, 2);
@@ -232,77 +87,70 @@ static int adl_pci8164_auto_attach(struct comedi_device *dev,
        if (ret)
                return ret;
 
+       /* read MSTS register / write CMD register for each axis (channel) */
        s = &dev->subdevices[0];
-       s->type = COMEDI_SUBD_PROC;
-       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-       s->n_chan = 4;
-       s->maxdata = 0xffff;
-       s->len_chanlist = 4;
-       /* s->range_table = &range_axis; */
-       s->insn_read = adl_pci8164_insn_read_msts;
-       s->insn_write = adl_pci8164_insn_write_cmd;
-
+       s->type         = COMEDI_SUBD_PROC;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+       s->n_chan       = 4;
+       s->maxdata      = 0xffff;
+       s->len_chanlist = 4;
+       s->insn_read    = adl_pci8164_insn_read;
+       s->insn_write   = adl_pci8164_insn_write;
+       s->private      = (void *)PCI8164_CMD_MSTS_REG;
+
+       /* read SSTS register / write OTP register for each axis (channel) */
        s = &dev->subdevices[1];
-       s->type = COMEDI_SUBD_PROC;
-       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-       s->n_chan = 4;
-       s->maxdata = 0xffff;
-       s->len_chanlist = 4;
-       /* s->range_table = &range_axis; */
-       s->insn_read = adl_pci8164_insn_read_ssts;
-       s->insn_write = adl_pci8164_insn_write_otp;
-
+       s->type         = COMEDI_SUBD_PROC;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+       s->n_chan       = 4;
+       s->maxdata      = 0xffff;
+       s->len_chanlist = 4;
+       s->insn_read    = adl_pci8164_insn_read;
+       s->insn_write   = adl_pci8164_insn_write;
+       s->private      = (void *)PCI8164_OTP_SSTS_REG;
+
+       /* read/write BUF0 register for each axis (channel) */
        s = &dev->subdevices[2];
-       s->type = COMEDI_SUBD_PROC;
-       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-       s->n_chan = 4;
-       s->maxdata = 0xffff;
-       s->len_chanlist = 4;
-       /* s->range_table = &range_axis; */
-       s->insn_read = adl_pci8164_insn_read_buf0;
-       s->insn_write = adl_pci8164_insn_write_buf0;
-
+       s->type         = COMEDI_SUBD_PROC;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+       s->n_chan       = 4;
+       s->maxdata      = 0xffff;
+       s->len_chanlist = 4;
+       s->insn_read    = adl_pci8164_insn_read;
+       s->insn_write   = adl_pci8164_insn_write;
+       s->private      = (void *)PCI8164_BUF0_REG;
+
+       /* read/write BUF1 register for each axis (channel) */
        s = &dev->subdevices[3];
-       s->type = COMEDI_SUBD_PROC;
-       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
-       s->n_chan = 4;
-       s->maxdata = 0xffff;
-       s->len_chanlist = 4;
-       /* s->range_table = &range_axis; */
-       s->insn_read = adl_pci8164_insn_read_buf1;
-       s->insn_write = adl_pci8164_insn_write_buf1;
-
-       dev_info(dev->class_dev, "%s attached\n", dev->board_name);
+       s->type         = COMEDI_SUBD_PROC;
+       s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+       s->n_chan       = 4;
+       s->maxdata      = 0xffff;
+       s->len_chanlist = 4;
+       s->insn_read    = adl_pci8164_insn_read;
+       s->insn_write   = adl_pci8164_insn_write;
+       s->private      = (void *)PCI8164_BUF1_REG;
 
        return 0;
 }
 
-static void adl_pci8164_detach(struct comedi_device *dev)
-{
-       struct pci_dev *pcidev = comedi_to_pci_dev(dev);
-
-       if (pcidev) {
-               if (dev->iobase)
-                       comedi_pci_disable(pcidev);
-       }
-}
-
 static struct comedi_driver adl_pci8164_driver = {
        .driver_name    = "adl_pci8164",
        .module         = THIS_MODULE,
        .auto_attach    = adl_pci8164_auto_attach,
-       .detach         = adl_pci8164_detach,
+       .detach         = comedi_pci_disable,
 };
 
 static int adl_pci8164_pci_probe(struct pci_dev *dev,
-                                          const struct pci_device_id *ent)
+                                const struct pci_device_id *id)
 {
-       return comedi_pci_auto_config(dev, &adl_pci8164_driver);
+       return comedi_pci_auto_config(dev, &adl_pci8164_driver,
+                                     id->driver_data);
 }
 
 static DEFINE_PCI_DEVICE_TABLE(adl_pci8164_pci_table) = {
-       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI8164) },
-       {0}
+       { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x8164) },
+       { 0 }
 };
 MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);