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