Commit 53dc6acd authored by Alessandro Rubini's avatar Alessandro Rubini

kernel: verify EEPROM calibration data

This commit verifies that the eeprom data makes sense. If an error
is found, identity calibration is selected instead.

Endian conversion is not there yet.
Signed-off-by: Alessandro Rubini's avatarAlessandro Rubini <rubini@gnudd.com>
parent da1e589a
......@@ -971,6 +971,71 @@ struct fmc_gpio zfat_gpio_cfg[] = {
}
};
/* * * * * * * * * * * * * * * * Calibration checks * * * * * * * * * * * */
/* This identity calibration is used as default */
static struct fa_calib_stanza fa_identity_calib = {
.offset = { 0, },
.gain = {0x8000, 0x8000, 0x8000, 0x8000},
.temperature = 50 * 100, /* 50 celsius degrees */
};
/* Max difference from identity thing */
#define FA_CALIB_MAX_DELTA_OFFSET 0x1000
#define FA_CALIB_MAX_DELTA_GAIN 0x1000
#define FA_CALIB_MAX_DELTA_TEMP (40 * 100) /* 10-90 celsius */
/* Actual verification code */
static int zfad_verify_calib_stanza(struct device *msgdev, char *name, int r,
struct fa_calib_stanza *cal,
struct fa_calib_stanza *iden)
{
int i, err = 0;
for (i = 0; i < ARRAY_SIZE(cal->offset); i++) {
if (abs(cal->offset[i] - iden->offset[i])
> FA_CALIB_MAX_DELTA_OFFSET) {
dev_dbg(msgdev, "wrong offset 0x%x\n", cal->offset[i]);
err++;
}
if (abs((s16)(cal->gain[i] - iden->gain[i]))
> FA_CALIB_MAX_DELTA_GAIN) {
dev_dbg(msgdev, "wrong gain 0x%x\n", cal->gain[i]);
err++;
}
}
if (abs((s16)(cal->temperature - iden->temperature))
> FA_CALIB_MAX_DELTA_TEMP) {
dev_dbg(msgdev, "wrong temper 0x%x\n", cal->temperature);
err++;
}
if (err)
dev_dbg(msgdev, "%i errors in %s calibration, range %i\n",
err, name, r);
return err;
}
static void zfad_verify_calib(struct device *msgdev,
struct fa_calib *calib,
struct fa_calib_stanza *identity)
{
int i, err = 0;
for (i = 0; i < ARRAY_SIZE(calib->adc); i++) {
err += zfad_verify_calib_stanza(msgdev, "adc", i,
calib->adc + i, identity);
err += zfad_verify_calib_stanza(msgdev, "dac", i,
calib->dac + i, identity);
}
if (!err)
return;
dev_info(msgdev, "Invalid calibration in EEPROM (%i errors)\n", err);
dev_info(msgdev, "Using identity calibration\n");
for (i = 0; i < ARRAY_SIZE(calib->adc); i++) {
calib->adc[i] = *identity;
calib->dac[i] = *identity;
}
}
/* * * * * * * * * * * * * * * * Initialization * * * * * * * * * * * * * * */
......@@ -990,8 +1055,9 @@ static int zfad_zio_probe(struct zio_device *zdev)
/* Save also the pointer to the real zio_device */
fa->zdev = zdev;
/* Retrieve calibration data from the eeprom. FIXME: verify it */
/* Retrieve calibration data from the eeprom, then verify it */
memcpy(&fa->calib, fa->fmc->eeprom + FA_CAL_OFFSET, sizeof(fa->calib));
zfad_verify_calib(&fa->fmc->dev, &fa->calib, &fa_identity_calib);
/* Configure GPIO for IRQ */
fa->fmc->op->gpio_config(fa->fmc, zfat_gpio_cfg,
......
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