Merge branches 'sh/serial-rework' and 'sh/oprofile'
[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         .serial_mpeg = 1,
495 };
496
497 static struct itd1000_config skystar2_rev2_7_itd1000_config = {
498         .i2c_address = 0x61,
499 };
500
501 /* SkyStar2 rev2.8 */
502 static struct cx24123_config skystar2_rev2_8_cx24123_config = {
503         .demod_address = 0x55,
504         .dont_use_pll = 1,
505         .agc_callback = cx24113_agc_callback,
506 };
507
508 static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
509         .i2c_addr = 0x54,
510         .xtal_khz = 10111,
511 };
512
513 /* try to figure out the frontend, each card/box can have on of the following list */
514 int flexcop_frontend_init(struct flexcop_device *fc)
515 {
516         struct dvb_frontend_ops *ops;
517         struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
518         struct i2c_adapter *i2c_tuner;
519
520         /* enable no_base_addr - no repeated start when reading */
521         fc->fc_i2c_adap[0].no_base_addr = 1;
522         fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c);
523         if (fc->fe != NULL) {
524                 flexcop_ibi_value r108;
525                 i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
526                 ops = &fc->fe->ops;
527
528                 fc->fe_sleep = ops->sleep;
529                 ops->sleep   = flexcop_sleep;
530
531                 fc->dev_type = FC_SKY_REV27;
532
533                 /* enable no_base_addr - no repeated start when reading */
534                 fc->fc_i2c_adap[2].no_base_addr = 1;
535                 if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
536                         err("ISL6421 could NOT be attached");
537                 else
538                         info("ISL6421 successfully attached");
539
540                 /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */
541                 r108.raw = 0x00000506;
542                 fc->write_ibi_reg(fc, tw_sm_c_108, r108);
543                 if (i2c_tuner) {
544                         if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL)
545                                 err("ITD1000 could NOT be attached");
546                         else
547                                 info("ITD1000 successfully attached");
548                 }
549                 goto fe_found;
550         }
551         fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */
552
553         /* try the sky v2.8 (cx24123, isl6421) */
554         fc->fe = dvb_attach(cx24123_attach,
555                 &skystar2_rev2_8_cx24123_config, i2c);
556         if (fc->fe != NULL) {
557                 i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
558                 if (i2c_tuner != NULL) {
559                         if (dvb_attach(cx24113_attach, fc->fe,
560                                         &skystar2_rev2_8_cx24113_config,
561                                         i2c_tuner) == NULL)
562                                 err("CX24113 could NOT be attached");
563                         else
564                                 info("CX24113 successfully attached");
565                 }
566
567                 fc->dev_type = FC_SKY_REV28;
568
569                 fc->fc_i2c_adap[2].no_base_addr = 1;
570                 if (dvb_attach(isl6421_attach, fc->fe,
571                        &fc->fc_i2c_adap[2].i2c_adap, 0x08, 0, 0) == NULL)
572                         err("ISL6421 could NOT be attached");
573                 else
574                         info("ISL6421 successfully attached");
575
576                 /* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
577                  * IR-receiver (PIC16F818) - but the card has no input for
578                  * that ??? */
579
580                 goto fe_found;
581     }
582
583         /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
584         fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
585         if (fc->fe != NULL) {
586                 ops = &fc->fe->ops;
587
588                 ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
589
590                 ops->set_voltage = flexcop_set_voltage;
591
592                 fc->fe_sleep = ops->sleep;
593                 ops->sleep = flexcop_sleep;
594
595                 fc->dev_type = FC_SKY;
596                 goto fe_found;
597         }
598
599         /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
600         fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
601         if (fc->fe != NULL) {
602                 fc->dev_type = FC_AIR_DVB;
603                 fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
604                 goto fe_found;
605         }
606
607         /* try the air atsc 2nd generation (nxt2002) */
608         fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
609         if (fc->fe != NULL) {
610                 fc->dev_type = FC_AIR_ATSC2;
611                 dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
612                 goto fe_found;
613         }
614
615         fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
616         if (fc->fe != NULL) {
617                 fc->dev_type = FC_AIR_ATSC3;
618                 dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
619                                 TUNER_LG_TDVS_H06XF);
620                 goto fe_found;
621         }
622
623         /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
624         fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
625         if (fc->fe != NULL) {
626                 fc->dev_type = FC_AIR_ATSC1;
627                 goto fe_found;
628         }
629
630         /* try the cable dvb (stv0297) */
631         fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
632         if (fc->fe != NULL) {
633                 fc->dev_type = FC_CABLE;
634                 fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
635                 goto fe_found;
636         }
637
638         /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
639         fc->fe = dvb_attach(mt312_attach,
640                 &skystar23_samsung_tbdu18132_config, i2c);
641         if (fc->fe != NULL) {
642                 ops = &fc->fe->ops;
643
644                 ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
645
646                 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
647                 ops->diseqc_send_burst      = flexcop_diseqc_send_burst;
648                 ops->set_tone               = flexcop_set_tone;
649                 ops->set_voltage            = flexcop_set_voltage;
650
651                 fc->fe_sleep                = ops->sleep;
652                 ops->sleep                  = flexcop_sleep;
653
654                 fc->dev_type                = FC_SKY_OLD;
655                 goto fe_found;
656         }
657
658         err("no frontend driver found for this B2C2/FlexCop adapter");
659         return -ENODEV;
660
661 fe_found:
662         info("found '%s' .", fc->fe->ops.info.name);
663         if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
664                 err("frontend registration failed!");
665                 ops = &fc->fe->ops;
666                 if (ops->release != NULL)
667                         ops->release(fc->fe);
668                 fc->fe = NULL;
669                 return -EINVAL;
670         }
671         fc->init_state |= FC_STATE_FE_INIT;
672         return 0;
673 }
674
675 void flexcop_frontend_exit(struct flexcop_device *fc)
676 {
677         if (fc->init_state & FC_STATE_FE_INIT) {
678                 dvb_unregister_frontend(fc->fe);
679                 dvb_frontend_detach(fc->fe);
680         }
681
682         fc->init_state &= ~FC_STATE_FE_INIT;
683 }