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