staging: comedi: use comedi_alloc_devpriv()
[linux-2.6-block.git] / drivers / staging / comedi / drivers / rtd520.c
CommitLineData
3d9f0739 1/*
9880d313
HS
2 * comedi/drivers/rtd520.c
3 * Comedi driver for Real Time Devices (RTD) PCI4520/DM7520
4 *
5 * COMEDI - Linux Control and Measurement Device Interface
6 * Copyright (C) 2001 David A. Schleef <ds@schleef.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
9880d313 17 */
3d9f0739 18
3d9f0739 19/*
9880d313
HS
20 * Driver: rtd520
21 * Description: Real Time Devices PCI4520/DM7520
22 * Devices: (Real Time Devices) DM7520HR-1 [DM7520]
23 * (Real Time Devices) DM7520HR-8 [DM7520]
24 * (Real Time Devices) PCI4520 [PCI4520]
25 * (Real Time Devices) PCI4520-8 [PCI4520]
26 * Author: Dan Christian
27 * Status: Works. Only tested on DM7520-8. Not SMP safe.
28 *
29 * Configuration options: not applicable, uses PCI auto config
30 */
3d9f0739 31
3d9f0739 32/*
9880d313
HS
33 * Created by Dan Christian, NASA Ames Research Center.
34 *
35 * The PCI4520 is a PCI card. The DM7520 is a PC/104-plus card.
36 * Both have:
37 * 8/16 12 bit ADC with FIFO and channel gain table
38 * 8 bits high speed digital out (for external MUX) (or 8 in or 8 out)
39 * 8 bits high speed digital in with FIFO and interrupt on change (or 8 IO)
40 * 2 12 bit DACs with FIFOs
41 * 2 bits output
42 * 2 bits input
43 * bus mastering DMA
44 * timers: ADC sample, pacer, burst, about, delay, DA1, DA2
45 * sample counter
46 * 3 user timer/counters (8254)
47 * external interrupt
48 *
49 * The DM7520 has slightly fewer features (fewer gain steps).
50 *
51 * These boards can support external multiplexors and multi-board
52 * synchronization, but this driver doesn't support that.
53 *
54 * Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm
55 * Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf
56 * Example source: http://www.rtdusa.com/examples/dm/dm7520.zip
57 * Call them and ask for the register level manual.
58 * PCI chip: http://www.plxtech.com/products/io/pci9080
59 *
60 * Notes:
61 * This board is memory mapped. There is some IO stuff, but it isn't needed.
62 *
63 * I use a pretty loose naming style within the driver (rtd_blah).
64 * All externally visible names should be rtd520_blah.
65 * I use camelCase for structures (and inside them).
66 * I may also use upper CamelCase for function names (old habit).
67 *
68 * This board is somewhat related to the RTD PCI4400 board.
69 *
70 * I borrowed heavily from the ni_mio_common, ni_atmio16d, mite, and
71 * das1800, since they have the best documented code. Driver cb_pcidas64.c
72 * uses the same DMA controller.
73 *
74 * As far as I can tell, the About interrupt doesn't work if Sample is
75 * also enabled. It turns out that About really isn't needed, since
76 * we always count down samples read.
77 *
78 * There was some timer/counter code, but it didn't follow the right API.
79 */
3d9f0739
DC
80
81/*
9880d313
HS
82 * driver status:
83 *
84 * Analog-In supports instruction and command mode.
85 *
86 * With DMA, you can sample at 1.15Mhz with 70% idle on a 400Mhz K6-2
87 * (single channel, 64K read buffer). I get random system lockups when
88 * using DMA with ALI-15xx based systems. I haven't been able to test
89 * any other chipsets. The lockups happen soon after the start of an
90 * acquistion, not in the middle of a long run.
91 *
92 * Without DMA, you can do 620Khz sampling with 20% idle on a 400Mhz K6-2
93 * (with a 256K read buffer).
94 *
95 * Digital-IO and Analog-Out only support instruction mode.
96 */
3d9f0739 97
33782dd5 98#include <linux/pci.h>
3d9f0739 99#include <linux/delay.h>
33782dd5 100#include <linux/interrupt.h>
3d9f0739
DC
101
102#include "../comedidev.h"
3d9f0739 103
27020ffe 104#include "comedi_fc.h"
fe559c02 105#include "plx9080.h"
27020ffe 106
f88bb22f
HS
107/*
108 * Local Address Space 0 Offsets
109 */
110#define LAS0_USER_IO 0x0008 /* User I/O */
111#define LAS0_ADC 0x0010 /* FIFO Status/Software A/D Start */
112#define FS_DAC1_NOT_EMPTY (1 << 0) /* DAC1 FIFO not empty */
113#define FS_DAC1_HEMPTY (1 << 1) /* DAC1 FIFO half empty */
114#define FS_DAC1_NOT_FULL (1 << 2) /* DAC1 FIFO not full */
115#define FS_DAC2_NOT_EMPTY (1 << 4) /* DAC2 FIFO not empty */
116#define FS_DAC2_HEMPTY (1 << 5) /* DAC2 FIFO half empty */
117#define FS_DAC2_NOT_FULL (1 << 6) /* DAC2 FIFO not full */
118#define FS_ADC_NOT_EMPTY (1 << 8) /* ADC FIFO not empty */
119#define FS_ADC_HEMPTY (1 << 9) /* ADC FIFO half empty */
120#define FS_ADC_NOT_FULL (1 << 10) /* ADC FIFO not full */
121#define FS_DIN_NOT_EMPTY (1 << 12) /* DIN FIFO not empty */
122#define FS_DIN_HEMPTY (1 << 13) /* DIN FIFO half empty */
123#define FS_DIN_NOT_FULL (1 << 14) /* DIN FIFO not full */
124#define LAS0_DAC1 0x0014 /* Software D/A1 Update (w) */
125#define LAS0_DAC2 0x0018 /* Software D/A2 Update (w) */
126#define LAS0_DAC 0x0024 /* Software Simultaneous Update (w) */
127#define LAS0_PACER 0x0028 /* Software Pacer Start/Stop */
128#define LAS0_TIMER 0x002c /* Timer Status/HDIN Software Trig. */
129#define LAS0_IT 0x0030 /* Interrupt Status/Enable */
130#define IRQM_ADC_FIFO_WRITE (1 << 0) /* ADC FIFO Write */
131#define IRQM_CGT_RESET (1 << 1) /* Reset CGT */
132#define IRQM_CGT_PAUSE (1 << 3) /* Pause CGT */
133#define IRQM_ADC_ABOUT_CNT (1 << 4) /* About Counter out */
134#define IRQM_ADC_DELAY_CNT (1 << 5) /* Delay Counter out */
135#define IRQM_ADC_SAMPLE_CNT (1 << 6) /* ADC Sample Counter */
136#define IRQM_DAC1_UCNT (1 << 7) /* DAC1 Update Counter */
137#define IRQM_DAC2_UCNT (1 << 8) /* DAC2 Update Counter */
138#define IRQM_UTC1 (1 << 9) /* User TC1 out */
139#define IRQM_UTC1_INV (1 << 10) /* User TC1 out, inverted */
140#define IRQM_UTC2 (1 << 11) /* User TC2 out */
141#define IRQM_DIGITAL_IT (1 << 12) /* Digital Interrupt */
142#define IRQM_EXTERNAL_IT (1 << 13) /* External Interrupt */
143#define IRQM_ETRIG_RISING (1 << 14) /* Ext Trigger rising-edge */
144#define IRQM_ETRIG_FALLING (1 << 15) /* Ext Trigger falling-edge */
145#define LAS0_CLEAR 0x0034 /* Clear/Set Interrupt Clear Mask */
146#define LAS0_OVERRUN 0x0038 /* Pending interrupts/Clear Overrun */
147#define LAS0_PCLK 0x0040 /* Pacer Clock (24bit) */
148#define LAS0_BCLK 0x0044 /* Burst Clock (10bit) */
149#define LAS0_ADC_SCNT 0x0048 /* A/D Sample counter (10bit) */
150#define LAS0_DAC1_UCNT 0x004c /* D/A1 Update counter (10 bit) */
151#define LAS0_DAC2_UCNT 0x0050 /* D/A2 Update counter (10 bit) */
152#define LAS0_DCNT 0x0054 /* Delay counter (16 bit) */
153#define LAS0_ACNT 0x0058 /* About counter (16 bit) */
154#define LAS0_DAC_CLK 0x005c /* DAC clock (16bit) */
155#define LAS0_UTC0 0x0060 /* 8254 TC Counter 0 */
156#define LAS0_UTC1 0x0064 /* 8254 TC Counter 1 */
157#define LAS0_UTC2 0x0068 /* 8254 TC Counter 2 */
158#define LAS0_UTC_CTRL 0x006c /* 8254 TC Control */
159#define LAS0_DIO0 0x0070 /* Digital I/O Port 0 */
160#define LAS0_DIO1 0x0074 /* Digital I/O Port 1 */
161#define LAS0_DIO0_CTRL 0x0078 /* Digital I/O Control */
162#define LAS0_DIO_STATUS 0x007c /* Digital I/O Status */
163#define LAS0_BOARD_RESET 0x0100 /* Board reset */
164#define LAS0_DMA0_SRC 0x0104 /* DMA 0 Sources select */
165#define LAS0_DMA1_SRC 0x0108 /* DMA 1 Sources select */
166#define LAS0_ADC_CONVERSION 0x010c /* A/D Conversion Signal select */
167#define LAS0_BURST_START 0x0110 /* Burst Clock Start Trigger select */
168#define LAS0_PACER_START 0x0114 /* Pacer Clock Start Trigger select */
169#define LAS0_PACER_STOP 0x0118 /* Pacer Clock Stop Trigger select */
170#define LAS0_ACNT_STOP_ENABLE 0x011c /* About Counter Stop Enable */
171#define LAS0_PACER_REPEAT 0x0120 /* Pacer Start Trigger Mode select */
172#define LAS0_DIN_START 0x0124 /* HiSpd DI Sampling Signal select */
173#define LAS0_DIN_FIFO_CLEAR 0x0128 /* Digital Input FIFO Clear */
174#define LAS0_ADC_FIFO_CLEAR 0x012c /* A/D FIFO Clear */
175#define LAS0_CGT_WRITE 0x0130 /* Channel Gain Table Write */
176#define LAS0_CGL_WRITE 0x0134 /* Channel Gain Latch Write */
177#define LAS0_CG_DATA 0x0138 /* Digital Table Write */
178#define LAS0_CGT_ENABLE 0x013c /* Channel Gain Table Enable */
179#define LAS0_CG_ENABLE 0x0140 /* Digital Table Enable */
180#define LAS0_CGT_PAUSE 0x0144 /* Table Pause Enable */
181#define LAS0_CGT_RESET 0x0148 /* Reset Channel Gain Table */
182#define LAS0_CGT_CLEAR 0x014c /* Clear Channel Gain Table */
183#define LAS0_DAC1_CTRL 0x0150 /* D/A1 output type/range */
184#define LAS0_DAC1_SRC 0x0154 /* D/A1 update source */
185#define LAS0_DAC1_CYCLE 0x0158 /* D/A1 cycle mode */
186#define LAS0_DAC1_RESET 0x015c /* D/A1 FIFO reset */
187#define LAS0_DAC1_FIFO_CLEAR 0x0160 /* D/A1 FIFO clear */
188#define LAS0_DAC2_CTRL 0x0164 /* D/A2 output type/range */
189#define LAS0_DAC2_SRC 0x0168 /* D/A2 update source */
190#define LAS0_DAC2_CYCLE 0x016c /* D/A2 cycle mode */
191#define LAS0_DAC2_RESET 0x0170 /* D/A2 FIFO reset */
192#define LAS0_DAC2_FIFO_CLEAR 0x0174 /* D/A2 FIFO clear */
193#define LAS0_ADC_SCNT_SRC 0x0178 /* A/D Sample Counter Source select */
194#define LAS0_PACER_SELECT 0x0180 /* Pacer Clock select */
195#define LAS0_SBUS0_SRC 0x0184 /* SyncBus 0 Source select */
196#define LAS0_SBUS0_ENABLE 0x0188 /* SyncBus 0 enable */
197#define LAS0_SBUS1_SRC 0x018c /* SyncBus 1 Source select */
198#define LAS0_SBUS1_ENABLE 0x0190 /* SyncBus 1 enable */
199#define LAS0_SBUS2_SRC 0x0198 /* SyncBus 2 Source select */
200#define LAS0_SBUS2_ENABLE 0x019c /* SyncBus 2 enable */
201#define LAS0_ETRG_POLARITY 0x01a4 /* Ext. Trigger polarity select */
202#define LAS0_EINT_POLARITY 0x01a8 /* Ext. Interrupt polarity select */
203#define LAS0_UTC0_CLOCK 0x01ac /* UTC0 Clock select */
204#define LAS0_UTC0_GATE 0x01b0 /* UTC0 Gate select */
205#define LAS0_UTC1_CLOCK 0x01b4 /* UTC1 Clock select */
206#define LAS0_UTC1_GATE 0x01b8 /* UTC1 Gate select */
207#define LAS0_UTC2_CLOCK 0x01bc /* UTC2 Clock select */
208#define LAS0_UTC2_GATE 0x01c0 /* UTC2 Gate select */
209#define LAS0_UOUT0_SELECT 0x01c4 /* User Output 0 source select */
210#define LAS0_UOUT1_SELECT 0x01c8 /* User Output 1 source select */
211#define LAS0_DMA0_RESET 0x01cc /* DMA0 Request state machine reset */
212#define LAS0_DMA1_RESET 0x01d0 /* DMA1 Request state machine reset */
213
214/*
215 * Local Address Space 1 Offsets
216 */
217#define LAS1_ADC_FIFO 0x0000 /* A/D FIFO (16bit) */
218#define LAS1_HDIO_FIFO 0x0004 /* HiSpd DI FIFO (16bit) */
219#define LAS1_DAC1_FIFO 0x0008 /* D/A1 FIFO (16bit) */
220#define LAS1_DAC2_FIFO 0x000c /* D/A2 FIFO (16bit) */
221
3d9f0739
DC
222/*======================================================================
223 Driver specific stuff (tunable)
224======================================================================*/
3d9f0739
DC
225
226/* We really only need 2 buffers. More than that means being much
227 smarter about knowing which ones are full. */
228#define DMA_CHAIN_COUNT 2 /* max DMA segments/buffers in a ring (min 2) */
229
230/* Target period for periodic transfers. This sets the user read latency. */
231/* Note: There are certain rates where we give this up and transfer 1/2 FIFO */
232/* If this is too low, efficiency is poor */
233#define TRANS_TARGET_PERIOD 10000000 /* 10 ms (in nanoseconds) */
234
235/* Set a practical limit on how long a list to support (affects memory use) */
236/* The board support a channel list up to the FIFO length (1K or 8K) */
237#define RTD_MAX_CHANLIST 128 /* max channel list that we allow */
238
239/* tuning for ai/ao instruction done polling */
240#ifdef FAST_SPIN
241#define WAIT_QUIETLY /* as nothing, spin on done bit */
242#define RTD_ADC_TIMEOUT 66000 /* 2 msec at 33mhz bus rate */
243#define RTD_DAC_TIMEOUT 66000
244#define RTD_DMA_TIMEOUT 33000 /* 1 msec */
245#else
246/* by delaying, power and electrical noise are reduced somewhat */
bc8bf90a 247#define WAIT_QUIETLY udelay(1)
3d9f0739
DC
248#define RTD_ADC_TIMEOUT 2000 /* in usec */
249#define RTD_DAC_TIMEOUT 2000 /* in usec */
250#define RTD_DMA_TIMEOUT 1000 /* in usec */
251#endif
252
253/*======================================================================
254 Board specific stuff
255======================================================================*/
256
3d9f0739
DC
257#define RTD_CLOCK_RATE 8000000 /* 8Mhz onboard clock */
258#define RTD_CLOCK_BASE 125 /* clock period in ns */
259
260/* Note: these speed are slower than the spec, but fit the counter resolution*/
261#define RTD_MAX_SPEED 1625 /* when sampling, in nanoseconds */
262/* max speed if we don't have to wait for settling */
263#define RTD_MAX_SPEED_1 875 /* if single channel, in nanoseconds */
264
265#define RTD_MIN_SPEED 2097151875 /* (24bit counter) in nanoseconds */
266/* min speed when only 1 channel (no burst counter) */
267#define RTD_MIN_SPEED_1 5000000 /* 200Hz, in nanoseconds */
268
3d9f0739
DC
269/* Setup continuous ring of 1/2 FIFO transfers. See RTD manual p91 */
270#define DMA_MODE_BITS (\
271 PLX_LOCAL_BUS_16_WIDE_BITS \
272 | PLX_DMA_EN_READYIN_BIT \
273 | PLX_DMA_LOCAL_BURST_EN_BIT \
274 | PLX_EN_CHAIN_BIT \
275 | PLX_DMA_INTR_PCI_BIT \
276 | PLX_LOCAL_ADDR_CONST_BIT \
277 | PLX_DEMAND_MODE_BIT)
278
279#define DMA_TRANSFER_BITS (\
6e882d47 280/* descriptors in PCI memory*/ PLX_DESC_IN_PCI_BIT \
3d9f0739
DC
281/* interrupt at end of block */ | PLX_INTR_TERM_COUNT \
282/* from board to PCI */ | PLX_XFER_LOCAL_TO_PCI)
283
284/*======================================================================
285 Comedi specific stuff
286======================================================================*/
287
288/*
feb153f3
HS
289 * The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128)
290 */
291static const struct comedi_lrange rtd_ai_7520_range = {
292 18, {
293 /* +-5V input range gain steps */
294 BIP_RANGE(5.0),
295 BIP_RANGE(5.0 / 2),
296 BIP_RANGE(5.0 / 4),
297 BIP_RANGE(5.0 / 8),
298 BIP_RANGE(5.0 / 16),
299 BIP_RANGE(5.0 / 32),
300 /* +-10V input range gain steps */
301 BIP_RANGE(10.0),
302 BIP_RANGE(10.0 / 2),
303 BIP_RANGE(10.0 / 4),
304 BIP_RANGE(10.0 / 8),
305 BIP_RANGE(10.0 / 16),
306 BIP_RANGE(10.0 / 32),
307 /* +10V input range gain steps */
308 UNI_RANGE(10.0),
309 UNI_RANGE(10.0 / 2),
310 UNI_RANGE(10.0 / 4),
311 UNI_RANGE(10.0 / 8),
312 UNI_RANGE(10.0 / 16),
313 UNI_RANGE(10.0 / 32),
314 }
3d9f0739
DC
315};
316
317/* PCI4520 has two more gains (6 more entries) */
feb153f3
HS
318static const struct comedi_lrange rtd_ai_4520_range = {
319 24, {
320 /* +-5V input range gain steps */
321 BIP_RANGE(5.0),
322 BIP_RANGE(5.0 / 2),
323 BIP_RANGE(5.0 / 4),
324 BIP_RANGE(5.0 / 8),
325 BIP_RANGE(5.0 / 16),
326 BIP_RANGE(5.0 / 32),
327 BIP_RANGE(5.0 / 64),
328 BIP_RANGE(5.0 / 128),
329 /* +-10V input range gain steps */
330 BIP_RANGE(10.0),
331 BIP_RANGE(10.0 / 2),
332 BIP_RANGE(10.0 / 4),
333 BIP_RANGE(10.0 / 8),
334 BIP_RANGE(10.0 / 16),
335 BIP_RANGE(10.0 / 32),
336 BIP_RANGE(10.0 / 64),
337 BIP_RANGE(10.0 / 128),
338 /* +10V input range gain steps */
339 UNI_RANGE(10.0),
340 UNI_RANGE(10.0 / 2),
341 UNI_RANGE(10.0 / 4),
342 UNI_RANGE(10.0 / 8),
343 UNI_RANGE(10.0 / 16),
344 UNI_RANGE(10.0 / 32),
345 UNI_RANGE(10.0 / 64),
346 UNI_RANGE(10.0 / 128),
347 }
3d9f0739
DC
348};
349
350/* Table order matches range values */
feb153f3
HS
351static const struct comedi_lrange rtd_ao_range = {
352 4, {
353 UNI_RANGE(5),
354 UNI_RANGE(10),
355 BIP_RANGE(5),
356 BIP_RANGE(10),
357 }
3d9f0739
DC
358};
359
b3322d42
HS
360enum rtd_boardid {
361 BOARD_DM7520,
362 BOARD_PCI4520,
363};
364
dcc2358f 365struct rtd_boardinfo {
3cdefc92 366 const char *name;
dcc2358f
HS
367 int range_bip10; /* start of +-10V range */
368 int range_uni10; /* start of +10V range */
8a799460 369 const struct comedi_lrange *ai_range;
d80235ce 370};
3d9f0739 371
dcc2358f 372static const struct rtd_boardinfo rtd520Boards[] = {
b3322d42 373 [BOARD_DM7520] = {
3cdefc92 374 .name = "DM7520",
dcc2358f
HS
375 .range_bip10 = 6,
376 .range_uni10 = 12,
8a799460 377 .ai_range = &rtd_ai_7520_range,
b3322d42
HS
378 },
379 [BOARD_PCI4520] = {
3cdefc92 380 .name = "PCI4520",
dcc2358f
HS
381 .range_bip10 = 8,
382 .range_uni10 = 16,
8a799460 383 .ai_range = &rtd_ai_4520_range,
3cdefc92 384 },
3d9f0739
DC
385};
386
4686a0e6 387struct rtd_private {
3d9f0739 388 /* memory mapped board structures */
54fe68a8
HS
389 void __iomem *las0;
390 void __iomem *las1;
391 void __iomem *lcfg;
3d9f0739 392
8bc1bd1f 393 long ai_count; /* total transfer size (samples) */
2d7b8b94 394 int xfer_count; /* # to transfer data. 0->1/2FIFO */
3d9f0739
DC
395 int flags; /* flag event modes */
396
34db8ef9 397 unsigned char chan_is_bipolar[RTD_MAX_CHANLIST / 8]; /* bit array */
3d9f0739 398
d7c115ce 399 unsigned int ao_readback[2];
3d9f0739 400
cd5e2d06 401 unsigned fifosz;
d80235ce 402};
3d9f0739
DC
403
404/* bit defines for "flags" */
405#define SEND_EOS 0x01 /* send End Of Scan events */
406#define DMA0_ACTIVE 0x02 /* DMA0 is active */
407#define DMA1_ACTIVE 0x04 /* DMA1 is active */
408
409/* Macros for accessing channel list bit array */
8086fff8 410#define CHAN_ARRAY_TEST(array, index) \
3d9f0739 411 (((array)[(index)/8] >> ((index) & 0x7)) & 0x1)
8086fff8 412#define CHAN_ARRAY_SET(array, index) \
3d9f0739 413 (((array)[(index)/8] |= 1 << ((index) & 0x7)))
8086fff8 414#define CHAN_ARRAY_CLEAR(array, index) \
3d9f0739
DC
415 (((array)[(index)/8] &= ~(1 << ((index) & 0x7))))
416
5bb196ad 417/*
c98d90fd
HS
418 Given a desired period and the clock period (both in ns),
419 return the proper counter value (divider-1).
420 Sets the original period to be the true value.
421 Note: you have to check if the value is larger than the counter range!
422*/
3ff20ef3 423static int rtd_ns_to_timer_base(unsigned int *nanosec,
c98d90fd 424 int round_mode, int base)
3ff20ef3 425{
c98d90fd
HS
426 int divider;
427
428 switch (round_mode) {
429 case TRIG_ROUND_NEAREST:
430 default:
431 divider = (*nanosec + base / 2) / base;
432 break;
433 case TRIG_ROUND_DOWN:
434 divider = (*nanosec) / base;
435 break;
436 case TRIG_ROUND_UP:
437 divider = (*nanosec + base - 1) / base;
438 break;
439 }
440 if (divider < 2)
441 divider = 2; /* min is divide by 2 */
442
443 /* Note: we don't check for max, because different timers
444 have different ranges */
445
446 *nanosec = base * divider;
447 return divider - 1; /* countdown is divisor+1 */
448}
3d9f0739
DC
449
450/*
c98d90fd
HS
451 Given a desired period (in ns),
452 return the proper counter value (divider-1) for the internal clock.
453 Sets the original period to be the true value.
454*/
455static int rtd_ns_to_timer(unsigned int *ns, int round_mode)
456{
457 return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE);
458}
3d9f0739 459
c98d90fd
HS
460/*
461 Convert a single comedi channel-gain entry to a RTD520 table entry
462*/
b0ae4368
HS
463static unsigned short rtd_convert_chan_gain(struct comedi_device *dev,
464 unsigned int chanspec, int index)
465{
e9e7023c 466 const struct rtd_boardinfo *board = comedi_board(dev);
4686a0e6 467 struct rtd_private *devpriv = dev->private;
b0ae4368
HS
468 unsigned int chan = CR_CHAN(chanspec);
469 unsigned int range = CR_RANGE(chanspec);
470 unsigned int aref = CR_AREF(chanspec);
c98d90fd 471 unsigned short r = 0;
3d9f0739 472
c98d90fd 473 r |= chan & 0xf;
3d9f0739 474
c98d90fd 475 /* Note: we also setup the channel list bipolar flag array */
e9e7023c 476 if (range < board->range_bip10) {
3ff20ef3
HS
477 /* +-5 range */
478 r |= 0x000;
479 r |= (range & 0x7) << 4;
34db8ef9 480 CHAN_ARRAY_SET(devpriv->chan_is_bipolar, index);
e9e7023c 481 } else if (range < board->range_uni10) {
3ff20ef3
HS
482 /* +-10 range */
483 r |= 0x100;
e9e7023c 484 r |= ((range - board->range_bip10) & 0x7) << 4;
34db8ef9 485 CHAN_ARRAY_SET(devpriv->chan_is_bipolar, index);
3ff20ef3
HS
486 } else {
487 /* +10 range */
488 r |= 0x200;
e9e7023c 489 r |= ((range - board->range_uni10) & 0x7) << 4;
34db8ef9 490 CHAN_ARRAY_CLEAR(devpriv->chan_is_bipolar, index);
c98d90fd 491 }
3d9f0739 492
c98d90fd
HS
493 switch (aref) {
494 case AREF_GROUND: /* on-board ground */
495 break;
496
497 case AREF_COMMON:
498 r |= 0x80; /* ref external analog common */
499 break;
500
501 case AREF_DIFF:
502 r |= 0x400; /* differential inputs */
503 break;
504
505 case AREF_OTHER: /* ??? */
506 break;
507 }
508 /*printk ("chan=%d r=%d a=%d -> 0x%x\n",
509 chan, range, aref, r); */
510 return r;
511}
512
513/*
514 Setup the channel-gain table from a comedi list
515*/
516static void rtd_load_channelgain_list(struct comedi_device *dev,
517 unsigned int n_chan, unsigned int *list)
518{
4686a0e6 519 struct rtd_private *devpriv = dev->private;
f782a255 520
c98d90fd
HS
521 if (n_chan > 1) { /* setup channel gain table */
522 int ii;
67e50c6c
HS
523
524 writel(0, devpriv->las0 + LAS0_CGT_CLEAR);
cfe43ed9 525 writel(1, devpriv->las0 + LAS0_CGT_ENABLE);
c98d90fd 526 for (ii = 0; ii < n_chan; ii++) {
b0ae4368 527 writel(rtd_convert_chan_gain(dev, list[ii], ii),
3194c5e3 528 devpriv->las0 + LAS0_CGT_WRITE);
3d9f0739 529 }
c98d90fd 530 } else { /* just use the channel gain latch */
cfe43ed9 531 writel(0, devpriv->las0 + LAS0_CGT_ENABLE);
b0ae4368 532 writel(rtd_convert_chan_gain(dev, list[0], 0),
9b3f95cc 533 devpriv->las0 + LAS0_CGL_WRITE);
3d9f0739 534 }
c98d90fd
HS
535}
536
537/* determine fifo size by doing adc conversions until the fifo half
538empty status flag clears */
539static int rtd520_probe_fifo_depth(struct comedi_device *dev)
540{
4686a0e6 541 struct rtd_private *devpriv = dev->private;
c98d90fd
HS
542 unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND);
543 unsigned i;
544 static const unsigned limit = 0x2000;
545 unsigned fifo_size = 0;
546
aa5372b8 547 writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
c98d90fd 548 rtd_load_channelgain_list(dev, 1, &chanspec);
9a1f7223 549 /* ADC conversion trigger source: SOFTWARE */
99e3cfc2 550 writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
c98d90fd
HS
551 /* convert samples */
552 for (i = 0; i < limit; ++i) {
553 unsigned fifo_status;
554 /* trigger conversion */
02818bba 555 writew(0, devpriv->las0 + LAS0_ADC);
c98d90fd 556 udelay(1);
0eecf787 557 fifo_status = readl(devpriv->las0 + LAS0_ADC);
c98d90fd
HS
558 if ((fifo_status & FS_ADC_HEMPTY) == 0) {
559 fifo_size = 2 * i;
560 break;
3d9f0739 561 }
c98d90fd
HS
562 }
563 if (i == limit) {
4370e80f 564 dev_info(dev->class_dev, "failed to probe fifo size.\n");
3d9f0739
DC
565 return -EIO;
566 }
aa5372b8 567 writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
c98d90fd 568 if (fifo_size != 0x400 && fifo_size != 0x2000) {
4370e80f
YT
569 dev_info(dev->class_dev,
570 "unexpected fifo size of %i, expected 1024 or 8192.\n",
571 fifo_size);
c98d90fd 572 return -EIO;
3d9f0739 573 }
c98d90fd
HS
574 return fifo_size;
575}
3d9f0739 576
c98d90fd
HS
577/*
578 "instructions" read/write data in "one-shot" or "software-triggered"
579 mode (simplest case).
580 This doesn't use interrupts.
bc8bf90a 581
c98d90fd
HS
582 Note, we don't do any settling delays. Use a instruction list to
583 select, delay, then read.
584 */
585static int rtd_ai_rinsn(struct comedi_device *dev,
586 struct comedi_subdevice *s, struct comedi_insn *insn,
587 unsigned int *data)
588{
4686a0e6 589 struct rtd_private *devpriv = dev->private;
c98d90fd
HS
590 int n, ii;
591 int stat;
3d9f0739 592
c98d90fd 593 /* clear any old fifo data */
aa5372b8 594 writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
3d9f0739 595
c98d90fd
HS
596 /* write channel to multiplexer and clear channel gain table */
597 rtd_load_channelgain_list(dev, 1, &insn->chanspec);
3d9f0739 598
9a1f7223 599 /* ADC conversion trigger source: SOFTWARE */
99e3cfc2 600 writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
3d9f0739 601
c98d90fd
HS
602 /* convert n samples */
603 for (n = 0; n < insn->n; n++) {
604 s16 d;
605 /* trigger conversion */
02818bba 606 writew(0, devpriv->las0 + LAS0_ADC);
c98d90fd
HS
607
608 for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) {
0eecf787 609 stat = readl(devpriv->las0 + LAS0_ADC);
c98d90fd
HS
610 if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */
611 break;
612 WAIT_QUIETLY;
613 }
d62bc468 614 if (ii >= RTD_ADC_TIMEOUT)
c98d90fd 615 return -ETIMEDOUT;
c98d90fd
HS
616
617 /* read data */
d2e1aebe 618 d = readw(devpriv->las1 + LAS1_ADC_FIFO);
c98d90fd
HS
619 /*printk ("rtd520: Got 0x%x after %d usec\n", d, ii+1); */
620 d = d >> 3; /* low 3 bits are marker lines */
34db8ef9 621 if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar, 0))
c98d90fd
HS
622 /* convert to comedi unsigned data */
623 data[n] = d + 2048;
624 else
625 data[n] = d;
3d9f0739
DC
626 }
627
c98d90fd
HS
628 /* return the number of samples read/written */
629 return n;
630}
3d9f0739 631
c98d90fd
HS
632/*
633 Get what we know is there.... Fast!
634 This uses 1/2 the bus cycles of read_dregs (below).
bc8bf90a 635
c98d90fd
HS
636 The manual claims that we can do a lword read, but it doesn't work here.
637*/
638static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
639 int count)
640{
4686a0e6 641 struct rtd_private *devpriv = dev->private;
c98d90fd 642 int ii;
3d9f0739 643
c98d90fd
HS
644 for (ii = 0; ii < count; ii++) {
645 short sample;
646 s16 d;
bc8bf90a 647
8bc1bd1f 648 if (0 == devpriv->ai_count) { /* done */
d2e1aebe 649 d = readw(devpriv->las1 + LAS1_ADC_FIFO);
c98d90fd
HS
650 continue;
651 }
3d9f0739 652
5133f127 653 d = readw(devpriv->las1 + LAS1_ADC_FIFO);
c98d90fd 654 d = d >> 3; /* low 3 bits are marker lines */
34db8ef9
HS
655 if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar,
656 s->async->cur_chan)) {
c98d90fd
HS
657 /* convert to comedi unsigned data */
658 sample = d + 2048;
659 } else
660 sample = d;
3d9f0739 661
c98d90fd
HS
662 if (!comedi_buf_put(s->async, sample))
663 return -1;
3d9f0739 664
8bc1bd1f
HS
665 if (devpriv->ai_count > 0) /* < 0, means read forever */
666 devpriv->ai_count--;
c98d90fd
HS
667 }
668 return 0;
669}
3d9f0739 670
c98d90fd
HS
671/*
672 unknown amout of data is waiting in fifo.
673*/
674static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
675{
4686a0e6 676 struct rtd_private *devpriv = dev->private;
f782a255 677
0eecf787 678 while (readl(devpriv->las0 + LAS0_ADC) & FS_ADC_NOT_EMPTY) {
c98d90fd 679 short sample;
d2e1aebe 680 s16 d = readw(devpriv->las1 + LAS1_ADC_FIFO);
3d9f0739 681
8bc1bd1f 682 if (0 == devpriv->ai_count) { /* done */
c98d90fd
HS
683 continue; /* read rest */
684 }
197c82bf 685
c98d90fd 686 d = d >> 3; /* low 3 bits are marker lines */
34db8ef9
HS
687 if (CHAN_ARRAY_TEST(devpriv->chan_is_bipolar,
688 s->async->cur_chan)) {
c98d90fd
HS
689 /* convert to comedi unsigned data */
690 sample = d + 2048;
691 } else
692 sample = d;
3d9f0739 693
c98d90fd
HS
694 if (!comedi_buf_put(s->async, sample))
695 return -1;
bc8bf90a 696
8bc1bd1f
HS
697 if (devpriv->ai_count > 0) /* < 0, means read forever */
698 devpriv->ai_count--;
c98d90fd
HS
699 }
700 return 0;
701}
3d9f0739 702
c98d90fd
HS
703/*
704 Handle all rtd520 interrupts.
705 Runs atomically and is never re-entered.
706 This is a "slow handler"; other interrupts may be active.
707 The data conversion may someday happen in a "bottom half".
708*/
2f021034
HS
709static irqreturn_t rtd_interrupt(int irq, void *d)
710{
f782a255 711 struct comedi_device *dev = d;
58f20459 712 struct comedi_subdevice *s = &dev->subdevices[0];
4686a0e6 713 struct rtd_private *devpriv = dev->private;
4c977b86 714 u32 overrun;
c98d90fd 715 u16 status;
2f021034 716 u16 fifo_status;
bc8bf90a 717
c98d90fd
HS
718 if (!dev->attached)
719 return IRQ_NONE;
bc8bf90a 720
2f021034 721 fifo_status = readl(devpriv->las0 + LAS0_ADC);
c98d90fd 722 /* check for FIFO full, this automatically halts the ADC! */
2f021034
HS
723 if (!(fifo_status & FS_ADC_NOT_FULL)) /* 0 -> full */
724 goto xfer_abort;
c98d90fd 725
732941ad 726 status = readw(devpriv->las0 + LAS0_IT);
c98d90fd
HS
727 /* if interrupt was not caused by our board, or handled above */
728 if (0 == status)
729 return IRQ_HANDLED;
730
731 if (status & IRQM_ADC_ABOUT_CNT) { /* sample count -> read FIFO */
3ff20ef3
HS
732 /*
733 * since the priority interrupt controller may have queued
734 * a sample counter interrupt, even though we have already
735 * finished, we must handle the possibility that there is
736 * no data here
737 */
2f021034 738 if (!(fifo_status & FS_ADC_HEMPTY)) {
3ff20ef3 739 /* FIFO half full */
cd5e2d06 740 if (ai_read_n(dev, s, devpriv->fifosz / 2) < 0)
2f021034 741 goto xfer_abort;
d62bc468 742
8bc1bd1f 743 if (0 == devpriv->ai_count)
2f021034 744 goto xfer_done;
d62bc468 745
c98d90fd 746 comedi_event(dev, s);
2d7b8b94 747 } else if (devpriv->xfer_count > 0) {
2f021034 748 if (fifo_status & FS_ADC_NOT_EMPTY) {
3ff20ef3 749 /* FIFO not empty */
2d7b8b94 750 if (ai_read_n(dev, s, devpriv->xfer_count) < 0)
2f021034 751 goto xfer_abort;
d62bc468 752
8bc1bd1f 753 if (0 == devpriv->ai_count)
2f021034 754 goto xfer_done;
d62bc468 755
c98d90fd
HS
756 comedi_event(dev, s);
757 }
3d9f0739
DC
758 }
759 }
3d9f0739 760
4c977b86 761 overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
d62bc468 762 if (overrun)
2f021034 763 goto xfer_abort;
3d9f0739 764
c98d90fd 765 /* clear the interrupt */
dc49788d 766 writew(status, devpriv->las0 + LAS0_CLEAR);
a2b520b7 767 readw(devpriv->las0 + LAS0_CLEAR);
c98d90fd 768 return IRQ_HANDLED;
3d9f0739 769
2f021034 770xfer_abort:
aa5372b8 771 writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
c98d90fd 772 s->async->events |= COMEDI_CB_ERROR;
8bc1bd1f 773 devpriv->ai_count = 0; /* stop and don't transfer any more */
2f021034 774 /* fall into xfer_done */
3d9f0739 775
2f021034 776xfer_done:
9a1f7223 777 /* pacer stop source: SOFTWARE */
1d137eb4 778 writel(0, devpriv->las0 + LAS0_PACER_STOP);
9a1f7223 779 writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
99e3cfc2 780 writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
4541b381 781 writew(0, devpriv->las0 + LAS0_IT);
3d9f0739 782
8bc1bd1f 783 if (devpriv->ai_count > 0) { /* there shouldn't be anything left */
2f021034 784 fifo_status = readl(devpriv->las0 + LAS0_ADC);
c98d90fd
HS
785 ai_read_dregs(dev, s); /* read anything left in FIFO */
786 }
3d9f0739 787
c98d90fd
HS
788 s->async->events |= COMEDI_CB_EOA; /* signal end to comedi */
789 comedi_event(dev, s);
3d9f0739 790
c98d90fd 791 /* clear the interrupt */
732941ad 792 status = readw(devpriv->las0 + LAS0_IT);
dc49788d 793 writew(status, devpriv->las0 + LAS0_CLEAR);
a2b520b7 794 readw(devpriv->las0 + LAS0_CLEAR);
3d9f0739 795
2f021034 796 fifo_status = readl(devpriv->las0 + LAS0_ADC);
4c977b86 797 overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
c98d90fd
HS
798
799 return IRQ_HANDLED;
3d9f0739
DC
800}
801
c98d90fd
HS
802/*
803 cmdtest tests a particular command to see if it is valid.
804 Using the cmdtest ioctl, a user can create a valid cmd
bff6c3e0 805 and then have it executed by the cmd ioctl (asynchronously).
c98d90fd
HS
806
807 cmdtest returns 1,2,3,4 or 0, depending on which tests
808 the command passes.
809*/
810
811static int rtd_ai_cmdtest(struct comedi_device *dev,
812 struct comedi_subdevice *s, struct comedi_cmd *cmd)
3d9f0739 813{
c98d90fd
HS
814 int err = 0;
815 int tmp;
3d9f0739 816
27020ffe 817 /* Step 1 : check if triggers are trivially valid */
c98d90fd 818
27020ffe
HS
819 err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
820 err |= cfc_check_trigger_src(&cmd->scan_begin_src,
821 TRIG_TIMER | TRIG_EXT);
822 err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT);
823 err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
824 err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE);
c98d90fd
HS
825
826 if (err)
827 return 1;
828
27020ffe 829 /* Step 2a : make sure trigger sources are unique */
3d9f0739 830
27020ffe
HS
831 err |= cfc_check_trigger_is_unique(cmd->scan_begin_src);
832 err |= cfc_check_trigger_is_unique(cmd->convert_src);
833 err |= cfc_check_trigger_is_unique(cmd->stop_src);
834
835 /* Step 2b : and mutually compatible */
3d9f0739 836
c98d90fd
HS
837 if (err)
838 return 2;
3d9f0739 839
8a2b08ec 840 /* Step 3: check if arguments are trivially valid */
3d9f0739 841
8a2b08ec 842 err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
3d9f0739 843
c98d90fd
HS
844 if (cmd->scan_begin_src == TRIG_TIMER) {
845 /* Note: these are time periods, not actual rates */
846 if (1 == cmd->chanlist_len) { /* no scanning */
8a2b08ec
HS
847 if (cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
848 RTD_MAX_SPEED_1)) {
c98d90fd
HS
849 rtd_ns_to_timer(&cmd->scan_begin_arg,
850 TRIG_ROUND_UP);
8a2b08ec 851 err |= -EINVAL;
c98d90fd 852 }
8a2b08ec
HS
853 if (cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
854 RTD_MIN_SPEED_1)) {
c98d90fd
HS
855 rtd_ns_to_timer(&cmd->scan_begin_arg,
856 TRIG_ROUND_DOWN);
8a2b08ec 857 err |= -EINVAL;
c98d90fd
HS
858 }
859 } else {
8a2b08ec
HS
860 if (cfc_check_trigger_arg_min(&cmd->scan_begin_arg,
861 RTD_MAX_SPEED)) {
c98d90fd
HS
862 rtd_ns_to_timer(&cmd->scan_begin_arg,
863 TRIG_ROUND_UP);
8a2b08ec 864 err |= -EINVAL;
c98d90fd 865 }
8a2b08ec
HS
866 if (cfc_check_trigger_arg_max(&cmd->scan_begin_arg,
867 RTD_MIN_SPEED)) {
c98d90fd
HS
868 rtd_ns_to_timer(&cmd->scan_begin_arg,
869 TRIG_ROUND_DOWN);
8a2b08ec 870 err |= -EINVAL;
c98d90fd 871 }
3d9f0739 872 }
c98d90fd
HS
873 } else {
874 /* external trigger */
875 /* should be level/edge, hi/lo specification here */
876 /* should specify multiple external triggers */
8a2b08ec 877 err |= cfc_check_trigger_arg_max(&cmd->scan_begin_arg, 9);
c98d90fd 878 }
8a2b08ec 879
c98d90fd
HS
880 if (cmd->convert_src == TRIG_TIMER) {
881 if (1 == cmd->chanlist_len) { /* no scanning */
8a2b08ec
HS
882 if (cfc_check_trigger_arg_min(&cmd->convert_arg,
883 RTD_MAX_SPEED_1)) {
c98d90fd
HS
884 rtd_ns_to_timer(&cmd->convert_arg,
885 TRIG_ROUND_UP);
8a2b08ec 886 err |= -EINVAL;
c98d90fd 887 }
8a2b08ec
HS
888 if (cfc_check_trigger_arg_max(&cmd->convert_arg,
889 RTD_MIN_SPEED_1)) {
c98d90fd
HS
890 rtd_ns_to_timer(&cmd->convert_arg,
891 TRIG_ROUND_DOWN);
8a2b08ec 892 err |= -EINVAL;
c98d90fd
HS
893 }
894 } else {
8a2b08ec
HS
895 if (cfc_check_trigger_arg_min(&cmd->convert_arg,
896 RTD_MAX_SPEED)) {
c98d90fd
HS
897 rtd_ns_to_timer(&cmd->convert_arg,
898 TRIG_ROUND_UP);
8a2b08ec 899 err |= -EINVAL;
c98d90fd 900 }
8a2b08ec
HS
901 if (cfc_check_trigger_arg_max(&cmd->convert_arg,
902 RTD_MIN_SPEED)) {
c98d90fd
HS
903 rtd_ns_to_timer(&cmd->convert_arg,
904 TRIG_ROUND_DOWN);
8a2b08ec 905 err |= -EINVAL;
c98d90fd
HS
906 }
907 }
908 } else {
909 /* external trigger */
910 /* see above */
8a2b08ec 911 err |= cfc_check_trigger_arg_max(&cmd->convert_arg, 9);
c98d90fd
HS
912 }
913
c98d90fd
HS
914 if (cmd->stop_src == TRIG_COUNT) {
915 /* TODO check for rounding error due to counter wrap */
c98d90fd
HS
916 } else {
917 /* TRIG_NONE */
8a2b08ec 918 err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
c98d90fd 919 }
bc8bf90a 920
c98d90fd
HS
921 if (err)
922 return 3;
3d9f0739 923
c98d90fd
HS
924
925 /* step 4: fix up any arguments */
926
927 if (cmd->chanlist_len > RTD_MAX_CHANLIST) {
928 cmd->chanlist_len = RTD_MAX_CHANLIST;
929 err++;
3d9f0739 930 }
c98d90fd
HS
931 if (cmd->scan_begin_src == TRIG_TIMER) {
932 tmp = cmd->scan_begin_arg;
933 rtd_ns_to_timer(&cmd->scan_begin_arg,
934 cmd->flags & TRIG_ROUND_MASK);
935 if (tmp != cmd->scan_begin_arg)
936 err++;
3d9f0739 937
c98d90fd
HS
938 }
939 if (cmd->convert_src == TRIG_TIMER) {
940 tmp = cmd->convert_arg;
941 rtd_ns_to_timer(&cmd->convert_arg,
942 cmd->flags & TRIG_ROUND_MASK);
943 if (tmp != cmd->convert_arg)
944 err++;
3d9f0739 945
c98d90fd
HS
946 if (cmd->scan_begin_src == TRIG_TIMER
947 && (cmd->scan_begin_arg
948 < (cmd->convert_arg * cmd->scan_end_arg))) {
949 cmd->scan_begin_arg =
950 cmd->convert_arg * cmd->scan_end_arg;
951 err++;
3d9f0739 952 }
c98d90fd 953 }
3d9f0739 954
c98d90fd
HS
955 if (err)
956 return 4;
3d9f0739 957
3d9f0739
DC
958 return 0;
959}
960
3d9f0739 961/*
c98d90fd
HS
962 Execute a analog in command with many possible triggering options.
963 The data get stored in the async structure of the subdevice.
964 This is usually done by an interrupt handler.
965 Userland gets to the data using read calls.
3d9f0739 966*/
c98d90fd
HS
967static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
968{
4686a0e6 969 struct rtd_private *devpriv = dev->private;
c98d90fd
HS
970 struct comedi_cmd *cmd = &s->async->cmd;
971 int timer;
3d9f0739 972
c98d90fd 973 /* stop anything currently running */
9a1f7223 974 /* pacer stop source: SOFTWARE */
1d137eb4 975 writel(0, devpriv->las0 + LAS0_PACER_STOP);
9a1f7223 976 writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
99e3cfc2 977 writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
4541b381 978 writew(0, devpriv->las0 + LAS0_IT);
aa5372b8 979 writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
50b0d087 980 writel(0, devpriv->las0 + LAS0_OVERRUN);
3d9f0739 981
c98d90fd
HS
982 /* start configuration */
983 /* load channel list and reset CGT */
984 rtd_load_channelgain_list(dev, cmd->chanlist_len, cmd->chanlist);
3d9f0739 985
c98d90fd
HS
986 /* setup the common case and override if needed */
987 if (cmd->chanlist_len > 1) {
9a1f7223 988 /* pacer start source: SOFTWARE */
f6104e15 989 writel(0, devpriv->las0 + LAS0_PACER_START);
9a1f7223 990 /* burst trigger source: PACER */
7a3bbeb7 991 writel(1, devpriv->las0 + LAS0_BURST_START);
9a1f7223 992 /* ADC conversion trigger source: BURST */
99e3cfc2 993 writel(2, devpriv->las0 + LAS0_ADC_CONVERSION);
c98d90fd 994 } else { /* single channel */
9a1f7223 995 /* pacer start source: SOFTWARE */
f6104e15 996 writel(0, devpriv->las0 + LAS0_PACER_START);
9a1f7223 997 /* ADC conversion trigger source: PACER */
99e3cfc2 998 writel(1, devpriv->las0 + LAS0_ADC_CONVERSION);
3d9f0739 999 }
cd5e2d06 1000 writel((devpriv->fifosz / 2 - 1) & 0xffff, devpriv->las0 + LAS0_ACNT);
c98d90fd
HS
1001
1002 if (TRIG_TIMER == cmd->scan_begin_src) {
1003 /* scan_begin_arg is in nanoseconds */
1004 /* find out how many samples to wait before transferring */
1005 if (cmd->flags & TRIG_WAKE_EOS) {
3ff20ef3
HS
1006 /*
1007 * this may generate un-sustainable interrupt rates
1008 * the application is responsible for doing the
1009 * right thing
1010 */
2d7b8b94 1011 devpriv->xfer_count = cmd->chanlist_len;
c98d90fd
HS
1012 devpriv->flags |= SEND_EOS;
1013 } else {
1014 /* arrange to transfer data periodically */
2d7b8b94 1015 devpriv->xfer_count =
c98d90fd
HS
1016 (TRANS_TARGET_PERIOD * cmd->chanlist_len) /
1017 cmd->scan_begin_arg;
2d7b8b94 1018 if (devpriv->xfer_count < cmd->chanlist_len) {
c98d90fd 1019 /* transfer after each scan (and avoid 0) */
2d7b8b94 1020 devpriv->xfer_count = cmd->chanlist_len;
c98d90fd 1021 } else { /* make a multiple of scan length */
2d7b8b94
HS
1022 devpriv->xfer_count =
1023 (devpriv->xfer_count +
c98d90fd
HS
1024 cmd->chanlist_len - 1)
1025 / cmd->chanlist_len;
2d7b8b94 1026 devpriv->xfer_count *= cmd->chanlist_len;
c98d90fd
HS
1027 }
1028 devpriv->flags |= SEND_EOS;
1029 }
cd5e2d06 1030 if (devpriv->xfer_count >= (devpriv->fifosz / 2)) {
c98d90fd 1031 /* out of counter range, use 1/2 fifo instead */
2d7b8b94 1032 devpriv->xfer_count = 0;
c98d90fd
HS
1033 devpriv->flags &= ~SEND_EOS;
1034 } else {
1035 /* interrupt for each transfer */
2d7b8b94 1036 writel((devpriv->xfer_count - 1) & 0xffff,
06bc659c 1037 devpriv->las0 + LAS0_ACNT);
c98d90fd 1038 }
c98d90fd 1039 } else { /* unknown timing, just use 1/2 FIFO */
2d7b8b94 1040 devpriv->xfer_count = 0;
c98d90fd 1041 devpriv->flags &= ~SEND_EOS;
3d9f0739 1042 }
9a1f7223 1043 /* pacer clock source: INTERNAL 8MHz */
896a64dd 1044 writel(1, devpriv->las0 + LAS0_PACER_SELECT);
9a1f7223 1045 /* just interrupt, don't stop */
dcfbb64c 1046 writel(1, devpriv->las0 + LAS0_ACNT_STOP_ENABLE);
3d9f0739 1047
c98d90fd 1048 /* BUG??? these look like enumerated values, but they are bit fields */
3d9f0739 1049
c98d90fd
HS
1050 /* First, setup when to stop */
1051 switch (cmd->stop_src) {
1052 case TRIG_COUNT: /* stop after N scans */
8bc1bd1f 1053 devpriv->ai_count = cmd->stop_arg * cmd->chanlist_len;
2d7b8b94 1054 if ((devpriv->xfer_count > 0)
8bc1bd1f
HS
1055 && (devpriv->xfer_count > devpriv->ai_count)) {
1056 devpriv->xfer_count = devpriv->ai_count;
c98d90fd
HS
1057 }
1058 break;
3d9f0739 1059
c98d90fd 1060 case TRIG_NONE: /* stop when cancel is called */
8bc1bd1f 1061 devpriv->ai_count = -1; /* read forever */
c98d90fd 1062 break;
c98d90fd
HS
1063 }
1064
1065 /* Scan timing */
1066 switch (cmd->scan_begin_src) {
1067 case TRIG_TIMER: /* periodic scanning */
1068 timer = rtd_ns_to_timer(&cmd->scan_begin_arg,
1069 TRIG_ROUND_NEAREST);
1070 /* set PACER clock */
5b8b384d 1071 writel(timer & 0xffffff, devpriv->las0 + LAS0_PCLK);
3d9f0739 1072
c98d90fd 1073 break;
bc8bf90a 1074
c98d90fd 1075 case TRIG_EXT:
9a1f7223 1076 /* pacer start source: EXTERNAL */
f6104e15 1077 writel(1, devpriv->las0 + LAS0_PACER_START);
c98d90fd 1078 break;
c98d90fd 1079 }
3d9f0739 1080
c98d90fd
HS
1081 /* Sample timing within a scan */
1082 switch (cmd->convert_src) {
1083 case TRIG_TIMER: /* periodic */
3ff20ef3
HS
1084 if (cmd->chanlist_len > 1) {
1085 /* only needed for multi-channel */
c98d90fd
HS
1086 timer = rtd_ns_to_timer(&cmd->convert_arg,
1087 TRIG_ROUND_NEAREST);
1088 /* setup BURST clock */
3c4aaead 1089 writel(timer & 0x3ff, devpriv->las0 + LAS0_BCLK);
3d9f0739 1090 }
3d9f0739 1091
c98d90fd 1092 break;
3d9f0739 1093
c98d90fd 1094 case TRIG_EXT: /* external */
9a1f7223 1095 /* burst trigger source: EXTERNAL */
7a3bbeb7 1096 writel(2, devpriv->las0 + LAS0_BURST_START);
c98d90fd 1097 break;
3d9f0739 1098 }
c98d90fd 1099 /* end configuration */
3d9f0739 1100
c98d90fd
HS
1101 /* This doesn't seem to work. There is no way to clear an interrupt
1102 that the priority controller has queued! */
dc49788d 1103 writew(~0, devpriv->las0 + LAS0_CLEAR);
a2b520b7 1104 readw(devpriv->las0 + LAS0_CLEAR);
3d9f0739 1105
c98d90fd 1106 /* TODO: allow multiple interrupt sources */
2d7b8b94 1107 if (devpriv->xfer_count > 0) { /* transfer every N samples */
4541b381 1108 writew(IRQM_ADC_ABOUT_CNT, devpriv->las0 + LAS0_IT);
c98d90fd 1109 } else { /* 1/2 FIFO transfers */
4541b381 1110 writew(IRQM_ADC_ABOUT_CNT, devpriv->las0 + LAS0_IT);
3d9f0739
DC
1111 }
1112
c98d90fd
HS
1113 /* BUG: start_src is ASSUMED to be TRIG_NOW */
1114 /* BUG? it seems like things are running before the "start" */
9a1f7223 1115 readl(devpriv->las0 + LAS0_PACER); /* start pacer */
c98d90fd
HS
1116 return 0;
1117}
3d9f0739 1118
c98d90fd
HS
1119/*
1120 Stop a running data acquisition.
1121*/
1122static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
1123{
4686a0e6 1124 struct rtd_private *devpriv = dev->private;
4c977b86 1125 u32 overrun;
c98d90fd 1126 u16 status;
3d9f0739 1127
9a1f7223 1128 /* pacer stop source: SOFTWARE */
1d137eb4 1129 writel(0, devpriv->las0 + LAS0_PACER_STOP);
9a1f7223 1130 writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
99e3cfc2 1131 writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
4541b381 1132 writew(0, devpriv->las0 + LAS0_IT);
8bc1bd1f 1133 devpriv->ai_count = 0; /* stop and don't transfer any more */
732941ad 1134 status = readw(devpriv->las0 + LAS0_IT);
4c977b86 1135 overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
c98d90fd 1136 return 0;
3d9f0739 1137}
3d9f0739
DC
1138
1139/*
c98d90fd 1140 Output one (or more) analog values to a single port as fast as possible.
3d9f0739 1141*/
c98d90fd
HS
1142static int rtd_ao_winsn(struct comedi_device *dev,
1143 struct comedi_subdevice *s, struct comedi_insn *insn,
1144 unsigned int *data)
3d9f0739 1145{
4686a0e6 1146 struct rtd_private *devpriv = dev->private;
c98d90fd
HS
1147 int i;
1148 int chan = CR_CHAN(insn->chanspec);
1149 int range = CR_RANGE(insn->chanspec);
bc8bf90a 1150
c98d90fd 1151 /* Configure the output range (table index matches the range values) */
9db311d1
HS
1152 writew(range & 7, devpriv->las0 +
1153 ((chan == 0) ? LAS0_DAC1_CTRL : LAS0_DAC2_CTRL));
3d9f0739 1154
c98d90fd
HS
1155 /* Writing a list of values to an AO channel is probably not
1156 * very useful, but that's how the interface is defined. */
1157 for (i = 0; i < insn->n; ++i) {
1158 int val = data[i] << 3;
1159 int stat = 0; /* initialize to avoid bogus warning */
1160 int ii;
3d9f0739 1161
c98d90fd 1162 /* VERIFY: comedi range and offset conversions */
bc8bf90a 1163
c98d90fd
HS
1164 if ((range > 1) /* bipolar */
1165 && (data[i] < 2048)) {
1166 /* offset and sign extend */
1167 val = (((int)data[i]) - 2048) << 3;
1168 } else { /* unipolor */
1169 val = data[i] << 3;
1170 }
3d9f0739 1171
c98d90fd 1172 /* a typical programming sequence */
5f73c718
HS
1173 writew(val, devpriv->las1 +
1174 ((chan == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO));
3ff20ef3
HS
1175 writew(0, devpriv->las0 +
1176 ((chan == 0) ? LAS0_DAC1 : LAS0_DAC2));
3d9f0739 1177
d7c115ce 1178 devpriv->ao_readback[chan] = data[i];
3d9f0739 1179
c98d90fd 1180 for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
0eecf787 1181 stat = readl(devpriv->las0 + LAS0_ADC);
c98d90fd
HS
1182 /* 1 -> not empty */
1183 if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY :
1184 FS_DAC2_NOT_EMPTY))
1185 break;
1186 WAIT_QUIETLY;
3d9f0739 1187 }
d62bc468 1188 if (ii >= RTD_DAC_TIMEOUT)
c98d90fd 1189 return -ETIMEDOUT;
3d9f0739
DC
1190 }
1191
c98d90fd
HS
1192 /* return the number of samples read/written */
1193 return i;
1194}
3d9f0739 1195
c98d90fd
HS
1196/* AO subdevices should have a read insn as well as a write insn.
1197 * Usually this means copying a value stored in devpriv. */
1198static int rtd_ao_rinsn(struct comedi_device *dev,
1199 struct comedi_subdevice *s, struct comedi_insn *insn,
1200 unsigned int *data)
1201{
4686a0e6 1202 struct rtd_private *devpriv = dev->private;
c98d90fd
HS
1203 int i;
1204 int chan = CR_CHAN(insn->chanspec);
3d9f0739 1205
c98d90fd 1206 for (i = 0; i < insn->n; i++)
d7c115ce 1207 data[i] = devpriv->ao_readback[chan];
bc8bf90a 1208
3d9f0739 1209
c98d90fd
HS
1210 return i;
1211}
3d9f0739 1212
c98d90fd
HS
1213static int rtd_dio_insn_bits(struct comedi_device *dev,
1214 struct comedi_subdevice *s,
45b6937a
HS
1215 struct comedi_insn *insn,
1216 unsigned int *data)
c98d90fd 1217{
4686a0e6 1218 struct rtd_private *devpriv = dev->private;
45b6937a
HS
1219 unsigned int mask = data[0];
1220 unsigned int bits = data[1];
f782a255 1221
45b6937a
HS
1222 if (mask) {
1223 s->state &= ~mask;
1224 s->state |= (bits & mask);
c98d90fd 1225
e91403b2 1226 writew(s->state & 0xff, devpriv->las0 + LAS0_DIO0);
3d9f0739 1227 }
45b6937a 1228
2b6e6b80 1229 data[1] = readw(devpriv->las0 + LAS0_DIO0) & 0xff;
3d9f0739 1230
a2714e3e 1231 return insn->n;
3d9f0739
DC
1232}
1233
c98d90fd
HS
1234static int rtd_dio_insn_config(struct comedi_device *dev,
1235 struct comedi_subdevice *s,
efa5b326
HS
1236 struct comedi_insn *insn,
1237 unsigned int *data)
3d9f0739 1238{
4686a0e6 1239 struct rtd_private *devpriv = dev->private;
efa5b326
HS
1240 unsigned int chan = CR_CHAN(insn->chanspec);
1241 unsigned int mask = 1 << chan;
3d9f0739 1242
c98d90fd
HS
1243 switch (data[0]) {
1244 case INSN_CONFIG_DIO_OUTPUT:
efa5b326 1245 s->io_bits |= mask;
c98d90fd
HS
1246 break;
1247 case INSN_CONFIG_DIO_INPUT:
efa5b326 1248 s->io_bits &= ~mask;
c98d90fd
HS
1249 break;
1250 case INSN_CONFIG_DIO_QUERY:
efa5b326 1251 data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT;
c98d90fd
HS
1252 return insn->n;
1253 break;
1254 default:
1255 return -EINVAL;
3d9f0739 1256 }
3d9f0739 1257
c98d90fd 1258 /* TODO support digital match interrupts and strobes */
360235af
HS
1259
1260 /* set direction */
1261 writew(0x01, devpriv->las0 + LAS0_DIO_STATUS);
b0c375a3 1262 writew(s->io_bits & 0xff, devpriv->las0 + LAS0_DIO0_CTRL);
360235af
HS
1263
1264 /* clear interrupts */
1265 writew(0x00, devpriv->las0 + LAS0_DIO_STATUS);
3d9f0739 1266
c98d90fd 1267 /* port1 can only be all input or all output */
3d9f0739 1268
c98d90fd 1269 /* there are also 2 user input lines and 2 user output lines */
3d9f0739 1270
efa5b326 1271 return insn->n;
c98d90fd 1272}
3d9f0739 1273
09d93a18 1274static void rtd_reset(struct comedi_device *dev)
b155c5fa 1275{
4686a0e6 1276 struct rtd_private *devpriv = dev->private;
b155c5fa 1277
b155c5fa
HS
1278 writel(0, devpriv->las0 + LAS0_BOARD_RESET);
1279 udelay(100); /* needed? */
2fb0e849 1280 writel(0, devpriv->lcfg + PLX_INTRCS_REG);
4541b381 1281 writew(0, devpriv->las0 + LAS0_IT);
dc49788d 1282 writew(~0, devpriv->las0 + LAS0_CLEAR);
b155c5fa 1283 readw(devpriv->las0 + LAS0_CLEAR);
09d93a18
HS
1284}
1285
1286/*
1287 * initialize board, per RTD spec
1288 * also, initialize shadow registers
1289 */
1290static void rtd_init_board(struct comedi_device *dev)
1291{
4686a0e6 1292 struct rtd_private *devpriv = dev->private;
09d93a18
HS
1293
1294 rtd_reset(dev);
1295
b155c5fa
HS
1296 writel(0, devpriv->las0 + LAS0_OVERRUN);
1297 writel(0, devpriv->las0 + LAS0_CGT_CLEAR);
1298 writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
1299 writel(0, devpriv->las0 + LAS0_DAC1_RESET);
1300 writel(0, devpriv->las0 + LAS0_DAC2_RESET);
1301 /* clear digital IO fifo */
360235af 1302 writew(0, devpriv->las0 + LAS0_DIO_STATUS);
2cc71f04
HS
1303 writeb((0 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL);
1304 writeb((1 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL);
1305 writeb((2 << 6) | 0x30, devpriv->las0 + LAS0_UTC_CTRL);
1306 writeb((3 << 6) | 0x00, devpriv->las0 + LAS0_UTC_CTRL);
b155c5fa
HS
1307 /* TODO: set user out source ??? */
1308}
1309
3d7e4416
HS
1310/* The RTD driver does this */
1311static void rtd_pci_latency_quirk(struct comedi_device *dev,
1312 struct pci_dev *pcidev)
1313{
1314 unsigned char pci_latency;
3d7e4416
HS
1315
1316 pci_read_config_byte(pcidev, PCI_LATENCY_TIMER, &pci_latency);
1317 if (pci_latency < 32) {
1318 dev_info(dev->class_dev,
1319 "PCI latency changed from %d to %d\n",
1320 pci_latency, 32);
1321 pci_write_config_byte(pcidev, PCI_LATENCY_TIMER, 32);
3d7e4416 1322 }
3d7e4416
HS
1323}
1324
a690b7e5 1325static int rtd_auto_attach(struct comedi_device *dev,
b3322d42 1326 unsigned long context)
825ca08e 1327{
5df39540 1328 struct pci_dev *pcidev = comedi_to_pci_dev(dev);
e9e7023c 1329 const struct rtd_boardinfo *board = NULL;
4686a0e6 1330 struct rtd_private *devpriv;
c98d90fd 1331 struct comedi_subdevice *s;
c98d90fd 1332 int ret;
3d9f0739 1333
b3322d42 1334 if (context < ARRAY_SIZE(rtd520Boards))
e9e7023c
HS
1335 board = &rtd520Boards[context];
1336 if (!board)
825ca08e 1337 return -ENODEV;
e9e7023c
HS
1338 dev->board_ptr = board;
1339 dev->board_name = board->name;
825ca08e 1340
0bdab509 1341 devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
c34fa261
HS
1342 if (!devpriv)
1343 return -ENOMEM;
3d9f0739 1344
818f569f 1345 ret = comedi_pci_enable(dev);
edecbd06 1346 if (ret)
c98d90fd 1347 return ret;
a26f4dd0 1348
dde4196e
HS
1349 devpriv->las0 = pci_ioremap_bar(pcidev, 2);
1350 devpriv->las1 = pci_ioremap_bar(pcidev, 3);
1351 devpriv->lcfg = pci_ioremap_bar(pcidev, 0);
c98d90fd
HS
1352 if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
1353 return -ENOMEM;
3d9f0739 1354
3d7e4416 1355 rtd_pci_latency_quirk(dev, pcidev);
3d9f0739 1356
90973498
HS
1357 if (pcidev->irq) {
1358 ret = request_irq(pcidev->irq, rtd_interrupt, IRQF_SHARED,
1359 dev->board_name, dev);
1360 if (ret == 0)
1361 dev->irq = pcidev->irq;
1362 }
1363
8b6c5694
HS
1364 ret = comedi_alloc_subdevices(dev, 4);
1365 if (ret)
1366 return ret;
3d9f0739 1367
58f20459 1368 s = &dev->subdevices[0];
c98d90fd 1369 /* analog input subdevice */
37f97e50
HS
1370 s->type = COMEDI_SUBD_AI;
1371 s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF;
1372 s->n_chan = 16;
1373 s->maxdata = 0x0fff;
e9e7023c 1374 s->range_table = board->ai_range;
37f97e50
HS
1375 s->len_chanlist = RTD_MAX_CHANLIST;
1376 s->insn_read = rtd_ai_rinsn;
90973498
HS
1377 if (dev->irq) {
1378 dev->read_subdev = s;
37f97e50
HS
1379 s->subdev_flags |= SDF_CMD_READ;
1380 s->do_cmd = rtd_ai_cmd;
1381 s->do_cmdtest = rtd_ai_cmdtest;
1382 s->cancel = rtd_ai_cancel;
90973498 1383 }
3d9f0739 1384
58f20459 1385 s = &dev->subdevices[1];
c98d90fd 1386 /* analog output subdevice */
37f97e50
HS
1387 s->type = COMEDI_SUBD_AO;
1388 s->subdev_flags = SDF_WRITABLE;
1389 s->n_chan = 2;
1390 s->maxdata = 0x0fff;
1391 s->range_table = &rtd_ao_range;
1392 s->insn_write = rtd_ao_winsn;
1393 s->insn_read = rtd_ao_rinsn;
3d9f0739 1394
58f20459 1395 s = &dev->subdevices[2];
c98d90fd 1396 /* digital i/o subdevice */
37f97e50
HS
1397 s->type = COMEDI_SUBD_DIO;
1398 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
c98d90fd 1399 /* we only support port 0 right now. Ignoring port 1 and user IO */
37f97e50
HS
1400 s->n_chan = 8;
1401 s->maxdata = 1;
1402 s->range_table = &range_digital;
1403 s->insn_bits = rtd_dio_insn_bits;
1404 s->insn_config = rtd_dio_insn_config;
3d9f0739 1405
c98d90fd 1406 /* timer/counter subdevices (not currently supported) */
58f20459 1407 s = &dev->subdevices[3];
37f97e50
HS
1408 s->type = COMEDI_SUBD_COUNTER;
1409 s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
1410 s->n_chan = 3;
1411 s->maxdata = 0xffff;
3d9f0739 1412
b155c5fa 1413 rtd_init_board(dev);
3d9f0739 1414
c98d90fd
HS
1415 ret = rtd520_probe_fifo_depth(dev);
1416 if (ret < 0)
1417 return ret;
cd5e2d06 1418 devpriv->fifosz = ret;
c98d90fd 1419
a5ca9475 1420 if (dev->irq)
2fb0e849 1421 writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + PLX_INTRCS_REG);
bc8bf90a 1422
edecbd06 1423 dev_info(dev->class_dev, "%s attached\n", dev->board_name);
3d9f0739 1424
edecbd06 1425 return 0;
3d9f0739
DC
1426}
1427
c98d90fd 1428static void rtd_detach(struct comedi_device *dev)
3d9f0739 1429{
4686a0e6 1430 struct rtd_private *devpriv = dev->private;
3d9f0739 1431
c98d90fd
HS
1432 if (devpriv) {
1433 /* Shut down any board ops by resetting it */
09d93a18
HS
1434 if (devpriv->las0 && devpriv->lcfg)
1435 rtd_reset(dev);
c98d90fd 1436 if (dev->irq) {
2fb0e849 1437 writel(readl(devpriv->lcfg + PLX_INTRCS_REG) &
a5ca9475 1438 ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E),
2fb0e849 1439 devpriv->lcfg + PLX_INTRCS_REG);
c98d90fd
HS
1440 free_irq(dev->irq, dev);
1441 }
1442 if (devpriv->las0)
1443 iounmap(devpriv->las0);
1444 if (devpriv->las1)
1445 iounmap(devpriv->las1);
1446 if (devpriv->lcfg)
1447 iounmap(devpriv->lcfg);
843c042d 1448 }
7f072f54 1449 comedi_pci_disable(dev);
3d9f0739
DC
1450}
1451
75e6301b
HS
1452static struct comedi_driver rtd520_driver = {
1453 .driver_name = "rtd520",
6beb8160 1454 .module = THIS_MODULE,
5df39540 1455 .auto_attach = rtd_auto_attach,
6beb8160
HS
1456 .detach = rtd_detach,
1457};
1458
a690b7e5 1459static int rtd520_pci_probe(struct pci_dev *dev,
b8f4ac23 1460 const struct pci_device_id *id)
727b286b 1461{
b8f4ac23 1462 return comedi_pci_auto_config(dev, &rtd520_driver, id->driver_data);
727b286b
AT
1463}
1464
6beb8160 1465static DEFINE_PCI_DEVICE_TABLE(rtd520_pci_table) = {
b3322d42
HS
1466 { PCI_VDEVICE(RTD, 0x7520), BOARD_DM7520 },
1467 { PCI_VDEVICE(RTD, 0x4520), BOARD_PCI4520 },
6beb8160
HS
1468 { 0 }
1469};
1470MODULE_DEVICE_TABLE(pci, rtd520_pci_table);
1471
75e6301b
HS
1472static struct pci_driver rtd520_pci_driver = {
1473 .name = "rtd520",
6beb8160 1474 .id_table = rtd520_pci_table,
75e6301b 1475 .probe = rtd520_pci_probe,
9901a4d7 1476 .remove = comedi_pci_auto_unconfig,
727b286b 1477};
75e6301b 1478module_comedi_pci_driver(rtd520_driver, rtd520_pci_driver);
90f703d3
AT
1479
1480MODULE_AUTHOR("Comedi http://www.comedi.org");
1481MODULE_DESCRIPTION("Comedi low-level driver");
1482MODULE_LICENSE("GPL");