ni_at_ao.c revision 34c43922e62708d45e9660eee4b4f1fb7b4bf2c7
1/* 2 comedi/drivers/ni_at_ao.c 3 Driver for NI AT-AO-6/10 boards 4 5 COMEDI - Linux Control and Measurement Device Interface 6 Copyright (C) 2000,2002 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: ni_at_ao 25Description: National Instruments AT-AO-6/10 26Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10) 27Status: should work 28Author: ds 29Updated: Sun Dec 26 12:26:28 EST 2004 30 31Configuration options: 32 [0] - I/O port base address 33 [1] - IRQ (unused) 34 [2] - DMA (unused) 35 [3] - analog output range, set by jumpers on hardware (0 for -10 to 10V bipolar, 1 for 0V to 10V unipolar) 36 37*/ 38/* 39 * Register-level programming information can be found in NI 40 * document 320379.pdf. 41 */ 42 43#include "../comedidev.h" 44 45#include <linux/ioport.h> 46 47/* board egisters */ 48/* registers with _2_ are accessed when GRP2WR is set in CFG1 */ 49 50#define ATAO_SIZE 0x20 51 52#define ATAO_2_DMATCCLR 0x00 /* W 16 */ 53#define ATAO_DIN 0x00 /* R 16 */ 54#define ATAO_DOUT 0x00 /* W 16 */ 55 56#define ATAO_CFG2 0x02 /* W 16 */ 57#define CALLD1 0x8000 58#define CALLD0 0x4000 59#define FFRTEN 0x2000 60#define DAC2S8 0x1000 61#define DAC2S6 0x0800 62#define DAC2S4 0x0400 63#define DAC2S2 0x0200 64#define DAC2S0 0x0100 65#define LDAC8 0x0080 66#define LDAC6 0x0040 67#define LDAC4 0x0020 68#define LDAC2 0x0010 69#define LDAC0 0x0008 70#define PROMEN 0x0004 71#define SCLK 0x0002 72#define SDATA 0x0001 73 74#define ATAO_2_INT1CLR 0x02 /* W 16 */ 75 76#define ATAO_CFG3 0x04 /* W 16 */ 77#define DMAMODE 0x0040 78#define CLKOUT 0x0020 79#define RCLKEN 0x0010 80#define DOUTEN2 0x0008 81#define DOUTEN1 0x0004 82#define EN2_5V 0x0002 83#define SCANEN 0x0001 84 85#define ATAO_2_INT2CLR 0x04 /* W 16 */ 86 87#define ATAO_82C53_BASE 0x06 /* RW 8 */ 88 89#define ATAO_82C53_CNTR1 0x06 /* RW 8 */ 90#define ATAO_82C53_CNTR2 0x07 /* RW 8 */ 91#define ATAO_82C53_CNTR3 0x08 /* RW 8 */ 92#define ATAO_82C53_CNTRCMD 0x09 /* W 8 */ 93#define CNTRSEL1 0x80 94#define CNTRSEL0 0x40 95#define RWSEL1 0x20 96#define RWSEL0 0x10 97#define MODESEL2 0x08 98#define MODESEL1 0x04 99#define MODESEL0 0x02 100#define BCDSEL 0x01 101 /* read-back command */ 102#define COUNT 0x20 103#define STATUS 0x10 104#define CNTR3 0x08 105#define CNTR2 0x04 106#define CNTR1 0x02 107 /* status */ 108#define OUT 0x80 109#define _NULL 0x40 110#define RW1 0x20 111#define RW0 0x10 112#define MODE2 0x08 113#define MODE1 0x04 114#define MODE0 0x02 115#define BCD 0x01 116 117#define ATAO_2_RTSISHFT 0x06 /* W 8 */ 118#define RSI 0x01 119 120#define ATAO_2_RTSISTRB 0x07 /* W 8 */ 121 122#define ATAO_CFG1 0x0a /* W 16 */ 123#define EXTINT2EN 0x8000 124#define EXTINT1EN 0x4000 125#define CNTINT2EN 0x2000 126#define CNTINT1EN 0x1000 127#define TCINTEN 0x0800 128#define CNT1SRC 0x0400 129#define CNT2SRC 0x0200 130#define FIFOEN 0x0100 131#define GRP2WR 0x0080 132#define EXTUPDEN 0x0040 133#define DMARQ 0x0020 134#define DMAEN 0x0010 135#define CH_mask 0x000f 136#define ATAO_STATUS 0x0a /* R 16 */ 137#define FH 0x0040 138#define FE 0x0020 139#define FF 0x0010 140#define INT2 0x0008 141#define INT1 0x0004 142#define TCINT 0x0002 143#define PROMOUT 0x0001 144 145#define ATAO_FIFO_WRITE 0x0c /* W 16 */ 146#define ATAO_FIFO_CLEAR 0x0c /* R 16 */ 147#define ATAO_DACn(x) (0x0c + 2*(x)) /* W */ 148 149/* 150 * Board descriptions for two imaginary boards. Describing the 151 * boards in this way is optional, and completely driver-dependent. 152 * Some drivers use arrays such as this, other do not. 153 */ 154typedef struct atao_board_struct { 155 const char *name; 156 int n_ao_chans; 157} atao_board; 158static const atao_board atao_boards[] = { 159 { 160 name: "ai-ao-6", 161 n_ao_chans:6, 162 }, 163 { 164 name: "ai-ao-10", 165 n_ao_chans:10, 166 }, 167}; 168 169#define thisboard ((atao_board *)dev->board_ptr) 170 171typedef struct { 172 unsigned short cfg1; 173 unsigned short cfg2; 174 unsigned short cfg3; 175 176 /* Used for AO readback */ 177 unsigned int ao_readback[10]; 178} atao_private; 179#define devpriv ((atao_private *)dev->private) 180 181static int atao_attach(struct comedi_device * dev, comedi_devconfig * it); 182static int atao_detach(struct comedi_device * dev); 183static comedi_driver driver_atao = { 184 driver_name:"ni_at_ao", 185 module:THIS_MODULE, 186 attach:atao_attach, 187 detach:atao_detach, 188 board_name:&atao_boards[0].name, 189 offset:sizeof(atao_board), 190 num_names:sizeof(atao_boards) / sizeof(atao_board), 191}; 192 193COMEDI_INITCLEANUP(driver_atao); 194 195static void atao_reset(struct comedi_device * dev); 196 197static int atao_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, 198 comedi_insn * insn, unsigned int * data); 199static int atao_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 200 comedi_insn * insn, unsigned int * data); 201static int atao_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 202 comedi_insn * insn, unsigned int * data); 203static int atao_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 204 comedi_insn * insn, unsigned int * data); 205static int atao_calib_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 206 comedi_insn * insn, unsigned int * data); 207static int atao_calib_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, 208 comedi_insn * insn, unsigned int * data); 209 210static int atao_attach(struct comedi_device * dev, comedi_devconfig * it) 211{ 212 struct comedi_subdevice *s; 213 unsigned long iobase; 214 int ao_unipolar; 215 216 iobase = it->options[0]; 217 if (iobase == 0) 218 iobase = 0x1c0; 219 ao_unipolar = it->options[3]; 220 221 printk("comedi%d: ni_at_ao: 0x%04lx", dev->minor, iobase); 222 223 if (!request_region(iobase, ATAO_SIZE, "ni_at_ao")) { 224 printk(" I/O port conflict\n"); 225 return -EIO; 226 } 227 dev->iobase = iobase; 228 229 //dev->board_ptr = atao_probe(dev); 230 231 dev->board_name = thisboard->name; 232 233 if (alloc_private(dev, sizeof(atao_private)) < 0) 234 return -ENOMEM; 235 236 if (alloc_subdevices(dev, 4) < 0) 237 return -ENOMEM; 238 239 s = dev->subdevices + 0; 240 /* analog output subdevice */ 241 s->type = COMEDI_SUBD_AO; 242 s->subdev_flags = SDF_WRITABLE; 243 s->n_chan = thisboard->n_ao_chans; 244 s->maxdata = (1 << 12) - 1; 245 if (ao_unipolar) 246 s->range_table = &range_unipolar10; 247 else 248 s->range_table = &range_bipolar10; 249 s->insn_write = &atao_ao_winsn; 250 s->insn_read = &atao_ao_rinsn; 251 252 s = dev->subdevices + 1; 253 /* digital i/o subdevice */ 254 s->type = COMEDI_SUBD_DIO; 255 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 256 s->n_chan = 8; 257 s->maxdata = 1; 258 s->range_table = &range_digital; 259 s->insn_bits = atao_dio_insn_bits; 260 s->insn_config = atao_dio_insn_config; 261 262 s = dev->subdevices + 2; 263 /* caldac subdevice */ 264 s->type = COMEDI_SUBD_CALIB; 265 s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; 266 s->n_chan = 21; 267 s->maxdata = 0xff; 268 s->insn_read = atao_calib_insn_read; 269 s->insn_write = atao_calib_insn_write; 270 271 s = dev->subdevices + 3; 272 /* eeprom subdevice */ 273 //s->type=COMEDI_SUBD_EEPROM; 274 s->type = COMEDI_SUBD_UNUSED; 275 276 atao_reset(dev); 277 278 printk("\n"); 279 280 return 0; 281} 282 283static int atao_detach(struct comedi_device * dev) 284{ 285 printk("comedi%d: atao: remove\n", dev->minor); 286 287 if (dev->iobase) 288 release_region(dev->iobase, ATAO_SIZE); 289 290 return 0; 291} 292 293static void atao_reset(struct comedi_device * dev) 294{ 295 /* This is the reset sequence described in the manual */ 296 297 devpriv->cfg1 = 0; 298 outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); 299 300 outb(RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); 301 outb(0x03, dev->iobase + ATAO_82C53_CNTR1); 302 outb(CNTRSEL0 | RWSEL0 | MODESEL2, dev->iobase + ATAO_82C53_CNTRCMD); 303 304 devpriv->cfg2 = 0; 305 outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); 306 307 devpriv->cfg3 = 0; 308 outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); 309 310 inw(dev->iobase + ATAO_FIFO_CLEAR); 311 312 devpriv->cfg1 |= GRP2WR; 313 outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); 314 315 outw(0, dev->iobase + ATAO_2_INT1CLR); 316 outw(0, dev->iobase + ATAO_2_INT2CLR); 317 outw(0, dev->iobase + ATAO_2_DMATCCLR); 318 319 devpriv->cfg1 &= ~GRP2WR; 320 outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); 321} 322 323static int atao_ao_winsn(struct comedi_device * dev, struct comedi_subdevice * s, 324 comedi_insn * insn, unsigned int * data) 325{ 326 int i; 327 int chan = CR_CHAN(insn->chanspec); 328 short bits; 329 330 for (i = 0; i < insn->n; i++) { 331 bits = data[i] - 0x800; 332 if (chan == 0) { 333 devpriv->cfg1 |= GRP2WR; 334 outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); 335 } 336 outw(bits, dev->iobase + ATAO_DACn(chan)); 337 if (chan == 0) { 338 devpriv->cfg1 &= ~GRP2WR; 339 outw(devpriv->cfg1, dev->iobase + ATAO_CFG1); 340 } 341 devpriv->ao_readback[chan] = data[i]; 342 } 343 344 return i; 345} 346 347static int atao_ao_rinsn(struct comedi_device * dev, struct comedi_subdevice * s, 348 comedi_insn * insn, unsigned int * data) 349{ 350 int i; 351 int chan = CR_CHAN(insn->chanspec); 352 353 for (i = 0; i < insn->n; i++) 354 data[i] = devpriv->ao_readback[chan]; 355 356 return i; 357} 358 359static int atao_dio_insn_bits(struct comedi_device * dev, struct comedi_subdevice * s, 360 comedi_insn * insn, unsigned int * data) 361{ 362 if (insn->n != 2) 363 return -EINVAL; 364 365 if (data[0]) { 366 s->state &= ~data[0]; 367 s->state |= data[0] & data[1]; 368 outw(s->state, dev->iobase + ATAO_DOUT); 369 } 370 371 data[1] = inw(dev->iobase + ATAO_DIN); 372 373 return 2; 374} 375 376static int atao_dio_insn_config(struct comedi_device * dev, struct comedi_subdevice * s, 377 comedi_insn * insn, unsigned int * data) 378{ 379 int chan = CR_CHAN(insn->chanspec); 380 unsigned int mask, bit; 381 382 /* The input or output configuration of each digital line is 383 * configured by a special insn_config instruction. chanspec 384 * contains the channel to be changed, and data[0] contains the 385 * value COMEDI_INPUT or COMEDI_OUTPUT. */ 386 387 mask = (chan < 4) ? 0x0f : 0xf0; 388 bit = (chan < 4) ? DOUTEN1 : DOUTEN2; 389 390 switch (data[0]) { 391 case INSN_CONFIG_DIO_OUTPUT: 392 s->io_bits |= mask; 393 devpriv->cfg3 |= bit; 394 break; 395 case INSN_CONFIG_DIO_INPUT: 396 s->io_bits &= ~mask; 397 devpriv->cfg3 &= ~bit; 398 break; 399 case INSN_CONFIG_DIO_QUERY: 400 data[1] = 401 (s-> 402 io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; 403 return insn->n; 404 break; 405 default: 406 return -EINVAL; 407 break; 408 } 409 410 outw(devpriv->cfg3, dev->iobase + ATAO_CFG3); 411 412 return 1; 413} 414 415/* 416 * Figure 2-1 in the manual shows 3 chips labeled DAC8800, which 417 * are 8-channel 8-bit DACs. These are most likely the calibration 418 * DACs. It is not explicitly stated in the manual how to access 419 * the caldacs, but we can guess. 420 */ 421static int atao_calib_insn_read(struct comedi_device * dev, struct comedi_subdevice * s, 422 comedi_insn * insn, unsigned int * data) 423{ 424 int i; 425 for (i = 0; i < insn->n; i++) { 426 data[i] = 0; /* XXX */ 427 } 428 return insn->n; 429} 430 431static int atao_calib_insn_write(struct comedi_device * dev, struct comedi_subdevice * s, 432 comedi_insn * insn, unsigned int * data) 433{ 434 unsigned int bitstring, bit; 435 unsigned int chan = CR_CHAN(insn->chanspec); 436 437 bitstring = ((chan & 0x7) << 8) | (data[insn->n - 1] & 0xff); 438 439 for (bit = 1 << (11 - 1); bit; bit >>= 1) { 440 outw(devpriv->cfg2 | ((bit & bitstring) ? SDATA : 0), 441 dev->iobase + ATAO_CFG2); 442 outw(devpriv->cfg2 | SCLK | ((bit & bitstring) ? SDATA : 0), 443 dev->iobase + ATAO_CFG2); 444 } 445 /* strobe the appropriate caldac */ 446 outw(devpriv->cfg2 | (((chan >> 3) + 1) << 14), 447 dev->iobase + ATAO_CFG2); 448 outw(devpriv->cfg2, dev->iobase + ATAO_CFG2); 449 450 return insn->n; 451} 452