linux/drivers/comedi/drivers/amplc_pci230.c

// SPDX-License-Identifier: GPL-2.0+
/*
 * comedi/drivers/amplc_pci230.c
 * Driver for Amplicon PCI230 and PCI260 Multifunction I/O boards.
 *
 * Copyright (C) 2001 Allan Willcox <[email protected]>
 *
 * COMEDI - Linux Control and Measurement Device Interface
 * Copyright (C) 2000 David A. Schleef <[email protected]>
 */

/*
 * Driver: amplc_pci230
 * Description: Amplicon PCI230, PCI260 Multifunction I/O boards
 * Author: Allan Willcox <[email protected]>,
 *   Steve D Sharples <[email protected]>,
 *   Ian Abbott <[email protected]>
 * Updated: Mon, 01 Sep 2014 10:09:16 +0000
 * Devices: [Amplicon] PCI230 (amplc_pci230), PCI230+, PCI260, PCI260+
 * Status: works
 *
 * Configuration options:
 *   none
 *
 * Manual configuration of PCI cards is not supported; they are configured
 * automatically.
 *
 * The PCI230+ and PCI260+ have the same PCI device IDs as the PCI230 and
 * PCI260, but can be distinguished by the size of the PCI regions.  A
 * card will be configured as a "+" model if detected as such.
 *
 * Subdevices:
 *
 *                 PCI230(+)    PCI260(+)
 *                 ---------    ---------
 *   Subdevices       3            1
 *         0          AI           AI
 *         1          AO
 *         2          DIO
 *
 * AI Subdevice:
 *
 *   The AI subdevice has 16 single-ended channels or 8 differential
 *   channels.
 *
 *   The PCI230 and PCI260 cards have 12-bit resolution.  The PCI230+ and
 *   PCI260+ cards have 16-bit resolution.
 *
 *   For differential mode, use inputs 2N and 2N+1 for channel N (e.g. use
 *   inputs 14 and 15 for channel 7).  If the card is physically a PCI230
 *   or PCI260 then it actually uses a "pseudo-differential" mode where the
 *   inputs are sampled a few microseconds apart.  The PCI230+ and PCI260+
 *   use true differential sampling.  Another difference is that if the
 *   card is physically a PCI230 or PCI260, the inverting input is 2N,
 *   whereas for a PCI230+ or PCI260+ the inverting input is 2N+1.  So if a
 *   PCI230 is physically replaced by a PCI230+ (or a PCI260 with a
 *   PCI260+) and differential mode is used, the differential inputs need
 *   to be physically swapped on the connector.
 *
 *   The following input ranges are supported:
 *
 *     0 => [-10, +10] V
 *     1 => [-5, +5] V
 *     2 => [-2.5, +2.5] V
 *     3 => [-1.25, +1.25] V
 *     4 => [0, 10] V
 *     5 => [0, 5] V
 *     6 => [0, 2.5] V
 *
 * AI Commands:
 *
 *   +=========+==============+===========+============+==========+
 *   |start_src|scan_begin_src|convert_src|scan_end_src| stop_src |
 *   +=========+==============+===========+============+==========+
 *   |TRIG_NOW | TRIG_FOLLOW  |TRIG_TIMER | TRIG_COUNT |TRIG_NONE |
 *   |TRIG_INT |              |TRIG_EXT(3)|            |TRIG_COUNT|
 *   |         |              |TRIG_INT   |            |          |
 *   |         |--------------|-----------|            |          |
 *   |         | TRIG_TIMER(1)|TRIG_TIMER |            |          |
 *   |         | TRIG_EXT(2)  |           |            |          |
 *   |         | TRIG_INT     |           |            |          |
 *   +---------+--------------+-----------+------------+----------+
 *
 *   Note 1: If AI command and AO command are used simultaneously, only
 *           one may have scan_begin_src == TRIG_TIMER.
 *
 *   Note 2: For PCI230 and PCI230+, scan_begin_src == TRIG_EXT uses
 *           DIO channel 16 (pin 49) which will need to be configured as
 *           a digital input.  For PCI260+, the EXTTRIG/EXTCONVCLK input
 *           (pin 17) is used instead.  For PCI230, scan_begin_src ==
 *           TRIG_EXT is not supported.  The trigger is a rising edge
 *           on the input.
 *
 *   Note 3: For convert_src == TRIG_EXT, the EXTTRIG/EXTCONVCLK input
 *           (pin 25 on PCI230(+), pin 17 on PCI260(+)) is used.  The
 *           convert_arg value is interpreted as follows:
 *
 *             convert_arg == (CR_EDGE | 0) => rising edge
 *             convert_arg == (CR_EDGE | CR_INVERT | 0) => falling edge
 *             convert_arg == 0 => falling edge (backwards compatibility)
 *             convert_arg == 1 => rising edge (backwards compatibility)
 *
 *   All entries in the channel list must use the same analogue reference.
 *   If the analogue reference is not AREF_DIFF (not differential) each
 *   pair of channel numbers (0 and 1, 2 and 3, etc.) must use the same
 *   input range.  The input ranges used in the sequence must be all
 *   bipolar (ranges 0 to 3) or all unipolar (ranges 4 to 6).  The channel
 *   sequence must consist of 1 or more identical subsequences.  Within the
 *   subsequence, channels must be in ascending order with no repeated
 *   channels.  For example, the following sequences are valid: 0 1 2 3
 *   (single valid subsequence), 0 2 3 5 0 2 3 5 (repeated valid
 *   subsequence), 1 1 1 1 (repeated valid subsequence).  The following
 *   sequences are invalid: 0 3 2 1 (invalid subsequence), 0 2 3 5 0 2 3
 *   (incompletely repeated subsequence).  Some versions of the PCI230+ and
 *   PCI260+ have a bug that requires a subsequence longer than one entry
 *   long to include channel 0.
 *
 * AO Subdevice:
 *
 *   The AO subdevice has 2 channels with 12-bit resolution.
 *   The following output ranges are supported:
 *     0 => [0, 10] V
 *     1 => [-10, +10] V
 *
 * AO Commands:
 *
 *   +=========+==============+===========+============+==========+
 *   |start_src|scan_begin_src|convert_src|scan_end_src| stop_src |
 *   +=========+==============+===========+============+==========+
 *   |TRIG_INT | TRIG_TIMER(1)| TRIG_NOW  | TRIG_COUNT |TRIG_NONE |
 *   |         | TRIG_EXT(2)  |           |            |TRIG_COUNT|
 *   |         | TRIG_INT     |           |            |          |
 *   +---------+--------------+-----------+------------+----------+
 *
 *   Note 1: If AI command and AO command are used simultaneously, only
 *           one may have scan_begin_src == TRIG_TIMER.
 *
 *   Note 2: scan_begin_src == TRIG_EXT is only supported if the card is
 *           configured as a PCI230+ and is only supported on later
 *           versions of the card.  As a card configured as a PCI230+ is
 *           not guaranteed to support external triggering, please consider
 *           this support to be a bonus.  It uses the EXTTRIG/ EXTCONVCLK
 *           input (PCI230+ pin 25).  Triggering will be on the rising edge
 *           unless the CR_INVERT flag is set in scan_begin_arg.
 *
 *   The channels in the channel sequence must be in ascending order with
 *   no repeats.  All entries in the channel sequence must use the same
 *   output range.
 *
 * DIO Subdevice:
 *
 *   The DIO subdevice is a 8255 chip providing 24 DIO channels.  The DIO
 *   channels are configurable as inputs or outputs in four groups:
 *
 *     Port A  - channels  0 to  7
 *     Port B  - channels  8 to 15
 *     Port CL - channels 16 to 19
 *     Port CH - channels 20 to 23
 *
 *   Only mode 0 of the 8255 chip is supported.
 *
 *   Bit 0 of port C (DIO channel 16) is also used as an external scan
 *   trigger input for AI commands on PCI230 and PCI230+, so would need to
 *   be configured as an input to use it for that purpose.
 */

/*
 * Extra triggered scan functionality, interrupt bug-fix added by Steve
 * Sharples.  Support for PCI230+/260+, more triggered scan functionality,
 * and workarounds for (or detection of) various hardware problems added
 * by Ian Abbott.
 */

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

/*
 * PCI230 PCI configuration register information
 */
#define PCI_DEVICE_ID_PCI230
#define PCI_DEVICE_ID_PCI260

/*
 * PCI230 i/o space 1 registers.
 */
#define PCI230_PPI_X_BASE
#define PCI230_PPI_X_A
#define PCI230_PPI_X_B
#define PCI230_PPI_X_C
#define PCI230_PPI_X_CMD
#define PCI230_Z2_CT_BASE
#define PCI230_ZCLK_SCE
#define PCI230_ZGAT_SCE
#define PCI230_INT_SCE
#define PCI230_INT_STAT

/*
 * PCI230 i/o space 2 registers.
 */
#define PCI230_DACCON
#define PCI230_DACOUT1
#define PCI230_DACOUT2
#define PCI230_ADCDATA
#define PCI230_ADCSWTRIG
#define PCI230_ADCCON
#define PCI230_ADCEN
#define PCI230_ADCG
/* PCI230+ i/o space 2 additional registers. */
#define PCI230P_ADCTRIG
#define PCI230P_ADCTH
#define PCI230P_ADCFFTH
#define PCI230P_ADCFFLEV
#define PCI230P_ADCPTSC
#define PCI230P_ADCHYST
#define PCI230P_EXTFUNC
#define PCI230P_HWVER
/* PCI230+ hardware version 2 onwards. */
#define PCI230P2_DACDATA
#define PCI230P2_DACSWTRIG
#define PCI230P2_DACEN

/*
 * DACCON read-write values.
 */
#define PCI230_DAC_OR(x)
#define PCI230_DAC_OR_UNI
#define PCI230_DAC_OR_BIP
#define PCI230_DAC_OR_MASK
/*
 * The following applies only if DAC FIFO support is enabled in the EXTFUNC
 * register (and only for PCI230+ hardware version 2 onwards).
 */
#define PCI230P2_DAC_FIFO_EN
/*
 * The following apply only if the DAC FIFO is enabled (and only for PCI230+
 * hardware version 2 onwards).
 */
#define PCI230P2_DAC_TRIG(x)
#define PCI230P2_DAC_TRIG_NONE
#define PCI230P2_DAC_TRIG_SW
#define PCI230P2_DAC_TRIG_EXTP
#define PCI230P2_DAC_TRIG_EXTN
#define PCI230P2_DAC_TRIG_Z2CT0
#define PCI230P2_DAC_TRIG_Z2CT1
#define PCI230P2_DAC_TRIG_Z2CT2
#define PCI230P2_DAC_TRIG_MASK
#define PCI230P2_DAC_FIFO_WRAP
#define PCI230P2_DAC_INT_FIFO(x)
#define PCI230P2_DAC_INT_FIFO_EMPTY
#define PCI230P2_DAC_INT_FIFO_NEMPTY
#define PCI230P2_DAC_INT_FIFO_NHALF
#define PCI230P2_DAC_INT_FIFO_HALF
#define PCI230P2_DAC_INT_FIFO_NFULL
#define PCI230P2_DAC_INT_FIFO_FULL
#define PCI230P2_DAC_INT_FIFO_MASK

/*
 * DACCON read-only values.
 */
#define PCI230_DAC_BUSY
/*
 * The following apply only if the DAC FIFO is enabled (and only for PCI230+
 * hardware version 2 onwards).
 */
#define PCI230P2_DAC_FIFO_UNDERRUN_LATCHED
#define PCI230P2_DAC_FIFO_EMPTY
#define PCI230P2_DAC_FIFO_FULL
#define PCI230P2_DAC_FIFO_HALF

/*
 * DACCON write-only, transient values.
 */
/*
 * The following apply only if the DAC FIFO is enabled (and only for PCI230+
 * hardware version 2 onwards).
 */
#define PCI230P2_DAC_FIFO_UNDERRUN_CLEAR
#define PCI230P2_DAC_FIFO_RESET

/*
 * PCI230+ hardware version 2 DAC FIFO levels.
 */
#define PCI230P2_DAC_FIFOLEVEL_HALF
#define PCI230P2_DAC_FIFOLEVEL_FULL
/* Free space in DAC FIFO. */
#define PCI230P2_DAC_FIFOROOM_EMPTY
#define PCI230P2_DAC_FIFOROOM_ONETOHALF
#define PCI230P2_DAC_FIFOROOM_HALFTOFULL
#define PCI230P2_DAC_FIFOROOM_FULL

/*
 * ADCCON read/write values.
 */
#define PCI230_ADC_TRIG(x)
#define PCI230_ADC_TRIG_NONE
#define PCI230_ADC_TRIG_SW
#define PCI230_ADC_TRIG_EXTP
#define PCI230_ADC_TRIG_EXTN
#define PCI230_ADC_TRIG_Z2CT0
#define PCI230_ADC_TRIG_Z2CT1
#define PCI230_ADC_TRIG_Z2CT2
#define PCI230_ADC_TRIG_MASK
#define PCI230_ADC_IR(x)
#define PCI230_ADC_IR_UNI
#define PCI230_ADC_IR_BIP
#define PCI230_ADC_IR_MASK
#define PCI230_ADC_IM(x)
#define PCI230_ADC_IM_SE
#define PCI230_ADC_IM_DIF
#define PCI230_ADC_IM_MASK
#define PCI230_ADC_FIFO_EN
#define PCI230_ADC_INT_FIFO(x)
#define PCI230_ADC_INT_FIFO_EMPTY
#define PCI230_ADC_INT_FIFO_NEMPTY
#define PCI230_ADC_INT_FIFO_NHALF
#define PCI230_ADC_INT_FIFO_HALF
#define PCI230_ADC_INT_FIFO_NFULL
#define PCI230_ADC_INT_FIFO_FULL
#define PCI230P_ADC_INT_FIFO_THRESH
#define PCI230_ADC_INT_FIFO_MASK

/*
 * ADCCON write-only, transient values.
 */
#define PCI230_ADC_FIFO_RESET
#define PCI230_ADC_GLOB_RESET

/*
 * ADCCON read-only values.
 */
#define PCI230_ADC_BUSY
#define PCI230_ADC_FIFO_EMPTY
#define PCI230_ADC_FIFO_FULL
#define PCI230_ADC_FIFO_HALF
#define PCI230_ADC_FIFO_FULL_LATCHED

/*
 * PCI230 ADC FIFO levels.
 */
#define PCI230_ADC_FIFOLEVEL_HALFFULL
#define PCI230_ADC_FIFOLEVEL_FULL

/*
 * PCI230+ EXTFUNC values.
 */
/* Route EXTTRIG pin to external gate inputs. */
#define PCI230P_EXTFUNC_GAT_EXTTRIG
/* PCI230+ hardware version 2 values. */
/* Allow DAC FIFO to be enabled. */
#define PCI230P2_EXTFUNC_DACFIFO

/*
 * Counter/timer clock input configuration sources.
 */
#define CLK_CLK
#define CLK_10MHZ
#define CLK_1MHZ
#define CLK_100KHZ
#define CLK_10KHZ
#define CLK_1KHZ
#define CLK_OUTNM1
#define CLK_EXT

static unsigned int pci230_clk_config(unsigned int chan, unsigned int src)
{}

/*
 * Counter/timer gate input configuration sources.
 */
#define GAT_VCC
#define GAT_GND
#define GAT_EXT
#define GAT_NOUTNM2

static unsigned int pci230_gat_config(unsigned int chan, unsigned int src)
{}

/*
 * Summary of CLK_OUTNM1 and GAT_NOUTNM2 connections for PCI230 and PCI260:
 *
 *              Channel's       Channel's
 *              clock input     gate input
 * Channel      CLK_OUTNM1      GAT_NOUTNM2
 * -------      ----------      -----------
 * Z2-CT0       Z2-CT2-OUT      /Z2-CT1-OUT
 * Z2-CT1       Z2-CT0-OUT      /Z2-CT2-OUT
 * Z2-CT2       Z2-CT1-OUT      /Z2-CT0-OUT
 */

/*
 * Interrupt enables/status register values.
 */
#define PCI230_INT_DISABLE
#define PCI230_INT_PPI_C0
#define PCI230_INT_PPI_C3
#define PCI230_INT_ADC
#define PCI230_INT_ZCLK_CT1
/* For PCI230+ hardware version 2 when DAC FIFO enabled. */
#define PCI230P2_INT_DAC

/*
 * (Potentially) shared resources and their owners
 */
enum {};

enum {};

/*
 * Handy macros.
 */

/* Combine old and new bits. */
#define COMBINE(old, new, mask)

/* Current CPU.  XXX should this be hard_smp_processor_id()? */
#define THISCPU

/*
 * Board descriptions for the two boards supported.
 */

struct pci230_board {};

static const struct pci230_board pci230_boards[] =;

struct pci230_private {};

/* PCI230 clock source periods in ns */
static const unsigned int pci230_timebase[8] =;

/* PCI230 analogue input range table */
static const struct comedi_lrange pci230_ai_range =;

/* PCI230 analogue gain bits for each input range. */
static const unsigned char pci230_ai_gain[7] =;

/* PCI230 analogue output range table */
static const struct comedi_lrange pci230_ao_range =;

static unsigned short pci230_ai_read(struct comedi_device *dev)
{}

static unsigned short pci230_ao_mangle_datum(struct comedi_device *dev,
					     unsigned short datum)
{}

static void pci230_ao_write_nofifo(struct comedi_device *dev,
				   unsigned short datum, unsigned int chan)
{}

static void pci230_ao_write_fifo(struct comedi_device *dev,
				 unsigned short datum, unsigned int chan)
{}

static bool pci230_claim_shared(struct comedi_device *dev,
				unsigned char res_mask, unsigned int owner)
{}

static void pci230_release_shared(struct comedi_device *dev,
				  unsigned char res_mask, unsigned int owner)
{}

static void pci230_release_all_resources(struct comedi_device *dev,
					 unsigned int owner)
{}

static unsigned int pci230_divide_ns(u64 ns, unsigned int timebase,
				     unsigned int flags)
{}

/*
 * Given desired period in ns, returns the required internal clock source
 * and gets the initial count.
 */
static unsigned int pci230_choose_clk_count(u64 ns, unsigned int *count,
					    unsigned int flags)
{}

static void pci230_ns_to_single_timer(unsigned int *ns, unsigned int flags)
{}

static void pci230_ct_setup_ns_mode(struct comedi_device *dev, unsigned int ct,
				    unsigned int mode, u64 ns,
				    unsigned int flags)
{}

static void pci230_cancel_ct(struct comedi_device *dev, unsigned int ct)
{}

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

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

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

static int pci230_ao_check_chanlist(struct comedi_device *dev,
				    struct comedi_subdevice *s,
				    struct comedi_cmd *cmd)
{}

static int pci230_ao_cmdtest(struct comedi_device *dev,
			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
{}

static void pci230_ao_stop(struct comedi_device *dev,
			   struct comedi_subdevice *s)
{}

static void pci230_handle_ao_nofifo(struct comedi_device *dev,
				    struct comedi_subdevice *s)
{}

/*
 * Loads DAC FIFO (if using it) from buffer.
 * Returns false if AO finished due to completion or error, true if still going.
 */
static bool pci230_handle_ao_fifo(struct comedi_device *dev,
				  struct comedi_subdevice *s)
{}

static int pci230_ao_inttrig_scan_begin(struct comedi_device *dev,
					struct comedi_subdevice *s,
					unsigned int trig_num)
{}

static void pci230_ao_start(struct comedi_device *dev,
			    struct comedi_subdevice *s)
{}

static int pci230_ao_inttrig_start(struct comedi_device *dev,
				   struct comedi_subdevice *s,
				   unsigned int trig_num)
{}

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

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

static int pci230_ai_check_scan_period(struct comedi_cmd *cmd)
{}

static int pci230_ai_check_chanlist(struct comedi_device *dev,
				    struct comedi_subdevice *s,
				    struct comedi_cmd *cmd)
{}

static int pci230_ai_cmdtest(struct comedi_device *dev,
			     struct comedi_subdevice *s, struct comedi_cmd *cmd)
{}

static void pci230_ai_update_fifo_trigger_level(struct comedi_device *dev,
						struct comedi_subdevice *s)
{}

static int pci230_ai_inttrig_convert(struct comedi_device *dev,
				     struct comedi_subdevice *s,
				     unsigned int trig_num)
{}

static int pci230_ai_inttrig_scan_begin(struct comedi_device *dev,
					struct comedi_subdevice *s,
					unsigned int trig_num)
{}

static void pci230_ai_stop(struct comedi_device *dev,
			   struct comedi_subdevice *s)
{}

static void pci230_ai_start(struct comedi_device *dev,
			    struct comedi_subdevice *s)
{}

static int pci230_ai_inttrig_start(struct comedi_device *dev,
				   struct comedi_subdevice *s,
				   unsigned int trig_num)
{}

static void pci230_handle_ai(struct comedi_device *dev,
			     struct comedi_subdevice *s)
{}

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

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

/* Interrupt handler */
static irqreturn_t pci230_interrupt(int irq, void *d)
{}

/* Check if PCI device matches a specific board. */
static bool pci230_match_pci_board(const struct pci230_board *board,
				   struct pci_dev *pci_dev)
{}

/* Look for board matching PCI device. */
static const struct pci230_board *pci230_find_pci_board(struct pci_dev *pci_dev)
{}

static int pci230_auto_attach(struct comedi_device *dev,
			      unsigned long context_unused)
{}

static struct comedi_driver amplc_pci230_driver =;

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

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

static struct pci_driver amplc_pci230_pci_driver =;
module_comedi_pci_driver();

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