linux/drivers/media/common/b2c2/flexcop-fe-tuner.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
   4 * flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
   5 * see flexcop.c for copyright information
   6 */
   7#include <media/tuner.h>
   8#include "flexcop.h"
   9#include "mt312.h"
  10#include "stv0299.h"
  11#include "s5h1420.h"
  12#include "itd1000.h"
  13#include "cx24113.h"
  14#include "cx24123.h"
  15#include "isl6421.h"
  16#include "cx24120.h"
  17#include "mt352.h"
  18#include "bcm3510.h"
  19#include "nxt200x.h"
  20#include "dvb-pll.h"
  21#include "lgdt330x.h"
  22#include "tuner-simple.h"
  23#include "stv0297.h"
  24
  25
  26/* Can we use the specified front-end?  Remember that if we are compiled
  27 * into the kernel we can't call code that's in modules.  */
  28#define FE_SUPPORTED(fe) IS_REACHABLE(CONFIG_DVB_ ## fe)
  29
  30#if FE_SUPPORTED(BCM3510) || (FE_SUPPORTED(CX24120) && FE_SUPPORTED(ISL6421))
  31static 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)) && FE_SUPPORTED(PLL)
  42static 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)
  71static int __maybe_unused 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)
  82static 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
 109static 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
 117static 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
 128static 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
 154static 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
 160static 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
 166static struct mt312_config skystar23_samsung_tbdu18132_config = {
 167        .demod_address = 0x0e,
 168};
 169
 170static 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)
 198static 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
 226static 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
 271static 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
 283static 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)
 306static 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
 313static struct itd1000_config skystar2_rev2_7_itd1000_config = {
 314        .i2c_address = 0x61,
 315};
 316
 317static 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
 359fail_isl:
 360        fc->fc_i2c_adap[2].no_base_addr = 0;
 361fail:
 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)
 372static 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
 378static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
 379        .i2c_addr = 0x54,
 380        .xtal_khz = 10111,
 381};
 382
 383static 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)
 422static 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
 439static struct mt352_config samsung_tdtc9251dh0_config = {
 440        .demod_address = 0x0f,
 441        .demod_init    = samsung_tdtc9251dh0_demod_init,
 442};
 443
 444static 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)
 460static struct bcm3510_config air2pc_atsc_first_gen_config = {
 461        .demod_address    = 0x0f,
 462        .request_firmware = flexcop_fe_request_firmware,
 463};
 464
 465static 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)
 477static const struct nxt200x_config samsung_tbmv_config = {
 478        .demod_address = 0x0a,
 479};
 480
 481static 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)
 497static struct lgdt330x_config air2pc_atsc_hd5000_config = {
 498        .demod_chip          = LGDT3303,
 499        .serial_mpeg         = 0x04,
 500        .clock_polarity_flip = 1,
 501};
 502
 503static 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,
 507                            0x59, 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)
 520static 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
 593static struct stv0297_config alps_tdee4_stv0297_config = {
 594        .demod_address = 0x1c,
 595        .inittab = alps_tdee4_stv0297_inittab,
 596};
 597
 598static 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
 618fail:
 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)
 629static 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
 637static 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
 664static 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 */
 681int 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
 702fe_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
 714void 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}
 722