18ffdff6aSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 28ffdff6aSGreg Kroah-Hartman /* 38ffdff6aSGreg Kroah-Hartman * dt3000.c 48ffdff6aSGreg Kroah-Hartman * Data Translation DT3000 series driver 58ffdff6aSGreg Kroah-Hartman * 68ffdff6aSGreg Kroah-Hartman * COMEDI - Linux Control and Measurement Device Interface 78ffdff6aSGreg Kroah-Hartman * Copyright (C) 1999 David A. Schleef <ds@schleef.org> 88ffdff6aSGreg Kroah-Hartman */ 98ffdff6aSGreg Kroah-Hartman 108ffdff6aSGreg Kroah-Hartman /* 118ffdff6aSGreg Kroah-Hartman * Driver: dt3000 128ffdff6aSGreg Kroah-Hartman * Description: Data Translation DT3000 series 138ffdff6aSGreg Kroah-Hartman * Devices: [Data Translation] DT3001 (dt3000), DT3001-PGL, DT3002, DT3003, 148ffdff6aSGreg Kroah-Hartman * DT3003-PGL, DT3004, DT3005, DT3004-200 158ffdff6aSGreg Kroah-Hartman * Author: ds 168ffdff6aSGreg Kroah-Hartman * Updated: Mon, 14 Apr 2008 15:41:24 +0100 178ffdff6aSGreg Kroah-Hartman * Status: works 188ffdff6aSGreg Kroah-Hartman * 198ffdff6aSGreg Kroah-Hartman * Configuration Options: not applicable, uses PCI auto config 208ffdff6aSGreg Kroah-Hartman * 218ffdff6aSGreg Kroah-Hartman * There is code to support AI commands, but it may not work. 228ffdff6aSGreg Kroah-Hartman * 238ffdff6aSGreg Kroah-Hartman * AO commands are not supported. 248ffdff6aSGreg Kroah-Hartman */ 258ffdff6aSGreg Kroah-Hartman 268ffdff6aSGreg Kroah-Hartman /* 278ffdff6aSGreg Kroah-Hartman * The DT3000 series is Data Translation's attempt to make a PCI 288ffdff6aSGreg Kroah-Hartman * data acquisition board. The design of this series is very nice, 298ffdff6aSGreg Kroah-Hartman * since each board has an on-board DSP (Texas Instruments TMS320C52). 308ffdff6aSGreg Kroah-Hartman * However, a few details are a little annoying. The boards lack 318ffdff6aSGreg Kroah-Hartman * bus-mastering DMA, which eliminates them from serious work. 328ffdff6aSGreg Kroah-Hartman * They also are not capable of autocalibration, which is a common 338ffdff6aSGreg Kroah-Hartman * feature in modern hardware. The default firmware is pretty bad, 348ffdff6aSGreg Kroah-Hartman * making it nearly impossible to write an RT compatible driver. 358ffdff6aSGreg Kroah-Hartman * It would make an interesting project to write a decent firmware 368ffdff6aSGreg Kroah-Hartman * for these boards. 378ffdff6aSGreg Kroah-Hartman * 388ffdff6aSGreg Kroah-Hartman * Data Translation originally wanted an NDA for the documentation 398ffdff6aSGreg Kroah-Hartman * for the 3k series. However, if you ask nicely, they might send 408ffdff6aSGreg Kroah-Hartman * you the docs without one, also. 418ffdff6aSGreg Kroah-Hartman */ 428ffdff6aSGreg Kroah-Hartman 438ffdff6aSGreg Kroah-Hartman #include <linux/module.h> 448ffdff6aSGreg Kroah-Hartman #include <linux/delay.h> 458ffdff6aSGreg Kroah-Hartman #include <linux/interrupt.h> 46*df0e68c1SIan Abbott #include <linux/comedi/comedi_pci.h> 478ffdff6aSGreg Kroah-Hartman 488ffdff6aSGreg Kroah-Hartman /* 498ffdff6aSGreg Kroah-Hartman * PCI BAR0 - dual-ported RAM location definitions (dev->mmio) 508ffdff6aSGreg Kroah-Hartman */ 518ffdff6aSGreg Kroah-Hartman #define DPR_DAC_BUFFER (4 * 0x000) 528ffdff6aSGreg Kroah-Hartman #define DPR_ADC_BUFFER (4 * 0x800) 538ffdff6aSGreg Kroah-Hartman #define DPR_COMMAND (4 * 0xfd3) 548ffdff6aSGreg Kroah-Hartman #define DPR_SUBSYS (4 * 0xfd3) 558ffdff6aSGreg Kroah-Hartman #define DPR_SUBSYS_AI 0 568ffdff6aSGreg Kroah-Hartman #define DPR_SUBSYS_AO 1 578ffdff6aSGreg Kroah-Hartman #define DPR_SUBSYS_DIN 2 588ffdff6aSGreg Kroah-Hartman #define DPR_SUBSYS_DOUT 3 598ffdff6aSGreg Kroah-Hartman #define DPR_SUBSYS_MEM 4 608ffdff6aSGreg Kroah-Hartman #define DPR_SUBSYS_CT 5 618ffdff6aSGreg Kroah-Hartman #define DPR_ENCODE (4 * 0xfd4) 628ffdff6aSGreg Kroah-Hartman #define DPR_PARAMS(x) (4 * (0xfd5 + (x))) 638ffdff6aSGreg Kroah-Hartman #define DPR_TICK_REG_LO (4 * 0xff5) 648ffdff6aSGreg Kroah-Hartman #define DPR_TICK_REG_HI (4 * 0xff6) 658ffdff6aSGreg Kroah-Hartman #define DPR_DA_BUF_FRONT (4 * 0xff7) 668ffdff6aSGreg Kroah-Hartman #define DPR_DA_BUF_REAR (4 * 0xff8) 678ffdff6aSGreg Kroah-Hartman #define DPR_AD_BUF_FRONT (4 * 0xff9) 688ffdff6aSGreg Kroah-Hartman #define DPR_AD_BUF_REAR (4 * 0xffa) 698ffdff6aSGreg Kroah-Hartman #define DPR_INT_MASK (4 * 0xffb) 708ffdff6aSGreg Kroah-Hartman #define DPR_INTR_FLAG (4 * 0xffc) 718ffdff6aSGreg Kroah-Hartman #define DPR_INTR_CMDONE BIT(7) 728ffdff6aSGreg Kroah-Hartman #define DPR_INTR_CTDONE BIT(6) 738ffdff6aSGreg Kroah-Hartman #define DPR_INTR_DAHWERR BIT(5) 748ffdff6aSGreg Kroah-Hartman #define DPR_INTR_DASWERR BIT(4) 758ffdff6aSGreg Kroah-Hartman #define DPR_INTR_DAEMPTY BIT(3) 768ffdff6aSGreg Kroah-Hartman #define DPR_INTR_ADHWERR BIT(2) 778ffdff6aSGreg Kroah-Hartman #define DPR_INTR_ADSWERR BIT(1) 788ffdff6aSGreg Kroah-Hartman #define DPR_INTR_ADFULL BIT(0) 798ffdff6aSGreg Kroah-Hartman #define DPR_RESPONSE_MBX (4 * 0xffe) 808ffdff6aSGreg Kroah-Hartman #define DPR_CMD_MBX (4 * 0xfff) 818ffdff6aSGreg Kroah-Hartman #define DPR_CMD_COMPLETION(x) ((x) << 8) 828ffdff6aSGreg Kroah-Hartman #define DPR_CMD_NOTPROCESSED DPR_CMD_COMPLETION(0x00) 838ffdff6aSGreg Kroah-Hartman #define DPR_CMD_NOERROR DPR_CMD_COMPLETION(0x55) 848ffdff6aSGreg Kroah-Hartman #define DPR_CMD_ERROR DPR_CMD_COMPLETION(0xaa) 858ffdff6aSGreg Kroah-Hartman #define DPR_CMD_NOTSUPPORTED DPR_CMD_COMPLETION(0xff) 868ffdff6aSGreg Kroah-Hartman #define DPR_CMD_COMPLETION_MASK DPR_CMD_COMPLETION(0xff) 878ffdff6aSGreg Kroah-Hartman #define DPR_CMD(x) ((x) << 0) 888ffdff6aSGreg Kroah-Hartman #define DPR_CMD_GETBRDINFO DPR_CMD(0) 898ffdff6aSGreg Kroah-Hartman #define DPR_CMD_CONFIG DPR_CMD(1) 908ffdff6aSGreg Kroah-Hartman #define DPR_CMD_GETCONFIG DPR_CMD(2) 918ffdff6aSGreg Kroah-Hartman #define DPR_CMD_START DPR_CMD(3) 928ffdff6aSGreg Kroah-Hartman #define DPR_CMD_STOP DPR_CMD(4) 938ffdff6aSGreg Kroah-Hartman #define DPR_CMD_READSINGLE DPR_CMD(5) 948ffdff6aSGreg Kroah-Hartman #define DPR_CMD_WRITESINGLE DPR_CMD(6) 958ffdff6aSGreg Kroah-Hartman #define DPR_CMD_CALCCLOCK DPR_CMD(7) 968ffdff6aSGreg Kroah-Hartman #define DPR_CMD_READEVENTS DPR_CMD(8) 978ffdff6aSGreg Kroah-Hartman #define DPR_CMD_WRITECTCTRL DPR_CMD(16) 988ffdff6aSGreg Kroah-Hartman #define DPR_CMD_READCTCTRL DPR_CMD(17) 998ffdff6aSGreg Kroah-Hartman #define DPR_CMD_WRITECT DPR_CMD(18) 1008ffdff6aSGreg Kroah-Hartman #define DPR_CMD_READCT DPR_CMD(19) 1018ffdff6aSGreg Kroah-Hartman #define DPR_CMD_WRITEDATA DPR_CMD(32) 1028ffdff6aSGreg Kroah-Hartman #define DPR_CMD_READDATA DPR_CMD(33) 1038ffdff6aSGreg Kroah-Hartman #define DPR_CMD_WRITEIO DPR_CMD(34) 1048ffdff6aSGreg Kroah-Hartman #define DPR_CMD_READIO DPR_CMD(35) 1058ffdff6aSGreg Kroah-Hartman #define DPR_CMD_WRITECODE DPR_CMD(36) 1068ffdff6aSGreg Kroah-Hartman #define DPR_CMD_READCODE DPR_CMD(37) 1078ffdff6aSGreg Kroah-Hartman #define DPR_CMD_EXECUTE DPR_CMD(38) 1088ffdff6aSGreg Kroah-Hartman #define DPR_CMD_HALT DPR_CMD(48) 1098ffdff6aSGreg Kroah-Hartman #define DPR_CMD_MASK DPR_CMD(0xff) 1108ffdff6aSGreg Kroah-Hartman 1118ffdff6aSGreg Kroah-Hartman #define DPR_PARAM5_AD_TRIG(x) (((x) & 0x7) << 2) 1128ffdff6aSGreg Kroah-Hartman #define DPR_PARAM5_AD_TRIG_INT DPR_PARAM5_AD_TRIG(0) 1138ffdff6aSGreg Kroah-Hartman #define DPR_PARAM5_AD_TRIG_EXT DPR_PARAM5_AD_TRIG(1) 1148ffdff6aSGreg Kroah-Hartman #define DPR_PARAM5_AD_TRIG_INT_RETRIG DPR_PARAM5_AD_TRIG(2) 1158ffdff6aSGreg Kroah-Hartman #define DPR_PARAM5_AD_TRIG_EXT_RETRIG DPR_PARAM5_AD_TRIG(3) 1168ffdff6aSGreg Kroah-Hartman #define DPR_PARAM5_AD_TRIG_INT_RETRIG2 DPR_PARAM5_AD_TRIG(4) 1178ffdff6aSGreg Kroah-Hartman 1188ffdff6aSGreg Kroah-Hartman #define DPR_PARAM6_AD_DIFF BIT(0) 1198ffdff6aSGreg Kroah-Hartman 1208ffdff6aSGreg Kroah-Hartman #define DPR_AI_FIFO_DEPTH 2003 1218ffdff6aSGreg Kroah-Hartman #define DPR_AO_FIFO_DEPTH 2048 1228ffdff6aSGreg Kroah-Hartman 1238ffdff6aSGreg Kroah-Hartman #define DPR_EXTERNAL_CLOCK 1 1248ffdff6aSGreg Kroah-Hartman #define DPR_RISING_EDGE 2 1258ffdff6aSGreg Kroah-Hartman 1268ffdff6aSGreg Kroah-Hartman #define DPR_TMODE_MASK 0x1c 1278ffdff6aSGreg Kroah-Hartman 1288ffdff6aSGreg Kroah-Hartman #define DPR_CMD_TIMEOUT 100 1298ffdff6aSGreg Kroah-Hartman 1308ffdff6aSGreg Kroah-Hartman static const struct comedi_lrange range_dt3000_ai = { 1318ffdff6aSGreg Kroah-Hartman 4, { 1328ffdff6aSGreg Kroah-Hartman BIP_RANGE(10), 1338ffdff6aSGreg Kroah-Hartman BIP_RANGE(5), 1348ffdff6aSGreg Kroah-Hartman BIP_RANGE(2.5), 1358ffdff6aSGreg Kroah-Hartman BIP_RANGE(1.25) 1368ffdff6aSGreg Kroah-Hartman } 1378ffdff6aSGreg Kroah-Hartman }; 1388ffdff6aSGreg Kroah-Hartman 1398ffdff6aSGreg Kroah-Hartman static const struct comedi_lrange range_dt3000_ai_pgl = { 1408ffdff6aSGreg Kroah-Hartman 4, { 1418ffdff6aSGreg Kroah-Hartman BIP_RANGE(10), 1428ffdff6aSGreg Kroah-Hartman BIP_RANGE(1), 1438ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.1), 1448ffdff6aSGreg Kroah-Hartman BIP_RANGE(0.02) 1458ffdff6aSGreg Kroah-Hartman } 1468ffdff6aSGreg Kroah-Hartman }; 1478ffdff6aSGreg Kroah-Hartman 1488ffdff6aSGreg Kroah-Hartman enum dt3k_boardid { 1498ffdff6aSGreg Kroah-Hartman BOARD_DT3001, 1508ffdff6aSGreg Kroah-Hartman BOARD_DT3001_PGL, 1518ffdff6aSGreg Kroah-Hartman BOARD_DT3002, 1528ffdff6aSGreg Kroah-Hartman BOARD_DT3003, 1538ffdff6aSGreg Kroah-Hartman BOARD_DT3003_PGL, 1548ffdff6aSGreg Kroah-Hartman BOARD_DT3004, 1558ffdff6aSGreg Kroah-Hartman BOARD_DT3005, 1568ffdff6aSGreg Kroah-Hartman }; 1578ffdff6aSGreg Kroah-Hartman 1588ffdff6aSGreg Kroah-Hartman struct dt3k_boardtype { 1598ffdff6aSGreg Kroah-Hartman const char *name; 1608ffdff6aSGreg Kroah-Hartman int adchan; 1618ffdff6aSGreg Kroah-Hartman int ai_speed; 1628ffdff6aSGreg Kroah-Hartman const struct comedi_lrange *adrange; 1638ffdff6aSGreg Kroah-Hartman unsigned int ai_is_16bit:1; 1648ffdff6aSGreg Kroah-Hartman unsigned int has_ao:1; 1658ffdff6aSGreg Kroah-Hartman }; 1668ffdff6aSGreg Kroah-Hartman 1678ffdff6aSGreg Kroah-Hartman static const struct dt3k_boardtype dt3k_boardtypes[] = { 1688ffdff6aSGreg Kroah-Hartman [BOARD_DT3001] = { 1698ffdff6aSGreg Kroah-Hartman .name = "dt3001", 1708ffdff6aSGreg Kroah-Hartman .adchan = 16, 1718ffdff6aSGreg Kroah-Hartman .adrange = &range_dt3000_ai, 1728ffdff6aSGreg Kroah-Hartman .ai_speed = 3000, 1738ffdff6aSGreg Kroah-Hartman .has_ao = 1, 1748ffdff6aSGreg Kroah-Hartman }, 1758ffdff6aSGreg Kroah-Hartman [BOARD_DT3001_PGL] = { 1768ffdff6aSGreg Kroah-Hartman .name = "dt3001-pgl", 1778ffdff6aSGreg Kroah-Hartman .adchan = 16, 1788ffdff6aSGreg Kroah-Hartman .adrange = &range_dt3000_ai_pgl, 1798ffdff6aSGreg Kroah-Hartman .ai_speed = 3000, 1808ffdff6aSGreg Kroah-Hartman .has_ao = 1, 1818ffdff6aSGreg Kroah-Hartman }, 1828ffdff6aSGreg Kroah-Hartman [BOARD_DT3002] = { 1838ffdff6aSGreg Kroah-Hartman .name = "dt3002", 1848ffdff6aSGreg Kroah-Hartman .adchan = 32, 1858ffdff6aSGreg Kroah-Hartman .adrange = &range_dt3000_ai, 1868ffdff6aSGreg Kroah-Hartman .ai_speed = 3000, 1878ffdff6aSGreg Kroah-Hartman }, 1888ffdff6aSGreg Kroah-Hartman [BOARD_DT3003] = { 1898ffdff6aSGreg Kroah-Hartman .name = "dt3003", 1908ffdff6aSGreg Kroah-Hartman .adchan = 64, 1918ffdff6aSGreg Kroah-Hartman .adrange = &range_dt3000_ai, 1928ffdff6aSGreg Kroah-Hartman .ai_speed = 3000, 1938ffdff6aSGreg Kroah-Hartman .has_ao = 1, 1948ffdff6aSGreg Kroah-Hartman }, 1958ffdff6aSGreg Kroah-Hartman [BOARD_DT3003_PGL] = { 1968ffdff6aSGreg Kroah-Hartman .name = "dt3003-pgl", 1978ffdff6aSGreg Kroah-Hartman .adchan = 64, 1988ffdff6aSGreg Kroah-Hartman .adrange = &range_dt3000_ai_pgl, 1998ffdff6aSGreg Kroah-Hartman .ai_speed = 3000, 2008ffdff6aSGreg Kroah-Hartman .has_ao = 1, 2018ffdff6aSGreg Kroah-Hartman }, 2028ffdff6aSGreg Kroah-Hartman [BOARD_DT3004] = { 2038ffdff6aSGreg Kroah-Hartman .name = "dt3004", 2048ffdff6aSGreg Kroah-Hartman .adchan = 16, 2058ffdff6aSGreg Kroah-Hartman .adrange = &range_dt3000_ai, 2068ffdff6aSGreg Kroah-Hartman .ai_speed = 10000, 2078ffdff6aSGreg Kroah-Hartman .ai_is_16bit = 1, 2088ffdff6aSGreg Kroah-Hartman .has_ao = 1, 2098ffdff6aSGreg Kroah-Hartman }, 2108ffdff6aSGreg Kroah-Hartman [BOARD_DT3005] = { 2118ffdff6aSGreg Kroah-Hartman .name = "dt3005", /* a.k.a. 3004-200 */ 2128ffdff6aSGreg Kroah-Hartman .adchan = 16, 2138ffdff6aSGreg Kroah-Hartman .adrange = &range_dt3000_ai, 2148ffdff6aSGreg Kroah-Hartman .ai_speed = 5000, 2158ffdff6aSGreg Kroah-Hartman .ai_is_16bit = 1, 2168ffdff6aSGreg Kroah-Hartman .has_ao = 1, 2178ffdff6aSGreg Kroah-Hartman }, 2188ffdff6aSGreg Kroah-Hartman }; 2198ffdff6aSGreg Kroah-Hartman 2208ffdff6aSGreg Kroah-Hartman struct dt3k_private { 2218ffdff6aSGreg Kroah-Hartman unsigned int lock; 2228ffdff6aSGreg Kroah-Hartman unsigned int ai_front; 2238ffdff6aSGreg Kroah-Hartman unsigned int ai_rear; 2248ffdff6aSGreg Kroah-Hartman }; 2258ffdff6aSGreg Kroah-Hartman 2268ffdff6aSGreg Kroah-Hartman static void dt3k_send_cmd(struct comedi_device *dev, unsigned int cmd) 2278ffdff6aSGreg Kroah-Hartman { 2288ffdff6aSGreg Kroah-Hartman int i; 2298ffdff6aSGreg Kroah-Hartman unsigned int status = 0; 2308ffdff6aSGreg Kroah-Hartman 2318ffdff6aSGreg Kroah-Hartman writew(cmd, dev->mmio + DPR_CMD_MBX); 2328ffdff6aSGreg Kroah-Hartman 2338ffdff6aSGreg Kroah-Hartman for (i = 0; i < DPR_CMD_TIMEOUT; i++) { 2348ffdff6aSGreg Kroah-Hartman status = readw(dev->mmio + DPR_CMD_MBX); 2358ffdff6aSGreg Kroah-Hartman status &= DPR_CMD_COMPLETION_MASK; 2368ffdff6aSGreg Kroah-Hartman if (status != DPR_CMD_NOTPROCESSED) 2378ffdff6aSGreg Kroah-Hartman break; 2388ffdff6aSGreg Kroah-Hartman udelay(1); 2398ffdff6aSGreg Kroah-Hartman } 2408ffdff6aSGreg Kroah-Hartman 2418ffdff6aSGreg Kroah-Hartman if (status != DPR_CMD_NOERROR) 2428ffdff6aSGreg Kroah-Hartman dev_dbg(dev->class_dev, "%s: timeout/error status=0x%04x\n", 2438ffdff6aSGreg Kroah-Hartman __func__, status); 2448ffdff6aSGreg Kroah-Hartman } 2458ffdff6aSGreg Kroah-Hartman 2468ffdff6aSGreg Kroah-Hartman static unsigned int dt3k_readsingle(struct comedi_device *dev, 2478ffdff6aSGreg Kroah-Hartman unsigned int subsys, unsigned int chan, 2488ffdff6aSGreg Kroah-Hartman unsigned int gain) 2498ffdff6aSGreg Kroah-Hartman { 2508ffdff6aSGreg Kroah-Hartman writew(subsys, dev->mmio + DPR_SUBSYS); 2518ffdff6aSGreg Kroah-Hartman 2528ffdff6aSGreg Kroah-Hartman writew(chan, dev->mmio + DPR_PARAMS(0)); 2538ffdff6aSGreg Kroah-Hartman writew(gain, dev->mmio + DPR_PARAMS(1)); 2548ffdff6aSGreg Kroah-Hartman 2558ffdff6aSGreg Kroah-Hartman dt3k_send_cmd(dev, DPR_CMD_READSINGLE); 2568ffdff6aSGreg Kroah-Hartman 2578ffdff6aSGreg Kroah-Hartman return readw(dev->mmio + DPR_PARAMS(2)); 2588ffdff6aSGreg Kroah-Hartman } 2598ffdff6aSGreg Kroah-Hartman 2608ffdff6aSGreg Kroah-Hartman static void dt3k_writesingle(struct comedi_device *dev, unsigned int subsys, 2618ffdff6aSGreg Kroah-Hartman unsigned int chan, unsigned int data) 2628ffdff6aSGreg Kroah-Hartman { 2638ffdff6aSGreg Kroah-Hartman writew(subsys, dev->mmio + DPR_SUBSYS); 2648ffdff6aSGreg Kroah-Hartman 2658ffdff6aSGreg Kroah-Hartman writew(chan, dev->mmio + DPR_PARAMS(0)); 2668ffdff6aSGreg Kroah-Hartman writew(0, dev->mmio + DPR_PARAMS(1)); 2678ffdff6aSGreg Kroah-Hartman writew(data, dev->mmio + DPR_PARAMS(2)); 2688ffdff6aSGreg Kroah-Hartman 2698ffdff6aSGreg Kroah-Hartman dt3k_send_cmd(dev, DPR_CMD_WRITESINGLE); 2708ffdff6aSGreg Kroah-Hartman } 2718ffdff6aSGreg Kroah-Hartman 2728ffdff6aSGreg Kroah-Hartman static void dt3k_ai_empty_fifo(struct comedi_device *dev, 2738ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s) 2748ffdff6aSGreg Kroah-Hartman { 2758ffdff6aSGreg Kroah-Hartman struct dt3k_private *devpriv = dev->private; 2768ffdff6aSGreg Kroah-Hartman int front; 2778ffdff6aSGreg Kroah-Hartman int rear; 2788ffdff6aSGreg Kroah-Hartman int count; 2798ffdff6aSGreg Kroah-Hartman int i; 2808ffdff6aSGreg Kroah-Hartman unsigned short data; 2818ffdff6aSGreg Kroah-Hartman 2828ffdff6aSGreg Kroah-Hartman front = readw(dev->mmio + DPR_AD_BUF_FRONT); 2838ffdff6aSGreg Kroah-Hartman count = front - devpriv->ai_front; 2848ffdff6aSGreg Kroah-Hartman if (count < 0) 2858ffdff6aSGreg Kroah-Hartman count += DPR_AI_FIFO_DEPTH; 2868ffdff6aSGreg Kroah-Hartman 2878ffdff6aSGreg Kroah-Hartman rear = devpriv->ai_rear; 2888ffdff6aSGreg Kroah-Hartman 2898ffdff6aSGreg Kroah-Hartman for (i = 0; i < count; i++) { 2908ffdff6aSGreg Kroah-Hartman data = readw(dev->mmio + DPR_ADC_BUFFER + rear); 2918ffdff6aSGreg Kroah-Hartman comedi_buf_write_samples(s, &data, 1); 2928ffdff6aSGreg Kroah-Hartman rear++; 2938ffdff6aSGreg Kroah-Hartman if (rear >= DPR_AI_FIFO_DEPTH) 2948ffdff6aSGreg Kroah-Hartman rear = 0; 2958ffdff6aSGreg Kroah-Hartman } 2968ffdff6aSGreg Kroah-Hartman 2978ffdff6aSGreg Kroah-Hartman devpriv->ai_rear = rear; 2988ffdff6aSGreg Kroah-Hartman writew(rear, dev->mmio + DPR_AD_BUF_REAR); 2998ffdff6aSGreg Kroah-Hartman } 3008ffdff6aSGreg Kroah-Hartman 3018ffdff6aSGreg Kroah-Hartman static int dt3k_ai_cancel(struct comedi_device *dev, 3028ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s) 3038ffdff6aSGreg Kroah-Hartman { 3048ffdff6aSGreg Kroah-Hartman writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); 3058ffdff6aSGreg Kroah-Hartman dt3k_send_cmd(dev, DPR_CMD_STOP); 3068ffdff6aSGreg Kroah-Hartman 3078ffdff6aSGreg Kroah-Hartman writew(0, dev->mmio + DPR_INT_MASK); 3088ffdff6aSGreg Kroah-Hartman 3098ffdff6aSGreg Kroah-Hartman return 0; 3108ffdff6aSGreg Kroah-Hartman } 3118ffdff6aSGreg Kroah-Hartman 3128ffdff6aSGreg Kroah-Hartman static int debug_n_ints; 3138ffdff6aSGreg Kroah-Hartman 3148ffdff6aSGreg Kroah-Hartman /* FIXME! Assumes shared interrupt is for this card. */ 3158ffdff6aSGreg Kroah-Hartman /* What's this debug_n_ints stuff? Obviously needs some work... */ 3168ffdff6aSGreg Kroah-Hartman static irqreturn_t dt3k_interrupt(int irq, void *d) 3178ffdff6aSGreg Kroah-Hartman { 3188ffdff6aSGreg Kroah-Hartman struct comedi_device *dev = d; 3198ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s = dev->read_subdev; 3208ffdff6aSGreg Kroah-Hartman unsigned int status; 3218ffdff6aSGreg Kroah-Hartman 3228ffdff6aSGreg Kroah-Hartman if (!dev->attached) 3238ffdff6aSGreg Kroah-Hartman return IRQ_NONE; 3248ffdff6aSGreg Kroah-Hartman 3258ffdff6aSGreg Kroah-Hartman status = readw(dev->mmio + DPR_INTR_FLAG); 3268ffdff6aSGreg Kroah-Hartman 3278ffdff6aSGreg Kroah-Hartman if (status & DPR_INTR_ADFULL) 3288ffdff6aSGreg Kroah-Hartman dt3k_ai_empty_fifo(dev, s); 3298ffdff6aSGreg Kroah-Hartman 3308ffdff6aSGreg Kroah-Hartman if (status & (DPR_INTR_ADSWERR | DPR_INTR_ADHWERR)) 3318ffdff6aSGreg Kroah-Hartman s->async->events |= COMEDI_CB_ERROR; 3328ffdff6aSGreg Kroah-Hartman 3338ffdff6aSGreg Kroah-Hartman debug_n_ints++; 3348ffdff6aSGreg Kroah-Hartman if (debug_n_ints >= 10) 3358ffdff6aSGreg Kroah-Hartman s->async->events |= COMEDI_CB_EOA; 3368ffdff6aSGreg Kroah-Hartman 3378ffdff6aSGreg Kroah-Hartman comedi_handle_events(dev, s); 3388ffdff6aSGreg Kroah-Hartman return IRQ_HANDLED; 3398ffdff6aSGreg Kroah-Hartman } 3408ffdff6aSGreg Kroah-Hartman 3418ffdff6aSGreg Kroah-Hartman static int dt3k_ns_to_timer(unsigned int timer_base, unsigned int *nanosec, 3428ffdff6aSGreg Kroah-Hartman unsigned int flags) 3438ffdff6aSGreg Kroah-Hartman { 3448ffdff6aSGreg Kroah-Hartman unsigned int divider, base, prescale; 3458ffdff6aSGreg Kroah-Hartman 3468ffdff6aSGreg Kroah-Hartman /* This function needs improvement */ 3478ffdff6aSGreg Kroah-Hartman /* Don't know if divider==0 works. */ 3488ffdff6aSGreg Kroah-Hartman 3498ffdff6aSGreg Kroah-Hartman for (prescale = 0; prescale < 16; prescale++) { 3508ffdff6aSGreg Kroah-Hartman base = timer_base * (prescale + 1); 3518ffdff6aSGreg Kroah-Hartman switch (flags & CMDF_ROUND_MASK) { 3528ffdff6aSGreg Kroah-Hartman case CMDF_ROUND_NEAREST: 3538ffdff6aSGreg Kroah-Hartman default: 3548ffdff6aSGreg Kroah-Hartman divider = DIV_ROUND_CLOSEST(*nanosec, base); 3558ffdff6aSGreg Kroah-Hartman break; 3568ffdff6aSGreg Kroah-Hartman case CMDF_ROUND_DOWN: 3578ffdff6aSGreg Kroah-Hartman divider = (*nanosec) / base; 3588ffdff6aSGreg Kroah-Hartman break; 3598ffdff6aSGreg Kroah-Hartman case CMDF_ROUND_UP: 3608ffdff6aSGreg Kroah-Hartman divider = DIV_ROUND_UP(*nanosec, base); 3618ffdff6aSGreg Kroah-Hartman break; 3628ffdff6aSGreg Kroah-Hartman } 3638ffdff6aSGreg Kroah-Hartman if (divider < 65536) { 3648ffdff6aSGreg Kroah-Hartman *nanosec = divider * base; 3658ffdff6aSGreg Kroah-Hartman return (prescale << 16) | (divider); 3668ffdff6aSGreg Kroah-Hartman } 3678ffdff6aSGreg Kroah-Hartman } 3688ffdff6aSGreg Kroah-Hartman 3698ffdff6aSGreg Kroah-Hartman prescale = 15; 3708ffdff6aSGreg Kroah-Hartman base = timer_base * (prescale + 1); 3718ffdff6aSGreg Kroah-Hartman divider = 65535; 3728ffdff6aSGreg Kroah-Hartman *nanosec = divider * base; 3738ffdff6aSGreg Kroah-Hartman return (prescale << 16) | (divider); 3748ffdff6aSGreg Kroah-Hartman } 3758ffdff6aSGreg Kroah-Hartman 3768ffdff6aSGreg Kroah-Hartman static int dt3k_ai_cmdtest(struct comedi_device *dev, 3778ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, struct comedi_cmd *cmd) 3788ffdff6aSGreg Kroah-Hartman { 3798ffdff6aSGreg Kroah-Hartman const struct dt3k_boardtype *board = dev->board_ptr; 3808ffdff6aSGreg Kroah-Hartman int err = 0; 3818ffdff6aSGreg Kroah-Hartman unsigned int arg; 3828ffdff6aSGreg Kroah-Hartman 3838ffdff6aSGreg Kroah-Hartman /* Step 1 : check if triggers are trivially valid */ 3848ffdff6aSGreg Kroah-Hartman 3858ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->start_src, TRIG_NOW); 3868ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); 3878ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->convert_src, TRIG_TIMER); 3888ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); 3898ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_src(&cmd->stop_src, TRIG_COUNT); 3908ffdff6aSGreg Kroah-Hartman 3918ffdff6aSGreg Kroah-Hartman if (err) 3928ffdff6aSGreg Kroah-Hartman return 1; 3938ffdff6aSGreg Kroah-Hartman 3948ffdff6aSGreg Kroah-Hartman /* Step 2a : make sure trigger sources are unique */ 3958ffdff6aSGreg Kroah-Hartman /* Step 2b : and mutually compatible */ 3968ffdff6aSGreg Kroah-Hartman 3978ffdff6aSGreg Kroah-Hartman /* Step 3: check if arguments are trivially valid */ 3988ffdff6aSGreg Kroah-Hartman 3998ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->start_arg, 0); 4008ffdff6aSGreg Kroah-Hartman 4018ffdff6aSGreg Kroah-Hartman if (cmd->scan_begin_src == TRIG_TIMER) { 4028ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_min(&cmd->scan_begin_arg, 4038ffdff6aSGreg Kroah-Hartman board->ai_speed); 4048ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_max(&cmd->scan_begin_arg, 4058ffdff6aSGreg Kroah-Hartman 100 * 16 * 65535); 4068ffdff6aSGreg Kroah-Hartman } 4078ffdff6aSGreg Kroah-Hartman 4088ffdff6aSGreg Kroah-Hartman if (cmd->convert_src == TRIG_TIMER) { 4098ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_min(&cmd->convert_arg, 4108ffdff6aSGreg Kroah-Hartman board->ai_speed); 4118ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_max(&cmd->convert_arg, 4128ffdff6aSGreg Kroah-Hartman 50 * 16 * 65535); 4138ffdff6aSGreg Kroah-Hartman } 4148ffdff6aSGreg Kroah-Hartman 4158ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->scan_end_arg, 4168ffdff6aSGreg Kroah-Hartman cmd->chanlist_len); 4178ffdff6aSGreg Kroah-Hartman 4188ffdff6aSGreg Kroah-Hartman if (cmd->stop_src == TRIG_COUNT) 4198ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_max(&cmd->stop_arg, 0x00ffffff); 4208ffdff6aSGreg Kroah-Hartman else /* TRIG_NONE */ 4218ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->stop_arg, 0); 4228ffdff6aSGreg Kroah-Hartman 4238ffdff6aSGreg Kroah-Hartman if (err) 4248ffdff6aSGreg Kroah-Hartman return 3; 4258ffdff6aSGreg Kroah-Hartman 4268ffdff6aSGreg Kroah-Hartman /* step 4: fix up any arguments */ 4278ffdff6aSGreg Kroah-Hartman 4288ffdff6aSGreg Kroah-Hartman if (cmd->scan_begin_src == TRIG_TIMER) { 4298ffdff6aSGreg Kroah-Hartman arg = cmd->scan_begin_arg; 4308ffdff6aSGreg Kroah-Hartman dt3k_ns_to_timer(100, &arg, cmd->flags); 4318ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->scan_begin_arg, arg); 4328ffdff6aSGreg Kroah-Hartman } 4338ffdff6aSGreg Kroah-Hartman 4348ffdff6aSGreg Kroah-Hartman if (cmd->convert_src == TRIG_TIMER) { 4358ffdff6aSGreg Kroah-Hartman arg = cmd->convert_arg; 4368ffdff6aSGreg Kroah-Hartman dt3k_ns_to_timer(50, &arg, cmd->flags); 4378ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_is(&cmd->convert_arg, arg); 4388ffdff6aSGreg Kroah-Hartman 4398ffdff6aSGreg Kroah-Hartman if (cmd->scan_begin_src == TRIG_TIMER) { 4408ffdff6aSGreg Kroah-Hartman arg = cmd->convert_arg * cmd->scan_end_arg; 4418ffdff6aSGreg Kroah-Hartman err |= comedi_check_trigger_arg_min( 4428ffdff6aSGreg Kroah-Hartman &cmd->scan_begin_arg, arg); 4438ffdff6aSGreg Kroah-Hartman } 4448ffdff6aSGreg Kroah-Hartman } 4458ffdff6aSGreg Kroah-Hartman 4468ffdff6aSGreg Kroah-Hartman if (err) 4478ffdff6aSGreg Kroah-Hartman return 4; 4488ffdff6aSGreg Kroah-Hartman 4498ffdff6aSGreg Kroah-Hartman return 0; 4508ffdff6aSGreg Kroah-Hartman } 4518ffdff6aSGreg Kroah-Hartman 4528ffdff6aSGreg Kroah-Hartman static int dt3k_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) 4538ffdff6aSGreg Kroah-Hartman { 4548ffdff6aSGreg Kroah-Hartman struct comedi_cmd *cmd = &s->async->cmd; 4558ffdff6aSGreg Kroah-Hartman int i; 4568ffdff6aSGreg Kroah-Hartman unsigned int chan, range, aref; 4578ffdff6aSGreg Kroah-Hartman unsigned int divider; 4588ffdff6aSGreg Kroah-Hartman unsigned int tscandiv; 4598ffdff6aSGreg Kroah-Hartman 4608ffdff6aSGreg Kroah-Hartman for (i = 0; i < cmd->chanlist_len; i++) { 4618ffdff6aSGreg Kroah-Hartman chan = CR_CHAN(cmd->chanlist[i]); 4628ffdff6aSGreg Kroah-Hartman range = CR_RANGE(cmd->chanlist[i]); 4638ffdff6aSGreg Kroah-Hartman 4648ffdff6aSGreg Kroah-Hartman writew((range << 6) | chan, dev->mmio + DPR_ADC_BUFFER + i); 4658ffdff6aSGreg Kroah-Hartman } 4668ffdff6aSGreg Kroah-Hartman aref = CR_AREF(cmd->chanlist[0]); 4678ffdff6aSGreg Kroah-Hartman 4688ffdff6aSGreg Kroah-Hartman writew(cmd->scan_end_arg, dev->mmio + DPR_PARAMS(0)); 4698ffdff6aSGreg Kroah-Hartman 4708ffdff6aSGreg Kroah-Hartman if (cmd->convert_src == TRIG_TIMER) { 4718ffdff6aSGreg Kroah-Hartman divider = dt3k_ns_to_timer(50, &cmd->convert_arg, cmd->flags); 4728ffdff6aSGreg Kroah-Hartman writew((divider >> 16), dev->mmio + DPR_PARAMS(1)); 4738ffdff6aSGreg Kroah-Hartman writew((divider & 0xffff), dev->mmio + DPR_PARAMS(2)); 4748ffdff6aSGreg Kroah-Hartman } 4758ffdff6aSGreg Kroah-Hartman 4768ffdff6aSGreg Kroah-Hartman if (cmd->scan_begin_src == TRIG_TIMER) { 4778ffdff6aSGreg Kroah-Hartman tscandiv = dt3k_ns_to_timer(100, &cmd->scan_begin_arg, 4788ffdff6aSGreg Kroah-Hartman cmd->flags); 4798ffdff6aSGreg Kroah-Hartman writew((tscandiv >> 16), dev->mmio + DPR_PARAMS(3)); 4808ffdff6aSGreg Kroah-Hartman writew((tscandiv & 0xffff), dev->mmio + DPR_PARAMS(4)); 4818ffdff6aSGreg Kroah-Hartman } 4828ffdff6aSGreg Kroah-Hartman 4838ffdff6aSGreg Kroah-Hartman writew(DPR_PARAM5_AD_TRIG_INT_RETRIG, dev->mmio + DPR_PARAMS(5)); 4848ffdff6aSGreg Kroah-Hartman writew((aref == AREF_DIFF) ? DPR_PARAM6_AD_DIFF : 0, 4858ffdff6aSGreg Kroah-Hartman dev->mmio + DPR_PARAMS(6)); 4868ffdff6aSGreg Kroah-Hartman 4878ffdff6aSGreg Kroah-Hartman writew(DPR_AI_FIFO_DEPTH / 2, dev->mmio + DPR_PARAMS(7)); 4888ffdff6aSGreg Kroah-Hartman 4898ffdff6aSGreg Kroah-Hartman writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); 4908ffdff6aSGreg Kroah-Hartman dt3k_send_cmd(dev, DPR_CMD_CONFIG); 4918ffdff6aSGreg Kroah-Hartman 4928ffdff6aSGreg Kroah-Hartman writew(DPR_INTR_ADFULL | DPR_INTR_ADSWERR | DPR_INTR_ADHWERR, 4938ffdff6aSGreg Kroah-Hartman dev->mmio + DPR_INT_MASK); 4948ffdff6aSGreg Kroah-Hartman 4958ffdff6aSGreg Kroah-Hartman debug_n_ints = 0; 4968ffdff6aSGreg Kroah-Hartman 4978ffdff6aSGreg Kroah-Hartman writew(DPR_SUBSYS_AI, dev->mmio + DPR_SUBSYS); 4988ffdff6aSGreg Kroah-Hartman dt3k_send_cmd(dev, DPR_CMD_START); 4998ffdff6aSGreg Kroah-Hartman 5008ffdff6aSGreg Kroah-Hartman return 0; 5018ffdff6aSGreg Kroah-Hartman } 5028ffdff6aSGreg Kroah-Hartman 5038ffdff6aSGreg Kroah-Hartman static int dt3k_ai_insn_read(struct comedi_device *dev, 5048ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, 5058ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 5068ffdff6aSGreg Kroah-Hartman unsigned int *data) 5078ffdff6aSGreg Kroah-Hartman { 5088ffdff6aSGreg Kroah-Hartman int i; 5098ffdff6aSGreg Kroah-Hartman unsigned int chan, gain; 5108ffdff6aSGreg Kroah-Hartman 5118ffdff6aSGreg Kroah-Hartman chan = CR_CHAN(insn->chanspec); 5128ffdff6aSGreg Kroah-Hartman gain = CR_RANGE(insn->chanspec); 5138ffdff6aSGreg Kroah-Hartman /* XXX docs don't explain how to select aref */ 5148ffdff6aSGreg Kroah-Hartman 5158ffdff6aSGreg Kroah-Hartman for (i = 0; i < insn->n; i++) 5168ffdff6aSGreg Kroah-Hartman data[i] = dt3k_readsingle(dev, DPR_SUBSYS_AI, chan, gain); 5178ffdff6aSGreg Kroah-Hartman 5188ffdff6aSGreg Kroah-Hartman return i; 5198ffdff6aSGreg Kroah-Hartman } 5208ffdff6aSGreg Kroah-Hartman 5218ffdff6aSGreg Kroah-Hartman static int dt3k_ao_insn_write(struct comedi_device *dev, 5228ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, 5238ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 5248ffdff6aSGreg Kroah-Hartman unsigned int *data) 5258ffdff6aSGreg Kroah-Hartman { 5268ffdff6aSGreg Kroah-Hartman unsigned int chan = CR_CHAN(insn->chanspec); 5278ffdff6aSGreg Kroah-Hartman unsigned int val = s->readback[chan]; 5288ffdff6aSGreg Kroah-Hartman int i; 5298ffdff6aSGreg Kroah-Hartman 5308ffdff6aSGreg Kroah-Hartman for (i = 0; i < insn->n; i++) { 5318ffdff6aSGreg Kroah-Hartman val = data[i]; 5328ffdff6aSGreg Kroah-Hartman dt3k_writesingle(dev, DPR_SUBSYS_AO, chan, val); 5338ffdff6aSGreg Kroah-Hartman } 5348ffdff6aSGreg Kroah-Hartman s->readback[chan] = val; 5358ffdff6aSGreg Kroah-Hartman 5368ffdff6aSGreg Kroah-Hartman return insn->n; 5378ffdff6aSGreg Kroah-Hartman } 5388ffdff6aSGreg Kroah-Hartman 5398ffdff6aSGreg Kroah-Hartman static void dt3k_dio_config(struct comedi_device *dev, int bits) 5408ffdff6aSGreg Kroah-Hartman { 5418ffdff6aSGreg Kroah-Hartman /* XXX */ 5428ffdff6aSGreg Kroah-Hartman writew(DPR_SUBSYS_DOUT, dev->mmio + DPR_SUBSYS); 5438ffdff6aSGreg Kroah-Hartman 5448ffdff6aSGreg Kroah-Hartman writew(bits, dev->mmio + DPR_PARAMS(0)); 5458ffdff6aSGreg Kroah-Hartman 5468ffdff6aSGreg Kroah-Hartman /* XXX write 0 to DPR_PARAMS(1) and DPR_PARAMS(2) ? */ 5478ffdff6aSGreg Kroah-Hartman 5488ffdff6aSGreg Kroah-Hartman dt3k_send_cmd(dev, DPR_CMD_CONFIG); 5498ffdff6aSGreg Kroah-Hartman } 5508ffdff6aSGreg Kroah-Hartman 5518ffdff6aSGreg Kroah-Hartman static int dt3k_dio_insn_config(struct comedi_device *dev, 5528ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, 5538ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 5548ffdff6aSGreg Kroah-Hartman unsigned int *data) 5558ffdff6aSGreg Kroah-Hartman { 5568ffdff6aSGreg Kroah-Hartman unsigned int chan = CR_CHAN(insn->chanspec); 5578ffdff6aSGreg Kroah-Hartman unsigned int mask; 5588ffdff6aSGreg Kroah-Hartman int ret; 5598ffdff6aSGreg Kroah-Hartman 5608ffdff6aSGreg Kroah-Hartman if (chan < 4) 5618ffdff6aSGreg Kroah-Hartman mask = 0x0f; 5628ffdff6aSGreg Kroah-Hartman else 5638ffdff6aSGreg Kroah-Hartman mask = 0xf0; 5648ffdff6aSGreg Kroah-Hartman 5658ffdff6aSGreg Kroah-Hartman ret = comedi_dio_insn_config(dev, s, insn, data, mask); 5668ffdff6aSGreg Kroah-Hartman if (ret) 5678ffdff6aSGreg Kroah-Hartman return ret; 5688ffdff6aSGreg Kroah-Hartman 5698ffdff6aSGreg Kroah-Hartman dt3k_dio_config(dev, (s->io_bits & 0x01) | ((s->io_bits & 0x10) >> 3)); 5708ffdff6aSGreg Kroah-Hartman 5718ffdff6aSGreg Kroah-Hartman return insn->n; 5728ffdff6aSGreg Kroah-Hartman } 5738ffdff6aSGreg Kroah-Hartman 5748ffdff6aSGreg Kroah-Hartman static int dt3k_dio_insn_bits(struct comedi_device *dev, 5758ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, 5768ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 5778ffdff6aSGreg Kroah-Hartman unsigned int *data) 5788ffdff6aSGreg Kroah-Hartman { 5798ffdff6aSGreg Kroah-Hartman if (comedi_dio_update_state(s, data)) 5808ffdff6aSGreg Kroah-Hartman dt3k_writesingle(dev, DPR_SUBSYS_DOUT, 0, s->state); 5818ffdff6aSGreg Kroah-Hartman 5828ffdff6aSGreg Kroah-Hartman data[1] = dt3k_readsingle(dev, DPR_SUBSYS_DIN, 0, 0); 5838ffdff6aSGreg Kroah-Hartman 5848ffdff6aSGreg Kroah-Hartman return insn->n; 5858ffdff6aSGreg Kroah-Hartman } 5868ffdff6aSGreg Kroah-Hartman 5878ffdff6aSGreg Kroah-Hartman static int dt3k_mem_insn_read(struct comedi_device *dev, 5888ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s, 5898ffdff6aSGreg Kroah-Hartman struct comedi_insn *insn, 5908ffdff6aSGreg Kroah-Hartman unsigned int *data) 5918ffdff6aSGreg Kroah-Hartman { 5928ffdff6aSGreg Kroah-Hartman unsigned int addr = CR_CHAN(insn->chanspec); 5938ffdff6aSGreg Kroah-Hartman int i; 5948ffdff6aSGreg Kroah-Hartman 5958ffdff6aSGreg Kroah-Hartman for (i = 0; i < insn->n; i++) { 5968ffdff6aSGreg Kroah-Hartman writew(DPR_SUBSYS_MEM, dev->mmio + DPR_SUBSYS); 5978ffdff6aSGreg Kroah-Hartman writew(addr, dev->mmio + DPR_PARAMS(0)); 5988ffdff6aSGreg Kroah-Hartman writew(1, dev->mmio + DPR_PARAMS(1)); 5998ffdff6aSGreg Kroah-Hartman 6008ffdff6aSGreg Kroah-Hartman dt3k_send_cmd(dev, DPR_CMD_READCODE); 6018ffdff6aSGreg Kroah-Hartman 6028ffdff6aSGreg Kroah-Hartman data[i] = readw(dev->mmio + DPR_PARAMS(2)); 6038ffdff6aSGreg Kroah-Hartman } 6048ffdff6aSGreg Kroah-Hartman 6058ffdff6aSGreg Kroah-Hartman return i; 6068ffdff6aSGreg Kroah-Hartman } 6078ffdff6aSGreg Kroah-Hartman 6088ffdff6aSGreg Kroah-Hartman static int dt3000_auto_attach(struct comedi_device *dev, 6098ffdff6aSGreg Kroah-Hartman unsigned long context) 6108ffdff6aSGreg Kroah-Hartman { 6118ffdff6aSGreg Kroah-Hartman struct pci_dev *pcidev = comedi_to_pci_dev(dev); 6128ffdff6aSGreg Kroah-Hartman const struct dt3k_boardtype *board = NULL; 6138ffdff6aSGreg Kroah-Hartman struct dt3k_private *devpriv; 6148ffdff6aSGreg Kroah-Hartman struct comedi_subdevice *s; 6158ffdff6aSGreg Kroah-Hartman int ret = 0; 6168ffdff6aSGreg Kroah-Hartman 6178ffdff6aSGreg Kroah-Hartman if (context < ARRAY_SIZE(dt3k_boardtypes)) 6188ffdff6aSGreg Kroah-Hartman board = &dt3k_boardtypes[context]; 6198ffdff6aSGreg Kroah-Hartman if (!board) 6208ffdff6aSGreg Kroah-Hartman return -ENODEV; 6218ffdff6aSGreg Kroah-Hartman dev->board_ptr = board; 6228ffdff6aSGreg Kroah-Hartman dev->board_name = board->name; 6238ffdff6aSGreg Kroah-Hartman 6248ffdff6aSGreg Kroah-Hartman devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); 6258ffdff6aSGreg Kroah-Hartman if (!devpriv) 6268ffdff6aSGreg Kroah-Hartman return -ENOMEM; 6278ffdff6aSGreg Kroah-Hartman 6288ffdff6aSGreg Kroah-Hartman ret = comedi_pci_enable(dev); 6298ffdff6aSGreg Kroah-Hartman if (ret < 0) 6308ffdff6aSGreg Kroah-Hartman return ret; 6318ffdff6aSGreg Kroah-Hartman 6328ffdff6aSGreg Kroah-Hartman dev->mmio = pci_ioremap_bar(pcidev, 0); 6338ffdff6aSGreg Kroah-Hartman if (!dev->mmio) 6348ffdff6aSGreg Kroah-Hartman return -ENOMEM; 6358ffdff6aSGreg Kroah-Hartman 6368ffdff6aSGreg Kroah-Hartman if (pcidev->irq) { 6378ffdff6aSGreg Kroah-Hartman ret = request_irq(pcidev->irq, dt3k_interrupt, IRQF_SHARED, 6388ffdff6aSGreg Kroah-Hartman dev->board_name, dev); 6398ffdff6aSGreg Kroah-Hartman if (ret == 0) 6408ffdff6aSGreg Kroah-Hartman dev->irq = pcidev->irq; 6418ffdff6aSGreg Kroah-Hartman } 6428ffdff6aSGreg Kroah-Hartman 6438ffdff6aSGreg Kroah-Hartman ret = comedi_alloc_subdevices(dev, 4); 6448ffdff6aSGreg Kroah-Hartman if (ret) 6458ffdff6aSGreg Kroah-Hartman return ret; 6468ffdff6aSGreg Kroah-Hartman 6478ffdff6aSGreg Kroah-Hartman /* Analog Input subdevice */ 6488ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[0]; 6498ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_AI; 6508ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; 6518ffdff6aSGreg Kroah-Hartman s->n_chan = board->adchan; 6528ffdff6aSGreg Kroah-Hartman s->maxdata = board->ai_is_16bit ? 0xffff : 0x0fff; 6538ffdff6aSGreg Kroah-Hartman s->range_table = &range_dt3000_ai; /* XXX */ 6548ffdff6aSGreg Kroah-Hartman s->insn_read = dt3k_ai_insn_read; 6558ffdff6aSGreg Kroah-Hartman if (dev->irq) { 6568ffdff6aSGreg Kroah-Hartman dev->read_subdev = s; 6578ffdff6aSGreg Kroah-Hartman s->subdev_flags |= SDF_CMD_READ; 6588ffdff6aSGreg Kroah-Hartman s->len_chanlist = 512; 6598ffdff6aSGreg Kroah-Hartman s->do_cmd = dt3k_ai_cmd; 6608ffdff6aSGreg Kroah-Hartman s->do_cmdtest = dt3k_ai_cmdtest; 6618ffdff6aSGreg Kroah-Hartman s->cancel = dt3k_ai_cancel; 6628ffdff6aSGreg Kroah-Hartman } 6638ffdff6aSGreg Kroah-Hartman 6648ffdff6aSGreg Kroah-Hartman /* Analog Output subdevice */ 6658ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[1]; 6668ffdff6aSGreg Kroah-Hartman if (board->has_ao) { 6678ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_AO; 6688ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_WRITABLE; 6698ffdff6aSGreg Kroah-Hartman s->n_chan = 2; 6708ffdff6aSGreg Kroah-Hartman s->maxdata = 0x0fff; 6718ffdff6aSGreg Kroah-Hartman s->range_table = &range_bipolar10; 6728ffdff6aSGreg Kroah-Hartman s->insn_write = dt3k_ao_insn_write; 6738ffdff6aSGreg Kroah-Hartman 6748ffdff6aSGreg Kroah-Hartman ret = comedi_alloc_subdev_readback(s); 6758ffdff6aSGreg Kroah-Hartman if (ret) 6768ffdff6aSGreg Kroah-Hartman return ret; 6778ffdff6aSGreg Kroah-Hartman 6788ffdff6aSGreg Kroah-Hartman } else { 6798ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_UNUSED; 6808ffdff6aSGreg Kroah-Hartman } 6818ffdff6aSGreg Kroah-Hartman 6828ffdff6aSGreg Kroah-Hartman /* Digital I/O subdevice */ 6838ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[2]; 6848ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_DIO; 6858ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_READABLE | SDF_WRITABLE; 6868ffdff6aSGreg Kroah-Hartman s->n_chan = 8; 6878ffdff6aSGreg Kroah-Hartman s->maxdata = 1; 6888ffdff6aSGreg Kroah-Hartman s->range_table = &range_digital; 6898ffdff6aSGreg Kroah-Hartman s->insn_config = dt3k_dio_insn_config; 6908ffdff6aSGreg Kroah-Hartman s->insn_bits = dt3k_dio_insn_bits; 6918ffdff6aSGreg Kroah-Hartman 6928ffdff6aSGreg Kroah-Hartman /* Memory subdevice */ 6938ffdff6aSGreg Kroah-Hartman s = &dev->subdevices[3]; 6948ffdff6aSGreg Kroah-Hartman s->type = COMEDI_SUBD_MEMORY; 6958ffdff6aSGreg Kroah-Hartman s->subdev_flags = SDF_READABLE; 6968ffdff6aSGreg Kroah-Hartman s->n_chan = 0x1000; 6978ffdff6aSGreg Kroah-Hartman s->maxdata = 0xff; 6988ffdff6aSGreg Kroah-Hartman s->range_table = &range_unknown; 6998ffdff6aSGreg Kroah-Hartman s->insn_read = dt3k_mem_insn_read; 7008ffdff6aSGreg Kroah-Hartman 7018ffdff6aSGreg Kroah-Hartman return 0; 7028ffdff6aSGreg Kroah-Hartman } 7038ffdff6aSGreg Kroah-Hartman 7048ffdff6aSGreg Kroah-Hartman static struct comedi_driver dt3000_driver = { 7058ffdff6aSGreg Kroah-Hartman .driver_name = "dt3000", 7068ffdff6aSGreg Kroah-Hartman .module = THIS_MODULE, 7078ffdff6aSGreg Kroah-Hartman .auto_attach = dt3000_auto_attach, 7088ffdff6aSGreg Kroah-Hartman .detach = comedi_pci_detach, 7098ffdff6aSGreg Kroah-Hartman }; 7108ffdff6aSGreg Kroah-Hartman 7118ffdff6aSGreg Kroah-Hartman static int dt3000_pci_probe(struct pci_dev *dev, 7128ffdff6aSGreg Kroah-Hartman const struct pci_device_id *id) 7138ffdff6aSGreg Kroah-Hartman { 7148ffdff6aSGreg Kroah-Hartman return comedi_pci_auto_config(dev, &dt3000_driver, id->driver_data); 7158ffdff6aSGreg Kroah-Hartman } 7168ffdff6aSGreg Kroah-Hartman 7178ffdff6aSGreg Kroah-Hartman static const struct pci_device_id dt3000_pci_table[] = { 7188ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(DT, 0x0022), BOARD_DT3001 }, 7198ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(DT, 0x0023), BOARD_DT3002 }, 7208ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(DT, 0x0024), BOARD_DT3003 }, 7218ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(DT, 0x0025), BOARD_DT3004 }, 7228ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(DT, 0x0026), BOARD_DT3005 }, 7238ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(DT, 0x0027), BOARD_DT3001_PGL }, 7248ffdff6aSGreg Kroah-Hartman { PCI_VDEVICE(DT, 0x0028), BOARD_DT3003_PGL }, 7258ffdff6aSGreg Kroah-Hartman { 0 } 7268ffdff6aSGreg Kroah-Hartman }; 7278ffdff6aSGreg Kroah-Hartman MODULE_DEVICE_TABLE(pci, dt3000_pci_table); 7288ffdff6aSGreg Kroah-Hartman 7298ffdff6aSGreg Kroah-Hartman static struct pci_driver dt3000_pci_driver = { 7308ffdff6aSGreg Kroah-Hartman .name = "dt3000", 7318ffdff6aSGreg Kroah-Hartman .id_table = dt3000_pci_table, 7328ffdff6aSGreg Kroah-Hartman .probe = dt3000_pci_probe, 7338ffdff6aSGreg Kroah-Hartman .remove = comedi_pci_auto_unconfig, 7348ffdff6aSGreg Kroah-Hartman }; 7358ffdff6aSGreg Kroah-Hartman module_comedi_pci_driver(dt3000_driver, dt3000_pci_driver); 7368ffdff6aSGreg Kroah-Hartman 7378ffdff6aSGreg Kroah-Hartman MODULE_AUTHOR("Comedi https://www.comedi.org"); 7388ffdff6aSGreg Kroah-Hartman MODULE_DESCRIPTION("Comedi driver for Data Translation DT3000 series boards"); 7398ffdff6aSGreg Kroah-Hartman MODULE_LICENSE("GPL"); 740