linux/drivers/staging/comedi/drivers/ni_atmio.c
<<
>>
Prefs
   1/*
   2    comedi/drivers/ni_atmio.c
   3    Hardware driver for NI AT-MIO E series cards
   4
   5    COMEDI - Linux Control and Measurement Device Interface
   6    Copyright (C) 1997-2001 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    You should have received a copy of the GNU General Public License
  19    along with this program; if not, write to the Free Software
  20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21*/
  22/*
  23Driver: ni_atmio
  24Description: National Instruments AT-MIO-E series
  25Author: ds
  26Devices: [National Instruments] AT-MIO-16E-1 (ni_atmio),
  27  AT-MIO-16E-2, AT-MIO-16E-10, AT-MIO-16DE-10, AT-MIO-64E-3,
  28  AT-MIO-16XE-50, AT-MIO-16XE-10, AT-AI-16XE-10
  29Status: works
  30Updated: Thu May  1 20:03:02 CDT 2003
  31
  32The driver has 2.6 kernel isapnp support, and
  33will automatically probe for a supported board if the
  34I/O base is left unspecified with comedi_config.
  35However, many of
  36the isapnp id numbers are unknown.  If your board is not
  37recognized, please send the output of 'cat /proc/isapnp'
  38(you may need to modprobe the isa-pnp module for
  39/proc/isapnp to exist) so the
  40id numbers for your board can be added to the driver.
  41
  42Otherwise, you can use the isapnptools package to configure
  43your board.  Use isapnp to
  44configure the I/O base and IRQ for the board, and then pass
  45the same values as
  46parameters in comedi_config.  A sample isapnp.conf file is included
  47in the etc/ directory of Comedilib.
  48
  49Comedilib includes a utility to autocalibrate these boards.  The
  50boards seem to boot into a state where the all calibration DACs
  51are at one extreme of their range, thus the default calibration
  52is terrible.  Calibration at boot is strongly encouraged.
  53
  54To use the extended digital I/O on some of the boards, enable the
  558255 driver when configuring the Comedi source tree.
  56
  57External triggering is supported for some events.  The channel index
  58(scan_begin_arg, etc.) maps to PFI0 - PFI9.
  59
  60Some of the more esoteric triggering possibilities of these boards
  61are not supported.
  62*/
  63/*
  64        The real guts of the driver is in ni_mio_common.c, which is included
  65        both here and in ni_pcimio.c
  66
  67        Interrupt support added by Truxton Fulton <trux@truxton.com>
  68
  69        References for specifications:
  70
  71           340747b.pdf  Register Level Programmer Manual (obsolete)
  72           340747c.pdf  Register Level Programmer Manual (new)
  73           DAQ-STC reference manual
  74
  75        Other possibly relevant info:
  76
  77           320517c.pdf  User manual (obsolete)
  78           320517f.pdf  User manual (new)
  79           320889a.pdf  delete
  80           320906c.pdf  maximum signal ratings
  81           321066a.pdf  about 16x
  82           321791a.pdf  discontinuation of at-mio-16e-10 rev. c
  83           321808a.pdf  about at-mio-16e-10 rev P
  84           321837a.pdf  discontinuation of at-mio-16de-10 rev d
  85           321838a.pdf  about at-mio-16de-10 rev N
  86
  87        ISSUES:
  88
  89        need to deal with external reference for DAC, and other DAC
  90        properties in board properties
  91
  92        deal with at-mio-16de-10 revision D to N changes, etc.
  93
  94*/
  95
  96#include <linux/interrupt.h>
  97#include "../comedidev.h"
  98
  99#include <linux/delay.h>
 100#include <linux/isapnp.h>
 101
 102#include "ni_stc.h"
 103#include "8255.h"
 104
 105#undef DEBUG
 106
 107#define ATMIO 1
 108#undef PCIMIO
 109
 110/*
 111 *  AT specific setup
 112 */
 113
 114#define NI_SIZE 0x20
 115
 116#define MAX_N_CALDACS 32
 117
 118static const struct ni_board_struct ni_boards[] = {
 119        {.device_id = 44,
 120         .isapnp_id = 0x0000,   /* XXX unknown */
 121         .name = "at-mio-16e-1",
 122         .n_adchan = 16,
 123         .adbits = 12,
 124         .ai_fifo_depth = 8192,
 125         .alwaysdither = 0,
 126         .gainlkup = ai_gain_16,
 127         .ai_speed = 800,
 128         .n_aochan = 2,
 129         .aobits = 12,
 130         .ao_fifo_depth = 2048,
 131         .ao_range_table = &range_ni_E_ao_ext,
 132         .ao_unipolar = 1,
 133         .ao_speed = 1000,
 134         .has_8255 = 0,
 135         .num_p0_dio_channels = 8,
 136         .caldac = {mb88341},
 137         },
 138        {.device_id = 25,
 139         .isapnp_id = 0x1900,
 140         .name = "at-mio-16e-2",
 141         .n_adchan = 16,
 142         .adbits = 12,
 143         .ai_fifo_depth = 2048,
 144         .alwaysdither = 0,
 145         .gainlkup = ai_gain_16,
 146         .ai_speed = 2000,
 147         .n_aochan = 2,
 148         .aobits = 12,
 149         .ao_fifo_depth = 2048,
 150         .ao_range_table = &range_ni_E_ao_ext,
 151         .ao_unipolar = 1,
 152         .ao_speed = 1000,
 153         .has_8255 = 0,
 154         .num_p0_dio_channels = 8,
 155         .caldac = {mb88341},
 156         },
 157        {.device_id = 36,
 158         .isapnp_id = 0x2400,
 159         .name = "at-mio-16e-10",
 160         .n_adchan = 16,
 161         .adbits = 12,
 162         .ai_fifo_depth = 512,
 163         .alwaysdither = 0,
 164         .gainlkup = ai_gain_16,
 165         .ai_speed = 10000,
 166         .n_aochan = 2,
 167         .aobits = 12,
 168         .ao_fifo_depth = 0,
 169         .ao_range_table = &range_ni_E_ao_ext,
 170         .ao_unipolar = 1,
 171         .ao_speed = 10000,
 172         .num_p0_dio_channels = 8,
 173         .caldac = {ad8804_debug},
 174         .has_8255 = 0,
 175         },
 176        {.device_id = 37,
 177         .isapnp_id = 0x2500,
 178         .name = "at-mio-16de-10",
 179         .n_adchan = 16,
 180         .adbits = 12,
 181         .ai_fifo_depth = 512,
 182         .alwaysdither = 0,
 183         .gainlkup = ai_gain_16,
 184         .ai_speed = 10000,
 185         .n_aochan = 2,
 186         .aobits = 12,
 187         .ao_fifo_depth = 0,
 188         .ao_range_table = &range_ni_E_ao_ext,
 189         .ao_unipolar = 1,
 190         .ao_speed = 10000,
 191         .num_p0_dio_channels = 8,
 192         .caldac = {ad8804_debug},
 193         .has_8255 = 1,
 194         },
 195        {.device_id = 38,
 196         .isapnp_id = 0x2600,
 197         .name = "at-mio-64e-3",
 198         .n_adchan = 64,
 199         .adbits = 12,
 200         .ai_fifo_depth = 2048,
 201         .alwaysdither = 0,
 202         .gainlkup = ai_gain_16,
 203         .ai_speed = 2000,
 204         .n_aochan = 2,
 205         .aobits = 12,
 206         .ao_fifo_depth = 2048,
 207         .ao_range_table = &range_ni_E_ao_ext,
 208         .ao_unipolar = 1,
 209         .ao_speed = 1000,
 210         .has_8255 = 0,
 211         .num_p0_dio_channels = 8,
 212         .caldac = {ad8804_debug},
 213         },
 214        {.device_id = 39,
 215         .isapnp_id = 0x2700,
 216         .name = "at-mio-16xe-50",
 217         .n_adchan = 16,
 218         .adbits = 16,
 219         .ai_fifo_depth = 512,
 220         .alwaysdither = 1,
 221         .gainlkup = ai_gain_8,
 222         .ai_speed = 50000,
 223         .n_aochan = 2,
 224         .aobits = 12,
 225         .ao_fifo_depth = 0,
 226         .ao_range_table = &range_bipolar10,
 227         .ao_unipolar = 0,
 228         .ao_speed = 50000,
 229         .num_p0_dio_channels = 8,
 230         .caldac = {dac8800, dac8043},
 231         .has_8255 = 0,
 232         },
 233        {.device_id = 50,
 234         .isapnp_id = 0x0000,   /* XXX unknown */
 235         .name = "at-mio-16xe-10",
 236         .n_adchan = 16,
 237         .adbits = 16,
 238         .ai_fifo_depth = 512,
 239         .alwaysdither = 1,
 240         .gainlkup = ai_gain_14,
 241         .ai_speed = 10000,
 242         .n_aochan = 2,
 243         .aobits = 16,
 244         .ao_fifo_depth = 2048,
 245         .ao_range_table = &range_ni_E_ao_ext,
 246         .ao_unipolar = 1,
 247         .ao_speed = 1000,
 248         .num_p0_dio_channels = 8,
 249         .caldac = {dac8800, dac8043, ad8522},
 250         .has_8255 = 0,
 251         },
 252        {.device_id = 51,
 253         .isapnp_id = 0x0000,   /* XXX unknown */
 254         .name = "at-ai-16xe-10",
 255         .n_adchan = 16,
 256         .adbits = 16,
 257         .ai_fifo_depth = 512,
 258         .alwaysdither = 1,     /* unknown */
 259         .gainlkup = ai_gain_14,
 260         .ai_speed = 10000,
 261         .n_aochan = 0,
 262         .aobits = 0,
 263         .ao_fifo_depth = 0,
 264         .ao_unipolar = 0,
 265         .num_p0_dio_channels = 8,
 266         .caldac = {dac8800, dac8043, ad8522},
 267         .has_8255 = 0,
 268         }
 269};
 270
 271static const int ni_irqpin[] =
 272    { -1, -1, -1, 0, 1, 2, -1, 3, -1, -1, 4, 5, 6, -1, -1, 7 };
 273
 274#define interrupt_pin(a)        (ni_irqpin[(a)])
 275
 276#define IRQ_POLARITY 0
 277
 278#define NI_E_IRQ_FLAGS          0
 279
 280struct ni_private {
 281        struct pnp_dev *isapnp_dev;
 282 NI_PRIVATE_COMMON};
 283#define devpriv ((struct ni_private *)dev->private)
 284
 285/* How we access registers */
 286
 287#define ni_writel(a, b)         (outl((a), (b)+dev->iobase))
 288#define ni_readl(a)             (inl((a)+dev->iobase))
 289#define ni_writew(a, b)         (outw((a), (b)+dev->iobase))
 290#define ni_readw(a)             (inw((a)+dev->iobase))
 291#define ni_writeb(a, b)         (outb((a), (b)+dev->iobase))
 292#define ni_readb(a)             (inb((a)+dev->iobase))
 293
 294/* How we access windowed registers */
 295
 296/* We automatically take advantage of STC registers that can be
 297 * read/written directly in the I/O space of the board.  The
 298 * AT-MIO devices map the low 8 STC registers to iobase+addr*2. */
 299
 300static void ni_atmio_win_out(struct comedi_device *dev, uint16_t data, int addr)
 301{
 302        unsigned long flags;
 303
 304        spin_lock_irqsave(&devpriv->window_lock, flags);
 305        if ((addr) < 8) {
 306                ni_writew(data, addr * 2);
 307        } else {
 308                ni_writew(addr, Window_Address);
 309                ni_writew(data, Window_Data);
 310        }
 311        spin_unlock_irqrestore(&devpriv->window_lock, flags);
 312}
 313
 314static uint16_t ni_atmio_win_in(struct comedi_device *dev, int addr)
 315{
 316        unsigned long flags;
 317        uint16_t ret;
 318
 319        spin_lock_irqsave(&devpriv->window_lock, flags);
 320        if (addr < 8) {
 321                ret = ni_readw(addr * 2);
 322        } else {
 323                ni_writew(addr, Window_Address);
 324                ret = ni_readw(Window_Data);
 325        }
 326        spin_unlock_irqrestore(&devpriv->window_lock, flags);
 327
 328        return ret;
 329}
 330
 331static struct pnp_device_id device_ids[] = {
 332        {.id = "NIC1900",.driver_data = 0},
 333        {.id = "NIC2400",.driver_data = 0},
 334        {.id = "NIC2500",.driver_data = 0},
 335        {.id = "NIC2600",.driver_data = 0},
 336        {.id = "NIC2700",.driver_data = 0},
 337        {.id = ""}
 338};
 339
 340MODULE_DEVICE_TABLE(pnp, device_ids);
 341
 342static int ni_atmio_attach(struct comedi_device *dev,
 343                           struct comedi_devconfig *it);
 344static int ni_atmio_detach(struct comedi_device *dev);
 345static struct comedi_driver driver_atmio = {
 346        .driver_name = "ni_atmio",
 347        .module = THIS_MODULE,
 348        .attach = ni_atmio_attach,
 349        .detach = ni_atmio_detach,
 350};
 351
 352COMEDI_INITCLEANUP(driver_atmio);
 353
 354#include "ni_mio_common.c"
 355
 356static int ni_getboardtype(struct comedi_device *dev);
 357
 358/* clean up allocated resources */
 359static int ni_atmio_detach(struct comedi_device *dev)
 360{
 361        mio_common_detach(dev);
 362
 363        if (dev->iobase)
 364                release_region(dev->iobase, NI_SIZE);
 365        if (dev->irq) {
 366                free_irq(dev->irq, dev);
 367        }
 368        if (devpriv->isapnp_dev)
 369                pnp_device_detach(devpriv->isapnp_dev);
 370
 371        return 0;
 372}
 373
 374static int ni_isapnp_find_board(struct pnp_dev **dev)
 375{
 376        struct pnp_dev *isapnp_dev = NULL;
 377        int i;
 378
 379        for (i = 0; i < n_ni_boards; i++) {
 380                isapnp_dev = pnp_find_dev(NULL,
 381                                          ISAPNP_VENDOR('N', 'I', 'C'),
 382                                          ISAPNP_FUNCTION(ni_boards[i].
 383                                                          isapnp_id), NULL);
 384
 385                if (isapnp_dev == NULL || isapnp_dev->card == NULL)
 386                        continue;
 387
 388                if (pnp_device_attach(isapnp_dev) < 0) {
 389                        printk
 390                            ("ni_atmio: %s found but already active, skipping.\n",
 391                             ni_boards[i].name);
 392                        continue;
 393                }
 394                if (pnp_activate_dev(isapnp_dev) < 0) {
 395                        pnp_device_detach(isapnp_dev);
 396                        return -EAGAIN;
 397                }
 398                if (!pnp_port_valid(isapnp_dev, 0)
 399                    || !pnp_irq_valid(isapnp_dev, 0)) {
 400                        pnp_device_detach(isapnp_dev);
 401                        printk("ni_atmio: pnp invalid port or irq, aborting\n");
 402                        return -ENOMEM;
 403                }
 404                break;
 405        }
 406        if (i == n_ni_boards)
 407                return -ENODEV;
 408        *dev = isapnp_dev;
 409        return 0;
 410}
 411
 412static int ni_atmio_attach(struct comedi_device *dev,
 413                           struct comedi_devconfig *it)
 414{
 415        struct pnp_dev *isapnp_dev;
 416        int ret;
 417        unsigned long iobase;
 418        int board;
 419        unsigned int irq;
 420
 421        /* allocate private area */
 422        ret = ni_alloc_private(dev);
 423        if (ret < 0)
 424                return ret;
 425
 426        devpriv->stc_writew = &ni_atmio_win_out;
 427        devpriv->stc_readw = &ni_atmio_win_in;
 428        devpriv->stc_writel = &win_out2;
 429        devpriv->stc_readl = &win_in2;
 430
 431        iobase = it->options[0];
 432        irq = it->options[1];
 433        isapnp_dev = NULL;
 434        if (iobase == 0) {
 435                ret = ni_isapnp_find_board(&isapnp_dev);
 436                if (ret < 0)
 437                        return ret;
 438
 439                iobase = pnp_port_start(isapnp_dev, 0);
 440                irq = pnp_irq(isapnp_dev, 0);
 441                devpriv->isapnp_dev = isapnp_dev;
 442        }
 443
 444        /* reserve our I/O region */
 445
 446        printk("comedi%d: ni_atmio: 0x%04lx", dev->minor, iobase);
 447        if (!request_region(iobase, NI_SIZE, "ni_atmio")) {
 448                printk(" I/O port conflict\n");
 449                return -EIO;
 450        }
 451
 452        dev->iobase = iobase;
 453
 454#ifdef DEBUG
 455        /* board existence sanity check */
 456        {
 457                int i;
 458
 459                printk(" board fingerprint:");
 460                for (i = 0; i < 16; i += 2) {
 461                        printk(" %04x %02x", inw(dev->iobase + i),
 462                               inb(dev->iobase + i + 1));
 463                }
 464        }
 465#endif
 466
 467        /* get board type */
 468
 469        board = ni_getboardtype(dev);
 470        if (board < 0)
 471                return -EIO;
 472
 473        dev->board_ptr = ni_boards + board;
 474
 475        printk(" %s", boardtype.name);
 476        dev->board_name = boardtype.name;
 477
 478        /* irq stuff */
 479
 480        if (irq != 0) {
 481                if (irq > 15 || ni_irqpin[irq] == -1) {
 482                        printk(" invalid irq %u\n", irq);
 483                        return -EINVAL;
 484                }
 485                printk(" ( irq = %u )", irq);
 486                ret = request_irq(irq, ni_E_interrupt, NI_E_IRQ_FLAGS,
 487                                  "ni_atmio", dev);
 488
 489                if (ret < 0) {
 490                        printk(" irq not available\n");
 491                        return -EINVAL;
 492                }
 493                dev->irq = irq;
 494        }
 495
 496        /* generic E series stuff in ni_mio_common.c */
 497
 498        ret = ni_E_init(dev, it);
 499        if (ret < 0) {
 500                return ret;
 501        }
 502
 503        return 0;
 504}
 505
 506static int ni_getboardtype(struct comedi_device *dev)
 507{
 508        int device_id = ni_read_eeprom(dev, 511);
 509        int i;
 510
 511        for (i = 0; i < n_ni_boards; i++) {
 512                if (ni_boards[i].device_id == device_id) {
 513                        return i;
 514                }
 515        }
 516        if (device_id == 255) {
 517                printk(" can't find board\n");
 518        } else if (device_id == 0) {
 519                printk(" EEPROM read error (?) or device not found\n");
 520        } else {
 521                printk(" unknown device ID %d -- contact author\n", device_id);
 522        }
 523        return -1;
 524}
 525