1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun Driver for VES1893 and VES1993 QPSK Demodulators
4*4882a593Smuzhiyun
5*4882a593Smuzhiyun Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
6*4882a593Smuzhiyun Copyright (C) 2001 Ronny Strutz <3des@elitedvb.de>
7*4882a593Smuzhiyun Copyright (C) 2002 Dennis Noermann <dennis.noermann@noernet.de>
8*4882a593Smuzhiyun Copyright (C) 2002-2003 Andreas Oberritter <obi@linuxtv.org>
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun
11*4882a593Smuzhiyun */
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun #include <linux/kernel.h>
14*4882a593Smuzhiyun #include <linux/module.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/string.h>
17*4882a593Smuzhiyun #include <linux/slab.h>
18*4882a593Smuzhiyun #include <linux/delay.h>
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun #include <media/dvb_frontend.h>
21*4882a593Smuzhiyun #include "ves1x93.h"
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun struct ves1x93_state {
25*4882a593Smuzhiyun struct i2c_adapter* i2c;
26*4882a593Smuzhiyun /* configuration settings */
27*4882a593Smuzhiyun const struct ves1x93_config* config;
28*4882a593Smuzhiyun struct dvb_frontend frontend;
29*4882a593Smuzhiyun
30*4882a593Smuzhiyun /* previous uncorrected block counter */
31*4882a593Smuzhiyun enum fe_spectral_inversion inversion;
32*4882a593Smuzhiyun u8 *init_1x93_tab;
33*4882a593Smuzhiyun u8 *init_1x93_wtab;
34*4882a593Smuzhiyun u8 tab_size;
35*4882a593Smuzhiyun u8 demod_type;
36*4882a593Smuzhiyun u32 frequency;
37*4882a593Smuzhiyun };
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun static int debug;
40*4882a593Smuzhiyun #define dprintk if (debug) printk
41*4882a593Smuzhiyun
42*4882a593Smuzhiyun #define DEMOD_VES1893 0
43*4882a593Smuzhiyun #define DEMOD_VES1993 1
44*4882a593Smuzhiyun
45*4882a593Smuzhiyun static u8 init_1893_tab [] = {
46*4882a593Smuzhiyun 0x01, 0xa4, 0x35, 0x80, 0x2a, 0x0b, 0x55, 0xc4,
47*4882a593Smuzhiyun 0x09, 0x69, 0x00, 0x86, 0x4c, 0x28, 0x7f, 0x00,
48*4882a593Smuzhiyun 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
49*4882a593Smuzhiyun 0x80, 0x00, 0x21, 0xb0, 0x14, 0x00, 0xdc, 0x00,
50*4882a593Smuzhiyun 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51*4882a593Smuzhiyun 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52*4882a593Smuzhiyun 0x00, 0x55, 0x00, 0x00, 0x7f, 0x00
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun static u8 init_1993_tab [] = {
56*4882a593Smuzhiyun 0x00, 0x9c, 0x35, 0x80, 0x6a, 0x09, 0x72, 0x8c,
57*4882a593Smuzhiyun 0x09, 0x6b, 0x00, 0x00, 0x4c, 0x08, 0x00, 0x00,
58*4882a593Smuzhiyun 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
59*4882a593Smuzhiyun 0x80, 0x40, 0x21, 0xb0, 0x00, 0x00, 0x00, 0x10,
60*4882a593Smuzhiyun 0x81, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
61*4882a593Smuzhiyun 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00,
62*4882a593Smuzhiyun 0x00, 0x55, 0x03, 0x00, 0x00, 0x00, 0x00, 0x03,
63*4882a593Smuzhiyun 0x00, 0x00, 0x0e, 0x80, 0x00
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static u8 init_1893_wtab[] =
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
69*4882a593Smuzhiyun 0,1,0,0,0,0,0,0, 1,0,1,1,0,0,0,1,
70*4882a593Smuzhiyun 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
71*4882a593Smuzhiyun 1,1,1,0,1,1
72*4882a593Smuzhiyun };
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun static u8 init_1993_wtab[] =
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 1,1,1,1,1,1,1,1, 1,1,0,0,1,1,0,0,
77*4882a593Smuzhiyun 0,1,0,0,0,0,0,0, 1,1,1,1,0,0,0,1,
78*4882a593Smuzhiyun 1,1,1,0,0,0,0,0, 0,0,1,1,0,0,0,0,
79*4882a593Smuzhiyun 1,1,1,0,1,1,1,1, 1,1,1,1,1
80*4882a593Smuzhiyun };
81*4882a593Smuzhiyun
ves1x93_writereg(struct ves1x93_state * state,u8 reg,u8 data)82*4882a593Smuzhiyun static int ves1x93_writereg (struct ves1x93_state* state, u8 reg, u8 data)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun u8 buf [] = { 0x00, reg, data };
85*4882a593Smuzhiyun struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 3 };
86*4882a593Smuzhiyun int err;
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
89*4882a593Smuzhiyun dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
90*4882a593Smuzhiyun return -EREMOTEIO;
91*4882a593Smuzhiyun }
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun return 0;
94*4882a593Smuzhiyun }
95*4882a593Smuzhiyun
ves1x93_readreg(struct ves1x93_state * state,u8 reg)96*4882a593Smuzhiyun static u8 ves1x93_readreg (struct ves1x93_state* state, u8 reg)
97*4882a593Smuzhiyun {
98*4882a593Smuzhiyun int ret;
99*4882a593Smuzhiyun u8 b0 [] = { 0x00, reg };
100*4882a593Smuzhiyun u8 b1 [] = { 0 };
101*4882a593Smuzhiyun struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
102*4882a593Smuzhiyun { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
103*4882a593Smuzhiyun
104*4882a593Smuzhiyun ret = i2c_transfer (state->i2c, msg, 2);
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun if (ret != 2) return ret;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun return b1[0];
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun
ves1x93_clr_bit(struct ves1x93_state * state)111*4882a593Smuzhiyun static int ves1x93_clr_bit (struct ves1x93_state* state)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun msleep(10);
114*4882a593Smuzhiyun ves1x93_writereg (state, 0, state->init_1x93_tab[0] & 0xfe);
115*4882a593Smuzhiyun ves1x93_writereg (state, 0, state->init_1x93_tab[0]);
116*4882a593Smuzhiyun msleep(50);
117*4882a593Smuzhiyun return 0;
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
ves1x93_set_inversion(struct ves1x93_state * state,enum fe_spectral_inversion inversion)120*4882a593Smuzhiyun static int ves1x93_set_inversion(struct ves1x93_state *state,
121*4882a593Smuzhiyun enum fe_spectral_inversion inversion)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun u8 val;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun /*
126*4882a593Smuzhiyun * inversion on/off are interchanged because i and q seem to
127*4882a593Smuzhiyun * be swapped on the hardware
128*4882a593Smuzhiyun */
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun switch (inversion) {
131*4882a593Smuzhiyun case INVERSION_OFF:
132*4882a593Smuzhiyun val = 0xc0;
133*4882a593Smuzhiyun break;
134*4882a593Smuzhiyun case INVERSION_ON:
135*4882a593Smuzhiyun val = 0x80;
136*4882a593Smuzhiyun break;
137*4882a593Smuzhiyun case INVERSION_AUTO:
138*4882a593Smuzhiyun val = 0x00;
139*4882a593Smuzhiyun break;
140*4882a593Smuzhiyun default:
141*4882a593Smuzhiyun return -EINVAL;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun return ves1x93_writereg (state, 0x0c, (state->init_1x93_tab[0x0c] & 0x3f) | val);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
ves1x93_set_fec(struct ves1x93_state * state,enum fe_code_rate fec)147*4882a593Smuzhiyun static int ves1x93_set_fec(struct ves1x93_state *state, enum fe_code_rate fec)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun if (fec == FEC_AUTO)
150*4882a593Smuzhiyun return ves1x93_writereg (state, 0x0d, 0x08);
151*4882a593Smuzhiyun else if (fec < FEC_1_2 || fec > FEC_8_9)
152*4882a593Smuzhiyun return -EINVAL;
153*4882a593Smuzhiyun else
154*4882a593Smuzhiyun return ves1x93_writereg (state, 0x0d, fec - FEC_1_2);
155*4882a593Smuzhiyun }
156*4882a593Smuzhiyun
ves1x93_get_fec(struct ves1x93_state * state)157*4882a593Smuzhiyun static enum fe_code_rate ves1x93_get_fec(struct ves1x93_state *state)
158*4882a593Smuzhiyun {
159*4882a593Smuzhiyun return FEC_1_2 + ((ves1x93_readreg (state, 0x0d) >> 4) & 0x7);
160*4882a593Smuzhiyun }
161*4882a593Smuzhiyun
ves1x93_set_symbolrate(struct ves1x93_state * state,u32 srate)162*4882a593Smuzhiyun static int ves1x93_set_symbolrate (struct ves1x93_state* state, u32 srate)
163*4882a593Smuzhiyun {
164*4882a593Smuzhiyun u32 BDR;
165*4882a593Smuzhiyun u32 ratio;
166*4882a593Smuzhiyun u8 ADCONF, FCONF, FNR, AGCR;
167*4882a593Smuzhiyun u32 BDRI;
168*4882a593Smuzhiyun u32 tmp;
169*4882a593Smuzhiyun u32 FIN;
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun dprintk("%s: srate == %d\n", __func__, (unsigned int) srate);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun if (srate > state->config->xin/2)
174*4882a593Smuzhiyun srate = state->config->xin/2;
175*4882a593Smuzhiyun
176*4882a593Smuzhiyun if (srate < 500000)
177*4882a593Smuzhiyun srate = 500000;
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun #define MUL (1UL<<26)
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun FIN = (state->config->xin + 6000) >> 4;
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun tmp = srate << 6;
184*4882a593Smuzhiyun ratio = tmp / FIN;
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun tmp = (tmp % FIN) << 8;
187*4882a593Smuzhiyun ratio = (ratio << 8) + tmp / FIN;
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun tmp = (tmp % FIN) << 8;
190*4882a593Smuzhiyun ratio = (ratio << 8) + tmp / FIN;
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun FNR = 0xff;
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun if (ratio < MUL/3) FNR = 0;
195*4882a593Smuzhiyun if (ratio < (MUL*11)/50) FNR = 1;
196*4882a593Smuzhiyun if (ratio < MUL/6) FNR = 2;
197*4882a593Smuzhiyun if (ratio < MUL/9) FNR = 3;
198*4882a593Smuzhiyun if (ratio < MUL/12) FNR = 4;
199*4882a593Smuzhiyun if (ratio < (MUL*11)/200) FNR = 5;
200*4882a593Smuzhiyun if (ratio < MUL/24) FNR = 6;
201*4882a593Smuzhiyun if (ratio < (MUL*27)/1000) FNR = 7;
202*4882a593Smuzhiyun if (ratio < MUL/48) FNR = 8;
203*4882a593Smuzhiyun if (ratio < (MUL*137)/10000) FNR = 9;
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun if (FNR == 0xff) {
206*4882a593Smuzhiyun ADCONF = 0x89;
207*4882a593Smuzhiyun FCONF = 0x80;
208*4882a593Smuzhiyun FNR = 0;
209*4882a593Smuzhiyun } else {
210*4882a593Smuzhiyun ADCONF = 0x81;
211*4882a593Smuzhiyun FCONF = 0x88 | (FNR >> 1) | ((FNR & 0x01) << 5);
212*4882a593Smuzhiyun /*FCONF = 0x80 | ((FNR & 0x01) << 5) | (((FNR > 1) & 0x03) << 3) | ((FNR >> 1) & 0x07);*/
213*4882a593Smuzhiyun }
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun BDR = (( (ratio << (FNR >> 1)) >> 4) + 1) >> 1;
216*4882a593Smuzhiyun BDRI = ( ((FIN << 8) / ((srate << (FNR >> 1)) >> 2)) + 1) >> 1;
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun dprintk("FNR= %d\n", FNR);
219*4882a593Smuzhiyun dprintk("ratio= %08x\n", (unsigned int) ratio);
220*4882a593Smuzhiyun dprintk("BDR= %08x\n", (unsigned int) BDR);
221*4882a593Smuzhiyun dprintk("BDRI= %02x\n", (unsigned int) BDRI);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (BDRI > 0xff)
224*4882a593Smuzhiyun BDRI = 0xff;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun ves1x93_writereg (state, 0x06, 0xff & BDR);
227*4882a593Smuzhiyun ves1x93_writereg (state, 0x07, 0xff & (BDR >> 8));
228*4882a593Smuzhiyun ves1x93_writereg (state, 0x08, 0x0f & (BDR >> 16));
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun ves1x93_writereg (state, 0x09, BDRI);
231*4882a593Smuzhiyun ves1x93_writereg (state, 0x20, ADCONF);
232*4882a593Smuzhiyun ves1x93_writereg (state, 0x21, FCONF);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun AGCR = state->init_1x93_tab[0x05];
235*4882a593Smuzhiyun if (state->config->invert_pwm)
236*4882a593Smuzhiyun AGCR |= 0x20;
237*4882a593Smuzhiyun
238*4882a593Smuzhiyun if (srate < 6000000)
239*4882a593Smuzhiyun AGCR |= 0x80;
240*4882a593Smuzhiyun else
241*4882a593Smuzhiyun AGCR &= ~0x80;
242*4882a593Smuzhiyun
243*4882a593Smuzhiyun ves1x93_writereg (state, 0x05, AGCR);
244*4882a593Smuzhiyun
245*4882a593Smuzhiyun /* ves1993 hates this, will lose lock */
246*4882a593Smuzhiyun if (state->demod_type != DEMOD_VES1993)
247*4882a593Smuzhiyun ves1x93_clr_bit (state);
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun return 0;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun
ves1x93_init(struct dvb_frontend * fe)252*4882a593Smuzhiyun static int ves1x93_init (struct dvb_frontend* fe)
253*4882a593Smuzhiyun {
254*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
255*4882a593Smuzhiyun int i;
256*4882a593Smuzhiyun int val;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun dprintk("%s: init chip\n", __func__);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun for (i = 0; i < state->tab_size; i++) {
261*4882a593Smuzhiyun if (state->init_1x93_wtab[i]) {
262*4882a593Smuzhiyun val = state->init_1x93_tab[i];
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (state->config->invert_pwm && (i == 0x05)) val |= 0x20; /* invert PWM */
265*4882a593Smuzhiyun ves1x93_writereg (state, i, val);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun return 0;
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun
ves1x93_set_voltage(struct dvb_frontend * fe,enum fe_sec_voltage voltage)272*4882a593Smuzhiyun static int ves1x93_set_voltage(struct dvb_frontend *fe,
273*4882a593Smuzhiyun enum fe_sec_voltage voltage)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
276*4882a593Smuzhiyun
277*4882a593Smuzhiyun switch (voltage) {
278*4882a593Smuzhiyun case SEC_VOLTAGE_13:
279*4882a593Smuzhiyun return ves1x93_writereg (state, 0x1f, 0x20);
280*4882a593Smuzhiyun case SEC_VOLTAGE_18:
281*4882a593Smuzhiyun return ves1x93_writereg (state, 0x1f, 0x30);
282*4882a593Smuzhiyun case SEC_VOLTAGE_OFF:
283*4882a593Smuzhiyun return ves1x93_writereg (state, 0x1f, 0x00);
284*4882a593Smuzhiyun default:
285*4882a593Smuzhiyun return -EINVAL;
286*4882a593Smuzhiyun }
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
ves1x93_read_status(struct dvb_frontend * fe,enum fe_status * status)289*4882a593Smuzhiyun static int ves1x93_read_status(struct dvb_frontend *fe,
290*4882a593Smuzhiyun enum fe_status *status)
291*4882a593Smuzhiyun {
292*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun u8 sync = ves1x93_readreg (state, 0x0e);
295*4882a593Smuzhiyun
296*4882a593Smuzhiyun /*
297*4882a593Smuzhiyun * The ves1893 sometimes returns sync values that make no sense,
298*4882a593Smuzhiyun * because, e.g., the SIGNAL bit is 0, while some of the higher
299*4882a593Smuzhiyun * bits are 1 (and how can there be a CARRIER w/o a SIGNAL?).
300*4882a593Smuzhiyun * Tests showed that the VITERBI and SYNC bits are returned
301*4882a593Smuzhiyun * reliably, while the SIGNAL and CARRIER bits ar sometimes wrong.
302*4882a593Smuzhiyun * If such a case occurs, we read the value again, until we get a
303*4882a593Smuzhiyun * valid value.
304*4882a593Smuzhiyun */
305*4882a593Smuzhiyun int maxtry = 10; /* just for safety - let's not get stuck here */
306*4882a593Smuzhiyun while ((sync & 0x03) != 0x03 && (sync & 0x0c) && maxtry--) {
307*4882a593Smuzhiyun msleep(10);
308*4882a593Smuzhiyun sync = ves1x93_readreg (state, 0x0e);
309*4882a593Smuzhiyun }
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun *status = 0;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun if (sync & 1)
314*4882a593Smuzhiyun *status |= FE_HAS_SIGNAL;
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun if (sync & 2)
317*4882a593Smuzhiyun *status |= FE_HAS_CARRIER;
318*4882a593Smuzhiyun
319*4882a593Smuzhiyun if (sync & 4)
320*4882a593Smuzhiyun *status |= FE_HAS_VITERBI;
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun if (sync & 8)
323*4882a593Smuzhiyun *status |= FE_HAS_SYNC;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if ((sync & 0x1f) == 0x1f)
326*4882a593Smuzhiyun *status |= FE_HAS_LOCK;
327*4882a593Smuzhiyun
328*4882a593Smuzhiyun return 0;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun
ves1x93_read_ber(struct dvb_frontend * fe,u32 * ber)331*4882a593Smuzhiyun static int ves1x93_read_ber(struct dvb_frontend* fe, u32* ber)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun *ber = ves1x93_readreg (state, 0x15);
336*4882a593Smuzhiyun *ber |= (ves1x93_readreg (state, 0x16) << 8);
337*4882a593Smuzhiyun *ber |= ((ves1x93_readreg (state, 0x17) & 0x0F) << 16);
338*4882a593Smuzhiyun *ber *= 10;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun return 0;
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
ves1x93_read_signal_strength(struct dvb_frontend * fe,u16 * strength)343*4882a593Smuzhiyun static int ves1x93_read_signal_strength(struct dvb_frontend* fe, u16* strength)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
346*4882a593Smuzhiyun
347*4882a593Smuzhiyun u8 signal = ~ves1x93_readreg (state, 0x0b);
348*4882a593Smuzhiyun *strength = (signal << 8) | signal;
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun return 0;
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
ves1x93_read_snr(struct dvb_frontend * fe,u16 * snr)353*4882a593Smuzhiyun static int ves1x93_read_snr(struct dvb_frontend* fe, u16* snr)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun u8 _snr = ~ves1x93_readreg (state, 0x1c);
358*4882a593Smuzhiyun *snr = (_snr << 8) | _snr;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun return 0;
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
ves1x93_read_ucblocks(struct dvb_frontend * fe,u32 * ucblocks)363*4882a593Smuzhiyun static int ves1x93_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
364*4882a593Smuzhiyun {
365*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
366*4882a593Smuzhiyun
367*4882a593Smuzhiyun *ucblocks = ves1x93_readreg (state, 0x18) & 0x7f;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun if (*ucblocks == 0x7f)
370*4882a593Smuzhiyun *ucblocks = 0xffffffff; /* counter overflow... */
371*4882a593Smuzhiyun
372*4882a593Smuzhiyun ves1x93_writereg (state, 0x18, 0x00); /* reset the counter */
373*4882a593Smuzhiyun ves1x93_writereg (state, 0x18, 0x80); /* dto. */
374*4882a593Smuzhiyun
375*4882a593Smuzhiyun return 0;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
ves1x93_set_frontend(struct dvb_frontend * fe)378*4882a593Smuzhiyun static int ves1x93_set_frontend(struct dvb_frontend *fe)
379*4882a593Smuzhiyun {
380*4882a593Smuzhiyun struct dtv_frontend_properties *p = &fe->dtv_property_cache;
381*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
382*4882a593Smuzhiyun
383*4882a593Smuzhiyun if (fe->ops.tuner_ops.set_params) {
384*4882a593Smuzhiyun fe->ops.tuner_ops.set_params(fe);
385*4882a593Smuzhiyun if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
386*4882a593Smuzhiyun }
387*4882a593Smuzhiyun ves1x93_set_inversion (state, p->inversion);
388*4882a593Smuzhiyun ves1x93_set_fec(state, p->fec_inner);
389*4882a593Smuzhiyun ves1x93_set_symbolrate(state, p->symbol_rate);
390*4882a593Smuzhiyun state->inversion = p->inversion;
391*4882a593Smuzhiyun state->frequency = p->frequency;
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun return 0;
394*4882a593Smuzhiyun }
395*4882a593Smuzhiyun
ves1x93_get_frontend(struct dvb_frontend * fe,struct dtv_frontend_properties * p)396*4882a593Smuzhiyun static int ves1x93_get_frontend(struct dvb_frontend *fe,
397*4882a593Smuzhiyun struct dtv_frontend_properties *p)
398*4882a593Smuzhiyun {
399*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
400*4882a593Smuzhiyun int afc;
401*4882a593Smuzhiyun
402*4882a593Smuzhiyun afc = ((int)((char)(ves1x93_readreg (state, 0x0a) << 1)))/2;
403*4882a593Smuzhiyun afc = (afc * (int)(p->symbol_rate/1000/8))/16;
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun p->frequency = state->frequency - afc;
406*4882a593Smuzhiyun
407*4882a593Smuzhiyun /*
408*4882a593Smuzhiyun * inversion indicator is only valid
409*4882a593Smuzhiyun * if auto inversion was used
410*4882a593Smuzhiyun */
411*4882a593Smuzhiyun if (state->inversion == INVERSION_AUTO)
412*4882a593Smuzhiyun p->inversion = (ves1x93_readreg (state, 0x0f) & 2) ?
413*4882a593Smuzhiyun INVERSION_OFF : INVERSION_ON;
414*4882a593Smuzhiyun p->fec_inner = ves1x93_get_fec(state);
415*4882a593Smuzhiyun /* XXX FIXME: timing offset !! */
416*4882a593Smuzhiyun
417*4882a593Smuzhiyun return 0;
418*4882a593Smuzhiyun }
419*4882a593Smuzhiyun
ves1x93_sleep(struct dvb_frontend * fe)420*4882a593Smuzhiyun static int ves1x93_sleep(struct dvb_frontend* fe)
421*4882a593Smuzhiyun {
422*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun return ves1x93_writereg (state, 0x00, 0x08);
425*4882a593Smuzhiyun }
426*4882a593Smuzhiyun
ves1x93_release(struct dvb_frontend * fe)427*4882a593Smuzhiyun static void ves1x93_release(struct dvb_frontend* fe)
428*4882a593Smuzhiyun {
429*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
430*4882a593Smuzhiyun kfree(state);
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
ves1x93_i2c_gate_ctrl(struct dvb_frontend * fe,int enable)433*4882a593Smuzhiyun static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun struct ves1x93_state* state = fe->demodulator_priv;
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun if (enable) {
438*4882a593Smuzhiyun return ves1x93_writereg(state, 0x00, 0x11);
439*4882a593Smuzhiyun } else {
440*4882a593Smuzhiyun return ves1x93_writereg(state, 0x00, 0x01);
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun }
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun static const struct dvb_frontend_ops ves1x93_ops;
445*4882a593Smuzhiyun
ves1x93_attach(const struct ves1x93_config * config,struct i2c_adapter * i2c)446*4882a593Smuzhiyun struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config,
447*4882a593Smuzhiyun struct i2c_adapter* i2c)
448*4882a593Smuzhiyun {
449*4882a593Smuzhiyun struct ves1x93_state* state = NULL;
450*4882a593Smuzhiyun u8 identity;
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /* allocate memory for the internal state */
453*4882a593Smuzhiyun state = kzalloc(sizeof(struct ves1x93_state), GFP_KERNEL);
454*4882a593Smuzhiyun if (state == NULL) goto error;
455*4882a593Smuzhiyun
456*4882a593Smuzhiyun /* setup the state */
457*4882a593Smuzhiyun state->config = config;
458*4882a593Smuzhiyun state->i2c = i2c;
459*4882a593Smuzhiyun state->inversion = INVERSION_OFF;
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /* check if the demod is there + identify it */
462*4882a593Smuzhiyun identity = ves1x93_readreg(state, 0x1e);
463*4882a593Smuzhiyun switch (identity) {
464*4882a593Smuzhiyun case 0xdc: /* VES1893A rev1 */
465*4882a593Smuzhiyun printk("ves1x93: Detected ves1893a rev1\n");
466*4882a593Smuzhiyun state->demod_type = DEMOD_VES1893;
467*4882a593Smuzhiyun state->init_1x93_tab = init_1893_tab;
468*4882a593Smuzhiyun state->init_1x93_wtab = init_1893_wtab;
469*4882a593Smuzhiyun state->tab_size = sizeof(init_1893_tab);
470*4882a593Smuzhiyun break;
471*4882a593Smuzhiyun
472*4882a593Smuzhiyun case 0xdd: /* VES1893A rev2 */
473*4882a593Smuzhiyun printk("ves1x93: Detected ves1893a rev2\n");
474*4882a593Smuzhiyun state->demod_type = DEMOD_VES1893;
475*4882a593Smuzhiyun state->init_1x93_tab = init_1893_tab;
476*4882a593Smuzhiyun state->init_1x93_wtab = init_1893_wtab;
477*4882a593Smuzhiyun state->tab_size = sizeof(init_1893_tab);
478*4882a593Smuzhiyun break;
479*4882a593Smuzhiyun
480*4882a593Smuzhiyun case 0xde: /* VES1993 */
481*4882a593Smuzhiyun printk("ves1x93: Detected ves1993\n");
482*4882a593Smuzhiyun state->demod_type = DEMOD_VES1993;
483*4882a593Smuzhiyun state->init_1x93_tab = init_1993_tab;
484*4882a593Smuzhiyun state->init_1x93_wtab = init_1993_wtab;
485*4882a593Smuzhiyun state->tab_size = sizeof(init_1993_tab);
486*4882a593Smuzhiyun break;
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun default:
489*4882a593Smuzhiyun goto error;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun
492*4882a593Smuzhiyun /* create dvb_frontend */
493*4882a593Smuzhiyun memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops));
494*4882a593Smuzhiyun state->frontend.demodulator_priv = state;
495*4882a593Smuzhiyun return &state->frontend;
496*4882a593Smuzhiyun
497*4882a593Smuzhiyun error:
498*4882a593Smuzhiyun kfree(state);
499*4882a593Smuzhiyun return NULL;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
502*4882a593Smuzhiyun static const struct dvb_frontend_ops ves1x93_ops = {
503*4882a593Smuzhiyun .delsys = { SYS_DVBS },
504*4882a593Smuzhiyun .info = {
505*4882a593Smuzhiyun .name = "VLSI VES1x93 DVB-S",
506*4882a593Smuzhiyun .frequency_min_hz = 950 * MHz,
507*4882a593Smuzhiyun .frequency_max_hz = 2150 * MHz,
508*4882a593Smuzhiyun .frequency_stepsize_hz = 125 * kHz,
509*4882a593Smuzhiyun .frequency_tolerance_hz = 29500 * kHz,
510*4882a593Smuzhiyun .symbol_rate_min = 1000000,
511*4882a593Smuzhiyun .symbol_rate_max = 45000000,
512*4882a593Smuzhiyun /* .symbol_rate_tolerance = ???,*/
513*4882a593Smuzhiyun .caps = FE_CAN_INVERSION_AUTO |
514*4882a593Smuzhiyun FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
515*4882a593Smuzhiyun FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
516*4882a593Smuzhiyun FE_CAN_QPSK
517*4882a593Smuzhiyun },
518*4882a593Smuzhiyun
519*4882a593Smuzhiyun .release = ves1x93_release,
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun .init = ves1x93_init,
522*4882a593Smuzhiyun .sleep = ves1x93_sleep,
523*4882a593Smuzhiyun .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl,
524*4882a593Smuzhiyun
525*4882a593Smuzhiyun .set_frontend = ves1x93_set_frontend,
526*4882a593Smuzhiyun .get_frontend = ves1x93_get_frontend,
527*4882a593Smuzhiyun
528*4882a593Smuzhiyun .read_status = ves1x93_read_status,
529*4882a593Smuzhiyun .read_ber = ves1x93_read_ber,
530*4882a593Smuzhiyun .read_signal_strength = ves1x93_read_signal_strength,
531*4882a593Smuzhiyun .read_snr = ves1x93_read_snr,
532*4882a593Smuzhiyun .read_ucblocks = ves1x93_read_ucblocks,
533*4882a593Smuzhiyun
534*4882a593Smuzhiyun .set_voltage = ves1x93_set_voltage,
535*4882a593Smuzhiyun };
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun module_param(debug, int, 0644);
538*4882a593Smuzhiyun
539*4882a593Smuzhiyun MODULE_DESCRIPTION("VLSI VES1x93 DVB-S Demodulator driver");
540*4882a593Smuzhiyun MODULE_AUTHOR("Ralph Metzler");
541*4882a593Smuzhiyun MODULE_LICENSE("GPL");
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun EXPORT_SYMBOL(ves1x93_attach);
544