linux/drivers/comedi/drivers/adl_pci8164.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * comedi/drivers/adl_pci8164.c
   4 *
   5 * Hardware comedi driver for PCI-8164 Adlink card
   6 * Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca>
   7 */
   8
   9/*
  10 * Driver: adl_pci8164
  11 * Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
  12 * Devices: [ADLink] PCI-8164 (adl_pci8164)
  13 * Author: Michel Lachaine <mike@mikelachaine.ca>
  14 * Status: experimental
  15 * Updated: Mon, 14 Apr 2008 15:10:32 +0100
  16 *
  17 * Configuration Options: not applicable, uses PCI auto config
  18 */
  19
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22
  23#include "../comedi_pci.h"
  24
  25#define PCI8164_AXIS(x)         ((x) * 0x08)
  26#define PCI8164_CMD_MSTS_REG    0x00
  27#define PCI8164_OTP_SSTS_REG    0x02
  28#define PCI8164_BUF0_REG        0x04
  29#define PCI8164_BUF1_REG        0x06
  30
  31static int adl_pci8164_insn_read(struct comedi_device *dev,
  32                                 struct comedi_subdevice *s,
  33                                 struct comedi_insn *insn,
  34                                 unsigned int *data)
  35{
  36        unsigned long offset = (unsigned long)s->private;
  37        unsigned int chan = CR_CHAN(insn->chanspec);
  38        int i;
  39
  40        for (i = 0; i < insn->n; i++)
  41                data[i] = inw(dev->iobase + PCI8164_AXIS(chan) + offset);
  42
  43        return insn->n;
  44}
  45
  46static int adl_pci8164_insn_write(struct comedi_device *dev,
  47                                  struct comedi_subdevice *s,
  48                                  struct comedi_insn *insn,
  49                                  unsigned int *data)
  50{
  51        unsigned long offset = (unsigned long)s->private;
  52        unsigned int chan = CR_CHAN(insn->chanspec);
  53        int i;
  54
  55        for (i = 0; i < insn->n; i++)
  56                outw(data[i], dev->iobase + PCI8164_AXIS(chan) + offset);
  57
  58        return insn->n;
  59}
  60
  61static int adl_pci8164_auto_attach(struct comedi_device *dev,
  62                                   unsigned long context_unused)
  63{
  64        struct pci_dev *pcidev = comedi_to_pci_dev(dev);
  65        struct comedi_subdevice *s;
  66        int ret;
  67
  68        ret = comedi_pci_enable(dev);
  69        if (ret)
  70                return ret;
  71        dev->iobase = pci_resource_start(pcidev, 2);
  72
  73        ret = comedi_alloc_subdevices(dev, 4);
  74        if (ret)
  75                return ret;
  76
  77        /* read MSTS register / write CMD register for each axis (channel) */
  78        s = &dev->subdevices[0];
  79        s->type         = COMEDI_SUBD_PROC;
  80        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
  81        s->n_chan       = 4;
  82        s->maxdata      = 0xffff;
  83        s->len_chanlist = 4;
  84        s->insn_read    = adl_pci8164_insn_read;
  85        s->insn_write   = adl_pci8164_insn_write;
  86        s->private      = (void *)PCI8164_CMD_MSTS_REG;
  87
  88        /* read SSTS register / write OTP register for each axis (channel) */
  89        s = &dev->subdevices[1];
  90        s->type         = COMEDI_SUBD_PROC;
  91        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
  92        s->n_chan       = 4;
  93        s->maxdata      = 0xffff;
  94        s->len_chanlist = 4;
  95        s->insn_read    = adl_pci8164_insn_read;
  96        s->insn_write   = adl_pci8164_insn_write;
  97        s->private      = (void *)PCI8164_OTP_SSTS_REG;
  98
  99        /* read/write BUF0 register for each axis (channel) */
 100        s = &dev->subdevices[2];
 101        s->type         = COMEDI_SUBD_PROC;
 102        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 103        s->n_chan       = 4;
 104        s->maxdata      = 0xffff;
 105        s->len_chanlist = 4;
 106        s->insn_read    = adl_pci8164_insn_read;
 107        s->insn_write   = adl_pci8164_insn_write;
 108        s->private      = (void *)PCI8164_BUF0_REG;
 109
 110        /* read/write BUF1 register for each axis (channel) */
 111        s = &dev->subdevices[3];
 112        s->type         = COMEDI_SUBD_PROC;
 113        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 114        s->n_chan       = 4;
 115        s->maxdata      = 0xffff;
 116        s->len_chanlist = 4;
 117        s->insn_read    = adl_pci8164_insn_read;
 118        s->insn_write   = adl_pci8164_insn_write;
 119        s->private      = (void *)PCI8164_BUF1_REG;
 120
 121        return 0;
 122}
 123
 124static struct comedi_driver adl_pci8164_driver = {
 125        .driver_name    = "adl_pci8164",
 126        .module         = THIS_MODULE,
 127        .auto_attach    = adl_pci8164_auto_attach,
 128        .detach         = comedi_pci_detach,
 129};
 130
 131static int adl_pci8164_pci_probe(struct pci_dev *dev,
 132                                 const struct pci_device_id *id)
 133{
 134        return comedi_pci_auto_config(dev, &adl_pci8164_driver,
 135                                      id->driver_data);
 136}
 137
 138static const struct pci_device_id adl_pci8164_pci_table[] = {
 139        { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x8164) },
 140        { 0 }
 141};
 142MODULE_DEVICE_TABLE(pci, adl_pci8164_pci_table);
 143
 144static struct pci_driver adl_pci8164_pci_driver = {
 145        .name           = "adl_pci8164",
 146        .id_table       = adl_pci8164_pci_table,
 147        .probe          = adl_pci8164_pci_probe,
 148        .remove         = comedi_pci_auto_unconfig,
 149};
 150module_comedi_pci_driver(adl_pci8164_driver, adl_pci8164_pci_driver);
 151
 152MODULE_AUTHOR("Comedi https://www.comedi.org");
 153MODULE_DESCRIPTION("Comedi low-level driver");
 154MODULE_LICENSE("GPL");
 155