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