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