Skip to content

Commit abd9025

Browse files
palosaarimchehab
authored andcommitted
[media] ts2020: add support for TS2022
TS2022 is slightly newer and different version of same tuner, which could be supported with rather small changes. Tuner type is auto-detected. Tested-by: David Howells <[email protected]> Signed-off-by: Antti Palosaari <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent 27254c3 commit abd9025

File tree

2 files changed

+129
-16
lines changed

2 files changed

+129
-16
lines changed

drivers/media/dvb-frontends/ts2020.c

Lines changed: 105 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,19 @@ struct ts2020_priv {
2929
/* i2c details */
3030
int i2c_address;
3131
struct i2c_adapter *i2c;
32-
u8 clk_out_div;
32+
u8 clk_out:2;
33+
u8 clk_out_div:5;
3334
u32 frequency;
3435
u32 frequency_div;
36+
#define TS2020_M88TS2020 0
37+
#define TS2020_M88TS2022 1
38+
u8 tuner;
39+
u8 loop_through:1;
40+
};
41+
42+
struct ts2020_reg_val {
43+
u8 reg;
44+
u8 val;
3545
};
3646

3747
static int ts2020_release(struct dvb_frontend *fe)
@@ -121,6 +131,9 @@ static int ts2020_sleep(struct dvb_frontend *fe)
121131
.len = 2
122132
};
123133

134+
if (priv->tuner == TS2020_M88TS2022)
135+
buf[0] = 0x00;
136+
124137
if (fe->ops.i2c_gate_ctrl)
125138
fe->ops.i2c_gate_ctrl(fe, 1);
126139

@@ -137,15 +150,64 @@ static int ts2020_sleep(struct dvb_frontend *fe)
137150
static int ts2020_init(struct dvb_frontend *fe)
138151
{
139152
struct ts2020_priv *priv = fe->tuner_priv;
153+
int i;
154+
u8 u8tmp;
155+
156+
if (priv->tuner == TS2020_M88TS2020) {
157+
ts2020_writereg(fe, 0x42, 0x73);
158+
ts2020_writereg(fe, 0x05, priv->clk_out_div);
159+
ts2020_writereg(fe, 0x20, 0x27);
160+
ts2020_writereg(fe, 0x07, 0x02);
161+
ts2020_writereg(fe, 0x11, 0xff);
162+
ts2020_writereg(fe, 0x60, 0xf9);
163+
ts2020_writereg(fe, 0x08, 0x01);
164+
ts2020_writereg(fe, 0x00, 0x41);
165+
} else {
166+
static const struct ts2020_reg_val reg_vals[] = {
167+
{0x7d, 0x9d},
168+
{0x7c, 0x9a},
169+
{0x7a, 0x76},
170+
{0x3b, 0x01},
171+
{0x63, 0x88},
172+
{0x61, 0x85},
173+
{0x22, 0x30},
174+
{0x30, 0x40},
175+
{0x20, 0x23},
176+
{0x24, 0x02},
177+
{0x12, 0xa0},
178+
};
179+
180+
ts2020_writereg(fe, 0x00, 0x01);
181+
ts2020_writereg(fe, 0x00, 0x03);
182+
183+
switch (priv->clk_out) {
184+
case TS2020_CLK_OUT_DISABLED:
185+
u8tmp = 0x60;
186+
break;
187+
case TS2020_CLK_OUT_ENABLED:
188+
u8tmp = 0x70;
189+
ts2020_writereg(fe, 0x05, priv->clk_out_div);
190+
break;
191+
case TS2020_CLK_OUT_ENABLED_XTALOUT:
192+
u8tmp = 0x6c;
193+
break;
194+
default:
195+
u8tmp = 0x60;
196+
break;
197+
}
198+
199+
ts2020_writereg(fe, 0x42, u8tmp);
200+
201+
if (priv->loop_through)
202+
u8tmp = 0xec;
203+
else
204+
u8tmp = 0x6c;
140205

141-
ts2020_writereg(fe, 0x42, 0x73);
142-
ts2020_writereg(fe, 0x05, priv->clk_out_div);
143-
ts2020_writereg(fe, 0x20, 0x27);
144-
ts2020_writereg(fe, 0x07, 0x02);
145-
ts2020_writereg(fe, 0x11, 0xff);
146-
ts2020_writereg(fe, 0x60, 0xf9);
147-
ts2020_writereg(fe, 0x08, 0x01);
148-
ts2020_writereg(fe, 0x00, 0x41);
206+
ts2020_writereg(fe, 0x62, u8tmp);
207+
208+
for (i = 0; i < ARRAY_SIZE(reg_vals); i++)
209+
ts2020_writereg(fe, reg_vals[i].reg, reg_vals[i].val);
210+
}
149211

150212
return 0;
151213
}
@@ -203,7 +265,14 @@ static int ts2020_set_params(struct dvb_frontend *fe)
203265
ndiv = ndiv + ndiv % 2;
204266
ndiv = ndiv - 1024;
205267

206-
ret = ts2020_writereg(fe, 0x10, 0x80 | lo);
268+
if (priv->tuner == TS2020_M88TS2020) {
269+
lpf_coeff = 2766;
270+
ret = ts2020_writereg(fe, 0x10, 0x80 | lo);
271+
} else {
272+
lpf_coeff = 3200;
273+
ret = ts2020_writereg(fe, 0x10, 0x0b);
274+
ret |= ts2020_writereg(fe, 0x11, 0x40);
275+
}
207276

208277
/* Set frequency divider */
209278
ret |= ts2020_writereg(fe, 0x01, (ndiv >> 8) & 0xf);
@@ -220,14 +289,24 @@ static int ts2020_set_params(struct dvb_frontend *fe)
220289
ret |= ts2020_tuner_gate_ctrl(fe, 0x08);
221290

222291
/* Tuner RF */
223-
ret |= ts2020_set_tuner_rf(fe);
292+
if (priv->tuner == TS2020_M88TS2020)
293+
ret |= ts2020_set_tuner_rf(fe);
224294

225295
gdiv28 = (TS2020_XTAL_FREQ / 1000 * 1694 + 500) / 1000;
226296
ret |= ts2020_writereg(fe, 0x04, gdiv28 & 0xff);
227297
ret |= ts2020_tuner_gate_ctrl(fe, 0x04);
228298
if (ret < 0)
229299
return -ENODEV;
230300

301+
if (priv->tuner == TS2020_M88TS2022) {
302+
ret = ts2020_writereg(fe, 0x25, 0x00);
303+
ret |= ts2020_writereg(fe, 0x27, 0x70);
304+
ret |= ts2020_writereg(fe, 0x41, 0x09);
305+
ret |= ts2020_writereg(fe, 0x08, 0x0b);
306+
if (ret < 0)
307+
return -ENODEV;
308+
}
309+
231310
value = ts2020_readreg(fe, 0x26);
232311

233312
f3db = (symbol_rate * 135) / 200 + 2000;
@@ -243,8 +322,6 @@ static int ts2020_set_params(struct dvb_frontend *fe)
243322
if (mlpf_max > 63)
244323
mlpf_max = 63;
245324

246-
lpf_coeff = 2766;
247-
248325
nlpf = (f3db * gdiv28 * 2 / lpf_coeff /
249326
(TS2020_XTAL_FREQ / 1000) + 1) / 2;
250327
if (nlpf > 23)
@@ -285,6 +362,13 @@ static int ts2020_get_frequency(struct dvb_frontend *fe, u32 *frequency)
285362
{
286363
struct ts2020_priv *priv = fe->tuner_priv;
287364
*frequency = priv->frequency;
365+
366+
return 0;
367+
}
368+
369+
static int ts2020_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
370+
{
371+
*frequency = 0; /* Zero-IF */
288372
return 0;
289373
}
290374

@@ -324,6 +408,7 @@ static struct dvb_tuner_ops ts2020_tuner_ops = {
324408
.sleep = ts2020_sleep,
325409
.set_params = ts2020_set_params,
326410
.get_frequency = ts2020_get_frequency,
411+
.get_if_frequency = ts2020_get_if_frequency,
327412
.get_rf_strength = ts2020_read_signal_strength,
328413
};
329414

@@ -340,6 +425,7 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
340425

341426
priv->i2c_address = config->tuner_address;
342427
priv->i2c = i2c;
428+
priv->clk_out = config->clk_out;
343429
priv->clk_out_div = config->clk_out_div;
344430
priv->frequency_div = config->frequency_div;
345431
fe->tuner_priv = priv;
@@ -358,9 +444,13 @@ struct dvb_frontend *ts2020_attach(struct dvb_frontend *fe,
358444

359445
/* Check the tuner version */
360446
buf = ts2020_readreg(fe, 0x00);
361-
if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81))
447+
if ((buf == 0x01) || (buf == 0x41) || (buf == 0x81)) {
362448
printk(KERN_INFO "%s: Find tuner TS2020!\n", __func__);
363-
else {
449+
priv->tuner = TS2020_M88TS2020;
450+
} else if ((buf == 0x83) || (buf == 0xc3)) {
451+
printk(KERN_INFO "%s: Find tuner TS2022!\n", __func__);
452+
priv->tuner = TS2020_M88TS2022;
453+
} else {
364454
printk(KERN_ERR "%s: Read tuner reg[0] = %d\n", __func__, buf);
365455
kfree(priv);
366456
return NULL;

drivers/media/dvb-frontends/ts2020.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,31 @@
2727

2828
struct ts2020_config {
2929
u8 tuner_address;
30-
u8 clk_out_div;
3130
u32 frequency_div;
31+
32+
/*
33+
* RF loop-through
34+
*/
35+
u8 loop_through:1;
36+
37+
/*
38+
* clock output
39+
*/
40+
#define TS2020_CLK_OUT_DISABLED 0
41+
#define TS2020_CLK_OUT_ENABLED 1
42+
#define TS2020_CLK_OUT_ENABLED_XTALOUT 2
43+
u8 clk_out:2;
44+
45+
/*
46+
* clock output divider
47+
* 1 - 31
48+
*/
49+
u8 clk_out_div:5;
50+
51+
/*
52+
* pointer to DVB frontend
53+
*/
54+
struct dvb_frontend *fe;
3255
};
3356

3457
#if IS_ENABLED(CONFIG_DVB_TS2020)

0 commit comments

Comments
 (0)