1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun TDA10021 - Single Chip Cable Channel Receiver driver module
4*4882a593Smuzhiyun used on the Siemens DVB-C cards
5*4882a593Smuzhiyun
6*4882a593Smuzhiyun Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
7*4882a593Smuzhiyun Copyright (C) 2004 Markus Schulz <msc@antzsystem.de>
8*4882a593Smuzhiyun Support for TDA10021
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun */
11*4882a593Smuzhiyun
12*4882a593Smuzhiyun #include <linux/delay.h>
13*4882a593Smuzhiyun #include <linux/errno.h>
14*4882a593Smuzhiyun #include <linux/init.h>
15*4882a593Smuzhiyun #include <linux/kernel.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <linux/string.h>
18*4882a593Smuzhiyun #include <linux/slab.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <media/dvb_frontend.h>
21*4882a593Smuzhiyun #include "tda1002x.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun struct tda10021_state {
25*4882a593Smuzhiyun struct i2c_adapter* i2c;
26*4882a593Smuzhiyun /* configuration settings */
27*4882a593Smuzhiyun const struct tda1002x_config* config;
28*4882a593Smuzhiyun struct dvb_frontend frontend;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun u8 pwm;
31*4882a593Smuzhiyun u8 reg0;
32*4882a593Smuzhiyun };
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun #if 0
36*4882a593Smuzhiyun #define dprintk(x...) printk(x)
37*4882a593Smuzhiyun #else
38*4882a593Smuzhiyun #define dprintk(x...)
39*4882a593Smuzhiyun #endif
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun static int verbose;
42*4882a593Smuzhiyun
43*4882a593Smuzhiyun #define XIN 57840000UL
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun #define FIN (XIN >> 4)
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun static int tda10021_inittab_size = 0x40;
48*4882a593Smuzhiyun static u8 tda10021_inittab[0x40]=
49*4882a593Smuzhiyun {
50*4882a593Smuzhiyun 0x73, 0x6a, 0x23, 0x0a, 0x02, 0x37, 0x77, 0x1a,
51*4882a593Smuzhiyun 0x37, 0x6a, 0x17, 0x8a, 0x1e, 0x86, 0x43, 0x40,
52*4882a593Smuzhiyun 0xb8, 0x3f, 0xa1, 0x00, 0xcd, 0x01, 0x00, 0xff,
53*4882a593Smuzhiyun 0x11, 0x00, 0x7c, 0x31, 0x30, 0x20, 0x00, 0x00,
54*4882a593Smuzhiyun 0x02, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, 0x00,
55*4882a593Smuzhiyun 0x07, 0x00, 0x33, 0x11, 0x0d, 0x95, 0x08, 0x58,
56*4882a593Smuzhiyun 0x00, 0x00, 0x80, 0x00, 0x80, 0xff, 0x00, 0x00,
57*4882a593Smuzhiyun 0x04, 0x2d, 0x2f, 0xff, 0x00, 0x00, 0x00, 0x00,
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
_tda10021_writereg(struct tda10021_state * state,u8 reg,u8 data)60*4882a593Smuzhiyun static int _tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun u8 buf[] = { reg, data };
63*4882a593Smuzhiyun struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
64*4882a593Smuzhiyun int ret;
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun ret = i2c_transfer (state->i2c, &msg, 1);
67*4882a593Smuzhiyun if (ret != 1)
68*4882a593Smuzhiyun printk("DVB: TDA10021(%d): %s, writereg error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
69*4882a593Smuzhiyun state->frontend.dvb->num, __func__, reg, data, ret);
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun msleep(10);
72*4882a593Smuzhiyun return (ret != 1) ? -EREMOTEIO : 0;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun
tda10021_readreg(struct tda10021_state * state,u8 reg)75*4882a593Smuzhiyun static u8 tda10021_readreg (struct tda10021_state* state, u8 reg)
76*4882a593Smuzhiyun {
77*4882a593Smuzhiyun u8 b0 [] = { reg };
78*4882a593Smuzhiyun u8 b1 [] = { 0 };
79*4882a593Smuzhiyun struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
80*4882a593Smuzhiyun { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
81*4882a593Smuzhiyun int ret;
82*4882a593Smuzhiyun
83*4882a593Smuzhiyun ret = i2c_transfer (state->i2c, msg, 2);
84*4882a593Smuzhiyun // Don't print an error message if the id is read.
85*4882a593Smuzhiyun if (ret != 2 && reg != 0x1a)
86*4882a593Smuzhiyun printk("DVB: TDA10021: %s: readreg error (ret == %i)\n",
87*4882a593Smuzhiyun __func__, ret);
88*4882a593Smuzhiyun return b1[0];
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun //get access to tuner
lock_tuner(struct tda10021_state * state)92*4882a593Smuzhiyun static int lock_tuner(struct tda10021_state* state)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] | 0x80 };
95*4882a593Smuzhiyun struct i2c_msg msg = {.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun if(i2c_transfer(state->i2c, &msg, 1) != 1)
98*4882a593Smuzhiyun {
99*4882a593Smuzhiyun printk("tda10021: lock tuner fails\n");
100*4882a593Smuzhiyun return -EREMOTEIO;
101*4882a593Smuzhiyun }
102*4882a593Smuzhiyun return 0;
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun //release access from tuner
unlock_tuner(struct tda10021_state * state)106*4882a593Smuzhiyun static int unlock_tuner(struct tda10021_state* state)
107*4882a593Smuzhiyun {
108*4882a593Smuzhiyun u8 buf[2] = { 0x0f, tda10021_inittab[0x0f] & 0x7f };
109*4882a593Smuzhiyun struct i2c_msg msg_post={.addr=state->config->demod_address, .flags=0, .buf=buf, .len=2};
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if(i2c_transfer(state->i2c, &msg_post, 1) != 1)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun printk("tda10021: unlock tuner fails\n");
114*4882a593Smuzhiyun return -EREMOTEIO;
115*4882a593Smuzhiyun }
116*4882a593Smuzhiyun return 0;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
tda10021_setup_reg0(struct tda10021_state * state,u8 reg0,enum fe_spectral_inversion inversion)119*4882a593Smuzhiyun static int tda10021_setup_reg0(struct tda10021_state *state, u8 reg0,
120*4882a593Smuzhiyun enum fe_spectral_inversion inversion)
121*4882a593Smuzhiyun {
122*4882a593Smuzhiyun reg0 |= state->reg0 & 0x63;
123*4882a593Smuzhiyun
124*4882a593Smuzhiyun if ((INVERSION_ON == inversion) ^ (state->config->invert == 0))
125*4882a593Smuzhiyun reg0 &= ~0x20;
126*4882a593Smuzhiyun else
127*4882a593Smuzhiyun reg0 |= 0x20;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun _tda10021_writereg (state, 0x00, reg0 & 0xfe);
130*4882a593Smuzhiyun _tda10021_writereg (state, 0x00, reg0 | 0x01);
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun state->reg0 = reg0;
133*4882a593Smuzhiyun return 0;
134*4882a593Smuzhiyun }
135*4882a593Smuzhiyun
tda10021_set_symbolrate(struct tda10021_state * state,u32 symbolrate)136*4882a593Smuzhiyun static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun s32 BDR;
139*4882a593Smuzhiyun s32 BDRI;
140*4882a593Smuzhiyun s16 SFIL = 0;
141*4882a593Smuzhiyun u16 NDEC = 0;
142*4882a593Smuzhiyun u32 tmp, ratio;
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun if (symbolrate > XIN / 2)
145*4882a593Smuzhiyun symbolrate = XIN / 2;
146*4882a593Smuzhiyun else if (symbolrate < 500000)
147*4882a593Smuzhiyun symbolrate = 500000;
148*4882a593Smuzhiyun
149*4882a593Smuzhiyun if (symbolrate < XIN / 16)
150*4882a593Smuzhiyun NDEC = 1;
151*4882a593Smuzhiyun if (symbolrate < XIN / 32)
152*4882a593Smuzhiyun NDEC = 2;
153*4882a593Smuzhiyun if (symbolrate < XIN / 64)
154*4882a593Smuzhiyun NDEC = 3;
155*4882a593Smuzhiyun
156*4882a593Smuzhiyun if (symbolrate < XIN * 10 / 123)
157*4882a593Smuzhiyun SFIL = 1;
158*4882a593Smuzhiyun if (symbolrate < XIN * 10 / 160)
159*4882a593Smuzhiyun SFIL = 0;
160*4882a593Smuzhiyun if (symbolrate < XIN * 10 / 246)
161*4882a593Smuzhiyun SFIL = 1;
162*4882a593Smuzhiyun if (symbolrate < XIN * 10 / 320)
163*4882a593Smuzhiyun SFIL = 0;
164*4882a593Smuzhiyun if (symbolrate < XIN * 10 / 492)
165*4882a593Smuzhiyun SFIL = 1;
166*4882a593Smuzhiyun if (symbolrate < XIN * 10 / 640)
167*4882a593Smuzhiyun SFIL = 0;
168*4882a593Smuzhiyun if (symbolrate < XIN * 10 / 984)
169*4882a593Smuzhiyun SFIL = 1;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun symbolrate <<= NDEC;
172*4882a593Smuzhiyun ratio = (symbolrate << 4) / FIN;
173*4882a593Smuzhiyun tmp = ((symbolrate << 4) % FIN) << 8;
174*4882a593Smuzhiyun ratio = (ratio << 8) + tmp / FIN;
175*4882a593Smuzhiyun tmp = (tmp % FIN) << 8;
176*4882a593Smuzhiyun ratio = (ratio << 8) + DIV_ROUND_CLOSEST(tmp, FIN);
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun BDR = ratio;
179*4882a593Smuzhiyun BDRI = (((XIN << 5) / symbolrate) + 1) / 2;
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun if (BDRI > 0xFF)
182*4882a593Smuzhiyun BDRI = 0xFF;
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun SFIL = (SFIL << 4) | tda10021_inittab[0x0E];
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun NDEC = (NDEC << 6) | tda10021_inittab[0x03];
187*4882a593Smuzhiyun
188*4882a593Smuzhiyun _tda10021_writereg (state, 0x03, NDEC);
189*4882a593Smuzhiyun _tda10021_writereg (state, 0x0a, BDR&0xff);
190*4882a593Smuzhiyun _tda10021_writereg (state, 0x0b, (BDR>> 8)&0xff);
191*4882a593Smuzhiyun _tda10021_writereg (state, 0x0c, (BDR>>16)&0x3f);
192*4882a593Smuzhiyun
193*4882a593Smuzhiyun _tda10021_writereg (state, 0x0d, BDRI);
194*4882a593Smuzhiyun _tda10021_writereg (state, 0x0e, SFIL);
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun return 0;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
tda10021_init(struct dvb_frontend * fe)199*4882a593Smuzhiyun static int tda10021_init (struct dvb_frontend *fe)
200*4882a593Smuzhiyun {
201*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
202*4882a593Smuzhiyun int i;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun dprintk("DVB: TDA10021(%d): init chip\n", fe->adapter->num);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun //_tda10021_writereg (fe, 0, 0);
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun for (i=0; i<tda10021_inittab_size; i++)
209*4882a593Smuzhiyun _tda10021_writereg (state, i, tda10021_inittab[i]);
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun _tda10021_writereg (state, 0x34, state->pwm);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun //Comment by markus
214*4882a593Smuzhiyun //0x2A[3-0] == PDIV -> P multiplaying factor (P=PDIV+1)(default 0)
215*4882a593Smuzhiyun //0x2A[4] == BYPPLL -> Power down mode (default 1)
216*4882a593Smuzhiyun //0x2A[5] == LCK -> PLL Lock Flag
217*4882a593Smuzhiyun //0x2A[6] == POLAXIN -> Polarity of the input reference clock (default 0)
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun //Activate PLL
220*4882a593Smuzhiyun _tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef);
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun }
223*4882a593Smuzhiyun
224*4882a593Smuzhiyun struct qam_params {
225*4882a593Smuzhiyun u8 conf, agcref, lthr, mseth, aref;
226*4882a593Smuzhiyun };
227*4882a593Smuzhiyun
tda10021_set_parameters(struct dvb_frontend * fe)228*4882a593Smuzhiyun static int tda10021_set_parameters(struct dvb_frontend *fe)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun struct dtv_frontend_properties *c = &fe->dtv_property_cache;
231*4882a593Smuzhiyun u32 delsys = c->delivery_system;
232*4882a593Smuzhiyun unsigned qam = c->modulation;
233*4882a593Smuzhiyun bool is_annex_c;
234*4882a593Smuzhiyun u32 reg0x3d;
235*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
236*4882a593Smuzhiyun static const struct qam_params qam_params[] = {
237*4882a593Smuzhiyun /* Modulation Conf AGCref LTHR MSETH AREF */
238*4882a593Smuzhiyun [QPSK] = { 0x14, 0x78, 0x78, 0x8c, 0x96 },
239*4882a593Smuzhiyun [QAM_16] = { 0x00, 0x8c, 0x87, 0xa2, 0x91 },
240*4882a593Smuzhiyun [QAM_32] = { 0x04, 0x8c, 0x64, 0x74, 0x96 },
241*4882a593Smuzhiyun [QAM_64] = { 0x08, 0x6a, 0x46, 0x43, 0x6a },
242*4882a593Smuzhiyun [QAM_128] = { 0x0c, 0x78, 0x36, 0x34, 0x7e },
243*4882a593Smuzhiyun [QAM_256] = { 0x10, 0x5c, 0x26, 0x23, 0x6b },
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun switch (delsys) {
247*4882a593Smuzhiyun case SYS_DVBC_ANNEX_A:
248*4882a593Smuzhiyun is_annex_c = false;
249*4882a593Smuzhiyun break;
250*4882a593Smuzhiyun case SYS_DVBC_ANNEX_C:
251*4882a593Smuzhiyun is_annex_c = true;
252*4882a593Smuzhiyun break;
253*4882a593Smuzhiyun default:
254*4882a593Smuzhiyun return -EINVAL;
255*4882a593Smuzhiyun }
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun /*
258*4882a593Smuzhiyun * gcc optimizes the code below the same way as it would code:
259*4882a593Smuzhiyun * "if (qam > 5) return -EINVAL;"
260*4882a593Smuzhiyun * Yet, the code is clearer, as it shows what QAM standards are
261*4882a593Smuzhiyun * supported by the driver, and avoids the usage of magic numbers on
262*4882a593Smuzhiyun * it.
263*4882a593Smuzhiyun */
264*4882a593Smuzhiyun switch (qam) {
265*4882a593Smuzhiyun case QPSK:
266*4882a593Smuzhiyun case QAM_16:
267*4882a593Smuzhiyun case QAM_32:
268*4882a593Smuzhiyun case QAM_64:
269*4882a593Smuzhiyun case QAM_128:
270*4882a593Smuzhiyun case QAM_256:
271*4882a593Smuzhiyun break;
272*4882a593Smuzhiyun default:
273*4882a593Smuzhiyun return -EINVAL;
274*4882a593Smuzhiyun }
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun if (c->inversion != INVERSION_ON && c->inversion != INVERSION_OFF)
277*4882a593Smuzhiyun return -EINVAL;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun /*printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->symbol_rate);*/
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun if (fe->ops.tuner_ops.set_params) {
282*4882a593Smuzhiyun fe->ops.tuner_ops.set_params(fe);
283*4882a593Smuzhiyun if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun tda10021_set_symbolrate(state, c->symbol_rate);
287*4882a593Smuzhiyun _tda10021_writereg(state, 0x34, state->pwm);
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun _tda10021_writereg(state, 0x01, qam_params[qam].agcref);
290*4882a593Smuzhiyun _tda10021_writereg(state, 0x05, qam_params[qam].lthr);
291*4882a593Smuzhiyun _tda10021_writereg(state, 0x08, qam_params[qam].mseth);
292*4882a593Smuzhiyun _tda10021_writereg(state, 0x09, qam_params[qam].aref);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun /*
295*4882a593Smuzhiyun * Bit 0 == 0 means roll-off = 0.15 (Annex A)
296*4882a593Smuzhiyun * == 1 means roll-off = 0.13 (Annex C)
297*4882a593Smuzhiyun */
298*4882a593Smuzhiyun reg0x3d = tda10021_readreg (state, 0x3d);
299*4882a593Smuzhiyun if (is_annex_c)
300*4882a593Smuzhiyun _tda10021_writereg (state, 0x3d, 0x01 | reg0x3d);
301*4882a593Smuzhiyun else
302*4882a593Smuzhiyun _tda10021_writereg (state, 0x3d, 0xfe & reg0x3d);
303*4882a593Smuzhiyun tda10021_setup_reg0(state, qam_params[qam].conf, c->inversion);
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun return 0;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
tda10021_read_status(struct dvb_frontend * fe,enum fe_status * status)308*4882a593Smuzhiyun static int tda10021_read_status(struct dvb_frontend *fe,
309*4882a593Smuzhiyun enum fe_status *status)
310*4882a593Smuzhiyun {
311*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
312*4882a593Smuzhiyun int sync;
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun *status = 0;
315*4882a593Smuzhiyun //0x11[0] == EQALGO -> Equalizer algorithms state
316*4882a593Smuzhiyun //0x11[1] == CARLOCK -> Carrier locked
317*4882a593Smuzhiyun //0x11[2] == FSYNC -> Frame synchronisation
318*4882a593Smuzhiyun //0x11[3] == FEL -> Front End locked
319*4882a593Smuzhiyun //0x11[6] == NODVB -> DVB Mode Information
320*4882a593Smuzhiyun sync = tda10021_readreg (state, 0x11);
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (sync & 2)
323*4882a593Smuzhiyun *status |= FE_HAS_SIGNAL|FE_HAS_CARRIER;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (sync & 4)
326*4882a593Smuzhiyun *status |= FE_HAS_SYNC|FE_HAS_VITERBI;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun if (sync & 8)
329*4882a593Smuzhiyun *status |= FE_HAS_LOCK;
330*4882a593Smuzhiyun
331*4882a593Smuzhiyun return 0;
332*4882a593Smuzhiyun }
333*4882a593Smuzhiyun
tda10021_read_ber(struct dvb_frontend * fe,u32 * ber)334*4882a593Smuzhiyun static int tda10021_read_ber(struct dvb_frontend* fe, u32* ber)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun u32 _ber = tda10021_readreg(state, 0x14) |
339*4882a593Smuzhiyun (tda10021_readreg(state, 0x15) << 8) |
340*4882a593Smuzhiyun ((tda10021_readreg(state, 0x16) & 0x0f) << 16);
341*4882a593Smuzhiyun _tda10021_writereg(state, 0x10, (tda10021_readreg(state, 0x10) & ~0xc0)
342*4882a593Smuzhiyun | (tda10021_inittab[0x10] & 0xc0));
343*4882a593Smuzhiyun *ber = 10 * _ber;
344*4882a593Smuzhiyun
345*4882a593Smuzhiyun return 0;
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun
tda10021_read_signal_strength(struct dvb_frontend * fe,u16 * strength)348*4882a593Smuzhiyun static int tda10021_read_signal_strength(struct dvb_frontend* fe, u16* strength)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun u8 config = tda10021_readreg(state, 0x02);
353*4882a593Smuzhiyun u8 gain = tda10021_readreg(state, 0x17);
354*4882a593Smuzhiyun if (config & 0x02)
355*4882a593Smuzhiyun /* the agc value is inverted */
356*4882a593Smuzhiyun gain = ~gain;
357*4882a593Smuzhiyun *strength = (gain << 8) | gain;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun return 0;
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun
tda10021_read_snr(struct dvb_frontend * fe,u16 * snr)362*4882a593Smuzhiyun static int tda10021_read_snr(struct dvb_frontend* fe, u16* snr)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun u8 quality = ~tda10021_readreg(state, 0x18);
367*4882a593Smuzhiyun *snr = (quality << 8) | quality;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun return 0;
370*4882a593Smuzhiyun }
371*4882a593Smuzhiyun
tda10021_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)372*4882a593Smuzhiyun static int tda10021_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
373*4882a593Smuzhiyun {
374*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun *ucblocks = tda10021_readreg (state, 0x13) & 0x7f;
377*4882a593Smuzhiyun if (*ucblocks == 0x7f)
378*4882a593Smuzhiyun *ucblocks = 0xffffffff;
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /* reset uncorrected block counter */
381*4882a593Smuzhiyun _tda10021_writereg (state, 0x10, tda10021_inittab[0x10] & 0xdf);
382*4882a593Smuzhiyun _tda10021_writereg (state, 0x10, tda10021_inittab[0x10]);
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun return 0;
385*4882a593Smuzhiyun }
386*4882a593Smuzhiyun
tda10021_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * p)387*4882a593Smuzhiyun static int tda10021_get_frontend(struct dvb_frontend *fe,
388*4882a593Smuzhiyun struct dtv_frontend_properties *p)
389*4882a593Smuzhiyun {
390*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
391*4882a593Smuzhiyun int sync;
392*4882a593Smuzhiyun s8 afc = 0;
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun sync = tda10021_readreg(state, 0x11);
395*4882a593Smuzhiyun afc = tda10021_readreg(state, 0x19);
396*4882a593Smuzhiyun if (verbose) {
397*4882a593Smuzhiyun /* AFC only valid when carrier has been recovered */
398*4882a593Smuzhiyun printk(sync & 2 ? "DVB: TDA10021(%d): AFC (%d) %dHz\n" :
399*4882a593Smuzhiyun "DVB: TDA10021(%d): [AFC (%d) %dHz]\n",
400*4882a593Smuzhiyun state->frontend.dvb->num, afc,
401*4882a593Smuzhiyun -((s32)p->symbol_rate * afc) >> 10);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun p->inversion = ((state->reg0 & 0x20) == 0x20) ^ (state->config->invert != 0) ? INVERSION_ON : INVERSION_OFF;
405*4882a593Smuzhiyun p->modulation = ((state->reg0 >> 2) & 7) + QAM_16;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun p->fec_inner = FEC_NONE;
408*4882a593Smuzhiyun p->frequency = ((p->frequency + 31250) / 62500) * 62500;
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun if (sync & 2)
411*4882a593Smuzhiyun p->frequency -= ((s32)p->symbol_rate * afc) >> 10;
412*4882a593Smuzhiyun
413*4882a593Smuzhiyun return 0;
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
tda10021_i2c_gate_ctrl(struct dvb_frontend * fe,int enable)416*4882a593Smuzhiyun static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
419*4882a593Smuzhiyun
420*4882a593Smuzhiyun if (enable) {
421*4882a593Smuzhiyun lock_tuner(state);
422*4882a593Smuzhiyun } else {
423*4882a593Smuzhiyun unlock_tuner(state);
424*4882a593Smuzhiyun }
425*4882a593Smuzhiyun return 0;
426*4882a593Smuzhiyun }
427*4882a593Smuzhiyun
tda10021_sleep(struct dvb_frontend * fe)428*4882a593Smuzhiyun static int tda10021_sleep(struct dvb_frontend* fe)
429*4882a593Smuzhiyun {
430*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
431*4882a593Smuzhiyun
432*4882a593Smuzhiyun _tda10021_writereg (state, 0x1b, 0x02); /* pdown ADC */
433*4882a593Smuzhiyun _tda10021_writereg (state, 0x00, 0x80); /* standby */
434*4882a593Smuzhiyun
435*4882a593Smuzhiyun return 0;
436*4882a593Smuzhiyun }
437*4882a593Smuzhiyun
tda10021_release(struct dvb_frontend * fe)438*4882a593Smuzhiyun static void tda10021_release(struct dvb_frontend* fe)
439*4882a593Smuzhiyun {
440*4882a593Smuzhiyun struct tda10021_state* state = fe->demodulator_priv;
441*4882a593Smuzhiyun kfree(state);
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun static const struct dvb_frontend_ops tda10021_ops;
445*4882a593Smuzhiyun
tda10021_attach(const struct tda1002x_config * config,struct i2c_adapter * i2c,u8 pwm)446*4882a593Smuzhiyun struct dvb_frontend* tda10021_attach(const struct tda1002x_config* config,
447*4882a593Smuzhiyun struct i2c_adapter* i2c,
448*4882a593Smuzhiyun u8 pwm)
449*4882a593Smuzhiyun {
450*4882a593Smuzhiyun struct tda10021_state* state = NULL;
451*4882a593Smuzhiyun u8 id;
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /* allocate memory for the internal state */
454*4882a593Smuzhiyun state = kzalloc(sizeof(struct tda10021_state), GFP_KERNEL);
455*4882a593Smuzhiyun if (state == NULL) goto error;
456*4882a593Smuzhiyun
457*4882a593Smuzhiyun /* setup the state */
458*4882a593Smuzhiyun state->config = config;
459*4882a593Smuzhiyun state->i2c = i2c;
460*4882a593Smuzhiyun state->pwm = pwm;
461*4882a593Smuzhiyun state->reg0 = tda10021_inittab[0];
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun /* check if the demod is there */
464*4882a593Smuzhiyun id = tda10021_readreg(state, 0x1a);
465*4882a593Smuzhiyun if ((id & 0xf0) != 0x70) goto error;
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /* Don't claim TDA10023 */
468*4882a593Smuzhiyun if (id == 0x7d)
469*4882a593Smuzhiyun goto error;
470*4882a593Smuzhiyun
471*4882a593Smuzhiyun printk("TDA10021: i2c-addr = 0x%02x, id = 0x%02x\n",
472*4882a593Smuzhiyun state->config->demod_address, id);
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun /* create dvb_frontend */
475*4882a593Smuzhiyun memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops));
476*4882a593Smuzhiyun state->frontend.demodulator_priv = state;
477*4882a593Smuzhiyun return &state->frontend;
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun error:
480*4882a593Smuzhiyun kfree(state);
481*4882a593Smuzhiyun return NULL;
482*4882a593Smuzhiyun }
483*4882a593Smuzhiyun
484*4882a593Smuzhiyun static const struct dvb_frontend_ops tda10021_ops = {
485*4882a593Smuzhiyun .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_C },
486*4882a593Smuzhiyun .info = {
487*4882a593Smuzhiyun .name = "Philips TDA10021 DVB-C",
488*4882a593Smuzhiyun .frequency_min_hz = 47 * MHz,
489*4882a593Smuzhiyun .frequency_max_hz = 862 * MHz,
490*4882a593Smuzhiyun .frequency_stepsize_hz = 62500,
491*4882a593Smuzhiyun .symbol_rate_min = (XIN / 2) / 64, /* SACLK/64 == (XIN/2)/64 */
492*4882a593Smuzhiyun .symbol_rate_max = (XIN / 2) / 4, /* SACLK/4 */
493*4882a593Smuzhiyun #if 0
494*4882a593Smuzhiyun .frequency_tolerance = ???,
495*4882a593Smuzhiyun .symbol_rate_tolerance = ???, /* ppm */ /* == 8% (spec p. 5) */
496*4882a593Smuzhiyun #endif
497*4882a593Smuzhiyun .caps = 0x400 | //FE_CAN_QAM_4
498*4882a593Smuzhiyun FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
499*4882a593Smuzhiyun FE_CAN_QAM_128 | FE_CAN_QAM_256 |
500*4882a593Smuzhiyun FE_CAN_FEC_AUTO
501*4882a593Smuzhiyun },
502*4882a593Smuzhiyun
503*4882a593Smuzhiyun .release = tda10021_release,
504*4882a593Smuzhiyun
505*4882a593Smuzhiyun .init = tda10021_init,
506*4882a593Smuzhiyun .sleep = tda10021_sleep,
507*4882a593Smuzhiyun .i2c_gate_ctrl = tda10021_i2c_gate_ctrl,
508*4882a593Smuzhiyun
509*4882a593Smuzhiyun .set_frontend = tda10021_set_parameters,
510*4882a593Smuzhiyun .get_frontend = tda10021_get_frontend,
511*4882a593Smuzhiyun
512*4882a593Smuzhiyun .read_status = tda10021_read_status,
513*4882a593Smuzhiyun .read_ber = tda10021_read_ber,
514*4882a593Smuzhiyun .read_signal_strength = tda10021_read_signal_strength,
515*4882a593Smuzhiyun .read_snr = tda10021_read_snr,
516*4882a593Smuzhiyun .read_ucblocks = tda10021_read_ucblocks,
517*4882a593Smuzhiyun };
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun module_param(verbose, int, 0644);
520*4882a593Smuzhiyun MODULE_PARM_DESC(verbose, "print AFC offset after tuning for debugging the PWM setting");
521*4882a593Smuzhiyun
522*4882a593Smuzhiyun MODULE_DESCRIPTION("Philips TDA10021 DVB-C demodulator driver");
523*4882a593Smuzhiyun MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Markus Schulz");
524*4882a593Smuzhiyun MODULE_LICENSE("GPL");
525*4882a593Smuzhiyun
526*4882a593Smuzhiyun EXPORT_SYMBOL(tda10021_attach);
527