Commit 398f233d authored by Federico Vaga's avatar Federico Vaga

drv: update calibration mechanism

First we change change the values in the GAIN and OFFSET register,
then we apply the configuration by writing 1 in the CALIB_APPLY field.

The patch is more complex than just set one bit becuase it is ready to
implement the calibration thread that will compensate the GAIN factor
based on the current temperature.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent 660db16b
......@@ -8,6 +8,8 @@
#include <linux/types.h>
#include <linux/byteorder/generic.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/zio.h>
#include <fmc-adc-100m14b4cha.h>
/* This identity calibration is used as default */
......@@ -21,6 +23,79 @@ static const struct fa_calib_stanza fa_identity_calib = {
#define FA_CALIB_MAX_DELTA_GAIN 0x1000
#define FA_CALIB_MAX_DELTA_TEMP (40 * 100) /* 10-90 celsius */
static bool fa_calib_is_busy(struct fa_dev *fa)
{
return !!fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_STA_CALIB_BUSY]);
}
static int fa_calib_apply(struct fa_dev *fa)
{
if (fa_calib_is_busy(fa))
return -EBUSY;
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[ZFA_CTL_CALIB_APPLY], 1);
ndelay(100);
if (fa_calib_is_busy(fa))
return -EBUSY;
return 0;
}
static void fa_calib_gain_set(struct fa_dev *fa, unsigned int chan, int val)
{
int attr_idx;
attr_idx = zfad_get_chx_index(ZFA_CHx_GAIN, chan);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[attr_idx], val);
}
static void fa_calib_offset_set(struct fa_dev *fa, unsigned int chan, int val)
{
int attr_idx;
attr_idx = zfad_get_chx_index(ZFA_CHx_OFFSET, chan);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[attr_idx],
val & 0xFFFF /* prevent warning */);
}
static int fa_calib_adc_offset_fix(struct fa_dev *fa, int range, int offset)
{
return offset;
}
static int fa_calib_adc_gain_fix(struct fa_dev *fa, int range, int gain)
{
return gain;
}
static void fa_calib_adc_config_chan(struct fa_dev *fa, unsigned int chan)
{
int range = fa->range[chan];
int offset = fa->calib.adc[range].offset[chan];
int gain = fa->calib.adc[range].gain[chan];
dev_dbg(&fa->pdev->dev, "%s: orig: {range: %d, gain: 0x%x, offset: 0x%x}\n",
__func__, range, gain, offset);
offset = fa_calib_adc_offset_fix(fa, range, offset);
gain = fa_calib_adc_gain_fix(fa, range, gain);
dev_dbg(&fa->pdev->dev, "%s: fixed: {range: %d, gain: 0x%x, offset: 0x%x}\n",
__func__, range, gain, offset);
fa_calib_gain_set(fa, chan, gain);
fa_calib_offset_set(fa, chan, offset);
}
int fa_calib_adc_config(struct fa_dev *fa)
{
int i;
for (i = 0; i < FA100M14B4C_NCHAN; ++i)
fa_calib_adc_config_chan(fa, i);
return fa_calib_apply(fa);
}
/* Actual verification code */
static int fa_verify_calib_stanza(struct device *msgdev, char *name, int r,
struct fa_calib_stanza *cal)
......
......@@ -248,7 +248,7 @@ void zfad_init_saturation(struct fa_dev *fa)
int zfad_set_range(struct fa_dev *fa, struct zio_channel *chan,
int range)
{
int i, offset, gain;
int i;
/* Actually set the range */
i = zfad_get_chx_index(ZFA_CHx_CTL_RANGE, chan->index);
......@@ -258,6 +258,7 @@ int zfad_set_range(struct fa_dev *fa, struct zio_channel *chan,
range = FA100M14B4C_RANGE_1V;
else if (range >= FA100M14B4C_RANGE_10V_CAL)
range -= FA100M14B4C_RANGE_10V_CAL;
fa->range[chan->index] = range;
if (range < 0 || range > ARRAY_SIZE(fa->calib.adc)) {
dev_info(fa->msgdev, "Invalid range %i or ch %i\n",
......@@ -265,19 +266,9 @@ int zfad_set_range(struct fa_dev *fa, struct zio_channel *chan,
return -EINVAL;
}
offset = fa->calib.adc[range].offset[chan->index];
gain = fa->calib.adc[range].gain[chan->index];
i = zfad_get_chx_index(ZFA_CHx_OFFSET, chan->index);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[i],
offset & 0xffff /* prevent warning */);
i = zfad_get_chx_index(ZFA_CHx_GAIN, chan->index);
fa_writel(fa, fa->fa_adc_csr_base, &zfad_regs[i], gain);
/* recalculate user offset for the new range */
zfad_apply_offset(chan);
return 0;
return fa_calib_adc_config(fa);
}
/*
......
......@@ -18,11 +18,13 @@ const struct zfa_field_desc zfad_regs[] = {
[ZFA_CTL_TRIG_LED] = {0x00, 0x00000040, 1},
[ZFA_CTL_ACQ_LED] = {0x00, 0x00000080, 1},
[ZFA_CTL_RST_TRG_STA] = {0x00, 0x00000100, 1},
[ZFA_CTL_CALIB_APPLY] = {0x00, 0x00008000, 1},
/* Status registers */
[ZFA_STA_FSM] = {0x04, 0x00000007, 1},
[ZFA_STA_SERDES_PLL] = {0x04, 0x00000008, 1},
[ZFA_STA_SERDES_SYNCED] = {0x04, 0x00000010, 1},
[ZFA_STA_FMC_NR] = {0x04, 0x000000c0, 1},
[ZFA_STA_CALIB_BUSY] = {0x04, 0x00008000, 1},
/* Trigger */
/* Config register */
[ZFAT_CFG_STA] = {0x08, 0xFFFFFFFF, 0},
......
......@@ -155,7 +155,7 @@ static struct zio_attribute zfad_dev_ext_zattr[] = {
};
/* Temporarily, user values are the same as hardware values */
static int zfad_convert_user_range(uint32_t user_val)
int zfad_convert_user_range(uint32_t user_val)
{
return zfad_convert_hw_range(user_val);
}
......
......@@ -214,11 +214,13 @@ enum zfadc_dregs_enum {
ZFA_CTL_TRIG_LED,
ZFA_CTL_ACQ_LED,
ZFA_CTL_RST_TRG_STA,
ZFA_CTL_CALIB_APPLY,
/* Status registers */
ZFA_STA_FSM,
ZFA_STA_SERDES_PLL,
ZFA_STA_SERDES_SYNCED,
ZFA_STA_FMC_NR,
ZFA_STA_CALIB_BUSY,
/* Configuration register */
ZFAT_CFG_STA,
ZFAT_CFG_SRC,
......@@ -447,6 +449,7 @@ struct fa_dev {
/* Calibration Data */
struct fa_calib calib;
int32_t range[FA100M14B4C_NCHAN];
/* flag */
int enable_auto_start;
......@@ -599,6 +602,9 @@ extern int zfad_fsm_command(struct fa_dev *fa, uint32_t command);
extern int zfad_apply_offset(struct zio_channel *chan);
extern void zfad_reset_offset(struct fa_dev *fa);
extern int zfad_convert_hw_range(uint32_t bitmask);
/* Temporarily, user values are the same as hardware values */
extern int zfad_convert_user_range(uint32_t user_val);
extern int zfad_set_range(struct fa_dev *fa, struct zio_channel *chan,
int range);
extern int zfad_get_chx_index(unsigned long addr, unsigned int chan);
......@@ -635,6 +641,7 @@ extern void fa_spi_exit(struct fa_dev *fd);
/* function exporetd by fa-calibration.c */
extern int fa_calib_init(struct fa_dev *fa);
extern void fa_calib_exit(struct fa_dev *fa);
extern int fa_calib_adc_config(struct fa_dev *fa);
/* functions exported by fa-debug.c */
extern int fa_debug_init(struct fa_dev *fa);
......
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