cb_pcidda.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419
  1. // SPDX-License-Identifier: GPL-2.0+
  2. /*
  3. * comedi/drivers/cb_pcidda.c
  4. * Driver for the ComputerBoards / MeasurementComputing PCI-DDA series.
  5. *
  6. * Copyright (C) 2001 Ivan Martinez <ivanmr@altavista.com>
  7. * Copyright (C) 2001 Frank Mori Hess <fmhess@users.sourceforge.net>
  8. *
  9. * COMEDI - Linux Control and Measurement Device Interface
  10. * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
  11. */
  12. /*
  13. * Driver: cb_pcidda
  14. * Description: MeasurementComputing PCI-DDA series
  15. * Devices: [Measurement Computing] PCI-DDA08/12 (pci-dda08/12),
  16. * PCI-DDA04/12 (pci-dda04/12), PCI-DDA02/12 (pci-dda02/12),
  17. * PCI-DDA08/16 (pci-dda08/16), PCI-DDA04/16 (pci-dda04/16),
  18. * PCI-DDA02/16 (pci-dda02/16)
  19. * Author: Ivan Martinez <ivanmr@altavista.com>
  20. * Frank Mori Hess <fmhess@users.sourceforge.net>
  21. * Status: works
  22. *
  23. * Configuration options: not applicable, uses PCI auto config
  24. *
  25. * Only simple analog output writing is supported.
  26. */
  27. #include <linux/module.h>
  28. #include <linux/comedi/comedi_pci.h>
  29. #include <linux/comedi/comedi_8255.h>
  30. #define EEPROM_SIZE 128 /* number of entries in eeprom */
  31. /* maximum number of ao channels for supported boards */
  32. #define MAX_AO_CHANNELS 8
  33. /* Digital I/O registers */
  34. #define CB_DDA_DIO0_8255_BASE 0x00
  35. #define CB_DDA_DIO1_8255_BASE 0x04
  36. /* DAC registers */
  37. #define CB_DDA_DA_CTRL_REG 0x00 /* D/A Control Register */
  38. #define CB_DDA_DA_CTRL_SU BIT(0) /* Simultaneous update */
  39. #define CB_DDA_DA_CTRL_EN BIT(1) /* Enable specified DAC */
  40. #define CB_DDA_DA_CTRL_DAC(x) ((x) << 2) /* Specify DAC channel */
  41. #define CB_DDA_DA_CTRL_RANGE2V5 (0 << 6) /* 2.5V range */
  42. #define CB_DDA_DA_CTRL_RANGE5V (2 << 6) /* 5V range */
  43. #define CB_DDA_DA_CTRL_RANGE10V (3 << 6) /* 10V range */
  44. #define CB_DDA_DA_CTRL_UNIP BIT(8) /* Unipolar range */
  45. #define DACALIBRATION1 4 /* D/A CALIBRATION REGISTER 1 */
  46. /* write bits */
  47. /* serial data input for eeprom, caldacs, reference dac */
  48. #define SERIAL_IN_BIT 0x1
  49. #define CAL_CHANNEL_MASK (0x7 << 1)
  50. #define CAL_CHANNEL_BITS(channel) (((channel) << 1) & CAL_CHANNEL_MASK)
  51. /* read bits */
  52. #define CAL_COUNTER_MASK 0x1f
  53. /* calibration counter overflow status bit */
  54. #define CAL_COUNTER_OVERFLOW_BIT 0x20
  55. /* analog output is less than reference dac voltage */
  56. #define AO_BELOW_REF_BIT 0x40
  57. #define SERIAL_OUT_BIT 0x80 /* serial data out, for reading from eeprom */
  58. #define DACALIBRATION2 6 /* D/A CALIBRATION REGISTER 2 */
  59. #define SELECT_EEPROM_BIT 0x1 /* send serial data in to eeprom */
  60. /* don't send serial data to MAX542 reference dac */
  61. #define DESELECT_REF_DAC_BIT 0x2
  62. /* don't send serial data to caldac n */
  63. #define DESELECT_CALDAC_BIT(n) (0x4 << (n))
  64. /* manual says to set this bit with no explanation */
  65. #define DUMMY_BIT 0x40
  66. #define CB_DDA_DA_DATA_REG(x) (0x08 + ((x) * 2))
  67. /* Offsets for the caldac channels */
  68. #define CB_DDA_CALDAC_FINE_GAIN 0
  69. #define CB_DDA_CALDAC_COURSE_GAIN 1
  70. #define CB_DDA_CALDAC_COURSE_OFFSET 2
  71. #define CB_DDA_CALDAC_FINE_OFFSET 3
  72. static const struct comedi_lrange cb_pcidda_ranges = {
  73. 6, {
  74. BIP_RANGE(10),
  75. BIP_RANGE(5),
  76. BIP_RANGE(2.5),
  77. UNI_RANGE(10),
  78. UNI_RANGE(5),
  79. UNI_RANGE(2.5)
  80. }
  81. };
  82. enum cb_pcidda_boardid {
  83. BOARD_DDA02_12,
  84. BOARD_DDA04_12,
  85. BOARD_DDA08_12,
  86. BOARD_DDA02_16,
  87. BOARD_DDA04_16,
  88. BOARD_DDA08_16,
  89. };
  90. struct cb_pcidda_board {
  91. const char *name;
  92. int ao_chans;
  93. int ao_bits;
  94. };
  95. static const struct cb_pcidda_board cb_pcidda_boards[] = {
  96. [BOARD_DDA02_12] = {
  97. .name = "pci-dda02/12",
  98. .ao_chans = 2,
  99. .ao_bits = 12,
  100. },
  101. [BOARD_DDA04_12] = {
  102. .name = "pci-dda04/12",
  103. .ao_chans = 4,
  104. .ao_bits = 12,
  105. },
  106. [BOARD_DDA08_12] = {
  107. .name = "pci-dda08/12",
  108. .ao_chans = 8,
  109. .ao_bits = 12,
  110. },
  111. [BOARD_DDA02_16] = {
  112. .name = "pci-dda02/16",
  113. .ao_chans = 2,
  114. .ao_bits = 16,
  115. },
  116. [BOARD_DDA04_16] = {
  117. .name = "pci-dda04/16",
  118. .ao_chans = 4,
  119. .ao_bits = 16,
  120. },
  121. [BOARD_DDA08_16] = {
  122. .name = "pci-dda08/16",
  123. .ao_chans = 8,
  124. .ao_bits = 16,
  125. },
  126. };
  127. struct cb_pcidda_private {
  128. unsigned long daqio;
  129. /* bits last written to da calibration register 1 */
  130. unsigned int dac_cal1_bits;
  131. /* current range settings for output channels */
  132. unsigned int ao_range[MAX_AO_CHANNELS];
  133. u16 eeprom_data[EEPROM_SIZE]; /* software copy of board's eeprom */
  134. };
  135. /* lowlevel read from eeprom */
  136. static unsigned int cb_pcidda_serial_in(struct comedi_device *dev)
  137. {
  138. struct cb_pcidda_private *devpriv = dev->private;
  139. unsigned int value = 0;
  140. int i;
  141. const int value_width = 16; /* number of bits wide values are */
  142. for (i = 1; i <= value_width; i++) {
  143. /* read bits most significant bit first */
  144. if (inw_p(devpriv->daqio + DACALIBRATION1) & SERIAL_OUT_BIT)
  145. value |= 1 << (value_width - i);
  146. }
  147. return value;
  148. }
  149. /* lowlevel write to eeprom/dac */
  150. static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value,
  151. unsigned int num_bits)
  152. {
  153. struct cb_pcidda_private *devpriv = dev->private;
  154. int i;
  155. for (i = 1; i <= num_bits; i++) {
  156. /* send bits most significant bit first */
  157. if (value & (1 << (num_bits - i)))
  158. devpriv->dac_cal1_bits |= SERIAL_IN_BIT;
  159. else
  160. devpriv->dac_cal1_bits &= ~SERIAL_IN_BIT;
  161. outw_p(devpriv->dac_cal1_bits, devpriv->daqio + DACALIBRATION1);
  162. }
  163. }
  164. /* reads a 16 bit value from board's eeprom */
  165. static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev,
  166. unsigned int address)
  167. {
  168. struct cb_pcidda_private *devpriv = dev->private;
  169. unsigned int i;
  170. unsigned int cal2_bits;
  171. unsigned int value;
  172. /* one caldac for every two dac channels */
  173. const int max_num_caldacs = 4;
  174. /* bits to send to tell eeprom we want to read */
  175. const int read_instruction = 0x6;
  176. const int instruction_length = 3;
  177. const int address_length = 8;
  178. /* send serial output stream to eeprom */
  179. cal2_bits = SELECT_EEPROM_BIT | DESELECT_REF_DAC_BIT | DUMMY_BIT;
  180. /* deactivate caldacs (one caldac for every two channels) */
  181. for (i = 0; i < max_num_caldacs; i++)
  182. cal2_bits |= DESELECT_CALDAC_BIT(i);
  183. outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
  184. /* tell eeprom we want to read */
  185. cb_pcidda_serial_out(dev, read_instruction, instruction_length);
  186. /* send address we want to read from */
  187. cb_pcidda_serial_out(dev, address, address_length);
  188. value = cb_pcidda_serial_in(dev);
  189. /* deactivate eeprom */
  190. cal2_bits &= ~SELECT_EEPROM_BIT;
  191. outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
  192. return value;
  193. }
  194. /* writes to 8 bit calibration dacs */
  195. static void cb_pcidda_write_caldac(struct comedi_device *dev,
  196. unsigned int caldac, unsigned int channel,
  197. unsigned int value)
  198. {
  199. struct cb_pcidda_private *devpriv = dev->private;
  200. unsigned int cal2_bits;
  201. unsigned int i;
  202. /* caldacs use 3 bit channel specification */
  203. const int num_channel_bits = 3;
  204. const int num_caldac_bits = 8; /* 8 bit calibration dacs */
  205. /* one caldac for every two dac channels */
  206. const int max_num_caldacs = 4;
  207. /* write 3 bit channel */
  208. cb_pcidda_serial_out(dev, channel, num_channel_bits);
  209. /* write 8 bit caldac value */
  210. cb_pcidda_serial_out(dev, value, num_caldac_bits);
  211. /*
  212. * latch stream into appropriate caldac deselect reference dac
  213. */
  214. cal2_bits = DESELECT_REF_DAC_BIT | DUMMY_BIT;
  215. /* deactivate caldacs (one caldac for every two channels) */
  216. for (i = 0; i < max_num_caldacs; i++)
  217. cal2_bits |= DESELECT_CALDAC_BIT(i);
  218. /* activate the caldac we want */
  219. cal2_bits &= ~DESELECT_CALDAC_BIT(caldac);
  220. outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
  221. /* deactivate caldac */
  222. cal2_bits |= DESELECT_CALDAC_BIT(caldac);
  223. outw_p(cal2_bits, devpriv->daqio + DACALIBRATION2);
  224. }
  225. /* set caldacs to eeprom values for given channel and range */
  226. static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel,
  227. unsigned int range)
  228. {
  229. struct cb_pcidda_private *devpriv = dev->private;
  230. unsigned int caldac = channel / 2; /* two caldacs per channel */
  231. unsigned int chan = 4 * (channel % 2); /* caldac channel base */
  232. unsigned int index = 2 * range + 12 * channel;
  233. unsigned int offset;
  234. unsigned int gain;
  235. /* save range so we can tell when we need to readjust calibration */
  236. devpriv->ao_range[channel] = range;
  237. /* get values from eeprom data */
  238. offset = devpriv->eeprom_data[0x7 + index];
  239. gain = devpriv->eeprom_data[0x8 + index];
  240. /* set caldacs */
  241. cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_OFFSET,
  242. (offset >> 8) & 0xff);
  243. cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_OFFSET,
  244. offset & 0xff);
  245. cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_COURSE_GAIN,
  246. (gain >> 8) & 0xff);
  247. cb_pcidda_write_caldac(dev, caldac, chan + CB_DDA_CALDAC_FINE_GAIN,
  248. gain & 0xff);
  249. }
  250. static int cb_pcidda_ao_insn_write(struct comedi_device *dev,
  251. struct comedi_subdevice *s,
  252. struct comedi_insn *insn,
  253. unsigned int *data)
  254. {
  255. struct cb_pcidda_private *devpriv = dev->private;
  256. unsigned int channel = CR_CHAN(insn->chanspec);
  257. unsigned int range = CR_RANGE(insn->chanspec);
  258. unsigned int ctrl;
  259. unsigned int i;
  260. if (range != devpriv->ao_range[channel])
  261. cb_pcidda_calibrate(dev, channel, range);
  262. ctrl = CB_DDA_DA_CTRL_EN | CB_DDA_DA_CTRL_DAC(channel);
  263. switch (range) {
  264. case 0:
  265. case 3:
  266. ctrl |= CB_DDA_DA_CTRL_RANGE10V;
  267. break;
  268. case 1:
  269. case 4:
  270. ctrl |= CB_DDA_DA_CTRL_RANGE5V;
  271. break;
  272. case 2:
  273. case 5:
  274. ctrl |= CB_DDA_DA_CTRL_RANGE2V5;
  275. break;
  276. }
  277. if (range > 2)
  278. ctrl |= CB_DDA_DA_CTRL_UNIP;
  279. outw(ctrl, devpriv->daqio + CB_DDA_DA_CTRL_REG);
  280. for (i = 0; i < insn->n; i++)
  281. outw(data[i], devpriv->daqio + CB_DDA_DA_DATA_REG(channel));
  282. return insn->n;
  283. }
  284. static int cb_pcidda_auto_attach(struct comedi_device *dev,
  285. unsigned long context)
  286. {
  287. struct pci_dev *pcidev = comedi_to_pci_dev(dev);
  288. const struct cb_pcidda_board *board = NULL;
  289. struct cb_pcidda_private *devpriv;
  290. struct comedi_subdevice *s;
  291. int i;
  292. int ret;
  293. if (context < ARRAY_SIZE(cb_pcidda_boards))
  294. board = &cb_pcidda_boards[context];
  295. if (!board)
  296. return -ENODEV;
  297. dev->board_ptr = board;
  298. dev->board_name = board->name;
  299. devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
  300. if (!devpriv)
  301. return -ENOMEM;
  302. ret = comedi_pci_enable(dev);
  303. if (ret)
  304. return ret;
  305. dev->iobase = pci_resource_start(pcidev, 2);
  306. devpriv->daqio = pci_resource_start(pcidev, 3);
  307. ret = comedi_alloc_subdevices(dev, 3);
  308. if (ret)
  309. return ret;
  310. s = &dev->subdevices[0];
  311. /* analog output subdevice */
  312. s->type = COMEDI_SUBD_AO;
  313. s->subdev_flags = SDF_WRITABLE;
  314. s->n_chan = board->ao_chans;
  315. s->maxdata = (1 << board->ao_bits) - 1;
  316. s->range_table = &cb_pcidda_ranges;
  317. s->insn_write = cb_pcidda_ao_insn_write;
  318. /* two 8255 digital io subdevices */
  319. for (i = 0; i < 2; i++) {
  320. s = &dev->subdevices[1 + i];
  321. ret = subdev_8255_io_init(dev, s, i * I8255_SIZE);
  322. if (ret)
  323. return ret;
  324. }
  325. /* Read the caldac eeprom data */
  326. for (i = 0; i < EEPROM_SIZE; i++)
  327. devpriv->eeprom_data[i] = cb_pcidda_read_eeprom(dev, i);
  328. /* set calibrations dacs */
  329. for (i = 0; i < board->ao_chans; i++)
  330. cb_pcidda_calibrate(dev, i, devpriv->ao_range[i]);
  331. return 0;
  332. }
  333. static struct comedi_driver cb_pcidda_driver = {
  334. .driver_name = "cb_pcidda",
  335. .module = THIS_MODULE,
  336. .auto_attach = cb_pcidda_auto_attach,
  337. .detach = comedi_pci_detach,
  338. };
  339. static int cb_pcidda_pci_probe(struct pci_dev *dev,
  340. const struct pci_device_id *id)
  341. {
  342. return comedi_pci_auto_config(dev, &cb_pcidda_driver,
  343. id->driver_data);
  344. }
  345. static const struct pci_device_id cb_pcidda_pci_table[] = {
  346. { PCI_VDEVICE(CB, 0x0020), BOARD_DDA02_12 },
  347. { PCI_VDEVICE(CB, 0x0021), BOARD_DDA04_12 },
  348. { PCI_VDEVICE(CB, 0x0022), BOARD_DDA08_12 },
  349. { PCI_VDEVICE(CB, 0x0023), BOARD_DDA02_16 },
  350. { PCI_VDEVICE(CB, 0x0024), BOARD_DDA04_16 },
  351. { PCI_VDEVICE(CB, 0x0025), BOARD_DDA08_16 },
  352. { 0 }
  353. };
  354. MODULE_DEVICE_TABLE(pci, cb_pcidda_pci_table);
  355. static struct pci_driver cb_pcidda_pci_driver = {
  356. .name = "cb_pcidda",
  357. .id_table = cb_pcidda_pci_table,
  358. .probe = cb_pcidda_pci_probe,
  359. .remove = comedi_pci_auto_unconfig,
  360. };
  361. module_comedi_pci_driver(cb_pcidda_driver, cb_pcidda_pci_driver);
  362. MODULE_AUTHOR("Comedi https://www.comedi.org");
  363. MODULE_DESCRIPTION("Comedi low-level driver");
  364. MODULE_LICENSE("GPL");