1/* 2 * comedi/drivers/me_daq.c 3 * Hardware driver for Meilhaus data acquisition cards: 4 * ME-2000i, ME-2600i, ME-3000vm1 5 * 6 * Copyright (C) 2002 Michael Hillmann <hillmann@syscongroup.de> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 */ 18 19/* 20 * Driver: me_daq 21 * Description: Meilhaus PCI data acquisition cards 22 * Devices: (Meilhaus) ME-2600i [me-2600i] 23 * (Meilhaus) ME-2000i [me-2000i] 24 * Author: Michael Hillmann <hillmann@syscongroup.de> 25 * Status: experimental 26 * 27 * Configuration options: not applicable, uses PCI auto config 28 * 29 * Supports: 30 * Analog Input, Analog Output, Digital I/O 31 */ 32 33#include <linux/module.h> 34#include <linux/pci.h> 35#include <linux/interrupt.h> 36#include <linux/sched.h> 37 38#include "../comedidev.h" 39 40#include "plx9052.h" 41 42#define ME2600_FIRMWARE "me2600_firmware.bin" 43 44#define XILINX_DOWNLOAD_RESET 0x42 /* Xilinx registers */ 45 46#define ME_CONTROL_1 0x0000 /* - | W */ 47#define INTERRUPT_ENABLE (1<<15) 48#define COUNTER_B_IRQ (1<<12) 49#define COUNTER_A_IRQ (1<<11) 50#define CHANLIST_READY_IRQ (1<<10) 51#define EXT_IRQ (1<<9) 52#define ADFIFO_HALFFULL_IRQ (1<<8) 53#define SCAN_COUNT_ENABLE (1<<5) 54#define SIMULTANEOUS_ENABLE (1<<4) 55#define TRIGGER_FALLING_EDGE (1<<3) 56#define CONTINUOUS_MODE (1<<2) 57#define DISABLE_ADC (0<<0) 58#define SOFTWARE_TRIGGERED_ADC (1<<0) 59#define SCAN_TRIGGERED_ADC (2<<0) 60#define EXT_TRIGGERED_ADC (3<<0) 61#define ME_ADC_START 0x0000 /* R | - */ 62#define ME_CONTROL_2 0x0002 /* - | W */ 63#define ENABLE_ADFIFO (1<<10) 64#define ENABLE_CHANLIST (1<<9) 65#define ENABLE_PORT_B (1<<7) 66#define ENABLE_PORT_A (1<<6) 67#define ENABLE_COUNTER_B (1<<4) 68#define ENABLE_COUNTER_A (1<<3) 69#define ENABLE_DAC (1<<1) 70#define BUFFERED_DAC (1<<0) 71#define ME_DAC_UPDATE 0x0002 /* R | - */ 72#define ME_STATUS 0x0004 /* R | - */ 73#define COUNTER_B_IRQ_PENDING (1<<12) 74#define COUNTER_A_IRQ_PENDING (1<<11) 75#define CHANLIST_READY_IRQ_PENDING (1<<10) 76#define EXT_IRQ_PENDING (1<<9) 77#define ADFIFO_HALFFULL_IRQ_PENDING (1<<8) 78#define ADFIFO_FULL (1<<4) 79#define ADFIFO_HALFFULL (1<<3) 80#define ADFIFO_EMPTY (1<<2) 81#define CHANLIST_FULL (1<<1) 82#define FST_ACTIVE (1<<0) 83#define ME_RESET_INTERRUPT 0x0004 /* - | W */ 84#define ME_DIO_PORT_A 0x0006 /* R | W */ 85#define ME_DIO_PORT_B 0x0008 /* R | W */ 86#define ME_TIMER_DATA_0 0x000A /* - | W */ 87#define ME_TIMER_DATA_1 0x000C /* - | W */ 88#define ME_TIMER_DATA_2 0x000E /* - | W */ 89#define ME_CHANNEL_LIST 0x0010 /* - | W */ 90#define ADC_UNIPOLAR (1<<6) 91#define ADC_GAIN_0 (0<<4) 92#define ADC_GAIN_1 (1<<4) 93#define ADC_GAIN_2 (2<<4) 94#define ADC_GAIN_3 (3<<4) 95#define ME_READ_AD_FIFO 0x0010 /* R | - */ 96#define ME_DAC_CONTROL 0x0012 /* - | W */ 97#define DAC_UNIPOLAR_D (0<<4) 98#define DAC_BIPOLAR_D (1<<4) 99#define DAC_UNIPOLAR_C (0<<5) 100#define DAC_BIPOLAR_C (1<<5) 101#define DAC_UNIPOLAR_B (0<<6) 102#define DAC_BIPOLAR_B (1<<6) 103#define DAC_UNIPOLAR_A (0<<7) 104#define DAC_BIPOLAR_A (1<<7) 105#define DAC_GAIN_0_D (0<<8) 106#define DAC_GAIN_1_D (1<<8) 107#define DAC_GAIN_0_C (0<<9) 108#define DAC_GAIN_1_C (1<<9) 109#define DAC_GAIN_0_B (0<<10) 110#define DAC_GAIN_1_B (1<<10) 111#define DAC_GAIN_0_A (0<<11) 112#define DAC_GAIN_1_A (1<<11) 113#define ME_DAC_CONTROL_UPDATE 0x0012 /* R | - */ 114#define ME_DAC_DATA_A 0x0014 /* - | W */ 115#define ME_DAC_DATA_B 0x0016 /* - | W */ 116#define ME_DAC_DATA_C 0x0018 /* - | W */ 117#define ME_DAC_DATA_D 0x001A /* - | W */ 118#define ME_COUNTER_ENDDATA_A 0x001C /* - | W */ 119#define ME_COUNTER_ENDDATA_B 0x001E /* - | W */ 120#define ME_COUNTER_STARTDATA_A 0x0020 /* - | W */ 121#define ME_COUNTER_VALUE_A 0x0020 /* R | - */ 122#define ME_COUNTER_STARTDATA_B 0x0022 /* - | W */ 123#define ME_COUNTER_VALUE_B 0x0022 /* R | - */ 124 125static const struct comedi_lrange me_ai_range = { 126 8, { 127 BIP_RANGE(10), 128 BIP_RANGE(5), 129 BIP_RANGE(2.5), 130 BIP_RANGE(1.25), 131 UNI_RANGE(10), 132 UNI_RANGE(5), 133 UNI_RANGE(2.5), 134 UNI_RANGE(1.25) 135 } 136}; 137 138static const struct comedi_lrange me_ao_range = { 139 3, { 140 BIP_RANGE(10), 141 BIP_RANGE(5), 142 UNI_RANGE(10) 143 } 144}; 145 146enum me_boardid { 147 BOARD_ME2600, 148 BOARD_ME2000, 149}; 150 151struct me_board { 152 const char *name; 153 int needs_firmware; 154 int has_ao; 155}; 156 157static const struct me_board me_boards[] = { 158 [BOARD_ME2600] = { 159 .name = "me-2600i", 160 .needs_firmware = 1, 161 .has_ao = 1, 162 }, 163 [BOARD_ME2000] = { 164 .name = "me-2000i", 165 }, 166}; 167 168struct me_private_data { 169 void __iomem *plx_regbase; /* PLX configuration base address */ 170 171 unsigned short control_1; /* Mirror of CONTROL_1 register */ 172 unsigned short control_2; /* Mirror of CONTROL_2 register */ 173 unsigned short dac_control; /* Mirror of the DAC_CONTROL register */ 174}; 175 176static inline void sleep(unsigned sec) 177{ 178 current->state = TASK_INTERRUPTIBLE; 179 schedule_timeout(sec * HZ); 180} 181 182static int me_dio_insn_config(struct comedi_device *dev, 183 struct comedi_subdevice *s, 184 struct comedi_insn *insn, 185 unsigned int *data) 186{ 187 struct me_private_data *devpriv = dev->private; 188 unsigned int chan = CR_CHAN(insn->chanspec); 189 unsigned int mask; 190 int ret; 191 192 if (chan < 16) 193 mask = 0x0000ffff; 194 else 195 mask = 0xffff0000; 196 197 ret = comedi_dio_insn_config(dev, s, insn, data, mask); 198 if (ret) 199 return ret; 200 201 if (s->io_bits & 0x0000ffff) 202 devpriv->control_2 |= ENABLE_PORT_A; 203 else 204 devpriv->control_2 &= ~ENABLE_PORT_A; 205 if (s->io_bits & 0xffff0000) 206 devpriv->control_2 |= ENABLE_PORT_B; 207 else 208 devpriv->control_2 &= ~ENABLE_PORT_B; 209 210 writew(devpriv->control_2, dev->mmio + ME_CONTROL_2); 211 212 return insn->n; 213} 214 215static int me_dio_insn_bits(struct comedi_device *dev, 216 struct comedi_subdevice *s, 217 struct comedi_insn *insn, 218 unsigned int *data) 219{ 220 void __iomem *mmio_porta = dev->mmio + ME_DIO_PORT_A; 221 void __iomem *mmio_portb = dev->mmio + ME_DIO_PORT_B; 222 unsigned int mask; 223 unsigned int val; 224 225 mask = comedi_dio_update_state(s, data); 226 if (mask) { 227 if (mask & 0x0000ffff) 228 writew((s->state & 0xffff), mmio_porta); 229 if (mask & 0xffff0000) 230 writew(((s->state >> 16) & 0xffff), mmio_portb); 231 } 232 233 if (s->io_bits & 0x0000ffff) 234 val = s->state & 0xffff; 235 else 236 val = readw(mmio_porta); 237 238 if (s->io_bits & 0xffff0000) 239 val |= (s->state & 0xffff0000); 240 else 241 val |= (readw(mmio_portb) << 16); 242 243 data[1] = val; 244 245 return insn->n; 246} 247 248static int me_ai_eoc(struct comedi_device *dev, 249 struct comedi_subdevice *s, 250 struct comedi_insn *insn, 251 unsigned long context) 252{ 253 unsigned int status; 254 255 status = readw(dev->mmio + ME_STATUS); 256 if ((status & 0x0004) == 0) 257 return 0; 258 return -EBUSY; 259} 260 261static int me_ai_insn_read(struct comedi_device *dev, 262 struct comedi_subdevice *s, 263 struct comedi_insn *insn, 264 unsigned int *data) 265{ 266 struct me_private_data *dev_private = dev->private; 267 unsigned int chan = CR_CHAN(insn->chanspec); 268 unsigned int rang = CR_RANGE(insn->chanspec); 269 unsigned int aref = CR_AREF(insn->chanspec); 270 unsigned short val; 271 int ret; 272 273 /* stop any running conversion */ 274 dev_private->control_1 &= 0xFFFC; 275 writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); 276 277 /* clear chanlist and ad fifo */ 278 dev_private->control_2 &= ~(ENABLE_ADFIFO | ENABLE_CHANLIST); 279 writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); 280 281 /* reset any pending interrupt */ 282 writew(0x00, dev->mmio + ME_RESET_INTERRUPT); 283 284 /* enable the chanlist and ADC fifo */ 285 dev_private->control_2 |= (ENABLE_ADFIFO | ENABLE_CHANLIST); 286 writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); 287 288 /* write to channel list fifo */ 289 val = chan & 0x0f; /* b3:b0 channel */ 290 val |= (rang & 0x03) << 4; /* b5:b4 gain */ 291 val |= (rang & 0x04) << 4; /* b6 polarity */ 292 val |= ((aref & AREF_DIFF) ? 0x80 : 0); /* b7 differential */ 293 writew(val & 0xff, dev->mmio + ME_CHANNEL_LIST); 294 295 /* set ADC mode to software trigger */ 296 dev_private->control_1 |= SOFTWARE_TRIGGERED_ADC; 297 writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); 298 299 /* start conversion by reading from ADC_START */ 300 readw(dev->mmio + ME_ADC_START); 301 302 /* wait for ADC fifo not empty flag */ 303 ret = comedi_timeout(dev, s, insn, me_ai_eoc, 0); 304 if (ret) 305 return ret; 306 307 /* get value from ADC fifo */ 308 val = readw(dev->mmio + ME_READ_AD_FIFO); 309 val = (val ^ 0x800) & 0x0fff; 310 data[0] = val; 311 312 /* stop any running conversion */ 313 dev_private->control_1 &= 0xFFFC; 314 writew(dev_private->control_1, dev->mmio + ME_CONTROL_1); 315 316 return 1; 317} 318 319static int me_ao_insn_write(struct comedi_device *dev, 320 struct comedi_subdevice *s, 321 struct comedi_insn *insn, 322 unsigned int *data) 323{ 324 struct me_private_data *dev_private = dev->private; 325 unsigned int chan = CR_CHAN(insn->chanspec); 326 unsigned int rang = CR_RANGE(insn->chanspec); 327 unsigned int val = s->readback[chan]; 328 int i; 329 330 /* Enable all DAC */ 331 dev_private->control_2 |= ENABLE_DAC; 332 writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); 333 334 /* and set DAC to "buffered" mode */ 335 dev_private->control_2 |= BUFFERED_DAC; 336 writew(dev_private->control_2, dev->mmio + ME_CONTROL_2); 337 338 /* Set dac-control register */ 339 for (i = 0; i < insn->n; i++) { 340 /* clear bits for this channel */ 341 dev_private->dac_control &= ~(0x0880 >> chan); 342 if (rang == 0) 343 dev_private->dac_control |= 344 ((DAC_BIPOLAR_A | DAC_GAIN_1_A) >> chan); 345 else if (rang == 1) 346 dev_private->dac_control |= 347 ((DAC_BIPOLAR_A | DAC_GAIN_0_A) >> chan); 348 } 349 writew(dev_private->dac_control, dev->mmio + ME_DAC_CONTROL); 350 351 /* Update dac-control register */ 352 readw(dev->mmio + ME_DAC_CONTROL_UPDATE); 353 354 /* Set data register */ 355 for (i = 0; i < insn->n; i++) { 356 val = data[i]; 357 358 writew(val, dev->mmio + ME_DAC_DATA_A + (chan << 1)); 359 } 360 s->readback[chan] = val; 361 362 /* Update dac with data registers */ 363 readw(dev->mmio + ME_DAC_UPDATE); 364 365 return insn->n; 366} 367 368static int me2600_xilinx_download(struct comedi_device *dev, 369 const u8 *data, size_t size, 370 unsigned long context) 371{ 372 struct me_private_data *dev_private = dev->private; 373 unsigned int value; 374 unsigned int file_length; 375 unsigned int i; 376 377 /* disable irq's on PLX */ 378 writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); 379 380 /* First, make a dummy read to reset xilinx */ 381 value = readw(dev->mmio + XILINX_DOWNLOAD_RESET); 382 383 /* Wait until reset is over */ 384 sleep(1); 385 386 /* Write a dummy value to Xilinx */ 387 writeb(0x00, dev->mmio + 0x0); 388 sleep(1); 389 390 /* 391 * Format of the firmware 392 * Build longs from the byte-wise coded header 393 * Byte 1-3: length of the array 394 * Byte 4-7: version 395 * Byte 8-11: date 396 * Byte 12-15: reserved 397 */ 398 if (size < 16) 399 return -EINVAL; 400 401 file_length = (((unsigned int)data[0] & 0xff) << 24) + 402 (((unsigned int)data[1] & 0xff) << 16) + 403 (((unsigned int)data[2] & 0xff) << 8) + 404 ((unsigned int)data[3] & 0xff); 405 406 /* 407 * Loop for writing firmware byte by byte to xilinx 408 * Firmware data start at offset 16 409 */ 410 for (i = 0; i < file_length; i++) 411 writeb((data[16 + i] & 0xff), dev->mmio + 0x0); 412 413 /* Write 5 dummy values to xilinx */ 414 for (i = 0; i < 5; i++) 415 writeb(0x00, dev->mmio + 0x0); 416 417 /* Test if there was an error during download -> INTB was thrown */ 418 value = readl(dev_private->plx_regbase + PLX9052_INTCSR); 419 if (value & PLX9052_INTCSR_LI2STAT) { 420 /* Disable interrupt */ 421 writel(0x00, dev_private->plx_regbase + PLX9052_INTCSR); 422 dev_err(dev->class_dev, "Xilinx download failed\n"); 423 return -EIO; 424 } 425 426 /* Wait until the Xilinx is ready for real work */ 427 sleep(1); 428 429 /* Enable PLX-Interrupts */ 430 writel(PLX9052_INTCSR_LI1ENAB | 431 PLX9052_INTCSR_LI1POL | 432 PLX9052_INTCSR_PCIENAB, 433 dev_private->plx_regbase + PLX9052_INTCSR); 434 435 return 0; 436} 437 438static int me_reset(struct comedi_device *dev) 439{ 440 struct me_private_data *dev_private = dev->private; 441 442 /* Reset board */ 443 writew(0x00, dev->mmio + ME_CONTROL_1); 444 writew(0x00, dev->mmio + ME_CONTROL_2); 445 writew(0x00, dev->mmio + ME_RESET_INTERRUPT); 446 writew(0x00, dev->mmio + ME_DAC_CONTROL); 447 448 /* Save values in the board context */ 449 dev_private->dac_control = 0; 450 dev_private->control_1 = 0; 451 dev_private->control_2 = 0; 452 453 return 0; 454} 455 456static int me_auto_attach(struct comedi_device *dev, 457 unsigned long context) 458{ 459 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 460 const struct me_board *board = NULL; 461 struct me_private_data *dev_private; 462 struct comedi_subdevice *s; 463 int ret; 464 465 if (context < ARRAY_SIZE(me_boards)) 466 board = &me_boards[context]; 467 if (!board) 468 return -ENODEV; 469 dev->board_ptr = board; 470 dev->board_name = board->name; 471 472 dev_private = comedi_alloc_devpriv(dev, sizeof(*dev_private)); 473 if (!dev_private) 474 return -ENOMEM; 475 476 ret = comedi_pci_enable(dev); 477 if (ret) 478 return ret; 479 480 dev_private->plx_regbase = pci_ioremap_bar(pcidev, 0); 481 if (!dev_private->plx_regbase) 482 return -ENOMEM; 483 484 dev->mmio = pci_ioremap_bar(pcidev, 2); 485 if (!dev->mmio) 486 return -ENOMEM; 487 488 /* Download firmware and reset card */ 489 if (board->needs_firmware) { 490 ret = comedi_load_firmware(dev, &comedi_to_pci_dev(dev)->dev, 491 ME2600_FIRMWARE, 492 me2600_xilinx_download, 0); 493 if (ret < 0) 494 return ret; 495 } 496 me_reset(dev); 497 498 ret = comedi_alloc_subdevices(dev, 3); 499 if (ret) 500 return ret; 501 502 s = &dev->subdevices[0]; 503 s->type = COMEDI_SUBD_AI; 504 s->subdev_flags = SDF_READABLE | SDF_COMMON; 505 s->n_chan = 16; 506 s->maxdata = 0x0fff; 507 s->len_chanlist = 16; 508 s->range_table = &me_ai_range; 509 s->insn_read = me_ai_insn_read; 510 511 s = &dev->subdevices[1]; 512 if (board->has_ao) { 513 s->type = COMEDI_SUBD_AO; 514 s->subdev_flags = SDF_WRITEABLE | SDF_COMMON; 515 s->n_chan = 4; 516 s->maxdata = 0x0fff; 517 s->len_chanlist = 4; 518 s->range_table = &me_ao_range; 519 s->insn_write = me_ao_insn_write; 520 s->insn_read = comedi_readback_insn_read; 521 522 ret = comedi_alloc_subdev_readback(s); 523 if (ret) 524 return ret; 525 } else { 526 s->type = COMEDI_SUBD_UNUSED; 527 } 528 529 s = &dev->subdevices[2]; 530 s->type = COMEDI_SUBD_DIO; 531 s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; 532 s->n_chan = 32; 533 s->maxdata = 1; 534 s->len_chanlist = 32; 535 s->range_table = &range_digital; 536 s->insn_bits = me_dio_insn_bits; 537 s->insn_config = me_dio_insn_config; 538 539 return 0; 540} 541 542static void me_detach(struct comedi_device *dev) 543{ 544 struct me_private_data *dev_private = dev->private; 545 546 if (dev_private) { 547 if (dev->mmio) 548 me_reset(dev); 549 if (dev_private->plx_regbase) 550 iounmap(dev_private->plx_regbase); 551 } 552 comedi_pci_detach(dev); 553} 554 555static struct comedi_driver me_daq_driver = { 556 .driver_name = "me_daq", 557 .module = THIS_MODULE, 558 .auto_attach = me_auto_attach, 559 .detach = me_detach, 560}; 561 562static int me_daq_pci_probe(struct pci_dev *dev, 563 const struct pci_device_id *id) 564{ 565 return comedi_pci_auto_config(dev, &me_daq_driver, id->driver_data); 566} 567 568static const struct pci_device_id me_daq_pci_table[] = { 569 { PCI_VDEVICE(MEILHAUS, 0x2600), BOARD_ME2600 }, 570 { PCI_VDEVICE(MEILHAUS, 0x2000), BOARD_ME2000 }, 571 { 0 } 572}; 573MODULE_DEVICE_TABLE(pci, me_daq_pci_table); 574 575static struct pci_driver me_daq_pci_driver = { 576 .name = "me_daq", 577 .id_table = me_daq_pci_table, 578 .probe = me_daq_pci_probe, 579 .remove = comedi_pci_auto_unconfig, 580}; 581module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver); 582 583MODULE_AUTHOR("Comedi http://www.comedi.org"); 584MODULE_DESCRIPTION("Comedi low-level driver"); 585MODULE_LICENSE("GPL"); 586MODULE_FIRMWARE(ME2600_FIRMWARE); 587