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