1/* 2 * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. 3 * 4 * ADDI-DATA GmbH 5 * Dieselstrasse 3 6 * D-77833 Ottersweier 7 * Tel: +19(0)7223/9493-0 8 * Fax: +49(0)7223/9493-92 9 * http://www.addi-data.com 10 * info@addi-data.com 11 * 12 * This program is free software; you can redistribute it and/or modify it under 13 * the terms of the GNU General Public License as published by the Free Software 14 * Foundation; either version 2 of the License, or (at your option) any later 15 * version. 16 * 17 * This program is distributed in the hope that it will be useful, but WITHOUT 18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 19 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 20 * details. 21 */ 22 23/* Card Specific information */ 24#define APCI035_ADDRESS_RANGE 255 25 26/* Timer / Watchdog Related Defines */ 27#define APCI035_TCW_SYNC_ENABLEDISABLE 0 28#define APCI035_TCW_RELOAD_VALUE 4 29#define APCI035_TCW_TIMEBASE 8 30#define APCI035_TCW_PROG 12 31#define APCI035_TCW_TRIG_STATUS 16 32#define APCI035_TCW_IRQ 20 33#define APCI035_TCW_WARN_TIMEVAL 24 34#define APCI035_TCW_WARN_TIMEBASE 28 35 36#define ADDIDATA_TIMER 0 37/* #define ADDIDATA_WATCHDOG 1 */ 38 39#define APCI035_TW1 0 40#define APCI035_TW2 32 41#define APCI035_TW3 64 42#define APCI035_TW4 96 43 44#define APCI035_AI_OFFSET 0 45#define APCI035_TEMP 128 46#define APCI035_ALR_SEQ 4 47#define APCI035_START_STOP_INDEX 8 48#define APCI035_ALR_START_STOP 12 49#define APCI035_ALR_IRQ 16 50#define APCI035_EOS 20 51#define APCI035_CHAN_NO 24 52#define APCI035_CHAN_VAL 28 53#define APCI035_CONV_TIME_TIME_BASE 36 54#define APCI035_RELOAD_CONV_TIME_VAL 32 55#define APCI035_DELAY_TIME_TIME_BASE 44 56#define APCI035_RELOAD_DELAY_TIME_VAL 40 57#define ENABLE_EXT_TRIG 1 58#define ENABLE_EXT_GATE 2 59#define ENABLE_EXT_TRIG_GATE 3 60 61#define ANALOG_INPUT 0 62#define TEMPERATURE 1 63#define RESISTANCE 2 64 65#define ADDIDATA_GREATER_THAN_TEST 0 66#define ADDIDATA_LESS_THAN_TEST 1 67 68#define APCI035_MAXVOLT 2.5 69 70#define ADDIDATA_UNIPOLAR 1 71#define ADDIDATA_BIPOLAR 2 72 73/* ANALOG INPUT RANGE */ 74static struct comedi_lrange range_apci035_ai = { 75 8, { 76 BIP_RANGE(10), 77 BIP_RANGE(5), 78 BIP_RANGE(2), 79 BIP_RANGE(1), 80 UNI_RANGE(10), 81 UNI_RANGE(5), 82 UNI_RANGE(2), 83 UNI_RANGE(1) 84 } 85}; 86 87static int i_WatchdogNbr; 88static int i_Temp; 89static int i_Flag = 1; 90 91/* 92 * Configures The Timer , Counter or Watchdog 93 * 94 * data[0] 0 = Configure As Timer, 1 = Configure As Watchdog 95 * data[1] Watchdog number 96 * data[2] Time base Unit 97 * data[3] Reload Value 98 * data[4] External Trigger, 1 = Enable, 0 = Disable 99 * data[5] External Trigger Level 100 * 00 = Trigger Disabled 101 * 01 = Trigger Enabled (Low level) 102 * 10 = Trigger Enabled (High Level) 103 * 11 = Trigger Enabled (High/Low level) 104 * data[6] External Gate, 1 = Enable, 0 = Disable 105 * data[7] External Gate level 106 * 00 = Gate Disabled 107 * 01 = Gate Enabled (Low level) 108 * 10 = Gate Enabled (High Level) 109 * data[8] Warning Relay, 1 = Enable, 0 = Disable 110 * data[9] Warning Delay available 111 * data[10] Warning Relay Time unit 112 * data[11] Warning Relay Time Reload value 113 * data[12] Reset Relay, 1 = Enable, 0 = Disable 114 * data[13] Interrupt, 1 = Enable, 0 = Disable 115 */ 116static int apci035_timer_config(struct comedi_device *dev, 117 struct comedi_subdevice *s, 118 struct comedi_insn *insn, 119 unsigned int *data) 120{ 121 struct addi_private *devpriv = dev->private; 122 unsigned int ui_Status; 123 unsigned int ui_Command; 124 unsigned int ui_Mode; 125 126 i_Temp = 0; 127 devpriv->tsk_Current = current; 128 devpriv->b_TimerSelectMode = data[0]; 129 i_WatchdogNbr = data[1]; 130 if (data[0] == 0) 131 ui_Mode = 2; 132 else 133 ui_Mode = 0; 134 135 ui_Command = 0; 136 outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 137 138 ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 139 140 /* Set the reload value */ 141 outl(data[3], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 4); 142 143 /* Set the time unit */ 144 outl(data[2], devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 8); 145 if (data[0] == ADDIDATA_TIMER) { 146 147 /* Set the mode : */ 148 /* - Disable the hardware */ 149 /* - Disable the counter mode */ 150 /* - Disable the warning */ 151 /* - Disable the reset */ 152 /* - Enable the timer mode */ 153 /* - Set the timer mode */ 154 155 ui_Command = 156 (ui_Command & 0xFFF719E2UL) | ui_Mode << 13UL | 0x10UL; 157 158 } else if (data[0] == ADDIDATA_WATCHDOG) { 159 160 /* Set the mode : */ 161 /* - Disable the hardware */ 162 /* - Disable the counter mode */ 163 /* - Disable the warning */ 164 /* - Disable the reset */ 165 /* - Disable the timer mode */ 166 167 ui_Command = ui_Command & 0xFFF819E2UL; 168 169 } else { 170 dev_err(dev->class_dev, "The parameter for Timer/watchdog selection is in error\n"); 171 return -EINVAL; 172 } 173 174 outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 175 176 ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 177 178 /* Disable the hardware trigger */ 179 ui_Command = ui_Command & 0xFFFFF89FUL; 180 if (data[4] == 1) { 181 /* Set the hardware trigger level */ 182 ui_Command = ui_Command | (data[5] << 5); 183 } 184 outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 185 186 ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 187 188 /* Disable the hardware gate */ 189 ui_Command = ui_Command & 0xFFFFF87FUL; 190 if (data[6] == 1) { 191 /* Set the hardware gate level */ 192 ui_Command = ui_Command | (data[7] << 7); 193 } 194 outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 195 196 ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 197 198 /* Disable the hardware output */ 199 ui_Command = ui_Command & 0xFFFFF9FBUL; 200 201 /* Set the hardware output level */ 202 ui_Command = ui_Command | (data[8] << 2); 203 outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 204 if (data[9] == 1) { 205 /* Set the reload value */ 206 outl(data[11], 207 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 24); 208 209 /* Set the time unite */ 210 outl(data[10], 211 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 28); 212 } 213 214 ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 215 216 /* Disable the hardware output */ 217 ui_Command = ui_Command & 0xFFFFF9F7UL; 218 219 /* Set the hardware output level */ 220 ui_Command = ui_Command | (data[12] << 3); 221 outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 222 223 /* Enable the watchdog interrupt */ 224 ui_Command = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 225 226 /* Set the interrupt selection */ 227 ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); 228 229 ui_Command = (ui_Command & 0xFFFFF9FDUL) | (data[13] << 1); 230 outl(ui_Command, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 231 232 return insn->n; 233} 234 235/* 236 * Start / Stop The Selected Timer , or Watchdog 237 * 238 * data[0] 239 * 0 - Stop Selected Timer/Watchdog 240 * 1 - Start Selected Timer/Watch*dog 241 * 2 - Trigger Selected Timer/Watchdog 242 * 3 - Stop All Timer/Watchdog 243 * 4 - Start All Timer/Watchdog 244 * 5 - Trigger All Timer/Watchdog 245 */ 246static int apci035_timer_write(struct comedi_device *dev, 247 struct comedi_subdevice *s, 248 struct comedi_insn *insn, 249 unsigned int *data) 250{ 251 struct addi_private *devpriv = dev->private; 252 unsigned int ui_Command; 253 int i_Count; 254 255 if (data[0] == 1) { 256 ui_Command = 257 inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 258 259 /* Start the hardware */ 260 ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x1UL; 261 outl(ui_Command, 262 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 263 } 264 if (data[0] == 2) { 265 ui_Command = 266 inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 267 268 /* Set the trigger command */ 269 ui_Command = (ui_Command & 0xFFFFF9FFUL) | 0x200UL; 270 outl(ui_Command, 271 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 272 } 273 274 if (data[0] == 0) { 275 /* Stop The Watchdog */ 276 ui_Command = 0; 277 /* 278 * ui_Command = inl(devpriv->iobase+((i_WatchdogNbr-1)*32)+12); 279 * ui_Command = ui_Command & 0xFFFFF9FEUL; 280 */ 281 outl(ui_Command, 282 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 12); 283 } 284 if (data[0] == 3) { 285 /* stop all Watchdogs */ 286 ui_Command = 0; 287 for (i_Count = 1; i_Count <= 4; i_Count++) { 288 if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) 289 ui_Command = 0x2UL; 290 else 291 ui_Command = 0x10UL; 292 293 i_WatchdogNbr = i_Count; 294 outl(ui_Command, 295 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 296 0); 297 } 298 299 } 300 if (data[0] == 4) { 301 /* start all Watchdogs */ 302 ui_Command = 0; 303 for (i_Count = 1; i_Count <= 4; i_Count++) { 304 if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) 305 ui_Command = 0x1UL; 306 else 307 ui_Command = 0x8UL; 308 309 i_WatchdogNbr = i_Count; 310 outl(ui_Command, 311 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 312 0); 313 } 314 } 315 if (data[0] == 5) { 316 /* trigger all Watchdogs */ 317 ui_Command = 0; 318 for (i_Count = 1; i_Count <= 4; i_Count++) { 319 if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) 320 ui_Command = 0x4UL; 321 else 322 ui_Command = 0x20UL; 323 324 i_WatchdogNbr = i_Count; 325 outl(ui_Command, 326 devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 327 0); 328 } 329 i_Temp = 1; 330 } 331 return insn->n; 332} 333 334/* 335 * Read The Selected Timer , Counter or Watchdog 336 * 337 * data[0] software trigger status 338 * data[1] hardware trigger status 339 * data[2] Software clear status 340 * data[3] Overflow status 341 * data[4] Timer actual value 342 */ 343static int apci035_timer_read(struct comedi_device *dev, 344 struct comedi_subdevice *s, 345 struct comedi_insn *insn, 346 unsigned int *data) 347{ 348 struct addi_private *devpriv = dev->private; 349 unsigned int ui_Status; /* Status register */ 350 351 i_WatchdogNbr = insn->unused[0]; 352 353 /* Get the status */ 354 ui_Status = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 16); 355 356 /* Get the software trigger status */ 357 data[0] = ((ui_Status >> 1) & 1); 358 359 /* Get the hardware trigger status */ 360 data[1] = ((ui_Status >> 2) & 1); 361 362 /* Get the software clear status */ 363 data[2] = ((ui_Status >> 3) & 1); 364 365 /* Get the overflow status */ 366 data[3] = ((ui_Status >> 0) & 1); 367 if (devpriv->b_TimerSelectMode == ADDIDATA_TIMER) 368 data[4] = inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); 369 370 return insn->n; 371} 372 373/* 374 * Configures The Analog Input Subdevice 375 * 376 * data[0] Warning delay value 377 */ 378static int apci035_ai_config(struct comedi_device *dev, 379 struct comedi_subdevice *s, 380 struct comedi_insn *insn, 381 unsigned int *data) 382{ 383 struct addi_private *devpriv = dev->private; 384 385 devpriv->tsk_Current = current; 386 outl(0x200 | 0, devpriv->iobase + 128 + 0x4); 387 outl(0, devpriv->iobase + 128 + 0); 388 389 /* Initialise the warning value */ 390 outl(0x300 | 0, devpriv->iobase + 128 + 0x4); 391 outl((data[0] << 8), devpriv->iobase + 128 + 0); 392 outl(0x200000UL, devpriv->iobase + 128 + 12); 393 394 return insn->n; 395} 396 397/* 398 * Read value of the selected channel 399 * 400 * data[0] Digital Value Of Input 401 */ 402static int apci035_ai_read(struct comedi_device *dev, 403 struct comedi_subdevice *s, 404 struct comedi_insn *insn, 405 unsigned int *data) 406{ 407 struct addi_private *devpriv = dev->private; 408 unsigned int ui_CommandRegister; 409 410 /* Set the start */ 411 ui_CommandRegister = 0x80000; 412 413 /* Write the command register */ 414 outl(ui_CommandRegister, devpriv->iobase + 128 + 8); 415 416 /* Read the digital value of the input */ 417 data[0] = inl(devpriv->iobase + 128 + 28); 418 return insn->n; 419} 420 421static int apci035_reset(struct comedi_device *dev) 422{ 423 struct addi_private *devpriv = dev->private; 424 int i_Count; 425 426 for (i_Count = 1; i_Count <= 4; i_Count++) { 427 i_WatchdogNbr = i_Count; 428 429 /* stop all timers */ 430 outl(0x0, devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 0); 431 } 432 outl(0x0, devpriv->iobase + 128 + 12); /* Disable the warning delay */ 433 434 return 0; 435} 436 437static void apci035_interrupt(int irq, void *d) 438{ 439 struct comedi_device *dev = d; 440 struct addi_private *devpriv = dev->private; 441 unsigned int ui_StatusRegister1; 442 unsigned int ui_StatusRegister2; 443 unsigned int ui_ReadCommand; 444 unsigned int ui_ChannelNumber; 445 unsigned int ui_DigitalTemperature; 446 447 if (i_Temp == 1) { 448 i_WatchdogNbr = i_Flag; 449 i_Flag = i_Flag + 1; 450 } 451 452 /* Read the interrupt status register of temperature Warning */ 453 ui_StatusRegister1 = inl(devpriv->iobase + 128 + 16); 454 455 /* Read the interrupt status register for Watchdog/timer */ 456 ui_StatusRegister2 = 457 inl(devpriv->iobase + ((i_WatchdogNbr - 1) * 32) + 20); 458 459 /* Test if warning relay interrupt */ 460 if ((((ui_StatusRegister1) & 0x8) == 0x8)) { 461 462 /* Disable the temperature warning */ 463 ui_ReadCommand = inl(devpriv->iobase + 128 + 12); 464 ui_ReadCommand = ui_ReadCommand & 0xFFDF0000UL; 465 outl(ui_ReadCommand, devpriv->iobase + 128 + 12); 466 467 /* Read the channel number */ 468 ui_ChannelNumber = inl(devpriv->iobase + 128 + 60); 469 470 /* Read the digital temperature value */ 471 ui_DigitalTemperature = inl(devpriv->iobase + 128 + 60); 472 473 /* send signal to the sample */ 474 send_sig(SIGIO, devpriv->tsk_Current, 0); 475 476 } else if ((ui_StatusRegister2 & 0x1) == 0x1) { 477 /* send signal to the sample */ 478 send_sig(SIGIO, devpriv->tsk_Current, 0); 479 } 480} 481