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