[media] DiB0700: add support for several board-layouts
authorOlivier Grenie <olivier.grenie@dibcom.fr>
Tue, 4 Jan 2011 08:42:19 +0000 (05:42 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 21 Mar 2011 23:31:43 +0000 (20:31 -0300)
This patchs adds support for DiBcom's NIM8096MD, NIM9090M, NIM9090MD,
NIM7090, TFE7090PVR (no diversity) reference designs.

Signed-off-by: Olivier Grenie <olivier.grenie@dibcom.fr>
Signed-off-by: Patrick Boettcher <patrick.boettcher@dibcom.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-usb/dib0700_core.c
drivers/media/dvb/dvb-usb/dib0700_devices.c
drivers/media/dvb/dvb-usb/dvb-usb-ids.h

index ebda77d..9ab5713 100644 (file)
@@ -186,7 +186,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                                 msg[i].len,
                                                 USB_CTRL_GET_TIMEOUT);
                        if (result < 0) {
-                               err("i2c read error (status = %d)\n", result);
+                               deb_info("i2c read error (status = %d)\n", result);
                                break;
                        }
 
@@ -215,7 +215,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
                                                 0, 0, buf, msg[i].len + 4,
                                                 USB_CTRL_GET_TIMEOUT);
                        if (result < 0) {
-                               err("i2c write error (status = %d)\n", result);
+                               deb_info("i2c write error (status = %d)\n", result);
                                break;
                        }
                }
index 193cdb7..2b91903 100644 (file)
@@ -12,6 +12,7 @@
 #include "dib7000m.h"
 #include "dib7000p.h"
 #include "dib8000.h"
+#include "dib9000.h"
 #include "mt2060.h"
 #include "mt2266.h"
 #include "tuner-xc2028.h"
@@ -29,6 +30,7 @@ MODULE_PARM_DESC(force_lna_activation, "force the activation of Low-Noise-Amplif
 
 struct dib0700_adapter_state {
        int (*set_param_save) (struct dvb_frontend *, struct dvb_frontend_parameters *);
+       const struct firmware *frontend_firmware;
 };
 
 /* Hauppauge Nova-T 500 (aka Bristol)
@@ -1243,13 +1245,13 @@ static int dib807x_tuner_attach(struct dvb_usb_adapter *adap)
 static int stk80xx_pid_filter(struct dvb_usb_adapter *adapter, int index,
        u16 pid, int onoff)
 {
-    return dib8000_pid_filter(adapter->fe, index, pid, onoff);
+       return dib8000_pid_filter(adapter->fe, index, pid, onoff);
 }
 
 static int stk80xx_pid_filter_ctrl(struct dvb_usb_adapter *adapter,
-       int onoff)
+               int onoff)
 {
-    return dib8000_pid_filter_ctrl(adapter->fe, onoff);
+       return dib8000_pid_filter_ctrl(adapter->fe, onoff);
 }
 
 /* STK807x */
@@ -1321,11 +1323,11 @@ static int stk807xpvr_frontend_attach1(struct dvb_usb_adapter *adap)
 
 /* STK8096GP */
 struct dibx000_agc_config dib8090_agc_config[2] = {
-    {
+       {
        BAND_UHF | BAND_VHF | BAND_LBAND | BAND_SBAND,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
-     * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-     * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+        * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+        * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
        (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
        | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
 
@@ -1362,12 +1364,12 @@ struct dibx000_agc_config dib8090_agc_config[2] = {
        51,
 
        0,
-    },
-    {
+       },
+       {
        BAND_CBAND,
        /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1,
-     * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
-     * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+        * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+        * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
        (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8)
        | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0),
 
@@ -1404,159 +1406,1098 @@ struct dibx000_agc_config dib8090_agc_config[2] = {
        51,
 
        0,
-    }
+       }
 };
 
 static struct dibx000_bandwidth_config dib8090_pll_config_12mhz = {
-    54000, 13500,
-    1, 18, 3, 1, 0,
-    0, 0, 1, 1, 2,
-    (3 << 14) | (1 << 12) | (599 << 0),
-    (0 << 25) | 0,
-    20199727,
-    12000000,
+       54000, 13500,
+       1, 18, 3, 1, 0,
+       0, 0, 1, 1, 2,
+       (3 << 14) | (1 << 12) | (599 << 0),
+       (0 << 25) | 0,
+       20199727,
+       12000000,
 };
 
 static int dib8090_get_adc_power(struct dvb_frontend *fe)
 {
-    return dib8000_get_adc_power(fe, 1);
+       return dib8000_get_adc_power(fe, 1);
+}
+
+static struct dib8000_config dib809x_dib8000_config[2] = {
+       {
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc_config_count = 2,
+       .agc = dib8090_agc_config,
+       .agc_control = dib0090_dcc_freq,
+       .pll = &dib8090_pll_config_12mhz,
+       .tuner_is_baseband = 1,
+
+       .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+       .hostbus_diversity = 1,
+       .div_cfg = 0x31,
+       .output_mode = OUTMODE_MPEG2_FIFO,
+       .drives = 0x2d98,
+       .diversity_delay = 48,
+       .refclksel = 3,
+       },{
+       .output_mpeg2_in_188_bytes = 1,
+
+       .agc_config_count = 2,
+       .agc = dib8090_agc_config,
+       .agc_control = dib0090_dcc_freq,
+       .pll = &dib8090_pll_config_12mhz,
+       .tuner_is_baseband = 1,
+
+       .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
+
+       .hostbus_diversity = 1,
+       .div_cfg = 0x31,
+       .output_mode = OUTMODE_DIVERSITY,
+       .drives = 0x2d08,
+       .diversity_delay = 1,
+       .refclksel = 3,
+       }
+};
+
+static struct dib0090_wbd_slope dib8090_wbd_table[] = {
+       /* max freq ; cold slope ; cold offset ; warm slope ; warm offset ; wbd gain */
+       { 120,     0, 500,  0,   500, 4 }, /* CBAND */
+       { 170,     0, 450,  0,   450, 4 }, /* CBAND */
+       { 380,    48, 373, 28,   259, 6 }, /* VHF */
+       { 860,    34, 700, 36,   616, 6 }, /* high UHF */
+       { 0xFFFF, 34, 700, 36,   616, 6 }, /* default */
+};
+
+static struct dib0090_config dib809x_dib0090_config = {
+       .io.pll_bypass = 1,
+       .io.pll_range = 1,
+       .io.pll_prediv = 1,
+       .io.pll_loopdiv = 20,
+       .io.adc_clock_ratio = 8,
+       .io.pll_int_loop_filt = 0,
+       .io.clock_khz = 12000,
+       .reset = dib80xx_tuner_reset,
+       .sleep = dib80xx_tuner_sleep,
+       .clkouttobamse = 1,
+       .analog_output = 1,
+       .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
+       .use_pwm_agc = 1,
+       .clkoutdrive = 1,
+       .get_adc_power = dib8090_get_adc_power,
+       .freq_offset_khz_uhf = -63,
+       .freq_offset_khz_vhf = -143,
+       .wbd = dib8090_wbd_table,
+       .fref_clock_ratio = 6,
+};
+
+static int dib8096_set_param_override(struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *fep)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dib0700_adapter_state *state = adap->priv;
+       u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
+       u16 target;
+       int ret = 0;
+       enum frontend_tune_state tune_state = CT_SHUTDOWN;
+       u16 ltgain, rf_gain_limit;
+
+       ret = state->set_param_save(fe, fep);
+       if (ret < 0)
+               return ret;
+
+       target = (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2;
+       dib8000_set_wbd_ref(fe, target);
+
+
+       if (band == BAND_CBAND) {
+       deb_info("tuning in CBAND - soft-AGC startup\n");
+       /* TODO specific wbd target for dib0090 - needed for startup ? */
+       dib0090_set_tune_state(fe, CT_AGC_START);
+       do {
+               ret = dib0090_gain_control(fe);
+               msleep(ret);
+               tune_state = dib0090_get_tune_state(fe);
+               if (tune_state == CT_AGC_STEP_0)
+                       dib8000_set_gpio(fe, 6, 0, 1);
+               else if (tune_state == CT_AGC_STEP_1) {
+                       dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
+                       if (rf_gain_limit == 0)
+                               dib8000_set_gpio(fe, 6, 0, 0);
+               }
+       } while (tune_state < CT_AGC_STOP);
+       dib0090_pwm_gain_reset(fe);
+       dib8000_pwm_agc_reset(fe);
+       dib8000_set_tune_state(fe, CT_DEMOD_START);
+       } else {
+       deb_info("not tuning in CBAND - standard AGC startup\n");
+       dib0090_pwm_gain_reset(fe);
+       }
+
+       return 0;
+}
+
+static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+               return -ENODEV;
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+       return 0;
+}
+
+static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
+
+       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+
+       return adap->fe == NULL ?  -ENODEV : 0;
+}
+
+static int nim8096md_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c;
+       struct dvb_frontend *fe_slave  = dib8000_get_slave_frontend(adap->fe, 1);
+
+       if (fe_slave) {
+               tun_i2c = dib8000_get_i2c_master(fe_slave, DIBX000_I2C_INTERFACE_TUNER, 1);
+               if (dvb_attach(dib0090_register, fe_slave, tun_i2c, &dib809x_dib0090_config) == NULL)
+                       return -ENODEV;
+               fe_slave->dvb = adap->fe->dvb;
+               fe_slave->ops.tuner_ops.set_params = dib8096_set_param_override;
+       }
+       tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
+               return -ENODEV;
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
+
+       return 0;
+}
+
+static int nim8096md_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dvb_frontend *fe_slave;
+
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(1000);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 2, 18, 0x80);
+
+       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config[0]);
+       if (adap->fe == NULL)
+               return -ENODEV;
+
+       fe_slave = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x82, &dib809x_dib8000_config[1]);
+       dib8000_set_slave_frontend(adap->fe, fe_slave);
+
+       return fe_slave == NULL ?  -ENODEV : 0;
+}
+
+/* STK9090M */
+static int dib90x0_pid_filter(struct dvb_usb_adapter *adapter, int index, u16 pid, int onoff)
+{
+       return dib9000_fw_pid_filter(adapter->fe, index, pid, onoff);
+}
+
+static int dib90x0_pid_filter_ctrl(struct dvb_usb_adapter *adapter, int onoff)
+{
+       return dib9000_fw_pid_filter_ctrl(adapter->fe, onoff);
+}
+
+static int dib90x0_tuner_reset(struct dvb_frontend *fe, int onoff)
+{
+       return dib9000_set_gpio(fe, 5, 0, !onoff);
+}
+
+static int dib90x0_tuner_sleep(struct dvb_frontend *fe, int onoff)
+{
+       return dib9000_set_gpio(fe, 0, 0, onoff);
+}
+
+static int dib01x0_pmu_update(struct i2c_adapter *i2c, u16 *data, u8 len)
+{
+       u8 wb[4] = { 0xc >> 8, 0xc & 0xff, 0, 0 };
+       u8 rb[2];
+       struct i2c_msg msg[2] = {
+               {.addr = 0x1e >> 1,.flags = 0,.buf = wb,.len = 2},
+               {.addr = 0x1e >> 1,.flags = I2C_M_RD,.buf = rb,.len = 2},
+       };
+       u8 index_data;
+
+       dibx000_i2c_set_speed(i2c, 250);
+
+       if (i2c_transfer(i2c, msg, 2) != 2)
+               return -EIO;
+
+       switch (rb[0] << 8 | rb[1]) {
+               case 0:
+                       deb_info("Found DiB0170 rev1: This version of DiB0170 is not supported any longer.\n");
+                       return -EIO;
+               case 1:
+                       deb_info("Found DiB0170 rev2");
+                       break;
+               case 2:
+                       deb_info("Found DiB0190 rev2");
+                       break;
+               default:
+                       deb_info("DiB01x0 not found");
+                       return -EIO;
+               }
+
+       for (index_data = 0; index_data < len; index_data += 2) {
+               wb[2] = (data[index_data + 1] >> 8) & 0xff;
+               wb[3] = (data[index_data + 1]) & 0xff;
+
+               if (data[index_data] == 0) {
+                       wb[0] = (data[index_data] >> 8) & 0xff;
+                       wb[1] = (data[index_data]) & 0xff;
+                       msg[0].len = 2;
+                       if (i2c_transfer(i2c, msg, 2) != 2)
+                               return -EIO;
+                       wb[2] |= rb[0];
+                       wb[3] |= rb[1] & ~(3 << 4);
+               }
+
+               wb[0] = (data[index_data  ] >> 8)&0xff;
+               wb[1] = (data[index_data  ]     )&0xff;
+               msg[0].len = 4;
+               if (i2c_transfer(i2c, &msg[0], 1) != 1)
+                       return -EIO;
+       }
+       return 0;
+}
+
+static struct dib9000_config stk9090m_config = {
+       .output_mpeg2_in_188_bytes = 1,
+       .output_mode = OUTMODE_MPEG2_FIFO,
+       .vcxo_timer = 279620,
+       .timing_frequency = 20452225,
+       .demod_clock_khz = 60000,
+       .xtal_clock_khz = 30000,
+       .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+       .subband = {
+               2,
+               {
+                       { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0008 } }, /* GPIO 3 to 1 for VHF */
+                       { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0008, 0x0000, 0x0000 } }, /* GPIO 3 to 0 for UHF */
+                       { 0 },
+               },
+       },
+       .gpio_function = {
+               { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
+               { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
+       },
+};
+
+static struct dib9000_config nim9090md_config[2] = {
+       {
+               .output_mpeg2_in_188_bytes = 1,
+               .output_mode = OUTMODE_MPEG2_FIFO,
+               .vcxo_timer = 279620,
+               .timing_frequency = 20452225,
+               .demod_clock_khz = 60000,
+               .xtal_clock_khz = 30000,
+               .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+       }, {
+               .output_mpeg2_in_188_bytes = 1,
+               .output_mode = OUTMODE_DIVERSITY,
+               .vcxo_timer = 279620,
+               .timing_frequency = 20452225,
+               .demod_clock_khz = 60000,
+               .xtal_clock_khz = 30000,
+               .if_drives = (0 << 15) | (1 << 13) | (0 << 12) | (3 << 10) | (0 << 9) | (1 << 7) | (0 << 6) | (0 << 4) | (1 << 3) | (1 << 1) | (0),
+               .subband = {
+                       2,
+                       {
+                               { 240, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0006 } }, /* GPIO 1 and 2 to 1 for VHF */
+                               { 890, { BOARD_GPIO_COMPONENT_DEMOD, BOARD_GPIO_FUNCTION_SUBBAND_GPIO, 0x0006, 0x0000, 0x0000 } }, /* GPIO 1 and 2 to 0 for UHF */
+                               { 0 },
+                       },
+               },
+               .gpio_function = {
+                       { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_ON, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = (0x10 & ~0x1) | 0x20 },
+                       { .component = BOARD_GPIO_COMPONENT_DEMOD, .function = BOARD_GPIO_FUNCTION_COMPONENT_OFF, .mask = 0x10 | 0x21, .direction = 0 & ~0x21, .value = 0 | 0x21 },
+               },
+       }
+};
+
+static struct dib0090_config dib9090_dib0090_config = {
+       .io.pll_bypass = 0,
+       .io.pll_range = 1,
+       .io.pll_prediv = 1,
+       .io.pll_loopdiv = 8,
+       .io.adc_clock_ratio = 8,
+       .io.pll_int_loop_filt = 0,
+       .io.clock_khz = 30000,
+       .reset = dib90x0_tuner_reset,
+       .sleep = dib90x0_tuner_sleep,
+       .clkouttobamse = 0,
+       .analog_output = 0,
+       .use_pwm_agc = 0,
+       .clkoutdrive = 0,
+       .freq_offset_khz_uhf = 0,
+       .freq_offset_khz_vhf = 0,
+};
+
+static struct dib0090_config nim9090md_dib0090_config[2] = {
+       {
+               .io.pll_bypass = 0,
+               .io.pll_range = 1,
+               .io.pll_prediv = 1,
+               .io.pll_loopdiv = 8,
+               .io.adc_clock_ratio = 8,
+               .io.pll_int_loop_filt = 0,
+               .io.clock_khz = 30000,
+               .reset = dib90x0_tuner_reset,
+               .sleep = dib90x0_tuner_sleep,
+               .clkouttobamse = 1,
+               .analog_output = 0,
+               .use_pwm_agc = 0,
+               .clkoutdrive = 0,
+               .freq_offset_khz_uhf = 0,
+               .freq_offset_khz_vhf = 0,
+       },{
+               .io.pll_bypass = 0,
+               .io.pll_range = 1,
+               .io.pll_prediv = 1,
+               .io.pll_loopdiv = 8,
+               .io.adc_clock_ratio = 8,
+               .io.pll_int_loop_filt = 0,
+               .io.clock_khz = 30000,
+               .reset = dib90x0_tuner_reset,
+               .sleep = dib90x0_tuner_sleep,
+               .clkouttobamse = 0,
+               .analog_output = 0,
+               .use_pwm_agc = 0,
+               .clkoutdrive = 0,
+               .freq_offset_khz_uhf = 0,
+               .freq_offset_khz_vhf = 0,
+       }
+};
+
+
+static int stk9090m_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct dib0700_state *st = adap->dev->priv;
+       u32 fw_version;
+
+       /* Make use of the new i2c functions from FW 1.20 */
+       dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+       if (fw_version >= 0x10200)
+               st->fw_use_new_i2c_api = 1;
+       dib0700_set_i2c_speed(adap->dev, 340);
+
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, 0x80);
+
+       if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
+               deb_info("%s: Upload failed. (file not found?)\n", __func__);
+               return -ENODEV;
+       } else {
+               deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
+       }
+       stk9090m_config.microcode_B_fe_size = state->frontend_firmware->size;
+       stk9090m_config.microcode_B_fe_buffer = state->frontend_firmware->data;
+
+       adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &stk9090m_config);
+
+       return adap->fe == NULL ?  -ENODEV : 0;
+}
+
+static int dib9090_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct i2c_adapter *i2c = dib9000_get_tuner_interface(adap->fe);
+       u16 data_dib190[10] = {
+               1, 0x1374,
+               2, 0x01a2,
+               7, 0x0020,
+               0, 0x00ef,
+               8, 0x0486,
+       };
+
+       if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &dib9090_dib0090_config) == NULL)
+               return -ENODEV;
+       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+       if (dib01x0_pmu_update(i2c, data_dib190, 10) != 0)
+               return -ENODEV;
+       dib0700_set_i2c_speed(adap->dev, 2000);
+       if (dib9000_firmware_post_pll_init(adap->fe) < 0)
+               return -ENODEV;
+    release_firmware(state->frontend_firmware);
+       return 0;
+}
+
+static int nim9090md_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct dib0700_state *st = adap->dev->priv;
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe_slave;
+       u32 fw_version;
+
+       /* Make use of the new i2c functions from FW 1.20 */
+       dib0700_get_version(adap->dev, NULL, NULL, &fw_version, NULL);
+       if (fw_version >= 0x10200)
+               st->fw_use_new_i2c_api = 1;
+       dib0700_set_i2c_speed(adap->dev, 340);
+
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       dib0700_ctrl_clock(adap->dev, 72, 1);
+
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+       if (request_firmware(&state->frontend_firmware, "dib9090.fw", &adap->dev->udev->dev)) {
+               deb_info("%s: Upload failed. (file not found?)\n", __func__);
+               return -EIO;
+       } else {
+               deb_info("%s: firmware read %Zu bytes.\n", __func__, state->frontend_firmware->size);
+       }
+       nim9090md_config[0].microcode_B_fe_size = state->frontend_firmware->size;
+       nim9090md_config[0].microcode_B_fe_buffer = state->frontend_firmware->data;
+       nim9090md_config[1].microcode_B_fe_size = state->frontend_firmware->size;
+       nim9090md_config[1].microcode_B_fe_buffer = state->frontend_firmware->data;
+
+       dib9000_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, 0x80);
+       adap->fe = dvb_attach(dib9000_attach, &adap->dev->i2c_adap, 0x80, &nim9090md_config[0]);
+
+       if (adap->fe == NULL)
+               return -ENODEV;
+
+       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_3_4, 0);
+       dib9000_i2c_enumeration(i2c, 1, 0x12, 0x82);
+
+       fe_slave = dvb_attach(dib9000_attach, i2c, 0x82, &nim9090md_config[1]);
+       dib9000_set_slave_frontend(adap->fe, fe_slave);
+
+       return fe_slave == NULL ?  -ENODEV : 0;
 }
 
-static struct dib8000_config dib809x_dib8000_config = {
-    .output_mpeg2_in_188_bytes = 1,
-
-    .agc_config_count = 2,
-    .agc = dib8090_agc_config,
-    .agc_control = dib0090_dcc_freq,
-    .pll = &dib8090_pll_config_12mhz,
-    .tuner_is_baseband = 1,
-
-    .gpio_dir = DIB8000_GPIO_DEFAULT_DIRECTIONS,
-    .gpio_val = DIB8000_GPIO_DEFAULT_VALUES,
-    .gpio_pwm_pos = DIB8000_GPIO_DEFAULT_PWM_POS,
-
-    .hostbus_diversity = 1,
-    .div_cfg = 0x31,
-    .output_mode = OUTMODE_MPEG2_FIFO,
-    .drives = 0x2d98,
-    .diversity_delay = 144,
-    .refclksel = 3,
+static int nim9090md_tuner_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *state = adap->priv;
+       struct i2c_adapter *i2c;
+       struct dvb_frontend *fe_slave;
+       u16 data_dib190[10] = {
+               1, 0x5374,
+               2, 0x01ae,
+               7, 0x0020,
+               0, 0x00ef,
+               8, 0x0406,
+       };
+       i2c = dib9000_get_tuner_interface(adap->fe);
+       if (dvb_attach(dib0090_fw_register, adap->fe, i2c, &nim9090md_dib0090_config[0]) == NULL)
+               return -ENODEV;
+       i2c = dib9000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_GPIO_1_2, 0);
+       if (dib01x0_pmu_update(i2c, data_dib190, 10) < 0)
+               return -ENODEV;
+       dib0700_set_i2c_speed(adap->dev, 2000);
+       if (dib9000_firmware_post_pll_init(adap->fe) < 0)
+               return -ENODEV;
+
+       fe_slave = dib9000_get_slave_frontend(adap->fe, 1);
+       if (fe_slave != NULL) {
+               i2c = dib9000_get_component_bus_interface(adap->fe);
+               dib9000_set_i2c_adapter(fe_slave, i2c);
+
+               i2c = dib9000_get_tuner_interface(fe_slave);
+               if (dvb_attach(dib0090_fw_register, fe_slave, i2c, &nim9090md_dib0090_config[1]) == NULL)
+                       return -ENODEV;
+               fe_slave->dvb = adap->fe->dvb;
+               dib9000_fw_set_component_bus_speed(adap->fe, 2000);
+               if (dib9000_firmware_post_pll_init(fe_slave) < 0)
+                       return -ENODEV;
+       }
+    release_firmware(state->frontend_firmware);
+
+       return 0;
+}
+
+/* NIM7090 */
+struct dib7090p_best_adc {
+       u32 timf;
+       u32 pll_loopdiv;
+       u32 pll_prediv;
+};
+
+static int dib7090p_get_best_sampling(struct dvb_frontend *fe , struct dib7090p_best_adc *adc)
+{
+       u8 spur = 0, prediv = 0, loopdiv = 0, min_prediv = 1, max_prediv = 1;
+
+       u16 xtal = 12000;
+       u32 fcp_min = 1900;  /* PLL Minimum Frequency comparator KHz */
+       u32 fcp_max = 20000; /* PLL Maximum Frequency comparator KHz */
+       u32 fdem_max = 76000;
+       u32 fdem_min = 69500;
+       u32 fcp = 0, fs = 0, fdem = 0;
+       u32 harmonic_id = 0;
+
+       adc->pll_loopdiv = loopdiv;
+       adc->pll_prediv = prediv;
+       adc->timf = 0;
+
+       deb_info("bandwidth = %d fdem_min =%d", fe->dtv_property_cache.bandwidth_hz, fdem_min);
+
+       /* Find Min and Max prediv */
+       while((xtal/max_prediv) >= fcp_min)
+               max_prediv++;
+
+       max_prediv--;
+       min_prediv = max_prediv;
+       while((xtal/min_prediv) <= fcp_max) {
+               min_prediv--;
+               if(min_prediv == 1)
+                       break;
+       }
+       deb_info("MIN prediv = %d : MAX prediv = %d", min_prediv, max_prediv);
+
+       min_prediv = 2;
+
+       for(prediv = min_prediv ; prediv < max_prediv; prediv ++) {
+               fcp = xtal / prediv;
+               if(fcp > fcp_min && fcp < fcp_max) {
+                       for(loopdiv = 1 ; loopdiv < 64 ; loopdiv++) {
+                               fdem = ((xtal/prediv) * loopdiv);
+                               fs   = fdem / 4;
+                               /* test min/max system restrictions */
+
+                               if((fdem >= fdem_min) && (fdem <= fdem_max) && (fs >= fe->dtv_property_cache.bandwidth_hz/1000)) {
+                                       spur = 0;
+                                       /* test fs harmonics positions */
+                                       for(harmonic_id = (fe->dtv_property_cache.frequency / (1000*fs)) ;  harmonic_id <= ((fe->dtv_property_cache.frequency / (1000*fs))+1) ; harmonic_id++) {
+                                               if(((fs*harmonic_id) >= ((fe->dtv_property_cache.frequency/1000) - (fe->dtv_property_cache.bandwidth_hz/2000))) &&  ((fs*harmonic_id) <= ((fe->dtv_property_cache.frequency/1000) + (fe->dtv_property_cache.bandwidth_hz/2000)))) {
+                                                       spur = 1;
+                                                       break;
+                                               }
+                                       }
+
+                                       if(!spur) {
+                                               adc->pll_loopdiv = loopdiv;
+                                               adc->pll_prediv = prediv;
+                                               adc->timf = 2396745143UL/fdem*(1<<9);
+                                               adc->timf+= ((2396745143UL%fdem)<< 9)/fdem;
+                                               deb_info("loopdiv=%i prediv=%i timf=%i", loopdiv, prediv, adc->timf);
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               if (!spur)
+                       break;
+       }
+
+
+       if(adc->pll_loopdiv == 0 && adc->pll_prediv == 0) {
+               return -EINVAL;
+       } else
+               return 0;
+}
+
+static int dib7090_agc_startup(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep)
+{
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct dib0700_adapter_state *state = adap->priv;
+       struct dibx000_bandwidth_config pll;
+       u16 target;
+       struct dib7090p_best_adc adc;
+       int ret;
+
+       ret = state->set_param_save(fe, fep);
+       if (ret < 0)
+               return ret;
+
+       memset(&pll, 0, sizeof(struct dibx000_bandwidth_config));
+       dib0090_pwm_gain_reset(fe);
+       target = (dib0090_get_wbd_offset(fe) * 8 + 1) / 2;
+       dib7000p_set_wbd_ref(fe, target);
+
+       if(dib7090p_get_best_sampling(fe, &adc) == 0) {
+               pll.pll_ratio  = adc.pll_loopdiv;
+               pll.pll_prediv = adc.pll_prediv;
+
+               dib7000p_update_pll(fe, &pll);
+               dib7000p_ctrl_timf(fe, DEMOD_TIMF_SET, adc.timf);
+       }
+       return 0;
+}
+
+static struct dib0090_wbd_slope dib7090_wbd_table[] = {
+       { 380,   81, 850, 64, 540 ,4},
+       { 860,   51, 866, 21,  375 ,4},
+       {1700,    0, 250, 0,   100, 6}, //LBAND Predefinition , NOT tested Yet
+       {2600,    0, 250, 0,   100, 6}, //SBAND Predefinition , NOT tested Yet
+       { 0xFFFF, 0,   0, 0,   0   ,0},
 };
 
-static struct dib0090_config dib809x_dib0090_config = {
-    .io.pll_bypass = 1,
-    .io.pll_range = 1,
-    .io.pll_prediv = 1,
-    .io.pll_loopdiv = 20,
-    .io.adc_clock_ratio = 8,
-    .io.pll_int_loop_filt = 0,
-    .io.clock_khz = 12000,
-    .reset = dib80xx_tuner_reset,
-    .sleep = dib80xx_tuner_sleep,
-    .clkouttobamse = 1,
-    .analog_output = 1,
-    .i2c_address = DEFAULT_DIB0090_I2C_ADDRESS,
-    .wbd_vhf_offset = 100,
-    .wbd_cband_offset = 450,
-    .use_pwm_agc = 1,
-    .clkoutdrive = 1,
-    .get_adc_power = dib8090_get_adc_power,
-       .freq_offset_khz_uhf = 0,
-       .freq_offset_khz_vhf = -143,
-};
+struct dibx000_agc_config dib7090_agc_config[2] = {
+       {
+               .band_caps      = BAND_UHF,
+               /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+               * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+               .setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+               .inv_gain       = 687,// inv_gain = 1/ 95.4dB // no boost, lower gain due to ramp quantification
+               .time_stabiliz  = 10,  // time_stabiliz
+
+               .alpha_level    = 0,  // alpha_level
+               .thlock         = 118,  // thlock
+
+               .wbd_inv        = 0,     // wbd_inv
+               .wbd_ref        = 1200,  // wbd_ref
+               .wbd_sel        = 3,     // wbd_sel
+               .wbd_alpha      = 5,     // wbd_alpha
+
+               .agc1_max       = 65535,  // agc1_max
+               .agc1_min       = 0,  // agc1_min
+
+               .agc2_max       = 65535,  // agc2_max
+               .agc2_min       = 0,      // agc2_min
+
+               .agc1_pt1       = 0,      // agc1_pt1
+               .agc1_pt2       = 32,     // agc1_pt2
+               .agc1_pt3       = 114,    // agc1_pt3  // 40.4dB
+               .agc1_slope1    = 143,    // agc1_slope1
+               .agc1_slope2    = 144,    // agc1_slope2
+               .agc2_pt1       = 114,    // agc2_pt1
+               .agc2_pt2       = 227,    // agc2_pt2
+               .agc2_slope1    = 116,    // agc2_slope1
+               .agc2_slope2    = 117,    // agc2_slope2
+
+               .alpha_mant     = 18,  // alpha_mant // 5Hz with 95.4dB
+               .alpha_exp      = 0,   // alpha_exp
+               .beta_mant      = 20,  // beta_mant
+               .beta_exp       = 59,  // beta_exp
+
+               .perform_agc_softsplit = 0,  // perform_agc_softsplit
+       } , {
+               .band_caps      = BAND_FM | BAND_VHF | BAND_CBAND,
+               /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=1, P_agc_inv_pwm1=0, P_agc_inv_pwm2=0,
+               * P_agc_inh_dc_rv_est=0, P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=5, P_agc_write=0 */
+               .setup          = (0 << 15) | (0 << 14) | (5 << 11) | (0 << 10) | (0 << 9) | (0 << 8) | (3 << 5) | (0 << 4) | (5 << 1) | (0 << 0), // setup
+
+               .inv_gain       = 732,// inv_gain = 1/ 89.5dB // no boost, lower gain due to ramp quantification
+               .time_stabiliz  = 10,  // time_stabiliz
+
+               .alpha_level    = 0,  // alpha_level
+               .thlock         = 118,  // thlock
+
+               .wbd_inv        = 0,     // wbd_inv
+               .wbd_ref        = 1200,  // wbd_ref
+               .wbd_sel        = 3,     // wbd_sel
+               .wbd_alpha      = 5,     // wbd_alpha
+
+               .agc1_max       = 65535,  // agc1_max : 1
+               .agc1_min       = 0,      // agc1_min
+
+               .agc2_max       = 65535,  // agc2_max
+               .agc2_min       = 0,      // agc2_min
+
+               .agc1_pt1       = 0,      // agc1_pt1
+               .agc1_pt2       = 0,      // agc1_pt2
+               .agc1_pt3       = 98,     // agc1_pt3  // 34.5dB CBAND P1G + 55dB BB boost = 89.5dB
+               .agc1_slope1    = 0,      // agc1_slope1
+               .agc1_slope2    = 167,    // agc1_slope2 = Dy/Dx * 2**6 * 2**8 = 1/98 * 2**6 *2**8 : Dy = 1
+               .agc1_pt1       = 98,     // agc2_pt1
+               .agc2_pt2       = 255,    // agc2_pt2
+               .agc2_slope1    = 104,    // agc2_slope1 = Dy/Dx * 2**6 * 2**8 = 1/(255-98) * 2**6 *2**8
+               .agc2_slope2    = 0,      // agc2_slope2
+
+               .alpha_mant     = 18,  // alpha_mant // 5Hz with 95.4dB
+               .alpha_exp      = 0,   // alpha_exp
+               .beta_mant      = 20,  // beta_mant
+               .beta_exp       = 59,  // beta_exp
+
+               .perform_agc_softsplit = 0,  // perform_agc_softsplit
+       }
+};
+
+static struct dibx000_bandwidth_config dib7090_clock_config_12_mhz = {
+       60000, 15000, // internal, sampling
+       1, 5, 0, 0, 0, // pll_cfg: prediv, ratio, range, reset, bypass
+       0, 0, 1, 1, 2, // misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc, modulo
+       (3 << 14) | (1 << 12) | (524 << 0), // sad_cfg: refsel, sel, freq_15k
+       (0 << 25) | 0, // ifreq = 0.000000 MHz
+       20452225, // timf
+       15000000, // xtal_hz
+};
+
+static struct dib7000p_config nim7090_dib7000p_config = {
+       .output_mpeg2_in_188_bytes  = 1,
+       .hostbus_diversity                      = 1,
+       .tuner_is_baseband                      = 1,
+       .update_lna                                     = NULL,
+
+       .agc_config_count                       = 2,
+       .agc                                            = dib7090_agc_config,
+
+       .bw                                                     = &dib7090_clock_config_12_mhz,
+
+       .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+       .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+       .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+       .pwm_freq_div                           = 0,
+
+       .agc_control                            = dib7090_agc_restart,
+
+       .spur_protect                           = 0,
+       .disable_sample_and_hold        = 0,
+       .enable_current_mirror          = 0,
+       .diversity_delay                        = 0,
+
+       .output_mode                            = OUTMODE_MPEG2_FIFO,
+       .enMpegOutput                           = 1,
+};
+
+static struct dib7000p_config tfe7090pvr_dib7000p_config[2] = {
+       {
+               .output_mpeg2_in_188_bytes  = 1,
+               .hostbus_diversity                      = 1,
+               .tuner_is_baseband                      = 1,
+               .update_lna                                     = NULL,
+
+               .agc_config_count                       = 2,
+               .agc                                            = dib7090_agc_config,
+
+               .bw                                                     = &dib7090_clock_config_12_mhz,
+
+               .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+               .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+               .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+               .pwm_freq_div                           = 0,
+
+               .agc_control                            = dib7090_agc_restart,
+
+               .spur_protect                           = 0,
+               .disable_sample_and_hold        = 0,
+               .enable_current_mirror          = 0,
+               .diversity_delay                        = 0,
+
+               .output_mode                            = OUTMODE_MPEG2_PAR_GATED_CLK,
+               .default_i2c_addr                       = 0x90,
+               .enMpegOutput                           = 1,
+       },{
+               .output_mpeg2_in_188_bytes  = 1,
+               .hostbus_diversity                      = 1,
+               .tuner_is_baseband                      = 1,
+               .update_lna                                     = NULL,
+
+               .agc_config_count                       = 2,
+               .agc                                            = dib7090_agc_config,
+
+               .bw                                                     = &dib7090_clock_config_12_mhz,
+
+               .gpio_dir                                       = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+               .gpio_val                                       = DIB7000P_GPIO_DEFAULT_VALUES,
+               .gpio_pwm_pos                           = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+               .pwm_freq_div                           = 0,
+
+               .agc_control                            = dib7090_agc_restart,
+
+               .spur_protect                           = 0,
+               .disable_sample_and_hold        = 0,
+               .enable_current_mirror          = 0,
+               .diversity_delay                        = 0,
+
+               .output_mode                            = OUTMODE_MPEG2_PAR_GATED_CLK,
+               .default_i2c_addr                       = 0x92,
+               .enMpegOutput                           = 0,
+       }
+};
+
+static const struct dib0090_config nim7090_dib0090_config = {
+       .io.clock_khz = 12000,
+       .io.pll_bypass = 0,
+       .io.pll_range = 0,
+       .io.pll_prediv = 3,
+       .io.pll_loopdiv = 6,
+       .io.adc_clock_ratio = 0,
+       .io.pll_int_loop_filt = 0,
+       .reset = dib7090_tuner_sleep,
+       .sleep = dib7090_tuner_sleep,
+
+       .freq_offset_khz_uhf = 0,
+       .freq_offset_khz_vhf = 0,
+
+       .get_adc_power = dib7090_get_adc_power,
+
+       .clkouttobamse = 1,
+       .analog_output = 0,
+
+       .wbd_vhf_offset = 0,
+       .wbd_cband_offset = 0,
+       .use_pwm_agc = 1,
+       .clkoutdrive = 0,
+
+       .fref_clock_ratio = 0,
+
+       .wbd = dib7090_wbd_table,
+
+       .ls_cfg_pad_drv = 0,
+       .data_tx_drv = 0,
+       .low_if = NULL,
+       .in_soc = 1,
+};
+
+static const struct dib0090_config tfe7090pvr_dib0090_config[2] = {
+       {
+               .io.clock_khz = 12000,
+               .io.pll_bypass = 0,
+               .io.pll_range = 0,
+               .io.pll_prediv = 3,
+               .io.pll_loopdiv = 6,
+               .io.adc_clock_ratio = 0,
+               .io.pll_int_loop_filt = 0,
+               .reset = dib7090_tuner_sleep,
+               .sleep = dib7090_tuner_sleep,
+
+               .freq_offset_khz_uhf = 50,
+               .freq_offset_khz_vhf = 70,
+
+               .get_adc_power = dib7090_get_adc_power,
+
+               .clkouttobamse = 1,
+               .analog_output = 0,
+
+               .wbd_vhf_offset = 0,
+               .wbd_cband_offset = 0,
+               .use_pwm_agc = 1,
+               .clkoutdrive = 0,
+
+               .fref_clock_ratio = 0,
+
+               .wbd = dib7090_wbd_table,
+
+               .ls_cfg_pad_drv = 0,
+               .data_tx_drv = 0,
+               .low_if = NULL,
+               .in_soc = 1,
+       },{
+               .io.clock_khz = 12000,
+               .io.pll_bypass = 0,
+               .io.pll_range = 0,
+               .io.pll_prediv = 3,
+               .io.pll_loopdiv = 6,
+               .io.adc_clock_ratio = 0,
+               .io.pll_int_loop_filt = 0,
+               .reset = dib7090_tuner_sleep,
+               .sleep = dib7090_tuner_sleep,
+
+               .freq_offset_khz_uhf = -50,
+               .freq_offset_khz_vhf = -70,
+
+               .get_adc_power = dib7090_get_adc_power,
+
+               .clkouttobamse = 1,
+               .analog_output = 0,
+
+               .wbd_vhf_offset = 0,
+               .wbd_cband_offset = 0,
+               .use_pwm_agc = 1,
+               .clkoutdrive = 0,
+
+               .fref_clock_ratio = 0,
+
+               .wbd = dib7090_wbd_table,
+
+               .ls_cfg_pad_drv = 0,
+               .data_tx_drv = 0,
+               .low_if = NULL,
+               .in_soc = 1,
+       }
+};
+
+static int nim7090_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+       msleep(10);
+       dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-static int dib8096_set_param_override(struct dvb_frontend *fe,
-               struct dvb_frontend_parameters *fep)
-{
-    struct dvb_usb_adapter *adap = fe->dvb->priv;
-    struct dib0700_adapter_state *state = adap->priv;
-    u8 band = BAND_OF_FREQUENCY(fep->frequency/1000);
-    u16 offset;
-    int ret = 0;
-    enum frontend_tune_state tune_state = CT_SHUTDOWN;
-    u16 ltgain, rf_gain_limit;
-
-    ret = state->set_param_save(fe, fep);
-    if (ret < 0)
-       return ret;
-
-    switch (band) {
-    case BAND_VHF:
-           offset = 100;
-           break;
-    case BAND_UHF:
-           offset = 550;
-           break;
-    default:
-           offset = 0;
-           break;
-    }
-    offset += (dib0090_get_wbd_offset(fe) * 8 * 18 / 33 + 1) / 2;
-    dib8000_set_wbd_ref(fe, offset);
-
-
-    if (band == BAND_CBAND) {
-       deb_info("tuning in CBAND - soft-AGC startup\n");
-       /* TODO specific wbd target for dib0090 - needed for startup ? */
-       dib0090_set_tune_state(fe, CT_AGC_START);
-       do {
-               ret = dib0090_gain_control(fe);
-               msleep(ret);
-               tune_state = dib0090_get_tune_state(fe);
-               if (tune_state == CT_AGC_STEP_0)
-                       dib8000_set_gpio(fe, 6, 0, 1);
-               else if (tune_state == CT_AGC_STEP_1) {
-                       dib0090_get_current_gain(fe, NULL, NULL, &rf_gain_limit, &ltgain);
-                       if (rf_gain_limit == 0)
-                               dib8000_set_gpio(fe, 6, 0, 0);
-               }
-       } while (tune_state < CT_AGC_STOP);
-       dib0090_pwm_gain_reset(fe);
-       dib8000_pwm_agc_reset(fe);
-       dib8000_set_tune_state(fe, CT_DEMOD_START);
-    } else {
-       deb_info("not tuning in CBAND - standard AGC startup\n");
-       dib0090_pwm_gain_reset(fe);
-    }
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x10, &nim7090_dib7000p_config) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+               return -ENODEV;
+       }
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &nim7090_dib7000p_config);
 
-    return 0;
+       return adap->fe == NULL ?  -ENODEV : 0;
 }
 
-static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
+static int nim7090_tuner_attach(struct dvb_usb_adapter *adap)
 {
-    struct dib0700_adapter_state *st = adap->priv;
-    struct i2c_adapter *tun_i2c = dib8000_get_i2c_master(adap->fe, DIBX000_I2C_INTERFACE_TUNER, 1);
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &nim7090_dib0090_config) == NULL)
+               return -ENODEV;
 
-    if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &dib809x_dib0090_config) == NULL)
-       return -ENODEV;
+       dib7000p_set_gpio(adap->fe, 8, 0, 1);
 
-    st->set_param_save = adap->fe->ops.tuner_ops.set_params;
-    adap->fe->ops.tuner_ops.set_params = dib8096_set_param_override;
-    return 0;
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
 }
 
-static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
+static int tfe7090pvr_frontend0_attach(struct dvb_usb_adapter *adap)
 {
+       struct dib0700_state *st = adap->dev->priv;
+
+       /* The TFE7090 requires the dib0700 to not be in master mode */
+       st->disable_streaming_master_mode = 1;
+
        dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
        msleep(10);
        dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
        dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
        dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
-
        dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
 
-       dib0700_ctrl_clock(adap->dev, 72, 1);
-
        msleep(10);
        dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
        msleep(10);
        dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
 
-       dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
+       /* initialize IC 0 */
+       if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 0x20, &tfe7090pvr_dib7000p_config[0]) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+               return -ENODEV;
+       }
 
-       adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config);
+       dib0700_set_i2c_speed(adap->dev, 340);
+       adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[0]);
 
-       return adap->fe == NULL ?  -ENODEV : 0;
+    dib7090_slave_reset(adap->fe);
+
+       if (adap->fe == NULL)
+               return -ENODEV;
+
+       return 0;
+}
+
+static int tfe7090pvr_frontend1_attach(struct dvb_usb_adapter *adap)
+{
+       struct i2c_adapter *i2c;
+
+       if (adap->dev->adapter[0].fe == NULL) {
+               err("the master dib7090 has to be initialized first");
+               return -ENODEV; /* the master device has not been initialized */
+       }
+
+       i2c = dib7000p_get_i2c_master(adap->dev->adapter[0].fe, DIBX000_I2C_INTERFACE_GPIO_6_7, 1);
+       if (dib7000p_i2c_enumeration(i2c, 1, 0x10, &tfe7090pvr_dib7000p_config[1]) != 0) {
+               err("%s: dib7000p_i2c_enumeration failed.  Cannot continue\n", __func__);
+               return -ENODEV;
+       }
+
+       adap->fe = dvb_attach(dib7000p_attach, i2c, 0x92, &tfe7090pvr_dib7000p_config[1]);
+       dib0700_set_i2c_speed(adap->dev, 200);
+
+       return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int tfe7090pvr_tuner0_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[0]) == NULL)
+               return -ENODEV;
+
+       dib7000p_set_gpio(adap->fe, 8, 0, 1);
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
+}
+
+static int tfe7090pvr_tuner1_attach(struct dvb_usb_adapter *adap)
+{
+       struct dib0700_adapter_state *st = adap->priv;
+       struct i2c_adapter *tun_i2c = dib7090_get_i2c_tuner(adap->fe);
+
+       if (dvb_attach(dib0090_register, adap->fe, tun_i2c, &tfe7090pvr_dib0090_config[1]) == NULL)
+               return -ENODEV;
+
+       dib7000p_set_gpio(adap->fe, 8, 0, 1);
+
+       st->set_param_save = adap->fe->ops.tuner_ops.set_params;
+       adap->fe->ops.tuner_ops.set_params = dib7090_agc_startup;
+       return 0;
 }
 
 /* STK7070PD */
@@ -1856,6 +2797,11 @@ struct usb_device_id dib0700_usb_id_table[] = {
        { USB_DEVICE(USB_VID_PINNACLE,  USB_PID_PINNACLE_PCTV282E) },
        { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_STK8096GP) },
        { USB_DEVICE(USB_VID_ELGATO,    USB_PID_ELGATO_EYETV_DIVERSITY) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090M) },
+/* 70 */{ USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM8096MD) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM9090MD) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_NIM7090) },
+       { USB_DEVICE(USB_VID_DIBCOM,    USB_PID_DIBCOM_TFE7090PVR) },
        { 0 }           /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -2609,6 +3555,205 @@ struct dvb_usb_device_properties dib0700_devices[] = {
                        },
                },
 
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = dib90x0_pid_filter,
+                               .pid_filter_ctrl = dib90x0_pid_filter_ctrl,
+                               .frontend_attach  = stk9090m_frontend_attach,
+                               .tuner_attach     = dib9090_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom STK9090M reference design",
+                               { &dib0700_usb_id_table[69], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk80xx_pid_filter,
+                               .pid_filter_ctrl = stk80xx_pid_filter_ctrl,
+                               .frontend_attach  = nim8096md_frontend_attach,
+                               .tuner_attach     = nim8096md_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom NIM8096MD reference design",
+                               { &dib0700_usb_id_table[70], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = dib90x0_pid_filter,
+                               .pid_filter_ctrl = dib90x0_pid_filter_ctrl,
+                               .frontend_attach  = nim9090md_frontend_attach,
+                               .tuner_attach     = nim9090md_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom NIM9090MD reference design",
+                               { &dib0700_usb_id_table[71], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 1,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk70x0p_pid_filter,
+                               .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = nim7090_frontend_attach,
+                               .tuner_attach     = nim7090_tuner_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom NIM7090 reference design",
+                               { &dib0700_usb_id_table[72], NULL },
+                               { NULL },
+                       },
+               },
+
+               .rc.core = {
+                       .rc_interval      = DEFAULT_RC_INTERVAL,
+                       .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
+                       .module_name      = "dib0700",
+                       .rc_query         = dib0700_rc_query_old_firmware,
+                       .allowed_protos   = RC_TYPE_RC5 |
+                                           RC_TYPE_RC6 |
+                                           RC_TYPE_NEC,
+                       .change_protocol  = dib0700_change_protocol,
+               },
+       }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+               .num_adapters = 2,
+               .adapter = {
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk70x0p_pid_filter,
+                               .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = tfe7090pvr_frontend0_attach,
+                               .tuner_attach     = tfe7090pvr_tuner0_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+                       {
+                               .caps  = DVB_USB_ADAP_HAS_PID_FILTER |
+                                       DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+                               .pid_filter_count = 32,
+                               .pid_filter = stk70x0p_pid_filter,
+                               .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+                               .frontend_attach  = tfe7090pvr_frontend1_attach,
+                               .tuner_attach     = tfe7090pvr_tuner1_attach,
+
+                               DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+                               .size_of_priv =
+                                       sizeof(struct dib0700_adapter_state),
+                       },
+               },
+
+               .num_device_descs = 1,
+               .devices = {
+                       {   "DiBcom TFE7090PVR reference design",
+                               { &dib0700_usb_id_table[73], NULL },
+                               { NULL },
+                       },
+               },
+
                .rc.core = {
                        .rc_interval      = DEFAULT_RC_INTERVAL,
                        .rc_codes         = RC_MAP_DIB0700_RC5_TABLE,
index d0bce04..b71540d 100644 (file)
 #define USB_PID_DIBCOM_STK807XP                                0x1f90
 #define USB_PID_DIBCOM_STK807XPVR                      0x1f98
 #define USB_PID_DIBCOM_STK8096GP                        0x1fa0
+#define USB_PID_DIBCOM_NIM8096MD                        0x1fa8
 #define USB_PID_DIBCOM_ANCHOR_2135_COLD                        0x2131
 #define USB_PID_DIBCOM_STK7770P                                0x1e80
+#define USB_PID_DIBCOM_NIM7090                         0x1bb2
+#define USB_PID_DIBCOM_TFE7090PVR                      0x1bb4
+#define USB_PID_DIBCOM_NIM9090M                                0x2383
+#define USB_PID_DIBCOM_NIM9090MD                       0x2384
 #define USB_PID_DPOSH_M9206_COLD                       0x9206
 #define USB_PID_DPOSH_M9206_WARM                       0xa090
 #define USB_PID_E3C_EC168                              0x1689