linux/drivers/comedi/drivers/rtd520.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * comedi/drivers/rtd520.c
 * Comedi driver for Real Time Devices (RTD) PCI4520/DM7520
 *
 * COMEDI - Linux Control and Measurement Device Interface
 * Copyright (C) 2001 David A. Schleef <[email protected]>
 */

/*
 * Driver: rtd520
 * Description: Real Time Devices PCI4520/DM7520
 * Devices: [Real Time Devices] DM7520HR-1 (DM7520), DM7520HR-8,
 *   PCI4520 (PCI4520), PCI4520-8
 * Author: Dan Christian
 * Status: Works. Only tested on DM7520-8. Not SMP safe.
 *
 * Configuration options: not applicable, uses PCI auto config
 */

/*
 * Created by Dan Christian, NASA Ames Research Center.
 *
 * The PCI4520 is a PCI card. The DM7520 is a PC/104-plus card.
 * Both have:
 *   8/16 12 bit ADC with FIFO and channel gain table
 *   8 bits high speed digital out (for external MUX) (or 8 in or 8 out)
 *   8 bits high speed digital in with FIFO and interrupt on change (or 8 IO)
 *   2 12 bit DACs with FIFOs
 *   2 bits output
 *   2 bits input
 *   bus mastering DMA
 *   timers: ADC sample, pacer, burst, about, delay, DA1, DA2
 *   sample counter
 *   3 user timer/counters (8254)
 *   external interrupt
 *
 * The DM7520 has slightly fewer features (fewer gain steps).
 *
 * These boards can support external multiplexors and multi-board
 * synchronization, but this driver doesn't support that.
 *
 * Board docs: http://www.rtdusa.com/PC104/DM/analog%20IO/dm7520.htm
 * Data sheet: http://www.rtdusa.com/pdf/dm7520.pdf
 * Example source: http://www.rtdusa.com/examples/dm/dm7520.zip
 * Call them and ask for the register level manual.
 * PCI chip: http://www.plxtech.com/products/io/pci9080
 *
 * Notes:
 * This board is memory mapped. There is some IO stuff, but it isn't needed.
 *
 * I use a pretty loose naming style within the driver (rtd_blah).
 * All externally visible names should be rtd520_blah.
 * I use camelCase for structures (and inside them).
 * I may also use upper CamelCase for function names (old habit).
 *
 * This board is somewhat related to the RTD PCI4400 board.
 *
 * I borrowed heavily from the ni_mio_common, ni_atmio16d, mite, and
 * das1800, since they have the best documented code. Driver cb_pcidas64.c
 * uses the same DMA controller.
 *
 * As far as I can tell, the About interrupt doesn't work if Sample is
 * also enabled. It turns out that About really isn't needed, since
 * we always count down samples read.
 */

/*
 * driver status:
 *
 * Analog-In supports instruction and command mode.
 *
 * With DMA, you can sample at 1.15Mhz with 70% idle on a 400Mhz K6-2
 * (single channel, 64K read buffer). I get random system lockups when
 * using DMA with ALI-15xx based systems. I haven't been able to test
 * any other chipsets. The lockups happen soon after the start of an
 * acquistion, not in the middle of a long run.
 *
 * Without DMA, you can do 620Khz sampling with 20% idle on a 400Mhz K6-2
 * (with a 256K read buffer).
 *
 * Digital-IO and Analog-Out only support instruction mode.
 */

#include <linux/module.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/comedi/comedi_pci.h>
#include <linux/comedi/comedi_8254.h>

#include "plx9080.h"

/*
 * Local Address Space 0 Offsets
 */
#define LAS0_USER_IO
#define LAS0_ADC
#define FS_DAC1_NOT_EMPTY
#define FS_DAC1_HEMPTY
#define FS_DAC1_NOT_FULL
#define FS_DAC2_NOT_EMPTY
#define FS_DAC2_HEMPTY
#define FS_DAC2_NOT_FULL
#define FS_ADC_NOT_EMPTY
#define FS_ADC_HEMPTY
#define FS_ADC_NOT_FULL
#define FS_DIN_NOT_EMPTY
#define FS_DIN_HEMPTY
#define FS_DIN_NOT_FULL
#define LAS0_UPDATE_DAC(x)
#define LAS0_DAC
#define LAS0_PACER
#define LAS0_TIMER
#define LAS0_IT
#define IRQM_ADC_FIFO_WRITE
#define IRQM_CGT_RESET
#define IRQM_CGT_PAUSE
#define IRQM_ADC_ABOUT_CNT
#define IRQM_ADC_DELAY_CNT
#define IRQM_ADC_SAMPLE_CNT
#define IRQM_DAC1_UCNT
#define IRQM_DAC2_UCNT
#define IRQM_UTC1
#define IRQM_UTC1_INV
#define IRQM_UTC2
#define IRQM_DIGITAL_IT
#define IRQM_EXTERNAL_IT
#define IRQM_ETRIG_RISING
#define IRQM_ETRIG_FALLING
#define LAS0_CLEAR
#define LAS0_OVERRUN
#define LAS0_PCLK
#define LAS0_BCLK
#define LAS0_ADC_SCNT
#define LAS0_DAC1_UCNT
#define LAS0_DAC2_UCNT
#define LAS0_DCNT
#define LAS0_ACNT
#define LAS0_DAC_CLK
#define LAS0_8254_TIMER_BASE
#define LAS0_DIO0
#define LAS0_DIO1
#define LAS0_DIO0_CTRL
#define LAS0_DIO_STATUS
#define LAS0_BOARD_RESET
#define LAS0_DMA0_SRC
#define LAS0_DMA1_SRC
#define LAS0_ADC_CONVERSION
#define LAS0_BURST_START
#define LAS0_PACER_START
#define LAS0_PACER_STOP
#define LAS0_ACNT_STOP_ENABLE
#define LAS0_PACER_REPEAT
#define LAS0_DIN_START
#define LAS0_DIN_FIFO_CLEAR
#define LAS0_ADC_FIFO_CLEAR
#define LAS0_CGT_WRITE
#define LAS0_CGL_WRITE
#define LAS0_CG_DATA
#define LAS0_CGT_ENABLE
#define LAS0_CG_ENABLE
#define LAS0_CGT_PAUSE
#define LAS0_CGT_RESET
#define LAS0_CGT_CLEAR
#define LAS0_DAC_CTRL(x)
#define LAS0_DAC_SRC(x)
#define LAS0_DAC_CYCLE(x)
#define LAS0_DAC_RESET(x)
#define LAS0_DAC_FIFO_CLEAR(x)
#define LAS0_ADC_SCNT_SRC
#define LAS0_PACER_SELECT
#define LAS0_SBUS0_SRC
#define LAS0_SBUS0_ENABLE
#define LAS0_SBUS1_SRC
#define LAS0_SBUS1_ENABLE
#define LAS0_SBUS2_SRC
#define LAS0_SBUS2_ENABLE
#define LAS0_ETRG_POLARITY
#define LAS0_EINT_POLARITY
#define LAS0_8254_CLK_SEL(x)
#define LAS0_8254_GATE_SEL(x)
#define LAS0_UOUT0_SELECT
#define LAS0_UOUT1_SELECT
#define LAS0_DMA0_RESET
#define LAS0_DMA1_RESET

/*
 * Local Address Space 1 Offsets
 */
#define LAS1_ADC_FIFO
#define LAS1_HDIO_FIFO
#define LAS1_DAC_FIFO(x)

/*
 * Driver specific stuff (tunable)
 */

/*
 * We really only need 2 buffers.  More than that means being much
 * smarter about knowing which ones are full.
 */
#define DMA_CHAIN_COUNT

/* Target period for periodic transfers.  This sets the user read latency. */
/* Note: There are certain rates where we give this up and transfer 1/2 FIFO */
/* If this is too low, efficiency is poor */
#define TRANS_TARGET_PERIOD

/* Set a practical limit on how long a list to support (affects memory use) */
/* The board support a channel list up to the FIFO length (1K or 8K) */
#define RTD_MAX_CHANLIST

/*
 * Board specific stuff
 */

#define RTD_CLOCK_RATE
#define RTD_CLOCK_BASE

/* Note: these speed are slower than the spec, but fit the counter resolution*/
#define RTD_MAX_SPEED
/* max speed if we don't have to wait for settling */
#define RTD_MAX_SPEED_1

#define RTD_MIN_SPEED
/* min speed when only 1 channel (no burst counter) */
#define RTD_MIN_SPEED_1

/* Setup continuous ring of 1/2 FIFO transfers.  See RTD manual p91 */
#define DMA_MODE_BITS

#define DMA_TRANSFER_BITS

/*
 * Comedi specific stuff
 */

/*
 * 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 =;

/* PCI4520 has two more gains (6 more entries) */
static const struct comedi_lrange rtd_ai_4520_range =;

/* Table order matches range values */
static const struct comedi_lrange rtd_ao_range =;

enum rtd_boardid {};

struct rtd_boardinfo {};

static const struct rtd_boardinfo rtd520_boards[] =;

struct rtd_private {};

/* bit defines for "flags" */
#define SEND_EOS
#define DMA0_ACTIVE
#define DMA1_ACTIVE

/*
 * 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,
				unsigned int flags, int base)
{}

/*
 * 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, unsigned int flags)
{}

/* Convert a single comedi channel-gain entry to a RTD520 table entry */
static unsigned short rtd_convert_chan_gain(struct comedi_device *dev,
					    unsigned int chanspec, int index)
{}

/* Setup the channel-gain table from a comedi list */
static void rtd_load_channelgain_list(struct comedi_device *dev,
				      unsigned int n_chan, unsigned int *list)
{}

/*
 * Determine fifo size by doing adc conversions until the fifo half
 * empty status flag clears.
 */
static int rtd520_probe_fifo_depth(struct comedi_device *dev)
{}

static int rtd_ai_eoc(struct comedi_device *dev,
		      struct comedi_subdevice *s,
		      struct comedi_insn *insn,
		      unsigned long context)
{}

static int rtd_ai_rinsn(struct comedi_device *dev,
			struct comedi_subdevice *s, struct comedi_insn *insn,
			unsigned int *data)
{}

static int ai_read_n(struct comedi_device *dev, struct comedi_subdevice *s,
		     int count)
{}

static irqreturn_t rtd_interrupt(int irq, void *d)
{}

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_ao_eoc(struct comedi_device *dev,
		      struct comedi_subdevice *s,
		      struct comedi_insn *insn,
		      unsigned long context)
{}

static int rtd_ao_insn_write(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_counter_insn_config(struct comedi_device *dev,
				   struct comedi_subdevice *s,
				   struct comedi_insn *insn,
				   unsigned int *data)
{}

static void rtd_reset(struct comedi_device *dev)
{}

/*
 * initialize board, per RTD spec
 * also, initialize shadow registers
 */
static void rtd_init_board(struct comedi_device *dev)
{}

/* The RTD driver does this */
static void rtd_pci_latency_quirk(struct comedi_device *dev,
				  struct pci_dev *pcidev)
{}

static int rtd_auto_attach(struct comedi_device *dev,
			   unsigned long context)
{}

static void rtd_detach(struct comedi_device *dev)
{}

static struct comedi_driver rtd520_driver =;

static int rtd520_pci_probe(struct pci_dev *dev,
			    const struct pci_device_id *id)
{}

static const struct pci_device_id rtd520_pci_table[] =;
MODULE_DEVICE_TABLE(pci, rtd520_pci_table);

static struct pci_driver rtd520_pci_driver =;
module_comedi_pci_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();