diff options
author | Antti Palosaari <crope@iki.fi> | 2013-08-02 21:49:49 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-08-20 16:04:50 -0300 |
commit | 23df427e3333882beea2e65d27fd2a581e37fae4 (patch) | |
tree | d9dde0746899c8dd9db50ccf451694eca5544a9d | |
parent | 22ca680e02aceb88d939b1eb1bbe3e94b71bf555 (diff) |
[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>
-rw-r--r-- | drivers/staging/media/msi3101/sdr-msi3101.c | 44 |
1 files changed, 27 insertions, 17 deletions
diff --git a/drivers/staging/media/msi3101/sdr-msi3101.c b/drivers/staging/media/msi3101/sdr-msi3101.c index 04bbbdf0acd3..4ff6030bc950 100644 --- a/drivers/staging/media/msi3101/sdr-msi3101.c +++ b/drivers/staging/media/msi3101/sdr-msi3101.c @@ -1079,9 +1079,10 @@ err: 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); |