0001
0002
0003
0004
0005
0006
0007 #include <media/tuner.h>
0008 #include "flexcop.h"
0009 #include "mt312.h"
0010 #include "stv0299.h"
0011 #include "s5h1420.h"
0012 #include "itd1000.h"
0013 #include "cx24113.h"
0014 #include "cx24123.h"
0015 #include "isl6421.h"
0016 #include "cx24120.h"
0017 #include "mt352.h"
0018 #include "bcm3510.h"
0019 #include "nxt200x.h"
0020 #include "dvb-pll.h"
0021 #include "lgdt330x.h"
0022 #include "tuner-simple.h"
0023 #include "stv0297.h"
0024
0025
0026
0027
0028 #define FE_SUPPORTED(fe) IS_REACHABLE(CONFIG_DVB_ ## fe)
0029
0030 #if FE_SUPPORTED(BCM3510) || (FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421))
0031 static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
0032 const struct firmware **fw, char *name)
0033 {
0034 struct flexcop_device *fc = fe->dvb->priv;
0035
0036 return request_firmware(fw, name, fc->dev);
0037 }
0038 #endif
0039
0040
0041 #if (FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)) && FE_SUPPORTED(PLL)
0042 static int flexcop_set_voltage(struct dvb_frontend *fe,
0043 enum fe_sec_voltage voltage)
0044 {
0045 struct flexcop_device *fc = fe->dvb->priv;
0046 flexcop_ibi_value v;
0047 deb_tuner("polarity/voltage = %u\n", voltage);
0048
0049 v = fc->read_ibi_reg(fc, misc_204);
0050 switch (voltage) {
0051 case SEC_VOLTAGE_OFF:
0052 v.misc_204.ACPI1_sig = 1;
0053 break;
0054 case SEC_VOLTAGE_13:
0055 v.misc_204.ACPI1_sig = 0;
0056 v.misc_204.LNB_L_H_sig = 0;
0057 break;
0058 case SEC_VOLTAGE_18:
0059 v.misc_204.ACPI1_sig = 0;
0060 v.misc_204.LNB_L_H_sig = 1;
0061 break;
0062 default:
0063 err("unknown SEC_VOLTAGE value");
0064 return -EINVAL;
0065 }
0066 return fc->write_ibi_reg(fc, misc_204, v);
0067 }
0068 #endif
0069
0070 #if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
0071 static int __maybe_unused flexcop_sleep(struct dvb_frontend* fe)
0072 {
0073 struct flexcop_device *fc = fe->dvb->priv;
0074 if (fc->fe_sleep)
0075 return fc->fe_sleep(fe);
0076 return 0;
0077 }
0078 #endif
0079
0080
0081 #if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
0082 static int flexcop_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
0083 {
0084
0085 struct flexcop_device *fc = fe->dvb->priv;
0086 flexcop_ibi_value v;
0087 u16 ax;
0088 v.raw = 0;
0089 deb_tuner("tone = %u\n",tone);
0090
0091 switch (tone) {
0092 case SEC_TONE_ON:
0093 ax = 0x01ff;
0094 break;
0095 case SEC_TONE_OFF:
0096 ax = 0;
0097 break;
0098 default:
0099 err("unknown SEC_TONE value");
0100 return -EINVAL;
0101 }
0102
0103 v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1;
0104 v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
0105 v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
0106 return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
0107 }
0108
0109 static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
0110 {
0111 flexcop_set_tone(fe, SEC_TONE_ON);
0112 udelay(data ? 500 : 1000);
0113 flexcop_set_tone(fe, SEC_TONE_OFF);
0114 udelay(data ? 1000 : 500);
0115 }
0116
0117 static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
0118 {
0119 int i, par = 1, d;
0120 for (i = 7; i >= 0; i--) {
0121 d = (data >> i) & 1;
0122 par ^= d;
0123 flexcop_diseqc_send_bit(fe, d);
0124 }
0125 flexcop_diseqc_send_bit(fe, par);
0126 }
0127
0128 static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
0129 int len, u8 *msg, unsigned long burst)
0130 {
0131 int i;
0132
0133 flexcop_set_tone(fe, SEC_TONE_OFF);
0134 mdelay(16);
0135
0136 for (i = 0; i < len; i++)
0137 flexcop_diseqc_send_byte(fe,msg[i]);
0138 mdelay(16);
0139
0140 if (burst != -1) {
0141 if (burst)
0142 flexcop_diseqc_send_byte(fe, 0xff);
0143 else {
0144 flexcop_set_tone(fe, SEC_TONE_ON);
0145 mdelay(12);
0146 udelay(500);
0147 flexcop_set_tone(fe, SEC_TONE_OFF);
0148 }
0149 msleep(20);
0150 }
0151 return 0;
0152 }
0153
0154 static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
0155 struct dvb_diseqc_master_cmd *cmd)
0156 {
0157 return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
0158 }
0159
0160 static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
0161 enum fe_sec_mini_cmd minicmd)
0162 {
0163 return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
0164 }
0165
0166 static struct mt312_config skystar23_samsung_tbdu18132_config = {
0167 .demod_address = 0x0e,
0168 };
0169
0170 static int skystar2_rev23_attach(struct flexcop_device *fc,
0171 struct i2c_adapter *i2c)
0172 {
0173 struct dvb_frontend_ops *ops;
0174
0175 fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
0176 if (!fc->fe)
0177 return 0;
0178
0179 if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
0180 DVB_PLL_SAMSUNG_TBDU18132))
0181 return 0;
0182
0183 ops = &fc->fe->ops;
0184 ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
0185 ops->diseqc_send_burst = flexcop_diseqc_send_burst;
0186 ops->set_tone = flexcop_set_tone;
0187 ops->set_voltage = flexcop_set_voltage;
0188 fc->fe_sleep = ops->sleep;
0189 ops->sleep = flexcop_sleep;
0190 return 1;
0191 }
0192 #else
0193 #define skystar2_rev23_attach NULL
0194 #endif
0195
0196
0197 #if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
0198 static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
0199 u32 srate, u32 ratio)
0200 {
0201 u8 aclk = 0;
0202 u8 bclk = 0;
0203
0204 if (srate < 1500000) {
0205 aclk = 0xb7; bclk = 0x47;
0206 } else if (srate < 3000000) {
0207 aclk = 0xb7; bclk = 0x4b;
0208 } else if (srate < 7000000) {
0209 aclk = 0xb7; bclk = 0x4f;
0210 } else if (srate < 14000000) {
0211 aclk = 0xb7; bclk = 0x53;
0212 } else if (srate < 30000000) {
0213 aclk = 0xb6; bclk = 0x53;
0214 } else if (srate < 45000000) {
0215 aclk = 0xb4; bclk = 0x51;
0216 }
0217
0218 stv0299_writereg(fe, 0x13, aclk);
0219 stv0299_writereg(fe, 0x14, bclk);
0220 stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
0221 stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
0222 stv0299_writereg(fe, 0x21, ratio & 0xf0);
0223 return 0;
0224 }
0225
0226 static u8 samsung_tbmu24112_inittab[] = {
0227 0x01, 0x15,
0228 0x02, 0x30,
0229 0x03, 0x00,
0230 0x04, 0x7D,
0231 0x05, 0x35,
0232 0x06, 0x02,
0233 0x07, 0x00,
0234 0x08, 0xC3,
0235 0x0C, 0x00,
0236 0x0D, 0x81,
0237 0x0E, 0x23,
0238 0x0F, 0x12,
0239 0x10, 0x7E,
0240 0x11, 0x84,
0241 0x12, 0xB9,
0242 0x13, 0x88,
0243 0x14, 0x89,
0244 0x15, 0xC9,
0245 0x16, 0x00,
0246 0x17, 0x5C,
0247 0x18, 0x00,
0248 0x19, 0x00,
0249 0x1A, 0x00,
0250 0x1C, 0x00,
0251 0x1D, 0x00,
0252 0x1E, 0x00,
0253 0x1F, 0x3A,
0254 0x20, 0x2E,
0255 0x21, 0x80,
0256 0x22, 0xFF,
0257 0x23, 0xC1,
0258 0x28, 0x00,
0259 0x29, 0x1E,
0260 0x2A, 0x14,
0261 0x2B, 0x0F,
0262 0x2C, 0x09,
0263 0x2D, 0x05,
0264 0x31, 0x1F,
0265 0x32, 0x19,
0266 0x33, 0xFE,
0267 0x34, 0x93,
0268 0xff, 0xff,
0269 };
0270
0271 static struct stv0299_config samsung_tbmu24112_config = {
0272 .demod_address = 0x68,
0273 .inittab = samsung_tbmu24112_inittab,
0274 .mclk = 88000000UL,
0275 .invert = 0,
0276 .skip_reinit = 0,
0277 .lock_output = STV0299_LOCKOUTPUT_LK,
0278 .volt13_op0_op1 = STV0299_VOLT13_OP1,
0279 .min_delay_ms = 100,
0280 .set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
0281 };
0282
0283 static int skystar2_rev26_attach(struct flexcop_device *fc,
0284 struct i2c_adapter *i2c)
0285 {
0286 fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
0287 if (!fc->fe)
0288 return 0;
0289
0290 if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
0291 DVB_PLL_SAMSUNG_TBMU24112))
0292 return 0;
0293
0294 fc->fe->ops.set_voltage = flexcop_set_voltage;
0295 fc->fe_sleep = fc->fe->ops.sleep;
0296 fc->fe->ops.sleep = flexcop_sleep;
0297 return 1;
0298
0299 }
0300 #else
0301 #define skystar2_rev26_attach NULL
0302 #endif
0303
0304
0305 #if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
0306 static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
0307 .demod_address = 0x53,
0308 .invert = 1,
0309 .repeated_start_workaround = 1,
0310 .serial_mpeg = 1,
0311 };
0312
0313 static struct itd1000_config skystar2_rev2_7_itd1000_config = {
0314 .i2c_address = 0x61,
0315 };
0316
0317 static int skystar2_rev27_attach(struct flexcop_device *fc,
0318 struct i2c_adapter *i2c)
0319 {
0320 flexcop_ibi_value r108;
0321 struct i2c_adapter *i2c_tuner;
0322
0323
0324 fc->fc_i2c_adap[0].no_base_addr = 1;
0325 fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
0326 i2c);
0327 if (!fc->fe)
0328 goto fail;
0329
0330 i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
0331 if (!i2c_tuner)
0332 goto fail;
0333
0334 fc->fe_sleep = fc->fe->ops.sleep;
0335 fc->fe->ops.sleep = flexcop_sleep;
0336
0337
0338 fc->fc_i2c_adap[2].no_base_addr = 1;
0339 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
0340 0x08, 1, 1, false)) {
0341 err("ISL6421 could NOT be attached");
0342 goto fail_isl;
0343 }
0344 info("ISL6421 successfully attached");
0345
0346
0347 r108.raw = 0x00000506;
0348 fc->write_ibi_reg(fc, tw_sm_c_108, r108);
0349 if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
0350 &skystar2_rev2_7_itd1000_config)) {
0351 err("ITD1000 could NOT be attached");
0352
0353 goto fail_isl;
0354 }
0355 info("ITD1000 successfully attached");
0356
0357 return 1;
0358
0359 fail_isl:
0360 fc->fc_i2c_adap[2].no_base_addr = 0;
0361 fail:
0362
0363 fc->fc_i2c_adap[0].no_base_addr = 0;
0364 return 0;
0365 }
0366 #else
0367 #define skystar2_rev27_attach NULL
0368 #endif
0369
0370
0371 #if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
0372 static struct cx24123_config skystar2_rev2_8_cx24123_config = {
0373 .demod_address = 0x55,
0374 .dont_use_pll = 1,
0375 .agc_callback = cx24113_agc_callback,
0376 };
0377
0378 static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
0379 .i2c_addr = 0x54,
0380 .xtal_khz = 10111,
0381 };
0382
0383 static int skystar2_rev28_attach(struct flexcop_device *fc,
0384 struct i2c_adapter *i2c)
0385 {
0386 struct i2c_adapter *i2c_tuner;
0387
0388 fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
0389 i2c);
0390 if (!fc->fe)
0391 return 0;
0392
0393 i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
0394 if (!i2c_tuner)
0395 return 0;
0396
0397 if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
0398 i2c_tuner)) {
0399 err("CX24113 could NOT be attached");
0400 return 0;
0401 }
0402 info("CX24113 successfully attached");
0403
0404 fc->fc_i2c_adap[2].no_base_addr = 1;
0405 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
0406 0x08, 0, 0, false)) {
0407 err("ISL6421 could NOT be attached");
0408 fc->fc_i2c_adap[2].no_base_addr = 0;
0409 return 0;
0410 }
0411 info("ISL6421 successfully attached");
0412
0413
0414 return 1;
0415 }
0416 #else
0417 #define skystar2_rev28_attach NULL
0418 #endif
0419
0420
0421 #if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
0422 static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
0423 {
0424 static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
0425 static u8 mt352_reset[] = { 0x50, 0x80 };
0426 static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
0427 static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
0428 static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
0429
0430 mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
0431 udelay(2000);
0432 mt352_write(fe, mt352_reset, sizeof(mt352_reset));
0433 mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
0434 mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
0435 mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
0436 return 0;
0437 }
0438
0439 static struct mt352_config samsung_tdtc9251dh0_config = {
0440 .demod_address = 0x0f,
0441 .demod_init = samsung_tdtc9251dh0_demod_init,
0442 };
0443
0444 static int airstar_dvbt_attach(struct flexcop_device *fc,
0445 struct i2c_adapter *i2c)
0446 {
0447 fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
0448 if (!fc->fe)
0449 return 0;
0450
0451 return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
0452 DVB_PLL_SAMSUNG_TDTC9251DH0);
0453 }
0454 #else
0455 #define airstar_dvbt_attach NULL
0456 #endif
0457
0458
0459 #if FE_SUPPORTED(BCM3510)
0460 static struct bcm3510_config air2pc_atsc_first_gen_config = {
0461 .demod_address = 0x0f,
0462 .request_firmware = flexcop_fe_request_firmware,
0463 };
0464
0465 static int airstar_atsc1_attach(struct flexcop_device *fc,
0466 struct i2c_adapter *i2c)
0467 {
0468 fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
0469 return fc->fe != NULL;
0470 }
0471 #else
0472 #define airstar_atsc1_attach NULL
0473 #endif
0474
0475
0476 #if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
0477 static const struct nxt200x_config samsung_tbmv_config = {
0478 .demod_address = 0x0a,
0479 };
0480
0481 static int airstar_atsc2_attach(struct flexcop_device *fc,
0482 struct i2c_adapter *i2c)
0483 {
0484 fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
0485 if (!fc->fe)
0486 return 0;
0487
0488 return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
0489 DVB_PLL_SAMSUNG_TBMV);
0490 }
0491 #else
0492 #define airstar_atsc2_attach NULL
0493 #endif
0494
0495
0496 #if FE_SUPPORTED(LGDT330X)
0497 static struct lgdt330x_config air2pc_atsc_hd5000_config = {
0498 .demod_chip = LGDT3303,
0499 .serial_mpeg = 0x04,
0500 .clock_polarity_flip = 1,
0501 };
0502
0503 static int airstar_atsc3_attach(struct flexcop_device *fc,
0504 struct i2c_adapter *i2c)
0505 {
0506 fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config,
0507 0x59, i2c);
0508 if (!fc->fe)
0509 return 0;
0510
0511 return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
0512 TUNER_LG_TDVS_H06XF);
0513 }
0514 #else
0515 #define airstar_atsc3_attach NULL
0516 #endif
0517
0518
0519 #if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
0520 static u8 alps_tdee4_stv0297_inittab[] = {
0521 0x80, 0x01,
0522 0x80, 0x00,
0523 0x81, 0x01,
0524 0x81, 0x00,
0525 0x00, 0x48,
0526 0x01, 0x58,
0527 0x03, 0x00,
0528 0x04, 0x00,
0529 0x07, 0x00,
0530 0x08, 0x00,
0531 0x30, 0xff,
0532 0x31, 0x9d,
0533 0x32, 0xff,
0534 0x33, 0x00,
0535 0x34, 0x29,
0536 0x35, 0x55,
0537 0x36, 0x80,
0538 0x37, 0x6e,
0539 0x38, 0x9c,
0540 0x40, 0x1a,
0541 0x41, 0xfe,
0542 0x42, 0x33,
0543 0x43, 0x00,
0544 0x44, 0xff,
0545 0x45, 0x00,
0546 0x46, 0x00,
0547 0x49, 0x04,
0548 0x4a, 0x51,
0549 0x4b, 0xf8,
0550 0x52, 0x30,
0551 0x53, 0x06,
0552 0x59, 0x06,
0553 0x5a, 0x5e,
0554 0x5b, 0x04,
0555 0x61, 0x49,
0556 0x62, 0x0a,
0557 0x70, 0xff,
0558 0x71, 0x04,
0559 0x72, 0x00,
0560 0x73, 0x00,
0561 0x74, 0x0c,
0562 0x80, 0x20,
0563 0x81, 0x00,
0564 0x82, 0x30,
0565 0x83, 0x00,
0566 0x84, 0x04,
0567 0x85, 0x22,
0568 0x86, 0x08,
0569 0x87, 0x1b,
0570 0x88, 0x00,
0571 0x89, 0x00,
0572 0x90, 0x00,
0573 0x91, 0x04,
0574 0xa0, 0x86,
0575 0xa1, 0x00,
0576 0xa2, 0x00,
0577 0xb0, 0x91,
0578 0xb1, 0x0b,
0579 0xc0, 0x5b,
0580 0xc1, 0x10,
0581 0xc2, 0x12,
0582 0xd0, 0x02,
0583 0xd1, 0x00,
0584 0xd2, 0x00,
0585 0xd3, 0x00,
0586 0xd4, 0x02,
0587 0xd5, 0x00,
0588 0xde, 0x00,
0589 0xdf, 0x01,
0590 0xff, 0xff,
0591 };
0592
0593 static struct stv0297_config alps_tdee4_stv0297_config = {
0594 .demod_address = 0x1c,
0595 .inittab = alps_tdee4_stv0297_inittab,
0596 };
0597
0598 static int cablestar2_attach(struct flexcop_device *fc,
0599 struct i2c_adapter *i2c)
0600 {
0601 fc->fc_i2c_adap[0].no_base_addr = 1;
0602 fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
0603 if (!fc->fe)
0604 goto fail;
0605
0606
0607
0608 if (fc->fe->ops.i2c_gate_ctrl)
0609 fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
0610 fc->fe->ops.i2c_gate_ctrl = NULL;
0611
0612 if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
0613 &fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
0614 goto fail;
0615
0616 return 1;
0617
0618 fail:
0619
0620 fc->fc_i2c_adap[0].no_base_addr = 0;
0621 return 0;
0622 }
0623 #else
0624 #define cablestar2_attach NULL
0625 #endif
0626
0627
0628 #if FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421)
0629 static const struct cx24120_config skystar2_rev3_3_cx24120_config = {
0630 .i2c_addr = 0x55,
0631 .xtal_khz = 10111,
0632 .initial_mpeg_config = { 0xa1, 0x76, 0x07 },
0633 .request_firmware = flexcop_fe_request_firmware,
0634 .i2c_wr_max = 4,
0635 };
0636
0637 static int skystarS2_rev33_attach(struct flexcop_device *fc,
0638 struct i2c_adapter *i2c)
0639 {
0640 fc->fe = dvb_attach(cx24120_attach,
0641 &skystar2_rev3_3_cx24120_config, i2c);
0642 if (!fc->fe)
0643 return 0;
0644
0645 fc->dev_type = FC_SKYS2_REV33;
0646 fc->fc_i2c_adap[2].no_base_addr = 1;
0647 if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
0648 0x08, 0, 0, false)) {
0649 err("ISL6421 could NOT be attached!");
0650 fc->fc_i2c_adap[2].no_base_addr = 0;
0651 return 0;
0652 }
0653 info("ISL6421 successfully attached.");
0654
0655 if (fc->has_32_hw_pid_filter)
0656 fc->skip_6_hw_pid_filter = 1;
0657
0658 return 1;
0659 }
0660 #else
0661 #define skystarS2_rev33_attach NULL
0662 #endif
0663
0664 static struct {
0665 flexcop_device_type_t type;
0666 int (*attach)(struct flexcop_device *, struct i2c_adapter *);
0667 } flexcop_frontends[] = {
0668 { FC_SKY_REV27, skystar2_rev27_attach },
0669 { FC_SKY_REV28, skystar2_rev28_attach },
0670 { FC_SKY_REV26, skystar2_rev26_attach },
0671 { FC_AIR_DVBT, airstar_dvbt_attach },
0672 { FC_AIR_ATSC2, airstar_atsc2_attach },
0673 { FC_AIR_ATSC3, airstar_atsc3_attach },
0674 { FC_AIR_ATSC1, airstar_atsc1_attach },
0675 { FC_CABLE, cablestar2_attach },
0676 { FC_SKY_REV23, skystar2_rev23_attach },
0677 { FC_SKYS2_REV33, skystarS2_rev33_attach },
0678 };
0679
0680
0681 int flexcop_frontend_init(struct flexcop_device *fc)
0682 {
0683 int i;
0684 for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
0685 if (!flexcop_frontends[i].attach)
0686 continue;
0687
0688
0689 fc->dev_type = flexcop_frontends[i].type;
0690 if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
0691 goto fe_found;
0692
0693 if (fc->fe) {
0694 dvb_frontend_detach(fc->fe);
0695 fc->fe = NULL;
0696 }
0697 }
0698 fc->dev_type = FC_UNK;
0699 err("no frontend driver found for this B2C2/FlexCop adapter");
0700 return -ENODEV;
0701
0702 fe_found:
0703 info("found '%s' .", fc->fe->ops.info.name);
0704 if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
0705 err("frontend registration failed!");
0706 dvb_frontend_detach(fc->fe);
0707 fc->fe = NULL;
0708 return -EINVAL;
0709 }
0710 fc->init_state |= FC_STATE_FE_INIT;
0711 return 0;
0712 }
0713
0714 void flexcop_frontend_exit(struct flexcop_device *fc)
0715 {
0716 if (fc->init_state & FC_STATE_FE_INIT) {
0717 dvb_unregister_frontend(fc->fe);
0718 dvb_frontend_detach(fc->fe);
0719 }
0720 fc->init_state &= ~FC_STATE_FE_INIT;
0721 }