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