linux/drivers/staging/comedi/drivers/amplc_dio200_common.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/amplc_dio200_common.c
   3
   4    Common support code for "amplc_dio200" and "amplc_dio200_pci".
   5
   6    Copyright (C) 2005-2013 MEV Ltd. <http://www.mev.co.uk/>
   7
   8    COMEDI - Linux Control and Measurement Device Interface
   9    Copyright (C) 1998,2000 David A. Schleef <ds@schleef.org>
  10
  11    This program is free software; you can redistribute it and/or modify
  12    it under the terms of the GNU General Public License as published by
  13    the Free Software Foundation; either version 2 of the License, or
  14    (at your option) any later version.
  15
  16    This program is distributed in the hope that it will be useful,
  17    but WITHOUT ANY WARRANTY; without even the implied warranty of
  18    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19    GNU General Public License for more details.
  20*/
  21
  22#include <linux/interrupt.h>
  23#include <linux/slab.h>
  24
  25#include "../comedidev.h"
  26
  27#include "amplc_dio200.h"
  28#include "comedi_fc.h"
  29#include "8253.h"
  30
  31/* 8255 control register bits */
  32#define CR_C_LO_IO      0x01
  33#define CR_B_IO         0x02
  34#define CR_B_MODE       0x04
  35#define CR_C_HI_IO      0x08
  36#define CR_A_IO         0x10
  37#define CR_A_MODE(a)    ((a)<<5)
  38#define CR_CW           0x80
  39
  40/* 200 series registers */
  41#define DIO200_IO_SIZE          0x20
  42#define DIO200_PCIE_IO_SIZE     0x4000
  43#define DIO200_XCLK_SCE         0x18    /* Group X clock selection register */
  44#define DIO200_YCLK_SCE         0x19    /* Group Y clock selection register */
  45#define DIO200_ZCLK_SCE         0x1a    /* Group Z clock selection register */
  46#define DIO200_XGAT_SCE         0x1b    /* Group X gate selection register */
  47#define DIO200_YGAT_SCE         0x1c    /* Group Y gate selection register */
  48#define DIO200_ZGAT_SCE         0x1d    /* Group Z gate selection register */
  49#define DIO200_INT_SCE          0x1e    /* Interrupt enable/status register */
  50/* Extra registers for new PCIe boards */
  51#define DIO200_ENHANCE          0x20    /* 1 to enable enhanced features */
  52#define DIO200_VERSION          0x24    /* Hardware version register */
  53#define DIO200_TS_CONFIG        0x600   /* Timestamp timer config register */
  54#define DIO200_TS_COUNT         0x602   /* Timestamp timer count register */
  55
  56/*
  57 * Functions for constructing value for DIO_200_?CLK_SCE and
  58 * DIO_200_?GAT_SCE registers:
  59 *
  60 * 'which' is: 0 for CTR-X1, CTR-Y1, CTR-Z1; 1 for CTR-X2, CTR-Y2 or CTR-Z2.
  61 * 'chan' is the channel: 0, 1 or 2.
  62 * 'source' is the signal source: 0 to 7, or 0 to 31 for "enhanced" boards.
  63 */
  64static unsigned char clk_gat_sce(unsigned int which, unsigned int chan,
  65                                 unsigned int source)
  66{
  67        return (which << 5) | (chan << 3) |
  68               ((source & 030) << 3) | (source & 007);
  69}
  70
  71static unsigned char clk_sce(unsigned int which, unsigned int chan,
  72                             unsigned int source)
  73{
  74        return clk_gat_sce(which, chan, source);
  75}
  76
  77static unsigned char gat_sce(unsigned int which, unsigned int chan,
  78                             unsigned int source)
  79{
  80        return clk_gat_sce(which, chan, source);
  81}
  82
  83/*
  84 * Periods of the internal clock sources in nanoseconds.
  85 */
  86static const unsigned int clock_period[32] = {
  87        [1] = 100,              /* 10 MHz */
  88        [2] = 1000,             /* 1 MHz */
  89        [3] = 10000,            /* 100 kHz */
  90        [4] = 100000,           /* 10 kHz */
  91        [5] = 1000000,          /* 1 kHz */
  92        [11] = 50,              /* 20 MHz (enhanced boards) */
  93        /* clock sources 12 and later reserved for enhanced boards */
  94};
  95
  96/*
  97 * Timestamp timer configuration register (for new PCIe boards).
  98 */
  99#define TS_CONFIG_RESET         0x100   /* Reset counter to zero. */
 100#define TS_CONFIG_CLK_SRC_MASK  0x0FF   /* Clock source. */
 101#define TS_CONFIG_MAX_CLK_SRC   2       /* Maximum clock source value. */
 102
 103/*
 104 * Periods of the timestamp timer clock sources in nanoseconds.
 105 */
 106static const unsigned int ts_clock_period[TS_CONFIG_MAX_CLK_SRC + 1] = {
 107        1,                      /* 1 nanosecond (but with 20 ns granularity). */
 108        1000,                   /* 1 microsecond. */
 109        1000000,                /* 1 millisecond. */
 110};
 111
 112struct dio200_subdev_8254 {
 113        unsigned int ofs;               /* Counter base offset */
 114        unsigned int clk_sce_ofs;       /* CLK_SCE base address */
 115        unsigned int gat_sce_ofs;       /* GAT_SCE base address */
 116        int which;                      /* Bit 5 of CLK_SCE or GAT_SCE */
 117        unsigned int clock_src[3];      /* Current clock sources */
 118        unsigned int gate_src[3];       /* Current gate sources */
 119        spinlock_t spinlock;
 120};
 121
 122struct dio200_subdev_8255 {
 123        unsigned int ofs;               /* DIO base offset */
 124};
 125
 126struct dio200_subdev_intr {
 127        spinlock_t spinlock;
 128        unsigned int ofs;
 129        unsigned int valid_isns;
 130        unsigned int enabled_isns;
 131        unsigned int stopcount;
 132        bool active:1;
 133        bool continuous:1;
 134};
 135
 136static inline const struct dio200_layout *
 137dio200_board_layout(const struct dio200_board *board)
 138{
 139        return &board->layout;
 140}
 141
 142static inline const struct dio200_layout *
 143dio200_dev_layout(struct comedi_device *dev)
 144{
 145        return dio200_board_layout(comedi_board(dev));
 146}
 147
 148/*
 149 * Read 8-bit register.
 150 */
 151static unsigned char dio200_read8(struct comedi_device *dev,
 152                                  unsigned int offset)
 153{
 154        const struct dio200_board *thisboard = comedi_board(dev);
 155        struct dio200_private *devpriv = dev->private;
 156
 157        offset <<= thisboard->mainshift;
 158        if (devpriv->io.regtype == io_regtype)
 159                return inb(devpriv->io.u.iobase + offset);
 160        else
 161                return readb(devpriv->io.u.membase + offset);
 162}
 163
 164/*
 165 * Write 8-bit register.
 166 */
 167static void dio200_write8(struct comedi_device *dev, unsigned int offset,
 168                          unsigned char val)
 169{
 170        const struct dio200_board *thisboard = comedi_board(dev);
 171        struct dio200_private *devpriv = dev->private;
 172
 173        offset <<= thisboard->mainshift;
 174        if (devpriv->io.regtype == io_regtype)
 175                outb(val, devpriv->io.u.iobase + offset);
 176        else
 177                writeb(val, devpriv->io.u.membase + offset);
 178}
 179
 180/*
 181 * Read 32-bit register.
 182 */
 183static unsigned int dio200_read32(struct comedi_device *dev,
 184                                  unsigned int offset)
 185{
 186        const struct dio200_board *thisboard = comedi_board(dev);
 187        struct dio200_private *devpriv = dev->private;
 188
 189        offset <<= thisboard->mainshift;
 190        if (devpriv->io.regtype == io_regtype)
 191                return inl(devpriv->io.u.iobase + offset);
 192        else
 193                return readl(devpriv->io.u.membase + offset);
 194}
 195
 196/*
 197 * Write 32-bit register.
 198 */
 199static void dio200_write32(struct comedi_device *dev, unsigned int offset,
 200                           unsigned int val)
 201{
 202        const struct dio200_board *thisboard = comedi_board(dev);
 203        struct dio200_private *devpriv = dev->private;
 204
 205        offset <<= thisboard->mainshift;
 206        if (devpriv->io.regtype == io_regtype)
 207                outl(val, devpriv->io.u.iobase + offset);
 208        else
 209                writel(val, devpriv->io.u.membase + offset);
 210}
 211
 212/*
 213 * 'insn_bits' function for an 'INTERRUPT' subdevice.
 214 */
 215static int
 216dio200_subdev_intr_insn_bits(struct comedi_device *dev,
 217                             struct comedi_subdevice *s,
 218                             struct comedi_insn *insn, unsigned int *data)
 219{
 220        const struct dio200_layout *layout = dio200_dev_layout(dev);
 221        struct dio200_subdev_intr *subpriv = s->private;
 222
 223        if (layout->has_int_sce) {
 224                /* Just read the interrupt status register.  */
 225                data[1] = dio200_read8(dev, subpriv->ofs) & subpriv->valid_isns;
 226        } else {
 227                /* No interrupt status register. */
 228                data[0] = 0;
 229        }
 230
 231        return insn->n;
 232}
 233
 234/*
 235 * Called to stop acquisition for an 'INTERRUPT' subdevice.
 236 */
 237static void dio200_stop_intr(struct comedi_device *dev,
 238                             struct comedi_subdevice *s)
 239{
 240        const struct dio200_layout *layout = dio200_dev_layout(dev);
 241        struct dio200_subdev_intr *subpriv = s->private;
 242
 243        subpriv->active = false;
 244        subpriv->enabled_isns = 0;
 245        if (layout->has_int_sce)
 246                dio200_write8(dev, subpriv->ofs, 0);
 247}
 248
 249/*
 250 * Called to start acquisition for an 'INTERRUPT' subdevice.
 251 */
 252static int dio200_start_intr(struct comedi_device *dev,
 253                             struct comedi_subdevice *s)
 254{
 255        unsigned int n;
 256        unsigned isn_bits;
 257        const struct dio200_layout *layout = dio200_dev_layout(dev);
 258        struct dio200_subdev_intr *subpriv = s->private;
 259        struct comedi_cmd *cmd = &s->async->cmd;
 260        int retval = 0;
 261
 262        if (!subpriv->continuous && subpriv->stopcount == 0) {
 263                /* An empty acquisition! */
 264                s->async->events |= COMEDI_CB_EOA;
 265                subpriv->active = false;
 266                retval = 1;
 267        } else {
 268                /* Determine interrupt sources to enable. */
 269                isn_bits = 0;
 270                if (cmd->chanlist) {
 271                        for (n = 0; n < cmd->chanlist_len; n++)
 272                                isn_bits |= (1U << CR_CHAN(cmd->chanlist[n]));
 273                }
 274                isn_bits &= subpriv->valid_isns;
 275                /* Enable interrupt sources. */
 276                subpriv->enabled_isns = isn_bits;
 277                if (layout->has_int_sce)
 278                        dio200_write8(dev, subpriv->ofs, isn_bits);
 279        }
 280
 281        return retval;
 282}
 283
 284/*
 285 * Internal trigger function to start acquisition for an 'INTERRUPT' subdevice.
 286 */
 287static int
 288dio200_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s,
 289                          unsigned int trignum)
 290{
 291        struct dio200_subdev_intr *subpriv;
 292        unsigned long flags;
 293        int event = 0;
 294
 295        if (trignum != 0)
 296                return -EINVAL;
 297
 298        subpriv = s->private;
 299
 300        spin_lock_irqsave(&subpriv->spinlock, flags);
 301        s->async->inttrig = NULL;
 302        if (subpriv->active)
 303                event = dio200_start_intr(dev, s);
 304
 305        spin_unlock_irqrestore(&subpriv->spinlock, flags);
 306
 307        if (event)
 308                comedi_event(dev, s);
 309
 310        return 1;
 311}
 312
 313static void dio200_read_scan_intr(struct comedi_device *dev,
 314                                  struct comedi_subdevice *s,
 315                                  unsigned int triggered)
 316{
 317        struct dio200_subdev_intr *subpriv = s->private;
 318        unsigned short val;
 319        unsigned int n, ch, len;
 320
 321        val = 0;
 322        len = s->async->cmd.chanlist_len;
 323        for (n = 0; n < len; n++) {
 324                ch = CR_CHAN(s->async->cmd.chanlist[n]);
 325                if (triggered & (1U << ch))
 326                        val |= (1U << n);
 327        }
 328        /* Write the scan to the buffer. */
 329        if (comedi_buf_put(s->async, val)) {
 330                s->async->events |= (COMEDI_CB_BLOCK | COMEDI_CB_EOS);
 331        } else {
 332                /* Error!  Stop acquisition.  */
 333                dio200_stop_intr(dev, s);
 334                s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_OVERFLOW;
 335                comedi_error(dev, "buffer overflow");
 336        }
 337
 338        /* Check for end of acquisition. */
 339        if (!subpriv->continuous) {
 340                /* stop_src == TRIG_COUNT */
 341                if (subpriv->stopcount > 0) {
 342                        subpriv->stopcount--;
 343                        if (subpriv->stopcount == 0) {
 344                                s->async->events |= COMEDI_CB_EOA;
 345                                dio200_stop_intr(dev, s);
 346                        }
 347                }
 348        }
 349}
 350
 351/*
 352 * This is called from the interrupt service routine to handle a read
 353 * scan on an 'INTERRUPT' subdevice.
 354 */
 355static int dio200_handle_read_intr(struct comedi_device *dev,
 356                                   struct comedi_subdevice *s)
 357{
 358        const struct dio200_layout *layout = dio200_dev_layout(dev);
 359        struct dio200_subdev_intr *subpriv = s->private;
 360        unsigned triggered;
 361        unsigned intstat;
 362        unsigned cur_enabled;
 363        unsigned int oldevents;
 364        unsigned long flags;
 365
 366        triggered = 0;
 367
 368        spin_lock_irqsave(&subpriv->spinlock, flags);
 369        oldevents = s->async->events;
 370        if (layout->has_int_sce) {
 371                /*
 372                 * Collect interrupt sources that have triggered and disable
 373                 * them temporarily.  Loop around until no extra interrupt
 374                 * sources have triggered, at which point, the valid part of
 375                 * the interrupt status register will read zero, clearing the
 376                 * cause of the interrupt.
 377                 *
 378                 * Mask off interrupt sources already seen to avoid infinite
 379                 * loop in case of misconfiguration.
 380                 */
 381                cur_enabled = subpriv->enabled_isns;
 382                while ((intstat = (dio200_read8(dev, subpriv->ofs) &
 383                                   subpriv->valid_isns & ~triggered)) != 0) {
 384                        triggered |= intstat;
 385                        cur_enabled &= ~triggered;
 386                        dio200_write8(dev, subpriv->ofs, cur_enabled);
 387                }
 388        } else {
 389                /*
 390                 * No interrupt status register.  Assume the single interrupt
 391                 * source has triggered.
 392                 */
 393                triggered = subpriv->enabled_isns;
 394        }
 395
 396        if (triggered) {
 397                /*
 398                 * Some interrupt sources have triggered and have been
 399                 * temporarily disabled to clear the cause of the interrupt.
 400                 *
 401                 * Reenable them NOW to minimize the time they are disabled.
 402                 */
 403                cur_enabled = subpriv->enabled_isns;
 404                if (layout->has_int_sce)
 405                        dio200_write8(dev, subpriv->ofs, cur_enabled);
 406
 407                if (subpriv->active) {
 408                        /*
 409                         * The command is still active.
 410                         *
 411                         * Ignore interrupt sources that the command isn't
 412                         * interested in (just in case there's a race
 413                         * condition).
 414                         */
 415                        if (triggered & subpriv->enabled_isns)
 416                                /* Collect scan data. */
 417                                dio200_read_scan_intr(dev, s, triggered);
 418                }
 419        }
 420        spin_unlock_irqrestore(&subpriv->spinlock, flags);
 421
 422        if (oldevents != s->async->events)
 423                comedi_event(dev, s);
 424
 425        return (triggered != 0);
 426}
 427
 428/*
 429 * 'cancel' function for an 'INTERRUPT' subdevice.
 430 */
 431static int dio200_subdev_intr_cancel(struct comedi_device *dev,
 432                                     struct comedi_subdevice *s)
 433{
 434        struct dio200_subdev_intr *subpriv = s->private;
 435        unsigned long flags;
 436
 437        spin_lock_irqsave(&subpriv->spinlock, flags);
 438        if (subpriv->active)
 439                dio200_stop_intr(dev, s);
 440
 441        spin_unlock_irqrestore(&subpriv->spinlock, flags);
 442
 443        return 0;
 444}
 445
 446/*
 447 * 'do_cmdtest' function for an 'INTERRUPT' subdevice.
 448 */
 449static int
 450dio200_subdev_intr_cmdtest(struct comedi_device *dev,
 451                           struct comedi_subdevice *s, struct comedi_cmd *cmd)
 452{
 453        int err = 0;
 454
 455        /* Step 1 : check if triggers are trivially valid */
 456
 457        err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT);
 458        err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
 459        err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW);
 460        err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
 461        err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
 462
 463        if (err)
 464                return 1;
 465
 466        /* Step 2a : make sure trigger sources are unique */
 467
 468        err |= cfc_check_trigger_is_unique(cmd->start_src);
 469        err |= cfc_check_trigger_is_unique(cmd->stop_src);
 470
 471        /* Step 2b : and mutually compatible */
 472
 473        if (err)
 474                return 2;
 475
 476        /* Step 3: check if arguments are trivially valid */
 477
 478        err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
 479        err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
 480        err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
 481        err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
 482
 483        switch (cmd->stop_src) {
 484        case TRIG_COUNT:
 485                /* any count allowed */
 486                break;
 487        case TRIG_NONE:
 488                err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
 489                break;
 490        default:
 491                break;
 492        }
 493
 494        if (err)
 495                return 3;
 496
 497        /* step 4: fix up any arguments */
 498
 499        /* if (err) return 4; */
 500
 501        return 0;
 502}
 503
 504/*
 505 * 'do_cmd' function for an 'INTERRUPT' subdevice.
 506 */
 507static int dio200_subdev_intr_cmd(struct comedi_device *dev,
 508                                  struct comedi_subdevice *s)
 509{
 510        struct comedi_cmd *cmd = &s->async->cmd;
 511        struct dio200_subdev_intr *subpriv = s->private;
 512        unsigned long flags;
 513        int event = 0;
 514
 515        spin_lock_irqsave(&subpriv->spinlock, flags);
 516        subpriv->active = 1;
 517
 518        /* Set up end of acquisition. */
 519        switch (cmd->stop_src) {
 520        case TRIG_COUNT:
 521                subpriv->continuous = false;
 522                subpriv->stopcount = cmd->stop_arg;
 523                break;
 524        default:
 525                /* TRIG_NONE */
 526                subpriv->continuous = true;
 527                subpriv->stopcount = 0;
 528                break;
 529        }
 530
 531        /* Set up start of acquisition. */
 532        switch (cmd->start_src) {
 533        case TRIG_INT:
 534                s->async->inttrig = dio200_inttrig_start_intr;
 535                break;
 536        default:
 537                /* TRIG_NOW */
 538                event = dio200_start_intr(dev, s);
 539                break;
 540        }
 541        spin_unlock_irqrestore(&subpriv->spinlock, flags);
 542
 543        if (event)
 544                comedi_event(dev, s);
 545
 546        return 0;
 547}
 548
 549/*
 550 * This function initializes an 'INTERRUPT' subdevice.
 551 */
 552static int
 553dio200_subdev_intr_init(struct comedi_device *dev, struct comedi_subdevice *s,
 554                        unsigned int offset, unsigned valid_isns)
 555{
 556        const struct dio200_layout *layout = dio200_dev_layout(dev);
 557        struct dio200_subdev_intr *subpriv;
 558
 559        subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
 560        if (!subpriv)
 561                return -ENOMEM;
 562
 563        subpriv->ofs = offset;
 564        subpriv->valid_isns = valid_isns;
 565        spin_lock_init(&subpriv->spinlock);
 566
 567        if (layout->has_int_sce)
 568                /* Disable interrupt sources. */
 569                dio200_write8(dev, subpriv->ofs, 0);
 570
 571        s->type = COMEDI_SUBD_DI;
 572        s->subdev_flags = SDF_READABLE | SDF_CMD_READ;
 573        if (layout->has_int_sce) {
 574                s->n_chan = DIO200_MAX_ISNS;
 575                s->len_chanlist = DIO200_MAX_ISNS;
 576        } else {
 577                /* No interrupt source register.  Support single channel. */
 578                s->n_chan = 1;
 579                s->len_chanlist = 1;
 580        }
 581        s->range_table = &range_digital;
 582        s->maxdata = 1;
 583        s->insn_bits = dio200_subdev_intr_insn_bits;
 584        s->do_cmdtest = dio200_subdev_intr_cmdtest;
 585        s->do_cmd = dio200_subdev_intr_cmd;
 586        s->cancel = dio200_subdev_intr_cancel;
 587
 588        return 0;
 589}
 590
 591/*
 592 * Interrupt service routine.
 593 */
 594static irqreturn_t dio200_interrupt(int irq, void *d)
 595{
 596        struct comedi_device *dev = d;
 597        struct dio200_private *devpriv = dev->private;
 598        struct comedi_subdevice *s;
 599        int handled;
 600
 601        if (!dev->attached)
 602                return IRQ_NONE;
 603
 604        if (devpriv->intr_sd >= 0) {
 605                s = &dev->subdevices[devpriv->intr_sd];
 606                handled = dio200_handle_read_intr(dev, s);
 607        } else {
 608                handled = 0;
 609        }
 610
 611        return IRQ_RETVAL(handled);
 612}
 613
 614/*
 615 * Read an '8254' counter subdevice channel.
 616 */
 617static unsigned int
 618dio200_subdev_8254_read_chan(struct comedi_device *dev,
 619                             struct comedi_subdevice *s, unsigned int chan)
 620{
 621        struct dio200_subdev_8254 *subpriv = s->private;
 622        unsigned int val;
 623
 624        /* latch counter */
 625        val = chan << 6;
 626        dio200_write8(dev, subpriv->ofs + i8254_control_reg, val);
 627        /* read lsb, msb */
 628        val = dio200_read8(dev, subpriv->ofs + chan);
 629        val += dio200_read8(dev, subpriv->ofs + chan) << 8;
 630        return val;
 631}
 632
 633/*
 634 * Write an '8254' subdevice channel.
 635 */
 636static void
 637dio200_subdev_8254_write_chan(struct comedi_device *dev,
 638                              struct comedi_subdevice *s, unsigned int chan,
 639                              unsigned int count)
 640{
 641        struct dio200_subdev_8254 *subpriv = s->private;
 642
 643        /* write lsb, msb */
 644        dio200_write8(dev, subpriv->ofs + chan, count & 0xff);
 645        dio200_write8(dev, subpriv->ofs + chan, (count >> 8) & 0xff);
 646}
 647
 648/*
 649 * Set mode of an '8254' subdevice channel.
 650 */
 651static void
 652dio200_subdev_8254_set_mode(struct comedi_device *dev,
 653                            struct comedi_subdevice *s, unsigned int chan,
 654                            unsigned int mode)
 655{
 656        struct dio200_subdev_8254 *subpriv = s->private;
 657        unsigned int byte;
 658
 659        byte = chan << 6;
 660        byte |= 0x30;           /* access order: lsb, msb */
 661        byte |= (mode & 0xf);   /* counter mode and BCD|binary */
 662        dio200_write8(dev, subpriv->ofs + i8254_control_reg, byte);
 663}
 664
 665/*
 666 * Read status byte of an '8254' counter subdevice channel.
 667 */
 668static unsigned int
 669dio200_subdev_8254_status(struct comedi_device *dev,
 670                          struct comedi_subdevice *s, unsigned int chan)
 671{
 672        struct dio200_subdev_8254 *subpriv = s->private;
 673
 674        /* latch status */
 675        dio200_write8(dev, subpriv->ofs + i8254_control_reg,
 676                      0xe0 | (2 << chan));
 677        /* read status */
 678        return dio200_read8(dev, subpriv->ofs + chan);
 679}
 680
 681/*
 682 * Handle 'insn_read' for an '8254' counter subdevice.
 683 */
 684static int
 685dio200_subdev_8254_read(struct comedi_device *dev, struct comedi_subdevice *s,
 686                        struct comedi_insn *insn, unsigned int *data)
 687{
 688        struct dio200_subdev_8254 *subpriv = s->private;
 689        int chan = CR_CHAN(insn->chanspec);
 690        unsigned int n;
 691        unsigned long flags;
 692
 693        for (n = 0; n < insn->n; n++) {
 694                spin_lock_irqsave(&subpriv->spinlock, flags);
 695                data[n] = dio200_subdev_8254_read_chan(dev, s, chan);
 696                spin_unlock_irqrestore(&subpriv->spinlock, flags);
 697        }
 698        return insn->n;
 699}
 700
 701/*
 702 * Handle 'insn_write' for an '8254' counter subdevice.
 703 */
 704static int
 705dio200_subdev_8254_write(struct comedi_device *dev, struct comedi_subdevice *s,
 706                         struct comedi_insn *insn, unsigned int *data)
 707{
 708        struct dio200_subdev_8254 *subpriv = s->private;
 709        int chan = CR_CHAN(insn->chanspec);
 710        unsigned int n;
 711        unsigned long flags;
 712
 713        for (n = 0; n < insn->n; n++) {
 714                spin_lock_irqsave(&subpriv->spinlock, flags);
 715                dio200_subdev_8254_write_chan(dev, s, chan, data[n]);
 716                spin_unlock_irqrestore(&subpriv->spinlock, flags);
 717        }
 718        return insn->n;
 719}
 720
 721/*
 722 * Set gate source for an '8254' counter subdevice channel.
 723 */
 724static int
 725dio200_subdev_8254_set_gate_src(struct comedi_device *dev,
 726                                struct comedi_subdevice *s,
 727                                unsigned int counter_number,
 728                                unsigned int gate_src)
 729{
 730        const struct dio200_layout *layout = dio200_dev_layout(dev);
 731        struct dio200_subdev_8254 *subpriv = s->private;
 732        unsigned char byte;
 733
 734        if (!layout->has_clk_gat_sce)
 735                return -1;
 736        if (counter_number > 2)
 737                return -1;
 738        if (gate_src > (layout->has_enhancements ? 31 : 7))
 739                return -1;
 740
 741        subpriv->gate_src[counter_number] = gate_src;
 742        byte = gat_sce(subpriv->which, counter_number, gate_src);
 743        dio200_write8(dev, subpriv->gat_sce_ofs, byte);
 744
 745        return 0;
 746}
 747
 748/*
 749 * Get gate source for an '8254' counter subdevice channel.
 750 */
 751static int
 752dio200_subdev_8254_get_gate_src(struct comedi_device *dev,
 753                                struct comedi_subdevice *s,
 754                                unsigned int counter_number)
 755{
 756        const struct dio200_layout *layout = dio200_dev_layout(dev);
 757        struct dio200_subdev_8254 *subpriv = s->private;
 758
 759        if (!layout->has_clk_gat_sce)
 760                return -1;
 761        if (counter_number > 2)
 762                return -1;
 763
 764        return subpriv->gate_src[counter_number];
 765}
 766
 767/*
 768 * Set clock source for an '8254' counter subdevice channel.
 769 */
 770static int
 771dio200_subdev_8254_set_clock_src(struct comedi_device *dev,
 772                                 struct comedi_subdevice *s,
 773                                 unsigned int counter_number,
 774                                 unsigned int clock_src)
 775{
 776        const struct dio200_layout *layout = dio200_dev_layout(dev);
 777        struct dio200_subdev_8254 *subpriv = s->private;
 778        unsigned char byte;
 779
 780        if (!layout->has_clk_gat_sce)
 781                return -1;
 782        if (counter_number > 2)
 783                return -1;
 784        if (clock_src > (layout->has_enhancements ? 31 : 7))
 785                return -1;
 786
 787        subpriv->clock_src[counter_number] = clock_src;
 788        byte = clk_sce(subpriv->which, counter_number, clock_src);
 789        dio200_write8(dev, subpriv->clk_sce_ofs, byte);
 790
 791        return 0;
 792}
 793
 794/*
 795 * Get clock source for an '8254' counter subdevice channel.
 796 */
 797static int
 798dio200_subdev_8254_get_clock_src(struct comedi_device *dev,
 799                                 struct comedi_subdevice *s,
 800                                 unsigned int counter_number,
 801                                 unsigned int *period_ns)
 802{
 803        const struct dio200_layout *layout = dio200_dev_layout(dev);
 804        struct dio200_subdev_8254 *subpriv = s->private;
 805        unsigned clock_src;
 806
 807        if (!layout->has_clk_gat_sce)
 808                return -1;
 809        if (counter_number > 2)
 810                return -1;
 811
 812        clock_src = subpriv->clock_src[counter_number];
 813        *period_ns = clock_period[clock_src];
 814        return clock_src;
 815}
 816
 817/*
 818 * Handle 'insn_config' for an '8254' counter subdevice.
 819 */
 820static int
 821dio200_subdev_8254_config(struct comedi_device *dev, struct comedi_subdevice *s,
 822                          struct comedi_insn *insn, unsigned int *data)
 823{
 824        struct dio200_subdev_8254 *subpriv = s->private;
 825        int ret = 0;
 826        int chan = CR_CHAN(insn->chanspec);
 827        unsigned long flags;
 828
 829        spin_lock_irqsave(&subpriv->spinlock, flags);
 830        switch (data[0]) {
 831        case INSN_CONFIG_SET_COUNTER_MODE:
 832                if (data[1] > (I8254_MODE5 | I8254_BINARY))
 833                        ret = -EINVAL;
 834                else
 835                        dio200_subdev_8254_set_mode(dev, s, chan, data[1]);
 836                break;
 837        case INSN_CONFIG_8254_READ_STATUS:
 838                data[1] = dio200_subdev_8254_status(dev, s, chan);
 839                break;
 840        case INSN_CONFIG_SET_GATE_SRC:
 841                ret = dio200_subdev_8254_set_gate_src(dev, s, chan, data[2]);
 842                if (ret < 0)
 843                        ret = -EINVAL;
 844                break;
 845        case INSN_CONFIG_GET_GATE_SRC:
 846                ret = dio200_subdev_8254_get_gate_src(dev, s, chan);
 847                if (ret < 0) {
 848                        ret = -EINVAL;
 849                        break;
 850                }
 851                data[2] = ret;
 852                break;
 853        case INSN_CONFIG_SET_CLOCK_SRC:
 854                ret = dio200_subdev_8254_set_clock_src(dev, s, chan, data[1]);
 855                if (ret < 0)
 856                        ret = -EINVAL;
 857                break;
 858        case INSN_CONFIG_GET_CLOCK_SRC:
 859                ret = dio200_subdev_8254_get_clock_src(dev, s, chan, &data[2]);
 860                if (ret < 0) {
 861                        ret = -EINVAL;
 862                        break;
 863                }
 864                data[1] = ret;
 865                break;
 866        default:
 867                ret = -EINVAL;
 868                break;
 869        }
 870        spin_unlock_irqrestore(&subpriv->spinlock, flags);
 871        return ret < 0 ? ret : insn->n;
 872}
 873
 874/*
 875 * This function initializes an '8254' counter subdevice.
 876 */
 877static int
 878dio200_subdev_8254_init(struct comedi_device *dev, struct comedi_subdevice *s,
 879                        unsigned int offset)
 880{
 881        const struct dio200_layout *layout = dio200_dev_layout(dev);
 882        struct dio200_subdev_8254 *subpriv;
 883        unsigned int chan;
 884
 885        subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
 886        if (!subpriv)
 887                return -ENOMEM;
 888
 889        s->type = COMEDI_SUBD_COUNTER;
 890        s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
 891        s->n_chan = 3;
 892        s->maxdata = 0xFFFF;
 893        s->insn_read = dio200_subdev_8254_read;
 894        s->insn_write = dio200_subdev_8254_write;
 895        s->insn_config = dio200_subdev_8254_config;
 896
 897        spin_lock_init(&subpriv->spinlock);
 898        subpriv->ofs = offset;
 899        if (layout->has_clk_gat_sce) {
 900                /* Derive CLK_SCE and GAT_SCE register offsets from
 901                 * 8254 offset. */
 902                subpriv->clk_sce_ofs = DIO200_XCLK_SCE + (offset >> 3);
 903                subpriv->gat_sce_ofs = DIO200_XGAT_SCE + (offset >> 3);
 904                subpriv->which = (offset >> 2) & 1;
 905        }
 906
 907        /* Initialize channels. */
 908        for (chan = 0; chan < 3; chan++) {
 909                dio200_subdev_8254_set_mode(dev, s, chan,
 910                                            I8254_MODE0 | I8254_BINARY);
 911                if (layout->has_clk_gat_sce) {
 912                        /* Gate source 0 is VCC (logic 1). */
 913                        dio200_subdev_8254_set_gate_src(dev, s, chan, 0);
 914                        /* Clock source 0 is the dedicated clock input. */
 915                        dio200_subdev_8254_set_clock_src(dev, s, chan, 0);
 916                }
 917        }
 918
 919        return 0;
 920}
 921
 922/*
 923 * This function sets I/O directions for an '8255' DIO subdevice.
 924 */
 925static void dio200_subdev_8255_set_dir(struct comedi_device *dev,
 926                                       struct comedi_subdevice *s)
 927{
 928        struct dio200_subdev_8255 *subpriv = s->private;
 929        int config;
 930
 931        config = CR_CW;
 932        /* 1 in io_bits indicates output, 1 in config indicates input */
 933        if (!(s->io_bits & 0x0000ff))
 934                config |= CR_A_IO;
 935        if (!(s->io_bits & 0x00ff00))
 936                config |= CR_B_IO;
 937        if (!(s->io_bits & 0x0f0000))
 938                config |= CR_C_LO_IO;
 939        if (!(s->io_bits & 0xf00000))
 940                config |= CR_C_HI_IO;
 941        dio200_write8(dev, subpriv->ofs + 3, config);
 942}
 943
 944/*
 945 * Handle 'insn_bits' for an '8255' DIO subdevice.
 946 */
 947static int dio200_subdev_8255_bits(struct comedi_device *dev,
 948                                   struct comedi_subdevice *s,
 949                                   struct comedi_insn *insn, unsigned int *data)
 950{
 951        struct dio200_subdev_8255 *subpriv = s->private;
 952
 953        if (data[0]) {
 954                s->state &= ~data[0];
 955                s->state |= (data[0] & data[1]);
 956                if (data[0] & 0xff)
 957                        dio200_write8(dev, subpriv->ofs, s->state & 0xff);
 958                if (data[0] & 0xff00)
 959                        dio200_write8(dev, subpriv->ofs + 1,
 960                                      (s->state >> 8) & 0xff);
 961                if (data[0] & 0xff0000)
 962                        dio200_write8(dev, subpriv->ofs + 2,
 963                                      (s->state >> 16) & 0xff);
 964        }
 965        data[1] = dio200_read8(dev, subpriv->ofs);
 966        data[1] |= dio200_read8(dev, subpriv->ofs + 1) << 8;
 967        data[1] |= dio200_read8(dev, subpriv->ofs + 2) << 16;
 968        return 2;
 969}
 970
 971/*
 972 * Handle 'insn_config' for an '8255' DIO subdevice.
 973 */
 974static int dio200_subdev_8255_config(struct comedi_device *dev,
 975                                     struct comedi_subdevice *s,
 976                                     struct comedi_insn *insn,
 977                                     unsigned int *data)
 978{
 979        unsigned int mask;
 980        unsigned int bits;
 981
 982        mask = 1 << CR_CHAN(insn->chanspec);
 983        if (mask & 0x0000ff)
 984                bits = 0x0000ff;
 985        else if (mask & 0x00ff00)
 986                bits = 0x00ff00;
 987        else if (mask & 0x0f0000)
 988                bits = 0x0f0000;
 989        else
 990                bits = 0xf00000;
 991        switch (data[0]) {
 992        case INSN_CONFIG_DIO_INPUT:
 993                s->io_bits &= ~bits;
 994                break;
 995        case INSN_CONFIG_DIO_OUTPUT:
 996                s->io_bits |= bits;
 997                break;
 998        case INSN_CONFIG_DIO_QUERY:
 999                data[1] = (s->io_bits & bits) ? COMEDI_OUTPUT : COMEDI_INPUT;
1000                return insn->n;
1001                break;
1002        default:
1003                return -EINVAL;
1004        }
1005        dio200_subdev_8255_set_dir(dev, s);
1006        return 1;
1007}
1008
1009/*
1010 * This function initializes an '8255' DIO subdevice.
1011 *
1012 * offset is the offset to the 8255 chip.
1013 */
1014static int dio200_subdev_8255_init(struct comedi_device *dev,
1015                                   struct comedi_subdevice *s,
1016                                   unsigned int offset)
1017{
1018        struct dio200_subdev_8255 *subpriv;
1019
1020        subpriv = comedi_alloc_spriv(s, sizeof(*subpriv));
1021        if (!subpriv)
1022                return -ENOMEM;
1023
1024        subpriv->ofs = offset;
1025
1026        s->type = COMEDI_SUBD_DIO;
1027        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1028        s->n_chan = 24;
1029        s->range_table = &range_digital;
1030        s->maxdata = 1;
1031        s->insn_bits = dio200_subdev_8255_bits;
1032        s->insn_config = dio200_subdev_8255_config;
1033        s->state = 0;
1034        s->io_bits = 0;
1035        dio200_subdev_8255_set_dir(dev, s);
1036        return 0;
1037}
1038
1039/*
1040 * Handle 'insn_read' for a timer subdevice.
1041 */
1042static int dio200_subdev_timer_read(struct comedi_device *dev,
1043                                    struct comedi_subdevice *s,
1044                                    struct comedi_insn *insn,
1045                                    unsigned int *data)
1046{
1047        unsigned int n;
1048
1049        for (n = 0; n < insn->n; n++)
1050                data[n] = dio200_read32(dev, DIO200_TS_COUNT);
1051        return n;
1052}
1053
1054/*
1055 * Reset timer subdevice.
1056 */
1057static void dio200_subdev_timer_reset(struct comedi_device *dev,
1058                                      struct comedi_subdevice *s)
1059{
1060        unsigned int clock;
1061
1062        clock = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
1063        dio200_write32(dev, DIO200_TS_CONFIG, clock | TS_CONFIG_RESET);
1064        dio200_write32(dev, DIO200_TS_CONFIG, clock);
1065}
1066
1067/*
1068 * Get timer subdevice clock source and period.
1069 */
1070static void dio200_subdev_timer_get_clock_src(struct comedi_device *dev,
1071                                              struct comedi_subdevice *s,
1072                                              unsigned int *src,
1073                                              unsigned int *period)
1074{
1075        unsigned int clk;
1076
1077        clk = dio200_read32(dev, DIO200_TS_CONFIG) & TS_CONFIG_CLK_SRC_MASK;
1078        *src = clk;
1079        *period = (clk < ARRAY_SIZE(ts_clock_period)) ?
1080                  ts_clock_period[clk] : 0;
1081}
1082
1083/*
1084 * Set timer subdevice clock source.
1085 */
1086static int dio200_subdev_timer_set_clock_src(struct comedi_device *dev,
1087                                             struct comedi_subdevice *s,
1088                                             unsigned int src)
1089{
1090        if (src > TS_CONFIG_MAX_CLK_SRC)
1091                return -EINVAL;
1092        dio200_write32(dev, DIO200_TS_CONFIG, src);
1093        return 0;
1094}
1095
1096/*
1097 * Handle 'insn_config' for a timer subdevice.
1098 */
1099static int dio200_subdev_timer_config(struct comedi_device *dev,
1100                                      struct comedi_subdevice *s,
1101                                      struct comedi_insn *insn,
1102                                      unsigned int *data)
1103{
1104        int ret = 0;
1105
1106        switch (data[0]) {
1107        case INSN_CONFIG_RESET:
1108                dio200_subdev_timer_reset(dev, s);
1109                break;
1110        case INSN_CONFIG_SET_CLOCK_SRC:
1111                ret = dio200_subdev_timer_set_clock_src(dev, s, data[1]);
1112                if (ret < 0)
1113                        ret = -EINVAL;
1114                break;
1115        case INSN_CONFIG_GET_CLOCK_SRC:
1116                dio200_subdev_timer_get_clock_src(dev, s, &data[1], &data[2]);
1117                break;
1118        default:
1119                ret = -EINVAL;
1120                break;
1121        }
1122        return ret < 0 ? ret : insn->n;
1123}
1124
1125/*
1126 * This function initializes a timer subdevice.
1127 *
1128 * Uses the timestamp timer registers.  There is only one timestamp timer.
1129 */
1130static int dio200_subdev_timer_init(struct comedi_device *dev,
1131                                    struct comedi_subdevice *s)
1132{
1133        s->type = COMEDI_SUBD_TIMER;
1134        s->subdev_flags = SDF_READABLE | SDF_LSAMPL;
1135        s->n_chan = 1;
1136        s->maxdata = 0xFFFFFFFF;
1137        s->insn_read = dio200_subdev_timer_read;
1138        s->insn_config = dio200_subdev_timer_config;
1139        return 0;
1140}
1141
1142void amplc_dio200_set_enhance(struct comedi_device *dev, unsigned char val)
1143{
1144        dio200_write8(dev, DIO200_ENHANCE, val);
1145}
1146EXPORT_SYMBOL_GPL(amplc_dio200_set_enhance);
1147
1148int amplc_dio200_common_attach(struct comedi_device *dev, unsigned int irq,
1149                               unsigned long req_irq_flags)
1150{
1151        const struct dio200_board *thisboard = comedi_board(dev);
1152        struct dio200_private *devpriv = dev->private;
1153        const struct dio200_layout *layout = dio200_board_layout(thisboard);
1154        struct comedi_subdevice *s;
1155        int sdx;
1156        unsigned int n;
1157        int ret;
1158
1159        devpriv->intr_sd = -1;
1160
1161        ret = comedi_alloc_subdevices(dev, layout->n_subdevs);
1162        if (ret)
1163                return ret;
1164
1165        for (n = 0; n < dev->n_subdevices; n++) {
1166                s = &dev->subdevices[n];
1167                switch (layout->sdtype[n]) {
1168                case sd_8254:
1169                        /* counter subdevice (8254) */
1170                        ret = dio200_subdev_8254_init(dev, s,
1171                                                      layout->sdinfo[n]);
1172                        if (ret < 0)
1173                                return ret;
1174                        break;
1175                case sd_8255:
1176                        /* digital i/o subdevice (8255) */
1177                        ret = dio200_subdev_8255_init(dev, s,
1178                                                      layout->sdinfo[n]);
1179                        if (ret < 0)
1180                                return ret;
1181                        break;
1182                case sd_intr:
1183                        /* 'INTERRUPT' subdevice */
1184                        if (irq) {
1185                                ret = dio200_subdev_intr_init(dev, s,
1186                                                              DIO200_INT_SCE,
1187                                                              layout->sdinfo[n]
1188                                                             );
1189                                if (ret < 0)
1190                                        return ret;
1191                                devpriv->intr_sd = n;
1192                        } else {
1193                                s->type = COMEDI_SUBD_UNUSED;
1194                        }
1195                        break;
1196                case sd_timer:
1197                        ret = dio200_subdev_timer_init(dev, s);
1198                        if (ret < 0)
1199                                return ret;
1200                        break;
1201                default:
1202                        s->type = COMEDI_SUBD_UNUSED;
1203                        break;
1204                }
1205        }
1206        sdx = devpriv->intr_sd;
1207        if (sdx >= 0 && sdx < dev->n_subdevices)
1208                dev->read_subdev = &dev->subdevices[sdx];
1209        if (irq) {
1210                if (request_irq(irq, dio200_interrupt, req_irq_flags,
1211                                dev->board_name, dev) >= 0) {
1212                        dev->irq = irq;
1213                } else {
1214                        dev_warn(dev->class_dev,
1215                                 "warning! irq %u unavailable!\n", irq);
1216                }
1217        }
1218        dev_info(dev->class_dev, "attached\n");
1219        return 0;
1220}
1221EXPORT_SYMBOL_GPL(amplc_dio200_common_attach);
1222
1223void amplc_dio200_common_detach(struct comedi_device *dev)
1224{
1225        const struct dio200_board *thisboard = comedi_board(dev);
1226        struct dio200_private *devpriv = dev->private;
1227
1228        if (!thisboard || !devpriv)
1229                return;
1230        if (dev->irq)
1231                free_irq(dev->irq, dev);
1232}
1233EXPORT_SYMBOL_GPL(amplc_dio200_common_detach);
1234
1235static int __init amplc_dio200_common_init(void)
1236{
1237        return 0;
1238}
1239module_init(amplc_dio200_common_init);
1240
1241static void __exit amplc_dio200_common_exit(void)
1242{
1243}
1244module_exit(amplc_dio200_common_exit);
1245
1246MODULE_AUTHOR("Comedi http://www.comedi.org");
1247MODULE_DESCRIPTION("Comedi helper for amplc_dio200 and amplc_dio200_pci");
1248MODULE_LICENSE("GPL");
1249