18ffdff6aSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 28ffdff6aSGreg Kroah-Hartman /* 38ffdff6aSGreg Kroah-Hartman * Hardware driver for NI 660x devices 48ffdff6aSGreg Kroah-Hartman */ 58ffdff6aSGreg Kroah-Hartman 68ffdff6aSGreg Kroah-Hartman /* 78ffdff6aSGreg Kroah-Hartman * Driver: ni_660x 88ffdff6aSGreg Kroah-Hartman * Description: National Instruments 660x counter/timer boards 98ffdff6aSGreg Kroah-Hartman * Devices: [National Instruments] PCI-6601 (ni_660x), PCI-6602, PXI-6602, 108ffdff6aSGreg Kroah-Hartman * PCI-6608, PXI-6608, PCI-6624, PXI-6624 118ffdff6aSGreg Kroah-Hartman * Author: J.P. Mellor <jpmellor@rose-hulman.edu>, 128ffdff6aSGreg Kroah-Hartman * Herman.Bruyninckx@mech.kuleuven.ac.be, 138ffdff6aSGreg Kroah-Hartman * Wim.Meeussen@mech.kuleuven.ac.be, 148ffdff6aSGreg Kroah-Hartman * Klaas.Gadeyne@mech.kuleuven.ac.be, 158ffdff6aSGreg Kroah-Hartman * Frank Mori Hess <fmhess@users.sourceforge.net> 168ffdff6aSGreg Kroah-Hartman * Updated: Mon, 16 Jan 2017 14:00:43 +0000 178ffdff6aSGreg Kroah-Hartman * Status: experimental 188ffdff6aSGreg Kroah-Hartman * 198ffdff6aSGreg Kroah-Hartman * Encoders work. PulseGeneration (both single pulse and pulse train) 208ffdff6aSGreg Kroah-Hartman * works. Buffered commands work for input but not output. 218ffdff6aSGreg Kroah-Hartman * 228ffdff6aSGreg Kroah-Hartman * References: 238ffdff6aSGreg Kroah-Hartman * DAQ 660x Register-Level Programmer Manual (NI 370505A-01) 248ffdff6aSGreg Kroah-Hartman * DAQ 6601/6602 User Manual (NI 322137B-01) 258ffdff6aSGreg Kroah-Hartman */ 268ffdff6aSGreg Kroah-Hartman 278ffdff6aSGreg Kroah-Hartman #include <linux/module.h> 288ffdff6aSGreg Kroah-Hartman #include <linux/interrupt.h> 29*df0e68c1SIan Abbott #include <linux/comedi/comedi_pci.h> 308ffdff6aSGreg Kroah-Hartman 318ffdff6aSGreg Kroah-Hartman #include "mite.h" 328ffdff6aSGreg Kroah-Hartman #include "ni_tio.h" 338ffdff6aSGreg Kroah-Hartman #include "ni_routes.h" 348ffdff6aSGreg Kroah-Hartman 358ffdff6aSGreg Kroah-Hartman /* See Register-Level Programmer Manual page 3.1 */ 368ffdff6aSGreg Kroah-Hartman enum ni_660x_register { 378ffdff6aSGreg Kroah-Hartman /* see enum ni_gpct_register */ 388ffdff6aSGreg Kroah-Hartman NI660X_STC_DIO_PARALLEL_INPUT = NITIO_NUM_REGS, 398ffdff6aSGreg Kroah-Hartman NI660X_STC_DIO_OUTPUT, 408ffdff6aSGreg Kroah-Hartman NI660X_STC_DIO_CONTROL, 418ffdff6aSGreg Kroah-Hartman NI660X_STC_DIO_SERIAL_INPUT, 428ffdff6aSGreg Kroah-Hartman NI660X_DIO32_INPUT, 438ffdff6aSGreg Kroah-Hartman NI660X_DIO32_OUTPUT, 448ffdff6aSGreg Kroah-Hartman NI660X_CLK_CFG, 458ffdff6aSGreg Kroah-Hartman NI660X_GLOBAL_INT_STATUS, 468ffdff6aSGreg Kroah-Hartman NI660X_DMA_CFG, 478ffdff6aSGreg Kroah-Hartman NI660X_GLOBAL_INT_CFG, 488ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_0_1, 498ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_2_3, 508ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_4_5, 518ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_6_7, 528ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_8_9, 538ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_10_11, 548ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_12_13, 558ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_14_15, 568ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_16_17, 578ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_18_19, 588ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_20_21, 598ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_22_23, 608ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_24_25, 618ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_26_27, 628ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_28_29, 638ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_30_31, 648ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_32_33, 658ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_34_35, 668ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_36_37, 678ffdff6aSGreg Kroah-Hartman NI660X_IO_CFG_38_39, 688ffdff6aSGreg Kroah-Hartman NI660X_NUM_REGS, 698ffdff6aSGreg Kroah-Hartman }; 708ffdff6aSGreg Kroah-Hartman 718ffdff6aSGreg Kroah-Hartman #define NI660X_CLK_CFG_COUNTER_SWAP BIT(21) 728ffdff6aSGreg Kroah-Hartman 738ffdff6aSGreg Kroah-Hartman #define NI660X_GLOBAL_INT_COUNTER0 BIT(8) 748ffdff6aSGreg Kroah-Hartman #define NI660X_GLOBAL_INT_COUNTER1 BIT(9) 758ffdff6aSGreg Kroah-Hartman #define NI660X_GLOBAL_INT_COUNTER2 BIT(10) 768ffdff6aSGreg Kroah-Hartman #define NI660X_GLOBAL_INT_COUNTER3 BIT(11) 778ffdff6aSGreg Kroah-Hartman #define NI660X_GLOBAL_INT_CASCADE BIT(29) 788ffdff6aSGreg Kroah-Hartman #define NI660X_GLOBAL_INT_GLOBAL_POL BIT(30) 798ffdff6aSGreg Kroah-Hartman #define NI660X_GLOBAL_INT_GLOBAL BIT(31) 808ffdff6aSGreg Kroah-Hartman 818ffdff6aSGreg Kroah-Hartman #define NI660X_DMA_CFG_SEL(_c, _s) (((_s) & 0x1f) << (8 * (_c))) 828ffdff6aSGreg Kroah-Hartman #define NI660X_DMA_CFG_SEL_MASK(_c) NI660X_DMA_CFG_SEL((_c), 0x1f) 838ffdff6aSGreg Kroah-Hartman #define NI660X_DMA_CFG_SEL_NONE(_c) NI660X_DMA_CFG_SEL((_c), 0x1f) 848ffdff6aSGreg Kroah-Hartman #define NI660X_DMA_CFG_RESET(_c) NI660X_DMA_CFG_SEL((_c), 0x80) 858ffdff6aSGreg Kroah-Hartman 868ffdff6aSGreg Kroah-Hartman #define NI660X_IO_CFG(x) (NI660X_IO_CFG_0_1 + ((x) / 2)) 878ffdff6aSGreg Kroah-Hartman #define NI660X_IO_CFG_OUT_SEL(_c, _s) (((_s) & 0x3) << (((_c) % 2) ? 0 : 8)) 888ffdff6aSGreg Kroah-Hartman #define NI660X_IO_CFG_OUT_SEL_MASK(_c) NI660X_IO_CFG_OUT_SEL((_c), 0x3) 898ffdff6aSGreg Kroah-Hartman #define NI660X_IO_CFG_IN_SEL(_c, _s) (((_s) & 0x7) << (((_c) % 2) ? 4 : 12)) 908ffdff6aSGreg Kroah-Hartman #define NI660X_IO_CFG_IN_SEL_MASK(_c) NI660X_IO_CFG_IN_SEL((_c), 0x7) 918ffdff6aSGreg Kroah-Hartman 928ffdff6aSGreg Kroah-Hartman struct ni_660x_register_data { 938ffdff6aSGreg Kroah-Hartman int offset; /* Offset from base address from GPCT chip */ 948ffdff6aSGreg Kroah-Hartman char size; /* 2 or 4 bytes */ 958ffdff6aSGreg Kroah-Hartman }; 968ffdff6aSGreg Kroah-Hartman 978ffdff6aSGreg Kroah-Hartman static const struct ni_660x_register_data ni_660x_reg_data[NI660X_NUM_REGS] = { 988ffdff6aSGreg Kroah-Hartman [NITIO_G0_INT_ACK] = { 0x004, 2 }, /* write */ 998ffdff6aSGreg Kroah-Hartman [NITIO_G0_STATUS] = { 0x004, 2 }, /* read */ 1008ffdff6aSGreg Kroah-Hartman [NITIO_G1_INT_ACK] = { 0x006, 2 }, /* write */ 1018ffdff6aSGreg Kroah-Hartman [NITIO_G1_STATUS] = { 0x006, 2 }, /* read */ 1028ffdff6aSGreg Kroah-Hartman [NITIO_G01_STATUS] = { 0x008, 2 }, /* read */ 1038ffdff6aSGreg Kroah-Hartman [NITIO_G0_CMD] = { 0x00c, 2 }, /* write */ 1048ffdff6aSGreg Kroah-Hartman [NI660X_STC_DIO_PARALLEL_INPUT] = { 0x00e, 2 }, /* read */ 1058ffdff6aSGreg Kroah-Hartman [NITIO_G1_CMD] = { 0x00e, 2 }, /* write */ 1068ffdff6aSGreg Kroah-Hartman [NITIO_G0_HW_SAVE] = { 0x010, 4 }, /* read */ 1078ffdff6aSGreg Kroah-Hartman [NITIO_G1_HW_SAVE] = { 0x014, 4 }, /* read */ 1088ffdff6aSGreg Kroah-Hartman [NI660X_STC_DIO_OUTPUT] = { 0x014, 2 }, /* write */ 1098ffdff6aSGreg Kroah-Hartman [NI660X_STC_DIO_CONTROL] = { 0x016, 2 }, /* write */ 1108ffdff6aSGreg Kroah-Hartman [NITIO_G0_SW_SAVE] = { 0x018, 4 }, /* read */ 1118ffdff6aSGreg Kroah-Hartman [NITIO_G1_SW_SAVE] = { 0x01c, 4 }, /* read */ 1128ffdff6aSGreg Kroah-Hartman [NITIO_G0_MODE] = { 0x034, 2 }, /* write */ 1138ffdff6aSGreg Kroah-Hartman [NITIO_G01_STATUS1] = { 0x036, 2 }, /* read */ 1148ffdff6aSGreg Kroah-Hartman [NITIO_G1_MODE] = { 0x036, 2 }, /* write */ 1158ffdff6aSGreg Kroah-Hartman [NI660X_STC_DIO_SERIAL_INPUT] = { 0x038, 2 }, /* read */ 1168ffdff6aSGreg Kroah-Hartman [NITIO_G0_LOADA] = { 0x038, 4 }, /* write */ 1178ffdff6aSGreg Kroah-Hartman [NITIO_G01_STATUS2] = { 0x03a, 2 }, /* read */ 1188ffdff6aSGreg Kroah-Hartman [NITIO_G0_LOADB] = { 0x03c, 4 }, /* write */ 1198ffdff6aSGreg Kroah-Hartman [NITIO_G1_LOADA] = { 0x040, 4 }, /* write */ 1208ffdff6aSGreg Kroah-Hartman [NITIO_G1_LOADB] = { 0x044, 4 }, /* write */ 1218ffdff6aSGreg Kroah-Hartman [NITIO_G0_INPUT_SEL] = { 0x048, 2 }, /* write */ 1228ffdff6aSGreg Kroah-Hartman [NITIO_G1_INPUT_SEL] = { 0x04a, 2 }, /* write */ 1238ffdff6aSGreg Kroah-Hartman [NITIO_G0_AUTO_INC] = { 0x088, 2 }, /* write */ 1248ffdff6aSGreg Kroah-Hartman [NITIO_G1_AUTO_INC] = { 0x08a, 2 }, /* write */ 1258ffdff6aSGreg Kroah-Hartman [NITIO_G01_RESET] = { 0x090, 2 }, /* write */ 1268ffdff6aSGreg Kroah-Hartman [NITIO_G0_INT_ENA] = { 0x092, 2 }, /* write */ 1278ffdff6aSGreg Kroah-Hartman [NITIO_G1_INT_ENA] = { 0x096, 2 }, /* write */ 1288ffdff6aSGreg Kroah-Hartman [NITIO_G0_CNT_MODE] = { 0x0b0, 2 }, /* write */ 1298ffdff6aSGreg Kroah-Hartman [NITIO_G1_CNT_MODE] = { 0x0b2, 2 }, /* write */ 1308ffdff6aSGreg Kroah-Hartman [NITIO_G0_GATE2] = { 0x0b4, 2 }, /* write */ 1318ffdff6aSGreg Kroah-Hartman [NITIO_G1_GATE2] = { 0x0b6, 2 }, /* write */ 1328ffdff6aSGreg Kroah-Hartman [NITIO_G0_DMA_CFG] = { 0x0b8, 2 }, /* write */ 1338ffdff6aSGreg Kroah-Hartman [NITIO_G0_DMA_STATUS] = { 0x0b8, 2 }, /* read */ 1348ffdff6aSGreg Kroah-Hartman [NITIO_G1_DMA_CFG] = { 0x0ba, 2 }, /* write */ 1358ffdff6aSGreg Kroah-Hartman [NITIO_G1_DMA_STATUS] = { 0x0ba, 2 }, /* read */ 1368ffdff6aSGreg Kroah-Hartman [NITIO_G2_INT_ACK] = { 0x104, 2 }, /* write */ 1378ffdff6aSGreg Kroah-Hartman [NITIO_G2_STATUS] = { 0x104, 2 }, /* read */ 1388ffdff6aSGreg Kroah-Hartman [NITIO_G3_INT_ACK] = { 0x106, 2 }, /* write */ 1398ffdff6aSGreg Kroah-Hartman [NITIO_G3_STATUS] = { 0x106, 2 }, /* read */ 1408ffdff6aSGreg Kroah-Hartman [NITIO_G23_STATUS] = { 0x108, 2 }, /* read */ 1418ffdff6aSGreg Kroah-Hartman [NITIO_G2_CMD] = { 0x10c, 2 }, /* write */ 1428ffdff6aSGreg Kroah-Hartman [NITIO_G3_CMD] = { 0x10e, 2 }, /* write */ 1438ffdff6aSGreg Kroah-Hartman [NITIO_G2_HW_SAVE] = { 0x110, 4 }, /* read */ 1448ffdff6aSGreg Kroah-Hartman [NITIO_G3_HW_SAVE] = { 0x114, 4 }, /* read */ 1458ffdff6aSGreg Kroah-Hartman [NITIO_G2_SW_SAVE] = { 0x118, 4 }, /* read */ 1468ffdff6aSGreg Kroah-Hartman [NITIO_G3_SW_SAVE] = { 0x11c, 4 }, /* read */ 1478ffdff6aSGreg Kroah-Hartman [NITIO_G2_MODE] = { 0x134, 2 }, /* write */ 1488ffdff6aSGreg Kroah-Hartman [NITIO_G23_STATUS1] = { 0x136, 2 }, /* read */ 1498ffdff6aSGreg Kroah-Hartman [NITIO_G3_MODE] = { 0x136, 2 }, /* write */ 1508ffdff6aSGreg Kroah-Hartman [NITIO_G2_LOADA] = { 0x138, 4 }, /* write */ 1518ffdff6aSGreg Kroah-Hartman [NITIO_G23_STATUS2] = { 0x13a, 2 }, /* read */ 1528ffdff6aSGreg Kroah-Hartman [NITIO_G2_LOADB] = { 0x13c, 4 }, /* write */ 1538ffdff6aSGreg Kroah-Hartman [NITIO_G3_LOADA] = { 0x140, 4 }, /* write */ 1548ffdff6aSGreg Kroah-Hartman [NITIO_G3_LOADB] = { 0x144, 4 }, /* write */ 1558ffdff6aSGreg Kroah-Hartman [NITIO_G2_INPUT_SEL] = { 0x148, 2 }, /* write */ 1568ffdff6aSGreg Kroah-Hartman [NITIO_G3_INPUT_SEL] = { 0x14a, 2 }, /* write */ 1578ffdff6aSGreg Kroah-Hartman [NITIO_G2_AUTO_INC] = { 0x188, 2 }, /* write */ 1588ffdff6aSGreg Kroah-Hartman [NITIO_G3_AUTO_INC] = { 0x18a, 2 }, /* write */ 1598ffdff6aSGreg Kroah-Hartman [NITIO_G23_RESET] = { 0x190, 2 }, /* write */ 1608ffdff6aSGreg Kroah-Hartman [NITIO_G2_INT_ENA] = { 0x192, 2 }, /* write */ 1618ffdff6aSGreg Kroah-Hartman [NITIO_G3_INT_ENA] = { 0x196, 2 }, /* write */ 1628ffdff6aSGreg Kroah-Hartman [NITIO_G2_CNT_MODE] = { 0x1b0, 2 }, /* write */ 1638ffdff6aSGreg Kroah-Hartman [NITIO_G3_CNT_MODE] = { 0x1b2, 2 }, /* write */ 1648ffdff6aSGreg Kroah-Hartman [NITIO_G2_GATE2] = { 0x1b4, 2 }, /* write */ 1658ffdff6aSGreg Kroah-Hartman [NITIO_G3_GATE2] = { 0x1b6, 2 }, /* write */ 1668ffdff6aSGreg Kroah-Hartman [NITIO_G2_DMA_CFG] = { 0x1b8, 2 }, /* write */ 1678ffdff6aSGreg Kroah-Hartman [NITIO_G2_DMA_STATUS] = { 0x1b8, 2 }, /* read */ 1688ffdff6aSGreg Kroah-Hartman [NITIO_G3_DMA_CFG] = { 0x1ba, 2 }, /* write */ 1698ffdff6aSGreg Kroah-Hartman [NITIO_G3_DMA_STATUS] = { 0x1ba, 2 }, /* read */ 1708ffdff6aSGreg Kroah-Hartman [NI660X_DIO32_INPUT] = { 0x414, 4 }, /* read */ 1718ffdff6aSGreg Kroah-Hartman [NI660X_DIO32_OUTPUT] = { 0x510, 4 }, /* write */ 1728ffdff6aSGreg Kroah-Hartman [NI660X_CLK_CFG] = { 0x73c, 4 }, /* write */ 1738ffdff6aSGreg Kroah-Hartman [NI660X_GLOBAL_INT_STATUS] = { 0x754, 4 }, /* read */ 1748ffdff6aSGreg Kroah-Hartman [NI660X_DMA_CFG] = { 0x76c, 4 }, /* write */ 1758ffdff6aSGreg Kroah-Hartman [NI660X_GLOBAL_INT_CFG] = { 0x770, 4 }, /* write */ 1768ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_0_1] = { 0x77c, 2 }, /* read/write */ 1778ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_2_3] = { 0x77e, 2 }, /* read/write */ 1788ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_4_5] = { 0x780, 2 }, /* read/write */ 1798ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_6_7] = { 0x782, 2 }, /* read/write */ 1808ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_8_9] = { 0x784, 2 }, /* read/write */ 1818ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_10_11] = { 0x786, 2 }, /* read/write */ 1828ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_12_13] = { 0x788, 2 }, /* read/write */ 1838ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_14_15] = { 0x78a, 2 }, /* read/write */ 1848ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_16_17] = { 0x78c, 2 }, /* read/write */ 1858ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_18_19] = { 0x78e, 2 }, /* read/write */ 1868ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_20_21] = { 0x790, 2 }, /* read/write */ 1878ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_22_23] = { 0x792, 2 }, /* read/write */ 1888ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_24_25] = { 0x794, 2 }, /* read/write */ 1898ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_26_27] = { 0x796, 2 }, /* read/write */ 1908ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_28_29] = { 0x798, 2 }, /* read/write */ 1918ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_30_31] = { 0x79a, 2 }, /* read/write */ 1928ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_32_33] = { 0x79c, 2 }, /* read/write */ 1938ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_34_35] = { 0x79e, 2 }, /* read/write */ 1948ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_36_37] = { 0x7a0, 2 }, /* read/write */ 1958ffdff6aSGreg Kroah-Hartman [NI660X_IO_CFG_38_39] = { 0x7a2, 2 } /* read/write */ 1968ffdff6aSGreg Kroah-Hartman }; 1978ffdff6aSGreg Kroah-Hartman 1988ffdff6aSGreg Kroah-Hartman #define NI660X_CHIP_OFFSET 0x800 1998ffdff6aSGreg Kroah-Hartman 2008ffdff6aSGreg Kroah-Hartman enum ni_660x_boardid { 2018ffdff6aSGreg Kroah-Hartman BOARD_PCI6601, 2028ffdff6aSGreg Kroah-Hartman BOARD_PCI6602, 2038ffdff6aSGreg Kroah-Hartman BOARD_PXI6602, 2048ffdff6aSGreg Kroah-Hartman BOARD_PCI6608, 2058ffdff6aSGreg Kroah-Hartman BOARD_PXI6608, 2068ffdff6aSGreg Kroah-Hartman BOARD_PCI6624, 2078ffdff6aSGreg Kroah-Hartman BOARD_PXI6624 2088ffdff6aSGreg Kroah-Hartman }; 2098ffdff6aSGreg Kroah-Hartman 2108ffdff6aSGreg Kroah-Hartman struct ni_660x_board { 2118ffdff6aSGreg Kroah-Hartman const char *name; 2128ffdff6aSGreg Kroah-Hartman unsigned int n_chips; /* total number of TIO chips */ 2138ffdff6aSGreg Kroah-Hartman }; 2148ffdff6aSGreg Kroah-Hartman 2158ffdff6aSGreg Kroah-Hartman static const struct ni_660x_board ni_660x_boards[] = { 2168ffdff6aSGreg Kroah-Hartman [BOARD_PCI6601] = { 2178ffdff6aSGreg Kroah-Hartman .name = "PCI-6601", 2188ffdff6aSGreg Kroah-Hartman .n_chips = 1, 2198ffdff6aSGreg Kroah-Hartman }, 2208ffdff6aSGreg Kroah-Hartman [BOARD_PCI6602] = { 2218ffdff6aSGreg Kroah-Hartman .name = "PCI-6602", 2228ffdff6aSGreg Kroah-Hartman .n_chips = 2, 2238ffdff6aSGreg Kroah-Hartman }, 2248ffdff6aSGreg Kroah-Hartman [BOARD_PXI6602] = { 2258ffdff6aSGreg Kroah-Hartman .name = "PXI-6602", 2268ffdff6aSGreg Kroah-Hartman .n_chips = 2, 2278ffdff6aSGreg Kroah-Hartman }, 2288ffdff6aSGreg Kroah-Hartman [BOARD_PCI6608] = { 2298ffdff6aSGreg Kroah-Hartman .name = "PCI-6608", 2308ffdff6aSGreg Kroah-Hartman .n_chips = 2, 2318ffdff6aSGreg Kroah-Hartman }, 2328ffdff6aSGreg Kroah-Hartman [BOARD_PXI6608] = { 2338ffdff6aSGreg Kroah-Hartman .name = "PXI-6608", 2348ffdff6aSGreg Kroah-Hartman .n_chips = 2, 2358ffdff6aSGreg Kroah-Hartman }, 2368ffdff6aSGreg Kroah-Hartman [BOARD_PCI6624] = { 2378ffdff6aSGreg Kroah-Hartman .name = "PCI-6624", 2388ffdff6aSGreg Kroah-Hartman .n_chips = 2, 2398ffdff6aSGreg Kroah-Hartman }, 2408ffdff6aSGreg Kroah-Hartman [BOARD_PXI6624] = { 2418ffdff6aSGreg Kroah-Hartman .name = "PXI-6624", 2428ffdff6aSGreg Kroah-Hartman .n_chips = 2, 2438ffdff6aSGreg Kroah-Hartman }, 2448ffdff6aSGreg Kroah-Hartman }; 2458ffdff6aSGreg Kroah-Hartman 2468ffdff6aSGreg Kroah-Hartman #define NI660X_NUM_PFI_CHANNELS 40 2478ffdff6aSGreg Kroah-Hartman 2488ffdff6aSGreg Kroah-Hartman /* there are only up to 3 dma channels, but the register layout allows for 4 */ 2498ffdff6aSGreg Kroah-Hartman #define NI660X_MAX_DMA_CHANNEL 4 2508ffdff6aSGreg Kroah-Hartman 2518ffdff6aSGreg Kroah-Hartman #define NI660X_COUNTERS_PER_CHIP 4 2528ffdff6aSGreg Kroah-Hartman #define NI660X_MAX_CHIPS 2 2538ffdff6aSGreg Kroah-Hartman #define NI660X_MAX_COUNTERS (NI660X_MAX_CHIPS * \ 2548ffdff6aSGreg Kroah-Hartman NI660X_COUNTERS_PER_CHIP) 2558ffdff6aSGreg Kroah-Hartman 2568ffdff6aSGreg Kroah-Hartman struct ni_660x_private { 2578ffdff6aSGreg Kroah-Hartman struct mite *mite; 2588ffdff6aSGreg Kroah-Hartman struct ni_gpct_device *counter_dev; 2598ffdff6aSGreg Kroah-Hartman struct mite_ring *ring[NI660X_MAX_CHIPS][NI660X_COUNTERS_PER_CHIP]; 2608ffdff6aSGreg Kroah-Hartman /* protects mite channel request/release */ 2618ffdff6aSGreg Kroah-Hartman spinlock_t mite_channel_lock; 2628ffdff6aSGreg Kroah-Hartman /* prevents races between interrupt and comedi_poll */ 2638ffdff6aSGreg Kroah-Hartman spinlock_t interrupt_lock; 2648ffdff6aSGreg Kroah-Hartman unsigned int dma_cfg[NI660X_MAX_CHIPS]; 2658ffdff6aSGreg Kroah-Hartman unsigned int io_cfg[NI660X_NUM_PFI_CHANNELS]; 2668ffdff6aSGreg Kroah-Hartman u64 io_dir; 2678ffdff6aSGreg Kroah-Hartman struct ni_route_tables routing_tables; 2688ffdff6aSGreg Kroah-Hartman }; 2698ffdff6aSGreg Kroah-Hartman 2708ffdff6aSGreg Kroah-Hartman static void ni_660x_write(struct comedi_device *dev, unsigned int chip, 2718ffdff6aSGreg Kroah-Hartman unsigned int bits, unsigned int reg) 2728ffdff6aSGreg Kroah-Hartman { 2738ffdff6aSGreg Kroah-Hartman unsigned int addr = (chip * NI660X_CHIP_OFFSET) + 2748ffdff6aSGreg Kroah-Hartman ni_660x_reg_data[reg].offset; 2758ffdff6aSGreg Kroah-Hartman 2768ffdff6aSGreg Kroah-Hartman if (ni_660x_reg_data[reg].size == 2) 2778ffdff6aSGreg Kroah-Hartman writew(bits, dev->mmio + addr); 2788ffdff6aSGreg Kroah-Hartman else 2798ffdff6aSGreg Kroah-Hartman writel(bits, dev->mmio + addr); 2808ffdff6aSGreg Kroah-Hartman } 2818ffdff6aSGreg Kroah-Hartman 2828ffdff6aSGreg Kroah-Hartman static unsigned int ni_660x_read(struct comedi_device *dev, 2838ffdff6aSGreg Kroah-Hartman unsigned int chip, unsigned int reg) 2848ffdff6aSGreg Kroah-Hartman { 2858ffdff6aSGreg Kroah-Hartman unsigned int addr = (chip * NI660X_CHIP_OFFSET) + 2868ffdff6aSGreg Kroah-Hartman ni_660x_reg_data[reg].offset; 2878ffdff6aSGreg Kroah-Hartman 2888ffdff6aSGreg Kroah-Hartman if (ni_660x_reg_data[reg].size == 2) 2898ffdff6aSGreg Kroah-Hartman return readw(dev->mmio + addr); 2908ffdff6aSGreg Kroah-Hartman return readl(dev->mmio + addr); 2918ffdff6aSGreg Kroah-Hartman } 2928ffdff6aSGreg Kroah-Hartman 2938ffdff6aSGreg Kroah-Hartman static void ni_660x_gpct_write(struct ni_gpct *counter, unsigned int bits, 2948ffdff6aSGreg Kroah-Hartman enum ni_gpct_register reg) 2958ffdff6aSGreg Kroah-Hartman { 2968ffdff6aSGreg Kroah-Hartman struct comedi_device *dev = counter->counter_dev->dev; 2978ffdff6aSGreg Kroah-Hartman 2988ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, counter->chip_index, bits, reg); 2998ffdff6aSGreg Kroah-Hartman } 3008ffdff6aSGreg Kroah-Hartman 3018ffdff6aSGreg Kroah-Hartman static unsigned int ni_660x_gpct_read(struct ni_gpct *counter, 3028ffdff6aSGreg Kroah-Hartman enum ni_gpct_register reg) 3038ffdff6aSGreg Kroah-Hartman { 3048ffdff6aSGreg Kroah-Hartman struct comedi_device *dev = counter->counter_dev->dev; 3058ffdff6aSGreg Kroah-Hartman 3068ffdff6aSGreg Kroah-Hartman return ni_660x_read(dev, counter->chip_index, reg); 3078ffdff6aSGreg Kroah-Hartman } 3088ffdff6aSGreg Kroah-Hartman 3098ffdff6aSGreg Kroah-Hartman static inline void ni_660x_set_dma_channel(struct comedi_device *dev, 3108ffdff6aSGreg Kroah-Hartman unsigned int mite_channel, 3118ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter) 3128ffdff6aSGreg Kroah-Hartman { 3138ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 3148ffdff6aSGreg Kroah-Hartman unsigned int chip = counter->chip_index; 3158ffdff6aSGreg Kroah-Hartman 3168ffdff6aSGreg Kroah-Hartman devpriv->dma_cfg[chip] &= ~NI660X_DMA_CFG_SEL_MASK(mite_channel); 3178ffdff6aSGreg Kroah-Hartman devpriv->dma_cfg[chip] |= NI660X_DMA_CFG_SEL(mite_channel, 3188ffdff6aSGreg Kroah-Hartman counter->counter_index); 3198ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, chip, devpriv->dma_cfg[chip] | 3208ffdff6aSGreg Kroah-Hartman NI660X_DMA_CFG_RESET(mite_channel), 3218ffdff6aSGreg Kroah-Hartman NI660X_DMA_CFG); 3228ffdff6aSGreg Kroah-Hartman } 3238ffdff6aSGreg Kroah-Hartman 3248ffdff6aSGreg Kroah-Hartman static inline void ni_660x_unset_dma_channel(struct comedi_device *dev, 3258ffdff6aSGreg Kroah-Hartman unsigned int mite_channel, 3268ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter) 3278ffdff6aSGreg Kroah-Hartman { 3288ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 3298ffdff6aSGreg Kroah-Hartman unsigned int chip = counter->chip_index; 3308ffdff6aSGreg Kroah-Hartman 3318ffdff6aSGreg Kroah-Hartman devpriv->dma_cfg[chip] &= ~NI660X_DMA_CFG_SEL_MASK(mite_channel); 3328ffdff6aSGreg Kroah-Hartman devpriv->dma_cfg[chip] |= NI660X_DMA_CFG_SEL_NONE(mite_channel); 3338ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, chip, devpriv->dma_cfg[chip], NI660X_DMA_CFG); 3348ffdff6aSGreg Kroah-Hartman } 3358ffdff6aSGreg Kroah-Hartman 3368ffdff6aSGreg Kroah-Hartman static int ni_660x_request_mite_channel(struct comedi_device *dev, 3378ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter, 3388ffdff6aSGreg Kroah-Hartman enum comedi_io_direction direction) 3398ffdff6aSGreg Kroah-Hartman { 3408ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 3418ffdff6aSGreg Kroah-Hartman struct mite_ring *ring; 3428ffdff6aSGreg Kroah-Hartman struct mite_channel *mite_chan; 3438ffdff6aSGreg Kroah-Hartman unsigned long flags; 3448ffdff6aSGreg Kroah-Hartman 3458ffdff6aSGreg Kroah-Hartman spin_lock_irqsave(&devpriv->mite_channel_lock, flags); 3468ffdff6aSGreg Kroah-Hartman ring = devpriv->ring[counter->chip_index][counter->counter_index]; 3478ffdff6aSGreg Kroah-Hartman mite_chan = mite_request_channel(devpriv->mite, ring); 3488ffdff6aSGreg Kroah-Hartman if (!mite_chan) { 3498ffdff6aSGreg Kroah-Hartman spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); 3508ffdff6aSGreg Kroah-Hartman dev_err(dev->class_dev, 3518ffdff6aSGreg Kroah-Hartman "failed to reserve mite dma channel for counter\n"); 3528ffdff6aSGreg Kroah-Hartman return -EBUSY; 3538ffdff6aSGreg Kroah-Hartman } 3548ffdff6aSGreg Kroah-Hartman mite_chan->dir = direction; 3558ffdff6aSGreg Kroah-Hartman ni_tio_set_mite_channel(counter, mite_chan); 3568ffdff6aSGreg Kroah-Hartman ni_660x_set_dma_channel(dev, mite_chan->channel, counter); 3578ffdff6aSGreg Kroah-Hartman spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); 3588ffdff6aSGreg Kroah-Hartman return 0; 3598ffdff6aSGreg Kroah-Hartman } 3608ffdff6aSGreg Kroah-Hartman 3618ffdff6aSGreg Kroah-Hartman static void ni_660x_release_mite_channel(struct comedi_device *dev, 3628ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter) 3638ffdff6aSGreg Kroah-Hartman { 3648ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 3658ffdff6aSGreg Kroah-Hartman unsigned long flags; 3668ffdff6aSGreg Kroah-Hartman 3678ffdff6aSGreg Kroah-Hartman spin_lock_irqsave(&devpriv->mite_channel_lock, flags); 3688ffdff6aSGreg Kroah-Hartman if (counter->mite_chan) { 3698ffdff6aSGreg Kroah-Hartman struct mite_channel *mite_chan = counter->mite_chan; 3708ffdff6aSGreg Kroah-Hartman 3718ffdff6aSGreg Kroah-Hartman ni_660x_unset_dma_channel(dev, mite_chan->channel, counter); 3728ffdff6aSGreg Kroah-Hartman ni_tio_set_mite_channel(counter, NULL); 3738ffdff6aSGreg Kroah-Hartman mite_release_channel(mite_chan); 3748ffdff6aSGreg Kroah-Hartman } 3758ffdff6aSGreg Kroah-Hartman spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); 3768ffdff6aSGreg Kroah-Hartman } 3778ffdff6aSGreg Kroah-Hartman 3788ffdff6aSGreg Kroah-Hartman static int ni_660x_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 3798ffdff6aSGreg Kroah-Hartman { 3808ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter = s->private; 3818ffdff6aSGreg Kroah-Hartman int retval; 3828ffdff6aSGreg Kroah-Hartman 3838ffdff6aSGreg Kroah-Hartman retval = ni_660x_request_mite_channel(dev, counter, COMEDI_INPUT); 3848ffdff6aSGreg Kroah-Hartman if (retval) { 3858ffdff6aSGreg Kroah-Hartman dev_err(dev->class_dev, 3868ffdff6aSGreg Kroah-Hartman "no dma channel available for use by counter\n"); 3878ffdff6aSGreg Kroah-Hartman return retval; 3888ffdff6aSGreg Kroah-Hartman } 3898ffdff6aSGreg Kroah-Hartman ni_tio_acknowledge(counter); 3908ffdff6aSGreg Kroah-Hartman 3918ffdff6aSGreg Kroah-Hartman return ni_tio_cmd(dev, s); 3928ffdff6aSGreg Kroah-Hartman } 3938ffdff6aSGreg Kroah-Hartman 3948ffdff6aSGreg Kroah-Hartman static int ni_660x_cancel(struct comedi_device *dev, struct comedi_subdevice *s) 3958ffdff6aSGreg Kroah-Hartman { 3968ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter = s->private; 3978ffdff6aSGreg Kroah-Hartman int retval; 3988ffdff6aSGreg Kroah-Hartman 3998ffdff6aSGreg Kroah-Hartman retval = ni_tio_cancel(counter); 4008ffdff6aSGreg Kroah-Hartman ni_660x_release_mite_channel(dev, counter); 4018ffdff6aSGreg Kroah-Hartman return retval; 4028ffdff6aSGreg Kroah-Hartman } 4038ffdff6aSGreg Kroah-Hartman 4048ffdff6aSGreg Kroah-Hartman static void set_tio_counterswap(struct comedi_device *dev, int chip) 4058ffdff6aSGreg Kroah-Hartman { 4068ffdff6aSGreg Kroah-Hartman unsigned int bits = 0; 4078ffdff6aSGreg Kroah-Hartman 4088ffdff6aSGreg Kroah-Hartman /* 4098ffdff6aSGreg Kroah-Hartman * See P. 3.5 of the Register-Level Programming manual. 4108ffdff6aSGreg Kroah-Hartman * The CounterSwap bit has to be set on the second chip, 4118ffdff6aSGreg Kroah-Hartman * otherwise it will try to use the same pins as the 4128ffdff6aSGreg Kroah-Hartman * first chip. 4138ffdff6aSGreg Kroah-Hartman */ 4148ffdff6aSGreg Kroah-Hartman if (chip) 4158ffdff6aSGreg Kroah-Hartman bits = NI660X_CLK_CFG_COUNTER_SWAP; 4168ffdff6aSGreg Kroah-Hartman 4178ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, chip, bits, NI660X_CLK_CFG); 4188ffdff6aSGreg Kroah-Hartman } 4198ffdff6aSGreg Kroah-Hartman 4208ffdff6aSGreg Kroah-Hartman static void ni_660x_handle_gpct_interrupt(struct comedi_device *dev, 4218ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s) 4228ffdff6aSGreg Kroah-Hartman { 4238ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter = s->private; 4248ffdff6aSGreg Kroah-Hartman 4258ffdff6aSGreg Kroah-Hartman ni_tio_handle_interrupt(counter, s); 4268ffdff6aSGreg Kroah-Hartman comedi_handle_events(dev, s); 4278ffdff6aSGreg Kroah-Hartman } 4288ffdff6aSGreg Kroah-Hartman 4298ffdff6aSGreg Kroah-Hartman static irqreturn_t ni_660x_interrupt(int irq, void *d) 4308ffdff6aSGreg Kroah-Hartman { 4318ffdff6aSGreg Kroah-Hartman struct comedi_device *dev = d; 4328ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 4338ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s; 4348ffdff6aSGreg Kroah-Hartman unsigned int i; 4358ffdff6aSGreg Kroah-Hartman unsigned long flags; 4368ffdff6aSGreg Kroah-Hartman 4378ffdff6aSGreg Kroah-Hartman if (!dev->attached) 4388ffdff6aSGreg Kroah-Hartman return IRQ_NONE; 4398ffdff6aSGreg Kroah-Hartman /* make sure dev->attached is checked before doing anything else */ 4408ffdff6aSGreg Kroah-Hartman smp_mb(); 4418ffdff6aSGreg Kroah-Hartman 4428ffdff6aSGreg Kroah-Hartman /* lock to avoid race with comedi_poll */ 4438ffdff6aSGreg Kroah-Hartman spin_lock_irqsave(&devpriv->interrupt_lock, flags); 4448ffdff6aSGreg Kroah-Hartman for (i = 0; i < dev->n_subdevices; ++i) { 4458ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[i]; 4468ffdff6aSGreg Kroah-Hartman if (s->type == COMEDI_SUBD_COUNTER) 4478ffdff6aSGreg Kroah-Hartman ni_660x_handle_gpct_interrupt(dev, s); 4488ffdff6aSGreg Kroah-Hartman } 4498ffdff6aSGreg Kroah-Hartman spin_unlock_irqrestore(&devpriv->interrupt_lock, flags); 4508ffdff6aSGreg Kroah-Hartman return IRQ_HANDLED; 4518ffdff6aSGreg Kroah-Hartman } 4528ffdff6aSGreg Kroah-Hartman 4538ffdff6aSGreg Kroah-Hartman static int ni_660x_input_poll(struct comedi_device *dev, 4548ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s) 4558ffdff6aSGreg Kroah-Hartman { 4568ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 4578ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter = s->private; 4588ffdff6aSGreg Kroah-Hartman unsigned long flags; 4598ffdff6aSGreg Kroah-Hartman 4608ffdff6aSGreg Kroah-Hartman /* lock to avoid race with comedi_poll */ 4618ffdff6aSGreg Kroah-Hartman spin_lock_irqsave(&devpriv->interrupt_lock, flags); 4628ffdff6aSGreg Kroah-Hartman mite_sync_dma(counter->mite_chan, s); 4638ffdff6aSGreg Kroah-Hartman spin_unlock_irqrestore(&devpriv->interrupt_lock, flags); 4648ffdff6aSGreg Kroah-Hartman return comedi_buf_read_n_available(s); 4658ffdff6aSGreg Kroah-Hartman } 4668ffdff6aSGreg Kroah-Hartman 4678ffdff6aSGreg Kroah-Hartman static int ni_660x_buf_change(struct comedi_device *dev, 4688ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s) 4698ffdff6aSGreg Kroah-Hartman { 4708ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 4718ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter = s->private; 4728ffdff6aSGreg Kroah-Hartman struct mite_ring *ring; 4738ffdff6aSGreg Kroah-Hartman int ret; 4748ffdff6aSGreg Kroah-Hartman 4758ffdff6aSGreg Kroah-Hartman ring = devpriv->ring[counter->chip_index][counter->counter_index]; 4768ffdff6aSGreg Kroah-Hartman ret = mite_buf_change(ring, s); 4778ffdff6aSGreg Kroah-Hartman if (ret < 0) 4788ffdff6aSGreg Kroah-Hartman return ret; 4798ffdff6aSGreg Kroah-Hartman 4808ffdff6aSGreg Kroah-Hartman return 0; 4818ffdff6aSGreg Kroah-Hartman } 4828ffdff6aSGreg Kroah-Hartman 4838ffdff6aSGreg Kroah-Hartman static int ni_660x_allocate_private(struct comedi_device *dev) 4848ffdff6aSGreg Kroah-Hartman { 4858ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv; 4868ffdff6aSGreg Kroah-Hartman unsigned int i; 4878ffdff6aSGreg Kroah-Hartman 4888ffdff6aSGreg Kroah-Hartman devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 4898ffdff6aSGreg Kroah-Hartman if (!devpriv) 4908ffdff6aSGreg Kroah-Hartman return -ENOMEM; 4918ffdff6aSGreg Kroah-Hartman 4928ffdff6aSGreg Kroah-Hartman spin_lock_init(&devpriv->mite_channel_lock); 4938ffdff6aSGreg Kroah-Hartman spin_lock_init(&devpriv->interrupt_lock); 4948ffdff6aSGreg Kroah-Hartman for (i = 0; i < NI660X_NUM_PFI_CHANNELS; ++i) 4958ffdff6aSGreg Kroah-Hartman devpriv->io_cfg[i] = NI_660X_PFI_OUTPUT_COUNTER; 4968ffdff6aSGreg Kroah-Hartman 4978ffdff6aSGreg Kroah-Hartman return 0; 4988ffdff6aSGreg Kroah-Hartman } 4998ffdff6aSGreg Kroah-Hartman 5008ffdff6aSGreg Kroah-Hartman static int ni_660x_alloc_mite_rings(struct comedi_device *dev) 5018ffdff6aSGreg Kroah-Hartman { 5028ffdff6aSGreg Kroah-Hartman const struct ni_660x_board *board = dev->board_ptr; 5038ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 5048ffdff6aSGreg Kroah-Hartman unsigned int i; 5058ffdff6aSGreg Kroah-Hartman unsigned int j; 5068ffdff6aSGreg Kroah-Hartman 5078ffdff6aSGreg Kroah-Hartman for (i = 0; i < board->n_chips; ++i) { 5088ffdff6aSGreg Kroah-Hartman for (j = 0; j < NI660X_COUNTERS_PER_CHIP; ++j) { 5098ffdff6aSGreg Kroah-Hartman devpriv->ring[i][j] = mite_alloc_ring(devpriv->mite); 5108ffdff6aSGreg Kroah-Hartman if (!devpriv->ring[i][j]) 5118ffdff6aSGreg Kroah-Hartman return -ENOMEM; 5128ffdff6aSGreg Kroah-Hartman } 5138ffdff6aSGreg Kroah-Hartman } 5148ffdff6aSGreg Kroah-Hartman return 0; 5158ffdff6aSGreg Kroah-Hartman } 5168ffdff6aSGreg Kroah-Hartman 5178ffdff6aSGreg Kroah-Hartman static void ni_660x_free_mite_rings(struct comedi_device *dev) 5188ffdff6aSGreg Kroah-Hartman { 5198ffdff6aSGreg Kroah-Hartman const struct ni_660x_board *board = dev->board_ptr; 5208ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 5218ffdff6aSGreg Kroah-Hartman unsigned int i; 5228ffdff6aSGreg Kroah-Hartman unsigned int j; 5238ffdff6aSGreg Kroah-Hartman 5248ffdff6aSGreg Kroah-Hartman for (i = 0; i < board->n_chips; ++i) { 5258ffdff6aSGreg Kroah-Hartman for (j = 0; j < NI660X_COUNTERS_PER_CHIP; ++j) 5268ffdff6aSGreg Kroah-Hartman mite_free_ring(devpriv->ring[i][j]); 5278ffdff6aSGreg Kroah-Hartman } 5288ffdff6aSGreg Kroah-Hartman } 5298ffdff6aSGreg Kroah-Hartman 5308ffdff6aSGreg Kroah-Hartman static int ni_660x_dio_insn_bits(struct comedi_device *dev, 5318ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, 5328ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 5338ffdff6aSGreg Kroah-Hartman unsigned int *data) 5348ffdff6aSGreg Kroah-Hartman { 5358ffdff6aSGreg Kroah-Hartman unsigned int shift = CR_CHAN(insn->chanspec); 5368ffdff6aSGreg Kroah-Hartman unsigned int mask = data[0] << shift; 5378ffdff6aSGreg Kroah-Hartman unsigned int bits = data[1] << shift; 5388ffdff6aSGreg Kroah-Hartman 5398ffdff6aSGreg Kroah-Hartman /* 5408ffdff6aSGreg Kroah-Hartman * There are 40 channels in this subdevice but only 32 are usable 5418ffdff6aSGreg Kroah-Hartman * as DIO. The shift adjusts the mask/bits to account for the base 5428ffdff6aSGreg Kroah-Hartman * channel in insn->chanspec. The state update can then be handled 5438ffdff6aSGreg Kroah-Hartman * normally for the 32 usable channels. 5448ffdff6aSGreg Kroah-Hartman */ 5458ffdff6aSGreg Kroah-Hartman if (mask) { 5468ffdff6aSGreg Kroah-Hartman s->state &= ~mask; 5478ffdff6aSGreg Kroah-Hartman s->state |= (bits & mask); 5488ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, 0, s->state, NI660X_DIO32_OUTPUT); 5498ffdff6aSGreg Kroah-Hartman } 5508ffdff6aSGreg Kroah-Hartman 5518ffdff6aSGreg Kroah-Hartman /* 5528ffdff6aSGreg Kroah-Hartman * Return the input channels, shifted back to account for the base 5538ffdff6aSGreg Kroah-Hartman * channel. 5548ffdff6aSGreg Kroah-Hartman */ 5558ffdff6aSGreg Kroah-Hartman data[1] = ni_660x_read(dev, 0, NI660X_DIO32_INPUT) >> shift; 5568ffdff6aSGreg Kroah-Hartman 5578ffdff6aSGreg Kroah-Hartman return insn->n; 5588ffdff6aSGreg Kroah-Hartman } 5598ffdff6aSGreg Kroah-Hartman 5608ffdff6aSGreg Kroah-Hartman static void ni_660x_select_pfi_output(struct comedi_device *dev, 5618ffdff6aSGreg Kroah-Hartman unsigned int chan, unsigned int out_sel) 5628ffdff6aSGreg Kroah-Hartman { 5638ffdff6aSGreg Kroah-Hartman const struct ni_660x_board *board = dev->board_ptr; 5648ffdff6aSGreg Kroah-Hartman unsigned int active_chip = 0; 5658ffdff6aSGreg Kroah-Hartman unsigned int idle_chip = 0; 5668ffdff6aSGreg Kroah-Hartman unsigned int bits; 5678ffdff6aSGreg Kroah-Hartman 5688ffdff6aSGreg Kroah-Hartman if (chan >= NI_PFI(0)) 5698ffdff6aSGreg Kroah-Hartman /* allow new and old names of pfi channels to work. */ 5708ffdff6aSGreg Kroah-Hartman chan -= NI_PFI(0); 5718ffdff6aSGreg Kroah-Hartman 5728ffdff6aSGreg Kroah-Hartman if (board->n_chips > 1) { 5738ffdff6aSGreg Kroah-Hartman if (out_sel == NI_660X_PFI_OUTPUT_COUNTER && 5748ffdff6aSGreg Kroah-Hartman chan >= 8 && chan <= 23) { 5758ffdff6aSGreg Kroah-Hartman /* counters 4-7 pfi channels */ 5768ffdff6aSGreg Kroah-Hartman active_chip = 1; 5778ffdff6aSGreg Kroah-Hartman idle_chip = 0; 5788ffdff6aSGreg Kroah-Hartman } else { 5798ffdff6aSGreg Kroah-Hartman /* counters 0-3 pfi channels */ 5808ffdff6aSGreg Kroah-Hartman active_chip = 0; 5818ffdff6aSGreg Kroah-Hartman idle_chip = 1; 5828ffdff6aSGreg Kroah-Hartman } 5838ffdff6aSGreg Kroah-Hartman } 5848ffdff6aSGreg Kroah-Hartman 5858ffdff6aSGreg Kroah-Hartman if (idle_chip != active_chip) { 5868ffdff6aSGreg Kroah-Hartman /* set the pfi channel to high-z on the inactive chip */ 5878ffdff6aSGreg Kroah-Hartman bits = ni_660x_read(dev, idle_chip, NI660X_IO_CFG(chan)); 5888ffdff6aSGreg Kroah-Hartman bits &= ~NI660X_IO_CFG_OUT_SEL_MASK(chan); 5898ffdff6aSGreg Kroah-Hartman bits |= NI660X_IO_CFG_OUT_SEL(chan, 0); /* high-z */ 5908ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, idle_chip, bits, NI660X_IO_CFG(chan)); 5918ffdff6aSGreg Kroah-Hartman } 5928ffdff6aSGreg Kroah-Hartman 5938ffdff6aSGreg Kroah-Hartman /* set the pfi channel output on the active chip */ 5948ffdff6aSGreg Kroah-Hartman bits = ni_660x_read(dev, active_chip, NI660X_IO_CFG(chan)); 5958ffdff6aSGreg Kroah-Hartman bits &= ~NI660X_IO_CFG_OUT_SEL_MASK(chan); 5968ffdff6aSGreg Kroah-Hartman bits |= NI660X_IO_CFG_OUT_SEL(chan, out_sel); 5978ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, active_chip, bits, NI660X_IO_CFG(chan)); 5988ffdff6aSGreg Kroah-Hartman } 5998ffdff6aSGreg Kroah-Hartman 6008ffdff6aSGreg Kroah-Hartman static void ni_660x_set_pfi_direction(struct comedi_device *dev, 6018ffdff6aSGreg Kroah-Hartman unsigned int chan, 6028ffdff6aSGreg Kroah-Hartman unsigned int direction) 6038ffdff6aSGreg Kroah-Hartman { 6048ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 6058ffdff6aSGreg Kroah-Hartman u64 bit; 6068ffdff6aSGreg Kroah-Hartman 6078ffdff6aSGreg Kroah-Hartman if (chan >= NI_PFI(0)) 6088ffdff6aSGreg Kroah-Hartman /* allow new and old names of pfi channels to work. */ 6098ffdff6aSGreg Kroah-Hartman chan -= NI_PFI(0); 6108ffdff6aSGreg Kroah-Hartman 6118ffdff6aSGreg Kroah-Hartman bit = 1ULL << chan; 6128ffdff6aSGreg Kroah-Hartman 6138ffdff6aSGreg Kroah-Hartman if (direction == COMEDI_OUTPUT) { 6148ffdff6aSGreg Kroah-Hartman devpriv->io_dir |= bit; 6158ffdff6aSGreg Kroah-Hartman /* reset the output to currently assigned output value */ 6168ffdff6aSGreg Kroah-Hartman ni_660x_select_pfi_output(dev, chan, devpriv->io_cfg[chan]); 6178ffdff6aSGreg Kroah-Hartman } else { 6188ffdff6aSGreg Kroah-Hartman devpriv->io_dir &= ~bit; 6198ffdff6aSGreg Kroah-Hartman /* set pin to high-z; do not change currently assigned route */ 6208ffdff6aSGreg Kroah-Hartman ni_660x_select_pfi_output(dev, chan, 0); 6218ffdff6aSGreg Kroah-Hartman } 6228ffdff6aSGreg Kroah-Hartman } 6238ffdff6aSGreg Kroah-Hartman 6248ffdff6aSGreg Kroah-Hartman static unsigned int ni_660x_get_pfi_direction(struct comedi_device *dev, 6258ffdff6aSGreg Kroah-Hartman unsigned int chan) 6268ffdff6aSGreg Kroah-Hartman { 6278ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 6288ffdff6aSGreg Kroah-Hartman u64 bit; 6298ffdff6aSGreg Kroah-Hartman 6308ffdff6aSGreg Kroah-Hartman if (chan >= NI_PFI(0)) 6318ffdff6aSGreg Kroah-Hartman /* allow new and old names of pfi channels to work. */ 6328ffdff6aSGreg Kroah-Hartman chan -= NI_PFI(0); 6338ffdff6aSGreg Kroah-Hartman 6348ffdff6aSGreg Kroah-Hartman bit = 1ULL << chan; 6358ffdff6aSGreg Kroah-Hartman 6368ffdff6aSGreg Kroah-Hartman return (devpriv->io_dir & bit) ? COMEDI_OUTPUT : COMEDI_INPUT; 6378ffdff6aSGreg Kroah-Hartman } 6388ffdff6aSGreg Kroah-Hartman 6398ffdff6aSGreg Kroah-Hartman static int ni_660x_set_pfi_routing(struct comedi_device *dev, 6408ffdff6aSGreg Kroah-Hartman unsigned int chan, unsigned int source) 6418ffdff6aSGreg Kroah-Hartman { 6428ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 6438ffdff6aSGreg Kroah-Hartman 6448ffdff6aSGreg Kroah-Hartman if (chan >= NI_PFI(0)) 6458ffdff6aSGreg Kroah-Hartman /* allow new and old names of pfi channels to work. */ 6468ffdff6aSGreg Kroah-Hartman chan -= NI_PFI(0); 6478ffdff6aSGreg Kroah-Hartman 6488ffdff6aSGreg Kroah-Hartman switch (source) { 6498ffdff6aSGreg Kroah-Hartman case NI_660X_PFI_OUTPUT_COUNTER: 6508ffdff6aSGreg Kroah-Hartman if (chan < 8) 6518ffdff6aSGreg Kroah-Hartman return -EINVAL; 6528ffdff6aSGreg Kroah-Hartman break; 6538ffdff6aSGreg Kroah-Hartman case NI_660X_PFI_OUTPUT_DIO: 6548ffdff6aSGreg Kroah-Hartman if (chan > 31) 6558ffdff6aSGreg Kroah-Hartman return -EINVAL; 6568ffdff6aSGreg Kroah-Hartman break; 6578ffdff6aSGreg Kroah-Hartman default: 6588ffdff6aSGreg Kroah-Hartman return -EINVAL; 6598ffdff6aSGreg Kroah-Hartman } 6608ffdff6aSGreg Kroah-Hartman 6618ffdff6aSGreg Kroah-Hartman devpriv->io_cfg[chan] = source; 6628ffdff6aSGreg Kroah-Hartman if (ni_660x_get_pfi_direction(dev, chan) == COMEDI_OUTPUT) 6638ffdff6aSGreg Kroah-Hartman ni_660x_select_pfi_output(dev, chan, devpriv->io_cfg[chan]); 6648ffdff6aSGreg Kroah-Hartman return 0; 6658ffdff6aSGreg Kroah-Hartman } 6668ffdff6aSGreg Kroah-Hartman 6678ffdff6aSGreg Kroah-Hartman static int ni_660x_get_pfi_routing(struct comedi_device *dev, unsigned int chan) 6688ffdff6aSGreg Kroah-Hartman { 6698ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 6708ffdff6aSGreg Kroah-Hartman 6718ffdff6aSGreg Kroah-Hartman if (chan >= NI_PFI(0)) 6728ffdff6aSGreg Kroah-Hartman /* allow new and old names of pfi channels to work. */ 6738ffdff6aSGreg Kroah-Hartman chan -= NI_PFI(0); 6748ffdff6aSGreg Kroah-Hartman 6758ffdff6aSGreg Kroah-Hartman return devpriv->io_cfg[chan]; 6768ffdff6aSGreg Kroah-Hartman } 6778ffdff6aSGreg Kroah-Hartman 6788ffdff6aSGreg Kroah-Hartman static void ni_660x_set_pfi_filter(struct comedi_device *dev, 6798ffdff6aSGreg Kroah-Hartman unsigned int chan, unsigned int value) 6808ffdff6aSGreg Kroah-Hartman { 6818ffdff6aSGreg Kroah-Hartman unsigned int val; 6828ffdff6aSGreg Kroah-Hartman 6838ffdff6aSGreg Kroah-Hartman if (chan >= NI_PFI(0)) 6848ffdff6aSGreg Kroah-Hartman /* allow new and old names of pfi channels to work. */ 6858ffdff6aSGreg Kroah-Hartman chan -= NI_PFI(0); 6868ffdff6aSGreg Kroah-Hartman 6878ffdff6aSGreg Kroah-Hartman val = ni_660x_read(dev, 0, NI660X_IO_CFG(chan)); 6888ffdff6aSGreg Kroah-Hartman val &= ~NI660X_IO_CFG_IN_SEL_MASK(chan); 6898ffdff6aSGreg Kroah-Hartman val |= NI660X_IO_CFG_IN_SEL(chan, value); 6908ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, 0, val, NI660X_IO_CFG(chan)); 6918ffdff6aSGreg Kroah-Hartman } 6928ffdff6aSGreg Kroah-Hartman 6938ffdff6aSGreg Kroah-Hartman static int ni_660x_dio_insn_config(struct comedi_device *dev, 6948ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, 6958ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 6968ffdff6aSGreg Kroah-Hartman unsigned int *data) 6978ffdff6aSGreg Kroah-Hartman { 6988ffdff6aSGreg Kroah-Hartman unsigned int chan = CR_CHAN(insn->chanspec); 6998ffdff6aSGreg Kroah-Hartman int ret; 7008ffdff6aSGreg Kroah-Hartman 7018ffdff6aSGreg Kroah-Hartman switch (data[0]) { 7028ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_DIO_OUTPUT: 7038ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_direction(dev, chan, COMEDI_OUTPUT); 7048ffdff6aSGreg Kroah-Hartman break; 7058ffdff6aSGreg Kroah-Hartman 7068ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_DIO_INPUT: 7078ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_direction(dev, chan, COMEDI_INPUT); 7088ffdff6aSGreg Kroah-Hartman break; 7098ffdff6aSGreg Kroah-Hartman 7108ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_DIO_QUERY: 7118ffdff6aSGreg Kroah-Hartman data[1] = ni_660x_get_pfi_direction(dev, chan); 7128ffdff6aSGreg Kroah-Hartman break; 7138ffdff6aSGreg Kroah-Hartman 7148ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_SET_ROUTING: 7158ffdff6aSGreg Kroah-Hartman ret = ni_660x_set_pfi_routing(dev, chan, data[1]); 7168ffdff6aSGreg Kroah-Hartman if (ret) 7178ffdff6aSGreg Kroah-Hartman return ret; 7188ffdff6aSGreg Kroah-Hartman break; 7198ffdff6aSGreg Kroah-Hartman 7208ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_GET_ROUTING: 7218ffdff6aSGreg Kroah-Hartman data[1] = ni_660x_get_pfi_routing(dev, chan); 7228ffdff6aSGreg Kroah-Hartman break; 7238ffdff6aSGreg Kroah-Hartman 7248ffdff6aSGreg Kroah-Hartman case INSN_CONFIG_FILTER: 7258ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_filter(dev, chan, data[1]); 7268ffdff6aSGreg Kroah-Hartman break; 7278ffdff6aSGreg Kroah-Hartman 7288ffdff6aSGreg Kroah-Hartman default: 7298ffdff6aSGreg Kroah-Hartman return -EINVAL; 7308ffdff6aSGreg Kroah-Hartman } 7318ffdff6aSGreg Kroah-Hartman 7328ffdff6aSGreg Kroah-Hartman return insn->n; 7338ffdff6aSGreg Kroah-Hartman } 7348ffdff6aSGreg Kroah-Hartman 7358ffdff6aSGreg Kroah-Hartman static unsigned int _ni_get_valid_routes(struct comedi_device *dev, 7368ffdff6aSGreg Kroah-Hartman unsigned int n_pairs, 7378ffdff6aSGreg Kroah-Hartman unsigned int *pair_data) 7388ffdff6aSGreg Kroah-Hartman { 7398ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 7408ffdff6aSGreg Kroah-Hartman 7418ffdff6aSGreg Kroah-Hartman return ni_get_valid_routes(&devpriv->routing_tables, n_pairs, 7428ffdff6aSGreg Kroah-Hartman pair_data); 7438ffdff6aSGreg Kroah-Hartman } 7448ffdff6aSGreg Kroah-Hartman 7458ffdff6aSGreg Kroah-Hartman /* 7468ffdff6aSGreg Kroah-Hartman * Retrieves the current source of the output selector for the given 7478ffdff6aSGreg Kroah-Hartman * destination. If the terminal for the destination is not already configured 7488ffdff6aSGreg Kroah-Hartman * as an output, this function returns -EINVAL as error. 7498ffdff6aSGreg Kroah-Hartman * 7508ffdff6aSGreg Kroah-Hartman * Return: The register value of the destination output selector; 7518ffdff6aSGreg Kroah-Hartman * -EINVAL if terminal is not configured for output. 7528ffdff6aSGreg Kroah-Hartman */ 7538ffdff6aSGreg Kroah-Hartman static inline int get_output_select_source(int dest, struct comedi_device *dev) 7548ffdff6aSGreg Kroah-Hartman { 7558ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 7568ffdff6aSGreg Kroah-Hartman int reg = -1; 7578ffdff6aSGreg Kroah-Hartman 7588ffdff6aSGreg Kroah-Hartman if (channel_is_pfi(dest)) { 7598ffdff6aSGreg Kroah-Hartman if (ni_660x_get_pfi_direction(dev, dest) == COMEDI_OUTPUT) 7608ffdff6aSGreg Kroah-Hartman reg = ni_660x_get_pfi_routing(dev, dest); 7618ffdff6aSGreg Kroah-Hartman } else if (channel_is_rtsi(dest)) { 7628ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev, 7638ffdff6aSGreg Kroah-Hartman "%s: unhandled rtsi destination (%d) queried\n", 7648ffdff6aSGreg Kroah-Hartman __func__, dest); 7658ffdff6aSGreg Kroah-Hartman /* 7668ffdff6aSGreg Kroah-Hartman * The following can be enabled when RTSI routing info is 7678ffdff6aSGreg Kroah-Hartman * determined (not currently documented): 7688ffdff6aSGreg Kroah-Hartman * if (ni_get_rtsi_direction(dev, dest) == COMEDI_OUTPUT) { 7698ffdff6aSGreg Kroah-Hartman * reg = ni_get_rtsi_routing(dev, dest); 7708ffdff6aSGreg Kroah-Hartman 7718ffdff6aSGreg Kroah-Hartman * if (reg == NI_RTSI_OUTPUT_RGOUT0) { 7728ffdff6aSGreg Kroah-Hartman * dest = NI_RGOUT0; ** prepare for lookup below ** 7738ffdff6aSGreg Kroah-Hartman * reg = get_rgout0_reg(dev); 7748ffdff6aSGreg Kroah-Hartman * } else if (reg >= NI_RTSI_OUTPUT_RTSI_BRD(0) && 7758ffdff6aSGreg Kroah-Hartman * reg <= NI_RTSI_OUTPUT_RTSI_BRD(3)) { 7768ffdff6aSGreg Kroah-Hartman * const int i = reg - NI_RTSI_OUTPUT_RTSI_BRD(0); 7778ffdff6aSGreg Kroah-Hartman 7788ffdff6aSGreg Kroah-Hartman * dest = NI_RTSI_BRD(i); ** prepare for lookup ** 7798ffdff6aSGreg Kroah-Hartman * reg = get_ith_rtsi_brd_reg(i, dev); 7808ffdff6aSGreg Kroah-Hartman * } 7818ffdff6aSGreg Kroah-Hartman * } 7828ffdff6aSGreg Kroah-Hartman */ 7838ffdff6aSGreg Kroah-Hartman } else if (channel_is_ctr(dest)) { 7848ffdff6aSGreg Kroah-Hartman reg = ni_tio_get_routing(devpriv->counter_dev, dest); 7858ffdff6aSGreg Kroah-Hartman } else { 7868ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev, 7878ffdff6aSGreg Kroah-Hartman "%s: unhandled destination (%d) queried\n", 7888ffdff6aSGreg Kroah-Hartman __func__, dest); 7898ffdff6aSGreg Kroah-Hartman } 7908ffdff6aSGreg Kroah-Hartman 7918ffdff6aSGreg Kroah-Hartman if (reg >= 0) 7928ffdff6aSGreg Kroah-Hartman return ni_find_route_source(CR_CHAN(reg), dest, 7938ffdff6aSGreg Kroah-Hartman &devpriv->routing_tables); 7948ffdff6aSGreg Kroah-Hartman return -EINVAL; 7958ffdff6aSGreg Kroah-Hartman } 7968ffdff6aSGreg Kroah-Hartman 7978ffdff6aSGreg Kroah-Hartman /* 7988ffdff6aSGreg Kroah-Hartman * Test a route: 7998ffdff6aSGreg Kroah-Hartman * 8008ffdff6aSGreg Kroah-Hartman * Return: -1 if not connectible; 8018ffdff6aSGreg Kroah-Hartman * 0 if connectible and not connected; 8028ffdff6aSGreg Kroah-Hartman * 1 if connectible and connected. 8038ffdff6aSGreg Kroah-Hartman */ 8048ffdff6aSGreg Kroah-Hartman static inline int test_route(unsigned int src, unsigned int dest, 8058ffdff6aSGreg Kroah-Hartman struct comedi_device *dev) 8068ffdff6aSGreg Kroah-Hartman { 8078ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 8088ffdff6aSGreg Kroah-Hartman s8 reg = ni_route_to_register(CR_CHAN(src), dest, 8098ffdff6aSGreg Kroah-Hartman &devpriv->routing_tables); 8108ffdff6aSGreg Kroah-Hartman 8118ffdff6aSGreg Kroah-Hartman if (reg < 0) 8128ffdff6aSGreg Kroah-Hartman return -1; 8138ffdff6aSGreg Kroah-Hartman if (get_output_select_source(dest, dev) != CR_CHAN(src)) 8148ffdff6aSGreg Kroah-Hartman return 0; 8158ffdff6aSGreg Kroah-Hartman return 1; 8168ffdff6aSGreg Kroah-Hartman } 8178ffdff6aSGreg Kroah-Hartman 8188ffdff6aSGreg Kroah-Hartman /* Connect the actual route. */ 8198ffdff6aSGreg Kroah-Hartman static inline int connect_route(unsigned int src, unsigned int dest, 8208ffdff6aSGreg Kroah-Hartman struct comedi_device *dev) 8218ffdff6aSGreg Kroah-Hartman { 8228ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 8238ffdff6aSGreg Kroah-Hartman s8 reg = ni_route_to_register(CR_CHAN(src), dest, 8248ffdff6aSGreg Kroah-Hartman &devpriv->routing_tables); 8258ffdff6aSGreg Kroah-Hartman s8 current_src; 8268ffdff6aSGreg Kroah-Hartman 8278ffdff6aSGreg Kroah-Hartman if (reg < 0) 8288ffdff6aSGreg Kroah-Hartman /* route is not valid */ 8298ffdff6aSGreg Kroah-Hartman return -EINVAL; 8308ffdff6aSGreg Kroah-Hartman 8318ffdff6aSGreg Kroah-Hartman current_src = get_output_select_source(dest, dev); 8328ffdff6aSGreg Kroah-Hartman if (current_src == CR_CHAN(src)) 8338ffdff6aSGreg Kroah-Hartman return -EALREADY; 8348ffdff6aSGreg Kroah-Hartman if (current_src >= 0) 8358ffdff6aSGreg Kroah-Hartman /* destination mux is already busy. complain, don't overwrite */ 8368ffdff6aSGreg Kroah-Hartman return -EBUSY; 8378ffdff6aSGreg Kroah-Hartman 8388ffdff6aSGreg Kroah-Hartman /* The route is valid and available. Now connect... */ 8398ffdff6aSGreg Kroah-Hartman if (channel_is_pfi(CR_CHAN(dest))) { 8408ffdff6aSGreg Kroah-Hartman /* 8418ffdff6aSGreg Kroah-Hartman * set routing and then direction so that the output does not 8428ffdff6aSGreg Kroah-Hartman * first get generated with the wrong pin 8438ffdff6aSGreg Kroah-Hartman */ 8448ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_routing(dev, dest, reg); 8458ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_direction(dev, dest, COMEDI_OUTPUT); 8468ffdff6aSGreg Kroah-Hartman } else if (channel_is_rtsi(CR_CHAN(dest))) { 8478ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev, "%s: unhandled rtsi destination (%d)\n", 8488ffdff6aSGreg Kroah-Hartman __func__, dest); 8498ffdff6aSGreg Kroah-Hartman return -EINVAL; 8508ffdff6aSGreg Kroah-Hartman /* 8518ffdff6aSGreg Kroah-Hartman * The following can be enabled when RTSI routing info is 8528ffdff6aSGreg Kroah-Hartman * determined (not currently documented): 8538ffdff6aSGreg Kroah-Hartman * if (reg == NI_RTSI_OUTPUT_RGOUT0) { 8548ffdff6aSGreg Kroah-Hartman * int ret = incr_rgout0_src_use(src, dev); 8558ffdff6aSGreg Kroah-Hartman 8568ffdff6aSGreg Kroah-Hartman * if (ret < 0) 8578ffdff6aSGreg Kroah-Hartman * return ret; 8588ffdff6aSGreg Kroah-Hartman * } else if (ni_rtsi_route_requires_mux(reg)) { 8598ffdff6aSGreg Kroah-Hartman * ** Attempt to allocate and route (src->brd) ** 8608ffdff6aSGreg Kroah-Hartman * int brd = incr_rtsi_brd_src_use(src, dev); 8618ffdff6aSGreg Kroah-Hartman 8628ffdff6aSGreg Kroah-Hartman * if (brd < 0) 8638ffdff6aSGreg Kroah-Hartman * return brd; 8648ffdff6aSGreg Kroah-Hartman 8658ffdff6aSGreg Kroah-Hartman * ** Now lookup the register value for (brd->dest) ** 8668ffdff6aSGreg Kroah-Hartman * reg = ni_lookup_route_register(brd, CR_CHAN(dest), 8678ffdff6aSGreg Kroah-Hartman * &devpriv->routing_tables); 8688ffdff6aSGreg Kroah-Hartman * } 8698ffdff6aSGreg Kroah-Hartman 8708ffdff6aSGreg Kroah-Hartman * ni_set_rtsi_direction(dev, dest, COMEDI_OUTPUT); 8718ffdff6aSGreg Kroah-Hartman * ni_set_rtsi_routing(dev, dest, reg); 8728ffdff6aSGreg Kroah-Hartman */ 8738ffdff6aSGreg Kroah-Hartman } else if (channel_is_ctr(CR_CHAN(dest))) { 8748ffdff6aSGreg Kroah-Hartman /* 8758ffdff6aSGreg Kroah-Hartman * we are adding back the channel modifier info to set 8768ffdff6aSGreg Kroah-Hartman * invert/edge info passed by the user 8778ffdff6aSGreg Kroah-Hartman */ 8788ffdff6aSGreg Kroah-Hartman ni_tio_set_routing(devpriv->counter_dev, dest, 8798ffdff6aSGreg Kroah-Hartman reg | (src & ~CR_CHAN(-1))); 8808ffdff6aSGreg Kroah-Hartman } else { 8818ffdff6aSGreg Kroah-Hartman return -EINVAL; 8828ffdff6aSGreg Kroah-Hartman } 8838ffdff6aSGreg Kroah-Hartman return 0; 8848ffdff6aSGreg Kroah-Hartman } 8858ffdff6aSGreg Kroah-Hartman 8868ffdff6aSGreg Kroah-Hartman static inline int disconnect_route(unsigned int src, unsigned int dest, 8878ffdff6aSGreg Kroah-Hartman struct comedi_device *dev) 8888ffdff6aSGreg Kroah-Hartman { 8898ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 8908ffdff6aSGreg Kroah-Hartman s8 reg = ni_route_to_register(CR_CHAN(src), CR_CHAN(dest), 8918ffdff6aSGreg Kroah-Hartman &devpriv->routing_tables); 8928ffdff6aSGreg Kroah-Hartman 8938ffdff6aSGreg Kroah-Hartman if (reg < 0) 8948ffdff6aSGreg Kroah-Hartman /* route is not valid */ 8958ffdff6aSGreg Kroah-Hartman return -EINVAL; 8968ffdff6aSGreg Kroah-Hartman if (get_output_select_source(dest, dev) != CR_CHAN(src)) 8978ffdff6aSGreg Kroah-Hartman /* cannot disconnect something not connected */ 8988ffdff6aSGreg Kroah-Hartman return -EINVAL; 8998ffdff6aSGreg Kroah-Hartman 9008ffdff6aSGreg Kroah-Hartman /* The route is valid and is connected. Now disconnect... */ 9018ffdff6aSGreg Kroah-Hartman if (channel_is_pfi(CR_CHAN(dest))) { 9028ffdff6aSGreg Kroah-Hartman unsigned int source = ((CR_CHAN(dest) - NI_PFI(0)) < 8) 9038ffdff6aSGreg Kroah-Hartman ? NI_660X_PFI_OUTPUT_DIO 9048ffdff6aSGreg Kroah-Hartman : NI_660X_PFI_OUTPUT_COUNTER; 9058ffdff6aSGreg Kroah-Hartman 9068ffdff6aSGreg Kroah-Hartman /* set the pfi to high impedance, and disconnect */ 9078ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_direction(dev, dest, COMEDI_INPUT); 9088ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_routing(dev, dest, source); 9098ffdff6aSGreg Kroah-Hartman } else if (channel_is_rtsi(CR_CHAN(dest))) { 9108ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev, "%s: unhandled rtsi destination (%d)\n", 9118ffdff6aSGreg Kroah-Hartman __func__, dest); 9128ffdff6aSGreg Kroah-Hartman return -EINVAL; 9138ffdff6aSGreg Kroah-Hartman /* 9148ffdff6aSGreg Kroah-Hartman * The following can be enabled when RTSI routing info is 9158ffdff6aSGreg Kroah-Hartman * determined (not currently documented): 9168ffdff6aSGreg Kroah-Hartman * if (reg == NI_RTSI_OUTPUT_RGOUT0) { 9178ffdff6aSGreg Kroah-Hartman * int ret = decr_rgout0_src_use(src, dev); 9188ffdff6aSGreg Kroah-Hartman 9198ffdff6aSGreg Kroah-Hartman * if (ret < 0) 9208ffdff6aSGreg Kroah-Hartman * return ret; 9218ffdff6aSGreg Kroah-Hartman * } else if (ni_rtsi_route_requires_mux(reg)) { 9228ffdff6aSGreg Kroah-Hartman * ** find which RTSI_BRD line is source for rtsi pin ** 9238ffdff6aSGreg Kroah-Hartman * int brd = ni_find_route_source( 9248ffdff6aSGreg Kroah-Hartman * ni_get_rtsi_routing(dev, dest), CR_CHAN(dest), 9258ffdff6aSGreg Kroah-Hartman * &devpriv->routing_tables); 9268ffdff6aSGreg Kroah-Hartman 9278ffdff6aSGreg Kroah-Hartman * if (brd < 0) 9288ffdff6aSGreg Kroah-Hartman * return brd; 9298ffdff6aSGreg Kroah-Hartman 9308ffdff6aSGreg Kroah-Hartman * ** decrement/disconnect RTSI_BRD line from source ** 9318ffdff6aSGreg Kroah-Hartman * decr_rtsi_brd_src_use(src, brd, dev); 9328ffdff6aSGreg Kroah-Hartman * } 9338ffdff6aSGreg Kroah-Hartman 9348ffdff6aSGreg Kroah-Hartman * ** set rtsi output selector to default state ** 9358ffdff6aSGreg Kroah-Hartman * reg = default_rtsi_routing[CR_CHAN(dest) - TRIGGER_LINE(0)]; 9368ffdff6aSGreg Kroah-Hartman * ni_set_rtsi_direction(dev, dest, COMEDI_INPUT); 9378ffdff6aSGreg Kroah-Hartman * ni_set_rtsi_routing(dev, dest, reg); 9388ffdff6aSGreg Kroah-Hartman */ 9398ffdff6aSGreg Kroah-Hartman } else if (channel_is_ctr(CR_CHAN(dest))) { 9408ffdff6aSGreg Kroah-Hartman ni_tio_unset_routing(devpriv->counter_dev, dest); 9418ffdff6aSGreg Kroah-Hartman } else { 9428ffdff6aSGreg Kroah-Hartman return -EINVAL; 9438ffdff6aSGreg Kroah-Hartman } 9448ffdff6aSGreg Kroah-Hartman return 0; 9458ffdff6aSGreg Kroah-Hartman } 9468ffdff6aSGreg Kroah-Hartman 9478ffdff6aSGreg Kroah-Hartman static int ni_global_insn_config(struct comedi_device *dev, 9488ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 9498ffdff6aSGreg Kroah-Hartman unsigned int *data) 9508ffdff6aSGreg Kroah-Hartman { 9518ffdff6aSGreg Kroah-Hartman switch (data[0]) { 9528ffdff6aSGreg Kroah-Hartman case INSN_DEVICE_CONFIG_TEST_ROUTE: 9538ffdff6aSGreg Kroah-Hartman data[0] = test_route(data[1], data[2], dev); 9548ffdff6aSGreg Kroah-Hartman return 2; 9558ffdff6aSGreg Kroah-Hartman case INSN_DEVICE_CONFIG_CONNECT_ROUTE: 9568ffdff6aSGreg Kroah-Hartman return connect_route(data[1], data[2], dev); 9578ffdff6aSGreg Kroah-Hartman case INSN_DEVICE_CONFIG_DISCONNECT_ROUTE: 9588ffdff6aSGreg Kroah-Hartman return disconnect_route(data[1], data[2], dev); 9598ffdff6aSGreg Kroah-Hartman /* 9608ffdff6aSGreg Kroah-Hartman * This case is already handled one level up. 9618ffdff6aSGreg Kroah-Hartman * case INSN_DEVICE_CONFIG_GET_ROUTES: 9628ffdff6aSGreg Kroah-Hartman */ 9638ffdff6aSGreg Kroah-Hartman default: 9648ffdff6aSGreg Kroah-Hartman return -EINVAL; 9658ffdff6aSGreg Kroah-Hartman } 9668ffdff6aSGreg Kroah-Hartman return 1; 9678ffdff6aSGreg Kroah-Hartman } 9688ffdff6aSGreg Kroah-Hartman 9698ffdff6aSGreg Kroah-Hartman static void ni_660x_init_tio_chips(struct comedi_device *dev, 9708ffdff6aSGreg Kroah-Hartman unsigned int n_chips) 9718ffdff6aSGreg Kroah-Hartman { 9728ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 9738ffdff6aSGreg Kroah-Hartman unsigned int chip; 9748ffdff6aSGreg Kroah-Hartman unsigned int chan; 9758ffdff6aSGreg Kroah-Hartman 9768ffdff6aSGreg Kroah-Hartman /* 9778ffdff6aSGreg Kroah-Hartman * We use the ioconfig registers to control dio direction, so zero 9788ffdff6aSGreg Kroah-Hartman * output enables in stc dio control reg. 9798ffdff6aSGreg Kroah-Hartman */ 9808ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, 0, 0, NI660X_STC_DIO_CONTROL); 9818ffdff6aSGreg Kroah-Hartman 9828ffdff6aSGreg Kroah-Hartman for (chip = 0; chip < n_chips; ++chip) { 9838ffdff6aSGreg Kroah-Hartman /* init dma configuration register */ 9848ffdff6aSGreg Kroah-Hartman devpriv->dma_cfg[chip] = 0; 9858ffdff6aSGreg Kroah-Hartman for (chan = 0; chan < NI660X_MAX_DMA_CHANNEL; ++chan) 9868ffdff6aSGreg Kroah-Hartman devpriv->dma_cfg[chip] |= NI660X_DMA_CFG_SEL_NONE(chan); 9878ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, chip, devpriv->dma_cfg[chip], 9888ffdff6aSGreg Kroah-Hartman NI660X_DMA_CFG); 9898ffdff6aSGreg Kroah-Hartman 9908ffdff6aSGreg Kroah-Hartman /* init ioconfig registers */ 9918ffdff6aSGreg Kroah-Hartman for (chan = 0; chan < NI660X_NUM_PFI_CHANNELS; ++chan) 9928ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, chip, 0, NI660X_IO_CFG(chan)); 9938ffdff6aSGreg Kroah-Hartman } 9948ffdff6aSGreg Kroah-Hartman } 9958ffdff6aSGreg Kroah-Hartman 9968ffdff6aSGreg Kroah-Hartman static int ni_660x_auto_attach(struct comedi_device *dev, 9978ffdff6aSGreg Kroah-Hartman unsigned long context) 9988ffdff6aSGreg Kroah-Hartman { 9998ffdff6aSGreg Kroah-Hartman struct pci_dev *pcidev = comedi_to_pci_dev(dev); 10008ffdff6aSGreg Kroah-Hartman const struct ni_660x_board *board = NULL; 10018ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv; 10028ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s; 10038ffdff6aSGreg Kroah-Hartman struct ni_gpct_device *gpct_dev; 10048ffdff6aSGreg Kroah-Hartman unsigned int n_counters; 10058ffdff6aSGreg Kroah-Hartman int subdev; 10068ffdff6aSGreg Kroah-Hartman int ret; 10078ffdff6aSGreg Kroah-Hartman unsigned int i; 10088ffdff6aSGreg Kroah-Hartman unsigned int global_interrupt_config_bits; 10098ffdff6aSGreg Kroah-Hartman 10108ffdff6aSGreg Kroah-Hartman if (context < ARRAY_SIZE(ni_660x_boards)) 10118ffdff6aSGreg Kroah-Hartman board = &ni_660x_boards[context]; 10128ffdff6aSGreg Kroah-Hartman if (!board) 10138ffdff6aSGreg Kroah-Hartman return -ENODEV; 10148ffdff6aSGreg Kroah-Hartman dev->board_ptr = board; 10158ffdff6aSGreg Kroah-Hartman dev->board_name = board->name; 10168ffdff6aSGreg Kroah-Hartman 10178ffdff6aSGreg Kroah-Hartman ret = comedi_pci_enable(dev); 10188ffdff6aSGreg Kroah-Hartman if (ret) 10198ffdff6aSGreg Kroah-Hartman return ret; 10208ffdff6aSGreg Kroah-Hartman 10218ffdff6aSGreg Kroah-Hartman ret = ni_660x_allocate_private(dev); 10228ffdff6aSGreg Kroah-Hartman if (ret < 0) 10238ffdff6aSGreg Kroah-Hartman return ret; 10248ffdff6aSGreg Kroah-Hartman devpriv = dev->private; 10258ffdff6aSGreg Kroah-Hartman 10268ffdff6aSGreg Kroah-Hartman devpriv->mite = mite_attach(dev, true); /* use win1 */ 10278ffdff6aSGreg Kroah-Hartman if (!devpriv->mite) 10288ffdff6aSGreg Kroah-Hartman return -ENOMEM; 10298ffdff6aSGreg Kroah-Hartman 10308ffdff6aSGreg Kroah-Hartman ret = ni_660x_alloc_mite_rings(dev); 10318ffdff6aSGreg Kroah-Hartman if (ret < 0) 10328ffdff6aSGreg Kroah-Hartman return ret; 10338ffdff6aSGreg Kroah-Hartman 10348ffdff6aSGreg Kroah-Hartman ni_660x_init_tio_chips(dev, board->n_chips); 10358ffdff6aSGreg Kroah-Hartman 10368ffdff6aSGreg Kroah-Hartman /* prepare the device for globally-named routes. */ 10378ffdff6aSGreg Kroah-Hartman if (ni_assign_device_routes("ni_660x", board->name, NULL, 10388ffdff6aSGreg Kroah-Hartman &devpriv->routing_tables) < 0) { 10398ffdff6aSGreg Kroah-Hartman dev_warn(dev->class_dev, "%s: %s device has no signal routing table.\n", 10408ffdff6aSGreg Kroah-Hartman __func__, board->name); 10418ffdff6aSGreg Kroah-Hartman dev_warn(dev->class_dev, "%s: High level NI signal names will not be available for this %s board.\n", 10428ffdff6aSGreg Kroah-Hartman __func__, board->name); 10438ffdff6aSGreg Kroah-Hartman } else { 10448ffdff6aSGreg Kroah-Hartman /* 10458ffdff6aSGreg Kroah-Hartman * only(?) assign insn_device_config if we have global names for 10468ffdff6aSGreg Kroah-Hartman * this device. 10478ffdff6aSGreg Kroah-Hartman */ 10488ffdff6aSGreg Kroah-Hartman dev->insn_device_config = ni_global_insn_config; 10498ffdff6aSGreg Kroah-Hartman dev->get_valid_routes = _ni_get_valid_routes; 10508ffdff6aSGreg Kroah-Hartman } 10518ffdff6aSGreg Kroah-Hartman 10528ffdff6aSGreg Kroah-Hartman n_counters = board->n_chips * NI660X_COUNTERS_PER_CHIP; 10538ffdff6aSGreg Kroah-Hartman gpct_dev = ni_gpct_device_construct(dev, 10548ffdff6aSGreg Kroah-Hartman ni_660x_gpct_write, 10558ffdff6aSGreg Kroah-Hartman ni_660x_gpct_read, 10568ffdff6aSGreg Kroah-Hartman ni_gpct_variant_660x, 10578ffdff6aSGreg Kroah-Hartman n_counters, 10588ffdff6aSGreg Kroah-Hartman NI660X_COUNTERS_PER_CHIP, 10598ffdff6aSGreg Kroah-Hartman &devpriv->routing_tables); 10608ffdff6aSGreg Kroah-Hartman if (!gpct_dev) 10618ffdff6aSGreg Kroah-Hartman return -ENOMEM; 10628ffdff6aSGreg Kroah-Hartman devpriv->counter_dev = gpct_dev; 10638ffdff6aSGreg Kroah-Hartman 10648ffdff6aSGreg Kroah-Hartman ret = comedi_alloc_subdevices(dev, 2 + NI660X_MAX_COUNTERS); 10658ffdff6aSGreg Kroah-Hartman if (ret) 10668ffdff6aSGreg Kroah-Hartman return ret; 10678ffdff6aSGreg Kroah-Hartman 10688ffdff6aSGreg Kroah-Hartman subdev = 0; 10698ffdff6aSGreg Kroah-Hartman 10708ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++]; 10718ffdff6aSGreg Kroah-Hartman /* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */ 10728ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_UNUSED; 10738ffdff6aSGreg Kroah-Hartman 10748ffdff6aSGreg Kroah-Hartman /* 10758ffdff6aSGreg Kroah-Hartman * Digital I/O subdevice 10768ffdff6aSGreg Kroah-Hartman * 10778ffdff6aSGreg Kroah-Hartman * There are 40 channels but only the first 32 can be digital I/Os. 10788ffdff6aSGreg Kroah-Hartman * The last 8 are dedicated to counters 0 and 1. 10798ffdff6aSGreg Kroah-Hartman * 10808ffdff6aSGreg Kroah-Hartman * Counter 0-3 signals are from the first TIO chip. 10818ffdff6aSGreg Kroah-Hartman * Counter 4-7 signals are from the second TIO chip. 10828ffdff6aSGreg Kroah-Hartman * 10838ffdff6aSGreg Kroah-Hartman * Comedi External 10848ffdff6aSGreg Kroah-Hartman * PFI Chan DIO Chan Counter Signal 10858ffdff6aSGreg Kroah-Hartman * ------- -------- -------------- 10868ffdff6aSGreg Kroah-Hartman * 0 0 10878ffdff6aSGreg Kroah-Hartman * 1 1 10888ffdff6aSGreg Kroah-Hartman * 2 2 10898ffdff6aSGreg Kroah-Hartman * 3 3 10908ffdff6aSGreg Kroah-Hartman * 4 4 10918ffdff6aSGreg Kroah-Hartman * 5 5 10928ffdff6aSGreg Kroah-Hartman * 6 6 10938ffdff6aSGreg Kroah-Hartman * 7 7 10948ffdff6aSGreg Kroah-Hartman * 8 8 CTR 7 OUT 10958ffdff6aSGreg Kroah-Hartman * 9 9 CTR 7 AUX 10968ffdff6aSGreg Kroah-Hartman * 10 10 CTR 7 GATE 10978ffdff6aSGreg Kroah-Hartman * 11 11 CTR 7 SOURCE 10988ffdff6aSGreg Kroah-Hartman * 12 12 CTR 6 OUT 10998ffdff6aSGreg Kroah-Hartman * 13 13 CTR 6 AUX 11008ffdff6aSGreg Kroah-Hartman * 14 14 CTR 6 GATE 11018ffdff6aSGreg Kroah-Hartman * 15 15 CTR 6 SOURCE 11028ffdff6aSGreg Kroah-Hartman * 16 16 CTR 5 OUT 11038ffdff6aSGreg Kroah-Hartman * 17 17 CTR 5 AUX 11048ffdff6aSGreg Kroah-Hartman * 18 18 CTR 5 GATE 11058ffdff6aSGreg Kroah-Hartman * 19 19 CTR 5 SOURCE 11068ffdff6aSGreg Kroah-Hartman * 20 20 CTR 4 OUT 11078ffdff6aSGreg Kroah-Hartman * 21 21 CTR 4 AUX 11088ffdff6aSGreg Kroah-Hartman * 22 22 CTR 4 GATE 11098ffdff6aSGreg Kroah-Hartman * 23 23 CTR 4 SOURCE 11108ffdff6aSGreg Kroah-Hartman * 24 24 CTR 3 OUT 11118ffdff6aSGreg Kroah-Hartman * 25 25 CTR 3 AUX 11128ffdff6aSGreg Kroah-Hartman * 26 26 CTR 3 GATE 11138ffdff6aSGreg Kroah-Hartman * 27 27 CTR 3 SOURCE 11148ffdff6aSGreg Kroah-Hartman * 28 28 CTR 2 OUT 11158ffdff6aSGreg Kroah-Hartman * 29 29 CTR 2 AUX 11168ffdff6aSGreg Kroah-Hartman * 30 30 CTR 2 GATE 11178ffdff6aSGreg Kroah-Hartman * 31 31 CTR 2 SOURCE 11188ffdff6aSGreg Kroah-Hartman * 32 CTR 1 OUT 11198ffdff6aSGreg Kroah-Hartman * 33 CTR 1 AUX 11208ffdff6aSGreg Kroah-Hartman * 34 CTR 1 GATE 11218ffdff6aSGreg Kroah-Hartman * 35 CTR 1 SOURCE 11228ffdff6aSGreg Kroah-Hartman * 36 CTR 0 OUT 11238ffdff6aSGreg Kroah-Hartman * 37 CTR 0 AUX 11248ffdff6aSGreg Kroah-Hartman * 38 CTR 0 GATE 11258ffdff6aSGreg Kroah-Hartman * 39 CTR 0 SOURCE 11268ffdff6aSGreg Kroah-Hartman */ 11278ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++]; 11288ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_DIO; 11298ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 11308ffdff6aSGreg Kroah-Hartman s->n_chan = NI660X_NUM_PFI_CHANNELS; 11318ffdff6aSGreg Kroah-Hartman s->maxdata = 1; 11328ffdff6aSGreg Kroah-Hartman s->range_table = &range_digital; 11338ffdff6aSGreg Kroah-Hartman s->insn_bits = ni_660x_dio_insn_bits; 11348ffdff6aSGreg Kroah-Hartman s->insn_config = ni_660x_dio_insn_config; 11358ffdff6aSGreg Kroah-Hartman 11368ffdff6aSGreg Kroah-Hartman /* 11378ffdff6aSGreg Kroah-Hartman * Default the DIO channels as: 11388ffdff6aSGreg Kroah-Hartman * chan 0-7: DIO inputs 11398ffdff6aSGreg Kroah-Hartman * chan 8-39: counter signal inputs 11408ffdff6aSGreg Kroah-Hartman */ 11418ffdff6aSGreg Kroah-Hartman for (i = 0; i < s->n_chan; ++i) { 11428ffdff6aSGreg Kroah-Hartman unsigned int source = (i < 8) ? NI_660X_PFI_OUTPUT_DIO 11438ffdff6aSGreg Kroah-Hartman : NI_660X_PFI_OUTPUT_COUNTER; 11448ffdff6aSGreg Kroah-Hartman 11458ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_routing(dev, i, source); 11468ffdff6aSGreg Kroah-Hartman ni_660x_set_pfi_direction(dev, i, COMEDI_INPUT);/* high-z */ 11478ffdff6aSGreg Kroah-Hartman } 11488ffdff6aSGreg Kroah-Hartman 11498ffdff6aSGreg Kroah-Hartman /* Counter subdevices (4 NI TIO General Purpose Counters per chip) */ 11508ffdff6aSGreg Kroah-Hartman for (i = 0; i < NI660X_MAX_COUNTERS; ++i) { 11518ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[subdev++]; 11528ffdff6aSGreg Kroah-Hartman if (i < n_counters) { 11538ffdff6aSGreg Kroah-Hartman struct ni_gpct *counter = &gpct_dev->counters[i]; 11548ffdff6aSGreg Kroah-Hartman 11558ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_COUNTER; 11568ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_READABLE | SDF_WRITABLE | 11578ffdff6aSGreg Kroah-Hartman SDF_LSAMPL | SDF_CMD_READ; 11588ffdff6aSGreg Kroah-Hartman s->n_chan = 3; 11598ffdff6aSGreg Kroah-Hartman s->maxdata = 0xffffffff; 11608ffdff6aSGreg Kroah-Hartman s->insn_read = ni_tio_insn_read; 11618ffdff6aSGreg Kroah-Hartman s->insn_write = ni_tio_insn_write; 11628ffdff6aSGreg Kroah-Hartman s->insn_config = ni_tio_insn_config; 11638ffdff6aSGreg Kroah-Hartman s->len_chanlist = 1; 11648ffdff6aSGreg Kroah-Hartman s->do_cmd = ni_660x_cmd; 11658ffdff6aSGreg Kroah-Hartman s->do_cmdtest = ni_tio_cmdtest; 11668ffdff6aSGreg Kroah-Hartman s->cancel = ni_660x_cancel; 11678ffdff6aSGreg Kroah-Hartman s->poll = ni_660x_input_poll; 11688ffdff6aSGreg Kroah-Hartman s->buf_change = ni_660x_buf_change; 11698ffdff6aSGreg Kroah-Hartman s->async_dma_dir = DMA_BIDIRECTIONAL; 11708ffdff6aSGreg Kroah-Hartman s->private = counter; 11718ffdff6aSGreg Kroah-Hartman 11728ffdff6aSGreg Kroah-Hartman ni_tio_init_counter(counter); 11738ffdff6aSGreg Kroah-Hartman } else { 11748ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_UNUSED; 11758ffdff6aSGreg Kroah-Hartman } 11768ffdff6aSGreg Kroah-Hartman } 11778ffdff6aSGreg Kroah-Hartman 11788ffdff6aSGreg Kroah-Hartman /* 11798ffdff6aSGreg Kroah-Hartman * To be safe, set counterswap bits on tio chips after all the counter 11808ffdff6aSGreg Kroah-Hartman * outputs have been set to high impedance mode. 11818ffdff6aSGreg Kroah-Hartman */ 11828ffdff6aSGreg Kroah-Hartman for (i = 0; i < board->n_chips; ++i) 11838ffdff6aSGreg Kroah-Hartman set_tio_counterswap(dev, i); 11848ffdff6aSGreg Kroah-Hartman 11858ffdff6aSGreg Kroah-Hartman ret = request_irq(pcidev->irq, ni_660x_interrupt, IRQF_SHARED, 11868ffdff6aSGreg Kroah-Hartman dev->board_name, dev); 11878ffdff6aSGreg Kroah-Hartman if (ret < 0) { 11888ffdff6aSGreg Kroah-Hartman dev_warn(dev->class_dev, " irq not available\n"); 11898ffdff6aSGreg Kroah-Hartman return ret; 11908ffdff6aSGreg Kroah-Hartman } 11918ffdff6aSGreg Kroah-Hartman dev->irq = pcidev->irq; 11928ffdff6aSGreg Kroah-Hartman global_interrupt_config_bits = NI660X_GLOBAL_INT_GLOBAL; 11938ffdff6aSGreg Kroah-Hartman if (board->n_chips > 1) 11948ffdff6aSGreg Kroah-Hartman global_interrupt_config_bits |= NI660X_GLOBAL_INT_CASCADE; 11958ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, 0, global_interrupt_config_bits, 11968ffdff6aSGreg Kroah-Hartman NI660X_GLOBAL_INT_CFG); 11978ffdff6aSGreg Kroah-Hartman 11988ffdff6aSGreg Kroah-Hartman return 0; 11998ffdff6aSGreg Kroah-Hartman } 12008ffdff6aSGreg Kroah-Hartman 12018ffdff6aSGreg Kroah-Hartman static void ni_660x_detach(struct comedi_device *dev) 12028ffdff6aSGreg Kroah-Hartman { 12038ffdff6aSGreg Kroah-Hartman struct ni_660x_private *devpriv = dev->private; 12048ffdff6aSGreg Kroah-Hartman 12058ffdff6aSGreg Kroah-Hartman if (dev->irq) { 12068ffdff6aSGreg Kroah-Hartman ni_660x_write(dev, 0, 0, NI660X_GLOBAL_INT_CFG); 12078ffdff6aSGreg Kroah-Hartman free_irq(dev->irq, dev); 12088ffdff6aSGreg Kroah-Hartman } 12098ffdff6aSGreg Kroah-Hartman if (devpriv) { 12108ffdff6aSGreg Kroah-Hartman ni_gpct_device_destroy(devpriv->counter_dev); 12118ffdff6aSGreg Kroah-Hartman ni_660x_free_mite_rings(dev); 12128ffdff6aSGreg Kroah-Hartman mite_detach(devpriv->mite); 12138ffdff6aSGreg Kroah-Hartman } 12148ffdff6aSGreg Kroah-Hartman if (dev->mmio) 12158ffdff6aSGreg Kroah-Hartman iounmap(dev->mmio); 12168ffdff6aSGreg Kroah-Hartman comedi_pci_disable(dev); 12178ffdff6aSGreg Kroah-Hartman } 12188ffdff6aSGreg Kroah-Hartman 12198ffdff6aSGreg Kroah-Hartman static struct comedi_driver ni_660x_driver = { 12208ffdff6aSGreg Kroah-Hartman .driver_name = "ni_660x", 12218ffdff6aSGreg Kroah-Hartman .module = THIS_MODULE, 12228ffdff6aSGreg Kroah-Hartman .auto_attach = ni_660x_auto_attach, 12238ffdff6aSGreg Kroah-Hartman .detach = ni_660x_detach, 12248ffdff6aSGreg Kroah-Hartman }; 12258ffdff6aSGreg Kroah-Hartman 12268ffdff6aSGreg Kroah-Hartman static int ni_660x_pci_probe(struct pci_dev *dev, 12278ffdff6aSGreg Kroah-Hartman const struct pci_device_id *id) 12288ffdff6aSGreg Kroah-Hartman { 12298ffdff6aSGreg Kroah-Hartman return comedi_pci_auto_config(dev, &ni_660x_driver, id->driver_data); 12308ffdff6aSGreg Kroah-Hartman } 12318ffdff6aSGreg Kroah-Hartman 12328ffdff6aSGreg Kroah-Hartman static const struct pci_device_id ni_660x_pci_table[] = { 12338ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(NI, 0x1310), BOARD_PCI6602 }, 12348ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(NI, 0x1360), BOARD_PXI6602 }, 12358ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(NI, 0x2c60), BOARD_PCI6601 }, 12368ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(NI, 0x2db0), BOARD_PCI6608 }, 12378ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(NI, 0x2cc0), BOARD_PXI6608 }, 12388ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(NI, 0x1e30), BOARD_PCI6624 }, 12398ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(NI, 0x1e40), BOARD_PXI6624 }, 12408ffdff6aSGreg Kroah-Hartman { 0 } 12418ffdff6aSGreg Kroah-Hartman }; 12428ffdff6aSGreg Kroah-Hartman MODULE_DEVICE_TABLE(pci, ni_660x_pci_table); 12438ffdff6aSGreg Kroah-Hartman 12448ffdff6aSGreg Kroah-Hartman static struct pci_driver ni_660x_pci_driver = { 12458ffdff6aSGreg Kroah-Hartman .name = "ni_660x", 12468ffdff6aSGreg Kroah-Hartman .id_table = ni_660x_pci_table, 12478ffdff6aSGreg Kroah-Hartman .probe = ni_660x_pci_probe, 12488ffdff6aSGreg Kroah-Hartman .remove = comedi_pci_auto_unconfig, 12498ffdff6aSGreg Kroah-Hartman }; 12508ffdff6aSGreg Kroah-Hartman module_comedi_pci_driver(ni_660x_driver, ni_660x_pci_driver); 12518ffdff6aSGreg Kroah-Hartman 12528ffdff6aSGreg Kroah-Hartman MODULE_AUTHOR("Comedi https://www.comedi.org"); 12538ffdff6aSGreg Kroah-Hartman MODULE_DESCRIPTION("Comedi driver for NI 660x counter/timer boards"); 12548ffdff6aSGreg Kroah-Hartman MODULE_LICENSE("GPL"); 1255