s526.c revision 2b0318a600989ed85fe020079fa20132f8aebaf3
1/* 2 comedi/drivers/s526.c 3 Sensoray s526 Comedi driver 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 2000 David A. Schleef <ds@schleef.org> 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 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 21 22*/ 23/* 24Driver: s526 25Description: Sensoray 526 driver 26Devices: [Sensoray] 526 (s526) 27Author: Richie 28 Everett Wang <everett.wang@everteq.com> 29Updated: Thu, 14 Sep. 2006 30Status: experimental 31 32Encoder works 33Analog input works 34Analog output works 35PWM output works 36Commands are not supported yet. 37 38Configuration Options: 39 40comedi_config /dev/comedi0 s526 0x2C0,0x3 41 42*/ 43 44#include "../comedidev.h" 45#include <linux/ioport.h> 46#include <asm/byteorder.h> 47 48#define S526_SIZE 64 49 50#define S526_START_AI_CONV 0 51#define S526_AI_READ 0 52 53/* Ports */ 54#define S526_IOSIZE 0x40 55#define S526_NUM_PORTS 27 56 57/* registers */ 58#define REG_TCR 0x00 59#define REG_WDC 0x02 60#define REG_DAC 0x04 61#define REG_ADC 0x06 62#define REG_ADD 0x08 63#define REG_DIO 0x0A 64#define REG_IER 0x0C 65#define REG_ISR 0x0E 66#define REG_MSC 0x10 67#define REG_C0L 0x12 68#define REG_C0H 0x14 69#define REG_C0M 0x16 70#define REG_C0C 0x18 71#define REG_C1L 0x1A 72#define REG_C1H 0x1C 73#define REG_C1M 0x1E 74#define REG_C1C 0x20 75#define REG_C2L 0x22 76#define REG_C2H 0x24 77#define REG_C2M 0x26 78#define REG_C2C 0x28 79#define REG_C3L 0x2A 80#define REG_C3H 0x2C 81#define REG_C3M 0x2E 82#define REG_C3C 0x30 83#define REG_EED 0x32 84#define REG_EEC 0x34 85 86static const int s526_ports[] = { 87 REG_TCR, 88 REG_WDC, 89 REG_DAC, 90 REG_ADC, 91 REG_ADD, 92 REG_DIO, 93 REG_IER, 94 REG_ISR, 95 REG_MSC, 96 REG_C0L, 97 REG_C0H, 98 REG_C0M, 99 REG_C0C, 100 REG_C1L, 101 REG_C1H, 102 REG_C1M, 103 REG_C1C, 104 REG_C2L, 105 REG_C2H, 106 REG_C2M, 107 REG_C2C, 108 REG_C3L, 109 REG_C3H, 110 REG_C3M, 111 REG_C3C, 112 REG_EED, 113 REG_EEC 114}; 115 116struct counter_mode_register_t { 117#if defined (__LITTLE_ENDIAN_BITFIELD) 118 unsigned short coutSource:1; 119 unsigned short coutPolarity:1; 120 unsigned short autoLoadResetRcap:3; 121 unsigned short hwCtEnableSource:2; 122 unsigned short ctEnableCtrl:2; 123 unsigned short clockSource:2; 124 unsigned short countDir:1; 125 unsigned short countDirCtrl:1; 126 unsigned short outputRegLatchCtrl:1; 127 unsigned short preloadRegSel:1; 128 unsigned short reserved:1; 129 #elif defined(__BIG_ENDIAN_BITFIELD) 130 unsigned short reserved:1; 131 unsigned short preloadRegSel:1; 132 unsigned short outputRegLatchCtrl:1; 133 unsigned short countDirCtrl:1; 134 unsigned short countDir:1; 135 unsigned short clockSource:2; 136 unsigned short ctEnableCtrl:2; 137 unsigned short hwCtEnableSource:2; 138 unsigned short autoLoadResetRcap:3; 139 unsigned short coutPolarity:1; 140 unsigned short coutSource:1; 141#else 142#error Unknown bit field order 143#endif 144}; 145 146union cmReg { 147 struct counter_mode_register_t reg; 148 unsigned short value; 149}; 150 151#define MAX_GPCT_CONFIG_DATA 6 152 153/* Different Application Classes for GPCT Subdevices */ 154/* The list is not exhaustive and needs discussion! */ 155enum S526_GPCT_APP_CLASS { 156 CountingAndTimeMeasurement, 157 SinglePulseGeneration, 158 PulseTrainGeneration, 159 PositionMeasurement, 160 Miscellaneous 161}; 162 163/* Config struct for different GPCT subdevice Application Classes and 164 their options 165*/ 166struct s526GPCTConfig { 167 enum S526_GPCT_APP_CLASS app; 168 int data[MAX_GPCT_CONFIG_DATA]; 169}; 170 171/* 172 * Board descriptions for two imaginary boards. Describing the 173 * boards in this way is optional, and completely driver-dependent. 174 * Some drivers use arrays such as this, other do not. 175 */ 176struct s526_board { 177 const char *name; 178 int gpct_chans; 179 int gpct_bits; 180 int ad_chans; 181 int ad_bits; 182 int da_chans; 183 int da_bits; 184 int have_dio; 185}; 186 187static const struct s526_board s526_boards[] = { 188 { 189 .name = "s526", 190 .gpct_chans = 4, 191 .gpct_bits = 24, 192 .ad_chans = 8, 193 .ad_bits = 16, 194 .da_chans = 4, 195 .da_bits = 16, 196 .have_dio = 1, 197 } 198}; 199 200#define ADDR_REG(reg) (dev->iobase + (reg)) 201#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8) 202 203/* 204 * Useful for shorthand access to the particular board structure 205 */ 206#define thisboard ((const struct s526_board *)dev->board_ptr) 207 208/* this structure is for data unique to this hardware driver. If 209 several hardware drivers keep similar information in this structure, 210 feel free to suggest moving the variable to the struct comedi_device struct. */ 211struct s526_private { 212 213 int data; 214 215 /* would be useful for a PCI device */ 216 struct pci_dev *pci_dev; 217 218 /* Used for AO readback */ 219 unsigned int ao_readback[2]; 220 221 struct s526GPCTConfig s526_gpct_config[4]; 222 unsigned short s526_ai_config; 223}; 224 225/* 226 * most drivers define the following macro to make it easy to 227 * access the private structure. 228 */ 229#define devpriv ((struct s526_private *)dev->private) 230 231/* 232 * The struct comedi_driver structure tells the Comedi core module 233 * which functions to call to configure/deconfigure (attach/detach) 234 * the board, and also about the kernel module that contains 235 * the device code. 236 */ 237static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it); 238static int s526_detach(struct comedi_device *dev); 239static struct comedi_driver driver_s526 = { 240 .driver_name = "s526", 241 .module = THIS_MODULE, 242 .attach = s526_attach, 243 .detach = s526_detach, 244/* It is not necessary to implement the following members if you are 245 * writing a driver for a ISA PnP or PCI card */ 246 /* Most drivers will support multiple types of boards by 247 * having an array of board structures. These were defined 248 * in s526_boards[] above. Note that the element 'name' 249 * was first in the structure -- Comedi uses this fact to 250 * extract the name of the board without knowing any details 251 * about the structure except for its length. 252 * When a device is attached (by comedi_config), the name 253 * of the device is given to Comedi, and Comedi tries to 254 * match it by going through the list of board names. If 255 * there is a match, the address of the pointer is put 256 * into dev->board_ptr and driver->attach() is called. 257 * 258 * Note that these are not necessary if you can determine 259 * the type of board in software. ISA PnP, PCI, and PCMCIA 260 * devices are such boards. 261 */ 262 .board_name = &s526_boards[0].name, 263 .offset = sizeof(struct s526_board), 264 .num_names = ARRAY_SIZE(s526_boards), 265}; 266 267static int s526_gpct_rinsn(struct comedi_device *dev, 268 struct comedi_subdevice *s, struct comedi_insn *insn, 269 unsigned int *data); 270static int s526_gpct_insn_config(struct comedi_device *dev, 271 struct comedi_subdevice *s, 272 struct comedi_insn *insn, unsigned int *data); 273static int s526_gpct_winsn(struct comedi_device *dev, 274 struct comedi_subdevice *s, struct comedi_insn *insn, 275 unsigned int *data); 276static int s526_ai_insn_config(struct comedi_device *dev, 277 struct comedi_subdevice *s, 278 struct comedi_insn *insn, unsigned int *data); 279static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 280 struct comedi_insn *insn, unsigned int *data); 281static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 282 struct comedi_insn *insn, unsigned int *data); 283static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 284 struct comedi_insn *insn, unsigned int *data); 285static int s526_dio_insn_bits(struct comedi_device *dev, 286 struct comedi_subdevice *s, 287 struct comedi_insn *insn, unsigned int *data); 288static int s526_dio_insn_config(struct comedi_device *dev, 289 struct comedi_subdevice *s, 290 struct comedi_insn *insn, unsigned int *data); 291 292/* 293 * Attach is called by the Comedi core to configure the driver 294 * for a particular board. If you specified a board_name array 295 * in the driver structure, dev->board_ptr contains that 296 * address. 297 */ 298static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) 299{ 300 struct comedi_subdevice *s; 301 int iobase; 302 int i, n; 303/* short value; */ 304/* int subdev_channel = 0; */ 305 union cmReg cmReg; 306 307 printk("comedi%d: s526: ", dev->minor); 308 309 iobase = it->options[0]; 310 if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) { 311 comedi_error(dev, "I/O port conflict"); 312 return -EIO; 313 } 314 dev->iobase = iobase; 315 316 printk("iobase=0x%lx\n", dev->iobase); 317 318 /*** make it a little quieter, exw, 8/29/06 319 for (i = 0; i < S526_NUM_PORTS; i++) { 320 printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); 321 } 322 ***/ 323 324/* 325 * Initialize dev->board_name. Note that we can use the "thisboard" 326 * macro now, since we just initialized it in the last line. 327 */ 328 dev->board_ptr = &s526_boards[0]; 329 330 dev->board_name = thisboard->name; 331 332/* 333 * Allocate the private structure area. alloc_private() is a 334 * convenient macro defined in comedidev.h. 335 */ 336 if (alloc_private(dev, sizeof(struct s526_private)) < 0) 337 return -ENOMEM; 338 339/* 340 * Allocate the subdevice structures. alloc_subdevice() is a 341 * convenient macro defined in comedidev.h. 342 */ 343 dev->n_subdevices = 4; 344 if (alloc_subdevices(dev, dev->n_subdevices) < 0) 345 return -ENOMEM; 346 347 s = dev->subdevices + 0; 348 /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ 349 s->type = COMEDI_SUBD_COUNTER; 350 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; 351 /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */ 352 s->n_chan = thisboard->gpct_chans; 353 s->maxdata = 0x00ffffff; /* 24 bit counter */ 354 s->insn_read = s526_gpct_rinsn; 355 s->insn_config = s526_gpct_insn_config; 356 s->insn_write = s526_gpct_winsn; 357 358 /* Command are not implemented yet, however they are necessary to 359 allocate the necessary memory for the comedi_async struct (used 360 to trigger the GPCT in case of pulsegenerator function */ 361 /* s->do_cmd = s526_gpct_cmd; */ 362 /* s->do_cmdtest = s526_gpct_cmdtest; */ 363 /* s->cancel = s526_gpct_cancel; */ 364 365 s = dev->subdevices + 1; 366 /* dev->read_subdev=s; */ 367 /* analog input subdevice */ 368 s->type = COMEDI_SUBD_AI; 369 /* we support differential */ 370 s->subdev_flags = SDF_READABLE | SDF_DIFF; 371 /* channels 0 to 7 are the regular differential inputs */ 372 /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ 373 s->n_chan = 10; 374 s->maxdata = 0xffff; 375 s->range_table = &range_bipolar10; 376 s->len_chanlist = 16; /* This is the maximum chanlist length that 377 the board can handle */ 378 s->insn_read = s526_ai_rinsn; 379 s->insn_config = s526_ai_insn_config; 380 381 s = dev->subdevices + 2; 382 /* analog output subdevice */ 383 s->type = COMEDI_SUBD_AO; 384 s->subdev_flags = SDF_WRITABLE; 385 s->n_chan = 4; 386 s->maxdata = 0xffff; 387 s->range_table = &range_bipolar10; 388 s->insn_write = s526_ao_winsn; 389 s->insn_read = s526_ao_rinsn; 390 391 s = dev->subdevices + 3; 392 /* digital i/o subdevice */ 393 if (thisboard->have_dio) { 394 s->type = COMEDI_SUBD_DIO; 395 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 396 s->n_chan = 8; 397 s->maxdata = 1; 398 s->range_table = &range_digital; 399 s->insn_bits = s526_dio_insn_bits; 400 s->insn_config = s526_dio_insn_config; 401 } else { 402 s->type = COMEDI_SUBD_UNUSED; 403 } 404 405 printk("attached\n"); 406 407 return 1; 408 409#if 0 410 /* Example of Counter Application */ 411 /* One-shot (software trigger) */ 412 cmReg.reg.coutSource = 0; /* out RCAP */ 413 cmReg.reg.coutPolarity = 1; /* Polarity inverted */ 414 cmReg.reg.autoLoadResetRcap = 1; /* Auto load 0:disabled, 1:enabled */ 415 cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ 416 cmReg.reg.ctEnableCtrl = 2; /* Hardware */ 417 cmReg.reg.clockSource = 2; /* Internal */ 418 cmReg.reg.countDir = 1; /* Down */ 419 cmReg.reg.countDirCtrl = 1; /* Software */ 420 cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ 421 cmReg.reg.preloadRegSel = 0; /* PR0 */ 422 cmReg.reg.reserved = 0; 423 424 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 425 426 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 427 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 428 429 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ 430 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ 431 432 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */ 433 434#else 435 436 /* Set Counter Mode Register */ 437 cmReg.reg.coutSource = 0; /* out RCAP */ 438 cmReg.reg.coutPolarity = 0; /* Polarity inverted */ 439 cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ 440 cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ 441 cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ 442 cmReg.reg.clockSource = 3; /* x4 */ 443 cmReg.reg.countDir = 0; /* up */ 444 cmReg.reg.countDirCtrl = 0; /* quadrature */ 445 cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ 446 cmReg.reg.preloadRegSel = 0; /* PR0 */ 447 cmReg.reg.reserved = 0; 448 449 n = 0; 450 printk("Mode reg=0x%04x, 0x%04lx\n", cmReg.value, ADDR_CHAN_REG(REG_C0M, 451 n)); 452 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); 453 udelay(1000); 454 printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n))); 455 456 /* Load the pre-laod register high word */ 457/* value = (short) (0x55); */ 458/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ 459 460 /* Load the pre-laod register low word */ 461/* value = (short)(0xaa55); */ 462/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ 463 464 /* Write the Counter Control Register */ 465/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ 466 467 /* Reset the counter if it is software preload */ 468 if (cmReg.reg.autoLoadResetRcap == 0) { 469 outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); /* Reset the counter */ 470 outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); /* Load the counter from PR0 */ 471 } 472 473 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); 474 udelay(1000); 475 printk("Read back mode reg=0x%04x\n", inw(ADDR_CHAN_REG(REG_C0M, n))); 476 477#endif 478 printk("Current registres:\n"); 479 480 for (i = 0; i < S526_NUM_PORTS; i++) { 481 printk("0x%02lx: 0x%04x\n", ADDR_REG(s526_ports[i]), 482 inw(ADDR_REG(s526_ports[i]))); 483 } 484 return 1; 485} 486 487/* 488 * _detach is called to deconfigure a device. It should deallocate 489 * resources. 490 * This function is also called when _attach() fails, so it should be 491 * careful not to release resources that were not necessarily 492 * allocated by _attach(). dev->private and dev->subdevices are 493 * deallocated automatically by the core. 494 */ 495static int s526_detach(struct comedi_device *dev) 496{ 497 printk("comedi%d: s526: remove\n", dev->minor); 498 499 if (dev->iobase > 0) 500 release_region(dev->iobase, S526_IOSIZE); 501 502 return 0; 503} 504 505static int s526_gpct_rinsn(struct comedi_device *dev, 506 struct comedi_subdevice *s, struct comedi_insn *insn, 507 unsigned int *data) 508{ 509 int i; /* counts the Data */ 510 int counter_channel = CR_CHAN(insn->chanspec); 511 unsigned short datalow; 512 unsigned short datahigh; 513 514 /* Check if (n > 0) */ 515 if (insn->n <= 0) { 516 printk("s526: INSN_READ: n should be > 0\n"); 517 return -EINVAL; 518 } 519 /* Read the low word first */ 520 for (i = 0; i < insn->n; i++) { 521 datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel)); 522 datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel)); 523 data[i] = (int)(datahigh & 0x00FF); 524 data[i] = (data[i] << 16) | (datalow & 0xFFFF); 525/* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", counter_channel, data[i], datahigh, datalow); */ 526 } 527 return i; 528} 529 530static int s526_gpct_insn_config(struct comedi_device *dev, 531 struct comedi_subdevice *s, 532 struct comedi_insn *insn, unsigned int *data) 533{ 534 int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ 535 int i; 536 short value; 537 union cmReg cmReg; 538 539/* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", subdev_channel); */ 540 541 for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) { 542 devpriv->s526_gpct_config[subdev_channel].data[i] = 543 insn->data[i]; 544/* printk("data[%d]=%x\n", i, insn->data[i]); */ 545 } 546 547 /* Check what type of Counter the user requested, data[0] contains */ 548 /* the Application type */ 549 switch (insn->data[0]) { 550 case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: 551 /* 552 data[0]: Application Type 553 data[1]: Counter Mode Register Value 554 data[2]: Pre-load Register Value 555 data[3]: Conter Control Register 556 */ 557 printk("s526: GPCT_INSN_CONFIG: Configuring Encoder\n"); 558 devpriv->s526_gpct_config[subdev_channel].app = 559 PositionMeasurement; 560 561#if 0 562 /* Example of Counter Application */ 563 /* One-shot (software trigger) */ 564 cmReg.reg.coutSource = 0; /* out RCAP */ 565 cmReg.reg.coutPolarity = 1; /* Polarity inverted */ 566 cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ 567 cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ 568 cmReg.reg.ctEnableCtrl = 2; /* Hardware */ 569 cmReg.reg.clockSource = 2; /* Internal */ 570 cmReg.reg.countDir = 1; /* Down */ 571 cmReg.reg.countDirCtrl = 1; /* Software */ 572 cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ 573 cmReg.reg.preloadRegSel = 0; /* PR0 */ 574 cmReg.reg.reserved = 0; 575 576 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 577 578 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 579 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 580 581 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ 582 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ 583 584 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset RCAP (fires one-shot) */ 585 586#endif 587 588#if 1 589 /* Set Counter Mode Register */ 590 cmReg.reg.coutSource = 0; /* out RCAP */ 591 cmReg.reg.coutPolarity = 0; /* Polarity inverted */ 592 cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ 593 cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ 594 cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ 595 cmReg.reg.clockSource = 3; /* x4 */ 596 cmReg.reg.countDir = 0; /* up */ 597 cmReg.reg.countDirCtrl = 0; /* quadrature */ 598 cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ 599 cmReg.reg.preloadRegSel = 0; /* PR0 */ 600 cmReg.reg.reserved = 0; 601 602 /* Set Counter Mode Register */ 603/* printk("s526: Counter Mode register=%x\n", cmReg.value); */ 604 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 605 606 /* Reset the counter if it is software preload */ 607 if (cmReg.reg.autoLoadResetRcap == 0) { 608 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ 609/* outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); Load the counter from PR0 */ 610 } 611#else 612 cmReg.reg.countDirCtrl = 0; /* 0 quadrature, 1 software control */ 613 614 /* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */ 615 if (insn->data[1] == GPCT_X2) { 616 cmReg.reg.clockSource = 1; 617 } else if (insn->data[1] == GPCT_X4) { 618 cmReg.reg.clockSource = 2; 619 } else { 620 cmReg.reg.clockSource = 0; 621 } 622 623 /* When to take into account the indexpulse: */ 624 if (insn->data[2] == GPCT_IndexPhaseLowLow) { 625 } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) { 626 } else if (insn->data[2] == GPCT_IndexPhaseHighLow) { 627 } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) { 628 } 629 /* Take into account the index pulse? */ 630 if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX) 631 cmReg.reg.autoLoadResetRcap = 4; /* Auto load with INDEX^ */ 632 633 /* Set Counter Mode Register */ 634 cmReg.value = (short)(insn->data[1] & 0xFFFF); 635 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 636 637 /* Load the pre-laod register high word */ 638 value = (short)((insn->data[2] >> 16) & 0xFFFF); 639 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 640 641 /* Load the pre-laod register low word */ 642 value = (short)(insn->data[2] & 0xFFFF); 643 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 644 645 /* Write the Counter Control Register */ 646 if (insn->data[3] != 0) { 647 value = (short)(insn->data[3] & 0xFFFF); 648 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 649 } 650 /* Reset the counter if it is software preload */ 651 if (cmReg.reg.autoLoadResetRcap == 0) { 652 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Reset the counter */ 653 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); /* Load the counter from PR0 */ 654 } 655#endif 656 break; 657 658 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR: 659 /* 660 data[0]: Application Type 661 data[1]: Counter Mode Register Value 662 data[2]: Pre-load Register 0 Value 663 data[3]: Pre-load Register 1 Value 664 data[4]: Conter Control Register 665 */ 666 printk("s526: GPCT_INSN_CONFIG: Configuring SPG\n"); 667 devpriv->s526_gpct_config[subdev_channel].app = 668 SinglePulseGeneration; 669 670 /* Set Counter Mode Register */ 671 cmReg.value = (short)(insn->data[1] & 0xFFFF); 672 cmReg.reg.preloadRegSel = 0; /* PR0 */ 673 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 674 675 /* Load the pre-laod register 0 high word */ 676 value = (short)((insn->data[2] >> 16) & 0xFFFF); 677 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 678 679 /* Load the pre-laod register 0 low word */ 680 value = (short)(insn->data[2] & 0xFFFF); 681 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 682 683 /* Set Counter Mode Register */ 684 cmReg.value = (short)(insn->data[1] & 0xFFFF); 685 cmReg.reg.preloadRegSel = 1; /* PR1 */ 686 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 687 688 /* Load the pre-laod register 1 high word */ 689 value = (short)((insn->data[3] >> 16) & 0xFFFF); 690 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 691 692 /* Load the pre-laod register 1 low word */ 693 value = (short)(insn->data[3] & 0xFFFF); 694 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 695 696 /* Write the Counter Control Register */ 697 if (insn->data[3] != 0) { 698 value = (short)(insn->data[3] & 0xFFFF); 699 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 700 } 701 break; 702 703 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR: 704 /* 705 data[0]: Application Type 706 data[1]: Counter Mode Register Value 707 data[2]: Pre-load Register 0 Value 708 data[3]: Pre-load Register 1 Value 709 data[4]: Conter Control Register 710 */ 711 printk("s526: GPCT_INSN_CONFIG: Configuring PTG\n"); 712 devpriv->s526_gpct_config[subdev_channel].app = 713 PulseTrainGeneration; 714 715 /* Set Counter Mode Register */ 716 cmReg.value = (short)(insn->data[1] & 0xFFFF); 717 cmReg.reg.preloadRegSel = 0; /* PR0 */ 718 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 719 720 /* Load the pre-laod register 0 high word */ 721 value = (short)((insn->data[2] >> 16) & 0xFFFF); 722 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 723 724 /* Load the pre-laod register 0 low word */ 725 value = (short)(insn->data[2] & 0xFFFF); 726 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 727 728 /* Set Counter Mode Register */ 729 cmReg.value = (short)(insn->data[1] & 0xFFFF); 730 cmReg.reg.preloadRegSel = 1; /* PR1 */ 731 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 732 733 /* Load the pre-laod register 1 high word */ 734 value = (short)((insn->data[3] >> 16) & 0xFFFF); 735 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 736 737 /* Load the pre-laod register 1 low word */ 738 value = (short)(insn->data[3] & 0xFFFF); 739 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 740 741 /* Write the Counter Control Register */ 742 if (insn->data[3] != 0) { 743 value = (short)(insn->data[3] & 0xFFFF); 744 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 745 } 746 break; 747 748 default: 749 printk("s526: unsupported GPCT_insn_config\n"); 750 return -EINVAL; 751 break; 752 } 753 754 return insn->n; 755} 756 757static int s526_gpct_winsn(struct comedi_device *dev, 758 struct comedi_subdevice *s, struct comedi_insn *insn, 759 unsigned int *data) 760{ 761 int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ 762 short value; 763 union cmReg cmReg; 764 765 printk("s526: GPCT_INSN_WRITE on channel %d\n", subdev_channel); 766 cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel)); 767 printk("s526: Counter Mode Register: %x\n", cmReg.value); 768 /* Check what Application of Counter this channel is configured for */ 769 switch (devpriv->s526_gpct_config[subdev_channel].app) { 770 case PositionMeasurement: 771 printk("S526: INSN_WRITE: PM\n"); 772 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, 773 subdev_channel)); 774 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); 775 break; 776 777 case SinglePulseGeneration: 778 printk("S526: INSN_WRITE: SPG\n"); 779 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, 780 subdev_channel)); 781 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); 782 break; 783 784 case PulseTrainGeneration: 785 /* data[0] contains the PULSE_WIDTH 786 data[1] contains the PULSE_PERIOD 787 @pre PULSE_PERIOD > PULSE_WIDTH > 0 788 The above periods must be expressed as a multiple of the 789 pulse frequency on the selected source 790 */ 791 printk("S526: INSN_WRITE: PTG\n"); 792 if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) { 793 (devpriv->s526_gpct_config[subdev_channel]).data[0] = 794 insn->data[0]; 795 (devpriv->s526_gpct_config[subdev_channel]).data[1] = 796 insn->data[1]; 797 } else { 798 printk("%d \t %d\n", insn->data[1], insn->data[2]); 799 printk 800 ("s526: INSN_WRITE: PTG: Problem with Pulse params\n"); 801 return -EINVAL; 802 } 803 804 value = (short)((*data >> 16) & 0xFFFF); 805 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 806 value = (short)(*data & 0xFFFF); 807 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 808 break; 809 default: /* Impossible */ 810 printk 811 ("s526: INSN_WRITE: Functionality %d not implemented yet\n", 812 devpriv->s526_gpct_config[subdev_channel].app); 813 return -EINVAL; 814 break; 815 } 816 /* return the number of samples written */ 817 return insn->n; 818} 819 820#define ISR_ADC_DONE 0x4 821static int s526_ai_insn_config(struct comedi_device *dev, 822 struct comedi_subdevice *s, 823 struct comedi_insn *insn, unsigned int *data) 824{ 825 int result = -EINVAL; 826 827 if (insn->n < 1) 828 return result; 829 830 result = insn->n; 831 832 /* data[0] : channels was set in relevant bits. 833 data[1] : delay 834 */ 835 /* COMMENT: abbotti 2008-07-24: I don't know why you'd want to 836 * enable channels here. The channel should be enabled in the 837 * INSN_READ handler. */ 838 839 /* Enable ADC interrupt */ 840 outw(ISR_ADC_DONE, ADDR_REG(REG_IER)); 841/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */ 842 devpriv->s526_ai_config = (data[0] & 0x3FF) << 5; 843 if (data[1] > 0) 844 devpriv->s526_ai_config |= 0x8000; /* set the delay */ 845 846 devpriv->s526_ai_config |= 0x0001; /* ADC start bit. */ 847 848 return result; 849} 850 851/* 852 * "instructions" read/write data in "one-shot" or "software-triggered" 853 * mode. 854 */ 855static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 856 struct comedi_insn *insn, unsigned int *data) 857{ 858 int n, i; 859 int chan = CR_CHAN(insn->chanspec); 860 unsigned short value; 861 unsigned int d; 862 unsigned int status; 863 864 /* Set configured delay, enable channel for this channel only, 865 * select "ADC read" channel, set "ADC start" bit. */ 866 value = (devpriv->s526_ai_config & 0x8000) | 867 ((1 << 5) << chan) | (chan << 1) | 0x0001; 868 869 /* convert n samples */ 870 for (n = 0; n < insn->n; n++) { 871 /* trigger conversion */ 872 outw(value, ADDR_REG(REG_ADC)); 873/* printk("s526: Wrote 0x%04x to ADC\n", value); */ 874/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */ 875 876#define TIMEOUT 100 877 /* wait for conversion to end */ 878 for (i = 0; i < TIMEOUT; i++) { 879 status = inw(ADDR_REG(REG_ISR)); 880 if (status & ISR_ADC_DONE) { 881 outw(ISR_ADC_DONE, ADDR_REG(REG_ISR)); 882 break; 883 } 884 } 885 if (i == TIMEOUT) { 886 /* printk() should be used instead of printk() 887 * whenever the code can be called from real-time. */ 888 printk("s526: ADC(0x%04x) timeout\n", 889 inw(ADDR_REG(REG_ISR))); 890 return -ETIMEDOUT; 891 } 892 893 /* read data */ 894 d = inw(ADDR_REG(REG_ADD)); 895/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */ 896 897 /* munge data */ 898 data[n] = d ^ 0x8000; 899 } 900 901 /* return the number of samples read/written */ 902 return n; 903} 904 905static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 906 struct comedi_insn *insn, unsigned int *data) 907{ 908 int i; 909 int chan = CR_CHAN(insn->chanspec); 910 unsigned short val; 911 912/* printk("s526_ao_winsn\n"); */ 913 val = chan << 1; 914/* outw(val, dev->iobase + REG_DAC); */ 915 outw(val, ADDR_REG(REG_DAC)); 916 917 /* Writing a list of values to an AO channel is probably not 918 * very useful, but that's how the interface is defined. */ 919 for (i = 0; i < insn->n; i++) { 920 /* a typical programming sequence */ 921/* outw(data[i], dev->iobase + REG_ADD); write the data to preload register */ 922 outw(data[i], ADDR_REG(REG_ADD)); /* write the data to preload register */ 923 devpriv->ao_readback[chan] = data[i]; 924/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */ 925 outw(val + 1, ADDR_REG(REG_DAC)); /* starts the D/A conversion. */ 926 } 927 928 /* return the number of samples read/written */ 929 return i; 930} 931 932/* AO subdevices should have a read insn as well as a write insn. 933 * Usually this means copying a value stored in devpriv. */ 934static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 935 struct comedi_insn *insn, unsigned int *data) 936{ 937 int i; 938 int chan = CR_CHAN(insn->chanspec); 939 940 for (i = 0; i < insn->n; i++) 941 data[i] = devpriv->ao_readback[chan]; 942 943 return i; 944} 945 946/* DIO devices are slightly special. Although it is possible to 947 * implement the insn_read/insn_write interface, it is much more 948 * useful to applications if you implement the insn_bits interface. 949 * This allows packed reading/writing of the DIO channels. The 950 * comedi core can convert between insn_bits and insn_read/write */ 951static int s526_dio_insn_bits(struct comedi_device *dev, 952 struct comedi_subdevice *s, 953 struct comedi_insn *insn, unsigned int *data) 954{ 955 if (insn->n != 2) 956 return -EINVAL; 957 958 /* The insn data is a mask in data[0] and the new data 959 * in data[1], each channel cooresponding to a bit. */ 960 if (data[0]) { 961 s->state &= ~data[0]; 962 s->state |= data[0] & data[1]; 963 /* Write out the new digital output lines */ 964 outw(s->state, ADDR_REG(REG_DIO)); 965 } 966 967 /* on return, data[1] contains the value of the digital 968 * input and output lines. */ 969 data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ 970 /* or we could just return the software copy of the output values if 971 * it was a purely digital output subdevice */ 972 /* data[1]=s->state & 0xFF; */ 973 974 return 2; 975} 976 977static int s526_dio_insn_config(struct comedi_device *dev, 978 struct comedi_subdevice *s, 979 struct comedi_insn *insn, unsigned int *data) 980{ 981 int chan = CR_CHAN(insn->chanspec); 982 int group, mask; 983 984 printk("S526 DIO insn_config\n"); 985 986 /* The input or output configuration of each digital line is 987 * configured by a special insn_config instruction. chanspec 988 * contains the channel to be changed, and data[0] contains the 989 * value COMEDI_INPUT or COMEDI_OUTPUT. */ 990 991 group = chan >> 2; 992 mask = 0xF << (group << 2); 993 switch (data[0]) { 994 case INSN_CONFIG_DIO_OUTPUT: 995 s->state |= 1 << (group + 10); // bit 10/11 set the group 1/2's mode 996 s->io_bits |= mask; 997 break; 998 case INSN_CONFIG_DIO_INPUT: 999 s->state &= ~(1 << (group + 10));// 1 is output, 0 is input. 1000 s->io_bits &= ~mask; 1001 break; 1002 case INSN_CONFIG_DIO_QUERY: 1003 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; 1004 return insn->n; 1005 default: 1006 return -EINVAL; 1007 } 1008 outw(s->state, ADDR_REG(REG_DIO)); 1009 1010 return 1; 1011} 1012 1013/* 1014 * A convenient macro that defines init_module() and cleanup_module(), 1015 * as necessary. 1016 */ 1017COMEDI_INITCLEANUP(driver_s526); 1018