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