summary refs log tree commit diff
path: root/drivers/media/dvb
diff options
context:
space:
mode:
authorOlivier Grenie <olivier.grenie@dibcom.fr>2011-01-04 05:42:19 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 20:31:43 -0300
commitbe9bae10ffa5aeeef051e893c3b15a5d10eb657d (patch)
tree2e7821fc885fe081bbc9b2f49673f5dfad67fe2b /drivers/media/dvb
parent713d54a8bd812229410a1902cd9b332a2a27af9f (diff)
downloadlinux-be9bae10ffa5aeeef051e893c3b15a5d10eb657d.tar.gz
[media] DiB0700: add support for several board-layouts
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>
Diffstat (limited to 'drivers/media/dvb')
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c1335
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h5
3 files changed, 1247 insertions, 97 deletions
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index ebda77dde97e..9ab57132b444 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -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;
 			}
 		}
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 193cdb77b76a..2b919034db87 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -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,98 +1406,117 @@ 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 = {
-    .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 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,
-    .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,
+	.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 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) {
+	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);
@@ -1514,25 +1535,25 @@ static int dib8096_set_param_override(struct dvb_frontend *fe,
 	dib0090_pwm_gain_reset(fe);
 	dib8000_pwm_agc_reset(fe);
 	dib8000_set_tune_state(fe, CT_DEMOD_START);
-    } else {
+	} else {
 	deb_info("not tuning in CBAND - standard AGC startup\n");
 	dib0090_pwm_gain_reset(fe);
-    }
+	}
 
-    return 0;
+	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);
+	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;
+	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;
+	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)
@@ -1554,11 +1575,931 @@ static int stk809x_frontend_attach(struct dvb_usb_adapter *adap)
 
 	dib8000_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, 0x80);
 
-	adap->fe = dvb_attach(dib8000_attach, &adap->dev->i2c_adap, 0x80, &dib809x_dib8000_config);
+	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 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},
+};
+
+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);
+
+	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 adap->fe == NULL ?  -ENODEV : 0;
 }
 
+static int nim7090_tuner_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, &nim7090_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 = dib7090_agc_startup;
+	return 0;
+}
+
+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);
+
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+	msleep(10);
+	dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+	/* 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;
+	}
+
+	dib0700_set_i2c_speed(adap->dev, 340);
+	adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x90, &tfe7090pvr_dib7000p_config[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 */
 static struct dib7000p_config stk7070pd_dib7000p_config[2] = {
 	{
@@ -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);
@@ -2619,6 +3565,205 @@ struct dvb_usb_device_properties dib0700_devices[] = {
 					    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,
+			.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,
+		},
 	},
 };
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index d0bce0445cc7..b71540d7e070 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -106,8 +106,13 @@
 #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