1/* 2 comedi/drivers/ni_atmio16d.c 3 Hardware driver for National Instruments AT-MIO16D board 4 Copyright (C) 2000 Chris R. Baugher <baugher@enteract.com> 5 6 This program is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful, 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU General Public License for more details. 15 */ 16/* 17Driver: ni_atmio16d 18Description: National Instruments AT-MIO-16D 19Author: Chris R. Baugher <baugher@enteract.com> 20Status: unknown 21Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) 22*/ 23/* 24 * I must give credit here to Michal Dobes <dobes@tesnet.cz> who 25 * wrote the driver for Advantec's pcl812 boards. I used the interrupt 26 * handling code from his driver as an example for this one. 27 * 28 * Chris Baugher 29 * 5/1/2000 30 * 31 */ 32 33#include <linux/module.h> 34#include <linux/interrupt.h> 35#include "../comedidev.h" 36 37#include "comedi_fc.h" 38#include "8255.h" 39 40/* Configuration and Status Registers */ 41#define COM_REG_1 0x00 /* wo 16 */ 42#define STAT_REG 0x00 /* ro 16 */ 43#define COM_REG_2 0x02 /* wo 16 */ 44/* Event Strobe Registers */ 45#define START_CONVERT_REG 0x08 /* wo 16 */ 46#define START_DAQ_REG 0x0A /* wo 16 */ 47#define AD_CLEAR_REG 0x0C /* wo 16 */ 48#define EXT_STROBE_REG 0x0E /* wo 16 */ 49/* Analog Output Registers */ 50#define DAC0_REG 0x10 /* wo 16 */ 51#define DAC1_REG 0x12 /* wo 16 */ 52#define INT2CLR_REG 0x14 /* wo 16 */ 53/* Analog Input Registers */ 54#define MUX_CNTR_REG 0x04 /* wo 16 */ 55#define MUX_GAIN_REG 0x06 /* wo 16 */ 56#define AD_FIFO_REG 0x16 /* ro 16 */ 57#define DMA_TC_INT_CLR_REG 0x16 /* wo 16 */ 58/* AM9513A Counter/Timer Registers */ 59#define AM9513A_DATA_REG 0x18 /* rw 16 */ 60#define AM9513A_COM_REG 0x1A /* wo 16 */ 61#define AM9513A_STAT_REG 0x1A /* ro 16 */ 62/* MIO-16 Digital I/O Registers */ 63#define MIO_16_DIG_IN_REG 0x1C /* ro 16 */ 64#define MIO_16_DIG_OUT_REG 0x1C /* wo 16 */ 65/* RTSI Switch Registers */ 66#define RTSI_SW_SHIFT_REG 0x1E /* wo 8 */ 67#define RTSI_SW_STROBE_REG 0x1F /* wo 8 */ 68/* DIO-24 Registers */ 69#define DIO_24_PORTA_REG 0x00 /* rw 8 */ 70#define DIO_24_PORTB_REG 0x01 /* rw 8 */ 71#define DIO_24_PORTC_REG 0x02 /* rw 8 */ 72#define DIO_24_CNFG_REG 0x03 /* wo 8 */ 73 74/* Command Register bits */ 75#define COMREG1_2SCADC 0x0001 76#define COMREG1_1632CNT 0x0002 77#define COMREG1_SCANEN 0x0008 78#define COMREG1_DAQEN 0x0010 79#define COMREG1_DMAEN 0x0020 80#define COMREG1_CONVINTEN 0x0080 81#define COMREG2_SCN2 0x0010 82#define COMREG2_INTEN 0x0080 83#define COMREG2_DOUTEN0 0x0100 84#define COMREG2_DOUTEN1 0x0200 85/* Status Register bits */ 86#define STAT_AD_OVERRUN 0x0100 87#define STAT_AD_OVERFLOW 0x0200 88#define STAT_AD_DAQPROG 0x0800 89#define STAT_AD_CONVAVAIL 0x2000 90#define STAT_AD_DAQSTOPINT 0x4000 91/* AM9513A Counter/Timer defines */ 92#define CLOCK_1_MHZ 0x8B25 93#define CLOCK_100_KHZ 0x8C25 94#define CLOCK_10_KHZ 0x8D25 95#define CLOCK_1_KHZ 0x8E25 96#define CLOCK_100_HZ 0x8F25 97 98struct atmio16_board_t { 99 100 const char *name; 101 int has_8255; 102}; 103 104/* range structs */ 105static const struct comedi_lrange range_atmio16d_ai_10_bipolar = { 106 4, { 107 BIP_RANGE(10), 108 BIP_RANGE(1), 109 BIP_RANGE(0.1), 110 BIP_RANGE(0.02) 111 } 112}; 113 114static const struct comedi_lrange range_atmio16d_ai_5_bipolar = { 115 4, { 116 BIP_RANGE(5), 117 BIP_RANGE(0.5), 118 BIP_RANGE(0.05), 119 BIP_RANGE(0.01) 120 } 121}; 122 123static const struct comedi_lrange range_atmio16d_ai_unipolar = { 124 4, { 125 UNI_RANGE(10), 126 UNI_RANGE(1), 127 UNI_RANGE(0.1), 128 UNI_RANGE(0.02) 129 } 130}; 131 132/* private data struct */ 133struct atmio16d_private { 134 enum { adc_diff, adc_singleended } adc_mux; 135 enum { adc_bipolar10, adc_bipolar5, adc_unipolar10 } adc_range; 136 enum { adc_2comp, adc_straight } adc_coding; 137 enum { dac_bipolar, dac_unipolar } dac0_range, dac1_range; 138 enum { dac_internal, dac_external } dac0_reference, dac1_reference; 139 enum { dac_2comp, dac_straight } dac0_coding, dac1_coding; 140 const struct comedi_lrange *ao_range_type_list[2]; 141 unsigned int com_reg_1_state; /* current state of command register 1 */ 142 unsigned int com_reg_2_state; /* current state of command register 2 */ 143}; 144 145static void reset_counters(struct comedi_device *dev) 146{ 147 /* Counter 2 */ 148 outw(0xFFC2, dev->iobase + AM9513A_COM_REG); 149 outw(0xFF02, dev->iobase + AM9513A_COM_REG); 150 outw(0x4, dev->iobase + AM9513A_DATA_REG); 151 outw(0xFF0A, dev->iobase + AM9513A_COM_REG); 152 outw(0x3, dev->iobase + AM9513A_DATA_REG); 153 outw(0xFF42, dev->iobase + AM9513A_COM_REG); 154 outw(0xFF42, dev->iobase + AM9513A_COM_REG); 155 /* Counter 3 */ 156 outw(0xFFC4, dev->iobase + AM9513A_COM_REG); 157 outw(0xFF03, dev->iobase + AM9513A_COM_REG); 158 outw(0x4, dev->iobase + AM9513A_DATA_REG); 159 outw(0xFF0B, dev->iobase + AM9513A_COM_REG); 160 outw(0x3, dev->iobase + AM9513A_DATA_REG); 161 outw(0xFF44, dev->iobase + AM9513A_COM_REG); 162 outw(0xFF44, dev->iobase + AM9513A_COM_REG); 163 /* Counter 4 */ 164 outw(0xFFC8, dev->iobase + AM9513A_COM_REG); 165 outw(0xFF04, dev->iobase + AM9513A_COM_REG); 166 outw(0x4, dev->iobase + AM9513A_DATA_REG); 167 outw(0xFF0C, dev->iobase + AM9513A_COM_REG); 168 outw(0x3, dev->iobase + AM9513A_DATA_REG); 169 outw(0xFF48, dev->iobase + AM9513A_COM_REG); 170 outw(0xFF48, dev->iobase + AM9513A_COM_REG); 171 /* Counter 5 */ 172 outw(0xFFD0, dev->iobase + AM9513A_COM_REG); 173 outw(0xFF05, dev->iobase + AM9513A_COM_REG); 174 outw(0x4, dev->iobase + AM9513A_DATA_REG); 175 outw(0xFF0D, dev->iobase + AM9513A_COM_REG); 176 outw(0x3, dev->iobase + AM9513A_DATA_REG); 177 outw(0xFF50, dev->iobase + AM9513A_COM_REG); 178 outw(0xFF50, dev->iobase + AM9513A_COM_REG); 179 180 outw(0, dev->iobase + AD_CLEAR_REG); 181} 182 183static void reset_atmio16d(struct comedi_device *dev) 184{ 185 struct atmio16d_private *devpriv = dev->private; 186 int i; 187 188 /* now we need to initialize the board */ 189 outw(0, dev->iobase + COM_REG_1); 190 outw(0, dev->iobase + COM_REG_2); 191 outw(0, dev->iobase + MUX_GAIN_REG); 192 /* init AM9513A timer */ 193 outw(0xFFFF, dev->iobase + AM9513A_COM_REG); 194 outw(0xFFEF, dev->iobase + AM9513A_COM_REG); 195 outw(0xFF17, dev->iobase + AM9513A_COM_REG); 196 outw(0xF000, dev->iobase + AM9513A_DATA_REG); 197 for (i = 1; i <= 5; ++i) { 198 outw(0xFF00 + i, dev->iobase + AM9513A_COM_REG); 199 outw(0x0004, dev->iobase + AM9513A_DATA_REG); 200 outw(0xFF08 + i, dev->iobase + AM9513A_COM_REG); 201 outw(0x3, dev->iobase + AM9513A_DATA_REG); 202 } 203 outw(0xFF5F, dev->iobase + AM9513A_COM_REG); 204 /* timer init done */ 205 outw(0, dev->iobase + AD_CLEAR_REG); 206 outw(0, dev->iobase + INT2CLR_REG); 207 /* select straight binary mode for Analog Input */ 208 devpriv->com_reg_1_state |= 1; 209 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); 210 devpriv->adc_coding = adc_straight; 211 /* zero the analog outputs */ 212 outw(2048, dev->iobase + DAC0_REG); 213 outw(2048, dev->iobase + DAC1_REG); 214} 215 216static irqreturn_t atmio16d_interrupt(int irq, void *d) 217{ 218 struct comedi_device *dev = d; 219 struct comedi_subdevice *s = dev->read_subdev; 220 221 comedi_buf_put(s, inw(dev->iobase + AD_FIFO_REG)); 222 223 comedi_event(dev, s); 224 return IRQ_HANDLED; 225} 226 227static int atmio16d_ai_cmdtest(struct comedi_device *dev, 228 struct comedi_subdevice *s, 229 struct comedi_cmd *cmd) 230{ 231 int err = 0; 232 233 /* Step 1 : check if triggers are trivially valid */ 234 235 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); 236 err |= cfc_check_trigger_src(&cmd->scan_begin_src, 237 TRIG_FOLLOW | TRIG_TIMER); 238 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); 239 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 240 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); 241 242 if (err) 243 return 1; 244 245 /* Step 2a : make sure trigger sources are unique */ 246 247 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); 248 err |= cfc_check_trigger_is_unique(cmd->stop_src); 249 250 /* Step 2b : and mutually compatible */ 251 252 if (err) 253 return 2; 254 255 /* Step 3: check if arguments are trivially valid */ 256 257 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0); 258 259 if (cmd->scan_begin_src == TRIG_FOLLOW) { 260 /* internal trigger */ 261 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 262 } else { 263#if 0 264 /* external trigger */ 265 /* should be level/edge, hi/lo specification here */ 266 err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 267#endif 268 } 269 270 err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000); 271#if 0 272 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, SLOWEST_TIMER); 273#endif 274 275 err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len); 276 277 if (cmd->stop_src == TRIG_COUNT) 278 err |= cfc_check_trigger_arg_min(&cmd->stop_arg, 1); 279 else /* TRIG_NONE */ 280 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0); 281 282 if (err) 283 return 3; 284 285 return 0; 286} 287 288static int atmio16d_ai_cmd(struct comedi_device *dev, 289 struct comedi_subdevice *s) 290{ 291 struct atmio16d_private *devpriv = dev->private; 292 struct comedi_cmd *cmd = &s->async->cmd; 293 unsigned int timer, base_clock; 294 unsigned int sample_count, tmp, chan, gain; 295 int i; 296 297 /* This is slowly becoming a working command interface. * 298 * It is still uber-experimental */ 299 300 reset_counters(dev); 301 s->async->cur_chan = 0; 302 303 /* check if scanning multiple channels */ 304 if (cmd->chanlist_len < 2) { 305 devpriv->com_reg_1_state &= ~COMREG1_SCANEN; 306 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); 307 } else { 308 devpriv->com_reg_1_state |= COMREG1_SCANEN; 309 devpriv->com_reg_2_state |= COMREG2_SCN2; 310 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); 311 outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2); 312 } 313 314 /* Setup the Mux-Gain Counter */ 315 for (i = 0; i < cmd->chanlist_len; ++i) { 316 chan = CR_CHAN(cmd->chanlist[i]); 317 gain = CR_RANGE(cmd->chanlist[i]); 318 outw(i, dev->iobase + MUX_CNTR_REG); 319 tmp = chan | (gain << 6); 320 if (i == cmd->scan_end_arg - 1) 321 tmp |= 0x0010; /* set LASTONE bit */ 322 outw(tmp, dev->iobase + MUX_GAIN_REG); 323 } 324 325 /* Now program the sample interval timer */ 326 /* Figure out which clock to use then get an 327 * appropriate timer value */ 328 if (cmd->convert_arg < 65536000) { 329 base_clock = CLOCK_1_MHZ; 330 timer = cmd->convert_arg / 1000; 331 } else if (cmd->convert_arg < 655360000) { 332 base_clock = CLOCK_100_KHZ; 333 timer = cmd->convert_arg / 10000; 334 } else /* cmd->convert_arg < 6553600000 */ { 335 base_clock = CLOCK_10_KHZ; 336 timer = cmd->convert_arg / 100000; 337 } 338 outw(0xFF03, dev->iobase + AM9513A_COM_REG); 339 outw(base_clock, dev->iobase + AM9513A_DATA_REG); 340 outw(0xFF0B, dev->iobase + AM9513A_COM_REG); 341 outw(0x2, dev->iobase + AM9513A_DATA_REG); 342 outw(0xFF44, dev->iobase + AM9513A_COM_REG); 343 outw(0xFFF3, dev->iobase + AM9513A_COM_REG); 344 outw(timer, dev->iobase + AM9513A_DATA_REG); 345 outw(0xFF24, dev->iobase + AM9513A_COM_REG); 346 347 /* Now figure out how many samples to get */ 348 /* and program the sample counter */ 349 sample_count = cmd->stop_arg * cmd->scan_end_arg; 350 outw(0xFF04, dev->iobase + AM9513A_COM_REG); 351 outw(0x1025, dev->iobase + AM9513A_DATA_REG); 352 outw(0xFF0C, dev->iobase + AM9513A_COM_REG); 353 if (sample_count < 65536) { 354 /* use only Counter 4 */ 355 outw(sample_count, dev->iobase + AM9513A_DATA_REG); 356 outw(0xFF48, dev->iobase + AM9513A_COM_REG); 357 outw(0xFFF4, dev->iobase + AM9513A_COM_REG); 358 outw(0xFF28, dev->iobase + AM9513A_COM_REG); 359 devpriv->com_reg_1_state &= ~COMREG1_1632CNT; 360 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); 361 } else { 362 /* Counter 4 and 5 are needed */ 363 364 tmp = sample_count & 0xFFFF; 365 if (tmp) 366 outw(tmp - 1, dev->iobase + AM9513A_DATA_REG); 367 else 368 outw(0xFFFF, dev->iobase + AM9513A_DATA_REG); 369 370 outw(0xFF48, dev->iobase + AM9513A_COM_REG); 371 outw(0, dev->iobase + AM9513A_DATA_REG); 372 outw(0xFF28, dev->iobase + AM9513A_COM_REG); 373 outw(0xFF05, dev->iobase + AM9513A_COM_REG); 374 outw(0x25, dev->iobase + AM9513A_DATA_REG); 375 outw(0xFF0D, dev->iobase + AM9513A_COM_REG); 376 tmp = sample_count & 0xFFFF; 377 if ((tmp == 0) || (tmp == 1)) { 378 outw((sample_count >> 16) & 0xFFFF, 379 dev->iobase + AM9513A_DATA_REG); 380 } else { 381 outw(((sample_count >> 16) & 0xFFFF) + 1, 382 dev->iobase + AM9513A_DATA_REG); 383 } 384 outw(0xFF70, dev->iobase + AM9513A_COM_REG); 385 devpriv->com_reg_1_state |= COMREG1_1632CNT; 386 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); 387 } 388 389 /* Program the scan interval timer ONLY IF SCANNING IS ENABLED */ 390 /* Figure out which clock to use then get an 391 * appropriate timer value */ 392 if (cmd->chanlist_len > 1) { 393 if (cmd->scan_begin_arg < 65536000) { 394 base_clock = CLOCK_1_MHZ; 395 timer = cmd->scan_begin_arg / 1000; 396 } else if (cmd->scan_begin_arg < 655360000) { 397 base_clock = CLOCK_100_KHZ; 398 timer = cmd->scan_begin_arg / 10000; 399 } else /* cmd->scan_begin_arg < 6553600000 */ { 400 base_clock = CLOCK_10_KHZ; 401 timer = cmd->scan_begin_arg / 100000; 402 } 403 outw(0xFF02, dev->iobase + AM9513A_COM_REG); 404 outw(base_clock, dev->iobase + AM9513A_DATA_REG); 405 outw(0xFF0A, dev->iobase + AM9513A_COM_REG); 406 outw(0x2, dev->iobase + AM9513A_DATA_REG); 407 outw(0xFF42, dev->iobase + AM9513A_COM_REG); 408 outw(0xFFF2, dev->iobase + AM9513A_COM_REG); 409 outw(timer, dev->iobase + AM9513A_DATA_REG); 410 outw(0xFF22, dev->iobase + AM9513A_COM_REG); 411 } 412 413 /* Clear the A/D FIFO and reset the MUX counter */ 414 outw(0, dev->iobase + AD_CLEAR_REG); 415 outw(0, dev->iobase + MUX_CNTR_REG); 416 outw(0, dev->iobase + INT2CLR_REG); 417 /* enable this acquisition operation */ 418 devpriv->com_reg_1_state |= COMREG1_DAQEN; 419 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); 420 /* enable interrupts for conversion completion */ 421 devpriv->com_reg_1_state |= COMREG1_CONVINTEN; 422 devpriv->com_reg_2_state |= COMREG2_INTEN; 423 outw(devpriv->com_reg_1_state, dev->iobase + COM_REG_1); 424 outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2); 425 /* apply a trigger. this starts the counters! */ 426 outw(0, dev->iobase + START_DAQ_REG); 427 428 return 0; 429} 430 431/* This will cancel a running acquisition operation */ 432static int atmio16d_ai_cancel(struct comedi_device *dev, 433 struct comedi_subdevice *s) 434{ 435 reset_atmio16d(dev); 436 437 return 0; 438} 439 440static int atmio16d_ai_eoc(struct comedi_device *dev, 441 struct comedi_subdevice *s, 442 struct comedi_insn *insn, 443 unsigned long context) 444{ 445 unsigned int status; 446 447 status = inw(dev->iobase + STAT_REG); 448 if (status & STAT_AD_CONVAVAIL) 449 return 0; 450 if (status & STAT_AD_OVERFLOW) { 451 outw(0, dev->iobase + AD_CLEAR_REG); 452 return -EOVERFLOW; 453 } 454 return -EBUSY; 455} 456 457static int atmio16d_ai_insn_read(struct comedi_device *dev, 458 struct comedi_subdevice *s, 459 struct comedi_insn *insn, unsigned int *data) 460{ 461 struct atmio16d_private *devpriv = dev->private; 462 int i; 463 int chan; 464 int gain; 465 int ret; 466 467 chan = CR_CHAN(insn->chanspec); 468 gain = CR_RANGE(insn->chanspec); 469 470 /* reset the Analog input circuitry */ 471 /* outw( 0, dev->iobase+AD_CLEAR_REG ); */ 472 /* reset the Analog Input MUX Counter to 0 */ 473 /* outw( 0, dev->iobase+MUX_CNTR_REG ); */ 474 475 /* set the Input MUX gain */ 476 outw(chan | (gain << 6), dev->iobase + MUX_GAIN_REG); 477 478 for (i = 0; i < insn->n; i++) { 479 /* start the conversion */ 480 outw(0, dev->iobase + START_CONVERT_REG); 481 482 /* wait for it to finish */ 483 ret = comedi_timeout(dev, s, insn, atmio16d_ai_eoc, 0); 484 if (ret) 485 return ret; 486 487 /* read the data now */ 488 data[i] = inw(dev->iobase + AD_FIFO_REG); 489 /* change to two's complement if need be */ 490 if (devpriv->adc_coding == adc_2comp) 491 data[i] ^= 0x800; 492 } 493 494 return i; 495} 496 497static int atmio16d_ao_insn_write(struct comedi_device *dev, 498 struct comedi_subdevice *s, 499 struct comedi_insn *insn, 500 unsigned int *data) 501{ 502 struct atmio16d_private *devpriv = dev->private; 503 unsigned int chan = CR_CHAN(insn->chanspec); 504 unsigned int reg = (chan) ? DAC1_REG : DAC0_REG; 505 bool munge = false; 506 int i; 507 508 if (chan == 0 && devpriv->dac0_coding == dac_2comp) 509 munge = true; 510 if (chan == 1 && devpriv->dac1_coding == dac_2comp) 511 munge = true; 512 513 for (i = 0; i < insn->n; i++) { 514 unsigned int val = data[i]; 515 516 s->readback[chan] = val; 517 518 if (munge) 519 val ^= 0x800; 520 521 outw(val, dev->iobase + reg); 522 } 523 524 return insn->n; 525} 526 527static int atmio16d_dio_insn_bits(struct comedi_device *dev, 528 struct comedi_subdevice *s, 529 struct comedi_insn *insn, 530 unsigned int *data) 531{ 532 if (comedi_dio_update_state(s, data)) 533 outw(s->state, dev->iobase + MIO_16_DIG_OUT_REG); 534 535 data[1] = inw(dev->iobase + MIO_16_DIG_IN_REG); 536 537 return insn->n; 538} 539 540static int atmio16d_dio_insn_config(struct comedi_device *dev, 541 struct comedi_subdevice *s, 542 struct comedi_insn *insn, 543 unsigned int *data) 544{ 545 struct atmio16d_private *devpriv = dev->private; 546 unsigned int chan = CR_CHAN(insn->chanspec); 547 unsigned int mask; 548 int ret; 549 550 if (chan < 4) 551 mask = 0x0f; 552 else 553 mask = 0xf0; 554 555 ret = comedi_dio_insn_config(dev, s, insn, data, mask); 556 if (ret) 557 return ret; 558 559 devpriv->com_reg_2_state &= ~(COMREG2_DOUTEN0 | COMREG2_DOUTEN1); 560 if (s->io_bits & 0x0f) 561 devpriv->com_reg_2_state |= COMREG2_DOUTEN0; 562 if (s->io_bits & 0xf0) 563 devpriv->com_reg_2_state |= COMREG2_DOUTEN1; 564 outw(devpriv->com_reg_2_state, dev->iobase + COM_REG_2); 565 566 return insn->n; 567} 568 569/* 570 options[0] - I/O port 571 options[1] - MIO irq 572 0 == no irq 573 N == irq N {3,4,5,6,7,9,10,11,12,14,15} 574 options[2] - DIO irq 575 0 == no irq 576 N == irq N {3,4,5,6,7,9} 577 options[3] - DMA1 channel 578 0 == no DMA 579 N == DMA N {5,6,7} 580 options[4] - DMA2 channel 581 0 == no DMA 582 N == DMA N {5,6,7} 583 584 options[5] - a/d mux 585 0=differential, 1=single 586 options[6] - a/d range 587 0=bipolar10, 1=bipolar5, 2=unipolar10 588 589 options[7] - dac0 range 590 0=bipolar, 1=unipolar 591 options[8] - dac0 reference 592 0=internal, 1=external 593 options[9] - dac0 coding 594 0=2's comp, 1=straight binary 595 596 options[10] - dac1 range 597 options[11] - dac1 reference 598 options[12] - dac1 coding 599 */ 600 601static int atmio16d_attach(struct comedi_device *dev, 602 struct comedi_devconfig *it) 603{ 604 const struct atmio16_board_t *board = dev->board_ptr; 605 struct atmio16d_private *devpriv; 606 struct comedi_subdevice *s; 607 int ret; 608 609 ret = comedi_request_region(dev, it->options[0], 0x20); 610 if (ret) 611 return ret; 612 613 ret = comedi_alloc_subdevices(dev, 4); 614 if (ret) 615 return ret; 616 617 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 618 if (!devpriv) 619 return -ENOMEM; 620 621 /* reset the atmio16d hardware */ 622 reset_atmio16d(dev); 623 624 if (it->options[1]) { 625 ret = request_irq(it->options[1], atmio16d_interrupt, 0, 626 dev->board_name, dev); 627 if (ret == 0) 628 dev->irq = it->options[1]; 629 } 630 631 /* set device options */ 632 devpriv->adc_mux = it->options[5]; 633 devpriv->adc_range = it->options[6]; 634 635 devpriv->dac0_range = it->options[7]; 636 devpriv->dac0_reference = it->options[8]; 637 devpriv->dac0_coding = it->options[9]; 638 devpriv->dac1_range = it->options[10]; 639 devpriv->dac1_reference = it->options[11]; 640 devpriv->dac1_coding = it->options[12]; 641 642 /* setup sub-devices */ 643 s = &dev->subdevices[0]; 644 /* ai subdevice */ 645 s->type = COMEDI_SUBD_AI; 646 s->subdev_flags = SDF_READABLE | SDF_GROUND; 647 s->n_chan = (devpriv->adc_mux ? 16 : 8); 648 s->insn_read = atmio16d_ai_insn_read; 649 s->maxdata = 0xfff; /* 4095 decimal */ 650 switch (devpriv->adc_range) { 651 case adc_bipolar10: 652 s->range_table = &range_atmio16d_ai_10_bipolar; 653 break; 654 case adc_bipolar5: 655 s->range_table = &range_atmio16d_ai_5_bipolar; 656 break; 657 case adc_unipolar10: 658 s->range_table = &range_atmio16d_ai_unipolar; 659 break; 660 } 661 if (dev->irq) { 662 dev->read_subdev = s; 663 s->subdev_flags |= SDF_CMD_READ; 664 s->len_chanlist = 16; 665 s->do_cmdtest = atmio16d_ai_cmdtest; 666 s->do_cmd = atmio16d_ai_cmd; 667 s->cancel = atmio16d_ai_cancel; 668 } 669 670 /* ao subdevice */ 671 s = &dev->subdevices[1]; 672 s->type = COMEDI_SUBD_AO; 673 s->subdev_flags = SDF_WRITABLE; 674 s->n_chan = 2; 675 s->maxdata = 0xfff; /* 4095 decimal */ 676 s->range_table_list = devpriv->ao_range_type_list; 677 switch (devpriv->dac0_range) { 678 case dac_bipolar: 679 devpriv->ao_range_type_list[0] = &range_bipolar10; 680 break; 681 case dac_unipolar: 682 devpriv->ao_range_type_list[0] = &range_unipolar10; 683 break; 684 } 685 switch (devpriv->dac1_range) { 686 case dac_bipolar: 687 devpriv->ao_range_type_list[1] = &range_bipolar10; 688 break; 689 case dac_unipolar: 690 devpriv->ao_range_type_list[1] = &range_unipolar10; 691 break; 692 } 693 s->insn_write = atmio16d_ao_insn_write; 694 s->insn_read = comedi_readback_insn_read; 695 696 ret = comedi_alloc_subdev_readback(s); 697 if (ret) 698 return ret; 699 700 /* Digital I/O */ 701 s = &dev->subdevices[2]; 702 s->type = COMEDI_SUBD_DIO; 703 s->subdev_flags = SDF_WRITABLE | SDF_READABLE; 704 s->n_chan = 8; 705 s->insn_bits = atmio16d_dio_insn_bits; 706 s->insn_config = atmio16d_dio_insn_config; 707 s->maxdata = 1; 708 s->range_table = &range_digital; 709 710 /* 8255 subdevice */ 711 s = &dev->subdevices[3]; 712 if (board->has_8255) { 713 ret = subdev_8255_init(dev, s, NULL, 0x00); 714 if (ret) 715 return ret; 716 } else { 717 s->type = COMEDI_SUBD_UNUSED; 718 } 719 720/* don't yet know how to deal with counter/timers */ 721#if 0 722 s = &dev->subdevices[4]; 723 /* do */ 724 s->type = COMEDI_SUBD_TIMER; 725 s->n_chan = 0; 726 s->maxdata = 0 727#endif 728 729 return 0; 730} 731 732static void atmio16d_detach(struct comedi_device *dev) 733{ 734 reset_atmio16d(dev); 735 comedi_legacy_detach(dev); 736} 737 738static const struct atmio16_board_t atmio16_boards[] = { 739 { 740 .name = "atmio16", 741 .has_8255 = 0, 742 }, { 743 .name = "atmio16d", 744 .has_8255 = 1, 745 }, 746}; 747 748static struct comedi_driver atmio16d_driver = { 749 .driver_name = "atmio16", 750 .module = THIS_MODULE, 751 .attach = atmio16d_attach, 752 .detach = atmio16d_detach, 753 .board_name = &atmio16_boards[0].name, 754 .num_names = ARRAY_SIZE(atmio16_boards), 755 .offset = sizeof(struct atmio16_board_t), 756}; 757module_comedi_driver(atmio16d_driver); 758 759MODULE_AUTHOR("Comedi http://www.comedi.org"); 760MODULE_DESCRIPTION("Comedi low-level driver"); 761MODULE_LICENSE("GPL"); 762