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