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