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

https://bitbucket.org/slukk/jb-tsm-kernel-4.2 · C · 737 lines · 551 code · 110 blank · 76 comment · 52 complexity · 6571c987dbad5978563d36ab065fdc27 MD5 · raw file

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