2 cx24110 - Single Chip Satellite Channel Receiver driver module
3 used on the the Pinnacle PCTV Sat cards
5 Copyright (C) 2002 Peter Hettkamp <peter.hettkamp@t-online.de> based on
7 Copyright (C) 1999 Convergence Integrated Media GmbH <ralph@convergence.de>
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.
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
18 GNU General Public License for more details.
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.
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.
32 Oct-2002: Migrate to API V3 (formerly known as NEWSTRUCT)
35 #include <linux/slab.h>
36 #include <linux/kernel.h>
37 #include <linux/module.h>
38 #include <linux/init.h>
40 #include "dvb_frontend.h"
41 #include "dvb_functions.h"
44 #define dprintk if (debug) printk
47 static struct dvb_frontend_info cx24110_info = {
48 .name = "Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811",
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
64 /* fixme: are these values correct? especially ..._tolerance and caps */
67 static struct {u8 reg; u8 data;} cx24110_regdata[]=
68 /* Comments beginning with @ denote this value should
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
93 /* leave the current code rate and normalization
94 registers as they are after reset... */
95 {0x21,0x10}, /* @ during AutoAcq, search each viterbi setting
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 */
130 static int cx24110_writereg (struct dvb_i2c_bus *i2c, int reg, int data)
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 */
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);
147 static u8 cx24110_readreg (struct dvb_i2c_bus *i2c, u8 reg)
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);
158 dprintk("%s: readreg error (ret == %i)\n", __FUNCTION__, ret);
164 static int cx24108_write (struct dvb_i2c_bus *i2c, u32 data)
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... */
170 dprintk("cx24110 debug: cx24108_write(%8.8x)\n",data);
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)
182 /* send another 8 bytes */
183 cx24110_writereg(i2c,0x72,(data>>16)&0xff);
184 while ((cx24110_readreg(i2c,0x6d)&0xc0)==0x80)
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)
190 /* now strobe the enable line once */
191 cx24110_writereg(i2c,0x6d,0x32);
192 cx24110_writereg(i2c,0x6d,0x30);
198 static int cx24108_set_tv_freq (struct dvb_i2c_bus *i2c, u32 freq)
200 /* fixme (low): error handling */
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,
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);
217 freq=950000; /* kHz */
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++)
223 dprintk("cx24110 debug: select vco #%d (f=%d)\n",i,freq);
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
230 n=((i<=2?2:1)*freq*10L)/(XTAL/100);
234 pump=(freq<(osci[i-1]+osci[i])/2);
236 ((pump?1:2)<<(14+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);
250 dvb_delay(10); /* wait a moment for the tuner pll to lock */
252 /* tuner pll lock can be monitored on GPIO pin 4 of cx24110 */
253 while (!(cx24110_readreg(i2c,0x66)&0x20)&&i<1000)
255 dprintk("cx24110 debug: GPIO IN=%2.2x(loop=%d)\n",
256 cx24110_readreg(i2c,0x66),i);
262 static int cx24110_init (struct dvb_i2c_bus *i2c)
264 /* fixme (low): error handling */
267 dprintk("%s: init chip\n", __FUNCTION__);
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);
277 static int cx24110_set_inversion (struct dvb_i2c_bus *i2c, fe_spectral_inversion_t inversion)
279 /* fixme (low): error handling */
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 */
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 */
301 cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)&0xfe);
302 /* AcqSpectrInvDis off. Leave initial & current states as is */
312 static int cx24110_set_fec (struct dvb_i2c_bus *i2c, fe_code_rate_t fec)
314 /* fixme (low): error handling */
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};
320 /* Well, the AutoAcq engine of the cx24106 and 24110 automatically
321 searches all enabled viterbi rates, and can handle non-standard
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 */
340 cx24110_writereg(i2c,0x37,cx24110_readreg(i2c,0x37)|0x20);
341 /* set AcqVitDis bit */
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 */
352 /* fixme (low): which is the correct return code? */
358 static fe_code_rate_t cx24110_get_fec (struct dvb_i2c_bus *i2c)
362 i=cx24110_readreg(i2c,0x22)&0x0f;
364 return FEC_1_2 + i - 1;
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. */
375 static int cx24110_set_symbolrate (struct dvb_i2c_bus *i2c, u32 srate)
377 /* fixme (low): add error handling */
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};
387 dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate);
388 if (srate>90999000UL/2)
393 for(i=0;(i<sizeof(bands)/sizeof(bands[0]))&&(srate>bands[i]);i++)
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);
403 } else if(srate<60666000UL/2) { /* sample rate 60MHz */
404 cx24110_writereg(i2c,0x07,tmp|0x1);
405 cx24110_writereg(i2c,0x06,0xa5);
407 } else if(srate<80888000UL/2) { /* sample rate 80MHz */
408 cx24110_writereg(i2c,0x07,tmp|0x2);
409 cx24110_writereg(i2c,0x06,0x87);
411 } else { /* sample rate 90MHz */
412 cx24110_writereg(i2c,0x07,tmp|0x3);
413 cx24110_writereg(i2c,0x06,0x78);
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 */
430 ratio=(ratio<<8)+(tmp/BDRI);
433 ratio=(ratio<<8)+(tmp/BDRI);
436 ratio=(ratio<<1)+(tmp/BDRI);
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);
442 cx24110_writereg(i2c, 0x1, (ratio>>16)&0xff);
443 cx24110_writereg(i2c, 0x2, (ratio>>8)&0xff);
444 cx24110_writereg(i2c, 0x3, (ratio)&0xff);
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 */
457 static int cx24110_set_voltage (struct dvb_i2c_bus *i2c, fe_sec_voltage_t voltage)
461 return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0xc0);
463 return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&0x3b)|0x40);
469 static void sendDiSEqCMessage(struct dvb_i2c_bus *i2c, struct dvb_diseqc_master_cmd *pCmd)
473 for (i = 0; i < pCmd->msg_len; i++)
474 cx24110_writereg(i2c, 0x79 + i, pCmd->msg[i]);
476 rv = cx24110_readreg(i2c, 0x76);
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 */
484 static int cx24110_ioctl (struct dvb_frontend *fe, unsigned int cmd, void *arg)
486 struct dvb_i2c_bus *i2c = fe->i2c;
487 static int lastber=0, lastbyer=0,lastbler=0, lastesn0=0, sum_bler=0;
491 memcpy (arg, &cx24110_info, sizeof(struct dvb_frontend_info));
496 fe_status_t *status = arg;
497 int sync = cx24110_readreg (i2c, 0x55);
502 *status |= FE_HAS_SIGNAL;
505 *status |= FE_HAS_CARRIER;
507 sync = cx24110_readreg (i2c, 0x08);
510 *status |= FE_HAS_VITERBI;
513 *status |= FE_HAS_SYNC;
515 if ((sync & 0x60) == 0x60)
516 *status |= FE_HAS_LOCK;
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;
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);
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 */
550 u32 *ber = (u32 *) arg;
553 /* fixme (maybe): value range is 16 bit. Scale? */
557 case FE_READ_SIGNAL_STRENGTH:
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;
567 /* no provision in hardware. Can be computed from the Es/N0 estimator, but I don't know how. */
568 *(u16*) arg = lastesn0;
572 case FE_READ_UNCORRECTED_BLOCKS:
574 *(u16*) arg = sum_bler&0xffff;
579 case FE_SET_FRONTEND:
581 struct dvb_frontend_parameters *p = arg;
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 */
591 case FE_GET_FRONTEND:
593 struct dvb_frontend_parameters *p = arg;
594 s32 afc; unsigned sclk;
596 /* cannot read back tuner settings (freq). Need to have some private storage */
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;
606 afc = sclk*(cx24110_readreg (i2c, 0x44)&0x1f)+
607 ((sclk*cx24110_readreg (i2c, 0x45))>>8)+
608 ((sclk*cx24110_readreg (i2c, 0x46))>>16);
611 p->inversion = (cx24110_readreg (i2c, 0x22) & 0x10) ?
612 INVERSION_ON : INVERSION_OFF;
613 p->u.qpsk.fec_inner = cx24110_get_fec (i2c);
618 /* cannot do this from the FE end. How to communicate this to the place where it can be done? */
621 return cx24110_init (i2c);
624 return cx24110_writereg(i2c,0x76,(cx24110_readreg(i2c,0x76)&~0x10)|((((fe_sec_tone_mode_t) arg)==SEC_TONE_ON)?0x10:0));
626 return cx24110_set_voltage (i2c, (fe_sec_voltage_t) arg);
628 case FE_DISEQC_SEND_MASTER_CMD:
629 sendDiSEqCMessage(i2c, (struct dvb_diseqc_master_cmd*) arg);
640 static int cx24110_attach (struct dvb_i2c_bus *i2c, void **data)
644 sig=cx24110_readreg (i2c, 0x00);
645 if ( sig != 0x5a && sig != 0x69 )
648 return dvb_register_frontend (cx24110_ioctl, i2c, NULL, &cx24110_info);
652 static void cx24110_detach (struct dvb_i2c_bus *i2c, void *data)
654 dvb_unregister_frontend (cx24110_ioctl, i2c);
658 static int __init init_cx24110 (void)
660 return dvb_register_i2c_device (THIS_MODULE, cx24110_attach, cx24110_detach);
664 static void __exit exit_cx24110 (void)
666 dvb_unregister_i2c_device (cx24110_attach);
670 module_init(init_cx24110);
671 module_exit(exit_cx24110);
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");