s526.c revision c9c62f4e2c9b526c5cbade3f3a61f126e6587c16
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 211 struct. 212*/ 213struct s526_private { 214 215 int data; 216 217 /* would be useful for a PCI device */ 218 struct pci_dev *pci_dev; 219 220 /* Used for AO readback */ 221 unsigned int ao_readback[2]; 222 223 struct s526GPCTConfig s526_gpct_config[4]; 224 unsigned short s526_ai_config; 225}; 226 227/* 228 * most drivers define the following macro to make it easy to 229 * access the private structure. 230 */ 231#define devpriv ((struct s526_private *)dev->private) 232 233/* 234 * The struct comedi_driver structure tells the Comedi core module 235 * which functions to call to configure/deconfigure (attach/detach) 236 * the board, and also about the kernel module that contains 237 * the device code. 238 */ 239static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it); 240static int s526_detach(struct comedi_device *dev); 241static struct comedi_driver driver_s526 = { 242 .driver_name = "s526", 243 .module = THIS_MODULE, 244 .attach = s526_attach, 245 .detach = s526_detach, 246/* It is not necessary to implement the following members if you are 247 * writing a driver for a ISA PnP or PCI card */ 248 /* Most drivers will support multiple types of boards by 249 * having an array of board structures. These were defined 250 * in s526_boards[] above. Note that the element 'name' 251 * was first in the structure -- Comedi uses this fact to 252 * extract the name of the board without knowing any details 253 * about the structure except for its length. 254 * When a device is attached (by comedi_config), the name 255 * of the device is given to Comedi, and Comedi tries to 256 * match it by going through the list of board names. If 257 * there is a match, the address of the pointer is put 258 * into dev->board_ptr and driver->attach() is called. 259 * 260 * Note that these are not necessary if you can determine 261 * the type of board in software. ISA PnP, PCI, and PCMCIA 262 * devices are such boards. 263 */ 264 .board_name = &s526_boards[0].name, 265 .offset = sizeof(struct s526_board), 266 .num_names = ARRAY_SIZE(s526_boards), 267}; 268 269static int s526_gpct_rinsn(struct comedi_device *dev, 270 struct comedi_subdevice *s, struct comedi_insn *insn, 271 unsigned int *data); 272static int s526_gpct_insn_config(struct comedi_device *dev, 273 struct comedi_subdevice *s, 274 struct comedi_insn *insn, unsigned int *data); 275static int s526_gpct_winsn(struct comedi_device *dev, 276 struct comedi_subdevice *s, struct comedi_insn *insn, 277 unsigned int *data); 278static int s526_ai_insn_config(struct comedi_device *dev, 279 struct comedi_subdevice *s, 280 struct comedi_insn *insn, unsigned int *data); 281static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 282 struct comedi_insn *insn, unsigned int *data); 283static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 284 struct comedi_insn *insn, unsigned int *data); 285static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 286 struct comedi_insn *insn, unsigned int *data); 287static int s526_dio_insn_bits(struct comedi_device *dev, 288 struct comedi_subdevice *s, 289 struct comedi_insn *insn, unsigned int *data); 290static int s526_dio_insn_config(struct comedi_device *dev, 291 struct comedi_subdevice *s, 292 struct comedi_insn *insn, unsigned int *data); 293 294/* 295 * Attach is called by the Comedi core to configure the driver 296 * for a particular board. If you specified a board_name array 297 * in the driver structure, dev->board_ptr contains that 298 * address. 299 */ 300static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) 301{ 302 struct comedi_subdevice *s; 303 int iobase; 304 int i, n; 305/* short value; */ 306/* int subdev_channel = 0; */ 307 union cmReg cmReg; 308 309 printk(KERN_INFO "comedi%d: s526: ", dev->minor); 310 311 iobase = it->options[0]; 312 if (!iobase || !request_region(iobase, S526_IOSIZE, thisboard->name)) { 313 comedi_error(dev, "I/O port conflict"); 314 return -EIO; 315 } 316 dev->iobase = iobase; 317 318 printk("iobase=0x%lx\n", dev->iobase); 319 320 /*** make it a little quieter, exw, 8/29/06 321 for (i = 0; i < S526_NUM_PORTS; i++) { 322 printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), 323 inw(ADDR_REG(s526_ports[i]))); 324 } 325 ***/ 326 327/* 328 * Initialize dev->board_name. Note that we can use the "thisboard" 329 * macro now, since we just initialized it in the last line. 330 */ 331 dev->board_ptr = &s526_boards[0]; 332 333 dev->board_name = thisboard->name; 334 335/* 336 * Allocate the private structure area. alloc_private() is a 337 * convenient macro defined in comedidev.h. 338 */ 339 if (alloc_private(dev, sizeof(struct s526_private)) < 0) 340 return -ENOMEM; 341 342/* 343 * Allocate the subdevice structures. alloc_subdevice() is a 344 * convenient macro defined in comedidev.h. 345 */ 346 dev->n_subdevices = 4; 347 if (alloc_subdevices(dev, dev->n_subdevices) < 0) 348 return -ENOMEM; 349 350 s = dev->subdevices + 0; 351 /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ 352 s->type = COMEDI_SUBD_COUNTER; 353 s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; 354 /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */ 355 s->n_chan = thisboard->gpct_chans; 356 s->maxdata = 0x00ffffff; /* 24 bit counter */ 357 s->insn_read = s526_gpct_rinsn; 358 s->insn_config = s526_gpct_insn_config; 359 s->insn_write = s526_gpct_winsn; 360 361 /* Command are not implemented yet, however they are necessary to 362 allocate the necessary memory for the comedi_async struct (used 363 to trigger the GPCT in case of pulsegenerator function */ 364 /* s->do_cmd = s526_gpct_cmd; */ 365 /* s->do_cmdtest = s526_gpct_cmdtest; */ 366 /* s->cancel = s526_gpct_cancel; */ 367 368 s = dev->subdevices + 1; 369 /* dev->read_subdev=s; */ 370 /* analog input subdevice */ 371 s->type = COMEDI_SUBD_AI; 372 /* we support differential */ 373 s->subdev_flags = SDF_READABLE | SDF_DIFF; 374 /* channels 0 to 7 are the regular differential inputs */ 375 /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ 376 s->n_chan = 10; 377 s->maxdata = 0xffff; 378 s->range_table = &range_bipolar10; 379 s->len_chanlist = 16; /* This is the maximum chanlist length that 380 the board can handle */ 381 s->insn_read = s526_ai_rinsn; 382 s->insn_config = s526_ai_insn_config; 383 384 s = dev->subdevices + 2; 385 /* analog output subdevice */ 386 s->type = COMEDI_SUBD_AO; 387 s->subdev_flags = SDF_WRITABLE; 388 s->n_chan = 4; 389 s->maxdata = 0xffff; 390 s->range_table = &range_bipolar10; 391 s->insn_write = s526_ao_winsn; 392 s->insn_read = s526_ao_rinsn; 393 394 s = dev->subdevices + 3; 395 /* digital i/o subdevice */ 396 if (thisboard->have_dio) { 397 s->type = COMEDI_SUBD_DIO; 398 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 399 s->n_chan = 8; 400 s->maxdata = 1; 401 s->range_table = &range_digital; 402 s->insn_bits = s526_dio_insn_bits; 403 s->insn_config = s526_dio_insn_config; 404 } else { 405 s->type = COMEDI_SUBD_UNUSED; 406 } 407 408 printk(KERN_INFO "attached\n"); 409 410 return 1; 411 412#if 0 413 /* Example of Counter Application */ 414 /* One-shot (software trigger) */ 415 cmReg.reg.coutSource = 0; /* out RCAP */ 416 cmReg.reg.coutPolarity = 1; /* Polarity inverted */ 417 cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */ 418 cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ 419 cmReg.reg.ctEnableCtrl = 2; /* Hardware */ 420 cmReg.reg.clockSource = 2; /* Internal */ 421 cmReg.reg.countDir = 1; /* Down */ 422 cmReg.reg.countDirCtrl = 1; /* Software */ 423 cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ 424 cmReg.reg.preloadRegSel = 0; /* PR0 */ 425 cmReg.reg.reserved = 0; 426 427 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 428 429 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 430 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 431 432 /* Reset the counter */ 433 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 434 /* Load the counter from PR0 */ 435 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 436 /* Reset RCAP (fires one-shot) */ 437 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 438 439#else 440 441 /* Set Counter Mode Register */ 442 cmReg.reg.coutSource = 0; /* out RCAP */ 443 cmReg.reg.coutPolarity = 0; /* Polarity inverted */ 444 cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ 445 cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ 446 cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ 447 cmReg.reg.clockSource = 3; /* x4 */ 448 cmReg.reg.countDir = 0; /* up */ 449 cmReg.reg.countDirCtrl = 0; /* quadrature */ 450 cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ 451 cmReg.reg.preloadRegSel = 0; /* PR0 */ 452 cmReg.reg.reserved = 0; 453 454 n = 0; 455 printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n", 456 cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); 457 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); 458 udelay(1000); 459 printk(KERN_INFO "Read back mode reg=0x%04x\n", 460 inw(ADDR_CHAN_REG(REG_C0M, n))); 461 462 /* Load the pre-load register high word */ 463/* value = (short) (0x55); */ 464/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ 465 466 /* Load the pre-load register low word */ 467/* value = (short)(0xaa55); */ 468/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ 469 470 /* Write the Counter Control Register */ 471/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ 472 473 /* Reset the counter if it is software preload */ 474 if (cmReg.reg.autoLoadResetRcap == 0) { 475 /* Reset the counter */ 476 outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); 477 /* Load the counter from PR0 */ 478 outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); 479 } 480 481 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); 482 udelay(1000); 483 printk(KERN_INFO "Read back mode reg=0x%04x\n", 484 inw(ADDR_CHAN_REG(REG_C0M, n))); 485 486#endif 487 printk(KERN_INFO "Current registres:\n"); 488 489 for (i = 0; i < S526_NUM_PORTS; i++) { 490 printk(KERN_INFO "0x%02lx: 0x%04x\n", 491 ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); 492 } 493 return 1; 494} 495 496/* 497 * _detach is called to deconfigure a device. It should deallocate 498 * resources. 499 * This function is also called when _attach() fails, so it should be 500 * careful not to release resources that were not necessarily 501 * allocated by _attach(). dev->private and dev->subdevices are 502 * deallocated automatically by the core. 503 */ 504static int s526_detach(struct comedi_device *dev) 505{ 506 printk(KERN_INFO "comedi%d: s526: remove\n", dev->minor); 507 508 if (dev->iobase > 0) 509 release_region(dev->iobase, S526_IOSIZE); 510 511 return 0; 512} 513 514static int s526_gpct_rinsn(struct comedi_device *dev, 515 struct comedi_subdevice *s, struct comedi_insn *insn, 516 unsigned int *data) 517{ 518 int i; /* counts the Data */ 519 int counter_channel = CR_CHAN(insn->chanspec); 520 unsigned short datalow; 521 unsigned short datahigh; 522 523 /* Check if (n > 0) */ 524 if (insn->n <= 0) { 525 printk(KERN_ERR "s526: INSN_READ: n should be > 0\n"); 526 return -EINVAL; 527 } 528 /* Read the low word first */ 529 for (i = 0; i < insn->n; i++) { 530 datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel)); 531 datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel)); 532 data[i] = (int)(datahigh & 0x00FF); 533 data[i] = (data[i] << 16) | (datalow & 0xFFFF); 534 /* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", 535 counter_channel, data[i], datahigh, datalow); */ 536 } 537 return i; 538} 539 540static int s526_gpct_insn_config(struct comedi_device *dev, 541 struct comedi_subdevice *s, 542 struct comedi_insn *insn, unsigned int *data) 543{ 544 int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ 545 int i; 546 short value; 547 union cmReg cmReg; 548 549 /* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", 550 subdev_channel); */ 551 552 for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) { 553 devpriv->s526_gpct_config[subdev_channel].data[i] = 554 insn->data[i]; 555/* printk("data[%d]=%x\n", i, insn->data[i]); */ 556 } 557 558 /* Check what type of Counter the user requested, data[0] contains */ 559 /* the Application type */ 560 switch (insn->data[0]) { 561 case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: 562 /* 563 data[0]: Application Type 564 data[1]: Counter Mode Register Value 565 data[2]: Pre-load Register Value 566 data[3]: Conter Control Register 567 */ 568 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n"); 569 devpriv->s526_gpct_config[subdev_channel].app = 570 PositionMeasurement; 571 572#if 0 573 /* Example of Counter Application */ 574 /* One-shot (software trigger) */ 575 cmReg.reg.coutSource = 0; /* out RCAP */ 576 cmReg.reg.coutPolarity = 1; /* Polarity inverted */ 577 cmReg.reg.autoLoadResetRcap = 0;/* Auto load disabled */ 578 cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ 579 cmReg.reg.ctEnableCtrl = 2; /* Hardware */ 580 cmReg.reg.clockSource = 2; /* Internal */ 581 cmReg.reg.countDir = 1; /* Down */ 582 cmReg.reg.countDirCtrl = 1; /* Software */ 583 cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ 584 cmReg.reg.preloadRegSel = 0; /* PR0 */ 585 cmReg.reg.reserved = 0; 586 587 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 588 589 outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 590 outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 591 592 /* Reset the counter */ 593 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 594 /* Load the counter from PR0 */ 595 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 596 597 /* Reset RCAP (fires one-shot) */ 598 outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 599 600#endif 601 602#if 1 603 /* Set Counter Mode Register */ 604 cmReg.value = insn->data[1] & 0xFFFF; 605 606/* printk("s526: Counter Mode register=%x\n", cmReg.value); */ 607 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 608 609 /* Reset the counter if it is software preload */ 610 if (cmReg.reg.autoLoadResetRcap == 0) { 611 /* Reset the counter */ 612 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 613 /* Load the counter from PR0 614 * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 615 */ 616 } 617#else 618 /* 0 quadrature, 1 software control */ 619 cmReg.reg.countDirCtrl = 0; 620 621 /* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */ 622 if (insn->data[1] == GPCT_X2) 623 cmReg.reg.clockSource = 1; 624 else if (insn->data[1] == GPCT_X4) 625 cmReg.reg.clockSource = 2; 626 else 627 cmReg.reg.clockSource = 0; 628 629 /* When to take into account the indexpulse: */ 630 /*if (insn->data[2] == GPCT_IndexPhaseLowLow) { 631 } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) { 632 } else if (insn->data[2] == GPCT_IndexPhaseHighLow) { 633 } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) { 634 }*/ 635 /* Take into account the index pulse? */ 636 if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX) 637 /* Auto load with INDEX^ */ 638 cmReg.reg.autoLoadResetRcap = 4; 639 640 /* Set Counter Mode Register */ 641 cmReg.value = (short)(insn->data[1] & 0xFFFF); 642 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 643 644 /* Load the pre-load register high word */ 645 value = (short)((insn->data[2] >> 16) & 0xFFFF); 646 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 647 648 /* Load the pre-load register low word */ 649 value = (short)(insn->data[2] & 0xFFFF); 650 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 651 652 /* Write the Counter Control Register */ 653 if (insn->data[3] != 0) { 654 value = (short)(insn->data[3] & 0xFFFF); 655 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 656 } 657 /* Reset the counter if it is software preload */ 658 if (cmReg.reg.autoLoadResetRcap == 0) { 659 /* Reset the counter */ 660 outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 661 /* Load the counter from PR0 */ 662 outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 663 } 664#endif 665 break; 666 667 case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR: 668 /* 669 data[0]: Application Type 670 data[1]: Counter Mode Register Value 671 data[2]: Pre-load Register 0 Value 672 data[3]: Pre-load Register 1 Value 673 data[4]: Conter Control Register 674 */ 675 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n"); 676 devpriv->s526_gpct_config[subdev_channel].app = 677 SinglePulseGeneration; 678 679 /* Set Counter Mode Register */ 680 cmReg.value = (short)(insn->data[1] & 0xFFFF); 681 cmReg.reg.preloadRegSel = 0; /* PR0 */ 682 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 683 684 /* Load the pre-load register 0 high word */ 685 value = (short)((insn->data[2] >> 16) & 0xFFFF); 686 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 687 688 /* Load the pre-load register 0 low word */ 689 value = (short)(insn->data[2] & 0xFFFF); 690 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 691 692 /* Set Counter Mode Register */ 693 cmReg.value = (short)(insn->data[1] & 0xFFFF); 694 cmReg.reg.preloadRegSel = 1; /* PR1 */ 695 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 696 697 /* Load the pre-load register 1 high word */ 698 value = (short)((insn->data[3] >> 16) & 0xFFFF); 699 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 700 701 /* Load the pre-load register 1 low word */ 702 value = (short)(insn->data[3] & 0xFFFF); 703 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 704 705 /* Write the Counter Control Register */ 706 if (insn->data[4] != 0) { 707 value = (short)(insn->data[4] & 0xFFFF); 708 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 709 } 710 break; 711 712 case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR: 713 /* 714 data[0]: Application Type 715 data[1]: Counter Mode Register Value 716 data[2]: Pre-load Register 0 Value 717 data[3]: Pre-load Register 1 Value 718 data[4]: Conter Control Register 719 */ 720 printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n"); 721 devpriv->s526_gpct_config[subdev_channel].app = 722 PulseTrainGeneration; 723 724 /* Set Counter Mode Register */ 725 cmReg.value = (short)(insn->data[1] & 0xFFFF); 726 cmReg.reg.preloadRegSel = 0; /* PR0 */ 727 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 728 729 /* Load the pre-load register 0 high word */ 730 value = (short)((insn->data[2] >> 16) & 0xFFFF); 731 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 732 733 /* Load the pre-load register 0 low word */ 734 value = (short)(insn->data[2] & 0xFFFF); 735 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 736 737 /* Set Counter Mode Register */ 738 cmReg.value = (short)(insn->data[1] & 0xFFFF); 739 cmReg.reg.preloadRegSel = 1; /* PR1 */ 740 outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); 741 742 /* Load the pre-load register 1 high word */ 743 value = (short)((insn->data[3] >> 16) & 0xFFFF); 744 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 745 746 /* Load the pre-load register 1 low word */ 747 value = (short)(insn->data[3] & 0xFFFF); 748 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 749 750 /* Write the Counter Control Register */ 751 if (insn->data[4] != 0) { 752 value = (short)(insn->data[4] & 0xFFFF); 753 outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); 754 } 755 break; 756 757 default: 758 printk(KERN_ERR "s526: unsupported GPCT_insn_config\n"); 759 return -EINVAL; 760 break; 761 } 762 763 return insn->n; 764} 765 766static int s526_gpct_winsn(struct comedi_device *dev, 767 struct comedi_subdevice *s, struct comedi_insn *insn, 768 unsigned int *data) 769{ 770 int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ 771 short value; 772 union cmReg cmReg; 773 774 printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n", 775 subdev_channel); 776 cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel)); 777 printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value); 778 /* Check what Application of Counter this channel is configured for */ 779 switch (devpriv->s526_gpct_config[subdev_channel].app) { 780 case PositionMeasurement: 781 printk(KERN_INFO "S526: INSN_WRITE: PM\n"); 782 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, 783 subdev_channel)); 784 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); 785 break; 786 787 case SinglePulseGeneration: 788 printk(KERN_INFO "S526: INSN_WRITE: SPG\n"); 789 outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, 790 subdev_channel)); 791 outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); 792 break; 793 794 case PulseTrainGeneration: 795 /* data[0] contains the PULSE_WIDTH 796 data[1] contains the PULSE_PERIOD 797 @pre PULSE_PERIOD > PULSE_WIDTH > 0 798 The above periods must be expressed as a multiple of the 799 pulse frequency on the selected source 800 */ 801 printk(KERN_INFO "S526: INSN_WRITE: PTG\n"); 802 if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) { 803 (devpriv->s526_gpct_config[subdev_channel]).data[0] = 804 insn->data[0]; 805 (devpriv->s526_gpct_config[subdev_channel]).data[1] = 806 insn->data[1]; 807 } else { 808 printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n", 809 insn->data[0], insn->data[1]); 810 return -EINVAL; 811 } 812 813 value = (short)((*data >> 16) & 0xFFFF); 814 outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); 815 value = (short)(*data & 0xFFFF); 816 outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); 817 break; 818 default: /* Impossible */ 819 printk 820 ("s526: INSN_WRITE: Functionality %d not implemented yet\n", 821 devpriv->s526_gpct_config[subdev_channel].app); 822 return -EINVAL; 823 break; 824 } 825 /* return the number of samples written */ 826 return insn->n; 827} 828 829#define ISR_ADC_DONE 0x4 830static int s526_ai_insn_config(struct comedi_device *dev, 831 struct comedi_subdevice *s, 832 struct comedi_insn *insn, unsigned int *data) 833{ 834 int result = -EINVAL; 835 836 if (insn->n < 1) 837 return result; 838 839 result = insn->n; 840 841 /* data[0] : channels was set in relevant bits. 842 data[1] : delay 843 */ 844 /* COMMENT: abbotti 2008-07-24: I don't know why you'd want to 845 * enable channels here. The channel should be enabled in the 846 * INSN_READ handler. */ 847 848 /* Enable ADC interrupt */ 849 outw(ISR_ADC_DONE, ADDR_REG(REG_IER)); 850/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */ 851 devpriv->s526_ai_config = (data[0] & 0x3FF) << 5; 852 if (data[1] > 0) 853 devpriv->s526_ai_config |= 0x8000; /* set the delay */ 854 855 devpriv->s526_ai_config |= 0x0001; /* ADC start bit. */ 856 857 return result; 858} 859 860/* 861 * "instructions" read/write data in "one-shot" or "software-triggered" 862 * mode. 863 */ 864static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 865 struct comedi_insn *insn, unsigned int *data) 866{ 867 int n, i; 868 int chan = CR_CHAN(insn->chanspec); 869 unsigned short value; 870 unsigned int d; 871 unsigned int status; 872 873 /* Set configured delay, enable channel for this channel only, 874 * select "ADC read" channel, set "ADC start" bit. */ 875 value = (devpriv->s526_ai_config & 0x8000) | 876 ((1 << 5) << chan) | (chan << 1) | 0x0001; 877 878 /* convert n samples */ 879 for (n = 0; n < insn->n; n++) { 880 /* trigger conversion */ 881 outw(value, ADDR_REG(REG_ADC)); 882/* printk("s526: Wrote 0x%04x to ADC\n", value); */ 883/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */ 884 885#define TIMEOUT 100 886 /* wait for conversion to end */ 887 for (i = 0; i < TIMEOUT; i++) { 888 status = inw(ADDR_REG(REG_ISR)); 889 if (status & ISR_ADC_DONE) { 890 outw(ISR_ADC_DONE, ADDR_REG(REG_ISR)); 891 break; 892 } 893 } 894 if (i == TIMEOUT) { 895 /* printk() should be used instead of printk() 896 * whenever the code can be called from real-time. */ 897 printk(KERN_ERR "s526: ADC(0x%04x) timeout\n", 898 inw(ADDR_REG(REG_ISR))); 899 return -ETIMEDOUT; 900 } 901 902 /* read data */ 903 d = inw(ADDR_REG(REG_ADD)); 904/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */ 905 906 /* munge data */ 907 data[n] = d ^ 0x8000; 908 } 909 910 /* return the number of samples read/written */ 911 return n; 912} 913 914static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, 915 struct comedi_insn *insn, unsigned int *data) 916{ 917 int i; 918 int chan = CR_CHAN(insn->chanspec); 919 unsigned short val; 920 921/* printk("s526_ao_winsn\n"); */ 922 val = chan << 1; 923/* outw(val, dev->iobase + REG_DAC); */ 924 outw(val, ADDR_REG(REG_DAC)); 925 926 /* Writing a list of values to an AO channel is probably not 927 * very useful, but that's how the interface is defined. */ 928 for (i = 0; i < insn->n; i++) { 929 /* a typical programming sequence */ 930 /* write the data to preload register 931 * outw(data[i], dev->iobase + REG_ADD); 932 */ 933 /* write the data to preload register */ 934 outw(data[i], ADDR_REG(REG_ADD)); 935 devpriv->ao_readback[chan] = data[i]; 936/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */ 937 outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/ 938 } 939 940 /* return the number of samples read/written */ 941 return i; 942} 943 944/* AO subdevices should have a read insn as well as a write insn. 945 * Usually this means copying a value stored in devpriv. */ 946static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, 947 struct comedi_insn *insn, unsigned int *data) 948{ 949 int i; 950 int chan = CR_CHAN(insn->chanspec); 951 952 for (i = 0; i < insn->n; i++) 953 data[i] = devpriv->ao_readback[chan]; 954 955 return i; 956} 957 958/* DIO devices are slightly special. Although it is possible to 959 * implement the insn_read/insn_write interface, it is much more 960 * useful to applications if you implement the insn_bits interface. 961 * This allows packed reading/writing of the DIO channels. The 962 * comedi core can convert between insn_bits and insn_read/write */ 963static int s526_dio_insn_bits(struct comedi_device *dev, 964 struct comedi_subdevice *s, 965 struct comedi_insn *insn, unsigned int *data) 966{ 967 if (insn->n != 2) 968 return -EINVAL; 969 970 /* The insn data is a mask in data[0] and the new data 971 * in data[1], each channel cooresponding to a bit. */ 972 if (data[0]) { 973 s->state &= ~data[0]; 974 s->state |= data[0] & data[1]; 975 /* Write out the new digital output lines */ 976 outw(s->state, ADDR_REG(REG_DIO)); 977 } 978 979 /* on return, data[1] contains the value of the digital 980 * input and output lines. */ 981 data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ 982 /* or we could just return the software copy of the output values if 983 * it was a purely digital output subdevice */ 984 /* data[1]=s->state & 0xFF; */ 985 986 return 2; 987} 988 989static int s526_dio_insn_config(struct comedi_device *dev, 990 struct comedi_subdevice *s, 991 struct comedi_insn *insn, unsigned int *data) 992{ 993 int chan = CR_CHAN(insn->chanspec); 994 int group, mask; 995 996 printk(KERN_INFO "S526 DIO insn_config\n"); 997 998 /* The input or output configuration of each digital line is 999 * configured by a special insn_config instruction. chanspec 1000 * contains the channel to be changed, and data[0] contains the 1001 * value COMEDI_INPUT or COMEDI_OUTPUT. */ 1002 1003 group = chan >> 2; 1004 mask = 0xF << (group << 2); 1005 switch (data[0]) { 1006 case INSN_CONFIG_DIO_OUTPUT: 1007 /* bit 10/11 set the group 1/2's mode */ 1008 s->state |= 1 << (group + 10); 1009 s->io_bits |= mask; 1010 break; 1011 case INSN_CONFIG_DIO_INPUT: 1012 s->state &= ~(1 << (group + 10)); /* 1 is output, 0 is input. */ 1013 s->io_bits &= ~mask; 1014 break; 1015 case INSN_CONFIG_DIO_QUERY: 1016 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; 1017 return insn->n; 1018 default: 1019 return -EINVAL; 1020 } 1021 outw(s->state, ADDR_REG(REG_DIO)); 1022 1023 return 1; 1024} 1025 1026/* 1027 * A convenient macro that defines init_module() and cleanup_module(), 1028 * as necessary. 1029 */ 1030static int __init driver_s526_init_module(void) 1031{ 1032 return comedi_driver_register(&driver_s526); 1033} 1034 1035static void __exit driver_s526_cleanup_module(void) 1036{ 1037 comedi_driver_unregister(&driver_s526); 1038} 1039 1040module_init(driver_s526_init_module); 1041module_exit(driver_s526_cleanup_module); 1042 1043MODULE_AUTHOR("Comedi http://www.comedi.org"); 1044MODULE_DESCRIPTION("Comedi low-level driver"); 1045MODULE_LICENSE("GPL"); 1046