1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * ni_65xx.c 4 * Comedi driver for National Instruments PCI-65xx static dio boards 5 * 6 * Copyright (C) 2006 Jon Grierson <jd@renko.co.uk> 7 * Copyright (C) 2006 Frank Mori Hess <fmhess@users.sourceforge.net> 8 * 9 * COMEDI - Linux Control and Measurement Device Interface 10 * Copyright (C) 1999,2002,2003 David A. Schleef <ds@schleef.org> 11 */ 12 13/* 14 * Driver: ni_65xx 15 * Description: National Instruments 65xx static dio boards 16 * Author: Jon Grierson <jd@renko.co.uk>, 17 * Frank Mori Hess <fmhess@users.sourceforge.net> 18 * Status: testing 19 * Devices: [National Instruments] PCI-6509 (pci-6509), PXI-6509 (pxi-6509), 20 * PCI-6510 (pci-6510), PCI-6511 (pci-6511), PXI-6511 (pxi-6511), 21 * PCI-6512 (pci-6512), PXI-6512 (pxi-6512), PCI-6513 (pci-6513), 22 * PXI-6513 (pxi-6513), PCI-6514 (pci-6514), PXI-6514 (pxi-6514), 23 * PCI-6515 (pxi-6515), PXI-6515 (pxi-6515), PCI-6516 (pci-6516), 24 * PCI-6517 (pci-6517), PCI-6518 (pci-6518), PCI-6519 (pci-6519), 25 * PCI-6520 (pci-6520), PCI-6521 (pci-6521), PXI-6521 (pxi-6521), 26 * PCI-6528 (pci-6528), PXI-6528 (pxi-6528) 27 * Updated: Mon, 21 Jul 2014 12:49:58 +0000 28 * 29 * Configuration Options: not applicable, uses PCI auto config 30 * 31 * Based on the PCI-6527 driver by ds. 32 * The interrupt subdevice (subdevice 3) is probably broken for all 33 * boards except maybe the 6514. 34 * 35 * This driver previously inverted the outputs on PCI-6513 through to 36 * PCI-6519 and on PXI-6513 through to PXI-6515. It no longer inverts 37 * outputs on those cards by default as it didn't make much sense. If 38 * you require the outputs to be inverted on those cards for legacy 39 * reasons, set the module parameter "legacy_invert_outputs=true" when 40 * loading the module, or set "ni_65xx.legacy_invert_outputs=true" on 41 * the kernel command line if the driver is built in to the kernel. 42 */ 43 44/* 45 * Manuals (available from ftp://ftp.natinst.com/support/manuals) 46 * 47 * 370106b.pdf 6514 Register Level Programmer Manual 48 */ 49 50#include <linux/module.h> 51#include <linux/interrupt.h> 52#include <linux/comedi/comedi_pci.h> 53 54/* 55 * PCI BAR1 Register Map 56 */ 57 58/* Non-recurring Registers (8-bit except where noted) */ 59#define NI_65XX_ID_REG 0x00 60#define NI_65XX_CLR_REG 0x01 61#define NI_65XX_CLR_WDOG_INT BIT(6) 62#define NI_65XX_CLR_WDOG_PING BIT(5) 63#define NI_65XX_CLR_WDOG_EXP BIT(4) 64#define NI_65XX_CLR_EDGE_INT BIT(3) 65#define NI_65XX_CLR_OVERFLOW_INT BIT(2) 66#define NI_65XX_STATUS_REG 0x02 67#define NI_65XX_STATUS_WDOG_INT BIT(5) 68#define NI_65XX_STATUS_FALL_EDGE BIT(4) 69#define NI_65XX_STATUS_RISE_EDGE BIT(3) 70#define NI_65XX_STATUS_INT BIT(2) 71#define NI_65XX_STATUS_OVERFLOW_INT BIT(1) 72#define NI_65XX_STATUS_EDGE_INT BIT(0) 73#define NI_65XX_CTRL_REG 0x03 74#define NI_65XX_CTRL_WDOG_ENA BIT(5) 75#define NI_65XX_CTRL_FALL_EDGE_ENA BIT(4) 76#define NI_65XX_CTRL_RISE_EDGE_ENA BIT(3) 77#define NI_65XX_CTRL_INT_ENA BIT(2) 78#define NI_65XX_CTRL_OVERFLOW_ENA BIT(1) 79#define NI_65XX_CTRL_EDGE_ENA BIT(0) 80#define NI_65XX_REV_REG 0x04 /* 32-bit */ 81#define NI_65XX_FILTER_REG 0x08 /* 32-bit */ 82#define NI_65XX_RTSI_ROUTE_REG 0x0c /* 16-bit */ 83#define NI_65XX_RTSI_EDGE_REG 0x0e /* 16-bit */ 84#define NI_65XX_RTSI_WDOG_REG 0x10 /* 16-bit */ 85#define NI_65XX_RTSI_TRIG_REG 0x12 /* 16-bit */ 86#define NI_65XX_AUTO_CLK_SEL_REG 0x14 /* PXI-6528 only */ 87#define NI_65XX_AUTO_CLK_SEL_STATUS BIT(1) 88#define NI_65XX_AUTO_CLK_SEL_DISABLE BIT(0) 89#define NI_65XX_WDOG_CTRL_REG 0x15 90#define NI_65XX_WDOG_CTRL_ENA BIT(0) 91#define NI_65XX_RTSI_CFG_REG 0x16 92#define NI_65XX_RTSI_CFG_RISE_SENSE BIT(2) 93#define NI_65XX_RTSI_CFG_FALL_SENSE BIT(1) 94#define NI_65XX_RTSI_CFG_SYNC_DETECT BIT(0) 95#define NI_65XX_WDOG_STATUS_REG 0x17 96#define NI_65XX_WDOG_STATUS_EXP BIT(0) 97#define NI_65XX_WDOG_INTERVAL_REG 0x18 /* 32-bit */ 98 99/* Recurring port registers (8-bit) */ 100#define NI_65XX_PORT(x) ((x) * 0x10) 101#define NI_65XX_IO_DATA_REG(x) (0x40 + NI_65XX_PORT(x)) 102#define NI_65XX_IO_SEL_REG(x) (0x41 + NI_65XX_PORT(x)) 103#define NI_65XX_IO_SEL_OUTPUT 0 104#define NI_65XX_IO_SEL_INPUT BIT(0) 105#define NI_65XX_RISE_EDGE_ENA_REG(x) (0x42 + NI_65XX_PORT(x)) 106#define NI_65XX_FALL_EDGE_ENA_REG(x) (0x43 + NI_65XX_PORT(x)) 107#define NI_65XX_FILTER_ENA(x) (0x44 + NI_65XX_PORT(x)) 108#define NI_65XX_WDOG_HIZ_REG(x) (0x46 + NI_65XX_PORT(x)) 109#define NI_65XX_WDOG_ENA(x) (0x47 + NI_65XX_PORT(x)) 110#define NI_65XX_WDOG_HI_LO_REG(x) (0x48 + NI_65XX_PORT(x)) 111#define NI_65XX_RTSI_ENA(x) (0x49 + NI_65XX_PORT(x)) 112 113#define NI_65XX_PORT_TO_CHAN(x) ((x) * 8) 114#define NI_65XX_CHAN_TO_PORT(x) ((x) / 8) 115#define NI_65XX_CHAN_TO_MASK(x) (1 << ((x) % 8)) 116 117enum ni_65xx_boardid { 118 BOARD_PCI6509, 119 BOARD_PXI6509, 120 BOARD_PCI6510, 121 BOARD_PCI6511, 122 BOARD_PXI6511, 123 BOARD_PCI6512, 124 BOARD_PXI6512, 125 BOARD_PCI6513, 126 BOARD_PXI6513, 127 BOARD_PCI6514, 128 BOARD_PXI6514, 129 BOARD_PCI6515, 130 BOARD_PXI6515, 131 BOARD_PCI6516, 132 BOARD_PCI6517, 133 BOARD_PCI6518, 134 BOARD_PCI6519, 135 BOARD_PCI6520, 136 BOARD_PCI6521, 137 BOARD_PXI6521, 138 BOARD_PCI6528, 139 BOARD_PXI6528, 140}; 141 142struct ni_65xx_board { 143 const char *name; 144 unsigned int num_dio_ports; 145 unsigned int num_di_ports; 146 unsigned int num_do_ports; 147 unsigned int legacy_invert:1; 148}; 149 150static const struct ni_65xx_board ni_65xx_boards[] = { 151 [BOARD_PCI6509] = { 152 .name = "pci-6509", 153 .num_dio_ports = 12, 154 }, 155 [BOARD_PXI6509] = { 156 .name = "pxi-6509", 157 .num_dio_ports = 12, 158 }, 159 [BOARD_PCI6510] = { 160 .name = "pci-6510", 161 .num_di_ports = 4, 162 }, 163 [BOARD_PCI6511] = { 164 .name = "pci-6511", 165 .num_di_ports = 8, 166 }, 167 [BOARD_PXI6511] = { 168 .name = "pxi-6511", 169 .num_di_ports = 8, 170 }, 171 [BOARD_PCI6512] = { 172 .name = "pci-6512", 173 .num_do_ports = 8, 174 }, 175 [BOARD_PXI6512] = { 176 .name = "pxi-6512", 177 .num_do_ports = 8, 178 }, 179 [BOARD_PCI6513] = { 180 .name = "pci-6513", 181 .num_do_ports = 8, 182 .legacy_invert = 1, 183 }, 184 [BOARD_PXI6513] = { 185 .name = "pxi-6513", 186 .num_do_ports = 8, 187 .legacy_invert = 1, 188 }, 189 [BOARD_PCI6514] = { 190 .name = "pci-6514", 191 .num_di_ports = 4, 192 .num_do_ports = 4, 193 .legacy_invert = 1, 194 }, 195 [BOARD_PXI6514] = { 196 .name = "pxi-6514", 197 .num_di_ports = 4, 198 .num_do_ports = 4, 199 .legacy_invert = 1, 200 }, 201 [BOARD_PCI6515] = { 202 .name = "pci-6515", 203 .num_di_ports = 4, 204 .num_do_ports = 4, 205 .legacy_invert = 1, 206 }, 207 [BOARD_PXI6515] = { 208 .name = "pxi-6515", 209 .num_di_ports = 4, 210 .num_do_ports = 4, 211 .legacy_invert = 1, 212 }, 213 [BOARD_PCI6516] = { 214 .name = "pci-6516", 215 .num_do_ports = 4, 216 .legacy_invert = 1, 217 }, 218 [BOARD_PCI6517] = { 219 .name = "pci-6517", 220 .num_do_ports = 4, 221 .legacy_invert = 1, 222 }, 223 [BOARD_PCI6518] = { 224 .name = "pci-6518", 225 .num_di_ports = 2, 226 .num_do_ports = 2, 227 .legacy_invert = 1, 228 }, 229 [BOARD_PCI6519] = { 230 .name = "pci-6519", 231 .num_di_ports = 2, 232 .num_do_ports = 2, 233 .legacy_invert = 1, 234 }, 235 [BOARD_PCI6520] = { 236 .name = "pci-6520", 237 .num_di_ports = 1, 238 .num_do_ports = 1, 239 }, 240 [BOARD_PCI6521] = { 241 .name = "pci-6521", 242 .num_di_ports = 1, 243 .num_do_ports = 1, 244 }, 245 [BOARD_PXI6521] = { 246 .name = "pxi-6521", 247 .num_di_ports = 1, 248 .num_do_ports = 1, 249 }, 250 [BOARD_PCI6528] = { 251 .name = "pci-6528", 252 .num_di_ports = 3, 253 .num_do_ports = 3, 254 }, 255 [BOARD_PXI6528] = { 256 .name = "pxi-6528", 257 .num_di_ports = 3, 258 .num_do_ports = 3, 259 }, 260}; 261 262static bool ni_65xx_legacy_invert_outputs; 263module_param_named(legacy_invert_outputs, ni_65xx_legacy_invert_outputs, 264 bool, 0444); 265MODULE_PARM_DESC(legacy_invert_outputs, 266 "invert outputs of PCI/PXI-6513/6514/6515/6516/6517/6518/6519 for compatibility with old user code"); 267 268static unsigned int ni_65xx_num_ports(struct comedi_device *dev) 269{ 270 const struct ni_65xx_board *board = dev->board_ptr; 271 272 return board->num_dio_ports + board->num_di_ports + board->num_do_ports; 273} 274 275static void ni_65xx_disable_input_filters(struct comedi_device *dev) 276{ 277 unsigned int num_ports = ni_65xx_num_ports(dev); 278 int i; 279 280 /* disable input filtering on all ports */ 281 for (i = 0; i < num_ports; ++i) 282 writeb(0x00, dev->mmio + NI_65XX_FILTER_ENA(i)); 283 284 /* set filter interval to 0 (32bit reg) */ 285 writel(0x00000000, dev->mmio + NI_65XX_FILTER_REG); 286} 287 288/* updates edge detection for base_chan to base_chan+31 */ 289static void ni_65xx_update_edge_detection(struct comedi_device *dev, 290 unsigned int base_chan, 291 unsigned int rising, 292 unsigned int falling) 293{ 294 unsigned int num_ports = ni_65xx_num_ports(dev); 295 unsigned int port; 296 297 if (base_chan >= NI_65XX_PORT_TO_CHAN(num_ports)) 298 return; 299 300 for (port = NI_65XX_CHAN_TO_PORT(base_chan); port < num_ports; port++) { 301 int bitshift = (int)(NI_65XX_PORT_TO_CHAN(port) - base_chan); 302 unsigned int port_mask, port_rising, port_falling; 303 304 if (bitshift >= 32) 305 break; 306 307 if (bitshift >= 0) { 308 port_mask = ~0U >> bitshift; 309 port_rising = rising >> bitshift; 310 port_falling = falling >> bitshift; 311 } else { 312 port_mask = ~0U << -bitshift; 313 port_rising = rising << -bitshift; 314 port_falling = falling << -bitshift; 315 } 316 if (port_mask & 0xff) { 317 if (~port_mask & 0xff) { 318 port_rising |= 319 readb(dev->mmio + 320 NI_65XX_RISE_EDGE_ENA_REG(port)) & 321 ~port_mask; 322 port_falling |= 323 readb(dev->mmio + 324 NI_65XX_FALL_EDGE_ENA_REG(port)) & 325 ~port_mask; 326 } 327 writeb(port_rising & 0xff, 328 dev->mmio + NI_65XX_RISE_EDGE_ENA_REG(port)); 329 writeb(port_falling & 0xff, 330 dev->mmio + NI_65XX_FALL_EDGE_ENA_REG(port)); 331 } 332 } 333} 334 335static void ni_65xx_disable_edge_detection(struct comedi_device *dev) 336{ 337 /* clear edge detection for channels 0 to 31 */ 338 ni_65xx_update_edge_detection(dev, 0, 0, 0); 339 /* clear edge detection for channels 32 to 63 */ 340 ni_65xx_update_edge_detection(dev, 32, 0, 0); 341 /* clear edge detection for channels 64 to 95 */ 342 ni_65xx_update_edge_detection(dev, 64, 0, 0); 343} 344 345static int ni_65xx_dio_insn_config(struct comedi_device *dev, 346 struct comedi_subdevice *s, 347 struct comedi_insn *insn, 348 unsigned int *data) 349{ 350 unsigned long base_port = (unsigned long)s->private; 351 unsigned int chan = CR_CHAN(insn->chanspec); 352 unsigned int chan_mask = NI_65XX_CHAN_TO_MASK(chan); 353 unsigned int port = base_port + NI_65XX_CHAN_TO_PORT(chan); 354 unsigned int interval; 355 unsigned int val; 356 357 switch (data[0]) { 358 case INSN_CONFIG_FILTER: 359 /* 360 * The deglitch filter interval is specified in nanoseconds. 361 * The hardware supports intervals in 200ns increments. Round 362 * the user values up and return the actual interval. 363 */ 364 interval = (data[1] + 100) / 200; 365 if (interval > 0xfffff) 366 interval = 0xfffff; 367 data[1] = interval * 200; 368 369 /* 370 * Enable/disable the channel for deglitch filtering. Note 371 * that the filter interval is never set to '0'. This is done 372 * because other channels might still be enabled for filtering. 373 */ 374 val = readb(dev->mmio + NI_65XX_FILTER_ENA(port)); 375 if (interval) { 376 writel(interval, dev->mmio + NI_65XX_FILTER_REG); 377 val |= chan_mask; 378 } else { 379 val &= ~chan_mask; 380 } 381 writeb(val, dev->mmio + NI_65XX_FILTER_ENA(port)); 382 break; 383 384 case INSN_CONFIG_DIO_OUTPUT: 385 if (s->type != COMEDI_SUBD_DIO) 386 return -EINVAL; 387 writeb(NI_65XX_IO_SEL_OUTPUT, 388 dev->mmio + NI_65XX_IO_SEL_REG(port)); 389 break; 390 391 case INSN_CONFIG_DIO_INPUT: 392 if (s->type != COMEDI_SUBD_DIO) 393 return -EINVAL; 394 writeb(NI_65XX_IO_SEL_INPUT, 395 dev->mmio + NI_65XX_IO_SEL_REG(port)); 396 break; 397 398 case INSN_CONFIG_DIO_QUERY: 399 if (s->type != COMEDI_SUBD_DIO) 400 return -EINVAL; 401 val = readb(dev->mmio + NI_65XX_IO_SEL_REG(port)); 402 data[1] = (val == NI_65XX_IO_SEL_INPUT) ? COMEDI_INPUT 403 : COMEDI_OUTPUT; 404 break; 405 406 default: 407 return -EINVAL; 408 } 409 410 return insn->n; 411} 412 413static int ni_65xx_dio_insn_bits(struct comedi_device *dev, 414 struct comedi_subdevice *s, 415 struct comedi_insn *insn, 416 unsigned int *data) 417{ 418 unsigned long base_port = (unsigned long)s->private; 419 unsigned int base_chan = CR_CHAN(insn->chanspec); 420 int last_port_offset = NI_65XX_CHAN_TO_PORT(s->n_chan - 1); 421 unsigned int read_bits = 0; 422 int port_offset; 423 424 for (port_offset = NI_65XX_CHAN_TO_PORT(base_chan); 425 port_offset <= last_port_offset; port_offset++) { 426 unsigned int port = base_port + port_offset; 427 int base_port_channel = NI_65XX_PORT_TO_CHAN(port_offset); 428 unsigned int port_mask, port_data, bits; 429 int bitshift = base_port_channel - base_chan; 430 431 if (bitshift >= 32) 432 break; 433 port_mask = data[0]; 434 port_data = data[1]; 435 if (bitshift > 0) { 436 port_mask >>= bitshift; 437 port_data >>= bitshift; 438 } else { 439 port_mask <<= -bitshift; 440 port_data <<= -bitshift; 441 } 442 port_mask &= 0xff; 443 port_data &= 0xff; 444 445 /* update the outputs */ 446 if (port_mask) { 447 bits = readb(dev->mmio + NI_65XX_IO_DATA_REG(port)); 448 bits ^= s->io_bits; /* invert if necessary */ 449 bits &= ~port_mask; 450 bits |= (port_data & port_mask); 451 bits ^= s->io_bits; /* invert back */ 452 writeb(bits, dev->mmio + NI_65XX_IO_DATA_REG(port)); 453 } 454 455 /* read back the actual state */ 456 bits = readb(dev->mmio + NI_65XX_IO_DATA_REG(port)); 457 bits ^= s->io_bits; /* invert if necessary */ 458 if (bitshift > 0) 459 bits <<= bitshift; 460 else 461 bits >>= -bitshift; 462 463 read_bits |= bits; 464 } 465 data[1] = read_bits; 466 return insn->n; 467} 468 469static irqreturn_t ni_65xx_interrupt(int irq, void *d) 470{ 471 struct comedi_device *dev = d; 472 struct comedi_subdevice *s = dev->read_subdev; 473 unsigned int status; 474 unsigned short val = 0; 475 476 status = readb(dev->mmio + NI_65XX_STATUS_REG); 477 if ((status & NI_65XX_STATUS_INT) == 0) 478 return IRQ_NONE; 479 if ((status & NI_65XX_STATUS_EDGE_INT) == 0) 480 return IRQ_NONE; 481 482 writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT, 483 dev->mmio + NI_65XX_CLR_REG); 484 485 comedi_buf_write_samples(s, &val, 1); 486 comedi_handle_events(dev, s); 487 488 return IRQ_HANDLED; 489} 490 491static int ni_65xx_intr_cmdtest(struct comedi_device *dev, 492 struct comedi_subdevice *s, 493 struct comedi_cmd *cmd) 494{ 495 int err = 0; 496 497 /* Step 1 : check if triggers are trivially valid */ 498 499 err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); 500 err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER); 501 err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); 502 err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 503 err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT); 504 505 if (err) 506 return 1; 507 508 /* Step 2a : make sure trigger sources are unique */ 509 /* Step 2b : and mutually compatible */ 510 511 /* Step 3: check if arguments are trivially valid */ 512 513 err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); 514 err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, 0); 515 err |= comedi_check_trigger_arg_is(&cmd->convert_arg, 0); 516 err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, 517 cmd->chanlist_len); 518 err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); 519 520 if (err) 521 return 3; 522 523 /* Step 4: fix up any arguments */ 524 525 /* Step 5: check channel list if it exists */ 526 527 return 0; 528} 529 530static int ni_65xx_intr_cmd(struct comedi_device *dev, 531 struct comedi_subdevice *s) 532{ 533 writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT, 534 dev->mmio + NI_65XX_CLR_REG); 535 writeb(NI_65XX_CTRL_FALL_EDGE_ENA | NI_65XX_CTRL_RISE_EDGE_ENA | 536 NI_65XX_CTRL_INT_ENA | NI_65XX_CTRL_EDGE_ENA, 537 dev->mmio + NI_65XX_CTRL_REG); 538 539 return 0; 540} 541 542static int ni_65xx_intr_cancel(struct comedi_device *dev, 543 struct comedi_subdevice *s) 544{ 545 writeb(0x00, dev->mmio + NI_65XX_CTRL_REG); 546 547 return 0; 548} 549 550static int ni_65xx_intr_insn_bits(struct comedi_device *dev, 551 struct comedi_subdevice *s, 552 struct comedi_insn *insn, 553 unsigned int *data) 554{ 555 data[1] = 0; 556 return insn->n; 557} 558 559static int ni_65xx_intr_insn_config(struct comedi_device *dev, 560 struct comedi_subdevice *s, 561 struct comedi_insn *insn, 562 unsigned int *data) 563{ 564 switch (data[0]) { 565 case INSN_CONFIG_CHANGE_NOTIFY: 566 /* add instruction to check_insn_config_length() */ 567 if (insn->n != 3) 568 return -EINVAL; 569 570 /* update edge detection for channels 0 to 31 */ 571 ni_65xx_update_edge_detection(dev, 0, data[1], data[2]); 572 /* clear edge detection for channels 32 to 63 */ 573 ni_65xx_update_edge_detection(dev, 32, 0, 0); 574 /* clear edge detection for channels 64 to 95 */ 575 ni_65xx_update_edge_detection(dev, 64, 0, 0); 576 break; 577 case INSN_CONFIG_DIGITAL_TRIG: 578 /* check trigger number */ 579 if (data[1] != 0) 580 return -EINVAL; 581 /* check digital trigger operation */ 582 switch (data[2]) { 583 case COMEDI_DIGITAL_TRIG_DISABLE: 584 ni_65xx_disable_edge_detection(dev); 585 break; 586 case COMEDI_DIGITAL_TRIG_ENABLE_EDGES: 587 /* 588 * update edge detection for channels data[3] 589 * to (data[3] + 31) 590 */ 591 ni_65xx_update_edge_detection(dev, data[3], 592 data[4], data[5]); 593 break; 594 default: 595 return -EINVAL; 596 } 597 break; 598 default: 599 return -EINVAL; 600 } 601 602 return insn->n; 603} 604 605/* ripped from mite.h and mite_setup2() to avoid mite dependency */ 606#define MITE_IODWBSR 0xc0 /* IO Device Window Base Size Register */ 607#define WENAB BIT(7) /* window enable */ 608 609static int ni_65xx_mite_init(struct pci_dev *pcidev) 610{ 611 void __iomem *mite_base; 612 u32 main_phys_addr; 613 614 /* ioremap the MITE registers (BAR 0) temporarily */ 615 mite_base = pci_ioremap_bar(pcidev, 0); 616 if (!mite_base) 617 return -ENOMEM; 618 619 /* set data window to main registers (BAR 1) */ 620 main_phys_addr = pci_resource_start(pcidev, 1); 621 writel(main_phys_addr | WENAB, mite_base + MITE_IODWBSR); 622 623 /* finished with MITE registers */ 624 iounmap(mite_base); 625 return 0; 626} 627 628static int ni_65xx_auto_attach(struct comedi_device *dev, 629 unsigned long context) 630{ 631 struct pci_dev *pcidev = comedi_to_pci_dev(dev); 632 const struct ni_65xx_board *board = NULL; 633 struct comedi_subdevice *s; 634 unsigned int i; 635 int ret; 636 637 if (context < ARRAY_SIZE(ni_65xx_boards)) 638 board = &ni_65xx_boards[context]; 639 if (!board) 640 return -ENODEV; 641 dev->board_ptr = board; 642 dev->board_name = board->name; 643 644 ret = comedi_pci_enable(dev); 645 if (ret) 646 return ret; 647 648 ret = ni_65xx_mite_init(pcidev); 649 if (ret) 650 return ret; 651 652 dev->mmio = pci_ioremap_bar(pcidev, 1); 653 if (!dev->mmio) 654 return -ENOMEM; 655 656 writeb(NI_65XX_CLR_EDGE_INT | NI_65XX_CLR_OVERFLOW_INT, 657 dev->mmio + NI_65XX_CLR_REG); 658 writeb(0x00, dev->mmio + NI_65XX_CTRL_REG); 659 660 if (pcidev->irq) { 661 ret = request_irq(pcidev->irq, ni_65xx_interrupt, IRQF_SHARED, 662 dev->board_name, dev); 663 if (ret == 0) 664 dev->irq = pcidev->irq; 665 } 666 667 dev_info(dev->class_dev, "board: %s, ID=0x%02x", dev->board_name, 668 readb(dev->mmio + NI_65XX_ID_REG)); 669 670 ret = comedi_alloc_subdevices(dev, 4); 671 if (ret) 672 return ret; 673 674 s = &dev->subdevices[0]; 675 if (board->num_di_ports) { 676 s->type = COMEDI_SUBD_DI; 677 s->subdev_flags = SDF_READABLE; 678 s->n_chan = NI_65XX_PORT_TO_CHAN(board->num_di_ports); 679 s->maxdata = 1; 680 s->range_table = &range_digital; 681 s->insn_bits = ni_65xx_dio_insn_bits; 682 s->insn_config = ni_65xx_dio_insn_config; 683 684 /* the input ports always start at port 0 */ 685 s->private = (void *)0; 686 } else { 687 s->type = COMEDI_SUBD_UNUSED; 688 } 689 690 s = &dev->subdevices[1]; 691 if (board->num_do_ports) { 692 s->type = COMEDI_SUBD_DO; 693 s->subdev_flags = SDF_WRITABLE; 694 s->n_chan = NI_65XX_PORT_TO_CHAN(board->num_do_ports); 695 s->maxdata = 1; 696 s->range_table = &range_digital; 697 s->insn_bits = ni_65xx_dio_insn_bits; 698 699 /* the output ports always start after the input ports */ 700 s->private = (void *)(unsigned long)board->num_di_ports; 701 702 /* 703 * Use the io_bits to handle the inverted outputs. Inverted 704 * outputs are only supported if the "legacy_invert_outputs" 705 * module parameter is set to "true". 706 */ 707 if (ni_65xx_legacy_invert_outputs && board->legacy_invert) 708 s->io_bits = 0xff; 709 710 /* reset all output ports to comedi '0' */ 711 for (i = 0; i < board->num_do_ports; ++i) { 712 writeb(s->io_bits, /* inverted if necessary */ 713 dev->mmio + 714 NI_65XX_IO_DATA_REG(board->num_di_ports + i)); 715 } 716 } else { 717 s->type = COMEDI_SUBD_UNUSED; 718 } 719 720 s = &dev->subdevices[2]; 721 if (board->num_dio_ports) { 722 s->type = COMEDI_SUBD_DIO; 723 s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 724 s->n_chan = NI_65XX_PORT_TO_CHAN(board->num_dio_ports); 725 s->maxdata = 1; 726 s->range_table = &range_digital; 727 s->insn_bits = ni_65xx_dio_insn_bits; 728 s->insn_config = ni_65xx_dio_insn_config; 729 730 /* the input/output ports always start at port 0 */ 731 s->private = (void *)0; 732 733 /* configure all ports for input */ 734 for (i = 0; i < board->num_dio_ports; ++i) { 735 writeb(NI_65XX_IO_SEL_INPUT, 736 dev->mmio + NI_65XX_IO_SEL_REG(i)); 737 } 738 } else { 739 s->type = COMEDI_SUBD_UNUSED; 740 } 741 742 s = &dev->subdevices[3]; 743 s->type = COMEDI_SUBD_DI; 744 s->subdev_flags = SDF_READABLE; 745 s->n_chan = 1; 746 s->maxdata = 1; 747 s->range_table = &range_digital; 748 s->insn_bits = ni_65xx_intr_insn_bits; 749 if (dev->irq) { 750 dev->read_subdev = s; 751 s->subdev_flags |= SDF_CMD_READ; 752 s->len_chanlist = 1; 753 s->insn_config = ni_65xx_intr_insn_config; 754 s->do_cmdtest = ni_65xx_intr_cmdtest; 755 s->do_cmd = ni_65xx_intr_cmd; 756 s->cancel = ni_65xx_intr_cancel; 757 } 758 759 ni_65xx_disable_input_filters(dev); 760 ni_65xx_disable_edge_detection(dev); 761 762 return 0; 763} 764 765static void ni_65xx_detach(struct comedi_device *dev) 766{ 767 if (dev->mmio) 768 writeb(0x00, dev->mmio + NI_65XX_CTRL_REG); 769 comedi_pci_detach(dev); 770} 771 772static struct comedi_driver ni_65xx_driver = { 773 .driver_name = "ni_65xx", 774 .module = THIS_MODULE, 775 .auto_attach = ni_65xx_auto_attach, 776 .detach = ni_65xx_detach, 777}; 778 779static int ni_65xx_pci_probe(struct pci_dev *dev, 780 const struct pci_device_id *id) 781{ 782 return comedi_pci_auto_config(dev, &ni_65xx_driver, id->driver_data); 783} 784 785static const struct pci_device_id ni_65xx_pci_table[] = { 786 { PCI_VDEVICE(NI, 0x1710), BOARD_PXI6509 }, 787 { PCI_VDEVICE(NI, 0x7085), BOARD_PCI6509 }, 788 { PCI_VDEVICE(NI, 0x7086), BOARD_PXI6528 }, 789 { PCI_VDEVICE(NI, 0x7087), BOARD_PCI6515 }, 790 { PCI_VDEVICE(NI, 0x7088), BOARD_PCI6514 }, 791 { PCI_VDEVICE(NI, 0x70a9), BOARD_PCI6528 }, 792 { PCI_VDEVICE(NI, 0x70c3), BOARD_PCI6511 }, 793 { PCI_VDEVICE(NI, 0x70c8), BOARD_PCI6513 }, 794 { PCI_VDEVICE(NI, 0x70c9), BOARD_PXI6515 }, 795 { PCI_VDEVICE(NI, 0x70cc), BOARD_PCI6512 }, 796 { PCI_VDEVICE(NI, 0x70cd), BOARD_PXI6514 }, 797 { PCI_VDEVICE(NI, 0x70d1), BOARD_PXI6513 }, 798 { PCI_VDEVICE(NI, 0x70d2), BOARD_PXI6512 }, 799 { PCI_VDEVICE(NI, 0x70d3), BOARD_PXI6511 }, 800 { PCI_VDEVICE(NI, 0x7124), BOARD_PCI6510 }, 801 { PCI_VDEVICE(NI, 0x7125), BOARD_PCI6516 }, 802 { PCI_VDEVICE(NI, 0x7126), BOARD_PCI6517 }, 803 { PCI_VDEVICE(NI, 0x7127), BOARD_PCI6518 }, 804 { PCI_VDEVICE(NI, 0x7128), BOARD_PCI6519 }, 805 { PCI_VDEVICE(NI, 0x718b), BOARD_PCI6521 }, 806 { PCI_VDEVICE(NI, 0x718c), BOARD_PXI6521 }, 807 { PCI_VDEVICE(NI, 0x71c5), BOARD_PCI6520 }, 808 { 0 } 809}; 810MODULE_DEVICE_TABLE(pci, ni_65xx_pci_table); 811 812static struct pci_driver ni_65xx_pci_driver = { 813 .name = "ni_65xx", 814 .id_table = ni_65xx_pci_table, 815 .probe = ni_65xx_pci_probe, 816 .remove = comedi_pci_auto_unconfig, 817}; 818module_comedi_pci_driver(ni_65xx_driver, ni_65xx_pci_driver); 819 820MODULE_AUTHOR("Comedi https://www.comedi.org"); 821MODULE_DESCRIPTION("Comedi driver for NI PCI-65xx static dio boards"); 822MODULE_LICENSE("GPL"); 823