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