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