// SPDX-License-Identifier: GPL-2.0+ /* * comedi/drivers/amplc_pci224.c * Driver for Amplicon PCI224 and PCI234 AO boards. * * Copyright (C) 2005 MEV Ltd. <https://www.mev.co.uk/> * * COMEDI - Linux Control and Measurement Device Interface * Copyright (C) 1998,2000 David A. Schleef <[email protected]> */ /* * Driver: amplc_pci224 * Description: Amplicon PCI224, PCI234 * Author: Ian Abbott <[email protected]> * Devices: [Amplicon] PCI224 (amplc_pci224), PCI234 * Updated: Thu, 31 Jul 2014 11:08:03 +0000 * Status: works, but see caveats * * Supports: * * - ao_insn read/write * - ao_do_cmd mode with the following sources: * * - start_src TRIG_INT TRIG_EXT * - scan_begin_src TRIG_TIMER TRIG_EXT * - convert_src TRIG_NOW * - scan_end_src TRIG_COUNT * - stop_src TRIG_COUNT TRIG_EXT TRIG_NONE * * The channel list must contain at least one channel with no repeated * channels. The scan end count must equal the number of channels in * the channel list. * * There is only one external trigger source so only one of start_src, * scan_begin_src or stop_src may use TRIG_EXT. * * Configuration options: * none * * Manual configuration of PCI cards is not supported; they are configured * automatically. * * Output range selection - PCI224: * * Output ranges on PCI224 are partly software-selectable and partly * hardware-selectable according to jumper LK1. All channels are set * to the same range: * * - LK1 position 1-2 (factory default) corresponds to the following * comedi ranges: * * 0: [-10V,+10V]; 1: [-5V,+5V]; 2: [-2.5V,+2.5V], 3: [-1.25V,+1.25V], * 4: [0,+10V], 5: [0,+5V], 6: [0,+2.5V], 7: [0,+1.25V] * * - LK1 position 2-3 corresponds to the following Comedi ranges, using * an external voltage reference: * * 0: [-Vext,+Vext], * 1: [0,+Vext] * * Output range selection - PCI234: * * Output ranges on PCI234 are hardware-selectable according to jumper * LK1 which affects all channels, and jumpers LK2, LK3, LK4 and LK5 * which affect channels 0, 1, 2 and 3 individually. LK1 chooses between * an internal 5V reference and an external voltage reference (Vext). * LK2/3/4/5 choose (per channel) to double the reference or not according * to the following table: * * LK1 position LK2/3/4/5 pos Comedi range * ------------- ------------- -------------- * 2-3 (factory) 1-2 (factory) 0: [-10V,+10V] * 2-3 (factory) 2-3 1: [-5V,+5V] * 1-2 1-2 (factory) 2: [-2*Vext,+2*Vext] * 1-2 2-3 3: [-Vext,+Vext] * * Caveats: * * 1) All channels on the PCI224 share the same range. Any change to the * range as a result of insn_write or a streaming command will affect * the output voltages of all channels, including those not specified * by the instruction or command. * * 2) For the analog output command, the first scan may be triggered * falsely at the start of acquisition. This occurs when the DAC scan * trigger source is switched from 'none' to 'timer' (scan_begin_src = * TRIG_TIMER) or 'external' (scan_begin_src == TRIG_EXT) at the start * of acquisition and the trigger source is at logic level 1 at the * time of the switch. This is very likely for TRIG_TIMER. For * TRIG_EXT, it depends on the state of the external line and whether * the CR_INVERT flag has been set. The remaining scans are triggered * correctly. */ #include <linux/module.h> #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/comedi/comedi_pci.h> #include <linux/comedi/comedi_8254.h> /* * PCI224/234 i/o space 1 (PCIBAR2) registers. */ #define PCI224_Z2_BASE … #define PCI224_ZCLK_SCE … #define PCI224_ZGAT_SCE … #define PCI224_INT_SCE … /* /Interrupt status */ /* * PCI224/234 i/o space 2 (PCIBAR3) 16-bit registers. */ #define PCI224_DACDATA … #define PCI224_SOFTTRIG … #define PCI224_DACCON … #define PCI224_FIFOSIZ … #define PCI224_DACCEN … /* * DACCON values. */ /* (r/w) Scan trigger. */ #define PCI224_DACCON_TRIG(x) … #define PCI224_DACCON_TRIG_MASK … #define PCI224_DACCON_TRIG_NONE … #define PCI224_DACCON_TRIG_SW … #define PCI224_DACCON_TRIG_EXTP … #define PCI224_DACCON_TRIG_EXTN … #define PCI224_DACCON_TRIG_Z2CT0 … #define PCI224_DACCON_TRIG_Z2CT1 … #define PCI224_DACCON_TRIG_Z2CT2 … /* (r/w) Polarity (PCI224 only, PCI234 always bipolar!). */ #define PCI224_DACCON_POLAR(x) … #define PCI224_DACCON_POLAR_MASK … #define PCI224_DACCON_POLAR_UNI … #define PCI224_DACCON_POLAR_BI … /* (r/w) Internal Vref (PCI224 only, when LK1 in position 1-2). */ #define PCI224_DACCON_VREF(x) … #define PCI224_DACCON_VREF_MASK … #define PCI224_DACCON_VREF_1_25 … #define PCI224_DACCON_VREF_2_5 … #define PCI224_DACCON_VREF_5 … #define PCI224_DACCON_VREF_10 … /* (r/w) Wraparound mode enable (to play back stored waveform). */ #define PCI224_DACCON_FIFOWRAP … /* (r/w) FIFO enable. It MUST be set! */ #define PCI224_DACCON_FIFOENAB … /* (r/w) FIFO interrupt trigger level (most values are not very useful). */ #define PCI224_DACCON_FIFOINTR(x) … #define PCI224_DACCON_FIFOINTR_MASK … #define PCI224_DACCON_FIFOINTR_EMPTY … #define PCI224_DACCON_FIFOINTR_NEMPTY … #define PCI224_DACCON_FIFOINTR_NHALF … #define PCI224_DACCON_FIFOINTR_HALF … #define PCI224_DACCON_FIFOINTR_NFULL … #define PCI224_DACCON_FIFOINTR_FULL … /* (r-o) FIFO fill level. */ #define PCI224_DACCON_FIFOFL(x) … #define PCI224_DACCON_FIFOFL_MASK … #define PCI224_DACCON_FIFOFL_EMPTY … #define PCI224_DACCON_FIFOFL_ONETOHALF … #define PCI224_DACCON_FIFOFL_HALFTOFULL … #define PCI224_DACCON_FIFOFL_FULL … /* (r-o) DAC busy flag. */ #define PCI224_DACCON_BUSY … /* (w-o) FIFO reset. */ #define PCI224_DACCON_FIFORESET … /* (w-o) Global reset (not sure what it does). */ #define PCI224_DACCON_GLOBALRESET … /* * DAC FIFO size. */ #define PCI224_FIFO_SIZE … /* * DAC FIFO guaranteed minimum room available, depending on reported fill level. * The maximum room available depends on the reported fill level and how much * has been written! */ #define PCI224_FIFO_ROOM_EMPTY … #define PCI224_FIFO_ROOM_ONETOHALF … #define PCI224_FIFO_ROOM_HALFTOFULL … #define PCI224_FIFO_ROOM_FULL … /* * 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 pci224_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 pci224_gat_config(unsigned int chan, unsigned int src) { … } /* * Summary of CLK_OUTNM1 and GAT_NOUTNM2 connections for PCI224 and PCI234: * * 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 enable/status bits */ #define PCI224_INTR_EXT … #define PCI224_INTR_DAC … #define PCI224_INTR_Z2CT1 … #define PCI224_INTR_EDGE_BITS … #define PCI224_INTR_LEVEL_BITS … /* * Handy macros. */ /* Combine old and new bits. */ #define COMBINE(old, new, mask) … /* Current CPU. XXX should this be hard_smp_processor_id()? */ #define THISCPU … /* State bits for use with atomic bit operations. */ #define AO_CMD_STARTED … /* * Range tables. */ /* * The ranges for PCI224. * * These are partly hardware-selectable by jumper LK1 and partly * software-selectable. * * All channels share the same hardware range. */ static const struct comedi_lrange range_pci224 = …; static const unsigned short hwrange_pci224[10] = …; /* Used to check all channels set to the same range on PCI224. */ static const unsigned char range_check_pci224[10] = …; /* * The ranges for PCI234. * * These are all hardware-selectable by jumper LK1 affecting all channels, * and jumpers LK2, LK3, LK4 and LK5 affecting channels 0, 1, 2 and 3 * individually. */ static const struct comedi_lrange range_pci234 = …; /* N.B. PCI234 ignores the polarity bit, but software uses it. */ static const unsigned short hwrange_pci234[4] = …; /* Used to check all channels use same LK1 setting on PCI234. */ static const unsigned char range_check_pci234[4] = …; /* * Board descriptions. */ enum pci224_model { … }; struct pci224_board { … }; static const struct pci224_board pci224_boards[] = …; struct pci224_private { … }; /* * Called from the 'insn_write' function to perform a single write. */ static void pci224_ao_set_data(struct comedi_device *dev, int chan, int range, unsigned int data) { … } static int pci224_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { … } /* * Kills a command running on the AO subdevice. */ static void pci224_ao_stop(struct comedi_device *dev, struct comedi_subdevice *s) { … } /* * Handles start of acquisition for the AO subdevice. */ static void pci224_ao_start(struct comedi_device *dev, struct comedi_subdevice *s) { … } /* * Handles interrupts from the DAC FIFO. */ static void pci224_ao_handle_fifo(struct comedi_device *dev, struct comedi_subdevice *s) { … } static int pci224_ao_inttrig_start(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trig_num) { … } static int pci224_ao_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { … } #define MAX_SCAN_PERIOD … #define MIN_SCAN_PERIOD … #define CONVERT_PERIOD … /* * 'do_cmdtest' function for AO subdevice. */ static int pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { … } static void pci224_ao_start_pacer(struct comedi_device *dev, struct comedi_subdevice *s) { … } static int pci224_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { … } /* * 'cancel' function for AO subdevice. */ static int pci224_ao_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { … } /* * 'munge' data for AO command. */ static void pci224_ao_munge(struct comedi_device *dev, struct comedi_subdevice *s, void *data, unsigned int num_bytes, unsigned int chan_index) { … } /* * Interrupt handler. */ static irqreturn_t pci224_interrupt(int irq, void *d) { … } static int pci224_auto_attach(struct comedi_device *dev, unsigned long context_model) { … } static void pci224_detach(struct comedi_device *dev) { … } static struct comedi_driver amplc_pci224_driver = …; static int amplc_pci224_pci_probe(struct pci_dev *dev, const struct pci_device_id *id) { … } static const struct pci_device_id amplc_pci224_pci_table[] = …; MODULE_DEVICE_TABLE(pci, amplc_pci224_pci_table); static struct pci_driver amplc_pci224_pci_driver = …; module_comedi_pci_driver(…); MODULE_AUTHOR(…) …; MODULE_DESCRIPTION(…) …; MODULE_LICENSE(…) …;