Commit 6a38c239 authored by Federico Vaga's avatar Federico Vaga

sw:drv: use raw values to describe offsets

This goes against what described in the ZIO framework, but it is
actually a source of problems because the framework is largely
unmaintained.

With this patch the driver play only with raw values. It will be part
of the library duty to propose a different convention.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent d873ca7c
......@@ -15,6 +15,10 @@ Added
- sw: software version validation against FPGA version
- bld: flawfinder check on software tools
Changed
-------
- sw: offsets are not anymore in uV but they are just raw values
Fixed
-----
- sw: security fixes detected by flawfinder
......
......@@ -195,16 +195,16 @@ chN-50ohm-term
turn on the termination resistor. Default is 0.
chN-offset
The user offset is an integer value in the range [-5000000,5000000], and
it represents microvolts. The offset represents the center-scale
of conversion for the input channel. Internally, a DAC is used to
The user offset is an integer value in the range [-5.000V, +4.999V]. It
follows the DAC data format, so the range is describe by 16bits from 0x0000
(-5.000V) to 0xFFFF (+4.999V). Internally, a DAC is used to
generate the requested voltage, which is then subtracted from the
input signal. DAC values are corrected according to the
calibration values retrieved from the FMC EEPROM. For this reason,
the offset may saturate at values less than +/- 5V.
chN-offset-zero
The necessary offset to to bring the signal to 0 in microvolts (it must be
The necessary offset to to bring the signal to 0 in Volts (it must be
withing the range of chN-offset).
chN-vref
......
......@@ -207,47 +207,52 @@ static int fa_dac_offset_set(struct fa_dev *fa, unsigned int chan,
return fa_spi_xfer(fa, FA_SPI_SS_DAC(chan), 16, val, NULL);
}
static int64_t fa_dac_offset_raw_get(int32_t offset)
static uint16_t fa_dac_offset_raw_calibrate(struct fa_dev *fa,
uint16_t raw_offset,
int gain, int offset)
{
int32_t signed_offset = raw_offset - 0x8000;
int64_t hwval;
hwval = offset * 0x8000LL / 5000000;
if (hwval == 0x8000)
hwval = 0x7fff; /* -32768 .. 32767 */
return hwval;
}
static int64_t fa_dac_offset_raw_calibrate(int32_t raw_offset,
int gain, int offset)
{
int64_t hwval;
hwval = ((raw_offset + offset) * gain) >> 15; /* signed */
hwval = ((signed_offset + offset) * gain) >> 15; /* signed */
hwval += 0x8000; /* offset binary */
if (hwval < 0)
dev_dbg(&fa->pdev->dev,
"Final DAC calibrated value: (0x%08x + 0x%08x) * 0x%08x = 0x%08llx\n",
signed_offset, offset, gain, hwval);
/* Saturate */
if (hwval < 0) {
hwval = 0;
if (hwval > 0xffff)
dev_warn(&fa->pdev->dev,
"Final DAC calibrated value: lower saturation, set 0x%04llx",
hwval);
}
if (hwval > 0xffff) {
hwval = 0xffff;
dev_warn(&fa->pdev->dev,
"Final DAC calibrated value: lower saturation, set 0x%04llx",
hwval);
}
return hwval;
}
static int fa_dac_offset_get(struct fa_dev *fa, unsigned int chan)
static int fa_dac_offset_get(struct fa_dev *fa, unsigned int chan, uint16_t *offset)
{
int32_t off_uv = fa->user_offset[chan] + fa->zero_offset[chan];
int32_t user = fa->user_offset[chan];
int32_t zero = fa->zero_offset[chan];
int32_t __offset = (user + zero) - 0x8000; /* Bring back to DAC format */
if (WARN(off_uv < DAC_SAT_LOW,
"DAC lower saturation %d < %d\n",
off_uv, DAC_SAT_LOW)) {
off_uv = DAC_SAT_LOW;
}
if (WARN(off_uv > DAC_SAT_UP,
"DAC upper saturation %d > %d\n",
off_uv, DAC_SAT_UP)) {
off_uv = DAC_SAT_UP;
if (__offset & ~DAC_VAL_MASK) {
dev_err(&fa->pdev->dev,
"DAC offset value overflows 16bits. {user: 0x%04x, zero: 0x%04x, sum: 0x%08x}\n",
user, zero, __offset);
return -EINVAL;
}
return off_uv;
*offset = __offset;
return 0;
}
/**
......@@ -261,12 +266,16 @@ static int fa_dac_offset_get(struct fa_dev *fa, unsigned int chan)
int fa_calib_dac_config_chan(struct fa_dev *fa, unsigned int chan,
int32_t temperature, unsigned int flags)
{
int32_t off_uv = fa_dac_offset_get(fa, chan);
int32_t off_uv_raw = fa_dac_offset_raw_get(off_uv);
uint16_t value;
int range = fa->range[chan];
struct fa_calib_stanza *cal = &fa->calib.dac[range];
int gain;
int hwval;
int err;
err = fa_dac_offset_get(fa, chan, &value);
if (err)
return err;
if (fa_calib_is_compensation_on(fa)) {
int32_t delta_temp;
......@@ -286,7 +295,7 @@ int fa_calib_dac_config_chan(struct fa_dev *fa, unsigned int chan,
__func__, chan, range, gain, cal->offset[chan]);
}
hwval = fa_dac_offset_raw_calibrate(off_uv_raw, gain,
hwval = fa_dac_offset_raw_calibrate(fa, value, gain,
cal->offset[chan]);
return fa_dac_offset_set(fa, chan, hwval);
......
......@@ -553,8 +553,8 @@ static int __fa_init(struct fa_dev *fa)
for (i = 0; i < 4; ++i) {
fa_adc_range_set(fa, &zdev->cset->chan[i], FA100M14B4C_RANGE_1V);
/* reset channel offset */
fa->user_offset[i] = 0;
fa->zero_offset[i] = 0;
fa->user_offset[i] = 0x8000;
fa->zero_offset[i] = 0x8000;
}
/* Set decimation to minimum */
......@@ -710,8 +710,8 @@ static int fa_metadata_get(struct fa_dev *fa)
}
/* Dump meta*/
for (i = 0; i < sizeof(fa->meta); i += 4)
*(((char *)&fa->meta) + i) = fa_ioread(fa, mem + i);
for (i = 0; i < sizeof(fa->meta) / 4; ++i)
((uint32_t *)&fa->meta)[i] = fa_ioread(fa, mem + (i * 4));
iounmap(mem);
return 0;
......
......@@ -44,15 +44,15 @@ static struct zio_attribute zfad_cset_ext_zattr[] = {
*/
ZIO_ATTR_EXT("undersample", ZIO_RW_PERM, ZFAT_SR_UNDER, 1),
ZIO_ATTR_EXT("ch0-offset", ZIO_RW_PERM, ZFA_CH1_OFFSET, 0),
ZIO_ATTR_EXT("ch1-offset", ZIO_RW_PERM, ZFA_CH2_OFFSET, 0),
ZIO_ATTR_EXT("ch2-offset", ZIO_RW_PERM, ZFA_CH3_OFFSET, 0),
ZIO_ATTR_EXT("ch3-offset", ZIO_RW_PERM, ZFA_CH4_OFFSET, 0),
ZIO_ATTR_EXT("ch0-offset", ZIO_RW_PERM, ZFA_CH1_OFFSET, 0x8000),
ZIO_ATTR_EXT("ch1-offset", ZIO_RW_PERM, ZFA_CH2_OFFSET, 0x8000),
ZIO_ATTR_EXT("ch2-offset", ZIO_RW_PERM, ZFA_CH3_OFFSET, 0x8000),
ZIO_ATTR_EXT("ch3-offset", ZIO_RW_PERM, ZFA_CH4_OFFSET, 0x8000),
ZIO_ATTR_EXT("ch0-offset-zero", ZIO_RW_PERM, ZFA_SW_CH1_OFFSET_ZERO, 0),
ZIO_ATTR_EXT("ch1-offset-zero", ZIO_RW_PERM, ZFA_SW_CH2_OFFSET_ZERO, 0),
ZIO_ATTR_EXT("ch2-offset-zero", ZIO_RW_PERM, ZFA_SW_CH3_OFFSET_ZERO, 0),
ZIO_ATTR_EXT("ch3-offset-zero", ZIO_RW_PERM, ZFA_SW_CH4_OFFSET_ZERO, 0),
ZIO_ATTR_EXT("ch0-offset-zero", ZIO_RW_PERM, ZFA_SW_CH1_OFFSET_ZERO, 0x8000),
ZIO_ATTR_EXT("ch1-offset-zero", ZIO_RW_PERM, ZFA_SW_CH2_OFFSET_ZERO, 0x8000),
ZIO_ATTR_EXT("ch2-offset-zero", ZIO_RW_PERM, ZFA_SW_CH3_OFFSET_ZERO, 0x8000),
ZIO_ATTR_EXT("ch3-offset-zero", ZIO_RW_PERM, ZFA_SW_CH4_OFFSET_ZERO, 0x8000),
ZIO_ATTR_EXT("ch0-vref", ZIO_RW_PERM, ZFA_CH1_CTL_RANGE, 0),
ZIO_ATTR_EXT("ch1-vref", ZIO_RW_PERM, ZFA_CH2_CTL_RANGE, 0),
......@@ -160,12 +160,6 @@ int zfad_convert_user_range(uint32_t user_val)
return zfad_convert_hw_range(user_val);
}
static bool fa_is_dac_offset_valid(int32_t user, int32_t zero)
{
int32_t offset = user + zero;
return (offset >= DAC_SAT_LOW && offset <= DAC_SAT_UP);
}
/*
* zfad_conf_set
*
......@@ -209,15 +203,11 @@ static int zfad_conf_set(struct device *dev, struct zio_attribute *zattr,
/*fallthrough*/
case ZFA_SW_CH4_OFFSET_ZERO:
i--;
chan = to_zio_cset(dev)->chan + i;
if (!fa_is_dac_offset_valid(fa->user_offset[chan->index],
usr_val))
return -EINVAL;
spin_lock(&fa->zdev->cset->lock);
fa->zero_offset[i] = usr_val;
fa_calib_dac_config_chan(fa, i, 0, FA_CALIB_FLAG_READ_TEMP);
err = fa_calib_dac_config_chan(fa, i, 0, FA_CALIB_FLAG_READ_TEMP);
spin_unlock(&fa->zdev->cset->lock);
return 0;
return err;
case ZFA_CHx_SAT:
/* TODO when TLV */
break;
......@@ -244,11 +234,8 @@ static int zfad_conf_set(struct device *dev, struct zio_attribute *zattr,
/*fallthrough*/
case ZFA_CH4_OFFSET:
i--;
chan = to_zio_cset(dev)->chan + i;
if (!fa_is_dac_offset_valid(usr_val, fa->zero_offset[chan->index]))
return -EINVAL;
spin_lock(&fa->zdev->cset->lock);
fa->user_offset[chan->index] = usr_val;
fa->user_offset[i] = usr_val;
err = fa_calib_dac_config_chan(fa, i, 0,
FA_CALIB_FLAG_READ_TEMP);
spin_unlock(&fa->zdev->cset->lock);
......
......@@ -57,8 +57,7 @@ enum fa100m14b4c_trg_ext_attr_krn {
#define ADC_SPI_OFF 0x1800
#define ADC_UTC_OFF 0x1900
#define DAC_SAT_LOW -5000000
#define DAC_SAT_UP 5000000
#define DAC_VAL_MASK 0xFFFF
#define ADC_DMA 0
......@@ -292,8 +291,8 @@ struct fa_dev; /* forward declaration */
* @n_fires: number of trigger fire occurred within an acquisition
*
* @n_dma_err: number of errors
* @user_offset: user offset (micro-Volts)
* @zero_offset: necessary offset to push the channel to zero (micro-Volts)
* @user_offset: user offset
* @zero_offset: necessary offset to push the channel to zero
*/
struct fa_dev {
unsigned long flags;
......@@ -341,8 +340,8 @@ struct fa_dev {
unsigned int n_dma_err;
/* Configuration */
int32_t user_offset[4]; /* one per channel */
int32_t zero_offset[FA100M14B4C_NCHAN];
uint16_t user_offset[4]; /* one per channel */
uint16_t zero_offset[FA100M14B4C_NCHAN];
/* one-wire */
uint8_t ds18_id[8];
unsigned long next_t;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment