root/drivers/staging/comedi/drivers/dt2801.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dt2801_readdata
  2. dt2801_readdata2
  3. dt2801_writedata
  4. dt2801_writedata2
  5. dt2801_wait_for_ready
  6. dt2801_writecmd
  7. dt2801_reset
  8. probe_number_of_ai_chans
  9. dac_range_lkup
  10. ai_range_lkup
  11. dt2801_error
  12. dt2801_ai_insn_read
  13. dt2801_ao_insn_write
  14. dt2801_dio_insn_bits
  15. dt2801_dio_insn_config
  16. dt2801_attach

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

/* [<][>][^][v][top][bottom][index][help] */