summaryrefslogtreecommitdiffstats
path: root/drivers/staging/comedi/drivers/rtd520.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/comedi/drivers/rtd520.c')
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c1667
1 files changed, 655 insertions, 1012 deletions
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 1678a0ccb8c1..112fdc3e9c69 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -105,7 +105,6 @@ Configuration options:
#include <linux/delay.h>
#include "../comedidev.h"
-#include "comedi_pci.h"
#define DRV_NAME "rtd520"
@@ -195,110 +194,79 @@ Configuration options:
======================================================================*/
/*
- The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128)
-*/
-static const struct comedi_lrange rtd_ai_7520_range = { 18, {
- /* +-5V input range gain steps */
- BIP_RANGE(5.0),
- BIP_RANGE(5.0 / 2),
- BIP_RANGE(5.0 / 4),
- BIP_RANGE(5.0 / 8),
- BIP_RANGE(5.0 /
- 16),
- BIP_RANGE(5.0 /
- 32),
- /* +-10V input range gain steps */
- BIP_RANGE(10.0),
- BIP_RANGE(10.0 /
- 2),
- BIP_RANGE(10.0 /
- 4),
- BIP_RANGE(10.0 /
- 8),
- BIP_RANGE(10.0 /
- 16),
- BIP_RANGE(10.0 /
- 32),
- /* +10V input range gain steps */
- UNI_RANGE(10.0),
- UNI_RANGE(10.0 /
- 2),
- UNI_RANGE(10.0 /
- 4),
- UNI_RANGE(10.0 /
- 8),
- UNI_RANGE(10.0 /
- 16),
- UNI_RANGE(10.0 /
- 32),
-
- }
+ * The board has 3 input modes and the gains of 1,2,4,...32 (, 64, 128)
+ */
+static const struct comedi_lrange rtd_ai_7520_range = {
+ 18, {
+ /* +-5V input range gain steps */
+ BIP_RANGE(5.0),
+ BIP_RANGE(5.0 / 2),
+ BIP_RANGE(5.0 / 4),
+ BIP_RANGE(5.0 / 8),
+ BIP_RANGE(5.0 / 16),
+ BIP_RANGE(5.0 / 32),
+ /* +-10V input range gain steps */
+ BIP_RANGE(10.0),
+ BIP_RANGE(10.0 / 2),
+ BIP_RANGE(10.0 / 4),
+ BIP_RANGE(10.0 / 8),
+ BIP_RANGE(10.0 / 16),
+ BIP_RANGE(10.0 / 32),
+ /* +10V input range gain steps */
+ UNI_RANGE(10.0),
+ UNI_RANGE(10.0 / 2),
+ UNI_RANGE(10.0 / 4),
+ UNI_RANGE(10.0 / 8),
+ UNI_RANGE(10.0 / 16),
+ UNI_RANGE(10.0 / 32),
+ }
};
/* PCI4520 has two more gains (6 more entries) */
-static const struct comedi_lrange rtd_ai_4520_range = { 24, {
- /* +-5V input range gain steps */
- BIP_RANGE(5.0),
- BIP_RANGE(5.0 / 2),
- BIP_RANGE(5.0 / 4),
- BIP_RANGE(5.0 / 8),
- BIP_RANGE(5.0 /
- 16),
- BIP_RANGE(5.0 /
- 32),
- BIP_RANGE(5.0 /
- 64),
- BIP_RANGE(5.0 /
- 128),
- /* +-10V input range gain steps */
- BIP_RANGE(10.0),
- BIP_RANGE(10.0 /
- 2),
- BIP_RANGE(10.0 /
- 4),
- BIP_RANGE(10.0 /
- 8),
- BIP_RANGE(10.0 /
- 16),
- BIP_RANGE(10.0 /
- 32),
- BIP_RANGE(10.0 /
- 64),
- BIP_RANGE(10.0 /
- 128),
- /* +10V input range gain steps */
- UNI_RANGE(10.0),
- UNI_RANGE(10.0 /
- 2),
- UNI_RANGE(10.0 /
- 4),
- UNI_RANGE(10.0 /
- 8),
- UNI_RANGE(10.0 /
- 16),
- UNI_RANGE(10.0 /
- 32),
- UNI_RANGE(10.0 /
- 64),
- UNI_RANGE(10.0 /
- 128),
- }
+static const struct comedi_lrange rtd_ai_4520_range = {
+ 24, {
+ /* +-5V input range gain steps */
+ BIP_RANGE(5.0),
+ BIP_RANGE(5.0 / 2),
+ BIP_RANGE(5.0 / 4),
+ BIP_RANGE(5.0 / 8),
+ BIP_RANGE(5.0 / 16),
+ BIP_RANGE(5.0 / 32),
+ BIP_RANGE(5.0 / 64),
+ BIP_RANGE(5.0 / 128),
+ /* +-10V input range gain steps */
+ BIP_RANGE(10.0),
+ BIP_RANGE(10.0 / 2),
+ BIP_RANGE(10.0 / 4),
+ BIP_RANGE(10.0 / 8),
+ BIP_RANGE(10.0 / 16),
+ BIP_RANGE(10.0 / 32),
+ BIP_RANGE(10.0 / 64),
+ BIP_RANGE(10.0 / 128),
+ /* +10V input range gain steps */
+ UNI_RANGE(10.0),
+ UNI_RANGE(10.0 / 2),
+ UNI_RANGE(10.0 / 4),
+ UNI_RANGE(10.0 / 8),
+ UNI_RANGE(10.0 / 16),
+ UNI_RANGE(10.0 / 32),
+ UNI_RANGE(10.0 / 64),
+ UNI_RANGE(10.0 / 128),
+ }
};
/* Table order matches range values */
-static const struct comedi_lrange rtd_ao_range = { 4, {
- RANGE(0, 5),
- RANGE(0, 10),
- RANGE(-5, 5),
- RANGE(-10, 10),
- }
+static const struct comedi_lrange rtd_ao_range = {
+ 4, {
+ UNI_RANGE(5),
+ UNI_RANGE(10),
+ BIP_RANGE(5),
+ BIP_RANGE(10),
+ }
};
-/*
- Board descriptions
- */
struct rtdBoard {
- const char *name; /* must be first */
+ const char *name;
int device_id;
int aiChans;
int aiBits;
@@ -309,31 +277,25 @@ struct rtdBoard {
static const struct rtdBoard rtd520Boards[] = {
{
- .name = "DM7520",
- .device_id = 0x7520,
- .aiChans = 16,
- .aiBits = 12,
- .aiMaxGain = 32,
- .range10Start = 6,
- .rangeUniStart = 12,
- },
- {
- .name = "PCI4520",
- .device_id = 0x4520,
- .aiChans = 16,
- .aiBits = 12,
- .aiMaxGain = 128,
- .range10Start = 8,
- .rangeUniStart = 16,
- },
+ .name = "DM7520",
+ .device_id = 0x7520,
+ .aiChans = 16,
+ .aiBits = 12,
+ .aiMaxGain = 32,
+ .range10Start = 6,
+ .rangeUniStart = 12,
+ }, {
+ .name = "PCI4520",
+ .device_id = 0x4520,
+ .aiChans = 16,
+ .aiBits = 12,
+ .aiMaxGain = 128,
+ .range10Start = 8,
+ .rangeUniStart = 16,
+ },
};
/*
- * Useful for shorthand access to the particular board structure
- */
-#define thisboard ((const struct rtdBoard *)dev->board_ptr)
-
-/*
This structure is for data unique to this hardware driver.
This is also unique for each board in the system.
*/
@@ -348,10 +310,6 @@ struct rtdPrivate {
int transCount; /* # to transfer data. 0->1/2FIFO */
int flags; /* flag event modes */
- /* PCI device info */
- struct pci_dev *pci_dev;
- int got_regions; /* non-zero if PCI regions owned */
-
/* channel list info */
/* chanBipolar tracks whether a channel is bipolar (and needs +2048) */
unsigned char chanBipolar[RTD_MAX_CHANLIST / 8]; /* bit array */
@@ -400,747 +358,46 @@ struct rtdPrivate {
(((array)[(index)/8] &= ~(1 << ((index) & 0x7))))
/*
- * most drivers define the following macro to make it easy to
- * access the private structure.
- */
-#define devpriv ((struct rtdPrivate *)dev->private)
-
-/* Macros to access registers */
-
-/* Reset board */
-#define RtdResetBoard(dev) \
- writel(0, devpriv->las0+LAS0_BOARD_RESET)
-
-/* Reset channel gain table read pointer */
-#define RtdResetCGT(dev) \
- writel(0, devpriv->las0+LAS0_CGT_RESET)
-
-/* Reset channel gain table read and write pointers */
-#define RtdClearCGT(dev) \
- writel(0, devpriv->las0+LAS0_CGT_CLEAR)
-
-/* Reset channel gain table read and write pointers */
-#define RtdEnableCGT(dev, v) \
- writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_CGT_ENABLE)
-
-/* Write channel gain table entry */
-#define RtdWriteCGTable(dev, v) \
- writel(v, devpriv->las0+LAS0_CGT_WRITE)
-
-/* Write Channel Gain Latch */
-#define RtdWriteCGLatch(dev, v) \
- writel(v, devpriv->las0+LAS0_CGL_WRITE)
-
-/* Reset ADC FIFO */
-#define RtdAdcClearFifo(dev) \
- writel(0, devpriv->las0+LAS0_ADC_FIFO_CLEAR)
-
-/* Set ADC start conversion source select (write only) */
-#define RtdAdcConversionSource(dev, v) \
- writel(v, devpriv->las0+LAS0_ADC_CONVERSION)
-
-/* Set burst start source select (write only) */
-#define RtdBurstStartSource(dev, v) \
- writel(v, devpriv->las0+LAS0_BURST_START)
-
-/* Set Pacer start source select (write only) */
-#define RtdPacerStartSource(dev, v) \
- writel(v, devpriv->las0+LAS0_PACER_START)
-
-/* Set Pacer stop source select (write only) */
-#define RtdPacerStopSource(dev, v) \
- writel(v, devpriv->las0+LAS0_PACER_STOP)
-
-/* Set Pacer clock source select (write only) 0=external 1=internal */
-#define RtdPacerClockSource(dev, v) \
- writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_PACER_SELECT)
-
-/* Set sample counter source select (write only) */
-#define RtdAdcSampleCounterSource(dev, v) \
- writel(v, devpriv->las0+LAS0_ADC_SCNT_SRC)
-
-/* Set Pacer trigger mode select (write only) 0=single cycle, 1=repeat */
-#define RtdPacerTriggerMode(dev, v) \
- writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_PACER_REPEAT)
-
-/* Set About counter stop enable (write only) */
-#define RtdAboutStopEnable(dev, v) \
- writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_ACNT_STOP_ENABLE)
-
-/* Set external trigger polarity (write only) 0=positive edge, 1=negative */
-#define RtdTriggerPolarity(dev, v) \
- writel((v > 0) ? 1 : 0, devpriv->las0+LAS0_ETRG_POLARITY)
-
-/* Start single ADC conversion */
-#define RtdAdcStart(dev) \
- writew(0, devpriv->las0+LAS0_ADC)
-
-/* Read one ADC data value (12bit (with sign extend) as 16bit) */
-/* Note: matches what DMA would get. Actual value >> 3 */
-#define RtdAdcFifoGet(dev) \
- readw(devpriv->las1+LAS1_ADC_FIFO)
-
-/* Read two ADC data values (DOESN'T WORK) */
-#define RtdAdcFifoGet2(dev) \
- readl(devpriv->las1+LAS1_ADC_FIFO)
-
-/* FIFO status */
-#define RtdFifoStatus(dev) \
- readl(devpriv->las0+LAS0_ADC)
-
-/* pacer start/stop read=start, write=stop*/
-#define RtdPacerStart(dev) \
- readl(devpriv->las0+LAS0_PACER)
-#define RtdPacerStop(dev) \
- writel(0, devpriv->las0+LAS0_PACER)
-
-/* Interrupt status */
-#define RtdInterruptStatus(dev) \
- readw(devpriv->las0+LAS0_IT)
-
-/* Interrupt mask */
-#define RtdInterruptMask(dev, v) \
- writew((devpriv->intMask = (v)), devpriv->las0+LAS0_IT)
-
-/* Interrupt status clear (only bits set in mask) */
-#define RtdInterruptClear(dev) \
- readw(devpriv->las0+LAS0_CLEAR)
-
-/* Interrupt clear mask */
-#define RtdInterruptClearMask(dev, v) \
- writew((devpriv->intClearMask = (v)), devpriv->las0+LAS0_CLEAR)
-
-/* Interrupt overrun status */
-#define RtdInterruptOverrunStatus(dev) \
- readl(devpriv->las0+LAS0_OVERRUN)
-
-/* Interrupt overrun clear */
-#define RtdInterruptOverrunClear(dev) \
- writel(0, devpriv->las0+LAS0_OVERRUN)
-
-/* Pacer counter, 24bit */
-#define RtdPacerCount(dev) \
- readl(devpriv->las0+LAS0_PCLK)
-#define RtdPacerCounter(dev, v) \
- writel((v) & 0xffffff, devpriv->las0+LAS0_PCLK)
-
-/* Burst counter, 10bit */
-#define RtdBurstCount(dev) \
- readl(devpriv->las0+LAS0_BCLK)
-#define RtdBurstCounter(dev, v) \
- writel((v) & 0x3ff, devpriv->las0+LAS0_BCLK)
-
-/* Delay counter, 16bit */
-#define RtdDelayCount(dev) \
- readl(devpriv->las0+LAS0_DCLK)
-#define RtdDelayCounter(dev, v) \
- writel((v) & 0xffff, devpriv->las0+LAS0_DCLK)
-
-/* About counter, 16bit */
-#define RtdAboutCount(dev) \
- readl(devpriv->las0+LAS0_ACNT)
-#define RtdAboutCounter(dev, v) \
- writel((v) & 0xffff, devpriv->las0+LAS0_ACNT)
-
-/* ADC sample counter, 10bit */
-#define RtdAdcSampleCount(dev) \
- readl(devpriv->las0+LAS0_ADC_SCNT)
-#define RtdAdcSampleCounter(dev, v) \
- writel((v) & 0x3ff, devpriv->las0+LAS0_ADC_SCNT)
-
-/* User Timer/Counter (8254) */
-#define RtdUtcCounterGet(dev, n) \
- readb(devpriv->las0 \
- + ((n <= 0) ? LAS0_UTC0 : ((1 == n) ? LAS0_UTC1 : LAS0_UTC2)))
-
-#define RtdUtcCounterPut(dev, n, v) \
- writeb((v) & 0xff, devpriv->las0 \
- + ((n <= 0) ? LAS0_UTC0 : ((1 == n) ? LAS0_UTC1 : LAS0_UTC2)))
-
-/* Set UTC (8254) control byte */
-#define RtdUtcCtrlPut(dev, n, v) \
- writeb(devpriv->utcCtrl[(n) & 3] = (((n) & 3) << 6) | ((v) & 0x3f), \
- devpriv->las0 + LAS0_UTC_CTRL)
-
-/* Set UTCn clock source (write only) */
-#define RtdUtcClockSource(dev, n, v) \
- writew(v, devpriv->las0 \
- + ((n <= 0) ? LAS0_UTC0_CLOCK : \
- ((1 == n) ? LAS0_UTC1_CLOCK : LAS0_UTC2_CLOCK)))
-
-/* Set UTCn gate source (write only) */
-#define RtdUtcGateSource(dev, n, v) \
- writew(v, devpriv->las0 \
- + ((n <= 0) ? LAS0_UTC0_GATE : \
- ((1 == n) ? LAS0_UTC1_GATE : LAS0_UTC2_GATE)))
-
-/* User output N source select (write only) */
-#define RtdUsrOutSource(dev, n, v) \
- writel(v, devpriv->las0+((n <= 0) ? LAS0_UOUT0_SELECT : \
- LAS0_UOUT1_SELECT))
-
-/* Digital IO */
-#define RtdDio0Read(dev) \
- (readw(devpriv->las0+LAS0_DIO0) & 0xff)
-#define RtdDio0Write(dev, v) \
- writew((v) & 0xff, devpriv->las0+LAS0_DIO0)
-
-#define RtdDio1Read(dev) \
- (readw(devpriv->las0+LAS0_DIO1) & 0xff)
-#define RtdDio1Write(dev, v) \
- writew((v) & 0xff, devpriv->las0+LAS0_DIO1)
-
-#define RtdDioStatusRead(dev) \
- (readw(devpriv->las0+LAS0_DIO_STATUS) & 0xff)
-#define RtdDioStatusWrite(dev, v) \
- writew((devpriv->dioStatus = (v)), devpriv->las0+LAS0_DIO_STATUS)
-
-#define RtdDio0CtrlRead(dev) \
- (readw(devpriv->las0+LAS0_DIO0_CTRL) & 0xff)
-#define RtdDio0CtrlWrite(dev, v) \
- writew((v) & 0xff, devpriv->las0+LAS0_DIO0_CTRL)
-
-/* Digital to Analog converter */
-/* Write one data value (sign + 12bit + marker bits) */
-/* Note: matches what DMA would put. Actual value << 3 */
-#define RtdDacFifoPut(dev, n, v) \
- writew((v), devpriv->las1 + (((n) == 0) ? LAS1_DAC1_FIFO : \
- LAS1_DAC2_FIFO))
-
-/* Start single DAC conversion */
-#define RtdDacUpdate(dev, n) \
- writew(0, devpriv->las0 + (((n) == 0) ? LAS0_DAC1 : LAS0_DAC2))
-
-/* Start single DAC conversion on both DACs */
-#define RtdDacBothUpdate(dev) \
- writew(0, devpriv->las0+LAS0_DAC)
-
-/* Set DAC output type and range */
-#define RtdDacRange(dev, n, v) \
- writew((v) & 7, devpriv->las0 \
- +(((n) == 0) ? LAS0_DAC1_CTRL : LAS0_DAC2_CTRL))
-
-/* Reset DAC FIFO */
-#define RtdDacClearFifo(dev, n) \
- writel(0, devpriv->las0+(((n) == 0) ? LAS0_DAC1_RESET : \
- LAS0_DAC2_RESET))
-
-/* Set source for DMA 0 (write only, shadow?) */
-#define RtdDma0Source(dev, n) \
- writel((n) & 0xf, devpriv->las0+LAS0_DMA0_SRC)
-
-/* Set source for DMA 1 (write only, shadow?) */
-#define RtdDma1Source(dev, n) \
- writel((n) & 0xf, devpriv->las0+LAS0_DMA1_SRC)
-
-/* Reset board state for DMA 0 */
-#define RtdDma0Reset(dev) \
- writel(0, devpriv->las0+LAS0_DMA0_RESET)
-
-/* Reset board state for DMA 1 */
-#define RtdDma1Reset(dev) \
- writel(0, devpriv->las0+LAS0_DMA1_SRC)
-
-/* PLX9080 interrupt mask and status */
-#define RtdPlxInterruptRead(dev) \
- readl(devpriv->lcfg+LCFG_ITCSR)
-#define RtdPlxInterruptWrite(dev, v) \
- writel(v, devpriv->lcfg+LCFG_ITCSR)
-
-/* Set mode for DMA 0 */
-#define RtdDma0Mode(dev, m) \
- writel((m), devpriv->lcfg+LCFG_DMAMODE0)
-
-/* Set PCI address for DMA 0 */
-#define RtdDma0PciAddr(dev, a) \
- writel((a), devpriv->lcfg+LCFG_DMAPADR0)
-
-/* Set local address for DMA 0 */
-#define RtdDma0LocalAddr(dev, a) \
- writel((a), devpriv->lcfg+LCFG_DMALADR0)
-
-/* Set byte count for DMA 0 */
-#define RtdDma0Count(dev, c) \
- writel((c), devpriv->lcfg+LCFG_DMASIZ0)
-
-/* Set next descriptor for DMA 0 */
-#define RtdDma0Next(dev, a) \
- writel((a), devpriv->lcfg+LCFG_DMADPR0)
-
-/* Set mode for DMA 1 */
-#define RtdDma1Mode(dev, m) \
- writel((m), devpriv->lcfg+LCFG_DMAMODE1)
-
-/* Set PCI address for DMA 1 */
-#define RtdDma1PciAddr(dev, a) \
- writel((a), devpriv->lcfg+LCFG_DMAADR1)
-
-/* Set local address for DMA 1 */
-#define RtdDma1LocalAddr(dev, a) \
- writel((a), devpriv->lcfg+LCFG_DMALADR1)
-
-/* Set byte count for DMA 1 */
-#define RtdDma1Count(dev, c) \
- writel((c), devpriv->lcfg+LCFG_DMASIZ1)
-
-/* Set next descriptor for DMA 1 */
-#define RtdDma1Next(dev, a) \
- writel((a), devpriv->lcfg+LCFG_DMADPR1)
-
-/* Set control for DMA 0 (write only, shadow?) */
-#define RtdDma0Control(dev, n) \
- writeb(devpriv->dma0Control = (n), devpriv->lcfg+LCFG_DMACSR0)
-
-/* Get status for DMA 0 */
-#define RtdDma0Status(dev) \
- readb(devpriv->lcfg+LCFG_DMACSR0)
-
-/* Set control for DMA 1 (write only, shadow?) */
-#define RtdDma1Control(dev, n) \
- writeb(devpriv->dma1Control = (n), devpriv->lcfg+LCFG_DMACSR1)
-
-/* Get status for DMA 1 */
-#define RtdDma1Status(dev) \
- readb(devpriv->lcfg+LCFG_DMACSR1)
-
-static int rtd_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int rtd_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int rtd_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int rtd_dio_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int rtd_dio_insn_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data);
-static int rtd_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s,
- struct comedi_cmd *cmd);
-static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s);
-static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s);
-/*
- * static int rtd_ai_poll(struct comedi_device *dev,
- * struct comedi_subdevice *s);
- */
-static int rtd_ns_to_timer(unsigned int *ns, int roundMode);
-static irqreturn_t rtd_interrupt(int irq, void *d);
-static int rtd520_probe_fifo_depth(struct comedi_device *dev);
-
-/*
- * Attach is called by the Comedi core to configure the driver
- * for a particular board. If you specified a board_name array
- * in the driver structure, dev->board_ptr contains that
- * address.
- */
-static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
-{ /* board name and options flags */
- struct comedi_subdevice *s;
- struct pci_dev *pcidev;
- int ret;
- resource_size_t physLas0; /* configuration */
- resource_size_t physLas1; /* data area */
- resource_size_t physLcfg; /* PLX9080 */
-#ifdef USE_DMA
- int index;
-#endif
-
- printk(KERN_INFO "comedi%d: rtd520 attaching.\n", dev->minor);
-
-#if defined(CONFIG_COMEDI_DEBUG) && defined(USE_DMA)
- /* You can set this a load time: modprobe comedi comedi_debug=1 */
- if (0 == comedi_debug) /* force DMA debug printks */
- comedi_debug = 1;
-#endif
-
- /*
- * Allocate the private structure area. alloc_private() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_private(dev, sizeof(struct rtdPrivate)) < 0)
- return -ENOMEM;
-
- /*
- * Probe the device to determine what device in the series it is.
- */
- for (pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, NULL);
- pcidev != NULL;
- pcidev = pci_get_device(PCI_VENDOR_ID_RTD, PCI_ANY_ID, pcidev)) {
- int i;
-
- if (it->options[0] || it->options[1]) {
- if (pcidev->bus->number != it->options[0]
- || PCI_SLOT(pcidev->devfn) != it->options[1]) {
- continue;
- }
- }
- for (i = 0; i < ARRAY_SIZE(rtd520Boards); ++i) {
- if (pcidev->device == rtd520Boards[i].device_id) {
- dev->board_ptr = &rtd520Boards[i];
- break;
- }
- }
- if (dev->board_ptr)
- break; /* found one */
- }
- if (!pcidev) {
- if (it->options[0] && it->options[1]) {
- printk(KERN_INFO "No RTD card at bus=%d slot=%d.\n",
- it->options[0], it->options[1]);
- } else {
- printk(KERN_INFO "No RTD card found.\n");
- }
- return -EIO;
- }
- devpriv->pci_dev = pcidev;
- dev->board_name = thisboard->name;
-
- ret = comedi_pci_enable(pcidev, DRV_NAME);
- if (ret < 0) {
- printk(KERN_INFO "Failed to enable PCI device and request regions.\n");
- return ret;
- }
- devpriv->got_regions = 1;
-
- /*
- * Initialize base addresses
- */
- /* Get the physical address from PCI config */
- physLas0 = pci_resource_start(devpriv->pci_dev, LAS0_PCIINDEX);
- physLas1 = pci_resource_start(devpriv->pci_dev, LAS1_PCIINDEX);
- physLcfg = pci_resource_start(devpriv->pci_dev, LCFG_PCIINDEX);
- /* Now have the kernel map this into memory */
- /* ASSUME page aligned */
- devpriv->las0 = ioremap_nocache(physLas0, LAS0_PCISIZE);
- devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE);
- devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE);
-
- if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
- return -ENOMEM;
-
-
- DPRINTK("%s: LAS0=%llx, LAS1=%llx, CFG=%llx.\n", dev->board_name,
- (unsigned long long)physLas0, (unsigned long long)physLas1,
- (unsigned long long)physLcfg);
- { /* The RTD driver does this */
- unsigned char pci_latency;
- u16 revision;
- /*uint32_t epld_version; */
-
- pci_read_config_word(devpriv->pci_dev, PCI_REVISION_ID,
- &revision);
- DPRINTK("%s: PCI revision %d.\n", dev->board_name, revision);
-
- pci_read_config_byte(devpriv->pci_dev,
- PCI_LATENCY_TIMER, &pci_latency);
- if (pci_latency < 32) {
- printk(KERN_INFO "%s: PCI latency changed from %d to %d\n",
- dev->board_name, pci_latency, 32);
- pci_write_config_byte(devpriv->pci_dev,
- PCI_LATENCY_TIMER, 32);
- } else {
- DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
- }
-
- /*
- * Undocumented EPLD version (doesn't match RTD driver results)
- */
- /*DPRINTK ("rtd520: Reading epld from %p\n",
- devpriv->las0+0);
- epld_version = readl (devpriv->las0+0);
- if ((epld_version & 0xF0) >> 4 == 0x0F) {
- DPRINTK("rtd520: pre-v8 EPLD. (%x)\n", epld_version);
- } else {
- DPRINTK("rtd520: EPLD version %x.\n", epld_version >> 4);
- } */
- }
-
- /* Show board configuration */
- printk(KERN_INFO "%s:", dev->board_name);
-
- /*
- * Allocate the subdevice structures. alloc_subdevice() is a
- * convenient macro defined in comedidev.h.
- */
- if (alloc_subdevices(dev, 4) < 0)
- return -ENOMEM;
-
-
- s = dev->subdevices + 0;
- dev->read_subdev = s;
- /* analog input subdevice */
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags =
- SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
- s->n_chan = thisboard->aiChans;
- s->maxdata = (1 << thisboard->aiBits) - 1;
- if (thisboard->aiMaxGain <= 32)
- s->range_table = &rtd_ai_7520_range;
- else
- s->range_table = &rtd_ai_4520_range;
-
- s->len_chanlist = RTD_MAX_CHANLIST; /* devpriv->fifoLen */
- s->insn_read = rtd_ai_rinsn;
- s->do_cmd = rtd_ai_cmd;
- s->do_cmdtest = rtd_ai_cmdtest;
- s->cancel = rtd_ai_cancel;
- /* s->poll = rtd_ai_poll; *//* not ready yet */
-
- s = dev->subdevices + 1;
- /* analog output subdevice */
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 2;
- s->maxdata = (1 << thisboard->aiBits) - 1;
- s->range_table = &rtd_ao_range;
- s->insn_write = rtd_ao_winsn;
- s->insn_read = rtd_ao_rinsn;
-
- s = dev->subdevices + 2;
- /* digital i/o subdevice */
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- /* we only support port 0 right now. Ignoring port 1 and user IO */
- s->n_chan = 8;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = rtd_dio_insn_bits;
- s->insn_config = rtd_dio_insn_config;
-
- /* timer/counter subdevices (not currently supported) */
- s = dev->subdevices + 3;
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 3;
- s->maxdata = 0xffff;
-
- /* initialize board, per RTD spec */
- /* also, initialize shadow registers */
- RtdResetBoard(dev);
- udelay(100); /* needed? */
- RtdPlxInterruptWrite(dev, 0);
- RtdInterruptMask(dev, 0); /* and sets shadow */
- RtdInterruptClearMask(dev, ~0); /* and sets shadow */
- RtdInterruptClear(dev); /* clears bits set by mask */
- RtdInterruptOverrunClear(dev);
- RtdClearCGT(dev);
- RtdAdcClearFifo(dev);
- RtdDacClearFifo(dev, 0);
- RtdDacClearFifo(dev, 1);
- /* clear digital IO fifo */
- RtdDioStatusWrite(dev, 0); /* safe state, set shadow */
- RtdUtcCtrlPut(dev, 0, 0x30); /* safe state, set shadow */
- RtdUtcCtrlPut(dev, 1, 0x30); /* safe state, set shadow */
- RtdUtcCtrlPut(dev, 2, 0x30); /* safe state, set shadow */
- RtdUtcCtrlPut(dev, 3, 0); /* safe state, set shadow */
- /* TODO: set user out source ??? */
-
- /* check if our interrupt is available and get it */
- ret = request_irq(devpriv->pci_dev->irq, rtd_interrupt,
- IRQF_SHARED, DRV_NAME, dev);
-
- if (ret < 0) {
- printk("Could not get interrupt! (%u)\n",
- devpriv->pci_dev->irq);
- return ret;
- }
- dev->irq = devpriv->pci_dev->irq;
- printk(KERN_INFO "( irq=%u )", dev->irq);
-
- ret = rtd520_probe_fifo_depth(dev);
- if (ret < 0)
- return ret;
-
- devpriv->fifoLen = ret;
- printk("( fifoLen=%d )", devpriv->fifoLen);
-
-#ifdef USE_DMA
- if (dev->irq > 0) {
- printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
- /*
- * The PLX9080 has 2 DMA controllers, but there could be
- * 4 sources: ADC, digital, DAC1, and DAC2. Since only the
- * ADC supports cmd mode right now, this isn't an issue (yet)
- */
- devpriv->dma0Offset = 0;
-
- for (index = 0; index < DMA_CHAIN_COUNT; index++) {
- devpriv->dma0Buff[index] =
- pci_alloc_consistent(devpriv->pci_dev,
- sizeof(u16) *
- devpriv->fifoLen / 2,
- &devpriv->
- dma0BuffPhysAddr[index]);
- if (devpriv->dma0Buff[index] == NULL) {
- ret = -ENOMEM;
- goto rtd_attach_die_error;
- }
- /*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",
- index,
- devpriv->dma0Buff[index],
- devpriv->dma0BuffPhysAddr[index]); */
- }
-
- /*
- * setup DMA descriptor ring (use cpu_to_le32 for byte
- * ordering?)
- */
- devpriv->dma0Chain =
- pci_alloc_consistent(devpriv->pci_dev,
- sizeof(struct plx_dma_desc) *
- DMA_CHAIN_COUNT,
- &devpriv->dma0ChainPhysAddr);
- for (index = 0; index < DMA_CHAIN_COUNT; index++) {
- devpriv->dma0Chain[index].pci_start_addr =
- devpriv->dma0BuffPhysAddr[index];
- devpriv->dma0Chain[index].local_start_addr =
- DMALADDR_ADC;
- devpriv->dma0Chain[index].transfer_size =
- sizeof(u16) * devpriv->fifoLen / 2;
- devpriv->dma0Chain[index].next =
- (devpriv->dma0ChainPhysAddr + ((index +
- 1) %
- (DMA_CHAIN_COUNT))
- * sizeof(devpriv->dma0Chain[0]))
- | DMA_TRANSFER_BITS;
- /*DPRINTK ("ring[%d] @%lx PCI: %x, local: %x, N: 0x%x, next: %x\n",
- index,
- ((long)devpriv->dma0ChainPhysAddr
- + (index * sizeof(devpriv->dma0Chain[0]))),
- devpriv->dma0Chain[index].pci_start_addr,
- devpriv->dma0Chain[index].local_start_addr,
- devpriv->dma0Chain[index].transfer_size,
- devpriv->dma0Chain[index].next); */
- }
-
- if (devpriv->dma0Chain == NULL) {
- ret = -ENOMEM;
- goto rtd_attach_die_error;
- }
-
- RtdDma0Mode(dev, DMA_MODE_BITS);
- /* set DMA trigger source */
- RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL);
- } else {
- printk(KERN_INFO "( no IRQ->no DMA )");
- }
-#endif /* USE_DMA */
-
- if (dev->irq) { /* enable plx9080 interrupts */
- RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
- }
-
- printk("\ncomedi%d: rtd520 driver attached.\n", dev->minor);
-
- return 1;
+ Given a desired period and the clock period (both in ns),
+ return the proper counter value (divider-1).
+ Sets the original period to be the true value.
+ Note: you have to check if the value is larger than the counter range!
+*/
+static int rtd_ns_to_timer_base(unsigned int *nanosec, /* desired period (in ns) */
+ int round_mode, int base)
+{ /* clock period (in ns) */
+ int divider;
-#if 0
- /* hit an error, clean up memory and return ret */
-/* rtd_attach_die_error: */
-#ifdef USE_DMA
- for (index = 0; index < DMA_CHAIN_COUNT; index++) {
- if (NULL != devpriv->dma0Buff[index]) { /* free buffer memory */
- pci_free_consistent(devpriv->pci_dev,
- sizeof(u16) * devpriv->fifoLen / 2,
- devpriv->dma0Buff[index],
- devpriv->dma0BuffPhysAddr[index]);
- devpriv->dma0Buff[index] = NULL;
- }
- }
- if (NULL != devpriv->dma0Chain) {
- pci_free_consistent(devpriv->pci_dev,
- sizeof(struct plx_dma_desc)
- * DMA_CHAIN_COUNT,
- devpriv->dma0Chain,
- devpriv->dma0ChainPhysAddr);
- devpriv->dma0Chain = NULL;
- }
-#endif /* USE_DMA */
- /* subdevices and priv are freed by the core */
- if (dev->irq) {
- /* disable interrupt controller */
- RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
- & ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E));
- free_irq(dev->irq, dev);
+ switch (round_mode) {
+ case TRIG_ROUND_NEAREST:
+ default:
+ divider = (*nanosec + base / 2) / base;
+ break;
+ case TRIG_ROUND_DOWN:
+ divider = (*nanosec) / base;
+ break;
+ case TRIG_ROUND_UP:
+ divider = (*nanosec + base - 1) / base;
+ break;
}
+ if (divider < 2)
+ divider = 2; /* min is divide by 2 */
- /* release all regions that were allocated */
- if (devpriv->las0)
- iounmap(devpriv->las0);
-
- if (devpriv->las1)
- iounmap(devpriv->las1);
-
- if (devpriv->lcfg)
- iounmap(devpriv->lcfg);
-
- if (devpriv->pci_dev)
- pci_dev_put(devpriv->pci_dev);
+ /* Note: we don't check for max, because different timers
+ have different ranges */
- return ret;
-#endif
+ *nanosec = base * divider;
+ return divider - 1; /* countdown is divisor+1 */
}
-static void rtd_detach(struct comedi_device *dev)
+/*
+ Given a desired period (in ns),
+ return the proper counter value (divider-1) for the internal clock.
+ Sets the original period to be the true value.
+*/
+static int rtd_ns_to_timer(unsigned int *ns, int round_mode)
{
-#ifdef USE_DMA
- int index;
-#endif
-
- if (devpriv) {
- /* Shut down any board ops by resetting it */
-#ifdef USE_DMA
- if (devpriv->lcfg) {
- RtdDma0Control(dev, 0); /* disable DMA */
- RtdDma1Control(dev, 0); /* disable DMA */
- RtdPlxInterruptWrite(dev, ICS_PIE | ICS_PLIE);
- }
-#endif /* USE_DMA */
- if (devpriv->las0) {
- RtdResetBoard(dev);
- RtdInterruptMask(dev, 0);
- RtdInterruptClearMask(dev, ~0);
- RtdInterruptClear(dev); /* clears bits set by mask */
- }
-#ifdef USE_DMA
- /* release DMA */
- for (index = 0; index < DMA_CHAIN_COUNT; index++) {
- if (NULL != devpriv->dma0Buff[index]) {
- pci_free_consistent(devpriv->pci_dev,
- sizeof(u16) *
- devpriv->fifoLen / 2,
- devpriv->dma0Buff[index],
- devpriv->
- dma0BuffPhysAddr[index]);
- devpriv->dma0Buff[index] = NULL;
- }
- }
- if (NULL != devpriv->dma0Chain) {
- pci_free_consistent(devpriv->pci_dev,
- sizeof(struct plx_dma_desc) *
- DMA_CHAIN_COUNT, devpriv->dma0Chain,
- devpriv->dma0ChainPhysAddr);
- devpriv->dma0Chain = NULL;
- }
-#endif /* USE_DMA */
- if (dev->irq) {
- RtdPlxInterruptWrite(dev, RtdPlxInterruptRead(dev)
- & ~(ICS_PLIE | ICS_DMA0_E |
- ICS_DMA1_E));
- free_irq(dev->irq, dev);
- }
- if (devpriv->las0)
- iounmap(devpriv->las0);
- if (devpriv->las1)
- iounmap(devpriv->las1);
- if (devpriv->lcfg)
- iounmap(devpriv->lcfg);
- if (devpriv->pci_dev) {
- if (devpriv->got_regions)
- comedi_pci_disable(devpriv->pci_dev);
- pci_dev_put(devpriv->pci_dev);
- }
- }
+ return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE);
}
/*
@@ -1149,6 +406,8 @@ static void rtd_detach(struct comedi_device *dev)
static unsigned short rtdConvertChanGain(struct comedi_device *dev,
unsigned int comediChan, int chanIndex)
{ /* index in channel list */
+ const struct rtdBoard *thisboard = comedi_board(dev);
+ struct rtdPrivate *devpriv = dev->private;
unsigned int chan, range, aref;
unsigned short r = 0;
@@ -1201,17 +460,21 @@ static unsigned short rtdConvertChanGain(struct comedi_device *dev,
static void rtd_load_channelgain_list(struct comedi_device *dev,
unsigned int n_chan, unsigned int *list)
{
+ struct rtdPrivate *devpriv = dev->private;
+
if (n_chan > 1) { /* setup channel gain table */
int ii;
- RtdClearCGT(dev);
- RtdEnableCGT(dev, 1); /* enable table */
+
+ writel(0, devpriv->las0 + LAS0_CGT_CLEAR);
+ writel(1, devpriv->las0 + LAS0_CGT_ENABLE);
for (ii = 0; ii < n_chan; ii++) {
- RtdWriteCGTable(dev, rtdConvertChanGain(dev, list[ii],
- ii));
+ writel(rtdConvertChanGain(dev, list[ii], ii),
+ devpriv->las0 + LAS0_CGT_WRITE);
}
} else { /* just use the channel gain latch */
- RtdEnableCGT(dev, 0); /* disable table, enable latch */
- RtdWriteCGLatch(dev, rtdConvertChanGain(dev, list[0], 0));
+ writel(0, devpriv->las0 + LAS0_CGT_ENABLE);
+ writel(rtdConvertChanGain(dev, list[0], 0),
+ devpriv->las0 + LAS0_CGL_WRITE);
}
}
@@ -1219,21 +482,23 @@ static void rtd_load_channelgain_list(struct comedi_device *dev,
empty status flag clears */
static int rtd520_probe_fifo_depth(struct comedi_device *dev)
{
+ struct rtdPrivate *devpriv = dev->private;
unsigned int chanspec = CR_PACK(0, 0, AREF_GROUND);
unsigned i;
static const unsigned limit = 0x2000;
unsigned fifo_size = 0;
- RtdAdcClearFifo(dev);
+ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
rtd_load_channelgain_list(dev, 1, &chanspec);
- RtdAdcConversionSource(dev, 0); /* software */
+ /* ADC conversion trigger source: SOFTWARE */
+ writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
/* convert samples */
for (i = 0; i < limit; ++i) {
unsigned fifo_status;
/* trigger conversion */
- RtdAdcStart(dev);
+ writew(0, devpriv->las0 + LAS0_ADC);
udelay(1);
- fifo_status = RtdFifoStatus(dev);
+ fifo_status = readl(devpriv->las0 + LAS0_ADC);
if ((fifo_status & FS_ADC_HEMPTY) == 0) {
fifo_size = 2 * i;
break;
@@ -1244,7 +509,7 @@ static int rtd520_probe_fifo_depth(struct comedi_device *dev)
DRV_NAME);
return -EIO;
}
- RtdAdcClearFifo(dev);
+ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
if (fifo_size != 0x400 && fifo_size != 0x2000) {
printk
(KERN_INFO "\ncomedi: %s: unexpected fifo size of %i, expected 1024 or 8192.\n",
@@ -1266,26 +531,27 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
+ struct rtdPrivate *devpriv = dev->private;
int n, ii;
int stat;
/* clear any old fifo data */
- RtdAdcClearFifo(dev);
+ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
/* write channel to multiplexer and clear channel gain table */
rtd_load_channelgain_list(dev, 1, &insn->chanspec);
- /* set conversion source */
- RtdAdcConversionSource(dev, 0); /* software */
+ /* ADC conversion trigger source: SOFTWARE */
+ writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
/* convert n samples */
for (n = 0; n < insn->n; n++) {
s16 d;
/* trigger conversion */
- RtdAdcStart(dev);
+ writew(0, devpriv->las0 + LAS0_ADC);
for (ii = 0; ii < RTD_ADC_TIMEOUT; ++ii) {
- stat = RtdFifoStatus(dev);
+ stat = readl(devpriv->las0 + LAS0_ADC);
if (stat & FS_ADC_NOT_EMPTY) /* 1 -> not empty */
break;
WAIT_QUIETLY;
@@ -1298,7 +564,7 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
}
/* read data */
- d = RtdAdcFifoGet(dev); /* get 2s comp value */
+ d = readw(devpriv->las1 + LAS1_ADC_FIFO);
/*printk ("rtd520: Got 0x%x after %d usec\n", d, ii+1); */
d = d >> 3; /* low 3 bits are marker lines */
if (CHAN_ARRAY_TEST(devpriv->chanBipolar, 0))
@@ -1321,6 +587,7 @@ static int rtd_ai_rinsn(struct comedi_device *dev,
static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
int count)
{
+ struct rtdPrivate *devpriv = dev->private;
int ii;
for (ii = 0; ii < count; ii++) {
@@ -1328,17 +595,17 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
s16 d;
if (0 == devpriv->aiCount) { /* done */
- d = RtdAdcFifoGet(dev); /* Read N and discard */
+ d = readw(devpriv->las1 + LAS1_ADC_FIFO);
continue;
}
#if 0
- if (0 == (RtdFifoStatus(dev) & FS_ADC_NOT_EMPTY)) { /* DEBUG */
+ if (!(readl(devpriv->las0 + LAS0_ADC) & FS_ADC_NOT_EMPTY)) {
DPRINTK("comedi: READ OOPS on %d of %d\n", ii + 1,
count);
break;
}
#endif
- d = RtdAdcFifoGet(dev); /* get 2s comp value */
+ d = readw(devpriv->las1 + LAS1_ADC_FIFO);
d = d >> 3; /* low 3 bits are marker lines */
if (CHAN_ARRAY_TEST(devpriv->chanBipolar, s->async->cur_chan)) {
@@ -1361,9 +628,11 @@ static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
*/
static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
{
- while (RtdFifoStatus(dev) & FS_ADC_NOT_EMPTY) { /* 1 -> not empty */
+ struct rtdPrivate *devpriv = dev->private;
+
+ while (readl(devpriv->las0 + LAS0_ADC) & FS_ADC_NOT_EMPTY) {
short sample;
- s16 d = RtdAdcFifoGet(dev); /* get 2s comp value */
+ s16 d = readw(devpriv->las1 + LAS1_ADC_FIFO);
if (0 == devpriv->aiCount) { /* done */
continue; /* read rest */
@@ -1391,6 +660,7 @@ static int ai_read_dregs(struct comedi_device *dev, struct comedi_subdevice *s)
*/
void abort_dma(struct comedi_device *dev, unsigned int channel)
{ /* DMA channel 0, 1 */
+ struct rtdPrivate *devpriv = dev->private;
unsigned long dma_cs_addr; /* the control/status register */
uint8_t status;
unsigned int ii;
@@ -1449,6 +719,7 @@ abortDmaExit:
*/
static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct rtdPrivate *devpriv = dev->private;
int ii, n;
s16 *dp;
@@ -1511,17 +782,19 @@ static int ai_process_dma(struct comedi_device *dev, struct comedi_subdevice *s)
static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */
void *d)
{ /* our data *//* cpu context (ignored) */
- struct comedi_device *dev = d; /* must be called "dev" for devpriv */
+ struct comedi_device *dev = d;
+ struct comedi_subdevice *s = dev->subdevices + 0; /* analog in subdevice */
+ struct rtdPrivate *devpriv = dev->private;
+ u32 overrun;
u16 status;
u16 fifoStatus;
- struct comedi_subdevice *s = dev->subdevices + 0; /* analog in subdevice */
if (!dev->attached)
return IRQ_NONE;
devpriv->intCount++; /* DEBUG statistics */
- fifoStatus = RtdFifoStatus(dev);
+ fifoStatus = readl(devpriv->las0 + LAS0_ADC);
/* check for FIFO full, this automatically halts the ADC! */
if (!(fifoStatus & FS_ADC_NOT_FULL)) { /* 0 -> full */
DPRINTK("rtd520: FIFO full! fifo_status=0x%x\n", (fifoStatus ^ 0x6666) & 0x7777); /* should be all 0s */
@@ -1529,26 +802,26 @@ static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */
}
#ifdef USE_DMA
if (devpriv->flags & DMA0_ACTIVE) { /* Check DMA */
- u32 istatus = RtdPlxInterruptRead(dev);
+ u32 istatus = readl(devpriv->lcfg + LCFG_ITCSR);
if (istatus & ICS_DMA0_A) {
if (ai_process_dma(dev, s) < 0) {
DPRINTK
("rtd520: comedi read buffer overflow (DMA) with %ld to go!\n",
devpriv->aiCount);
- RtdDma0Control(dev,
- (devpriv->dma0Control &
- ~PLX_DMA_START_BIT)
- | PLX_CLEAR_DMA_INTR_BIT);
+ devpriv->dma0Control &= ~PLX_DMA_START_BIT;
+ devpriv->dma0Control |= PLX_CLEAR_DMA_INTR_BIT;
+ writeb(devpriv->dma0Control,
+ devpriv->lcfg + LCFG_DMACSR0);
goto abortTransfer;
}
/*DPRINTK ("rtd520: DMA transfer: %ld to go, istatus %x\n",
devpriv->aiCount, istatus); */
- RtdDma0Control(dev,
- (devpriv->
- dma0Control & ~PLX_DMA_START_BIT)
- | PLX_CLEAR_DMA_INTR_BIT);
+ devpriv->dma0Control &= ~PLX_DMA_START_BIT;
+ devpriv->dma0Control |= PLX_CLEAR_DMA_INTR_BIT;
+ writeb(devpriv->dma0Control,
+ devpriv->lcfg + LCFG_DMACSR0);
if (0 == devpriv->aiCount) { /* counted down */
DPRINTK("rtd520: Samples Done (DMA).\n");
goto transferDone;
@@ -1561,7 +834,7 @@ static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */
/* Fall through and check for other interrupt sources */
#endif /* USE_DMA */
- status = RtdInterruptStatus(dev);
+ status = readw(devpriv->las0 + LAS0_IT);
/* if interrupt was not caused by our board, or handled above */
if (0 == status)
return IRQ_HANDLED;
@@ -1611,33 +884,37 @@ static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */
DPRINTK("rtd520: unknown interrupt source!\n");
}
- if (0xffff & RtdInterruptOverrunStatus(dev)) { /* interrupt overrun */
+ overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
+ if (overrun) {
DPRINTK
("rtd520: Interrupt overrun with %ld to go! over_status=0x%x\n",
- devpriv->aiCount, 0xffff & RtdInterruptOverrunStatus(dev));
+ devpriv->aiCount, overrun);
goto abortTransfer;
}
/* clear the interrupt */
- RtdInterruptClearMask(dev, status);
- RtdInterruptClear(dev);
+ devpriv->intClearMask = status;
+ writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ readw(devpriv->las0 + LAS0_CLEAR);
return IRQ_HANDLED;
abortTransfer:
- RtdAdcClearFifo(dev); /* clears full flag */
+ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
s->async->events |= COMEDI_CB_ERROR;
devpriv->aiCount = 0; /* stop and don't transfer any more */
/* fall into transferDone */
transferDone:
- RtdPacerStopSource(dev, 0); /* stop on SOFTWARE stop */
- RtdPacerStop(dev); /* Stop PACER */
- RtdAdcConversionSource(dev, 0); /* software trigger only */
- RtdInterruptMask(dev, 0); /* mask out SAMPLE */
+ /* pacer stop source: SOFTWARE */
+ writel(0, devpriv->las0 + LAS0_PACER_STOP);
+ writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
+ writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
+ devpriv->intMask = 0;
+ writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
#ifdef USE_DMA
if (devpriv->flags & DMA0_ACTIVE) {
- RtdPlxInterruptWrite(dev, /* disable any more interrupts */
- RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
+ writel(readl(devpriv->lcfg + LCFG_ITCSR) & ~ICS_DMA0_E,
+ devpriv->lcfg + LCFG_ITCSR);
abort_dma(dev, 0);
devpriv->flags &= ~DMA0_ACTIVE;
/* if Using DMA, then we should have read everything by now */
@@ -1649,7 +926,7 @@ transferDone:
#endif /* USE_DMA */
if (devpriv->aiCount > 0) { /* there shouldn't be anything left */
- fifoStatus = RtdFifoStatus(dev);
+ fifoStatus = readl(devpriv->las0 + LAS0_ADC);
DPRINTK("rtd520: Finishing up. %ld remain, fifoStat=%x\n", devpriv->aiCount, (fifoStatus ^ 0x6666) & 0x7777); /* should read all 0s */
ai_read_dregs(dev, s); /* read anything left in FIFO */
}
@@ -1658,15 +935,16 @@ transferDone:
comedi_event(dev, s);
/* clear the interrupt */
- status = RtdInterruptStatus(dev);
- RtdInterruptClearMask(dev, status);
- RtdInterruptClear(dev);
+ status = readw(devpriv->las0 + LAS0_IT);
+ devpriv->intClearMask = status;
+ writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ readw(devpriv->las0 + LAS0_CLEAR);
- fifoStatus = RtdFifoStatus(dev); /* DEBUG */
+ fifoStatus = readl(devpriv->las0 + LAS0_ADC);
+ overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
DPRINTK
("rtd520: Acquisition complete. %ld ints, intStat=%x, overStat=%x\n",
- devpriv->intCount, status,
- 0xffff & RtdInterruptOverrunStatus(dev));
+ devpriv->intCount, status, overrun);
return IRQ_HANDLED;
}
@@ -1895,28 +1173,33 @@ static int rtd_ai_cmdtest(struct comedi_device *dev,
*/
static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct rtdPrivate *devpriv = dev->private;
struct comedi_cmd *cmd = &s->async->cmd;
int timer;
/* stop anything currently running */
- RtdPacerStopSource(dev, 0); /* stop on SOFTWARE stop */
- RtdPacerStop(dev); /* make sure PACER is stopped */
- RtdAdcConversionSource(dev, 0); /* software trigger only */
- RtdInterruptMask(dev, 0);
+ /* pacer stop source: SOFTWARE */
+ writel(0, devpriv->las0 + LAS0_PACER_STOP);
+ writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
+ writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
+ devpriv->intMask = 0;
+ writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
#ifdef USE_DMA
if (devpriv->flags & DMA0_ACTIVE) { /* cancel anything running */
- RtdPlxInterruptWrite(dev, /* disable any more interrupts */
- RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
+ writel(readl(devpriv->lcfg + LCFG_ITCSR) & ~ICS_DMA0_E,
+ devpriv->lcfg + LCFG_ITCSR);
abort_dma(dev, 0);
devpriv->flags &= ~DMA0_ACTIVE;
- if (RtdPlxInterruptRead(dev) & ICS_DMA0_A) { /*clear pending int */
- RtdDma0Control(dev, PLX_CLEAR_DMA_INTR_BIT);
+ if (readl(devpriv->lcfg + LCFG_ITCSR) & ICS_DMA0_A) {
+ devpriv->dma0Control = PLX_CLEAR_DMA_INTR_BIT;
+ writeb(devpriv->dma0Control,
+ devpriv->lcfg + LCFG_DMACSR0);
}
}
- RtdDma0Reset(dev); /* reset onboard state */
+ writel(0, devpriv->las0 + LAS0_DMA0_RESET);
#endif /* USE_DMA */
- RtdAdcClearFifo(dev); /* clear any old data */
- RtdInterruptOverrunClear(dev);
+ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
+ writel(0, devpriv->las0 + LAS0_OVERRUN);
devpriv->intCount = 0;
if (!dev->irq) { /* we need interrupts for this */
@@ -1931,15 +1214,20 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* setup the common case and override if needed */
if (cmd->chanlist_len > 1) {
/*DPRINTK ("rtd520: Multi channel setup\n"); */
- RtdPacerStartSource(dev, 0); /* software triggers pacer */
- RtdBurstStartSource(dev, 1); /* PACER triggers burst */
- RtdAdcConversionSource(dev, 2); /* BURST triggers ADC */
+ /* pacer start source: SOFTWARE */
+ writel(0, devpriv->las0 + LAS0_PACER_START);
+ /* burst trigger source: PACER */
+ writel(1, devpriv->las0 + LAS0_BURST_START);
+ /* ADC conversion trigger source: BURST */
+ writel(2, devpriv->las0 + LAS0_ADC_CONVERSION);
} else { /* single channel */
/*DPRINTK ("rtd520: single channel setup\n"); */
- RtdPacerStartSource(dev, 0); /* software triggers pacer */
- RtdAdcConversionSource(dev, 1); /* PACER triggers ADC */
+ /* pacer start source: SOFTWARE */
+ writel(0, devpriv->las0 + LAS0_PACER_START);
+ /* ADC conversion trigger source: PACER */
+ writel(1, devpriv->las0 + LAS0_ADC_CONVERSION);
}
- RtdAboutCounter(dev, devpriv->fifoLen / 2 - 1); /* 1/2 FIFO */
+ writel((devpriv->fifoLen / 2 - 1) & 0xffff, devpriv->las0 + LAS0_ACNT);
if (TRIG_TIMER == cmd->scan_begin_src) {
/* scan_begin_arg is in nanoseconds */
@@ -1973,7 +1261,8 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->flags &= ~SEND_EOS;
} else {
/* interrupt for each transfer */
- RtdAboutCounter(dev, devpriv->transCount - 1);
+ writel((devpriv->transCount - 1) & 0xffff,
+ devpriv->las0 + LAS0_ACNT);
}
DPRINTK
@@ -1984,8 +1273,10 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->transCount = 0;
devpriv->flags &= ~SEND_EOS;
}
- RtdPacerClockSource(dev, 1); /* use INTERNAL 8Mhz clock source */
- RtdAboutStopEnable(dev, 1); /* just interrupt, dont stop */
+ /* pacer clock source: INTERNAL 8MHz */
+ writel(1, devpriv->las0 + LAS0_PACER_SELECT);
+ /* just interrupt, don't stop */
+ writel(1, devpriv->las0 + LAS0_ACNT_STOP_ENABLE);
/* BUG??? these look like enumerated values, but they are bit fields */
@@ -2015,12 +1306,13 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
TRIG_ROUND_NEAREST);
/* set PACER clock */
/*DPRINTK ("rtd520: loading %d into pacer\n", timer); */
- RtdPacerCounter(dev, timer);
+ writel(timer & 0xffffff, devpriv->las0 + LAS0_PCLK);
break;
case TRIG_EXT:
- RtdPacerStartSource(dev, 1); /* EXTERNALy trigger pacer */
+ /* pacer start source: EXTERNAL */
+ writel(1, devpriv->las0 + LAS0_PACER_START);
break;
default:
@@ -2036,13 +1328,14 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
TRIG_ROUND_NEAREST);
/* setup BURST clock */
/*DPRINTK ("rtd520: loading %d into burst\n", timer); */
- RtdBurstCounter(dev, timer);
+ writel(timer & 0x3ff, devpriv->las0 + LAS0_BCLK);
}
break;
case TRIG_EXT: /* external */
- RtdBurstStartSource(dev, 2); /* EXTERNALy trigger burst */
+ /* burst trigger source: EXTERNAL */
+ writel(2, devpriv->las0 + LAS0_BURST_START);
break;
default:
@@ -2053,12 +1346,14 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* This doesn't seem to work. There is no way to clear an interrupt
that the priority controller has queued! */
- RtdInterruptClearMask(dev, ~0); /* clear any existing flags */
- RtdInterruptClear(dev);
+ devpriv->intClearMask = ~0;
+ writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ readw(devpriv->las0 + LAS0_CLEAR);
/* TODO: allow multiple interrupt sources */
if (devpriv->transCount > 0) { /* transfer every N samples */
- RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
+ devpriv->intMask = IRQM_ADC_ABOUT_CNT;
+ writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
DPRINTK("rtd520: Transferring every %d\n", devpriv->transCount);
} else { /* 1/2 FIFO transfers */
#ifdef USE_DMA
@@ -2066,27 +1361,32 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* point to first transfer in ring */
devpriv->dma0Offset = 0;
- RtdDma0Mode(dev, DMA_MODE_BITS);
- RtdDma0Next(dev, /* point to first block */
- devpriv->dma0Chain[DMA_CHAIN_COUNT - 1].next);
- RtdDma0Source(dev, DMAS_ADFIFO_HALF_FULL); /* set DMA trigger source */
-
- RtdPlxInterruptWrite(dev, /* enable interrupt */
- RtdPlxInterruptRead(dev) | ICS_DMA0_E);
+ writel(DMA_MODE_BITS, devpriv->lcfg + LCFG_DMAMODE0);
+ /* point to first block */
+ writel(devpriv->dma0Chain[DMA_CHAIN_COUNT - 1].next,
+ devpriv->lcfg + LCFG_DMADPR0);
+ writel(DMAS_ADFIFO_HALF_FULL, devpriv->las0 + LAS0_DMA0_SRC);
+ writel(readl(devpriv->lcfg + LCFG_ITCSR) | ICS_DMA0_E,
+ devpriv->lcfg + LCFG_ITCSR);
/* Must be 2 steps. See PLX app note about "Starting a DMA transfer" */
- RtdDma0Control(dev, PLX_DMA_EN_BIT); /* enable DMA (clear INTR?) */
- RtdDma0Control(dev, PLX_DMA_EN_BIT | PLX_DMA_START_BIT); /*start DMA */
+ devpriv->dma0Control = PLX_DMA_EN_BIT;
+ writeb(devpriv->dma0Control,
+ devpriv->lcfg + LCFG_DMACSR0);
+ devpriv->dma0Control |= PLX_DMA_START_BIT;
+ writeb(devpriv->dma0Control,
+ devpriv->lcfg + LCFG_DMACSR0);
DPRINTK("rtd520: Using DMA0 transfers. plxInt %x RtdInt %x\n",
- RtdPlxInterruptRead(dev), devpriv->intMask);
+ readl(devpriv->lcfg + LCFG_ITCSR), devpriv->intMask);
#else /* USE_DMA */
- RtdInterruptMask(dev, IRQM_ADC_ABOUT_CNT);
+ devpriv->intMask = IRQM_ADC_ABOUT_CNT;
+ writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
DPRINTK("rtd520: Transferring every 1/2 FIFO\n");
#endif /* USE_DMA */
}
/* BUG: start_src is ASSUMED to be TRIG_NOW */
/* BUG? it seems like things are running before the "start" */
- RtdPacerStart(dev); /* Start PACER */
+ readl(devpriv->las0 + LAS0_PACER); /* start pacer */
return 0;
}
@@ -2095,85 +1395,48 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
*/
static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
+ struct rtdPrivate *devpriv = dev->private;
+ u32 overrun;
u16 status;
- RtdPacerStopSource(dev, 0); /* stop on SOFTWARE stop */
- RtdPacerStop(dev); /* Stop PACER */
- RtdAdcConversionSource(dev, 0); /* software trigger only */
- RtdInterruptMask(dev, 0);
+ /* pacer stop source: SOFTWARE */
+ writel(0, devpriv->las0 + LAS0_PACER_STOP);
+ writel(0, devpriv->las0 + LAS0_PACER); /* stop pacer */
+ writel(0, devpriv->las0 + LAS0_ADC_CONVERSION);
+ devpriv->intMask = 0;
+ writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
devpriv->aiCount = 0; /* stop and don't transfer any more */
#ifdef USE_DMA
if (devpriv->flags & DMA0_ACTIVE) {
- RtdPlxInterruptWrite(dev, /* disable any more interrupts */
- RtdPlxInterruptRead(dev) & ~ICS_DMA0_E);
+ writel(readl(devpriv->lcfg + LCFG_ITCSR) & ~ICS_DMA0_E,
+ devpriv->lcfg + LCFG_ITCSR);
abort_dma(dev, 0);
devpriv->flags &= ~DMA0_ACTIVE;
}
#endif /* USE_DMA */
- status = RtdInterruptStatus(dev);
+ status = readw(devpriv->las0 + LAS0_IT);
+ overrun = readl(devpriv->las0 + LAS0_OVERRUN) & 0xffff;
DPRINTK
("rtd520: Acquisition canceled. %ld ints, intStat=%x, overStat=%x\n",
- devpriv->intCount, status,
- 0xffff & RtdInterruptOverrunStatus(dev));
+ devpriv->intCount, status, overrun);
return 0;
}
/*
- Given a desired period and the clock period (both in ns),
- return the proper counter value (divider-1).
- Sets the original period to be the true value.
- Note: you have to check if the value is larger than the counter range!
-*/
-static int rtd_ns_to_timer_base(unsigned int *nanosec, /* desired period (in ns) */
- int round_mode, int base)
-{ /* clock period (in ns) */
- int divider;
-
- switch (round_mode) {
- case TRIG_ROUND_NEAREST:
- default:
- divider = (*nanosec + base / 2) / base;
- break;
- case TRIG_ROUND_DOWN:
- divider = (*nanosec) / base;
- break;
- case TRIG_ROUND_UP:
- divider = (*nanosec + base - 1) / base;
- break;
- }
- if (divider < 2)
- divider = 2; /* min is divide by 2 */
-
- /* Note: we don't check for max, because different timers
- have different ranges */
-
- *nanosec = base * divider;
- return divider - 1; /* countdown is divisor+1 */
-}
-
-/*
- Given a desired period (in ns),
- return the proper counter value (divider-1) for the internal clock.
- Sets the original period to be the true value.
-*/
-static int rtd_ns_to_timer(unsigned int *ns, int round_mode)
-{
- return rtd_ns_to_timer_base(ns, round_mode, RTD_CLOCK_BASE);
-}
-
-/*
Output one (or more) analog values to a single port as fast as possible.
*/
static int rtd_ao_winsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
+ struct rtdPrivate *devpriv = dev->private;
int i;
int chan = CR_CHAN(insn->chanspec);
int range = CR_RANGE(insn->chanspec);
/* Configure the output range (table index matches the range values) */
- RtdDacRange(dev, chan, range);
+ writew(range & 7, devpriv->las0 +
+ ((chan == 0) ? LAS0_DAC1_CTRL : LAS0_DAC2_CTRL));
/* Writing a list of values to an AO channel is probably not
* very useful, but that's how the interface is defined. */
@@ -2197,13 +1460,14 @@ static int rtd_ao_winsn(struct comedi_device *dev,
chan, range, data[i], val);
/* a typical programming sequence */
- RtdDacFifoPut(dev, chan, val); /* put the value in */
- RtdDacUpdate(dev, chan); /* trigger the conversion */
+ writew(val, devpriv->las1 +
+ ((chan == 0) ? LAS1_DAC1_FIFO : LAS1_DAC2_FIFO));
+ writew(0, devpriv->las0 + ((chan == 0) ? LAS0_DAC1 : LAS0_DAC2));
devpriv->aoValue[chan] = data[i]; /* save for read back */
for (ii = 0; ii < RTD_DAC_TIMEOUT; ++ii) {
- stat = RtdFifoStatus(dev);
+ stat = readl(devpriv->las0 + LAS0_ADC);
/* 1 -> not empty */
if (stat & ((0 == chan) ? FS_DAC1_NOT_EMPTY :
FS_DAC2_NOT_EMPTY))
@@ -2228,6 +1492,7 @@ static int rtd_ao_rinsn(struct comedi_device *dev,
struct comedi_subdevice *s, struct comedi_insn *insn,
unsigned int *data)
{
+ struct rtdPrivate *devpriv = dev->private;
int i;
int chan = CR_CHAN(insn->chanspec);
@@ -2252,8 +1517,7 @@ static int rtd_dio_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
- if (insn->n != 2)
- return -EINVAL;
+ struct rtdPrivate *devpriv = dev->private;
/* The insn data is a mask in data[0] and the new data
* in data[1], each channel cooresponding to a bit. */
@@ -2262,15 +1526,15 @@ static int rtd_dio_insn_bits(struct comedi_device *dev,
s->state |= data[0] & data[1];
/* Write out the new digital output lines */
- RtdDio0Write(dev, s->state);
+ writew(s->state & 0xff, devpriv->las0 + LAS0_DIO0);
}
/* on return, data[1] contains the value of the digital
* input lines. */
- data[1] = RtdDio0Read(dev);
+ data[1] = readw(devpriv->las0 + LAS0_DIO0) & 0xff;
/*DPRINTK("rtd520:port_0 wrote: 0x%x read: 0x%x\n", s->state, data[1]); */
- return 2;
+ return insn->n;
}
/*
@@ -2280,6 +1544,7 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn, unsigned int *data)
{
+ struct rtdPrivate *devpriv = dev->private;
int chan = CR_CHAN(insn->chanspec);
/* The input or output configuration of each digital line is
@@ -2304,9 +1569,11 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
DPRINTK("rtd520: port_0_direction=0x%x (1 means out)\n", s->io_bits);
/* TODO support digital match interrupts and strobes */
- RtdDioStatusWrite(dev, 0x01); /* make Dio0Ctrl point to direction */
- RtdDio0CtrlWrite(dev, s->io_bits); /* set direction 1 means Out */
- RtdDioStatusWrite(dev, 0); /* make Dio0Ctrl clear interrupts */
+ devpriv->dioStatus = 0x01; /* set direction */
+ writew(devpriv->dioStatus, devpriv->las0 + LAS0_DIO_STATUS);
+ writew(s->io_bits & 0xff, devpriv->las0 + LAS0_DIO0_CTRL);
+ devpriv->dioStatus = 0x00; /* clear interrupts */
+ writew(devpriv->dioStatus, devpriv->las0 + LAS0_DIO_STATUS);
/* port1 can only be all input or all output */
@@ -2315,6 +1582,382 @@ static int rtd_dio_insn_config(struct comedi_device *dev,
return 1;
}
+static struct pci_dev *rtd_find_pci(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ const struct rtdBoard *thisboard;
+ struct pci_dev *pcidev = NULL;
+ int bus = it->options[0];
+ int slot = it->options[1];
+ int i;
+
+ for_each_pci_dev(pcidev) {
+ if (pcidev->vendor != PCI_VENDOR_ID_RTD)
+ continue;
+ if (bus || slot) {
+ if (pcidev->bus->number != bus ||
+ PCI_SLOT(pcidev->devfn) != slot)
+ continue;
+ }
+ for (i = 0; i < ARRAY_SIZE(rtd520Boards); i++) {
+ thisboard = &rtd520Boards[i];
+ if (pcidev->device == thisboard->device_id) {
+ dev->board_ptr = thisboard;
+ return pcidev;
+ }
+ }
+ }
+ dev_warn(dev->class_dev,
+ "no supported board found! (req. bus/slot: %d/%d)\n",
+ bus, slot);
+ return NULL;
+}
+
+static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it)
+{ /* board name and options flags */
+ const struct rtdBoard *thisboard;
+ struct rtdPrivate *devpriv;
+ struct pci_dev *pcidev;
+ struct comedi_subdevice *s;
+ int ret;
+ resource_size_t physLas1; /* data area */
+ resource_size_t physLcfg; /* PLX9080 */
+#ifdef USE_DMA
+ int index;
+#endif
+
+ printk(KERN_INFO "comedi%d: rtd520 attaching.\n", dev->minor);
+
+#if defined(CONFIG_COMEDI_DEBUG) && defined(USE_DMA)
+ /* You can set this a load time: modprobe comedi comedi_debug=1 */
+ if (0 == comedi_debug) /* force DMA debug printks */
+ comedi_debug = 1;
+#endif
+
+ /*
+ * Allocate the private structure area. alloc_private() is a
+ * convenient macro defined in comedidev.h.
+ */
+ if (alloc_private(dev, sizeof(struct rtdPrivate)) < 0)
+ return -ENOMEM;
+ devpriv = dev->private;
+
+ pcidev = rtd_find_pci(dev, it);
+ if (!pcidev)
+ return -EIO;
+ comedi_set_hw_dev(dev, &pcidev->dev);
+ thisboard = comedi_board(dev);
+
+ dev->board_name = thisboard->name;
+
+ ret = comedi_pci_enable(pcidev, DRV_NAME);
+ if (ret < 0) {
+ printk(KERN_INFO "Failed to enable PCI device and request regions.\n");
+ return ret;
+ }
+
+ /*
+ * Initialize base addresses
+ */
+ /* Get the physical address from PCI config */
+ dev->iobase = pci_resource_start(pcidev, LAS0_PCIINDEX);
+ physLas1 = pci_resource_start(pcidev, LAS1_PCIINDEX);
+ physLcfg = pci_resource_start(pcidev, LCFG_PCIINDEX);
+ /* Now have the kernel map this into memory */
+ /* ASSUME page aligned */
+ devpriv->las0 = ioremap_nocache(dev->iobase, LAS0_PCISIZE);
+ devpriv->las1 = ioremap_nocache(physLas1, LAS1_PCISIZE);
+ devpriv->lcfg = ioremap_nocache(physLcfg, LCFG_PCISIZE);
+
+ if (!devpriv->las0 || !devpriv->las1 || !devpriv->lcfg)
+ return -ENOMEM;
+
+ { /* The RTD driver does this */
+ unsigned char pci_latency;
+ u16 revision;
+ /*uint32_t epld_version; */
+
+ pci_read_config_word(pcidev, PCI_REVISION_ID,
+ &revision);
+ DPRINTK("%s: PCI revision %d.\n", dev->board_name, revision);
+
+ pci_read_config_byte(pcidev,
+ PCI_LATENCY_TIMER, &pci_latency);
+ if (pci_latency < 32) {
+ printk(KERN_INFO "%s: PCI latency changed from %d to %d\n",
+ dev->board_name, pci_latency, 32);
+ pci_write_config_byte(pcidev,
+ PCI_LATENCY_TIMER, 32);
+ } else {
+ DPRINTK("rtd520: PCI latency = %d\n", pci_latency);
+ }
+
+ /*
+ * Undocumented EPLD version (doesn't match RTD driver results)
+ */
+ /*DPRINTK ("rtd520: Reading epld from %p\n",
+ devpriv->las0+0);
+ epld_version = readl (devpriv->las0+0);
+ if ((epld_version & 0xF0) >> 4 == 0x0F) {
+ DPRINTK("rtd520: pre-v8 EPLD. (%x)\n", epld_version);
+ } else {
+ DPRINTK("rtd520: EPLD version %x.\n", epld_version >> 4);
+ } */
+ }
+
+ /* Show board configuration */
+ printk(KERN_INFO "%s:", dev->board_name);
+
+ ret = comedi_alloc_subdevices(dev, 4);
+ if (ret)
+ return ret;
+
+ s = dev->subdevices + 0;
+ dev->read_subdev = s;
+ /* analog input subdevice */
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags =
+ SDF_READABLE | SDF_GROUND | SDF_COMMON | SDF_DIFF | SDF_CMD_READ;
+ s->n_chan = thisboard->aiChans;
+ s->maxdata = (1 << thisboard->aiBits) - 1;
+ if (thisboard->aiMaxGain <= 32)
+ s->range_table = &rtd_ai_7520_range;
+ else
+ s->range_table = &rtd_ai_4520_range;
+
+ s->len_chanlist = RTD_MAX_CHANLIST; /* devpriv->fifoLen */
+ s->insn_read = rtd_ai_rinsn;
+ s->do_cmd = rtd_ai_cmd;
+ s->do_cmdtest = rtd_ai_cmdtest;
+ s->cancel = rtd_ai_cancel;
+ /* s->poll = rtd_ai_poll; *//* not ready yet */
+
+ s = dev->subdevices + 1;
+ /* analog output subdevice */
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 2;
+ s->maxdata = (1 << thisboard->aiBits) - 1;
+ s->range_table = &rtd_ao_range;
+ s->insn_write = rtd_ao_winsn;
+ s->insn_read = rtd_ao_rinsn;
+
+ s = dev->subdevices + 2;
+ /* digital i/o subdevice */
+ s->type = COMEDI_SUBD_DIO;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ /* we only support port 0 right now. Ignoring port 1 and user IO */
+ s->n_chan = 8;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = rtd_dio_insn_bits;
+ s->insn_config = rtd_dio_insn_config;
+
+ /* timer/counter subdevices (not currently supported) */
+ s = dev->subdevices + 3;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 3;
+ s->maxdata = 0xffff;
+
+ /* initialize board, per RTD spec */
+ /* also, initialize shadow registers */
+ writel(0, devpriv->las0 + LAS0_BOARD_RESET);
+ udelay(100); /* needed? */
+ writel(0, devpriv->lcfg + LCFG_ITCSR);
+ devpriv->intMask = 0;
+ writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
+ devpriv->intClearMask = ~0;
+ writew(devpriv->intClearMask, devpriv->las0 + LAS0_CLEAR);
+ readw(devpriv->las0 + LAS0_CLEAR);
+ writel(0, devpriv->las0 + LAS0_OVERRUN);
+ writel(0, devpriv->las0 + LAS0_CGT_CLEAR);
+ writel(0, devpriv->las0 + LAS0_ADC_FIFO_CLEAR);
+ writel(0, devpriv->las0 + LAS0_DAC1_RESET);
+ writel(0, devpriv->las0 + LAS0_DAC2_RESET);
+ /* clear digital IO fifo */
+ devpriv->dioStatus = 0;
+ writew(devpriv->dioStatus, devpriv->las0 + LAS0_DIO_STATUS);
+ devpriv->utcCtrl[0] = (0 << 6) | 0x30;
+ devpriv->utcCtrl[1] = (1 << 6) | 0x30;
+ devpriv->utcCtrl[2] = (2 << 6) | 0x30;
+ devpriv->utcCtrl[3] = (3 << 6) | 0x00;
+ writeb(devpriv->utcCtrl[0], devpriv->las0 + LAS0_UTC_CTRL);
+ writeb(devpriv->utcCtrl[1], devpriv->las0 + LAS0_UTC_CTRL);
+ writeb(devpriv->utcCtrl[2], devpriv->las0 + LAS0_UTC_CTRL);
+ writeb(devpriv->utcCtrl[3], devpriv->las0 + LAS0_UTC_CTRL);
+ /* TODO: set user out source ??? */
+
+ /* check if our interrupt is available and get it */
+ ret = request_irq(pcidev->irq, rtd_interrupt,
+ IRQF_SHARED, DRV_NAME, dev);
+
+ if (ret < 0) {
+ printk("Could not get interrupt! (%u)\n",
+ pcidev->irq);
+ return ret;
+ }
+ dev->irq = pcidev->irq;
+ printk(KERN_INFO "( irq=%u )", dev->irq);
+
+ ret = rtd520_probe_fifo_depth(dev);
+ if (ret < 0)
+ return ret;
+
+ devpriv->fifoLen = ret;
+ printk("( fifoLen=%d )", devpriv->fifoLen);
+
+#ifdef USE_DMA
+ if (dev->irq > 0) {
+ printk("( DMA buff=%d )\n", DMA_CHAIN_COUNT);
+ /*
+ * The PLX9080 has 2 DMA controllers, but there could be
+ * 4 sources: ADC, digital, DAC1, and DAC2. Since only the
+ * ADC supports cmd mode right now, this isn't an issue (yet)
+ */
+ devpriv->dma0Offset = 0;
+
+ for (index = 0; index < DMA_CHAIN_COUNT; index++) {
+ devpriv->dma0Buff[index] =
+ pci_alloc_consistent(pcidev,
+ sizeof(u16) *
+ devpriv->fifoLen / 2,
+ &devpriv->
+ dma0BuffPhysAddr[index]);
+ if (devpriv->dma0Buff[index] == NULL) {
+ ret = -ENOMEM;
+ goto rtd_attach_die_error;
+ }
+ /*DPRINTK ("buff[%d] @ %p virtual, %x PCI\n",
+ index,
+ devpriv->dma0Buff[index],
+ devpriv->dma0BuffPhysAddr[index]); */
+ }
+
+ /*
+ * setup DMA descriptor ring (use cpu_to_le32 for byte
+ * ordering?)
+ */
+ devpriv->dma0Chain =
+ pci_alloc_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ DMA_CHAIN_COUNT,
+ &devpriv->dma0ChainPhysAddr);
+ for (index = 0; index < DMA_CHAIN_COUNT; index++) {
+ devpriv->dma0Chain[index].pci_start_addr =
+ devpriv->dma0BuffPhysAddr[index];
+ devpriv->dma0Chain[index].local_start_addr =
+ DMALADDR_ADC;
+ devpriv->dma0Chain[index].transfer_size =
+ sizeof(u16) * devpriv->fifoLen / 2;
+ devpriv->dma0Chain[index].next =
+ (devpriv->dma0ChainPhysAddr + ((index +
+ 1) %
+ (DMA_CHAIN_COUNT))
+ * sizeof(devpriv->dma0Chain[0]))
+ | DMA_TRANSFER_BITS;
+ /*DPRINTK ("ring[%d] @%lx PCI: %x, local: %x, N: 0x%x, next: %x\n",
+ index,
+ ((long)devpriv->dma0ChainPhysAddr
+ + (index * sizeof(devpriv->dma0Chain[0]))),
+ devpriv->dma0Chain[index].pci_start_addr,
+ devpriv->dma0Chain[index].local_start_addr,
+ devpriv->dma0Chain[index].transfer_size,
+ devpriv->dma0Chain[index].next); */
+ }
+
+ if (devpriv->dma0Chain == NULL) {
+ ret = -ENOMEM;
+ goto rtd_attach_die_error;
+ }
+
+ writel(DMA_MODE_BITS, devpriv->lcfg + LCFG_DMAMODE0);
+ /* set DMA trigger source */
+ writel(DMAS_ADFIFO_HALF_FULL, devpriv->las0 + LAS0_DMA0_SRC);
+ } else {
+ printk(KERN_INFO "( no IRQ->no DMA )");
+ }
+#endif /* USE_DMA */
+
+ if (dev->irq)
+ writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + LCFG_ITCSR);
+
+ printk("\ncomedi%d: rtd520 driver attached.\n", dev->minor);
+
+ return 1;
+}
+
+static void rtd_detach(struct comedi_device *dev)
+{
+ struct rtdPrivate *devpriv = dev->private;
+ struct pci_dev *pcidev = comedi_to_pci_dev(dev);
+#ifdef USE_DMA
+ int index;
+#endif
+
+ if (devpriv) {
+ /* Shut down any board ops by resetting it */
+#ifdef USE_DMA
+ if (devpriv->lcfg) {
+ devpriv->dma0Control = 0;
+ devpriv->dma1Control = 0;
+ writeb(devpriv->dma0Control,
+ devpriv->lcfg + LCFG_DMACSR0);
+ writeb(devpriv->dma1Control,
+ devpriv->lcfg + LCFG_DMACSR1);
+ writel(ICS_PIE | ICS_PLIE, devpriv->lcfg + LCFG_ITCSR);
+ }
+#endif /* USE_DMA */
+ if (devpriv->las0) {
+ writel(0, devpriv->las0 + LAS0_BOARD_RESET);
+ devpriv->intMask = 0;
+ writew(devpriv->intMask, devpriv->las0 + LAS0_IT);
+ devpriv->intClearMask = ~0;
+ writew(devpriv->intClearMask,
+ devpriv->las0 + LAS0_CLEAR);
+ readw(devpriv->las0 + LAS0_CLEAR);
+ }
+#ifdef USE_DMA
+ /* release DMA */
+ for (index = 0; index < DMA_CHAIN_COUNT; index++) {
+ if (NULL != devpriv->dma0Buff[index]) {
+ pci_free_consistent(pcidev,
+ sizeof(u16) *
+ devpriv->fifoLen / 2,
+ devpriv->dma0Buff[index],
+ devpriv->
+ dma0BuffPhysAddr[index]);
+ devpriv->dma0Buff[index] = NULL;
+ }
+ }
+ if (NULL != devpriv->dma0Chain) {
+ pci_free_consistent(pcidev,
+ sizeof(struct plx_dma_desc) *
+ DMA_CHAIN_COUNT, devpriv->dma0Chain,
+ devpriv->dma0ChainPhysAddr);
+ devpriv->dma0Chain = NULL;
+ }
+#endif /* USE_DMA */
+ if (dev->irq) {
+ writel(readl(devpriv->lcfg + LCFG_ITCSR) &
+ ~(ICS_PLIE | ICS_DMA0_E | ICS_DMA1_E),
+ devpriv->lcfg + LCFG_ITCSR);
+ free_irq(dev->irq, dev);
+ }
+ if (devpriv->las0)
+ iounmap(devpriv->las0);
+ if (devpriv->las1)
+ iounmap(devpriv->las1);
+ if (devpriv->lcfg)
+ iounmap(devpriv->lcfg);
+ }
+ if (pcidev) {
+ if (dev->iobase)
+ comedi_pci_disable(pcidev);
+ pci_dev_put(pcidev);
+ }
+}
+
static struct comedi_driver rtd520_driver = {
.driver_name = "rtd520",
.module = THIS_MODULE,