Commit fdf2ee65 authored by Federico Vaga's avatar Federico Vaga

kernel: add the possibility to provide custum calibration

Here we do a little hack because I'm already thinking about
a future verison of this driver.

Instead of providing a calibration binary attribute the driver
offers an eeprom_config binary attribute where you can write
data as if it was on the eeprom (calibration data included).
The driver will extract the calibration and configure the ADC.

I'm doing this because we plan to move to platform devices
instead of fmc devices. For this reason the access to the eeprom
will not be easy as today. To begin with we will have a binary
attrbibute where you can write your eeprom content.
Signed-off-by: Federico Vaga's avatarFederico Vaga <federico.vaga@cern.ch>
parent c8eccabe
......@@ -91,3 +91,68 @@ void fa_read_eeprom_calib(struct fa_dev *fa)
fa_endian_calib(&fa->calib);
fa_verify_calib(&fa->fmc->dev, &fa->calib, &fa_identity_calib);
}
/**
* Calculate calibrated values for offset and range using current values
* @fa: FMC ADC device
* @chan: channel
*/
static void fa_apply_calib(struct fa_dev *fa, struct zio_channel *chan)
{
int reg = zfad_get_chx_index(ZFA_CHx_CTL_RANGE, chan);
int range = fa_readl(fa, fa->fa_adc_csr_base, &zfad_regs[reg]);
zfad_set_range(fa, chan, range);
zfad_apply_offset(chan);
}
static ssize_t fa_write_eeprom(struct file *file, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct fa_dev *fa = get_zfadc(dev);
struct fa_calib *calib = (struct fa_calib *) buf;
int i;
if (off != 0 || count != sizeof(*calib))
return -EINVAL;
fa_endian_calib(calib);
fa_verify_calib(dev, calib, &fa_identity_calib);
/*
* The user should be careful enough to not change calibration
* values while running an acquisition
*/
memcpy(&fa->calib, calib, sizeof(*calib));
for (i = 0; i < FA100M14B4C_NCHAN; ++i)
fa_apply_calib(fa, &fa->zdev->cset->chan[i]);
return count;
}
static ssize_t fa_read_eeprom(struct file *file, struct kobject *kobj,
struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct fa_dev *fa = get_zfadc(dev);
if (off != 0 || count < sizeof(fa->calib))
return -EINVAL;
memcpy(buf, &fa->calib, sizeof(fa->calib));
return count;
}
struct bin_attribute dev_attr_calibration = {
.attr = {
.name = "calibration_data",
.mode = 0744,
},
.size = sizeof(struct fa_calib),
.write = fa_write_eeprom,
.read = fa_read_eeprom,
};
......@@ -394,7 +394,7 @@ static int __fa_init(struct fa_dev *fa)
}
}
/* Retrieve calibration from the eeprom and validate*/
/* Use identity calibration */
fa_read_eeprom_calib(fa);
fa->mshot_max_samples = fa_readl(fa, fa->fa_adc_csr_base,
&zfad_regs[ZFA_MULT_MAX_SAMP]);
......@@ -557,7 +557,7 @@ int fa_probe(struct fmc_device *fmc)
err = fa_setup_irqs(fa);
if (err < 0)
goto out;
goto out_irq;
/* Pin the carrier */
if (!try_module_get(fmc->owner))
......@@ -567,6 +567,7 @@ int fa_probe(struct fmc_device *fmc)
out_mod:
fa_free_irqs(fa);
out_irq:
out:
while (--m, --i >= 0)
if (m->exit)
......
......@@ -544,6 +544,10 @@ static int zfad_zio_probe(struct zio_device *zdev)
if (err)
return err;
err = device_create_bin_file(&zdev->cset->head.dev, &dev_attr_calibration);
if (err)
return err;
/* We don't have csets at this point, so don't do anything more */
return 0;
}
......@@ -556,6 +560,8 @@ static int zfad_zio_probe(struct zio_device *zdev)
*/
static int zfad_zio_remove(struct zio_device *zdev)
{
device_remove_bin_file(&zdev->cset->head.dev, &dev_attr_calibration);
return 0;
}
......
......@@ -540,6 +540,8 @@ static inline void fa_writel(struct fa_dev *fa,
fa_iowrite(fa, val, base_off+field->offset);
}
extern struct bin_attribute dev_attr_calibration;
/* Global variable exported by fa-core.c */
extern struct workqueue_struct *fa_workqueue;
......
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