// SPDX-License-Identifier: GPL-2.0+
/*
* dt282x.c
* Comedi driver for Data Translation DT2821 series
*
* COMEDI - Linux Control and Measurement Device Interface
* Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
*/
/*
* Driver: dt282x
* Description: Data Translation DT2821 series (including DT-EZ)
* Author: ds
* Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
* DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
* DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
* DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
* DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
* DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
* Status: complete
* Updated: Wed, 22 Aug 2001 17:11:34 -0700
*
* Configuration options:
* [0] - I/O port base address
* [1] - IRQ (optional, required for async command support)
* [2] - DMA 1 (optional, required for async command support)
* [3] - DMA 2 (optional, required for async command support)
* [4] - AI jumpered for 0=single ended, 1=differential
* [5] - AI jumpered for 0=straight binary, 1=2's complement
* [6] - AO 0 data format (deprecated, see below)
* [7] - AO 1 data format (deprecated, see below)
* [8] - AI jumpered for 0=[-10,10]V, 1=[0,10], 2=[-5,5], 3=[0,5]
* [9] - AO channel 0 range (deprecated, see below)
* [10]- AO channel 1 range (deprecated, see below)
*
* Notes:
* - AO commands might be broken.
* - If you try to run a command on both the AI and AO subdevices
* simultaneously, bad things will happen. The driver needs to
* be fixed to check for this situation and return an error.
* - AO range is not programmable. The AO subdevice has a range_table
* containing all the possible analog output ranges. Use the range
* that matches your board configuration to convert between data
* values and physical units. The format of the data written to the
* board is handled automatically based on the unipolar/bipolar
* range that is selected.
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include "../comedidev.h"
#include "comedi_isadma.h"
/*
* Register map
*/
#define DT2821_ADCSR_REG 0x00
#define DT2821_ADCSR_ADERR BIT(15)
#define DT2821_ADCSR_ADCLK BIT(9)
#define DT2821_ADCSR_MUXBUSY BIT(8)
#define DT2821_ADCSR_ADDONE BIT(7)
#define DT2821_ADCSR_IADDONE BIT(6)
#define DT2821_ADCSR_GS(x) (((x) & 0x3) << 4)
#define DT2821_ADCSR_CHAN(x) (((x) & 0xf) << 0)
#define DT2821_CHANCSR_REG 0x02
#define DT2821_CHANCSR_LLE BIT(15)
#define DT2821_CHANCSR_TO_PRESLA(x) (((x) >> 8) & 0xf)
#define DT2821_CHANCSR_NUMB(x) ((((x) - 1) & 0xf) << 0)
#define DT2821_ADDAT_REG 0x04
#define DT2821_DACSR_REG 0x06
#define DT2821_DACSR_DAERR BIT(15)
#define DT2821_DACSR_YSEL(x) ((x) << 9)
#define DT2821_DACSR_SSEL BIT(8)
#define DT2821_DACSR_DACRDY BIT(7)
#define DT2821_DACSR_IDARDY BIT(6)
#define DT2821_DACSR_DACLK BIT(5)
#define DT2821_DACSR_HBOE BIT(1)
#define DT2821_DACSR_LBOE BIT(0)
#define DT2821_DADAT_REG 0x08
#define DT2821_DIODAT_REG 0x0a
#define DT2821_SUPCSR_REG 0x0c
#define DT2821_SUPCSR_DMAD BIT(15)
#define DT2821_SUPCSR_ERRINTEN BIT(14)
#define DT2821_SUPCSR_CLRDMADNE BIT(13)
#define DT2821_SUPCSR_DDMA BIT(12)
#define DT2821_SUPCSR_DS(x) (((x) & 0x3) << 10)
#define DT2821_SUPCSR_DS_PIO DT2821_SUPCSR_DS(0)
#define DT2821_SUPCSR_DS_AD_CLK DT2821_SUPCSR_DS(1)
#define DT2821_SUPCSR_DS_DA_CLK DT2821_SUPCSR_DS(2)
#define DT2821_SUPCSR_DS_AD_TRIG DT2821_SUPCSR_DS(3)
#define DT2821_SUPCSR_BUFFB BIT(9)
#define DT2821_SUPCSR_SCDN BIT(8)
#define DT2821_SUPCSR_DACON BIT(7)
#define DT2821_SUPCSR_ADCINIT BIT(6)
#define DT2821_SUPCSR_DACINIT BIT(5)
#define DT2821_SUPCSR_PRLD BIT(4)
#define DT2821_SUPCSR_STRIG BIT(3)
#define DT2821_SUPCSR_XTRIG BIT(2)
#define DT2821_SUPCSR_XCLK BIT(1)
#define DT2821_SUPCSR_BDINIT BIT(0)
#define DT2821_TMRCTR_REG 0x0e
#define DT2821_TMRCTR_PRESCALE(x) (((x) & 0xf) << 8)
#define DT2821_TMRCTR_DIVIDER(x) ((255 - ((x) & 0xff)) << 0)
/* Pacer Clock */
#define DT2821_OSC_BASE 250 /* 4 MHz (in nanoseconds) */
#define DT2821_PRESCALE(x) BIT(x)
#define DT2821_PRESCALE_MAX 15
#define DT2821_DIVIDER_MAX 255
#define DT2821_OSC_MAX (DT2821_OSC_BASE * \
DT2821_PRESCALE(DT2821_PRESCALE_MAX) * \
DT2821_DIVIDER_MAX)
static const struct comedi_lrange range_dt282x_ai_lo_bipolar = {
4, {
BIP_RANGE(10),
BIP_RANGE(5),
BIP_RANGE(2.5),
BIP_RANGE(1.25)
}
};
static const struct comedi_lrange range_dt282x_ai_lo_unipolar = {
4, {
UNI_RANGE(10),
UNI_RANGE(5),
UNI_RANGE(2.5),
UNI_RANGE(1.25)
}
};
static const struct comedi_lrange range_dt282x_ai_5_bipolar = {
4, {
BIP_RANGE(5),
BIP_RANGE(2.5),
BIP_RANGE(1.25),
BIP_RANGE(0.625)
}
};
static const struct comedi_lrange range_dt282x_ai_5_unipolar = {
4, {
UNI_RANGE(5),
UNI_RANGE(2.5),
UNI_RANGE(1.25),
UNI_RANGE(0.625)
}
};
static const struct comedi_lrange range_dt282x_ai_hi_bipolar = {
4, {
BIP_RANGE(10),
BIP_RANGE(1),
BIP_RANGE(0.1),
BIP_RANGE(0.02)
}
};
static const struct comedi_lrange range_dt282x_ai_hi_unipolar = {
4, {
UNI_RANGE(10),
UNI_RANGE(1),
UNI_RANGE(0.1),
UNI_RANGE(0.02)
}
};
/*
* The Analog Output range is set per-channel using jumpers on the board.
* All of these ranges may not be available on some DT2821 series boards.
* The default jumper setting has both channels set for +/-10V output.
*/
static const struct comedi_lrange dt282x_ao_range = {
5, {
BIP_RANGE(10),
BIP_RANGE(5),
BIP_RANGE(2.5),
UNI_RANGE(10),
UNI_RANGE(5),
}
};
struct dt282x_board {
const char *name;
unsigned int ai_maxdata;
int