root/drivers/staging/comedi/drivers/pcl730.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcl730_do_insn_bits
  2. pcl730_get_bits
  3. pcl730_di_insn_bits
  4. pcl730_attach

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * comedi/drivers/pcl730.c
   4  * Driver for Advantech PCL-730 and clones
   5  * José Luis Sánchez
   6  */
   7 
   8 /*
   9  * Driver: pcl730
  10  * Description: Advantech PCL-730 (& compatibles)
  11  * Devices: [Advantech] PCL-730 (pcl730), PCM-3730 (pcm3730), PCL-725 (pcl725),
  12  *   PCL-733 (pcl733), PCL-734 (pcl734),
  13  *   [ADLink] ACL-7130 (acl7130), ACL-7225b (acl7225b),
  14  *   [ICP] ISO-730 (iso730), P8R8-DIO (p8r8dio), P16R16-DIO (p16r16dio),
  15  *   [Diamond Systems] OPMM-1616-XT (opmm-1616-xt), PEARL-MM-P (pearl-mm-p),
  16  *   IR104-PBF (ir104-pbf),
  17  * Author: José Luis Sánchez (jsanchezv@teleline.es)
  18  * Status: untested
  19  *
  20  * Configuration options:
  21  *   [0] - I/O port base
  22  *
  23  * Interrupts are not supported.
  24  * The ACL-7130 card has an 8254 timer/counter not supported by this driver.
  25  */
  26 
  27 #include <linux/module.h>
  28 #include "../comedidev.h"
  29 
  30 /*
  31  * Register map
  32  *
  33  * The register map varies slightly depending on the board type but
  34  * all registers are 8-bit.
  35  *
  36  * The boardinfo 'io_range' is used to allow comedi to request the
  37  * proper range required by the board.
  38  *
  39  * The comedi_subdevice 'private' data is used to pass the register
  40  * offset to the (*insn_bits) functions to read/write the correct
  41  * registers.
  42  *
  43  * The basic register mapping looks like this:
  44  *
  45  *     BASE+0  Isolated outputs 0-7 (write) / inputs 0-7 (read)
  46  *     BASE+1  Isolated outputs 8-15 (write) / inputs 8-15 (read)
  47  *     BASE+2  TTL outputs 0-7 (write) / inputs 0-7 (read)
  48  *     BASE+3  TTL outputs 8-15 (write) / inputs 8-15 (read)
  49  *
  50  * The pcm3730 board does not have register BASE+1.
  51  *
  52  * The pcl725 and p8r8dio only have registers BASE+0 and BASE+1:
  53  *
  54  *     BASE+0  Isolated outputs 0-7 (write) (read back on p8r8dio)
  55  *     BASE+1  Isolated inputs 0-7 (read)
  56  *
  57  * The acl7225b and p16r16dio boards have this register mapping:
  58  *
  59  *     BASE+0  Isolated outputs 0-7 (write) (read back)
  60  *     BASE+1  Isolated outputs 8-15 (write) (read back)
  61  *     BASE+2  Isolated inputs 0-7 (read)
  62  *     BASE+3  Isolated inputs 8-15 (read)
  63  *
  64  * The pcl733 and pcl733 boards have this register mapping:
  65  *
  66  *     BASE+0  Isolated outputs 0-7 (write) or inputs 0-7 (read)
  67  *     BASE+1  Isolated outputs 8-15 (write) or inputs 8-15 (read)
  68  *     BASE+2  Isolated outputs 16-23 (write) or inputs 16-23 (read)
  69  *     BASE+3  Isolated outputs 24-31 (write) or inputs 24-31 (read)
  70  *
  71  * The opmm-1616-xt board has this register mapping:
  72  *
  73  *     BASE+0  Isolated outputs 0-7 (write) (read back)
  74  *     BASE+1  Isolated outputs 8-15 (write) (read back)
  75  *     BASE+2  Isolated inputs 0-7 (read)
  76  *     BASE+3  Isolated inputs 8-15 (read)
  77  *
  78  *     These registers are not currently supported:
  79  *
  80  *     BASE+2  Relay select register (write)
  81  *     BASE+3  Board reset control register (write)
  82  *     BASE+4  Interrupt control register (write)
  83  *     BASE+4  Change detect 7-0 status register (read)
  84  *     BASE+5  LED control register (write)
  85  *     BASE+5  Change detect 15-8 status register (read)
  86  *
  87  * The pearl-mm-p board has this register mapping:
  88  *
  89  *     BASE+0  Isolated outputs 0-7 (write)
  90  *     BASE+1  Isolated outputs 8-15 (write)
  91  *
  92  * The ir104-pbf board has this register mapping:
  93  *
  94  *     BASE+0  Isolated outputs 0-7 (write) (read back)
  95  *     BASE+1  Isolated outputs 8-15 (write) (read back)
  96  *     BASE+2  Isolated outputs 16-19 (write) (read back)
  97  *     BASE+4  Isolated inputs 0-7 (read)
  98  *     BASE+5  Isolated inputs 8-15 (read)
  99  *     BASE+6  Isolated inputs 16-19 (read)
 100  */
 101 
 102 struct pcl730_board {
 103         const char *name;
 104         unsigned int io_range;
 105         unsigned is_pcl725:1;
 106         unsigned is_acl7225b:1;
 107         unsigned is_ir104:1;
 108         unsigned has_readback:1;
 109         unsigned has_ttl_io:1;
 110         int n_subdevs;
 111         int n_iso_out_chan;
 112         int n_iso_in_chan;
 113         int n_ttl_chan;
 114 };
 115 
 116 static const struct pcl730_board pcl730_boards[] = {
 117         {
 118                 .name           = "pcl730",
 119                 .io_range       = 0x04,
 120                 .has_ttl_io     = 1,
 121                 .n_subdevs      = 4,
 122                 .n_iso_out_chan = 16,
 123                 .n_iso_in_chan  = 16,
 124                 .n_ttl_chan     = 16,
 125         }, {
 126                 .name           = "iso730",
 127                 .io_range       = 0x04,
 128                 .n_subdevs      = 4,
 129                 .n_iso_out_chan = 16,
 130                 .n_iso_in_chan  = 16,
 131                 .n_ttl_chan     = 16,
 132         }, {
 133                 .name           = "acl7130",
 134                 .io_range       = 0x08,
 135                 .has_ttl_io     = 1,
 136                 .n_subdevs      = 4,
 137                 .n_iso_out_chan = 16,
 138                 .n_iso_in_chan  = 16,
 139                 .n_ttl_chan     = 16,
 140         }, {
 141                 .name           = "pcm3730",
 142                 .io_range       = 0x04,
 143                 .has_ttl_io     = 1,
 144                 .n_subdevs      = 4,
 145                 .n_iso_out_chan = 8,
 146                 .n_iso_in_chan  = 8,
 147                 .n_ttl_chan     = 16,
 148         }, {
 149                 .name           = "pcl725",
 150                 .io_range       = 0x02,
 151                 .is_pcl725      = 1,
 152                 .n_subdevs      = 2,
 153                 .n_iso_out_chan = 8,
 154                 .n_iso_in_chan  = 8,
 155         }, {
 156                 .name           = "p8r8dio",
 157                 .io_range       = 0x02,
 158                 .is_pcl725      = 1,
 159                 .has_readback   = 1,
 160                 .n_subdevs      = 2,
 161                 .n_iso_out_chan = 8,
 162                 .n_iso_in_chan  = 8,
 163         }, {
 164                 .name           = "acl7225b",
 165                 .io_range       = 0x08,         /* only 4 are used */
 166                 .is_acl7225b    = 1,
 167                 .has_readback   = 1,
 168                 .n_subdevs      = 2,
 169                 .n_iso_out_chan = 16,
 170                 .n_iso_in_chan  = 16,
 171         }, {
 172                 .name           = "p16r16dio",
 173                 .io_range       = 0x04,
 174                 .is_acl7225b    = 1,
 175                 .has_readback   = 1,
 176                 .n_subdevs      = 2,
 177                 .n_iso_out_chan = 16,
 178                 .n_iso_in_chan  = 16,
 179         }, {
 180                 .name           = "pcl733",
 181                 .io_range       = 0x04,
 182                 .n_subdevs      = 1,
 183                 .n_iso_in_chan  = 32,
 184         }, {
 185                 .name           = "pcl734",
 186                 .io_range       = 0x04,
 187                 .n_subdevs      = 1,
 188                 .n_iso_out_chan = 32,
 189         }, {
 190                 .name           = "opmm-1616-xt",
 191                 .io_range       = 0x10,
 192                 .is_acl7225b    = 1,
 193                 .has_readback   = 1,
 194                 .n_subdevs      = 2,
 195                 .n_iso_out_chan = 16,
 196                 .n_iso_in_chan  = 16,
 197         }, {
 198                 .name           = "pearl-mm-p",
 199                 .io_range       = 0x02,
 200                 .n_subdevs      = 1,
 201                 .n_iso_out_chan = 16,
 202         }, {
 203                 .name           = "ir104-pbf",
 204                 .io_range       = 0x08,
 205                 .is_ir104       = 1,
 206                 .has_readback   = 1,
 207                 .n_iso_out_chan = 20,
 208                 .n_iso_in_chan  = 20,
 209         },
 210 };
 211 
 212 static int pcl730_do_insn_bits(struct comedi_device *dev,
 213                                struct comedi_subdevice *s,
 214                                struct comedi_insn *insn,
 215                                unsigned int *data)
 216 {
 217         unsigned long reg = (unsigned long)s->private;
 218         unsigned int mask;
 219 
 220         mask = comedi_dio_update_state(s, data);
 221         if (mask) {
 222                 if (mask & 0x00ff)
 223                         outb(s->state & 0xff, dev->iobase + reg);
 224                 if ((mask & 0xff00) && (s->n_chan > 8))
 225                         outb((s->state >> 8) & 0xff, dev->iobase + reg + 1);
 226                 if ((mask & 0xff0000) && (s->n_chan > 16))
 227                         outb((s->state >> 16) & 0xff, dev->iobase + reg + 2);
 228                 if ((mask & 0xff000000) && (s->n_chan > 24))
 229                         outb((s->state >> 24) & 0xff, dev->iobase + reg + 3);
 230         }
 231 
 232         data[1] = s->state;
 233 
 234         return insn->n;
 235 }
 236 
 237 static unsigned int pcl730_get_bits(struct comedi_device *dev,
 238                                     struct comedi_subdevice *s)
 239 {
 240         unsigned long reg = (unsigned long)s->private;
 241         unsigned int val;
 242 
 243         val = inb(dev->iobase + reg);
 244         if (s->n_chan > 8)
 245                 val |= (inb(dev->iobase + reg + 1) << 8);
 246         if (s->n_chan > 16)
 247                 val |= (inb(dev->iobase + reg + 2) << 16);
 248         if (s->n_chan > 24)
 249                 val |= (inb(dev->iobase + reg + 3) << 24);
 250 
 251         return val;
 252 }
 253 
 254 static int pcl730_di_insn_bits(struct comedi_device *dev,
 255                                struct comedi_subdevice *s,
 256                                struct comedi_insn *insn,
 257                                unsigned int *data)
 258 {
 259         data[1] = pcl730_get_bits(dev, s);
 260 
 261         return insn->n;
 262 }
 263 
 264 static int pcl730_attach(struct comedi_device *dev,
 265                          struct comedi_devconfig *it)
 266 {
 267         const struct pcl730_board *board = dev->board_ptr;
 268         struct comedi_subdevice *s;
 269         int subdev;
 270         int ret;
 271 
 272         ret = comedi_request_region(dev, it->options[0], board->io_range);
 273         if (ret)
 274                 return ret;
 275 
 276         ret = comedi_alloc_subdevices(dev, board->n_subdevs);
 277         if (ret)
 278                 return ret;
 279 
 280         subdev = 0;
 281 
 282         if (board->n_iso_out_chan) {
 283                 /* Isolated Digital Outputs */
 284                 s = &dev->subdevices[subdev++];
 285                 s->type         = COMEDI_SUBD_DO;
 286                 s->subdev_flags = SDF_WRITABLE;
 287                 s->n_chan       = board->n_iso_out_chan;
 288                 s->maxdata      = 1;
 289                 s->range_table  = &range_digital;
 290                 s->insn_bits    = pcl730_do_insn_bits;
 291                 s->private      = (void *)0;
 292 
 293                 /* get the initial state if supported */
 294                 if (board->has_readback)
 295                         s->state = pcl730_get_bits(dev, s);
 296         }
 297 
 298         if (board->n_iso_in_chan) {
 299                 /* Isolated Digital Inputs */
 300                 s = &dev->subdevices[subdev++];
 301                 s->type         = COMEDI_SUBD_DI;
 302                 s->subdev_flags = SDF_READABLE;
 303                 s->n_chan       = board->n_iso_in_chan;
 304                 s->maxdata      = 1;
 305                 s->range_table  = &range_digital;
 306                 s->insn_bits    = pcl730_di_insn_bits;
 307                 s->private      = board->is_ir104 ? (void *)4 :
 308                                   board->is_acl7225b ? (void *)2 :
 309                                   board->is_pcl725 ? (void *)1 : (void *)0;
 310         }
 311 
 312         if (board->has_ttl_io) {
 313                 /* TTL Digital Outputs */
 314                 s = &dev->subdevices[subdev++];
 315                 s->type         = COMEDI_SUBD_DO;
 316                 s->subdev_flags = SDF_WRITABLE;
 317                 s->n_chan       = board->n_ttl_chan;
 318                 s->maxdata      = 1;
 319                 s->range_table  = &range_digital;
 320                 s->insn_bits    = pcl730_do_insn_bits;
 321                 s->private      = (void *)2;
 322 
 323                 /* TTL Digital Inputs */
 324                 s = &dev->subdevices[subdev++];
 325                 s->type         = COMEDI_SUBD_DI;
 326                 s->subdev_flags = SDF_READABLE;
 327                 s->n_chan       = board->n_ttl_chan;
 328                 s->maxdata      = 1;
 329                 s->range_table  = &range_digital;
 330                 s->insn_bits    = pcl730_di_insn_bits;
 331                 s->private      = (void *)2;
 332         }
 333 
 334         return 0;
 335 }
 336 
 337 static struct comedi_driver pcl730_driver = {
 338         .driver_name    = "pcl730",
 339         .module         = THIS_MODULE,
 340         .attach         = pcl730_attach,
 341         .detach         = comedi_legacy_detach,
 342         .board_name     = &pcl730_boards[0].name,
 343         .num_names      = ARRAY_SIZE(pcl730_boards),
 344         .offset         = sizeof(struct pcl730_board),
 345 };
 346 module_comedi_driver(pcl730_driver);
 347 
 348 MODULE_AUTHOR("Comedi http://www.comedi.org");
 349 MODULE_DESCRIPTION("Comedi low-level driver");
 350 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */