linux/drivers/staging/comedi/drivers/dt2801.c
<<
>>
Prefs
   1/*
   2 * comedi/drivers/dt2801.c
   3 * Device Driver for DataTranslation DT2801
   4 *
   5 */
   6/*
   7Driver: dt2801
   8Description: Data Translation DT2801 series and DT01-EZ
   9Author: ds
  10Status: works
  11Devices: [Data Translation] DT2801 (dt2801), DT2801-A, DT2801/5716A,
  12  DT2805, DT2805/5716A, DT2808, DT2818, DT2809, DT01-EZ
  13
  14This driver can autoprobe the type of board.
  15
  16Configuration options:
  17  [0] - I/O port base address
  18  [1] - unused
  19  [2] - A/D reference 0=differential, 1=single-ended
  20  [3] - A/D range
  21          0 = [-10, 10]
  22          1 = [0,10]
  23  [4] - D/A 0 range
  24          0 = [-10, 10]
  25          1 = [-5,5]
  26          2 = [-2.5,2.5]
  27          3 = [0,10]
  28          4 = [0,5]
  29  [5] - D/A 1 range (same choices)
  30*/
  31
  32#include <linux/module.h>
  33#include "../comedidev.h"
  34#include <linux/delay.h>
  35
  36#define DT2801_TIMEOUT 1000
  37
  38/* Hardware Configuration */
  39/* ====================== */
  40
  41#define DT2801_MAX_DMA_SIZE (64 * 1024)
  42
  43/* define's */
  44/* ====================== */
  45
  46/* Commands */
  47#define DT_C_RESET       0x0
  48#define DT_C_CLEAR_ERR   0x1
  49#define DT_C_READ_ERRREG 0x2
  50#define DT_C_SET_CLOCK   0x3
  51
  52#define DT_C_TEST        0xb
  53#define DT_C_STOP        0xf
  54
  55#define DT_C_SET_DIGIN   0x4
  56#define DT_C_SET_DIGOUT  0x5
  57#define DT_C_READ_DIG    0x6
  58#define DT_C_WRITE_DIG   0x7
  59
  60#define DT_C_WRITE_DAIM  0x8
  61#define DT_C_SET_DA      0x9
  62#define DT_C_WRITE_DA    0xa
  63
  64#define DT_C_READ_ADIM   0xc
  65#define DT_C_SET_AD      0xd
  66#define DT_C_READ_AD     0xe
  67
  68/* Command modifiers (only used with read/write), EXTTRIG can be
  69   used with some other commands.
  70*/
  71#define DT_MOD_DMA     (1<<4)
  72#define DT_MOD_CONT    (1<<5)
  73#define DT_MOD_EXTCLK  (1<<6)
  74#define DT_MOD_EXTTRIG (1<<7)
  75
  76/* Bits in status register */
  77#define DT_S_DATA_OUT_READY   (1<<0)
  78#define DT_S_DATA_IN_FULL     (1<<1)
  79#define DT_S_READY            (1<<2)
  80#define DT_S_COMMAND          (1<<3)
  81#define DT_S_COMPOSITE_ERROR  (1<<7)
  82
  83/* registers */
  84#define DT2801_DATA             0
  85#define DT2801_STATUS           1
  86#define DT2801_CMD              1
  87
  88#if 0
  89/* ignore 'defined but not used' warning */
  90static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = {
  91        4, {
  92                BIP_RANGE(10),
  93                BIP_RANGE(5),
  94                BIP_RANGE(2.5),
  95                BIP_RANGE(1.25)
  96        }
  97};
  98#endif
  99static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = {
 100        4, {
 101                BIP_RANGE(10),
 102                BIP_RANGE(1),
 103                BIP_RANGE(0.1),
 104                BIP_RANGE(0.02)
 105        }
 106};
 107
 108#if 0
 109/* ignore 'defined but not used' warning */
 110static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = {
 111        4, {
 112                UNI_RANGE(10),
 113                UNI_RANGE(5),
 114                UNI_RANGE(2.5),
 115                UNI_RANGE(1.25)
 116        }
 117};
 118#endif
 119static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = {
 120        4, {
 121                UNI_RANGE(10),
 122                UNI_RANGE(1),
 123                UNI_RANGE(0.1),
 124                UNI_RANGE(0.02)
 125        }
 126};
 127
 128struct dt2801_board {
 129
 130        const char *name;
 131        int boardcode;
 132        int ad_diff;
 133        int ad_chan;
 134        int adbits;
 135        int adrangetype;
 136        int dabits;
 137};
 138
 139/* Typeid's for the different boards of the DT2801-series
 140   (taken from the test-software, that comes with the board)
 141   */
 142static const struct dt2801_board boardtypes[] = {
 143        {
 144         .name = "dt2801",
 145         .boardcode = 0x09,
 146         .ad_diff = 2,
 147         .ad_chan = 16,
 148         .adbits = 12,
 149         .adrangetype = 0,
 150         .dabits = 12},
 151        {
 152         .name = "dt2801-a",
 153         .boardcode = 0x52,
 154         .ad_diff = 2,
 155         .ad_chan = 16,
 156         .adbits = 12,
 157         .adrangetype = 0,
 158         .dabits = 12},
 159        {
 160         .name = "dt2801/5716a",
 161         .boardcode = 0x82,
 162         .ad_diff = 1,
 163         .ad_chan = 16,
 164         .adbits = 16,
 165         .adrangetype = 1,
 166         .dabits = 12},
 167        {
 168         .name = "dt2805",
 169         .boardcode = 0x12,
 170         .ad_diff = 1,
 171         .ad_chan = 16,
 172         .adbits = 12,
 173         .adrangetype = 0,
 174         .dabits = 12},
 175        {
 176         .name = "dt2805/5716a",
 177         .boardcode = 0x92,
 178         .ad_diff = 1,
 179         .ad_chan = 16,
 180         .adbits = 16,
 181         .adrangetype = 1,
 182         .dabits = 12},
 183        {
 184         .name = "dt2808",
 185         .boardcode = 0x20,
 186         .ad_diff = 0,
 187         .ad_chan = 16,
 188         .adbits = 12,
 189         .adrangetype = 2,
 190         .dabits = 8},
 191        {
 192         .name = "dt2818",
 193         .boardcode = 0xa2,
 194         .ad_diff = 0,
 195         .ad_chan = 4,
 196         .adbits = 12,
 197         .adrangetype = 0,
 198         .dabits = 12},
 199        {
 200         .name = "dt2809",
 201         .boardcode = 0xb0,
 202         .ad_diff = 0,
 203         .ad_chan = 8,
 204         .adbits = 12,
 205         .adrangetype = 1,
 206         .dabits = 12},
 207};
 208
 209struct dt2801_private {
 210        const struct comedi_lrange *dac_range_types[2];
 211};
 212
 213/* These are the low-level routines:
 214   writecommand: write a command to the board
 215   writedata: write data byte
 216   readdata: read data byte
 217 */
 218
 219/* Only checks DataOutReady-flag, not the Ready-flag as it is done
 220   in the examples of the manual. I don't see why this should be
 221   necessary. */
 222static int dt2801_readdata(struct comedi_device *dev, int *data)
 223{
 224        int stat = 0;
 225        int timeout = DT2801_TIMEOUT;
 226
 227        do {
 228                stat = inb_p(dev->iobase + DT2801_STATUS);
 229                if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY))
 230                        return stat;
 231                if (stat & DT_S_DATA_OUT_READY) {
 232                        *data = inb_p(dev->iobase + DT2801_DATA);
 233                        return 0;
 234                }
 235        } while (--timeout > 0);
 236
 237        return -ETIME;
 238}
 239
 240static int dt2801_readdata2(struct comedi_device *dev, int *data)
 241{
 242        int lb = 0;
 243        int hb = 0;
 244        int ret;
 245
 246        ret = dt2801_readdata(dev, &lb);
 247        if (ret)
 248                return ret;
 249        ret = dt2801_readdata(dev, &hb);
 250        if (ret)
 251                return ret;
 252
 253        *data = (hb << 8) + lb;
 254        return 0;
 255}
 256
 257static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
 258{
 259        int stat = 0;
 260        int timeout = DT2801_TIMEOUT;
 261
 262        do {
 263                stat = inb_p(dev->iobase + DT2801_STATUS);
 264
 265                if (stat & DT_S_COMPOSITE_ERROR)
 266                        return stat;
 267                if (!(stat & DT_S_DATA_IN_FULL)) {
 268                        outb_p(data & 0xff, dev->iobase + DT2801_DATA);
 269                        return 0;
 270                }
 271        } while (--timeout > 0);
 272
 273        return -ETIME;
 274}
 275
 276static int dt2801_writedata2(struct comedi_device *dev, unsigned int data)
 277{
 278        int ret;
 279
 280        ret = dt2801_writedata(dev, data & 0xff);
 281        if (ret < 0)
 282                return ret;
 283        ret = dt2801_writedata(dev, (data >> 8));
 284        if (ret < 0)
 285                return ret;
 286
 287        return 0;
 288}
 289
 290static int dt2801_wait_for_ready(struct comedi_device *dev)
 291{
 292        int timeout = DT2801_TIMEOUT;
 293        int stat;
 294
 295        stat = inb_p(dev->iobase + DT2801_STATUS);
 296        if (stat & DT_S_READY)
 297                return 0;
 298        do {
 299                stat = inb_p(dev->iobase + DT2801_STATUS);
 300
 301                if (stat & DT_S_COMPOSITE_ERROR)
 302                        return stat;
 303                if (stat & DT_S_READY)
 304                        return 0;
 305        } while (--timeout > 0);
 306
 307        return -ETIME;
 308}
 309
 310static void dt2801_writecmd(struct comedi_device *dev, int command)
 311{
 312        int stat;
 313
 314        dt2801_wait_for_ready(dev);
 315
 316        stat = inb_p(dev->iobase + DT2801_STATUS);
 317        if (stat & DT_S_COMPOSITE_ERROR) {
 318                dev_dbg(dev->class_dev,
 319                        "composite-error in %s, ignoring\n", __func__);
 320        }
 321        if (!(stat & DT_S_READY))
 322                dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__);
 323        outb_p(command, dev->iobase + DT2801_CMD);
 324}
 325
 326static int dt2801_reset(struct comedi_device *dev)
 327{
 328        int board_code = 0;
 329        unsigned int stat;
 330        int timeout;
 331
 332        /* pull random data from data port */
 333        inb_p(dev->iobase + DT2801_DATA);
 334        inb_p(dev->iobase + DT2801_DATA);
 335        inb_p(dev->iobase + DT2801_DATA);
 336        inb_p(dev->iobase + DT2801_DATA);
 337
 338        /* dt2801_writecmd(dev,DT_C_STOP); */
 339        outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
 340
 341        /* dt2801_wait_for_ready(dev); */
 342        udelay(100);
 343        timeout = 10000;
 344        do {
 345                stat = inb_p(dev->iobase + DT2801_STATUS);
 346                if (stat & DT_S_READY)
 347                        break;
 348        } while (timeout--);
 349        if (!timeout)
 350                dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat);
 351
 352        /* dt2801_readdata(dev,&board_code); */
 353
 354        outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
 355        /* dt2801_writecmd(dev,DT_C_RESET); */
 356
 357        udelay(100);
 358        timeout = 10000;
 359        do {
 360                stat = inb_p(dev->iobase + DT2801_STATUS);
 361                if (stat & DT_S_READY)
 362                        break;
 363        } while (timeout--);
 364        if (!timeout)
 365                dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat);
 366
 367        dt2801_readdata(dev, &board_code);
 368
 369        return board_code;
 370}
 371
 372static int probe_number_of_ai_chans(struct comedi_device *dev)
 373{
 374        int n_chans;
 375        int stat;
 376        int data;
 377
 378        for (n_chans = 0; n_chans < 16; n_chans++) {
 379                dt2801_writecmd(dev, DT_C_READ_ADIM);
 380                dt2801_writedata(dev, 0);
 381                dt2801_writedata(dev, n_chans);
 382                stat = dt2801_readdata2(dev, &data);
 383
 384                if (stat)
 385                        break;
 386        }
 387
 388        dt2801_reset(dev);
 389        dt2801_reset(dev);
 390
 391        return n_chans;
 392}
 393
 394static const struct comedi_lrange *dac_range_table[] = {
 395        &range_bipolar10,
 396        &range_bipolar5,
 397        &range_bipolar2_5,
 398        &range_unipolar10,
 399        &range_unipolar5
 400};
 401
 402static const struct comedi_lrange *dac_range_lkup(int opt)
 403{
 404        if (opt < 0 || opt >= 5)
 405                return &range_unknown;
 406        return dac_range_table[opt];
 407}
 408
 409static const struct comedi_lrange *ai_range_lkup(int type, int opt)
 410{
 411        switch (type) {
 412        case 0:
 413                return (opt) ?
 414                    &range_dt2801_ai_pgl_unipolar :
 415                    &range_dt2801_ai_pgl_bipolar;
 416        case 1:
 417                return (opt) ? &range_unipolar10 : &range_bipolar10;
 418        case 2:
 419                return &range_unipolar5;
 420        }
 421        return &range_unknown;
 422}
 423
 424static int dt2801_error(struct comedi_device *dev, int stat)
 425{
 426        if (stat < 0) {
 427                if (stat == -ETIME)
 428                        dev_dbg(dev->class_dev, "timeout\n");
 429                else
 430                        dev_dbg(dev->class_dev, "error %d\n", stat);
 431                return stat;
 432        }
 433        dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat);
 434
 435        dt2801_reset(dev);
 436        dt2801_reset(dev);
 437
 438        return -EIO;
 439}
 440
 441static int dt2801_ai_insn_read(struct comedi_device *dev,
 442                               struct comedi_subdevice *s,
 443                               struct comedi_insn *insn, unsigned int *data)
 444{
 445        int d;
 446        int stat;
 447        int i;
 448
 449        for (i = 0; i < insn->n; i++) {
 450                dt2801_writecmd(dev, DT_C_READ_ADIM);
 451                dt2801_writedata(dev, CR_RANGE(insn->chanspec));
 452                dt2801_writedata(dev, CR_CHAN(insn->chanspec));
 453                stat = dt2801_readdata2(dev, &d);
 454
 455                if (stat != 0)
 456                        return dt2801_error(dev, stat);
 457
 458                data[i] = d;
 459        }
 460
 461        return i;
 462}
 463
 464static int dt2801_ao_insn_write(struct comedi_device *dev,
 465                                struct comedi_subdevice *s,
 466                                struct comedi_insn *insn,
 467                                unsigned int *data)
 468{
 469        unsigned int chan = CR_CHAN(insn->chanspec);
 470
 471        dt2801_writecmd(dev, DT_C_WRITE_DAIM);
 472        dt2801_writedata(dev, chan);
 473        dt2801_writedata2(dev, data[0]);
 474
 475        s->readback[chan] = data[0];
 476
 477        return 1;
 478}
 479
 480static int dt2801_dio_insn_bits(struct comedi_device *dev,
 481                                struct comedi_subdevice *s,
 482                                struct comedi_insn *insn,
 483                                unsigned int *data)
 484{
 485        int which = (s == &dev->subdevices[3]) ? 1 : 0;
 486        unsigned int val = 0;
 487
 488        if (comedi_dio_update_state(s, data)) {
 489                dt2801_writecmd(dev, DT_C_WRITE_DIG);
 490                dt2801_writedata(dev, which);
 491                dt2801_writedata(dev, s->state);
 492        }
 493
 494        dt2801_writecmd(dev, DT_C_READ_DIG);
 495        dt2801_writedata(dev, which);
 496        dt2801_readdata(dev, &val);
 497
 498        data[1] = val;
 499
 500        return insn->n;
 501}
 502
 503static int dt2801_dio_insn_config(struct comedi_device *dev,
 504                                  struct comedi_subdevice *s,
 505                                  struct comedi_insn *insn,
 506                                  unsigned int *data)
 507{
 508        int ret;
 509
 510        ret = comedi_dio_insn_config(dev, s, insn, data, 0xff);
 511        if (ret)
 512                return ret;
 513
 514        dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN);
 515        dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0);
 516
 517        return insn->n;
 518}
 519
 520/*
 521   options:
 522        [0] - i/o base
 523        [1] - unused
 524        [2] - a/d 0=differential, 1=single-ended
 525        [3] - a/d range 0=[-10,10], 1=[0,10]
 526        [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
 527        [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
 528*/
 529static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 530{
 531        const struct dt2801_board *board;
 532        struct dt2801_private *devpriv;
 533        struct comedi_subdevice *s;
 534        int board_code, type;
 535        int ret = 0;
 536        int n_ai_chans;
 537
 538        ret = comedi_request_region(dev, it->options[0], 0x2);
 539        if (ret)
 540                return ret;
 541
 542        /* do some checking */
 543
 544        board_code = dt2801_reset(dev);
 545
 546        /* heh.  if it didn't work, try it again. */
 547        if (!board_code)
 548                board_code = dt2801_reset(dev);
 549
 550        for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
 551                if (boardtypes[type].boardcode == board_code)
 552                        goto havetype;
 553        }
 554        dev_dbg(dev->class_dev,
 555                "unrecognized board code=0x%02x, contact author\n", board_code);
 556        type = 0;
 557
 558havetype:
 559        dev->board_ptr = boardtypes + type;
 560        board = dev->board_ptr;
 561
 562        n_ai_chans = probe_number_of_ai_chans(dev);
 563
 564        ret = comedi_alloc_subdevices(dev, 4);
 565        if (ret)
 566                goto out;
 567
 568        devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
 569        if (!devpriv)
 570                return -ENOMEM;
 571
 572        dev->board_name = board->name;
 573
 574        s = &dev->subdevices[0];
 575        /* ai subdevice */
 576        s->type = COMEDI_SUBD_AI;
 577        s->subdev_flags = SDF_READABLE | SDF_GROUND;
 578#if 1
 579        s->n_chan = n_ai_chans;
 580#else
 581        if (it->options[2])
 582                s->n_chan = board->ad_chan;
 583        else
 584                s->n_chan = board->ad_chan / 2;
 585#endif
 586        s->maxdata = (1 << board->adbits) - 1;
 587        s->range_table = ai_range_lkup(board->adrangetype, it->options[3]);
 588        s->insn_read = dt2801_ai_insn_read;
 589
 590        s = &dev->subdevices[1];
 591        /* ao subdevice */
 592        s->type = COMEDI_SUBD_AO;
 593        s->subdev_flags = SDF_WRITABLE;
 594        s->n_chan = 2;
 595        s->maxdata = (1 << board->dabits) - 1;
 596        s->range_table_list = devpriv->dac_range_types;
 597        devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
 598        devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
 599        s->insn_write = dt2801_ao_insn_write;
 600        s->insn_read = comedi_readback_insn_read;
 601
 602        ret = comedi_alloc_subdev_readback(s);
 603        if (ret)
 604                return ret;
 605
 606        s = &dev->subdevices[2];
 607        /* 1st digital subdevice */
 608        s->type = COMEDI_SUBD_DIO;
 609        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 610        s->n_chan = 8;
 611        s->maxdata = 1;
 612        s->range_table = &range_digital;
 613        s->insn_bits = dt2801_dio_insn_bits;
 614        s->insn_config = dt2801_dio_insn_config;
 615
 616        s = &dev->subdevices[3];
 617        /* 2nd digital subdevice */
 618        s->type = COMEDI_SUBD_DIO;
 619        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 620        s->n_chan = 8;
 621        s->maxdata = 1;
 622        s->range_table = &range_digital;
 623        s->insn_bits = dt2801_dio_insn_bits;
 624        s->insn_config = dt2801_dio_insn_config;
 625
 626        ret = 0;
 627out:
 628        return ret;
 629}
 630
 631static struct comedi_driver dt2801_driver = {
 632        .driver_name    = "dt2801",
 633        .module         = THIS_MODULE,
 634        .attach         = dt2801_attach,
 635        .detach         = comedi_legacy_detach,
 636};
 637module_comedi_driver(dt2801_driver);
 638
 639MODULE_AUTHOR("Comedi http://www.comedi.org");
 640MODULE_DESCRIPTION("Comedi low-level driver");
 641MODULE_LICENSE("GPL");
 642