// SPDX-License-Identifier: GPL-2.0+ /* * comedi/drivers/dt9812.c * COMEDI driver for DataTranslation DT9812 USB module * * Copyright (C) 2005 Anders Blomdell <anders.blomdell@control.lth.se> * * COMEDI - Linux Control and Measurement Device Interface
*/
/* * Driver: dt9812 * Description: Data Translation DT9812 USB module * Devices: [Data Translation] DT9812 (dt9812) * Author: anders.blomdell@control.lth.se (Anders Blomdell) * Status: in development * Updated: Sun Nov 20 20:18:34 EST 2005 * * This driver works, but bulk transfers not implemented. Might be a * starting point for someone else. I found out too late that USB has * too high latencies (>1 ms) for my needs.
*/
/* * Nota Bene: * 1. All writes to command pipe has to be 32 bytes (ISP1181B SHRTP=0 ?) * 2. The DDK source (as of sep 2005) is in error regarding the * input MUX bits (example code says P4, but firmware schematics * says P1).
*/
/* * Register read/write commands for processor
*/
/* Read a single byte of USB memory */
DT9812_R_SINGLE_BYTE_REG = 2, /* Write a single byte of USB memory */
DT9812_W_SINGLE_BYTE_REG = 3, /* Multiple Reads of USB memory */
DT9812_R_MULTI_BYTE_REG = 4, /* Multiple Writes of USB memory */
DT9812_W_MULTI_BYTE_REG = 5, /* Read, (AND) with mask, OR value, then write (single) */
DT9812_RMW_SINGLE_BYTE_REG = 6, /* Read, (AND) with mask, OR value, then write (multiple) */
DT9812_RMW_MULTI_BYTE_REG = 7,
/* * Register read/write commands for SMBus
*/
/* Read a single byte of SMBus */
DT9812_R_SINGLE_BYTE_SMBUS = 8, /* Write a single byte of SMBus */
DT9812_W_SINGLE_BYTE_SMBUS = 9, /* Multiple Reads of SMBus */
DT9812_R_MULTI_BYTE_SMBUS = 10, /* Multiple Writes of SMBus */
DT9812_W_MULTI_BYTE_SMBUS = 11,
/* * Register read/write commands for a device
*/
/* Read a single byte of a device */
DT9812_R_SINGLE_BYTE_DEV = 12, /* Write a single byte of a device */
DT9812_W_SINGLE_BYTE_DEV = 13, /* Multiple Reads of a device */
DT9812_R_MULTI_BYTE_DEV = 14, /* Multiple Writes of a device */
DT9812_W_MULTI_BYTE_DEV = 15,
/* Not sure if we'll need this */
DT9812_W_DAC_THRESHOLD = 16,
/* Set interrupt on change mask */
DT9812_W_INT_ON_CHANGE_MASK = 17,
/* Write (or Clear) the CGL for the ADC */
DT9812_W_CGL = 18, /* Multiple Reads of USB memory */
DT9812_R_MULTI_BYTE_USBMEM = 19, /* Multiple Writes to USB memory */
DT9812_W_MULTI_BYTE_USBMEM = 20,
/* Issue a start command to a given subsystem */
DT9812_START_SUBSYSTEM = 21, /* Issue a stop command to a given subsystem */
DT9812_STOP_SUBSYSTEM = 22,
/* calibrate the board using CAL_POT_CMD */
DT9812_CALIBRATE_POT = 23, /* set the DAC FIFO size */
DT9812_W_DAC_FIFO_SIZE = 24, /* Write or Clear the CGL for the DAC */
DT9812_W_CGL_DAC = 25, /* Read a single value from a subsystem */
DT9812_R_SINGLE_VALUE_CMD = 26, /* Write a single value to a subsystem */
DT9812_W_SINGLE_VALUE_CMD = 27, /* Valid DT9812_USB_FIRMWARE_CMD_CODE's will be less than this number */
DT9812_MAX_USB_FIRMWARE_CMD_CODE,
};
mutex_lock(&devpriv->mut);
ret = dt9812_read_multiple_registers(dev, 2, reg, value); if (ret == 0) { /* * bits 0-6 in F020_SFR_P3 are bits 0-6 in the digital * input port bit 3 in F020_SFR_P1 is bit 7 in the * digital input port
*/
*bits = (value[0] & 0x7f) | ((value[1] & 0x08) << 4);
}
mutex_unlock(&devpriv->mut);
switch (gain) { /* * 000 -> Gain = 1 * 001 -> Gain = 2 * 010 -> Gain = 4 * 011 -> Gain = 8 * 10x -> Gain = 16 * 11x -> Gain = 0.5
*/ case DT9812_GAIN_0PT5:
rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 |
F020_MASK_ADC0CF_AMP0GN1; break; default: /* this should never happen, just use a gain of 1 */ case DT9812_GAIN_1:
rmw->or_value = 0x00; break; case DT9812_GAIN_2:
rmw->or_value = F020_MASK_ADC0CF_AMP0GN0; break; case DT9812_GAIN_4:
rmw->or_value = F020_MASK_ADC0CF_AMP0GN1; break; case DT9812_GAIN_8:
rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 |
F020_MASK_ADC0CF_AMP0GN0; break; case DT9812_GAIN_16:
rmw->or_value = F020_MASK_ADC0CF_AMP0GN2; break;
}
}
ret = dt9812_rmw_multiple_registers(dev, 3, rmw); if (ret) gotoexit;
/* read the status and ADC */
ret = dt9812_read_multiple_registers(dev, 3, reg, val); if (ret) gotoexit;
/* * An ADC conversion takes 16 SAR clocks cycles, i.e. about 9us. * Therefore, between the instant that AD0BUSY was set via * dt9812_rmw_multiple_registers and the read of AD0BUSY via * dt9812_read_multiple_registers, the conversion should be complete * since these two operations require two USB transactions each taking * at least a millisecond to complete. However, lets make sure that * conversion is finished.
*/ if ((val[0] & (F020_MASK_ADC0CN_AD0INT | F020_MASK_ADC0CN_AD0BUSY)) ==
F020_MASK_ADC0CN_AD0INT) { switch (devpriv->device) { case DT9812_DEVID_DT9812_10: /* * For DT9812-10V the personality module set the * encoding to 2's complement. Hence, convert it before * returning it
*/
*value = ((val[1] << 8) | val[2]) + 0x800; break; case DT9812_DEVID_DT9812_2PT5:
*value = (val[1] << 8) | val[2]; break;
}
}
exit:
mutex_unlock(&devpriv->mut);
return ret;
}
staticint dt9812_analog_out(struct comedi_device *dev, int channel, u16 value)
{ struct dt9812_private *devpriv = dev->private; struct dt9812_rmw_byte rmw[3]; int ret;
mutex_lock(&devpriv->mut);
switch (channel) { case 0: /* 1. Set DAC mode */
rmw[0].address = F020_SFR_DAC0CN;
rmw[0].and_mask = 0xff;
rmw[0].or_value = F020_MASK_DACXCN_DACXEN;
/* 2. load lsb of DAC value first */
rmw[1].address = F020_SFR_DAC0L;
rmw[1].and_mask = 0xff;
rmw[1].or_value = value & 0xff;
/* 3. load msb of DAC value next to latch the 12-bit value */
rmw[2].address = F020_SFR_DAC0H;
rmw[2].and_mask = 0xff;
rmw[2].or_value = (value >> 8) & 0xf; break;
case 1: /* 1. Set DAC mode */
rmw[0].address = F020_SFR_DAC1CN;
rmw[0].and_mask = 0xff;
rmw[0].or_value = F020_MASK_DACXCN_DACXEN;
/* 2. load lsb of DAC value first */
rmw[1].address = F020_SFR_DAC1L;
rmw[1].and_mask = 0xff;
rmw[1].or_value = value & 0xff;
/* 3. load msb of DAC value next to latch the 12-bit value */
rmw[2].address = F020_SFR_DAC1H;
rmw[2].and_mask = 0xff;
rmw[2].or_value = (value >> 8) & 0xf; break;
}
ret = dt9812_rmw_multiple_registers(dev, 3, rmw);
ret = dt9812_read_info(dev, 0, &tmp8, sizeof(tmp8)); if (ret) { /* * Seems like a configuration reset is necessary if driver is * reloaded while device is attached
*/
usb_reset_configuration(usb); for (i = 0; i < 10; i++) {
ret = dt9812_read_info(dev, 1, &tmp8, sizeof(tmp8)); if (ret == 0) break;
} if (ret) {
dev_err(dev->class_dev, "unable to reset configuration\n"); return ret;
}
}
ret = dt9812_read_info(dev, 1, &tmp16, sizeof(tmp16)); if (ret) {
dev_err(dev->class_dev, "failed to read vendor id\n"); return ret;
}
vendor = le16_to_cpu(tmp16);
ret = dt9812_read_info(dev, 3, &tmp16, sizeof(tmp16)); if (ret) {
dev_err(dev->class_dev, "failed to read product id\n"); return ret;
}
product = le16_to_cpu(tmp16);
ret = dt9812_read_info(dev, 5, &tmp16, sizeof(tmp16)); if (ret) {
dev_err(dev->class_dev, "failed to read device id\n"); return ret;
}
devpriv->device = le16_to_cpu(tmp16);
ret = dt9812_read_info(dev, 7, &tmp32, sizeof(tmp32)); if (ret) {
dev_err(dev->class_dev, "failed to read serial number\n"); return ret;
}
serial = le32_to_cpu(tmp32);
/* let the user know what node this device is now attached to */
dev_info(dev->class_dev, "USB DT9812 (%4.4x.%4.4x.%4.4x) #0x%8.8x\n",
vendor, product, devpriv->device, serial);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.