]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blob - drivers/media/common/b2c2/flexcop-fe-tuner.c
Merge tag 'media/v4.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
[mirror_ubuntu-artful-kernel.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 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 }