diff options
Diffstat (limited to 'drivers/staging/comedi/drivers/dt2801.c')
-rw-r--r-- | drivers/staging/comedi/drivers/dt2801.c | 645 |
1 files changed, 0 insertions, 645 deletions
diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c deleted file mode 100644 index 0d571d817b4e..000000000000 --- a/drivers/staging/comedi/drivers/dt2801.c +++ /dev/null @@ -1,645 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * comedi/drivers/dt2801.c - * Device Driver for DataTranslation DT2801 - * - */ -/* - * Driver: dt2801 - * Description: Data Translation DT2801 series and DT01-EZ - * Author: ds - * Status: works - * Devices: [Data Translation] DT2801 (dt2801), DT2801-A, DT2801/5716A, - * DT2805, DT2805/5716A, DT2808, DT2818, DT2809, DT01-EZ - * - * This driver can autoprobe the type of board. - * - * Configuration options: - * [0] - I/O port base address - * [1] - unused - * [2] - A/D reference 0=differential, 1=single-ended - * [3] - A/D range - * 0 = [-10, 10] - * 1 = [0,10] - * [4] - D/A 0 range - * 0 = [-10, 10] - * 1 = [-5,5] - * 2 = [-2.5,2.5] - * 3 = [0,10] - * 4 = [0,5] - * [5] - D/A 1 range (same choices) - */ - -#include <linux/module.h> -#include "../comedidev.h" -#include <linux/delay.h> - -#define DT2801_TIMEOUT 1000 - -/* Hardware Configuration */ -/* ====================== */ - -#define DT2801_MAX_DMA_SIZE (64 * 1024) - -/* define's */ -/* ====================== */ - -/* Commands */ -#define DT_C_RESET 0x0 -#define DT_C_CLEAR_ERR 0x1 -#define DT_C_READ_ERRREG 0x2 -#define DT_C_SET_CLOCK 0x3 - -#define DT_C_TEST 0xb -#define DT_C_STOP 0xf - -#define DT_C_SET_DIGIN 0x4 -#define DT_C_SET_DIGOUT 0x5 -#define DT_C_READ_DIG 0x6 -#define DT_C_WRITE_DIG 0x7 - -#define DT_C_WRITE_DAIM 0x8 -#define DT_C_SET_DA 0x9 -#define DT_C_WRITE_DA 0xa - -#define DT_C_READ_ADIM 0xc -#define DT_C_SET_AD 0xd -#define DT_C_READ_AD 0xe - -/* - * Command modifiers (only used with read/write), EXTTRIG can be - * used with some other commands. - */ -#define DT_MOD_DMA BIT(4) -#define DT_MOD_CONT BIT(5) -#define DT_MOD_EXTCLK BIT(6) -#define DT_MOD_EXTTRIG BIT(7) - -/* Bits in status register */ -#define DT_S_DATA_OUT_READY BIT(0) -#define DT_S_DATA_IN_FULL BIT(1) -#define DT_S_READY BIT(2) -#define DT_S_COMMAND BIT(3) -#define DT_S_COMPOSITE_ERROR BIT(7) - -/* registers */ -#define DT2801_DATA 0 -#define DT2801_STATUS 1 -#define DT2801_CMD 1 - -#if 0 -/* ignore 'defined but not used' warning */ -static const struct comedi_lrange range_dt2801_ai_pgh_bipolar = { - 4, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25) - } -}; -#endif -static const struct comedi_lrange range_dt2801_ai_pgl_bipolar = { - 4, { - BIP_RANGE(10), - BIP_RANGE(1), - BIP_RANGE(0.1), - BIP_RANGE(0.02) - } -}; - -#if 0 -/* ignore 'defined but not used' warning */ -static const struct comedi_lrange range_dt2801_ai_pgh_unipolar = { - 4, { - UNI_RANGE(10), - UNI_RANGE(5), - UNI_RANGE(2.5), - UNI_RANGE(1.25) - } -}; -#endif -static const struct comedi_lrange range_dt2801_ai_pgl_unipolar = { - 4, { - UNI_RANGE(10), - UNI_RANGE(1), - UNI_RANGE(0.1), - UNI_RANGE(0.02) - } -}; - -struct dt2801_board { - const char *name; - int boardcode; - int ad_diff; - int ad_chan; - int adbits; - int adrangetype; - int dabits; -}; - -/* - * Typeid's for the different boards of the DT2801-series - * (taken from the test-software, that comes with the board) - */ -static const struct dt2801_board boardtypes[] = { - { - .name = "dt2801", - .boardcode = 0x09, - .ad_diff = 2, - .ad_chan = 16, - .adbits = 12, - .adrangetype = 0, - .dabits = 12}, - { - .name = "dt2801-a", - .boardcode = 0x52, - .ad_diff = 2, - .ad_chan = 16, - .adbits = 12, - .adrangetype = 0, - .dabits = 12}, - { - .name = "dt2801/5716a", - .boardcode = 0x82, - .ad_diff = 1, - .ad_chan = 16, - .adbits = 16, - .adrangetype = 1, - .dabits = 12}, - { - .name = "dt2805", - .boardcode = 0x12, - .ad_diff = 1, - .ad_chan = 16, - .adbits = 12, - .adrangetype = 0, - .dabits = 12}, - { - .name = "dt2805/5716a", - .boardcode = 0x92, - .ad_diff = 1, - .ad_chan = 16, - .adbits = 16, - .adrangetype = 1, - .dabits = 12}, - { - .name = "dt2808", - .boardcode = 0x20, - .ad_diff = 0, - .ad_chan = 16, - .adbits = 12, - .adrangetype = 2, - .dabits = 8}, - { - .name = "dt2818", - .boardcode = 0xa2, - .ad_diff = 0, - .ad_chan = 4, - .adbits = 12, - .adrangetype = 0, - .dabits = 12}, - { - .name = "dt2809", - .boardcode = 0xb0, - .ad_diff = 0, - .ad_chan = 8, - .adbits = 12, - .adrangetype = 1, - .dabits = 12}, -}; - -struct dt2801_private { - const struct comedi_lrange *dac_range_types[2]; -}; - -/* - * These are the low-level routines: - * writecommand: write a command to the board - * writedata: write data byte - * readdata: read data byte - */ - -/* - * Only checks DataOutReady-flag, not the Ready-flag as it is done - * in the examples of the manual. I don't see why this should be - * necessary. - */ -static int dt2801_readdata(struct comedi_device *dev, int *data) -{ - int stat = 0; - int timeout = DT2801_TIMEOUT; - - do { - stat = inb_p(dev->iobase + DT2801_STATUS); - if (stat & (DT_S_COMPOSITE_ERROR | DT_S_READY)) - return stat; - if (stat & DT_S_DATA_OUT_READY) { - *data = inb_p(dev->iobase + DT2801_DATA); - return 0; - } - } while (--timeout > 0); - - return -ETIME; -} - -static int dt2801_readdata2(struct comedi_device *dev, int *data) -{ - int lb = 0; - int hb = 0; - int ret; - - ret = dt2801_readdata(dev, &lb); - if (ret) - return ret; - ret = dt2801_readdata(dev, &hb); - if (ret) - return ret; - - *data = (hb << 8) + lb; - return 0; -} - -static int dt2801_writedata(struct comedi_device *dev, unsigned int data) -{ - int stat = 0; - int timeout = DT2801_TIMEOUT; - - do { - stat = inb_p(dev->iobase + DT2801_STATUS); - - if (stat & DT_S_COMPOSITE_ERROR) - return stat; - if (!(stat & DT_S_DATA_IN_FULL)) { - outb_p(data & 0xff, dev->iobase + DT2801_DATA); - return 0; - } - } while (--timeout > 0); - - return -ETIME; -} - -static int dt2801_writedata2(struct comedi_device *dev, unsigned int data) -{ - int ret; - - ret = dt2801_writedata(dev, data & 0xff); - if (ret < 0) - return ret; - ret = dt2801_writedata(dev, data >> 8); - if (ret < 0) - return ret; - - return 0; -} - -static int dt2801_wait_for_ready(struct comedi_device *dev) -{ - int timeout = DT2801_TIMEOUT; - int stat; - - stat = inb_p(dev->iobase + DT2801_STATUS); - if (stat & DT_S_READY) - return 0; - do { - stat = inb_p(dev->iobase + DT2801_STATUS); - - if (stat & DT_S_COMPOSITE_ERROR) - return stat; - if (stat & DT_S_READY) - return 0; - } while (--timeout > 0); - - return -ETIME; -} - -static void dt2801_writecmd(struct comedi_device *dev, int command) -{ - int stat; - - dt2801_wait_for_ready(dev); - - stat = inb_p(dev->iobase + DT2801_STATUS); - if (stat & DT_S_COMPOSITE_ERROR) { - dev_dbg(dev->class_dev, - "composite-error in %s, ignoring\n", __func__); - } - if (!(stat & DT_S_READY)) - dev_dbg(dev->class_dev, "!ready in %s, ignoring\n", __func__); - outb_p(command, dev->iobase + DT2801_CMD); -} - -static int dt2801_reset(struct comedi_device *dev) -{ - int board_code = 0; - unsigned int stat; - int timeout; - - /* pull random data from data port */ - inb_p(dev->iobase + DT2801_DATA); - inb_p(dev->iobase + DT2801_DATA); - inb_p(dev->iobase + DT2801_DATA); - inb_p(dev->iobase + DT2801_DATA); - - /* dt2801_writecmd(dev,DT_C_STOP); */ - outb_p(DT_C_STOP, dev->iobase + DT2801_CMD); - - /* dt2801_wait_for_ready(dev); */ - usleep_range(100, 200); - timeout = 10000; - do { - stat = inb_p(dev->iobase + DT2801_STATUS); - if (stat & DT_S_READY) - break; - } while (timeout--); - if (!timeout) - dev_dbg(dev->class_dev, "timeout 1 status=0x%02x\n", stat); - - /* dt2801_readdata(dev,&board_code); */ - - outb_p(DT_C_RESET, dev->iobase + DT2801_CMD); - /* dt2801_writecmd(dev,DT_C_RESET); */ - - usleep_range(100, 200); - timeout = 10000; - do { - stat = inb_p(dev->iobase + DT2801_STATUS); - if (stat & DT_S_READY) - break; - } while (timeout--); - if (!timeout) - dev_dbg(dev->class_dev, "timeout 2 status=0x%02x\n", stat); - - dt2801_readdata(dev, &board_code); - - return board_code; -} - -static int probe_number_of_ai_chans(struct comedi_device *dev) -{ - int n_chans; - int stat; - int data; - - for (n_chans = 0; n_chans < 16; n_chans++) { - dt2801_writecmd(dev, DT_C_READ_ADIM); - dt2801_writedata(dev, 0); - dt2801_writedata(dev, n_chans); - stat = dt2801_readdata2(dev, &data); - - if (stat) - break; - } - - dt2801_reset(dev); - dt2801_reset(dev); - - return n_chans; -} - -static const struct comedi_lrange *dac_range_table[] = { - &range_bipolar10, - &range_bipolar5, - &range_bipolar2_5, - &range_unipolar10, - &range_unipolar5 -}; - -static const struct comedi_lrange *dac_range_lkup(int opt) -{ - if (opt < 0 || opt >= 5) - return &range_unknown; - return dac_range_table[opt]; -} - -static const struct comedi_lrange *ai_range_lkup(int type, int opt) -{ - switch (type) { - case 0: - return (opt) ? - &range_dt2801_ai_pgl_unipolar : - &range_dt2801_ai_pgl_bipolar; - case 1: - return (opt) ? &range_unipolar10 : &range_bipolar10; - case 2: - return &range_unipolar5; - } - return &range_unknown; -} - -static int dt2801_error(struct comedi_device *dev, int stat) -{ - if (stat < 0) { - if (stat == -ETIME) - dev_dbg(dev->class_dev, "timeout\n"); - else - dev_dbg(dev->class_dev, "error %d\n", stat); - return stat; - } - dev_dbg(dev->class_dev, "error status 0x%02x, resetting...\n", stat); - - dt2801_reset(dev); - dt2801_reset(dev); - - return -EIO; -} - -static int dt2801_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int d; - int stat; - int i; - - for (i = 0; i < insn->n; i++) { - dt2801_writecmd(dev, DT_C_READ_ADIM); - dt2801_writedata(dev, CR_RANGE(insn->chanspec)); - dt2801_writedata(dev, CR_CHAN(insn->chanspec)); - stat = dt2801_readdata2(dev, &d); - - if (stat != 0) - return dt2801_error(dev, stat); - - data[i] = d; - } - - return i; -} - -static int dt2801_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - unsigned int chan = CR_CHAN(insn->chanspec); - - dt2801_writecmd(dev, DT_C_WRITE_DAIM); - dt2801_writedata(dev, chan); - dt2801_writedata2(dev, data[0]); - - s->readback[chan] = data[0]; - - return 1; -} - -static int dt2801_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int which = (s == &dev->subdevices[3]) ? 1 : 0; - unsigned int val = 0; - - if (comedi_dio_update_state(s, data)) { - dt2801_writecmd(dev, DT_C_WRITE_DIG); - dt2801_writedata(dev, which); - dt2801_writedata(dev, s->state); - } - - dt2801_writecmd(dev, DT_C_READ_DIG); - dt2801_writedata(dev, which); - dt2801_readdata(dev, &val); - - data[1] = val; - - return insn->n; -} - -static int dt2801_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int ret; - - ret = comedi_dio_insn_config(dev, s, insn, data, 0xff); - if (ret) - return ret; - - dt2801_writecmd(dev, s->io_bits ? DT_C_SET_DIGOUT : DT_C_SET_DIGIN); - dt2801_writedata(dev, (s == &dev->subdevices[3]) ? 1 : 0); - - return insn->n; -} - -/* - * options: - * [0] - i/o base - * [1] - unused - * [2] - a/d 0=differential, 1=single-ended - * [3] - a/d range 0=[-10,10], 1=[0,10] - * [4] - dac0 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] - * [5] - dac1 range 0=[-10,10], 1=[-5,5], 2=[-2.5,2.5] 3=[0,10], 4=[0,5] - */ -static int dt2801_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - const struct dt2801_board *board; - struct dt2801_private *devpriv; - struct comedi_subdevice *s; - int board_code, type; - int ret = 0; - int n_ai_chans; - - ret = comedi_request_region(dev, it->options[0], 0x2); - if (ret) - return ret; - - /* do some checking */ - - board_code = dt2801_reset(dev); - - /* heh. if it didn't work, try it again. */ - if (!board_code) - board_code = dt2801_reset(dev); - - for (type = 0; type < ARRAY_SIZE(boardtypes); type++) { - if (boardtypes[type].boardcode == board_code) - goto havetype; - } - dev_dbg(dev->class_dev, - "unrecognized board code=0x%02x, contact author\n", board_code); - type = 0; - -havetype: - dev->board_ptr = boardtypes + type; - board = dev->board_ptr; - - n_ai_chans = probe_number_of_ai_chans(dev); - - ret = comedi_alloc_subdevices(dev, 4); - if (ret) - goto out; - - devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv)); - if (!devpriv) - return -ENOMEM; - - dev->board_name = board->name; - - s = &dev->subdevices[0]; - /* ai subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; -#if 1 - s->n_chan = n_ai_chans; -#else - if (it->options[2]) - s->n_chan = board->ad_chan; - else - s->n_chan = board->ad_chan / 2; -#endif - s->maxdata = (1 << board->adbits) - 1; - s->range_table = ai_range_lkup(board->adrangetype, it->options[3]); - s->insn_read = dt2801_ai_insn_read; - - s = &dev->subdevices[1]; - /* ao subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 2; - s->maxdata = (1 << board->dabits) - 1; - s->range_table_list = devpriv->dac_range_types; - devpriv->dac_range_types[0] = dac_range_lkup(it->options[4]); - devpriv->dac_range_types[1] = dac_range_lkup(it->options[5]); - s->insn_write = dt2801_ao_insn_write; - - ret = comedi_alloc_subdev_readback(s); - if (ret) - return ret; - - s = &dev->subdevices[2]; - /* 1st digital subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = dt2801_dio_insn_bits; - s->insn_config = dt2801_dio_insn_config; - - s = &dev->subdevices[3]; - /* 2nd digital subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = dt2801_dio_insn_bits; - s->insn_config = dt2801_dio_insn_config; - - ret = 0; -out: - return ret; -} - -static struct comedi_driver dt2801_driver = { - .driver_name = "dt2801", - .module = THIS_MODULE, - .attach = dt2801_attach, - .detach = comedi_legacy_detach, -}; -module_comedi_driver(dt2801_driver); - -MODULE_AUTHOR("Comedi https://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); |