[media] msi3101: improve tuner synth calc step size

Allow stepless synthesizer configuration. With that change we lose
precision a little bit, as it is now between +-500Hz from the target.
It could be better but on that case calculation algorithm goes more
complex and atm there is more important things to do.
Two approach to improve which comes to my mind are:
1) select and use biggest suitable step
2) use greatest common divisor algo to find divisor for thresh & frac
when possible to avoid rounding errors, which is root of cause of
current +-500Hz inaccuracy.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
Antti Palosaari 2013-08-02 21:49:49 -03:00 committed by Mauro Carvalho Chehab
parent 22ca680e02
commit 23df427e33

View file

@ -1079,9 +1079,10 @@ static int msi3101_set_usb_adc(struct msi3101_state *s)
static int msi3101_set_tuner(struct msi3101_state *s)
{
int i, ret, len;
u32 reg, synthstep, thresh, n, frac;
u64 fsynth;
int ret, i, len;
unsigned int n, m, thresh, frac, vco_step, tmp;
u32 reg;
u64 f_vco;
u8 mode, lo_div;
const struct msi3101_gain *gain_lut;
static const struct {
@ -1176,21 +1177,30 @@ static int msi3101_set_tuner(struct msi3101_state *s)
if (i == ARRAY_SIZE(bandwidth_lut))
goto err;
#define FSTEP 10000
#define FREF1 24000000
fsynth = (rf_freq + 0) * lo_div;
synthstep = FSTEP * lo_div;
thresh = (FREF1 * 4) / synthstep;
n = fsynth / (FREF1 * 4);
frac = thresh * (fsynth % (FREF1 * 4)) / (FREF1 * 4);
#define F_OUT_STEP 1
#define R_REF 4
#define F_IF 0
f_vco = (rf_freq + F_IF) * lo_div;
n = f_vco / (F_REF * R_REF);
m = f_vco % (F_REF * R_REF);
if (thresh > 4095 || n > 63 || frac > 4095) {
dev_dbg(&s->udev->dev,
"%s: synth setup failed rf=%d thresh=%d n=%d frac=%d\n",
__func__, rf_freq, thresh, n, frac);
ret = -EINVAL;
goto err;
}
vco_step = F_OUT_STEP * lo_div;
thresh = (F_REF * R_REF) / vco_step;
frac = 1ul * thresh * m / (F_REF * R_REF);
/* Divide to reg max. After that RF resolution will be +-500Hz. */
tmp = DIV_ROUND_UP(thresh, 4095);
thresh = DIV_ROUND_CLOSEST(thresh, tmp);
frac = DIV_ROUND_CLOSEST(frac, tmp);
/* calc real RF set */
tmp = 1ul * F_REF * R_REF * n;
tmp += 1ul * F_REF * R_REF * frac / thresh;
tmp /= lo_div;
dev_dbg(&s->udev->dev,
"%s: rf=%u:%u n=%d thresh=%d frac=%d\n",
__func__, rf_freq, tmp, n, thresh, frac);
ret = msi3101_tuner_write(s, 0x00000e);
ret = msi3101_tuner_write(s, 0x000003);