ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / media / dvb / frontends / cx24110.c
1 /*
2     cx24110 - Single Chip Satellite Channel Receiver driver module
3                used on the the Pinnacle PCTV Sat cards
4
5     Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on
6     work
7     Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
8
9     This program is free software; you can redistribute it and/or modify
10     it under the terms of the GNU General Public License as published by
11     the Free Software Foundation; either version 2 of the License, or
12     (at your option) any later version.
13
14     This program is distributed in the hope that it will be useful,
15     but WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
18     GNU General Public License for more details.
19
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
24 */
25
26 /* currently drives the Conexant cx24110 and cx24106 QPSK decoder chips,
27    connected via i2c to a Conexant Fusion 878 (this uses the standard
28    linux bttv driver). The tuner chip is supposed to be the Conexant
29    cx24108 digital satellite tuner, driven through the tuner interface
30    of the cx24110. SEC is also supplied by the cx24110.
31
32    Oct-2002: Migrate to API V3 (formerly known as NEWSTRUCT)
33 */
34
35 #include <linux/slab.h>
36 #include <linux/kernel.h>
37 #include <linux/module.h>
38 #include <linux/init.h>
39
40 #include "dvb_frontend.h"
41 #include "dvb_functions.h"
42
43 static int debug = 0;
44 #define dprintk if (debug) printk
45
46
47 static struct dvb_frontend_info cx24110_info = {
48         .name = "Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811",
49         .type = FE_QPSK,
50         .frequency_min = 950000,
51         .frequency_max = 2150000,
52         .frequency_stepsize = 1011,  /* kHz for QPSK frontends, can be reduced
53                                         to 253kHz on the cx24108 tuner */
54         .frequency_tolerance = 29500,
55         .symbol_rate_min = 1000000,
56         .symbol_rate_max = 45000000,
57 /*      .symbol_rate_tolerance = ???,*/
58         .notifier_delay = 50,                /* 1/20 s */
59         .caps = FE_CAN_INVERSION_AUTO |
60                 FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
61                 FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
62                 FE_CAN_QPSK | FE_CAN_RECOVER
63 };
64 /* fixme: are these values correct? especially ..._tolerance and caps */
65
66
67 static struct {u8 reg; u8 data;} cx24110_regdata[]=
68                       /* Comments beginning with @ denote this value should
69                          be the default */
70         {{0x09,0x01}, /* SoftResetAll */
71          {0x09,0x00}, /* release reset */
72          {0x01,0xe8}, /* MSB of code rate 27.5MS/s */
73          {0x02,0x17}, /* middle byte " */
74          {0x03,0x29}, /* LSB         " */
75          {0x05,0x03}, /* @ DVB mode, standard code rate 3/4 */
76          {0x06,0xa5}, /* @ PLL 60MHz */
77          {0x07,0x01}, /* @ Fclk, i.e. sampling clock, 60MHz */
78          {0x0a,0x00}, /* @ partial chip disables, do not set */
79          {0x0b,0x01}, /* set output clock in gapped mode, start signal low
80                          active for first byte */
81          {0x0c,0x11}, /* no parity bytes, large hold time, serial data out */
82          {0x0d,0x6f}, /* @ RS Sync/Unsync thresholds */
83          {0x10,0x40}, /* chip doc is misleading here: write bit 6 as 1
84                          to avoid starting the BER counter. Reset the
85                          CRC test bit. Finite counting selected */
86          {0x15,0xff}, /* @ size of the limited time window for RS BER
87                          estimation. It is <value>*256 RS blocks, this
88                          gives approx. 2.6 sec at 27.5MS/s, rate 3/4 */
89          {0x16,0x00}, /* @ enable all RS output ports */
90          {0x17,0x04}, /* @ time window allowed for the RS to sync */
91          {0x18,0xae}, /* @ allow all standard DVB code rates to be scanned
92                          for automatically */
93                       /* leave the current code rate and normalization
94                          registers as they are after reset... */
95          {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
96                          only once */
97          {0x23,0x18}, /* @ size of the limited time window for Viterbi BER
98                          estimation. It is <value>*65536 channel bits, i.e.
99                          approx. 38ms at 27.5MS/s, rate 3/4 */
100          {0x24,0x24}, /* do not trigger Viterbi CRC test. Finite count window */
101                       /* leave front-end AGC parameters at default values */
102                       /* leave decimation AGC parameters at default values */
103          {0x35,0x40}, /* disable all interrupts. They are not connected anyway */
104          {0x36,0xff}, /* clear all interrupt pending flags */
105          {0x37,0x00}, /* @ fully enable AutoAcqq state machine */
106          {0x38,0x07}, /* @ enable fade recovery, but not autostart AutoAcq */
107                       /* leave the equalizer parameters on their default values */
108                       /* leave the final AGC parameters on their default values */
109          {0x41,0x00}, /* @ MSB of front-end derotator frequency */
110          {0x42,0x00}, /* @ middle bytes " */
111          {0x43,0x00}, /* @ LSB          " */
112                       /* leave the carrier tracking loop parameters on default */
113                       /* leave the bit timing loop parameters at gefault */
114          {0x56,0x4d}, /* set the filtune voltage to 2.7V, as recommended by */
115                       /* the cx24108 data sheet for symbol rates above 15MS/s */
116          {0x57,0x00}, /* @ Filter sigma delta enabled, positive */
117          {0x61,0x95}, /* GPIO pins 1-4 have special function */
118          {0x62,0x05}, /* GPIO pin 5 has special function, pin 6 is GPIO */
119          {0x63,0x00}, /* All GPIO pins use CMOS output characteristics */
120          {0x64,0x20}, /* GPIO 6 is input, all others are outputs */
121          {0x6d,0x30}, /* tuner auto mode clock freq 62kHz */
122          {0x70,0x15}, /* use auto mode, tuner word is 21 bits long */
123          {0x73,0x00}, /* @ disable several demod bypasses */
124          {0x74,0x00}, /* @  " */
125          {0x75,0x00}  /* @  " */
126                       /* the remaining registers are for SEC */
127         };
128
129
130 static int cx24110_writereg (struct dvb_i2c_bus *i2c, int reg, int data)
131 {
132         u8 buf [] = { reg, data };
133         struct i2c_msg msg = { .addr = 0x55, .flags = 0, .buf = buf, .len = 2 };
134 /* fixme (medium): HW allows any i2c address. 0x55 is the default, but the
135    cx24110 might show up at any address */
136         int err;
137
138         if ((err = i2c->xfer (i2c, &msg, 1)) != 1) {
139                 dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __FUNCTION__, err, reg, data);
140                 return -EREMOTEIO;
141         }
142
143         return 0;
144 }
145
146
147 static u8 cx24110_readreg (struct dvb_i2c_bus *i2c, u8 reg)
148 {
149         int ret;
150         u8 b0 [] = { reg };
151         u8 b1 [] = { 0 };
152         struct i2c_msg msg [] = { { .addr = 0x55, .flags = 0, .buf = b0, .len = 1 },
153                            { .addr = 0x55, .flags = I2C_M_RD, .buf = b1, .len = 1 } };
154 /* fixme (medium): address might be different from 0x55 */
155         ret = i2c->xfer (i2c, msg, 2);
156
157         if (ret != 2)
158                 dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
159
160         return b1[0];
161 }
162
163
164 static int cx24108_write (struct dvb_i2c_bus *i2c, u32 data)
165 {
166 /* tuner data is 21 bits long, must be left-aligned in data */
167 /* tuner cx24108 is written through a dedicated 3wire interface on the demod chip */
168 /* FIXME (low): add error handling, avoid infinite loops if HW fails... */
169
170 dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
171
172         cx24110_writereg(i2c,0x6d,0x30); /* auto mode at 62kHz */
173         cx24110_writereg(i2c,0x70,0x15); /* auto mode 21 bits */
174         /* if the auto tuner writer is still busy, clear it out */
175         while (cx24110_readreg(i2c,0x6d)&0x80)
176                 cx24110_writereg(i2c,0x72,0);
177         /* write the topmost 8 bits */
178         cx24110_writereg(i2c,0x72,(data>>24)&0xff);
179         /* wait for the send to be completed */
180         while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
181                 ;
182         /* send another 8 bytes */
183         cx24110_writereg(i2c,0x72,(data>>16)&0xff);
184         while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
185                 ;
186         /* and the topmost 5 bits of this byte */
187         cx24110_writereg(i2c,0x72,(data>>8)&0xff);
188         while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
189                 ;
190         /* now strobe the enable line once */
191         cx24110_writereg(i2c,0x6d,0x32);
192         cx24110_writereg(i2c,0x6d,0x30);
193
194         return 0;
195 }
196
197
198 static int cx24108_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
199 {
200 /* fixme (low): error handling */
201         int i, a, n, pump;
202         u32 band, pll;
203
204
205         static const u32 osci[]={ 950000,1019000,1075000,1178000,
206                                  1296000,1432000,1576000,1718000,
207                                  1856000,2036000,2150000};
208         static const u32 bandsel[]={0,0x00020000,0x00040000,0x00100800,
209                                       0x00101000,0x00102000,0x00104000,
210                                       0x00108000,0x00110000,0x00120000,
211                                       0x00140000};
212
213 #define XTAL 1011100 /* Hz, really 1.0111 MHz and a /10 prescaler */
214         dprintk("cx24110 debug: cx24108_set_tv_freq, freq=%d\n",freq);
215
216         if (freq<950000)
217                 freq=950000; /* kHz */
218         if (freq>2150000)
219                 freq=2150000; /* satellite IF is 950..2150MHz */
220         /* decide which VCO to use for the input frequency */
221         for (i=1;(i<sizeof(osci)/sizeof(osci[0]))&&(osci[i]<freq);i++)
222                 ;
223         dprintk("cx24110 debug: select vco #%d (f=%d)\n",i,freq);
224         band=bandsel[i];
225         /* the gain values must be set by SetSymbolrate */
226         /* compute the pll divider needed, from Conexant data sheet,
227            resolved for (n*32+a), remember f(vco) is f(receive) *2 or *4,
228            depending on the divider bit. It is set to /4 on the 2 lowest
229            bands  */
230         n=((i<=2?2:1)*freq*10L)/(XTAL/100);
231         a=n%32; n/=32;
232         if (a==0)
233                 n--;
234         pump=(freq<(osci[i-1]+osci[i])/2);
235         pll=0xf8000000|
236             ((pump?1:2)<<(14+11))|
237             ((n&0x1ff)<<(5+11))|
238             ((a&0x1f)<<11);
239         /* everything is shifted left 11 bits to left-align the bits in the
240            32bit word. Output to the tuner goes MSB-aligned, after all */
241         dprintk("cx24110 debug: pump=%d, n=%d, a=%d\n",pump,n,a);
242         cx24108_write(i2c,band);
243         /* set vga and vca to their widest-band settings, as a precaution.
244            SetSymbolrate might not be called to set this up */
245         cx24108_write(i2c,0x500c0000);
246         cx24108_write(i2c,0x83f1f800);
247         cx24108_write(i2c,pll);
248         cx24110_writereg(i2c,0x56,0x7f);
249
250         dvb_delay(10); /* wait a moment for the tuner pll to lock */
251
252         /* tuner pll lock can be monitored on GPIO pin 4 of cx24110 */
253         while (!(cx24110_readreg(i2c,0x66)&0x20)&&i<1000)
254                 i++;
255         dprintk("cx24110 debug: GPIO IN=%2.2x(loop=%d)\n",
256                 cx24110_readreg(i2c,0x66),i);
257         return 0;
258
259 }
260
261
262 static int cx24110_init (struct dvb_i2c_bus *i2c)
263 {
264 /* fixme (low): error handling */
265         int i;
266
267         dprintk("%s: init chip\n", __FUNCTION__);
268
269         for(i=0;i<sizeof(cx24110_regdata)/sizeof(cx24110_regdata[0]);i++) {
270                 cx24110_writereg(i2c,cx24110_regdata[i].reg,cx24110_regdata[i].data);
271         };
272
273         return 0;
274 }
275
276
277 static int cx24110_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
278 {
279 /* fixme (low): error handling */
280
281         switch (inversion) {
282         case INVERSION_OFF:
283                 cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x1);
284                 /* AcqSpectrInvDis on. No idea why someone should want this */
285                 cx24110_writereg(i2c,0x5,cx24110_readreg(i2c,0x5)&0xf7);
286                 /* Initial value 0 at start of acq */
287                 cx24110_writereg(i2c,0x22,cx24110_readreg(i2c,0x22)&0xef);
288                 /* current value 0 */
289                 /* The cx24110 manual tells us this reg is read-only.
290                    But what the heck... set it ayways */
291                 break;
292         case INVERSION_ON:
293                 cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x1);
294                 /* AcqSpectrInvDis on. No idea why someone should want this */
295                 cx24110_writereg(i2c,0x5,cx24110_readreg(i2c,0x5)|0x08);
296                 /* Initial value 1 at start of acq */
297                 cx24110_writereg(i2c,0x22,cx24110_readreg(i2c,0x22)|0x10);
298                 /* current value 1 */
299                 break;
300         case INVERSION_AUTO:
301                 cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)&0xfe);
302                 /* AcqSpectrInvDis off. Leave initial & current states as is */
303                 break;
304         default:
305                 return -EINVAL;
306         }
307
308         return 0;
309 }
310
311
312 static int cx24110_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
313 {
314 /* fixme (low): error handling */
315
316         static const int rate[]={-1,1,2,3,5,7,-1};
317         static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1};
318         static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1};
319
320         /* Well, the AutoAcq engine of the cx24106 and 24110 automatically
321            searches all enabled viterbi rates, and can handle non-standard
322            rates as well. */
323
324         if (fec>FEC_AUTO)
325                 fec=FEC_AUTO;
326
327         if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
328                 cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)&0xdf);
329                 /* clear AcqVitDis bit */
330                 cx24110_writereg(i2c,0x18,0xae);
331                 /* allow all DVB standard code rates */
332                 cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|0x3);
333                 /* set nominal Viterbi rate 3/4 */
334                 cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|0x3);
335                 /* set current Viterbi rate 3/4 */
336                 cx24110_writereg(i2c,0x1a,0x05); cx24110_writereg(i2c,0x1b,0x06);
337                 /* set the puncture registers for code rate 3/4 */
338                 return 0;
339         } else {
340                 cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x20);
341                 /* set AcqVitDis bit */
342                 if(rate[fec]>0) {
343                         cx24110_writereg(i2c,0x05,(cx24110_readreg(i2c,0x05)&0xf0)|rate[fec]);
344                         /* set nominal Viterbi rate */
345                         cx24110_writereg(i2c,0x22,(cx24110_readreg(i2c,0x22)&0xf0)|rate[fec]);
346                         /* set current Viterbi rate */
347                         cx24110_writereg(i2c,0x1a,g1[fec]);
348                         cx24110_writereg(i2c,0x1b,g2[fec]);
349                         /* not sure if this is the right way: I always used AutoAcq mode */
350            } else
351                    return -EOPNOTSUPP;
352 /* fixme (low): which is the correct return code? */
353         };
354         return 0;
355 }
356
357
358 static fe_code_rate_t cx24110_get_fec (struct dvb_i2c_bus *i2c)
359 {
360         int i;
361
362         i=cx24110_readreg(i2c,0x22)&0x0f;
363         if(!(i&0x08)) {
364                 return FEC_1_2 + i - 1;
365         } else {
366 /* fixme (low): a special code rate has been selected. In theory, we need to
367    return a denominator value, a numerator value, and a pair of puncture
368    maps to correctly describe this mode. But this should never happen in
369    practice, because it cannot be set by cx24110_get_fec. */
370            return FEC_NONE;
371         }
372 }
373
374
375 static int cx24110_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
376 {
377 /* fixme (low): add error handling */
378         u32 ratio;
379         u32 tmp, fclk, BDRI;
380
381         static const u32 bands[]={5000000UL,15000000UL,90999000UL/2};
382         static const u32 vca[]={0x80f03800,0x81f0f800,0x83f1f800};
383         static const u32 vga[]={0x5f8fc000,0x580f0000,0x500c0000};
384         static const u8  filtune[]={0xa2,0xcc,0x66};
385         int i;
386
387 dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
388         if (srate>90999000UL/2)
389                 srate=90999000UL/2;
390         if (srate<500000)
391                 srate=500000;
392
393         for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++)
394                 ;
395         /* first, check which sample rate is appropriate: 45, 60 80 or 90 MHz,
396            and set the PLL accordingly (R07[1:0] Fclk, R06[7:4] PLLmult,
397            R06[3:0] PLLphaseDetGain */
398         tmp=cx24110_readreg(i2c,0x07)&0xfc;
399         if(srate<90999000UL/4) { /* sample rate 45MHz*/
400                 cx24110_writereg(i2c,0x07,tmp);
401                 cx24110_writereg(i2c,0x06,0x78);
402                 fclk=90999000UL/2;
403         } else if(srate<60666000UL/2) { /* sample rate 60MHz */
404                 cx24110_writereg(i2c,0x07,tmp|0x1);
405                 cx24110_writereg(i2c,0x06,0xa5);
406                 fclk=60666000UL;
407         } else if(srate<80888000UL/2) { /* sample rate 80MHz */
408                 cx24110_writereg(i2c,0x07,tmp|0x2);
409                 cx24110_writereg(i2c,0x06,0x87);
410                 fclk=80888000UL;
411         } else { /* sample rate 90MHz */
412                 cx24110_writereg(i2c,0x07,tmp|0x3);
413                 cx24110_writereg(i2c,0x06,0x78);
414                 fclk=90999000UL;
415         };
416         dprintk("cx24110 debug: fclk %d Hz\n",fclk);
417         /* we need to divide two integers with approx. 27 bits in 32 bit
418            arithmetic giving a 25 bit result */
419         /* the maximum dividend is 90999000/2, 0x02b6446c, this number is
420            also the most complex divisor. Hence, the dividend has,
421            assuming 32bit unsigned arithmetic, 6 clear bits on top, the
422            divisor 2 unused bits at the bottom. Also, the quotient is
423            always less than 1/2. Borrowed from VES1893.c, of course */
424
425         tmp=srate<<6;
426         BDRI=fclk>>2;
427         ratio=(tmp/BDRI);
428
429         tmp=(tmp%BDRI)<<8;
430         ratio=(ratio<<8)+(tmp/BDRI);
431
432         tmp=(tmp%BDRI)<<8;
433         ratio=(ratio<<8)+(tmp/BDRI);
434
435         tmp=(tmp%BDRI)<<1;
436         ratio=(ratio<<1)+(tmp/BDRI);
437
438         dprintk("srate= %d (range %d, up to %d)\n", srate,i,bands[i]);
439         dprintk("fclk = %d\n", fclk);
440         dprintk("ratio= %08x\n", ratio);
441
442         cx24110_writereg(i2c, 0x1, (ratio>>16)&0xff);
443         cx24110_writereg(i2c, 0x2, (ratio>>8)&0xff);
444         cx24110_writereg(i2c, 0x3, (ratio)&0xff);
445
446         /* please see the cx24108 data sheet, this controls tuner gain
447            and bandwidth settings depending on the symbol rate */
448         cx24108_write(i2c,vga[i]);
449         cx24108_write(i2c,vca[i]); /* gain is set on tuner chip */
450         cx24110_writereg(i2c,0x56,filtune[i]); /* bw is contolled by filtune voltage */
451
452         return 0;
453
454 }
455
456
457 static int cx24110_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
458 {
459         switch (voltage) {
460         case SEC_VOLTAGE_13:
461                 return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0xc0);
462         case SEC_VOLTAGE_18:
463                 return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0x40);
464         default:
465                 return -EINVAL;
466         };
467 }
468
469 static void sendDiSEqCMessage(struct dvb_i2c_bus *i2c, struct dvb_diseqc_master_cmd *pCmd)
470 {
471         int i, rv;
472
473         for (i = 0; i < pCmd->msg_len; i++)
474                 cx24110_writereg(i2c, 0x79 + i, pCmd->msg[i]);
475
476         rv = cx24110_readreg(i2c, 0x76);
477
478         cx24110_writereg(i2c, 0x76, ((rv & 0x90) | 0x40) | ((pCmd->msg_len-3) & 3));
479         for (i=500; i-- > 0 && !(cx24110_readreg(i2c,0x76)&0x40);)
480                 ; /* wait for LNB ready */
481 }
482
483
484 static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
485 {
486         struct dvb_i2c_bus *i2c = fe->i2c;
487         static int lastber=0, lastbyer=0,lastbler=0, lastesn0=0, sum_bler=0;
488
489         switch (cmd) {
490         case FE_GET_INFO:
491                 memcpy (arg, &cx24110_info, sizeof(struct dvb_frontend_info));
492                 break;
493
494         case FE_READ_STATUS:
495         {
496                 fe_status_t *status = arg;
497                 int sync = cx24110_readreg (i2c, 0x55);
498
499                 *status = 0;
500
501                 if (sync & 0x10)
502                         *status |= FE_HAS_SIGNAL;
503
504                 if (sync & 0x08)
505                         *status |= FE_HAS_CARRIER;
506
507                 sync = cx24110_readreg (i2c, 0x08);
508
509                 if (sync & 0x40)
510                         *status |= FE_HAS_VITERBI;
511
512                 if (sync & 0x20)
513                         *status |= FE_HAS_SYNC;
514
515                 if ((sync & 0x60) == 0x60)
516                         *status |= FE_HAS_LOCK;
517
518                 if(cx24110_readreg(i2c,0x10)&0x40) {
519                         /* the RS error counter has finished one counting window */
520                         cx24110_writereg(i2c,0x10,0x60); /* select the byer reg */
521                         lastbyer=cx24110_readreg(i2c,0x12)|
522                                 (cx24110_readreg(i2c,0x13)<<8)|
523                                 (cx24110_readreg(i2c,0x14)<<16);
524                         cx24110_writereg(i2c,0x10,0x70); /* select the bler reg */
525                         lastbler=cx24110_readreg(i2c,0x12)|
526                                 (cx24110_readreg(i2c,0x13)<<8)|
527                                 (cx24110_readreg(i2c,0x14)<<16);
528                         cx24110_writereg(i2c,0x10,0x20); /* start new count window */
529                         sum_bler += lastbler;
530                 }
531                 if(cx24110_readreg(i2c,0x24)&0x10) {
532                         /* the Viterbi error counter has finished one counting window */
533                         cx24110_writereg(i2c,0x24,0x04); /* select the ber reg */
534                         lastber=cx24110_readreg(i2c,0x25)|
535                                 (cx24110_readreg(i2c,0x26)<<8);
536                         cx24110_writereg(i2c,0x24,0x04); /* start new count window */
537                         cx24110_writereg(i2c,0x24,0x14);
538                 }
539                 if(cx24110_readreg(i2c,0x6a)&0x80) {
540                         /* the Es/N0 error counter has finished one counting window */
541                         lastesn0=cx24110_readreg(i2c,0x69)|
542                                 (cx24110_readreg(i2c,0x68)<<8);
543                         cx24110_writereg(i2c,0x6a,0x84); /* start new count window */
544                 }
545                 break;
546         }
547
548         case FE_READ_BER:
549         {
550                 u32 *ber = (u32 *) arg;
551
552                 *ber = lastber;
553 /* fixme (maybe): value range is 16 bit. Scale? */
554                 break;
555         }
556
557         case FE_READ_SIGNAL_STRENGTH:
558         {
559 /* no provision in hardware. Read the frontend AGC accumulator. No idea how to scale this, but I know it is 2s complement */
560                 u8 signal = cx24110_readreg (i2c, 0x27)+128;
561                 *((u16*) arg) = (signal << 8) | signal;
562                 break;
563         }
564
565         case FE_READ_SNR:
566         {
567 /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
568                 *(u16*) arg = lastesn0;
569                 break;
570         }
571
572         case FE_READ_UNCORRECTED_BLOCKS:
573         {
574                 *(u16*) arg = sum_bler&0xffff;
575                 sum_bler=0;
576                 break;
577         }
578
579         case FE_SET_FRONTEND:
580         {
581                 struct dvb_frontend_parameters *p = arg;
582
583                 cx24108_set_tv_freq (i2c, p->frequency);
584                 cx24110_set_inversion (i2c, p->inversion);
585                 cx24110_set_fec (i2c, p->u.qpsk.fec_inner);
586                 cx24110_set_symbolrate (i2c, p->u.qpsk.symbol_rate);
587                 cx24110_writereg(i2c,0x04,0x05); /* start aquisition */
588                 break;
589         }
590
591         case FE_GET_FRONTEND:
592         {
593                 struct dvb_frontend_parameters *p = arg;
594                 s32 afc; unsigned sclk;
595
596 /* cannot read back tuner settings (freq). Need to have some private storage */
597
598                 sclk = cx24110_readreg (i2c, 0x07) & 0x03;
599 /* ok, real AFC (FEDR) freq. is afc/2^24*fsamp, fsamp=45/60/80/90MHz.
600  * Need 64 bit arithmetic. Is thiss possible in the kernel? */
601                 if (sclk==0) sclk=90999000L/2L;
602                 else if (sclk==1) sclk=60666000L;
603                 else if (sclk==2) sclk=80888000L;
604                 else sclk=90999000L;
605                 sclk>>=8;
606                 afc = sclk*(cx24110_readreg (i2c, 0x44)&0x1f)+
607                       ((sclk*cx24110_readreg (i2c, 0x45))>>8)+
608                       ((sclk*cx24110_readreg (i2c, 0x46))>>16);
609
610                 p->frequency += afc;
611                 p->inversion = (cx24110_readreg (i2c, 0x22) & 0x10) ?
612                                         INVERSION_ON : INVERSION_OFF;
613                 p->u.qpsk.fec_inner = cx24110_get_fec (i2c);
614                 break;
615         }
616
617         case FE_SLEEP:
618 /* cannot do this from the FE end. How to communicate this to the place where it can be done? */
619                 break;
620         case FE_INIT:
621                 return cx24110_init (i2c);
622
623         case FE_SET_TONE:
624                 return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0));
625         case FE_SET_VOLTAGE:
626                 return cx24110_set_voltage (i2c, (fe_sec_voltage_t) arg);
627
628         case FE_DISEQC_SEND_MASTER_CMD:
629                 sendDiSEqCMessage(i2c, (struct dvb_diseqc_master_cmd*) arg);
630                 return 0;
631
632         default:
633                 return -EOPNOTSUPP;
634         };
635
636         return 0;
637 }
638
639
640 static int cx24110_attach (struct dvb_i2c_bus *i2c, void **data)
641 {
642         u8 sig;
643
644         sig=cx24110_readreg (i2c, 0x00);
645         if ( sig != 0x5a && sig != 0x69 )
646                 return -ENODEV;
647
648         return dvb_register_frontend (cx24110_ioctl, i2c, NULL, &cx24110_info);
649 }
650
651
652 static void cx24110_detach (struct dvb_i2c_bus *i2c, void *data)
653 {
654         dvb_unregister_frontend (cx24110_ioctl, i2c);
655 }
656
657
658 static int __init init_cx24110 (void)
659 {
660         return dvb_register_i2c_device (THIS_MODULE, cx24110_attach, cx24110_detach);
661 }
662
663
664 static void __exit exit_cx24110 (void)
665 {
666         dvb_unregister_i2c_device (cx24110_attach);
667 }
668
669
670 module_init(init_cx24110);
671 module_exit(exit_cx24110);
672
673
674 MODULE_DESCRIPTION("DVB Frontend driver module for the Conexant cx24108/cx24110 chipset");
675 MODULE_AUTHOR("Peter Hettkamp");
676 MODULE_LICENSE("GPL");
677 MODULE_PARM(debug,"i");
678