- Add support for the Hauppauge HVR1100 and HVR1100-LP products.
- Add i2c_gate_ctrl callback function to dvb_frontend_ops struct.
Signed-off-by: Steven Toth <stoth@hauppauge.com>
Signed-off-by: Michael Krufky <mkrufky@m1k.net>
Signed-off-by: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
  37 -> Hauppauge Nova-S-Plus DVB-S                         [0070:9201,0070:9202]
  38 -> Hauppauge Nova-SE2 DVB-S                            [0070:9200]
  39 -> KWorld DVB-S 100                                    [17de:08b2]
+ 40 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid                [0070:9400,0070:9402]
+ 41 -> Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)  [0070:9800,0070:9802]
 
        int (*set_voltage)(struct dvb_frontend* fe, fe_sec_voltage_t voltage);
        int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, int arg);
        int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned int cmd);
+       int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable);
 };
 
 #define MAX_EVENT 8
 
        return 0;
 }
 
+static int cx22702_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+       struct cx22702_state* state = fe->demodulator_priv;
+       dprintk ("%s(%d)\n", __FUNCTION__, enable);
+       if (enable)
+               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) & 0xfe);
+       else
+               return cx22702_writereg (state, 0x0D, cx22702_readreg(state, 0x0D) | 1);
+}
+
 /* Talk to the demod, set the FEC, GUARD, QAM settings etc */
 static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
 {
        struct cx22702_state* state = fe->demodulator_priv;
 
        /* set PLL */
-       cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) &0xfe);
+       cx22702_i2c_gate_ctrl(fe, 1);
        if (state->config->pll_set) {
                state->config->pll_set(fe, p);
        } else if (state->config->pll_desc) {
        } else {
                BUG();
        }
-       cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
+       cx22702_i2c_gate_ctrl(fe, 0);
 
        /* set inversion */
        cx22702_set_inversion (state, p->inversion);
        cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02);
 
        /* init PLL */
-       if (state->config->pll_init) {
-               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) & 0xfe);
+       if (state->config->pll_init)
                state->config->pll_init(fe);
-               cx22702_writereg (state, 0x0D, cx22702_readreg(state,0x0D) | 1);
-       }
+
+       cx22702_i2c_gate_ctrl(fe, 0);
 
        return 0;
 }
        .read_signal_strength = cx22702_read_signal_strength,
        .read_snr = cx22702_read_snr,
        .read_ucblocks = cx22702_read_ucblocks,
+       .i2c_gate_ctrl = cx22702_i2c_gate_ctrl,
 };
 
 module_param(debug, int, 0644);
 
                .radio_type     = UNSET,
                .tuner_addr     = ADDR_UNSET,
                .radio_addr     = ADDR_UNSET,
-               /* fixme: add the analog gpio stuff here */
                .input          = {{
                        .type   = CX88_VMUX_DVB,
                        .vmux   = 0,
                }},
                .dvb            = 1,
        },
+       [CX88_BOARD_HAUPPAUGE_HVR1100] = {
+               .name           = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+               },{
+                       .type   = CX88_VMUX_SVIDEO,
+                       .vmux   = 2,
+               }},
+               /* fixme: Add radio support */
+               .dvb            = 1,
+       },
+       [CX88_BOARD_HAUPPAUGE_HVR1100LP] = {
+               .name           = "Hauppauge WinTV-HVR1100 DVB-T/Hybrid (Low Profile)",
+               .tuner_type     = TUNER_PHILIPS_FMD1216ME_MK3,
+               .radio_type     = UNSET,
+               .tuner_addr     = ADDR_UNSET,
+               .radio_addr     = ADDR_UNSET,
+               .tda9887_conf   = TDA9887_PRESENT,
+               .input          = {{
+                       .type   = CX88_VMUX_TELEVISION,
+                       .vmux   = 0,
+               },{
+                       .type   = CX88_VMUX_COMPOSITE1,
+                       .vmux   = 1,
+               }},
+               /* fixme: Add radio support */
+               .dvb            = 1,
+       },
 };
 const unsigned int cx88_bcount = ARRAY_SIZE(cx88_boards);
 
                .subvendor = 0x17de,
                .subdevice = 0x08b2,
                .card      = CX88_BOARD_KWORLD_DVBS_100,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9400,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9402,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9800,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
+       },{
+               .subvendor = 0x0070,
+               .subdevice = 0x9802,
+               .card      = CX88_BOARD_HAUPPAUGE_HVR1100LP,
        },
 };
 const unsigned int cx88_idcount = ARRAY_SIZE(cx88_subids);
               core->name, core->tuner_type, eeprom_data[0]);
 }
 
-
-/* ----------------------------------------------------------------------- */
-
 static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
 {
        struct tveeprom tv;
        case 90500: /* Nova-T-PCI (oem) */
        case 90501: /* Nova-T-PCI (oem/IR) */
        case 92000: /* Nova-SE2 (OEM, No Video or IR) */
-
+       case 94009: /* WinTV-HVR1100 (Video and IR Retail) */
+       case 94501: /* WinTV-HVR1100 (Video and IR OEM) */
+       case 98559: /* WinTV-HVR1100LP (Video no IR, Retail - Low Profile) */
                /* known */
                break;
        default:
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
+       case CX88_BOARD_HAUPPAUGE_HVR1100:
+       case CX88_BOARD_HAUPPAUGE_HVR1100LP:
                if (0 == core->i2c_rc)
                        hauppauge_eeprom(core,eeprom);
                break;
 
        .pll_address   = 0x61,
        .pll_desc      = &dvb_pll_thomson_dtt759x,
 };
+static struct cx22702_config hauppauge_hvr1100_config = {
+       .demod_address = 0x63,
+       .output_mode   = CX22702_SERIAL_OUTPUT,
+       .pll_address   = 0x61,
+       .pll_desc      = &dvb_pll_fmd1216me,
+};
 #endif
 
 #ifdef HAVE_OR51132
                dev->dvb.frontend = cx22702_attach(&connexant_refboard_config,
                                                   &dev->core->i2c_adap);
                break;
+       case CX88_BOARD_HAUPPAUGE_HVR1100:
+       case CX88_BOARD_HAUPPAUGE_HVR1100LP:
+               dev->dvb.frontend = cx22702_attach(&hauppauge_hvr1100_config,
+                                                  &dev->core->i2c_adap);
+               break;
 #endif
 #ifdef HAVE_MT352
        case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
        err = dvb_register(dev);
        if (0 != err)
                goto fail_fini;
+
+       /* Maintain a reference to cx88-video can query the 8802 device. */
+       core->dvbdev = dev;
        return 0;
 
  fail_fini:
 {
        struct cx8802_dev *dev = pci_get_drvdata(pci_dev);
 
+       /* Destroy any 8802 reference. */
+       dev->core->dvbdev = NULL;
+
        /* dvb */
        videobuf_dvb_unregister(&dev->dvb);
 
 
 {
        if (0 != core->i2c_rc)
                return;
-       i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+       if (core->dvbdev == NULL) {
+               i2c_clients_command(&core->i2c_adap, cmd, arg);
+       } else {
+
+               if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+                       core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 1);
+
+               i2c_clients_command(&core->i2c_adap, cmd, arg);
+
+               if (core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl)
+                       core->dvbdev->dvb.frontend->ops->i2c_gate_ctrl(core->dvbdev->dvb.frontend, 0);
+       }
+
 }
 
 static struct i2c_algo_bit_data cx8800_i2c_algo_template = {
 
        case CX88_BOARD_HAUPPAUGE_DVB_T1:
        case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
        case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
+       case CX88_BOARD_HAUPPAUGE_HVR1100:
                ir_codes = ir_codes_hauppauge_new;
                ir_type = IR_TYPE_RC5;
                ir->sampling = 1;
 
 #define CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1  37
 #define CX88_BOARD_HAUPPAUGE_NOVASE2_S1    38
 #define CX88_BOARD_KWORLD_DVBS_100         39
+#define CX88_BOARD_HAUPPAUGE_HVR1100       40
+#define CX88_BOARD_HAUPPAUGE_HVR1100LP     41
 
 enum cx88_itype {
        CX88_VMUX_COMPOSITE1 = 1,
 
        /* various v4l controls */
        u32                        freq;
+
+       /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
+       struct cx8802_dev          *dvbdev;
 };
 
 struct cx8800_dev;