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