Merge branch 'linus' into x86/threadinfo
[linux-2.6] / drivers / media / dvb / b2c2 / flexcop-fe-tuner.c
1 /*
2  * This file is part of linux driver the digital TV devices equipped with B2C2 FlexcopII(b)/III
3  *
4  * flexcop-fe-tuner.c - methods for attaching a frontend and controlling DiSEqC.
5  *
6  * see flexcop.c for copyright information.
7  */
8 #include <media/tuner.h>
9
10 #include "flexcop.h"
11
12 #include "stv0299.h"
13 #include "mt352.h"
14 #include "nxt200x.h"
15 #include "bcm3510.h"
16 #include "stv0297.h"
17 #include "mt312.h"
18 #include "lgdt330x.h"
19 #include "dvb-pll.h"
20 #include "tuner-simple.h"
21
22 #include "s5h1420.h"
23 #include "itd1000.h"
24
25 #include "cx24123.h"
26 #include "cx24113.h"
27
28 #include "isl6421.h"
29
30 /* lnb control */
31
32 static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
33 {
34         struct flexcop_device *fc = fe->dvb->priv;
35         flexcop_ibi_value v;
36         deb_tuner("polarity/voltage = %u\n", voltage);
37
38         v = fc->read_ibi_reg(fc, misc_204);
39         switch (voltage) {
40                 case SEC_VOLTAGE_OFF:
41                         v.misc_204.ACPI1_sig = 1;
42                         break;
43                 case SEC_VOLTAGE_13:
44                         v.misc_204.ACPI1_sig = 0;
45                         v.misc_204.LNB_L_H_sig = 0;
46                         break;
47                 case SEC_VOLTAGE_18:
48                         v.misc_204.ACPI1_sig = 0;
49                         v.misc_204.LNB_L_H_sig = 1;
50                         break;
51                 default:
52                         err("unknown SEC_VOLTAGE value");
53                         return -EINVAL;
54         }
55         return fc->write_ibi_reg(fc, misc_204, v);
56 }
57
58 static int flexcop_sleep(struct dvb_frontend* fe)
59 {
60         struct flexcop_device *fc = fe->dvb->priv;
61 /*      flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204); */
62
63         if (fc->fe_sleep)
64                 return fc->fe_sleep(fe);
65
66 /*      v.misc_204.ACPI3_sig = 1;
67         fc->write_ibi_reg(fc,misc_204,v);*/
68
69         return 0;
70 }
71
72 static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
73 {
74         /* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
75         struct flexcop_device *fc = fe->dvb->priv;
76         flexcop_ibi_value v;
77         u16 ax;
78         v.raw = 0;
79
80         deb_tuner("tone = %u\n",tone);
81
82         switch (tone) {
83                 case SEC_TONE_ON:
84                         ax = 0x01ff;
85                         break;
86                 case SEC_TONE_OFF:
87                         ax = 0;
88                         break;
89                 default:
90                         err("unknown SEC_TONE value");
91                         return -EINVAL;
92         }
93
94         v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
95
96         v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
97         v.lnb_switch_freq_200.LNB_CTLLowCount_sig  = ax == 0 ? 0x1ff : ax;
98
99         return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
100 }
101
102 static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
103 {
104         flexcop_set_tone(fe, SEC_TONE_ON);
105         udelay(data ? 500 : 1000);
106         flexcop_set_tone(fe, SEC_TONE_OFF);
107         udelay(data ? 1000 : 500);
108 }
109
110 static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
111 {
112         int i, par = 1, d;
113
114         for (i = 7; i >= 0; i--) {
115                 d = (data >> i) & 1;
116                 par ^= d;
117                 flexcop_diseqc_send_bit(fe, d);
118         }
119
120         flexcop_diseqc_send_bit(fe, par);
121 }
122
123 static int flexcop_send_diseqc_msg(struct dvb_frontend* fe, int len, u8 *msg, unsigned long burst)
124 {
125         int i;
126
127         flexcop_set_tone(fe, SEC_TONE_OFF);
128         mdelay(16);
129
130         for (i = 0; i < len; i++)
131                 flexcop_diseqc_send_byte(fe,msg[i]);
132
133         mdelay(16);
134
135         if (burst != -1) {
136                 if (burst)
137                         flexcop_diseqc_send_byte(fe, 0xff);
138                 else {
139                         flexcop_set_tone(fe, SEC_TONE_ON);
140                         udelay(12500);
141                         flexcop_set_tone(fe, SEC_TONE_OFF);
142                 }
143                 msleep(20);
144         }
145         return 0;
146 }
147
148 static int flexcop_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
149 {
150         return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
151 }
152
153 static int flexcop_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t minicmd)
154 {
155         return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
156 }
157
158 /* dvb-s stv0299 */
159 static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio)
160 {
161         u8 aclk = 0;
162         u8 bclk = 0;
163
164         if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; }
165         else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; }
166         else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; }
167         else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; }
168         else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; }
169         else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; }
170
171         stv0299_writereg (fe, 0x13, aclk);
172         stv0299_writereg (fe, 0x14, bclk);
173         stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff);
174         stv0299_writereg (fe, 0x20, (ratio >>  8) & 0xff);
175         stv0299_writereg (fe, 0x21, (ratio      ) & 0xf0);
176
177         return 0;
178 }
179
180 static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
181 {
182         u8 buf[4];
183         u32 div;
184         struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
185         struct flexcop_device *fc = fe->dvb->priv;
186
187         div = params->frequency / 125;
188
189         buf[0] = (div >> 8) & 0x7f;
190         buf[1] = div & 0xff;
191         buf[2] = 0x84;  /* 0xC4 */
192         buf[3] = 0x08;
193
194         if (params->frequency < 1500000)
195                 buf[3] |= 0x10;
196
197         if (fe->ops.i2c_gate_ctrl)
198                 fe->ops.i2c_gate_ctrl(fe, 1);
199         if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
200                 return -EIO;
201         return 0;
202 }
203
204 static u8 samsung_tbmu24112_inittab[] = {
205              0x01, 0x15,
206              0x02, 0x30,
207              0x03, 0x00,
208              0x04, 0x7D,
209              0x05, 0x35,
210              0x06, 0x02,
211              0x07, 0x00,
212              0x08, 0xC3,
213              0x0C, 0x00,
214              0x0D, 0x81,
215              0x0E, 0x23,
216              0x0F, 0x12,
217              0x10, 0x7E,
218              0x11, 0x84,
219              0x12, 0xB9,
220              0x13, 0x88,
221              0x14, 0x89,
222              0x15, 0xC9,
223              0x16, 0x00,
224              0x17, 0x5C,
225              0x18, 0x00,
226              0x19, 0x00,
227              0x1A, 0x00,
228              0x1C, 0x00,
229              0x1D, 0x00,
230              0x1E, 0x00,
231              0x1F, 0x3A,
232              0x20, 0x2E,
233              0x21, 0x80,
234              0x22, 0xFF,
235              0x23, 0xC1,
236              0x28, 0x00,
237              0x29, 0x1E,
238              0x2A, 0x14,
239              0x2B, 0x0F,
240              0x2C, 0x09,
241              0x2D, 0x05,
242              0x31, 0x1F,
243              0x32, 0x19,
244              0x33, 0xFE,
245              0x34, 0x93,
246              0xff, 0xff,
247 };
248
249 static struct stv0299_config samsung_tbmu24112_config = {
250         .demod_address = 0x68,
251         .inittab = samsung_tbmu24112_inittab,
252         .mclk = 88000000UL,
253         .invert = 0,
254         .skip_reinit = 0,
255         .lock_output = STV0299_LOCKOUTPUT_LK,
256         .volt13_op0_op1 = STV0299_VOLT13_OP1,
257         .min_delay_ms = 100,
258         .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
259 };
260
261 /* dvb-t mt352 */
262 static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe)
263 {
264         static u8 mt352_clock_config [] = { 0x89, 0x18, 0x2d };
265         static u8 mt352_reset [] = { 0x50, 0x80 };
266         static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 };
267         static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 };
268         static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
269
270         mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
271         udelay(2000);
272         mt352_write(fe, mt352_reset, sizeof(mt352_reset));
273         mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
274
275         mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
276         mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
277
278         return 0;
279 }
280
281 static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len)
282 {
283         u32 div;
284         unsigned char bs = 0;
285
286         if (buf_len < 5)
287                 return -EINVAL;
288
289         #define IF_FREQUENCYx6 217    /* 6 * 36.16666666667MHz */
290         div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6;
291
292         if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09;
293         if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a;
294         if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08;
295
296         pllbuf[0] = 0x61;
297         pllbuf[1] = div >> 8;
298         pllbuf[2] = div & 0xff;
299         pllbuf[3] = 0xcc;
300         pllbuf[4] = bs;
301
302         return 5;
303 }
304
305 static struct mt352_config samsung_tdtc9251dh0_config = {
306         .demod_address = 0x0f,
307         .demod_init    = samsung_tdtc9251dh0_demod_init,
308 };
309
310 static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
311 {
312         struct flexcop_device *fc = fe->dvb->priv;
313         return request_firmware(fw, name, fc->dev);
314 }
315
316 static struct lgdt330x_config air2pc_atsc_hd5000_config = {
317         .demod_address       = 0x59,
318         .demod_chip          = LGDT3303,
319         .serial_mpeg         = 0x04,
320         .clock_polarity_flip = 1,
321 };
322
323 static struct nxt200x_config samsung_tbmv_config = {
324         .demod_address    = 0x0a,
325 };
326
327 static struct bcm3510_config air2pc_atsc_first_gen_config = {
328         .demod_address    = 0x0f,
329         .request_firmware = flexcop_fe_request_firmware,
330 };
331
332 static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params)
333 {
334         u8 buf[4];
335         u32 div;
336         struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
337         struct flexcop_device *fc = fe->dvb->priv;
338
339         div = (params->frequency + (125/2)) / 125;
340
341         buf[0] = (div >> 8) & 0x7f;
342         buf[1] = (div >> 0) & 0xff;
343         buf[2] = 0x84 | ((div >> 10) & 0x60);
344         buf[3] = 0x80;
345
346         if (params->frequency < 1550000)
347                 buf[3] |= 0x02;
348
349         if (fe->ops.i2c_gate_ctrl)
350                 fe->ops.i2c_gate_ctrl(fe, 1);
351         if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
352                 return -EIO;
353         return 0;
354 }
355
356 static struct mt312_config skystar23_samsung_tbdu18132_config = {
357
358         .demod_address = 0x0e,
359 };
360
361 static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
362                                                struct dvb_frontend_parameters *fep)
363 {
364         struct flexcop_device *fc = fe->dvb->priv;
365         u8 buf[4];
366         u16 div;
367         int ret;
368
369 /*  62.5 kHz * 10 */
370 #define REF_FREQ    625
371 #define FREQ_OFFSET 36125
372
373         div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10)  / REF_FREQ; // 4 MHz = 4000 KHz
374
375         buf[0] = (u8)( div >> 8) & 0x7f;
376         buf[1] = (u8)        div & 0xff;
377
378 /* F(osc) = N * Reference Freq. (62.5 kHz)
379  * byte 2 :  0 N14 N13 N12 N11 N10 N9  N8
380  * byte 3 : N7 N6  N5  N4  N3  N2  N1  N0
381  * byte 4 : 1  *   *   AGD R3  R2  R1  R0
382  * byte 5 : C1 *   RE  RTS BS4 BS3 BS2 BS1
383  * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */
384         buf[2] = 0x95;
385
386 // Range(MHz)  C1 *  RE RTS BS4 BS3 BS2 BS1  Byte 5
387 //  47 - 153   0  *  0   0   0   0   0   1   0x01
388 // 153 - 430   0  *  0   0   0   0   1   0   0x02
389 // 430 - 822   0  *  0   0   1   0   0   0   0x08
390 // 822 - 862   1  *  0   0   1   0   0   0   0x88
391
392              if (fep->frequency <= 153000000) buf[3] = 0x01;
393         else if (fep->frequency <= 430000000) buf[3] = 0x02;
394         else if (fep->frequency <= 822000000) buf[3] = 0x08;
395         else buf[3] = 0x88;
396
397         if (fe->ops.i2c_gate_ctrl)
398                 fe->ops.i2c_gate_ctrl(fe, 0);
399         deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
400         ret = fc->i2c_request(&fc->fc_i2c_adap[2],
401                 FC_WRITE, 0x61, buf[0], &buf[1], 3);
402         deb_tuner("tuner write returned: %d\n",ret);
403
404         return ret;
405 }
406
407 static u8 alps_tdee4_stv0297_inittab[] = {
408         0x80, 0x01,
409         0x80, 0x00,
410         0x81, 0x01,
411         0x81, 0x00,
412         0x00, 0x48,
413         0x01, 0x58,
414         0x03, 0x00,
415         0x04, 0x00,
416         0x07, 0x00,
417         0x08, 0x00,
418         0x30, 0xff,
419         0x31, 0x9d,
420         0x32, 0xff,
421         0x33, 0x00,
422         0x34, 0x29,
423         0x35, 0x55,
424         0x36, 0x80,
425         0x37, 0x6e,
426         0x38, 0x9c,
427         0x40, 0x1a,
428         0x41, 0xfe,
429         0x42, 0x33,
430         0x43, 0x00,
431         0x44, 0xff,
432         0x45, 0x00,
433         0x46, 0x00,
434         0x49, 0x04,
435         0x4a, 0x51,
436         0x4b, 0xf8,
437         0x52, 0x30,
438         0x53, 0x06,
439         0x59, 0x06,
440         0x5a, 0x5e,
441         0x5b, 0x04,
442         0x61, 0x49,
443         0x62, 0x0a,
444         0x70, 0xff,
445         0x71, 0x04,
446         0x72, 0x00,
447         0x73, 0x00,
448         0x74, 0x0c,
449         0x80, 0x20,
450         0x81, 0x00,
451         0x82, 0x30,
452         0x83, 0x00,
453         0x84, 0x04,
454         0x85, 0x22,
455         0x86, 0x08,
456         0x87, 0x1b,
457         0x88, 0x00,
458         0x89, 0x00,
459         0x90, 0x00,
460         0x91, 0x04,
461         0xa0, 0x86,
462         0xa1, 0x00,
463         0xa2, 0x00,
464         0xb0, 0x91,
465         0xb1, 0x0b,
466         0xc0, 0x5b,
467         0xc1, 0x10,
468         0xc2, 0x12,
469         0xd0, 0x02,
470         0xd1, 0x00,
471         0xd2, 0x00,
472         0xd3, 0x00,
473         0xd4, 0x02,
474         0xd5, 0x00,
475         0xde, 0x00,
476         0xdf, 0x01,
477         0xff, 0xff,
478 };
479
480 static struct stv0297_config alps_tdee4_stv0297_config = {
481         .demod_address = 0x1c,
482         .inittab = alps_tdee4_stv0297_inittab,
483 //      .invert = 1,
484 //      .pll_set = alps_tdee4_stv0297_pll_set,
485 };
486
487
488 /* SkyStar2 rev2.7 (a/u) */
489 static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
490         .demod_address = 0x53,
491         .invert = 1,
492         .repeated_start_workaround = 1,
493 };
494
495 static struct itd1000_config skystar2_rev2_7_itd1000_config = {
496         .i2c_address = 0x61,
497 };
498
499 /* SkyStar2 rev2.8 */
500 static struct cx24123_config skystar2_rev2_8_cx24123_config = {
501         .demod_address = 0x55,
502         .dont_use_pll = 1,
503         .agc_callback = cx24113_agc_callback,
504 };
505
506 static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
507         .i2c_addr = 0x54,
508         .xtal_khz = 10111,
509 };
510
511 /* try to figure out the frontend, each card/box can have on of the following list */
512 int flexcop_frontend_init(struct flexcop_device *fc)
513 {
514         struct dvb_frontend_ops *ops;
515         struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
516         struct i2c_adapter *i2c_tuner;
517
518         /* enable no_base_addr - no repeated start when reading */
519         fc->fc_i2c_adap[0].no_base_addr = 1;
520         fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c);
521         if (fc->fe != NULL) {
522                 flexcop_ibi_value r108;
523                 i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
524                 ops = &fc->fe->ops;
525
526                 fc->fe_sleep = ops->sleep;
527                 ops->sleep   = flexcop_sleep;
528
529                 fc->dev_type = FC_SKY_REV27;
530
531                 /* enable no_base_addr - no repeated start when reading */
532                 fc->fc_i2c_adap[2].no_base_addr = 1;
533                 if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
534                         err("ISL6421 could NOT be attached");
535                 else
536                         info("ISL6421 successfully attached");
537
538                 /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */
539                 r108.raw = 0x00000506;
540                 fc->write_ibi_reg(fc, tw_sm_c_108, r108);
541                 if (i2c_tuner) {
542                         if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL)
543                                 err("ITD1000 could NOT be attached");
544                         else
545                                 info("ITD1000 successfully attached");
546                 }
547                 goto fe_found;
548         }
549         fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */
550
551         /* try the sky v2.8 (cx24123, isl6421) */
552         fc->fe = dvb_attach(cx24123_attach,
553                 &skystar2_rev2_8_cx24123_config, i2c);
554         if (fc->fe != NULL) {
555                 i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
556                 if (i2c_tuner != NULL) {
557                         if (dvb_attach(cx24113_attach, fc->fe,
558                                         &skystar2_rev2_8_cx24113_config,
559                                         i2c_tuner) == NULL)
560                                 err("CX24113 could NOT be attached");
561                         else
562                                 info("CX24113 successfully attached");
563                 }
564
565                 fc->dev_type = FC_SKY_REV28;
566
567                 fc->fc_i2c_adap[2].no_base_addr = 1;
568                 if (dvb_attach(isl6421_attach, fc->fe,
569                        &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
570                         err("ISL6421 could NOT be attached");
571                 else
572                         info("ISL6421 successfully attached");
573
574                 /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
575                  * IR-receiver (PIC16F818) - but the card has no input for
576                  * that ??? */
577
578                 goto fe_found;
579     }
580
581         /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
582         fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
583         if (fc->fe != NULL) {
584                 ops = &fc->fe->ops;
585
586                 ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
587
588                 ops->set_voltage = flexcop_set_voltage;
589
590                 fc->fe_sleep = ops->sleep;
591                 ops->sleep = flexcop_sleep;
592
593                 fc->dev_type = FC_SKY;
594                 goto fe_found;
595         }
596
597         /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
598         fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
599         if (fc->fe != NULL) {
600                 fc->dev_type = FC_AIR_DVB;
601                 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
602                 goto fe_found;
603         }
604
605         /* try the air atsc 2nd generation (nxt2002) */
606         fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
607         if (fc->fe != NULL) {
608                 fc->dev_type = FC_AIR_ATSC2;
609                 dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
610                 goto fe_found;
611         }
612
613         fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
614         if (fc->fe != NULL) {
615                 fc->dev_type = FC_AIR_ATSC3;
616                 dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
617                                 TUNER_LG_TDVS_H06XF);
618                 goto fe_found;
619         }
620
621         /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
622         fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
623         if (fc->fe != NULL) {
624                 fc->dev_type = FC_AIR_ATSC1;
625                 goto fe_found;
626         }
627
628         /* try the cable dvb (stv0297) */
629         fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
630         if (fc->fe != NULL) {
631                 fc->dev_type = FC_CABLE;
632                 fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
633                 goto fe_found;
634         }
635
636         /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
637         fc->fe = dvb_attach(mt312_attach,
638                 &skystar23_samsung_tbdu18132_config, i2c);
639         if (fc->fe != NULL) {
640                 ops = &fc->fe->ops;
641
642                 ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
643
644                 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
645                 ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
646                 ops->set_tone               = flexcop_set_tone;
647                 ops->set_voltage            = flexcop_set_voltage;
648
649                 fc->fe_sleep                = ops->sleep;
650                 ops->sleep                  = flexcop_sleep;
651
652                 fc->dev_type                = FC_SKY_OLD;
653                 goto fe_found;
654         }
655
656         err("no frontend driver found for this B2C2/FlexCop adapter");
657         return -ENODEV;
658
659 fe_found:
660         info("found '%s' .", fc->fe->ops.info.name);
661         if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
662                 err("frontend registration failed!");
663                 ops = &fc->fe->ops;
664                 if (ops->release != NULL)
665                         ops->release(fc->fe);
666                 fc->fe = NULL;
667                 return -EINVAL;
668         }
669         fc->init_state |= FC_STATE_FE_INIT;
670         return 0;
671 }
672
673 void flexcop_frontend_exit(struct flexcop_device *fc)
674 {
675         if (fc->init_state & FC_STATE_FE_INIT) {
676                 dvb_unregister_frontend(fc->fe);
677                 dvb_frontend_detach(fc->fe);
678         }
679
680         fc->init_state &= ~FC_STATE_FE_INIT;
681 }