rti800.c revision 139dfbdfacb02e3ef3df936d2fabd1ad5f14ea88
1/* 2 comedi/drivers/rti800.c 3 Hardware driver for Analog Devices RTI-800/815 board 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 1998 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: rti800 25Description: Analog Devices RTI-800/815 26Author: ds 27Status: unknown 28Updated: Fri, 05 Sep 2008 14:50:44 +0100 29Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815) 30 31Configuration options: 32 [0] - I/O port base address 33 [1] - IRQ 34 [2] - A/D reference 35 0 = differential 36 1 = pseudodifferential (common) 37 2 = single-ended 38 [3] - A/D range 39 0 = [-10,10] 40 1 = [-5,5] 41 2 = [0,10] 42 [4] - A/D encoding 43 0 = two's complement 44 1 = straight binary 45 [5] - DAC 0 range 46 0 = [-10,10] 47 1 = [0,10] 48 [6] - DAC 0 encoding 49 0 = two's complement 50 1 = straight binary 51 [7] - DAC 1 range (same as DAC 0) 52 [8] - DAC 1 encoding (same as DAC 0) 53*/ 54 55#include "../comedidev.h" 56 57#include <linux/ioport.h> 58 59#define RTI800_SIZE 16 60 61#define RTI800_CSR 0 62#define RTI800_MUXGAIN 1 63#define RTI800_CONVERT 2 64#define RTI800_ADCLO 3 65#define RTI800_ADCHI 4 66#define RTI800_DAC0LO 5 67#define RTI800_DAC0HI 6 68#define RTI800_DAC1LO 7 69#define RTI800_DAC1HI 8 70#define RTI800_CLRFLAGS 9 71#define RTI800_DI 10 72#define RTI800_DO 11 73#define RTI800_9513A_DATA 12 74#define RTI800_9513A_CNTRL 13 75#define RTI800_9513A_STATUS 13 76 77/* 78 * flags for CSR register 79 */ 80 81#define RTI800_BUSY 0x80 82#define RTI800_DONE 0x40 83#define RTI800_OVERRUN 0x20 84#define RTI800_TCR 0x10 85#define RTI800_DMA_ENAB 0x08 86#define RTI800_INTR_TC 0x04 87#define RTI800_INTR_EC 0x02 88#define RTI800_INTR_OVRN 0x01 89 90#define Am9513_8BITBUS 91 92#define Am9513_output_control(a) outb(a,dev->iobase+RTI800_9513A_CNTRL) 93#define Am9513_output_data(a) outb(a,dev->iobase+RTI800_9513A_DATA) 94#define Am9513_input_data() inb(dev->iobase+RTI800_9513A_DATA) 95#define Am9513_input_status() inb(dev->iobase+RTI800_9513A_STATUS) 96 97#include "am9513.h" 98 99static const comedi_lrange range_rti800_ai_10_bipolar = { 4, { 100 BIP_RANGE(10), 101 BIP_RANGE(1), 102 BIP_RANGE(0.1), 103 BIP_RANGE(0.02) 104 } 105}; 106static const comedi_lrange range_rti800_ai_5_bipolar = { 4, { 107 BIP_RANGE(5), 108 BIP_RANGE(0.5), 109 BIP_RANGE(0.05), 110 BIP_RANGE(0.01) 111 } 112}; 113static const comedi_lrange range_rti800_ai_unipolar = { 4, { 114 UNI_RANGE(10), 115 UNI_RANGE(1), 116 UNI_RANGE(0.1), 117 UNI_RANGE(0.02) 118 } 119}; 120 121typedef struct { 122 const char *name; 123 int has_ao; 124} boardtype; 125static const boardtype boardtypes[] = { 126 {"rti800", 0}, 127 {"rti815", 1}, 128}; 129 130#define this_board ((const boardtype *)dev->board_ptr) 131 132static int rti800_attach(struct comedi_device * dev, comedi_devconfig * it); 133static int rti800_detach(struct comedi_device * dev); 134static struct comedi_driver driver_rti800 = { 135 driver_name:"rti800", 136 module:THIS_MODULE, 137 attach:rti800_attach, 138 detach:rti800_detach, 139 num_names:sizeof(boardtypes) / sizeof(boardtype), 140 board_name:&boardtypes[0].name, 141 offset:sizeof(boardtype), 142}; 143 144COMEDI_INITCLEANUP(driver_rti800); 145 146static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG); 147 148typedef struct { 149 enum { 150 adc_diff, adc_pseudodiff, adc_singleended 151 } adc_mux; 152 enum { 153 adc_bipolar10, adc_bipolar5, adc_unipolar10 154 } adc_range; 155 enum { 156 adc_2comp, adc_straight 157 } adc_coding; 158 enum { 159 dac_bipolar10, dac_unipolar10 160 } dac0_range, dac1_range; 161 enum { 162 dac_2comp, dac_straight 163 } dac0_coding, dac1_coding; 164 const comedi_lrange *ao_range_type_list[2]; 165 unsigned int ao_readback[2]; 166 int muxgain_bits; 167} rti800_private; 168 169#define devpriv ((rti800_private *)dev->private) 170 171#define RTI800_TIMEOUT 100 172 173static irqreturn_t rti800_interrupt(int irq, void *dev PT_REGS_ARG) 174{ 175 return IRQ_HANDLED; 176} 177 178// settling delay times in usec for different gains 179static const int gaindelay[] = { 10, 20, 40, 80 }; 180 181static int rti800_ai_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 182 comedi_insn * insn, unsigned int * data) 183{ 184 int i, t; 185 int status; 186 int chan = CR_CHAN(insn->chanspec); 187 unsigned gain = CR_RANGE(insn->chanspec); 188 unsigned muxgain_bits; 189 190 inb(dev->iobase + RTI800_ADCHI); 191 outb(0, dev->iobase + RTI800_CLRFLAGS); 192 193 muxgain_bits = chan | (gain << 5); 194 if (muxgain_bits != devpriv->muxgain_bits) { 195 devpriv->muxgain_bits = muxgain_bits; 196 outb(devpriv->muxgain_bits, dev->iobase + RTI800_MUXGAIN); 197 /* without a delay here, the RTI_OVERRUN bit 198 * gets set, and you will have an error. */ 199 if (insn->n > 0) { 200 BUG_ON(gain >= 201 sizeof(gaindelay) / sizeof(gaindelay[0])); 202 comedi_udelay(gaindelay[gain]); 203 } 204 } 205 206 for (i = 0; i < insn->n; i++) { 207 outb(0, dev->iobase + RTI800_CONVERT); 208 for (t = RTI800_TIMEOUT; t; t--) { 209 status = inb(dev->iobase + RTI800_CSR); 210 if (status & RTI800_OVERRUN) { 211 rt_printk("rti800: a/d overrun\n"); 212 outb(0, dev->iobase + RTI800_CLRFLAGS); 213 return -EIO; 214 } 215 if (status & RTI800_DONE) 216 break; 217 comedi_udelay(1); 218 } 219 if (t == 0) { 220 rt_printk("rti800: timeout\n"); 221 return -ETIME; 222 } 223 data[i] = inb(dev->iobase + RTI800_ADCLO); 224 data[i] |= (0xf & inb(dev->iobase + RTI800_ADCHI)) << 8; 225 226 if (devpriv->adc_coding == adc_2comp) { 227 data[i] ^= 0x800; 228 } 229 } 230 231 return i; 232} 233 234static int rti800_ao_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 235 comedi_insn * insn, unsigned int * data) 236{ 237 int i; 238 int chan = CR_CHAN(insn->chanspec); 239 240 for (i = 0; i < insn->n; i++) 241 data[i] = devpriv->ao_readback[chan]; 242 243 return i; 244} 245 246static int rti800_ao_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, 247 comedi_insn * insn, unsigned int * data) 248{ 249 int chan = CR_CHAN(insn->chanspec); 250 int d; 251 int i; 252 253 for (i = 0; i < insn->n; i++) { 254 devpriv->ao_readback[chan] = d = data[i]; 255 if (devpriv->dac0_coding == dac_2comp) { 256 d ^= 0x800; 257 } 258 outb(d & 0xff, 259 dev->iobase + (chan ? RTI800_DAC1LO : RTI800_DAC0LO)); 260 outb(d >> 8, 261 dev->iobase + (chan ? RTI800_DAC1HI : RTI800_DAC0HI)); 262 } 263 return i; 264} 265 266static int rti800_di_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 267 comedi_insn * insn, unsigned int * data) 268{ 269 if (insn->n != 2) 270 return -EINVAL; 271 data[1] = inb(dev->iobase + RTI800_DI); 272 return 2; 273} 274 275static int rti800_do_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 276 comedi_insn * insn, unsigned int * data) 277{ 278 if (insn->n != 2) 279 return -EINVAL; 280 281 if (data[0]) { 282 s->state &= ~data[0]; 283 s->state |= data[0] & data[1]; 284 /* Outputs are inverted... */ 285 outb(s->state ^ 0xff, dev->iobase + RTI800_DO); 286 } 287 288 data[1] = s->state; 289 290 return 2; 291} 292 293/* 294 options[0] - I/O port 295 options[1] - irq 296 options[2] - a/d mux 297 0=differential, 1=pseudodiff, 2=single 298 options[3] - a/d range 299 0=bipolar10, 1=bipolar5, 2=unipolar10 300 options[4] - a/d coding 301 0=2's comp, 1=straight binary 302 options[5] - dac0 range 303 0=bipolar10, 1=unipolar10 304 options[6] - dac0 coding 305 0=2's comp, 1=straight binary 306 options[7] - dac1 range 307 options[8] - dac1 coding 308 */ 309 310static int rti800_attach(struct comedi_device * dev, comedi_devconfig * it) 311{ 312 unsigned int irq; 313 unsigned long iobase; 314 int ret; 315 struct comedi_subdevice *s; 316 317 iobase = it->options[0]; 318 printk("comedi%d: rti800: 0x%04lx ", dev->minor, iobase); 319 if (!request_region(iobase, RTI800_SIZE, "rti800")) { 320 printk("I/O port conflict\n"); 321 return -EIO; 322 } 323 dev->iobase = iobase; 324 325#ifdef DEBUG 326 printk("fingerprint=%x,%x,%x,%x,%x ", 327 inb(dev->iobase + 0), 328 inb(dev->iobase + 1), 329 inb(dev->iobase + 2), 330 inb(dev->iobase + 3), inb(dev->iobase + 4)); 331#endif 332 333 outb(0, dev->iobase + RTI800_CSR); 334 inb(dev->iobase + RTI800_ADCHI); 335 outb(0, dev->iobase + RTI800_CLRFLAGS); 336 337 irq = it->options[1]; 338 if (irq) { 339 printk("( irq = %u )", irq); 340 if ((ret = comedi_request_irq(irq, rti800_interrupt, 0, 341 "rti800", dev)) < 0) { 342 printk(" Failed to allocate IRQ\n"); 343 return ret; 344 } 345 dev->irq = irq; 346 } else { 347 printk("( no irq )"); 348 } 349 350 dev->board_name = this_board->name; 351 352 if ((ret = alloc_subdevices(dev, 4)) < 0) 353 return ret; 354 if ((ret = alloc_private(dev, sizeof(rti800_private))) < 0) 355 return ret; 356 357 devpriv->adc_mux = it->options[2]; 358 devpriv->adc_range = it->options[3]; 359 devpriv->adc_coding = it->options[4]; 360 devpriv->dac0_range = it->options[5]; 361 devpriv->dac0_coding = it->options[6]; 362 devpriv->dac1_range = it->options[7]; 363 devpriv->dac1_coding = it->options[8]; 364 devpriv->muxgain_bits = -1; 365 366 s = dev->subdevices + 0; 367 /* ai subdevice */ 368 s->type = COMEDI_SUBD_AI; 369 s->subdev_flags = SDF_READABLE | SDF_GROUND; 370 s->n_chan = (devpriv->adc_mux ? 16 : 8); 371 s->insn_read = rti800_ai_insn_read; 372 s->maxdata = 0xfff; 373 switch (devpriv->adc_range) { 374 case adc_bipolar10: 375 s->range_table = &range_rti800_ai_10_bipolar; 376 break; 377 case adc_bipolar5: 378 s->range_table = &range_rti800_ai_5_bipolar; 379 break; 380 case adc_unipolar10: 381 s->range_table = &range_rti800_ai_unipolar; 382 break; 383 } 384 385 s++; 386 if (this_board->has_ao) { 387 /* ao subdevice (only on rti815) */ 388 s->type = COMEDI_SUBD_AO; 389 s->subdev_flags = SDF_WRITABLE; 390 s->n_chan = 2; 391 s->insn_read = rti800_ao_insn_read; 392 s->insn_write = rti800_ao_insn_write; 393 s->maxdata = 0xfff; 394 s->range_table_list = devpriv->ao_range_type_list; 395 switch (devpriv->dac0_range) { 396 case dac_bipolar10: 397 devpriv->ao_range_type_list[0] = &range_bipolar10; 398 break; 399 case dac_unipolar10: 400 devpriv->ao_range_type_list[0] = &range_unipolar10; 401 break; 402 } 403 switch (devpriv->dac1_range) { 404 case dac_bipolar10: 405 devpriv->ao_range_type_list[1] = &range_bipolar10; 406 break; 407 case dac_unipolar10: 408 devpriv->ao_range_type_list[1] = &range_unipolar10; 409 break; 410 } 411 } else { 412 s->type = COMEDI_SUBD_UNUSED; 413 } 414 415 s++; 416 /* di */ 417 s->type = COMEDI_SUBD_DI; 418 s->subdev_flags = SDF_READABLE; 419 s->n_chan = 8; 420 s->insn_bits = rti800_di_insn_bits; 421 s->maxdata = 1; 422 s->range_table = &range_digital; 423 424 s++; 425 /* do */ 426 s->type = COMEDI_SUBD_DO; 427 s->subdev_flags = SDF_WRITABLE; 428 s->n_chan = 8; 429 s->insn_bits = rti800_do_insn_bits; 430 s->maxdata = 1; 431 s->range_table = &range_digital; 432 433/* don't yet know how to deal with counter/timers */ 434#if 0 435 s++; 436 /* do */ 437 s->type = COMEDI_SUBD_TIMER; 438#endif 439 440 printk("\n"); 441 442 return 0; 443} 444 445static int rti800_detach(struct comedi_device * dev) 446{ 447 printk("comedi%d: rti800: remove\n", dev->minor); 448 449 if (dev->iobase) 450 release_region(dev->iobase, RTI800_SIZE); 451 452 if (dev->irq) 453 comedi_free_irq(dev->irq, dev); 454 455 return 0; 456} 457