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
 228#define boardtype (*(const struct dt2801_board *)dev->board_ptr)
 229
 230struct dt2801_private {
 231
 232        const struct comedi_lrange *dac_range_types[2];
 233        unsigned int ao_readback[2];
 234};
 235
 236/* These are the low-level routines:
 237   writecommand: write a command to the board
 238   writedata: write data byte
 239   readdata: read data byte
 240 */
 241
 242/* Only checks DataOutReady-flag, not the Ready-flag as it is done
 243   in the examples of the manual. I don't see why this should be
 244   necessary. */
 245static int dt2801_readdata(struct comedi_device *dev, int *data)
 246{
 247        int stat = 0;
 248        int timeout = DT2801_TIMEOUT;
 249
 250        do {
 251                stat = inb_p(dev->iobase + DT2801_STATUS);
 252                if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY))
 253                        return stat;
 254                if (stat & DT_S_DATA_OUT_READY) {
 255                        *data = inb_p(dev->iobase + DT2801_DATA);
 256                        return 0;
 257                }
 258        } while (--timeout > 0);
 259
 260        return -ETIME;
 261}
 262
 263static int dt2801_readdata2(struct comedi_device *dev, int *data)
 264{
 265        int lb, hb;
 266        int ret;
 267
 268        ret = dt2801_readdata(dev, &lb);
 269        if (ret)
 270                return ret;
 271        ret = dt2801_readdata(dev, &hb);
 272        if (ret)
 273                return ret;
 274
 275        *data = (hb << 8) + lb;
 276        return 0;
 277}
 278
 279static int dt2801_writedata(struct comedi_device *dev, unsigned int data)
 280{
 281        int stat = 0;
 282        int timeout = DT2801_TIMEOUT;
 283
 284        do {
 285                stat = inb_p(dev->iobase + DT2801_STATUS);
 286
 287                if (stat & DT_S_COMPOSITE_ERROR)
 288                        return stat;
 289                if (!(stat & DT_S_DATA_IN_FULL)) {
 290                        outb_p(data & 0xff, dev->iobase + DT2801_DATA);
 291                        return 0;
 292                }
 293#if 0
 294                if (stat & DT_S_READY) {
 295                        printk
 296                            ("dt2801: ready flag set (bad!) in dt2801_writedata()\n");
 297                        return -EIO;
 298                }
 299#endif
 300        } while (--timeout > 0);
 301
 302        return -ETIME;
 303}
 304
 305static int dt2801_writedata2(struct comedi_device *dev, unsigned int data)
 306{
 307        int ret;
 308
 309        ret = dt2801_writedata(dev, data & 0xff);
 310        if (ret < 0)
 311                return ret;
 312        ret = dt2801_writedata(dev, (data >> 8));
 313        if (ret < 0)
 314                return ret;
 315
 316        return 0;
 317}
 318
 319static int dt2801_wait_for_ready(struct comedi_device *dev)
 320{
 321        int timeout = DT2801_TIMEOUT;
 322        int stat;
 323
 324        stat = inb_p(dev->iobase + DT2801_STATUS);
 325        if (stat & DT_S_READY)
 326                return 0;
 327        do {
 328                stat = inb_p(dev->iobase + DT2801_STATUS);
 329
 330                if (stat & DT_S_COMPOSITE_ERROR)
 331                        return stat;
 332                if (stat & DT_S_READY)
 333                        return 0;
 334        } while (--timeout > 0);
 335
 336        return -ETIME;
 337}
 338
 339static int dt2801_writecmd(struct comedi_device *dev, int command)
 340{
 341        int stat;
 342
 343        dt2801_wait_for_ready(dev);
 344
 345        stat = inb_p(dev->iobase + DT2801_STATUS);
 346        if (stat & DT_S_COMPOSITE_ERROR) {
 347                printk
 348                    ("dt2801: composite-error in dt2801_writecmd(), ignoring\n");
 349        }
 350        if (!(stat & DT_S_READY))
 351                printk("dt2801: !ready in dt2801_writecmd(), ignoring\n");
 352        outb_p(command, dev->iobase + DT2801_CMD);
 353
 354        return 0;
 355}
 356
 357static int dt2801_reset(struct comedi_device *dev)
 358{
 359        int board_code = 0;
 360        unsigned int stat;
 361        int timeout;
 362
 363        DPRINTK("dt2801: resetting board...\n");
 364        DPRINTK("fingerprint: 0x%02x 0x%02x\n", inb_p(dev->iobase),
 365                inb_p(dev->iobase + 1));
 366
 367        /* pull random data from data port */
 368        inb_p(dev->iobase + DT2801_DATA);
 369        inb_p(dev->iobase + DT2801_DATA);
 370        inb_p(dev->iobase + DT2801_DATA);
 371        inb_p(dev->iobase + DT2801_DATA);
 372
 373        DPRINTK("dt2801: stop\n");
 374        /* dt2801_writecmd(dev,DT_C_STOP); */
 375        outb_p(DT_C_STOP, dev->iobase + DT2801_CMD);
 376
 377        /* dt2801_wait_for_ready(dev); */
 378        udelay(100);
 379        timeout = 10000;
 380        do {
 381                stat = inb_p(dev->iobase + DT2801_STATUS);
 382                if (stat & DT_S_READY)
 383                        break;
 384        } while (timeout--);
 385        if (!timeout)
 386                printk("dt2801: timeout 1 status=0x%02x\n", stat);
 387
 388        /* printk("dt2801: reading dummy\n"); */
 389        /* dt2801_readdata(dev,&board_code); */
 390
 391        DPRINTK("dt2801: reset\n");
 392        outb_p(DT_C_RESET, dev->iobase + DT2801_CMD);
 393        /* dt2801_writecmd(dev,DT_C_RESET); */
 394
 395        udelay(100);
 396        timeout = 10000;
 397        do {
 398                stat = inb_p(dev->iobase + DT2801_STATUS);
 399                if (stat & DT_S_READY)
 400                        break;
 401        } while (timeout--);
 402        if (!timeout)
 403                printk("dt2801: timeout 2 status=0x%02x\n", stat);
 404
 405        DPRINTK("dt2801: reading code\n");
 406        dt2801_readdata(dev, &board_code);
 407
 408        DPRINTK("dt2801: ok.  code=0x%02x\n", board_code);
 409
 410        return board_code;
 411}
 412
 413static int probe_number_of_ai_chans(struct comedi_device *dev)
 414{
 415        int n_chans;
 416        int stat;
 417        int data;
 418
 419        for (n_chans = 0; n_chans < 16; n_chans++) {
 420                stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
 421                dt2801_writedata(dev, 0);
 422                dt2801_writedata(dev, n_chans);
 423                stat = dt2801_readdata2(dev, &data);
 424
 425                if (stat)
 426                        break;
 427        }
 428
 429        dt2801_reset(dev);
 430        dt2801_reset(dev);
 431
 432        return n_chans;
 433}
 434
 435static const struct comedi_lrange *dac_range_table[] = {
 436        &range_bipolar10,
 437        &range_bipolar5,
 438        &range_bipolar2_5,
 439        &range_unipolar10,
 440        &range_unipolar5
 441};
 442
 443static const struct comedi_lrange *dac_range_lkup(int opt)
 444{
 445        if (opt < 0 || opt >= 5)
 446                return &range_unknown;
 447        return dac_range_table[opt];
 448}
 449
 450static const struct comedi_lrange *ai_range_lkup(int type, int opt)
 451{
 452        switch (type) {
 453        case 0:
 454                return (opt) ?
 455                    &range_dt2801_ai_pgl_unipolar :
 456                    &range_dt2801_ai_pgl_bipolar;
 457        case 1:
 458                return (opt) ? &range_unipolar10 : &range_bipolar10;
 459        case 2:
 460                return &range_unipolar5;
 461        }
 462        return &range_unknown;
 463}
 464
 465static int dt2801_error(struct comedi_device *dev, int stat)
 466{
 467        if (stat < 0) {
 468                if (stat == -ETIME)
 469                        printk("dt2801: timeout\n");
 470                else
 471                        printk("dt2801: error %d\n", stat);
 472                return stat;
 473        }
 474        printk("dt2801: error status 0x%02x, resetting...\n", stat);
 475
 476        dt2801_reset(dev);
 477        dt2801_reset(dev);
 478
 479        return -EIO;
 480}
 481
 482static int dt2801_ai_insn_read(struct comedi_device *dev,
 483                               struct comedi_subdevice *s,
 484                               struct comedi_insn *insn, unsigned int *data)
 485{
 486        int d;
 487        int stat;
 488        int i;
 489
 490        for (i = 0; i < insn->n; i++) {
 491                stat = dt2801_writecmd(dev, DT_C_READ_ADIM);
 492                dt2801_writedata(dev, CR_RANGE(insn->chanspec));
 493                dt2801_writedata(dev, CR_CHAN(insn->chanspec));
 494                stat = dt2801_readdata2(dev, &d);
 495
 496                if (stat != 0)
 497                        return dt2801_error(dev, stat);
 498
 499                data[i] = d;
 500        }
 501
 502        return i;
 503}
 504
 505static int dt2801_ao_insn_read(struct comedi_device *dev,
 506                               struct comedi_subdevice *s,
 507                               struct comedi_insn *insn, unsigned int *data)
 508{
 509        struct dt2801_private *devpriv = dev->private;
 510
 511        data[0] = devpriv->ao_readback[CR_CHAN(insn->chanspec)];
 512
 513        return 1;
 514}
 515
 516static int dt2801_ao_insn_write(struct comedi_device *dev,
 517                                struct comedi_subdevice *s,
 518                                struct comedi_insn *insn, unsigned int *data)
 519{
 520        struct dt2801_private *devpriv = dev->private;
 521
 522        dt2801_writecmd(dev, DT_C_WRITE_DAIM);
 523        dt2801_writedata(dev, CR_CHAN(insn->chanspec));
 524        dt2801_writedata2(dev, data[0]);
 525
 526        devpriv->ao_readback[CR_CHAN(insn->chanspec)] = data[0];
 527
 528        return 1;
 529}
 530
 531static int dt2801_dio_insn_bits(struct comedi_device *dev,
 532                                struct comedi_subdevice *s,
 533                                struct comedi_insn *insn, unsigned int *data)
 534{
 535        int which = 0;
 536
 537        if (s == &dev->subdevices[3])
 538                which = 1;
 539
 540        if (data[0]) {
 541                s->state &= ~data[0];
 542                s->state |= (data[0] & data[1]);
 543                dt2801_writecmd(dev, DT_C_WRITE_DIG);
 544                dt2801_writedata(dev, which);
 545                dt2801_writedata(dev, s->state);
 546        }
 547        dt2801_writecmd(dev, DT_C_READ_DIG);
 548        dt2801_writedata(dev, which);
 549        dt2801_readdata(dev, data + 1);
 550
 551        return insn->n;
 552}
 553
 554static int dt2801_dio_insn_config(struct comedi_device *dev,
 555                                  struct comedi_subdevice *s,
 556                                  struct comedi_insn *insn, unsigned int *data)
 557{
 558        int which = 0;
 559
 560        if (s == &dev->subdevices[3])
 561                which = 1;
 562
 563        /* configure */
 564        switch (data[0]) {
 565        case INSN_CONFIG_DIO_OUTPUT:
 566                s->io_bits = 0xff;
 567                dt2801_writecmd(dev, DT_C_SET_DIGOUT);
 568                break;
 569        case INSN_CONFIG_DIO_INPUT:
 570                s->io_bits = 0;
 571                dt2801_writecmd(dev, DT_C_SET_DIGIN);
 572                break;
 573        case INSN_CONFIG_DIO_QUERY:
 574                data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
 575                return insn->n;
 576        default:
 577                return -EINVAL;
 578        }
 579        dt2801_writedata(dev, which);
 580
 581        return 1;
 582}
 583
 584/*
 585   options:
 586        [0] - i/o base
 587        [1] - unused
 588        [2] - a/d 0=differential, 1=single-ended
 589        [3] - a/d range 0=[-10,10], 1=[0,10]
 590        [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
 591        [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5]
 592*/
 593static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it)
 594{
 595        struct dt2801_private *devpriv;
 596        struct comedi_subdevice *s;
 597        unsigned long iobase;
 598        int board_code, type;
 599        int ret = 0;
 600        int n_ai_chans;
 601
 602        iobase = it->options[0];
 603        if (!request_region(iobase, DT2801_IOSIZE, "dt2801")) {
 604                comedi_error(dev, "I/O port conflict");
 605                return -EIO;
 606        }
 607        dev->iobase = iobase;
 608
 609        /* do some checking */
 610
 611        board_code = dt2801_reset(dev);
 612
 613        /* heh.  if it didn't work, try it again. */
 614        if (!board_code)
 615                board_code = dt2801_reset(dev);
 616
 617        for (type = 0; type < ARRAY_SIZE(boardtypes); type++) {
 618                if (boardtypes[type].boardcode == board_code)
 619                        goto havetype;
 620        }
 621        printk("dt2801: unrecognized board code=0x%02x, contact author\n",
 622               board_code);
 623        type = 0;
 624
 625havetype:
 626        dev->board_ptr = boardtypes + type;
 627        printk("dt2801: %s at port 0x%lx", boardtype.name, iobase);
 628
 629        n_ai_chans = probe_number_of_ai_chans(dev);
 630        printk(" (ai channels = %d)\n", n_ai_chans);
 631
 632        ret = comedi_alloc_subdevices(dev, 4);
 633        if (ret)
 634                goto out;
 635
 636        devpriv = kzalloc(sizeof(*devpriv), GFP_KERNEL);
 637        if (!devpriv)
 638                return -ENOMEM;
 639        dev->private = devpriv;
 640
 641        dev->board_name = boardtype.name;
 642
 643        s = &dev->subdevices[0];
 644        /* ai subdevice */
 645        s->type = COMEDI_SUBD_AI;
 646        s->subdev_flags = SDF_READABLE | SDF_GROUND;
 647#if 1
 648        s->n_chan = n_ai_chans;
 649#else
 650        if (it->options[2])
 651                s->n_chan = boardtype.ad_chan;
 652        else
 653                s->n_chan = boardtype.ad_chan / 2;
 654#endif
 655        s->maxdata = (1 << boardtype.adbits) - 1;
 656        s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]);
 657        s->insn_read = dt2801_ai_insn_read;
 658
 659        s = &dev->subdevices[1];
 660        /* ao subdevice */
 661        s->type = COMEDI_SUBD_AO;
 662        s->subdev_flags = SDF_WRITABLE;
 663        s->n_chan = 2;
 664        s->maxdata = (1 << boardtype.dabits) - 1;
 665        s->range_table_list = devpriv->dac_range_types;
 666        devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]);
 667        devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]);
 668        s->insn_read = dt2801_ao_insn_read;
 669        s->insn_write = dt2801_ao_insn_write;
 670
 671        s = &dev->subdevices[2];
 672        /* 1st digital subdevice */
 673        s->type = COMEDI_SUBD_DIO;
 674        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 675        s->n_chan = 8;
 676        s->maxdata = 1;
 677        s->range_table = &range_digital;
 678        s->insn_bits = dt2801_dio_insn_bits;
 679        s->insn_config = dt2801_dio_insn_config;
 680
 681        s = &dev->subdevices[3];
 682        /* 2nd digital subdevice */
 683        s->type = COMEDI_SUBD_DIO;
 684        s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
 685        s->n_chan = 8;
 686        s->maxdata = 1;
 687        s->range_table = &range_digital;
 688        s->insn_bits = dt2801_dio_insn_bits;
 689        s->insn_config = dt2801_dio_insn_config;
 690
 691        ret = 0;
 692out:
 693        return ret;
 694}
 695
 696static void dt2801_detach(struct comedi_device *dev)
 697{
 698        if (dev->iobase)
 699                release_region(dev->iobase, DT2801_IOSIZE);
 700}
 701
 702static struct comedi_driver dt2801_driver = {
 703        .driver_name    = "dt2801",
 704        .module         = THIS_MODULE,
 705        .attach         = dt2801_attach,
 706        .detach         = dt2801_detach,
 707};
 708module_comedi_driver(dt2801_driver);
 709
 710MODULE_AUTHOR("Comedi http://www.comedi.org");
 711MODULE_DESCRIPTION("Comedi low-level driver");
 712MODULE_LICENSE("GPL");
 713