Commit 98e64175 authored by Alessandro Rubini's avatar Alessandro Rubini

calibrate: added timer_temp (renamed timer_fifo)

parent 62903999
......@@ -15,10 +15,14 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/math64.h>
#include <linux/moduleparam.h>
#include "fine-delay.h"
#include "hw/fd_main_regs.h"
#include "hw/acam_gpx.h"
int fd_calib_period_s = 30;
module_param_named(calib_s, fd_calib_period_s, int, 0444);
/*
* Calculation is fixed point: picoseconds and 16 decimals (i.e. ps << 16).
* We know the bin is small, but the Tref is several nanos so we need 64 bits
......@@ -331,10 +335,15 @@ int fd_acam_init(struct spec_fd *fd)
fd_writel(fd, 3 * fd->calib.acam_start_offset, FD_REG_ASOR);
fd_writel(fd, fd->calib.atmcr_val, FD_REG_ATMCR);
/* Prepare the timely recalibration */
setup_timer(&fd->temp_timer, fd_update_calibration, (unsigned long)fd);
if (fd_calib_period_s)
mod_timer(&fd->temp_timer, jiffies + HZ * fd_calib_period_s);
return 0;
}
void fd_acam_exit(struct spec_fd *fd)
{
/* nothing to do */
del_timer_sync(&fd->temp_timer);
}
......@@ -179,25 +179,55 @@ static int fd_find_8ns_tap(struct spec_fd *fd, int ch)
int fd_calibrate_outputs(struct spec_fd *fd)
{
int ret, ch;
int measured, fitted;
int measured, fitted, new;
acam_set_bypass(fd, 1); /* not useful */
fd_writel(fd, FD_TDCSR_START_EN | FD_TDCSR_STOP_EN, FD_REG_TDCSR);
if ((ret = acam_test_delay_transfer_function(fd)) < 0)
return ret;
fd_read_temp(fd, 0);
fitted = fd_eval_polynomial(fd);
for (ch = FD_CH_1; ch <= FD_CH_LAST; ch++) {
fd_read_temp(fd, 0);
measured = fd_find_8ns_tap(fd, ch);
fd->ch[ch].frr_cur = measured;
fd->ch[ch].frr_offset = measured - fitted;
pr_info("%s: ch %i: 8ns @ %i (f %i, offset %i, t %i.%02i)\n",
__func__, FD_CH_EXT(ch),
fd->ch[ch].frr_cur, fitted, fd->ch[ch].frr_offset,
fd->temp / 16, (fd->temp & 0xf) * 100 / 16);
new = measured;
fd->ch[ch].frr_offset = new - fitted;
fd_ch_writel(fd, ch, new, FD_REG_FRR);
fd->ch[ch].frr_cur = new;
if (1) {
pr_info("%s: ch%i: 8ns @%i (f %i, off %i, t %i.%02i)\n",
__func__, FD_CH_EXT(ch),
new, fitted, fd->ch[ch].frr_offset,
fd->temp / 16, (fd->temp & 0xf) * 100 / 16);
}
}
return 0;
}
/* Called from a timer any few seconds */
void fd_update_calibration(unsigned long arg)
{
struct spec_fd *fd = (void *)arg;
int ch, fitted, new;
fd_read_temp(fd, 0 /* not verbose */);
fitted = fd_eval_polynomial(fd);
for (ch = FD_CH_1; ch <= FD_CH_LAST; ch++) {
new = fitted + fd->ch[ch].frr_offset;
fd_ch_writel(fd, ch, new, FD_REG_FRR);
fd->ch[ch].frr_cur = new;
if (0) {
pr_info("%s: ch%i: 8ns @%i (f %i, off %i, t %i.%02i)\n",
__func__, FD_CH_EXT(ch),
new, fitted, fd->ch[ch].frr_offset,
fd->temp / 16, (fd->temp & 0xf) * 100 / 16);
}
}
mod_timer(&fd->temp_timer, jiffies + HZ * fd_calib_period_s);
}
......@@ -275,6 +275,12 @@ The following parameters are used:
polling code. The interval by default is 10ms and currently
only one timestamp is retrieved at each timer execution.
@item calib_s=
The period, in seconds, of temperature measurement to recalibrate
the output delays. Defaults to 30. If set to zero, the timer is
not activated.
@end table
@c ##########################################################################
......
......@@ -304,7 +304,7 @@ static void fd_timer_fn(unsigned long arg)
}
out:
mod_timer(&fd->timer, jiffies + fd_timer_period_jiffies);
mod_timer(&fd->fifo_timer, jiffies + fd_timer_period_jiffies);
}
static int fd_output(struct zio_cset *cset)
......@@ -490,15 +490,15 @@ int fd_zio_init(struct spec_fd *fd)
return err;
}
setup_timer(&fd->timer, fd_timer_fn, (unsigned long)fd);
setup_timer(&fd->fifo_timer, fd_timer_fn, (unsigned long)fd);
if (fd_timer_period_ms)
mod_timer(&fd->timer, jiffies + fd_timer_period_jiffies);
mod_timer(&fd->fifo_timer, jiffies + fd_timer_period_jiffies);
return 0;
}
void fd_zio_exit(struct spec_fd *fd)
{
del_timer_sync(&fd->timer);
del_timer_sync(&fd->fifo_timer);
zio_unregister_device(fd->hwzdev);
zio_free_device(fd->hwzdev);
}
......@@ -93,7 +93,8 @@ struct spec_fd {
unsigned long flags;
struct spec_dev *spec;
struct zio_device *zdev, *hwzdev;
struct timer_list timer;
struct timer_list fifo_timer;
struct timer_list temp_timer;
struct fd_calib calib;
struct fd_ch ch[FD_CH_NUMBER];
unsigned char __iomem *base; /* regs files are byte-oriented */
......@@ -240,6 +241,9 @@ extern void acam_writel(struct spec_fd *fd, int val, int reg);
/* Functions exported by calibrate.c, called within acam.c */
extern int fd_calibrate_outputs(struct spec_fd *fd);
extern void fd_update_calibration(unsigned long arg);
extern int fd_calib_period_s;
/* Functions exported by gpio.c */
extern int fd_gpio_init(struct spec_fd *fd);
......
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