PageRenderTime 32ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

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

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