Commit af9d5255 authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab

[media] ts2020: re-implement PLL calculations

Used frequency synthesizer is simple Integer-N PLL, with configurable
reference divider, output divider and of course N itself. Old
calculations were working fine, but not so easy to understand.
Signed-off-by: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@osg.samsung.com>
parent 95a86e43
...@@ -32,8 +32,8 @@ struct ts2020_priv { ...@@ -32,8 +32,8 @@ struct ts2020_priv {
struct i2c_adapter *i2c; struct i2c_adapter *i2c;
u8 clk_out:2; u8 clk_out:2;
u8 clk_out_div:5; u8 clk_out_div:5;
u32 frequency; u32 frequency_div; /* LO output divider switch frequency */
u32 frequency_div; u32 frequency_khz; /* actual used LO frequency */
#define TS2020_M88TS2020 0 #define TS2020_M88TS2020 0
#define TS2020_M88TS2022 1 #define TS2020_M88TS2022 1
u8 tuner; u8 tuner;
...@@ -233,45 +233,62 @@ static int ts2020_set_params(struct dvb_frontend *fe) ...@@ -233,45 +233,62 @@ static int ts2020_set_params(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct ts2020_priv *priv = fe->tuner_priv; struct ts2020_priv *priv = fe->tuner_priv;
int ret; int ret;
u32 frequency = c->frequency;
s32 offset_khz;
u32 symbol_rate = (c->symbol_rate / 1000); u32 symbol_rate = (c->symbol_rate / 1000);
u32 f3db, gdiv28; u32 f3db, gdiv28;
u16 value, ndiv, lpf_coeff; u16 u16tmp, value, lpf_coeff;
u8 lpf_mxdiv, mlpf_max, mlpf_min, nlpf; u8 buf[3], reg10, lpf_mxdiv, mlpf_max, mlpf_min, nlpf;
u8 lo = 0x01, div4 = 0x0; unsigned int f_ref_khz, f_vco_khz, div_ref, div_out, pll_n;
unsigned int frequency_khz = c->frequency;
/* Calculate frequency divider */
if (frequency < priv->frequency_div) { /*
lo |= 0x10; * Integer-N PLL synthesizer
div4 = 0x1; * kHz is used for all calculations to keep calculations within 32-bit
ndiv = (frequency * 14 * 4) / TS2020_XTAL_FREQ; */
} else f_ref_khz = TS2020_XTAL_FREQ;
ndiv = (frequency * 14 * 2) / TS2020_XTAL_FREQ; div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000);
ndiv = ndiv + ndiv % 2;
ndiv = ndiv - 1024; /* select LO output divider */
if (frequency_khz < priv->frequency_div) {
div_out = 4;
reg10 = 0x10;
} else {
div_out = 2;
reg10 = 0x00;
}
f_vco_khz = frequency_khz * div_out;
pll_n = f_vco_khz * div_ref / f_ref_khz;
pll_n += pll_n % 2;
priv->frequency_khz = pll_n * f_ref_khz / div_ref / div_out;
pr_debug("frequency=%u offset=%d f_vco_khz=%u pll_n=%u div_ref=%u div_out=%u\n",
priv->frequency_khz, priv->frequency_khz - c->frequency,
f_vco_khz, pll_n, div_ref, div_out);
if (priv->tuner == TS2020_M88TS2020) { if (priv->tuner == TS2020_M88TS2020) {
lpf_coeff = 2766; lpf_coeff = 2766;
ret = ts2020_writereg(fe, 0x10, 0x80 | lo); reg10 |= 0x01;
ret = ts2020_writereg(fe, 0x10, reg10);
} else { } else {
lpf_coeff = 3200; lpf_coeff = 3200;
ret = ts2020_writereg(fe, 0x10, 0x0b); reg10 |= 0x0b;
ret = ts2020_writereg(fe, 0x10, reg10);
ret |= ts2020_writereg(fe, 0x11, 0x40); ret |= ts2020_writereg(fe, 0x11, 0x40);
} }
/* Set frequency divider */ u16tmp = pll_n - 1024;
ret |= ts2020_writereg(fe, 0x01, (ndiv >> 8) & 0xf); buf[0] = (u16tmp >> 8) & 0xff;
ret |= ts2020_writereg(fe, 0x02, ndiv & 0xff); buf[1] = (u16tmp >> 0) & 0xff;
buf[2] = div_ref - 8;
ret |= ts2020_writereg(fe, 0x01, buf[0]);
ret |= ts2020_writereg(fe, 0x02, buf[1]);
ret |= ts2020_writereg(fe, 0x03, buf[2]);
ret |= ts2020_writereg(fe, 0x03, 0x06);
ret |= ts2020_tuner_gate_ctrl(fe, 0x10); ret |= ts2020_tuner_gate_ctrl(fe, 0x10);
if (ret < 0) if (ret < 0)
return -ENODEV; return -ENODEV;
/* Tuner Frequency Range */
ret = ts2020_writereg(fe, 0x10, lo);
ret |= ts2020_tuner_gate_ctrl(fe, 0x08); ret |= ts2020_tuner_gate_ctrl(fe, 0x08);
/* Tuner RF */ /* Tuner RF */
...@@ -335,11 +352,6 @@ static int ts2020_set_params(struct dvb_frontend *fe) ...@@ -335,11 +352,6 @@ static int ts2020_set_params(struct dvb_frontend *fe)
ret |= ts2020_tuner_gate_ctrl(fe, 0x01); ret |= ts2020_tuner_gate_ctrl(fe, 0x01);
msleep(80); msleep(80);
/* calculate offset assuming 96000kHz*/
offset_khz = (ndiv - ndiv % 2 + 1024) * TS2020_XTAL_FREQ
/ (6 + 8) / (div4 + 1) / 2;
priv->frequency = offset_khz;
return (ret < 0) ? -EINVAL : 0; return (ret < 0) ? -EINVAL : 0;
} }
...@@ -347,8 +359,8 @@ static int ts2020_set_params(struct dvb_frontend *fe) ...@@ -347,8 +359,8 @@ static int ts2020_set_params(struct dvb_frontend *fe)
static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency) static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{ {
struct ts2020_priv *priv = fe->tuner_priv; struct ts2020_priv *priv = fe->tuner_priv;
*frequency = priv->frequency;
*frequency = priv->frequency_khz;
return 0; return 0;
} }
......
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