All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Driver for RTL2832 demodulator chip
@ 2012-04-29 21:42 Thomas Mair
  2012-04-30  9:38 ` poma
  0 siblings, 1 reply; 16+ messages in thread
From: Thomas Mair @ 2012-04-29 21:42 UTC (permalink / raw)
  To: linux-media, Antti Palosaari

Hello,

I just finished the driver for the RTL2832 demodulator chip. The patch
contais modifications of Antti's rtl28xxu driver and a modified
version of the fc0012 driver from Hans-Frieder Vogt posted recently on
this list.

The driver as of now just implements the bare minimum to be working.
The features I plan to add next are:
- Remote control
- Signal quality readings
- Hardware PID filtering

I tested the driver with the Terratec Cinergy T Stick Black, which is
the only device supported so far.

Regrads
Thomas

>From f6f653264cdd440bcbd09323e5a3445a7bcab96a Mon Sep 17 00:00:00 2001
From: Thomas Mair <thomas.mair86@googlemail.com>
Date: Sun, 29 Apr 2012 22:51:26 +0200
Subject: [PATCH] First version of RTL2832 demod driver
Cc: Linux Media Mailing List <linux-media@vger.kernel.org>

Signed-off-by: Thomas Mair <thomas.mair86@googlemail.com>
---
 drivers/media/common/tuners/Kconfig        |    7 +
 drivers/media/common/tuners/Makefile       |    1 +
 drivers/media/common/tuners/fc0012-priv.h  |   42 ++
 drivers/media/common/tuners/fc0012.c       |  384 +++++++++++++
 drivers/media/common/tuners/fc0012.h       |   60 ++
 drivers/media/dvb/dvb-usb/Kconfig          |    2 +
 drivers/media/dvb/dvb-usb/dvb-usb-ids.h    |    1 +
 drivers/media/dvb/dvb-usb/rtl28xxu.c       |  430 ++++++++++++---
 drivers/media/dvb/frontends/Kconfig        |    7 +
 drivers/media/dvb/frontends/Makefile       |    2 +-
 drivers/media/dvb/frontends/rtl2832.c      |  832 ++++++++++++++++++++++++++++
 drivers/media/dvb/frontends/rtl2832.h      |  300 ++++++++++
 drivers/media/dvb/frontends/rtl2832_priv.h |   60 ++
 13 files changed, 2060 insertions(+), 68 deletions(-)
 create mode 100644 drivers/media/common/tuners/fc0012-priv.h
 create mode 100644 drivers/media/common/tuners/fc0012.c
 create mode 100644 drivers/media/common/tuners/fc0012.h
 create mode 100644 drivers/media/dvb/frontends/rtl2832.c
 create mode 100644 drivers/media/dvb/frontends/rtl2832.h
 create mode 100644 drivers/media/dvb/frontends/rtl2832_priv.h

diff --git a/drivers/media/common/tuners/Kconfig
b/drivers/media/common/tuners/Kconfig
index 0fd15d9..8518251 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -211,6 +211,13 @@ config MEDIA_TUNER_FC0011
 	help
 	  Fitipower FC0011 silicon tuner driver.

+config MEDIA_TUNER_FC0012
+	tristate "Fitipower FC0012 silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0012 silicon tuner driver.
+
 config MEDIA_TUNER_TDA18212
 	tristate "NXP TDA18212 silicon tuner"
 	depends on VIDEO_MEDIA && I2C
diff --git a/drivers/media/common/tuners/Makefile
b/drivers/media/common/tuners/Makefile
index 64ee06f..f046106 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
 obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
 obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
+obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o

 ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/fc0012-priv.h
b/drivers/media/common/tuners/fc0012-priv.h
new file mode 100644
index 0000000..c2c3c47
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012-priv.h
@@ -0,0 +1,42 @@
+/*
+ * Fitipower FC0012 tuner driver - private includes
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_PRIV_H_
+#define _FC0012_PRIV_H_
+
+#define LOG_PREFIX "fc0012"
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0012_priv {
+       struct i2c_adapter *i2c;
+       u8 addr;
+       u8 xtal_freq;
+
+       u32 frequency;
+       u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/fc0012.c
b/drivers/media/common/tuners/fc0012.c
new file mode 100644
index 0000000..bb9f008
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.c
@@ -0,0 +1,384 @@
+/*
+ * Fitipower FC0012 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0012.h"
+#include "fc0012-priv.h"
+
+static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = { .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+	return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		err("I2C read failed, reg: %02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int fc0012_init(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	unsigned char reg[] = {
+		0x00,   /* dummy reg. 0 */
+		0x05,   /* reg. 0x01 */
+		0x10,   /* reg. 0x02 */
+		0x00,   /* reg. 0x03 */
+		0x00,   /* reg. 0x04 */
+		0x0f,   /* reg. 0x05 CHECK: correct? */ /* this is 0x0f in RTL (CNR test) */
+		0x00,   /* reg. 0x06: divider 2, VCO slow */
+		0x00,   /* reg. 0x07 */ /* this is also different in RTL code */
+		0xff,   /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+			   Loop Bw 1/8 */
+		0x6e,   /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
+		0xb8,   /* reg. 0x0a: Disable LO Test Buffer */
+		0x82,   /* reg. 0x0b: Output Clock is same as clock frequency */ /*
also different in RTL*/
+		0xfc,   /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8
*/ /* RTL */
+		0x02,   /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
+		0x00,   /* reg. 0x0e */
+		0x00,   /* reg. 0x0f */
+		0x00,   /* reg. 0x10 */ /* RTL */
+		0x00,   /* reg. 0x11 */
+		0x1f,   /* reg. 0x12: Set to maximum gain */
+		0x08,   /* reg. 0x13: Enable IX2, Set to Middle Gain: 0x08,
+			   Low Gain: 0x00, High Gain: 0x10 */
+		0x00,   /* reg. 0x14 */
+		0x04,   /* reg. 0x15: Enable LNA COMPS */
+	};
+
+	info("%s", __func__);
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+	case FC_XTAL_28_8_MHZ:
+		reg[0x07] |= 0x20;
+		break;
+	case FC_XTAL_36_MHZ:
+	default:
+		break;
+	}
+	
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+	
+	for (i = 1; i < sizeof(reg); i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+	if (ret)
+		break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0012_sleep(struct dvb_frontend *fe)
+{
+	/* nothing to do here */
+	return 0;
+}
+
+static int fc0012_set_params(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 freq = p->frequency / 1000;
+	u32 delsys = p->delivery_system;
+	unsigned char reg[0x16], am, pm, multi;
+	unsigned long fVCO;
+	unsigned short xtal_freq_khz_2, xin, xdiv;
+	int vco_select = false;
+
+	info("%s", __func__);
+
+	if(fe->callback){
+		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
FC0012_FE_CALLBACK_UHF_ENABLE, (freq > 300000 ? 0 : 1));
+		if (ret)
+			goto exit;
+	}
+	
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+		xtal_freq_khz_2 = 27000 / 2;
+		break;
+	case FC_XTAL_36_MHZ:
+		xtal_freq_khz_2 = 36000 / 2;
+		break;
+	case FC_XTAL_28_8_MHZ:
+	default:
+		xtal_freq_khz_2 = 28800 / 2;
+		break;
+	}
+
+	/* select frequency divider and the frequency of VCO */
+	if (freq * 96 < 3560000) {
+		multi = 96;
+		reg[5] = 0x82;
+		reg[6] = 0x00;
+	} else if (freq * 64 < 3560000) {
+		multi = 64;
+		reg[5] = 0x82;
+		reg[6] = 0x02;
+	} else if (freq * 48 < 3560000) {
+		multi = 48;
+		reg[5] = 0x42;
+		reg[6] = 0x00;
+	} else if (freq * 32 < 3560000) {
+		multi = 32;
+		reg[5] = 0x42;
+		reg[6] = 0x02;
+	} else if (freq * 24 < 3560000) {
+		multi = 24;
+		reg[5] = 0x22;
+		reg[6] = 0x00;
+	} else if (freq * 16 < 3560000) {
+		multi = 16;
+		reg[5] = 0x22;
+		reg[6] = 0x02;
+	} else if (freq * 12 < 3560000) {
+		multi = 12;
+		reg[5] = 0x12;
+		reg[6] = 0x00;
+	} else if (freq * 8 < 3560000) {
+		multi = 8;
+		reg[5] = 0x12;
+		reg[6] = 0x02;
+	} else if (freq * 6 < 3560000) {
+		multi = 6;
+		reg[5] = 0x0a;
+		reg[6] = 0x00;
+	} else {
+		multi = 4;
+		reg[5] = 0x0a;
+		reg[6] = 0x02;
+	}
+
+	fVCO = freq * multi;
+	
+	reg[6] |= 0x08;
+	vco_select = true;
+
+	/* From divided value (XDIV) determined the FA and FP value */
+	xdiv = (unsigned short)(fVCO / xtal_freq_khz_2);
+	if ((fVCO - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+		xdiv++;
+	
+	pm = (unsigned char)(xdiv / 8);
+	am = (unsigned char)(xdiv - (8 * pm));
+	
+	if (am < 2) {
+		reg[1] = am + 8;
+		reg[2] = pm - 1;
+	} else {
+		reg[1] = am;
+		reg[2] = pm;
+	}
+
+
+	/* From VCO frequency determines the XIN ( fractional part of Delta
+	Sigma PLL) and divided value (XDIV) */
+ 	xin = (unsigned short)(fVCO - (fVCO / xtal_freq_khz_2) * xtal_freq_khz_2);
+	xin = (xin << 15) / xtal_freq_khz_2;
+	if (xin >= 16384)
+		xin += 32768;
+
+	reg[3] = xin >> 8;      /* xin with 9 bit resolution */
+	reg[4] = xin & 0xff;
+
+	if (delsys == SYS_DVBT) {
+		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			reg[6] |= 0x80;
+			break;
+		case 7000000:
+			reg[6] &= ~0x80;
+			reg[6] |= 0x40;
+			break;
+		case 8000000:
+		default:
+			reg[6] &= ~0xc0;
+			break;
+	}
+	} else {
+		err("%s: modulation type not supported!", __func__);
+		return -EINVAL;
+	}
+
+	/* modified for Realtek demod */
+	reg[5] |= 0x07;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i <= 6; i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+		if (ret)
+			goto exit;
+       }
+
+	/* VCO Calibration */
+	ret = fc0012_writereg(priv, 0x0e, 0x80);
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	/* VCO Re-Calibration if needed */
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	if (!ret) {
+		msleep(10);
+		ret = fc0012_readreg(priv, 0x0e, &reg[0x0e]);
+	}
+	if (ret)
+		goto exit;
+
+	/* vco selection */
+	reg[0x0e] &= 0x3f;
+
+	if (vco_select) {
+		if (reg[0x0e] > 0x3c) {
+		reg[6] &= ~0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+		if (!ret)
+			ret = fc0012_writereg(priv, 0x0e, 0x80);
+		if (!ret)
+			ret = fc0012_writereg(priv, 0x0e, 0x00);
+	       }
+	} else {
+		if (reg[0x0e] < 0x02) {
+			reg[6] |= 0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x00);
+		}
+	}
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+	if (ret)
+		pr_debug("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct fc0012_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       /* CHECK: always ? */
+       *frequency = 0;
+       return 0;
+}
+
+static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct fc0012_priv *priv = fe->tuner_priv;
+       *bandwidth = priv->bandwidth;
+       return 0;
+}
+
+
+static const struct dvb_tuner_ops fc0012_tuner_ops = {
+       .info = {
+	       .name		= "Fitipower FC0012",
+
+	       .frequency_min	= 170000000,
+	       .frequency_max	= 860000000,
+	       .frequency_step	= 0,
+       },
+
+       .release	= fc0012_release,
+
+       .init = fc0012_init,
+       .sleep = fc0012_sleep,
+
+       .set_params = fc0012_set_params,
+
+       .get_frequency = fc0012_get_frequency,
+       .get_if_frequency = fc0012_get_if_frequency,
+       .get_bandwidth = fc0012_get_bandwidth,
+};
+
+struct dvb_frontend * fc0012_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, u8 i2c_address,
+       enum fc0012_xtal_freq xtal_freq)
+{
+       struct fc0012_priv *priv = NULL;
+
+       priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
+       if (priv == NULL)
+	       return NULL;
+
+       priv->i2c = i2c;
+       priv->addr = i2c_address;
+       priv->xtal_freq = xtal_freq;
+
+       info("Fitipower FC0012 successfully attached.");
+
+       fe->tuner_priv = priv;
+
+       memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+       return fe;
+}
+EXPORT_SYMBOL(fc0012_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfv...@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
diff --git a/drivers/media/common/tuners/fc0012.h
b/drivers/media/common/tuners/fc0012.h
new file mode 100644
index 0000000..1406e58
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.h
@@ -0,0 +1,60 @@
+/*
+ * Fitipower FC0012 tuner driver - include
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_H_
+#define _FC0012_H_
+
+#include "dvb_frontend.h"
+
+enum fc0012_xtal_freq {
+       FC_XTAL_27_MHZ,         /* 27000000 */
+       FC_XTAL_28_8_MHZ,       /* 28800000 */
+       FC_XTAL_36_MHZ,         /* 36000000 */
+};
+
+
+/** enum fc0011_fe_callback_commands - Frontend callbacks
+ *
+ * @FC0012_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
+ */
+enum fc0012_fe_callback_commands {
+	FC0012_FE_CALLBACK_UHF_ENABLE,
+};
+
+#define CONFIG_MEDIA_TUNER_FC0012
+
+#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
+        (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+                                       struct i2c_adapter *i2c,
+                                       u8 i2c_address,
+                                       enum fc0012_xtal_freq xtal_freq);
+#else
+static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+                                               struct i2c_adapter *i2c,
+                                               u8 i2c_address,
+                                               enum fc0012_xtal_freq xtal_freq)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/Kconfig
b/drivers/media/dvb/dvb-usb/Kconfig
index be1db75..a24bbc1 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -417,9 +417,11 @@ config DVB_USB_RTL28XXU
 	tristate "Realtek RTL28xxU DVB USB support"
 	depends on DVB_USB && EXPERIMENTAL
 	select DVB_RTL2830
+	select DVB_RTL2832
 	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
 	help
 	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.

diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 2418e41..19e942e 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -238,6 +238,7 @@
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
 #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
 #define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
+#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK		0x00a9
 #define USB_PID_TERRATEC_H7				0x10b4
 #define USB_PID_TERRATEC_H7_2				0x10a3
 #define USB_PID_TERRATEC_T3				0x10a0
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c
b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index 8f4736a..bc9f966 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
  * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -22,10 +23,12 @@
 #include "rtl28xxu.h"

 #include "rtl2830.h"
+#include "rtl2832.h"

 #include "qt1010.h"
 #include "mt2060.h"
 #include "mxl5005s.h"
+#include "fc0012.h"

 /* debug */
 static int dvb_usb_rtl28xxu_debug;
@@ -76,7 +79,7 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device
*d, struct rtl28xxu_req *req)

 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

@@ -297,7 +300,7 @@ static int rtl2831u_frontend_attach(struct
dvb_usb_adapter *adap)
 	/* for QT1010 tuner probe */
 	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };

-	deb_info("%s:\n", __func__);
+	deb_info("%s:", __func__);

 	/*
 	 * RTL2831U GPIOs
@@ -312,6 +315,7 @@ static int rtl2831u_frontend_attach(struct
dvb_usb_adapter *adap)
 	if (ret)
 		goto err;

+
 	/* enable as output GPIO0, GPIO2, GPIO4 */
 	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
 	if (ret)
@@ -332,10 +336,10 @@ static int rtl2831u_frontend_attach(struct
dvb_usb_adapter *adap)
 	if (ret == 0 && buf[0] == 0x2c) {
 		priv->tuner = TUNER_RTL2830_QT1010;
 		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
-		deb_info("%s: QT1010\n", __func__);
+		deb_info("%s: QT1010", __func__);
 		goto found;
 	} else {
-		deb_info("%s: QT1010 probe failed=%d - %02x\n",
+		deb_info("%s: QT1010 probe failed=%d - %02x",
 			__func__, ret, buf[0]);
 	}

@@ -349,10 +353,10 @@ static int rtl2831u_frontend_attach(struct
dvb_usb_adapter *adap)
 	if (ret == 0 && buf[0] == 0x63) {
 		priv->tuner = TUNER_RTL2830_MT2060;
 		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
-		deb_info("%s: MT2060\n", __func__);
+		deb_info("%s: MT2060", __func__);
 		goto found;
 	} else {
-		deb_info("%s: MT2060 probe failed=%d - %02x\n",
+		deb_info("%s: MT2060 probe failed=%d - %02x",
 			__func__, ret, buf[0]);
 	}

@@ -360,7 +364,7 @@ static int rtl2831u_frontend_attach(struct
dvb_usb_adapter *adap)
 	ret = 0;
 	priv->tuner = TUNER_RTL2830_MXL5005S;
 	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
-	deb_info("%s: MXL5005S\n", __func__);
+	deb_info("%s: MXL5005S", __func__);
 	goto found;

 found:
@@ -374,37 +378,130 @@ found:

 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 1,
+	.if_dvbt = 0,
+	.vtop = 0x20,
+	.krf = 0x04,
+	.agc_targ_val = 0x2d,
+	.tuner = TUNER_RTL2832_FC0012
+};
+
+
+static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
+		int cmd, int arg)
+{
+	int ret;
+	u8 val;
+
+	info("%s cmd=%d arg=%d", __func__, cmd, arg);
+	switch (cmd) {
+	case FC0012_FE_CALLBACK_UHF_ENABLE:
+		/* set output values */
+
+		ret = rtl2831_rd_reg(d, SYS_GPIO_DIR, &val);
+		if (ret)
+			goto err;
+
+		val &= 0xbf;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_DIR, val);
+		if (ret)
+			goto err;
+
+
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x40;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
+		if (ret)
+			goto err;
+
+
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+			goto err;
+
+		if (arg)
+			val &= 0xbf; /* set GPIO6 low */
+		else
+			val |= 0x40; /* set GPIO6 high */
+		
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	}
+	return 0;
+
+err:
+	err("%s: failed=%d", __func__, ret);
+
 	return ret;
 }

+static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+	struct rtl28xxu_priv *priv = d->priv;
+
+	switch (priv->tuner) {
+	case TUNER_RTL2832_FC0012:
+		return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -ENODEV;
+}
+
+static int rtl2832u_frontend_callback(void *adapter_priv, int component,
+				    int cmd, int arg)
+{
+	struct i2c_adapter *adap = adapter_priv;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+	switch (component) {
+	case DVB_FRONTEND_COMPONENT_TUNER:
+		return rtl2832u_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+
+
+
 static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	int ret;
 	struct rtl28xxu_priv *priv = adap->dev->priv;
+	struct rtl2832_config *rtl2832_config;
+
 	u8 buf[1];
 	/* open RTL2832U/RTL2832 I2C gate */
 	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
 	/* close RTL2832U/RTL2832 I2C gate */
 	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
-	/* for FC2580 tuner probe */
-	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
+	/* for FC0012 tuner probe */
+	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};

-	deb_info("%s:\n", __func__);
-
-	/* GPIO direction */
-	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
-	if (ret)
-		goto err;
-
-	/* enable as output GPIO0, GPIO2, GPIO4 */
-	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
-	if (ret)
-		goto err;
-
-	ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
-	if (ret)
-		goto err;
+	deb_info("%s:", __func__);

 	/*
 	 * Probe used tuner. We need to know used tuner before demod attach
@@ -416,17 +513,20 @@ static int rtl2832u_frontend_attach(struct
dvb_usb_adapter *adap)
 	if (ret)
 		goto err;

-	/* check FC2580 ID register; reg=01 val=56 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
-	if (ret == 0 && buf[0] == 0x56) {
-		priv->tuner = TUNER_RTL2832_FC2580;
-		deb_info("%s: FC2580\n", __func__);
+
+	/* check FC0012 ID register; reg=00 val=a1 */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
+	if (ret == 0 && buf[0] == 0xa1) {
+		priv->tuner = TUNER_RTL2832_FC0012;
+		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
+		deb_info("%s: FC0012", __func__);
 		goto found;
 	} else {
-		deb_info("%s: FC2580 probe failed=%d - %02x\n",
+		deb_info("%s: FC0012 probe failed=%d - %02x",
 			__func__, ret, buf[0]);
 	}

+
 	/* close demod I2C gate */
 	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
 	if (ret)
@@ -443,11 +543,19 @@ found:
 		goto err;

 	/* attach demodulator */
-	/* TODO: */
+	adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
+		&adap->dev->i2c_adap, priv->tuner);
+		if (adap->fe_adap[0].fe == NULL) {
+			ret = -ENODEV;
+			goto err;
+		}
+
+	/* set fe callbacks */
+	adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;

 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

@@ -484,7 +592,7 @@ static int rtl2831u_tuner_attach(struct
dvb_usb_adapter *adap)
 	struct i2c_adapter *rtl2830_tuner_i2c;
 	struct dvb_frontend *fe;

-	deb_info("%s:\n", __func__);
+	deb_info("%s:", __func__);

 	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
 	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
@@ -515,7 +623,7 @@ static int rtl2831u_tuner_attach(struct
dvb_usb_adapter *adap)

 	return 0;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

@@ -525,12 +633,13 @@ static int rtl2832u_tuner_attach(struct
dvb_usb_adapter *adap)
 	struct rtl28xxu_priv *priv = adap->dev->priv;
 	struct dvb_frontend *fe;

-	deb_info("%s:\n", __func__);
+	deb_info("%s:", __func__);

 	switch (priv->tuner) {
-	case TUNER_RTL2832_FC2580:
-		/* TODO: */
-		fe = NULL;
+	case TUNER_RTL2832_FC0012:
+		fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
+			&adap->dev->i2c_adap, 0xc6>>1, FC_XTAL_28_8_MHZ);
+		return 0;
 		break;
 	default:
 		fe = NULL;
@@ -544,16 +653,16 @@ static int rtl2832u_tuner_attach(struct
dvb_usb_adapter *adap)

 	return 0;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

-static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
 {
 	int ret;
 	u8 buf[2], gpio;

-	deb_info("%s: onoff=%d\n", __func__, onoff);
+	deb_info("%s: onoff=%d", __func__, onoff);

 	ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
 	if (ret)
@@ -579,16 +688,186 @@ static int rtl28xxu_streaming_ctrl(struct
dvb_usb_adapter *adap , int onoff)

 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+{
+	int ret;
+	u8 buf[2];
+
+	deb_info("%s: onoff=%d", __func__, onoff);
+
+
+	if (onoff) {
+		buf[0] = 0x00;
+		buf[1] = 0x00;
+	} else {
+		buf[0] = 0x10; /* stall EPA */
+		buf[1] = 0x02; /* reset EPA */
+	}
+
+	ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

-static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+
+static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) {
+
+	int ret;
+	struct rtl28xxu_req req;
+	u8 val;
+
+	deb_info("%s: onoff=%d", __func__, onoff);
+
+	if(onoff){
+		/* set output values */
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x08;
+		val &= 0xef;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+
+		/* enable as output GPIO3 */
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x08;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
+		if (ret)
+			goto err;
+
+		/* demod_ctl_1 */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
+		if (ret)
+			goto err;
+
+		val &= 0xef;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
+		if (ret)
+			goto err;
+
+		/* demod control */
+		/* PLL enable */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		/* bit 7 to 1 */
+		val |= 0x80;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		/* demod HW reset */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+		/* bit 5 to 0 */
+		val &= 0xdf;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x20;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		/* set page cache to 0 */
+		req.index = 0x0;
+		req.value = 0x20 + (1<<8);
+		req.data = &val;
+		req.size = 1;
+		ret = rtl28xxu_ctrl_msg(d, &req);
+		if (ret)
+			goto err;
+
+
+		mdelay(5);
+
+		/*enable ADC_Q and ADC_I */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x48;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+
+	} else {
+		/* demod_ctl_1 */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x0c;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
+		if (ret)
+			goto err;
+
+		/* set output values */
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+				goto err;
+
+		val |= 0x10;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+
+		/* demod control */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val &= 0x37;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+	}
+
+	return ret;
+err:
+	deb_info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 	int ret;
 	u8 gpio, sys0;

-	deb_info("%s: onoff=%d\n", __func__, onoff);
+	deb_info("%s: onoff=%d", __func__, onoff);

 	/* demod adc */
 	ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
@@ -600,12 +879,12 @@ static int rtl28xxu_power_ctrl(struct
dvb_usb_device *d, int onoff)
 	if (ret)
 		goto err;

-	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);

 	if (onoff) {
 		gpio |= 0x01; /* GPIO0 = 1 */
 		gpio &= (~0x10); /* GPIO4 = 0 */
-		sys0 = sys0 & 0x0f;
+		sys0 = sys0 & 0x0f; /* enable demod adc */
 		sys0 |= 0xe0;
 	} else {
 		gpio &= (~0x01); /* GPIO0 = 0 */
@@ -613,7 +892,7 @@ static int rtl28xxu_power_ctrl(struct
dvb_usb_device *d, int onoff)
 		sys0 = sys0 & (~0xc0);
 	}

-	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);

 	/* demod adc */
 	ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
@@ -627,7 +906,7 @@ static int rtl28xxu_power_ctrl(struct
dvb_usb_device *d, int onoff)

 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

@@ -699,10 +978,12 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)

 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

+/* unused for now */
+#if 0
 static int rtl2832u_rc_query(struct dvb_usb_device *d)
 {
 	int ret, i;
@@ -760,14 +1041,16 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
 exit:
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
+#endif

 enum rtl28xxu_usb_table_entry {
 	RTL2831U_0BDA_2831,
 	RTL2831U_14AA_0160,
 	RTL2831U_14AA_0161,
+	RTL2832U_0CCD_00A9,
 };

 static struct usb_device_id rtl28xxu_table[] = {
@@ -780,6 +1063,8 @@ static struct usb_device_id rtl28xxu_table[] = {
 		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},

 	/* RTL2832U */
+	[RTL2832U_0CCD_00A9] = {
+		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
 	{} /* terminating entry */
 };

@@ -802,7 +1087,7 @@ static struct dvb_usb_device_properties
rtl28xxu_properties[] = {
 					{
 						.frontend_attach = rtl2831u_frontend_attach,
 						.tuner_attach    = rtl2831u_tuner_attach,
-						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
+						.streaming_ctrl  = rtl2831u_streaming_ctrl,
 						.stream = {
 							.type = USB_BULK,
 							.count = 6,
@@ -818,7 +1103,7 @@ static struct dvb_usb_device_properties
rtl28xxu_properties[] = {
 			}
 		},

-		.power_ctrl = rtl28xxu_power_ctrl,
+		.power_ctrl = rtl2831u_power_ctrl,

 		.rc.core = {
 			.protocol       = RC_TYPE_NEC,
@@ -864,11 +1149,11 @@ static struct dvb_usb_device_properties
rtl28xxu_properties[] = {
 					{
 						.frontend_attach = rtl2832u_frontend_attach,
 						.tuner_attach    = rtl2832u_tuner_attach,
-						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
+						.streaming_ctrl  = rtl2832u_streaming_ctrl,
 						.stream = {
 							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x81,
+							.count = 10,
+							.endpoint = 0x01,
 							.u = {
 								.bulk = {
 									.buffersize = 8*512,
@@ -880,23 +1165,26 @@ static struct dvb_usb_device_properties
rtl28xxu_properties[] = {
 			}
 		},

-		.power_ctrl = rtl28xxu_power_ctrl,
+		.power_ctrl = rtl2832u_power_ctrl,

-		.rc.core = {
+		/*.rc.core = {
 			.protocol       = RC_TYPE_NEC,
 			.module_name    = "rtl28xxu",
 			.rc_query       = rtl2832u_rc_query,
 			.rc_interval    = 400,
 			.allowed_protos = RC_TYPE_NEC,
 			.rc_codes       = RC_MAP_EMPTY,
-		},
+		},*/

 		.i2c_algo = &rtl28xxu_i2c_algo,

-		.num_device_descs = 0, /* disabled as no support for RTL2832 */
+		.num_device_descs = 1,
 		.devices = {
 			{
-				.name = "Realtek RTL2832U reference design",
+				.name = "Terratec Cinergy T Stick Black",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_0CCD_00A9],
+				},
 			},
 		}
 	},
@@ -907,10 +1195,11 @@ static int rtl28xxu_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	int ret, i;
+	u8 val;
 	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
 	struct dvb_usb_device *d;

-	deb_info("%s: interface=%d\n", __func__,
+	deb_info("%s: interface=%d", __func__,
 		intf->cur_altsetting->desc.bInterfaceNumber);

 	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
@@ -926,22 +1215,31 @@ static int rtl28xxu_probe(struct usb_interface *intf,
 	if (ret)
 		goto err;

+
 	/* init USB endpoints */
-	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
+	ret = rtl2831_rd_reg(d, USB_SYSCTL_0, &val);
+	if (ret)
+			goto err;
+
+	/* enable DMA and Full Packet Mode*/
+	val |= 0x09;
+	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, val);
 	if (ret)
 		goto err;

+	/* set EPA maximum packet size to 0x0200 */
 	ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
 	if (ret)
 		goto err;

+	/* change EPA FIFO length */
 	ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
 	if (ret)
 		goto err;

 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }

@@ -957,8 +1255,6 @@ static int __init rtl28xxu_module_init(void)
 {
 	int ret;

-	deb_info("%s:\n", __func__);
-
 	ret = usb_register(&rtl28xxu_driver);
 	if (ret)
 		err("usb_register failed=%d", ret);
@@ -968,7 +1264,6 @@ static int __init rtl28xxu_module_init(void)

 static void __exit rtl28xxu_module_exit(void)
 {
-	deb_info("%s:\n", __func__);

 	/* deregister this driver from the USB subsystem */
 	usb_deregister(&rtl28xxu_driver);
@@ -979,4 +1274,5 @@ module_exit(rtl28xxu_module_exit);

 MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/Kconfig
b/drivers/media/dvb/frontends/Kconfig
index f479834..f7d67d7 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -432,6 +432,13 @@ config DVB_RTL2830
 	help
 	  Say Y when you want to support this frontend.

+config DVB_RTL2832
+	tristate "Realtek RTL2832 DVB-T"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE

diff --git a/drivers/media/dvb/frontends/Makefile
b/drivers/media/dvb/frontends/Makefile
index b0381dc..a109aae 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -100,4 +100,4 @@ obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
-
+obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
diff --git a/drivers/media/dvb/frontends/rtl2832.c
b/drivers/media/dvb/frontends/rtl2832.c
new file mode 100644
index 0000000..920b068
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2832.c
@@ -0,0 +1,832 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rtl2832_priv.h"
+
+
+
+int rtl2832_debug = 1;
+module_param_named(debug, rtl2832_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+
+static int reg_mask[32] = {
+    0x00000001,
+    0x00000003,
+    0x00000007,
+    0x0000000f,
+    0x0000001f,
+    0x0000003f,
+    0x0000007f,
+    0x000000ff,
+    0x000001ff,
+    0x000003ff,
+    0x000007ff,
+    0x00000fff,
+    0x00001fff,
+    0x00003fff,
+    0x00007fff,
+    0x0000ffff,
+    0x0001ffff,
+    0x0003ffff,
+    0x0007ffff,
+    0x000fffff,
+    0x001fffff,
+    0x003fffff,
+    0x007fffff,
+    0x00ffffff,
+    0x01ffffff,
+    0x03ffffff,
+    0x07ffffff,
+    0x0fffffff,
+    0x1fffffff,
+    0x3fffffff,
+    0x7fffffff,
+    0xffffffff
+};
+
+static const rtl2832_reg_entry registers[] = {
+  [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2},
+  [DVBT_IIC_REPEAT] = {0x1,  0x1,   3,  3},
+  [DVBT_TR_WAIT_MIN_8K]   = {0x1,  0x88,   11,  2},
+  [DVBT_RSD_BER_FAIL_VAL] = {0x1,  0x8f,   15,  0},
+  [DVBT_EN_BK_TRK]        = {0x1,  0xa6,   7,  7},
+  [DVBT_AD_EN_REG]        = {0x0,  0x8,   7,  7},
+  [DVBT_AD_EN_REG1]       = {0x0,  0x8,   6,  6},
+  [DVBT_EN_BBIN]          = {0x1,  0xb1,   0,  0},
+  [DVBT_MGD_THD0]         = {0x1,  0x95,   7,  0},
+  [DVBT_MGD_THD1]         = {0x1,  0x96,   7,  0},
+  [DVBT_MGD_THD2]         = {0x1,  0x97,   7,  0},
+  [DVBT_MGD_THD3]         = {0x1,  0x98,   7,  0},
+  [DVBT_MGD_THD4]         = {0x1,  0x99,   7,  0},
+  [DVBT_MGD_THD5]         = {0x1,  0x9a,   7,  0},
+  [DVBT_MGD_THD6]         = {0x1,  0x9b,   7,  0},
+  [DVBT_MGD_THD7]         = {0x1,  0x9c,   7,  0},
+  [DVBT_EN_CACQ_NOTCH]    = {0x1,  0x61,   4,  4},
+  [DVBT_AD_AV_REF]        = {0x0,  0x9,   6,  0},
+  [DVBT_REG_PI]           = {0x0,  0xa,   2,  0},
+  [DVBT_PIP_ON]           = {0x0,  0x21,   3,  3},
+  [DVBT_SCALE1_B92]       = {0x2,  0x92,   7,  0},
+  [DVBT_SCALE1_B93]       = {0x2,  0x93,   7,  0},
+  [DVBT_SCALE1_BA7]       = {0x2,  0xa7,   7,  0},
+  [DVBT_SCALE1_BA9]       = {0x2,  0xa9,   7,  0},
+  [DVBT_SCALE1_BAA]       = {0x2,  0xaa,   7,  0},
+  [DVBT_SCALE1_BAB]       = {0x2,  0xab,   7,  0},
+  [DVBT_SCALE1_BAC]       = {0x2,  0xac,   7,  0},
+  [DVBT_SCALE1_BB0]       = {0x2,  0xb0,   7,  0},
+  [DVBT_SCALE1_BB1]       = {0x2,  0xb1,   7,  0},
+  [DVBT_KB_P1]            = {0x1,  0x64,   3,  1},
+  [DVBT_KB_P2]            = {0x1,  0x64,   6,  4},
+  [DVBT_KB_P3]            = {0x1,  0x65,   2,  0},
+  [DVBT_OPT_ADC_IQ]       = {0x0,  0x6,   5,  4},
+  [DVBT_AD_AVI]           = {0x0,  0x9,   1,  0},
+  [DVBT_AD_AVQ]           = {0x0,  0x9,   3,  2},
+  [DVBT_K1_CR_STEP12]     = {0x2,  0xad,   9,  4},
+  [DVBT_TRK_KS_P2]        = {0x1,  0x6f,   2,  0},
+  [DVBT_TRK_KS_I2]        = {0x1,  0x70,   5,  3},
+  [DVBT_TR_THD_SET2]      = {0x1,  0x72,   3,  0},
+  [DVBT_TRK_KC_P2]        = {0x1,  0x73,   5,  3},
+  [DVBT_TRK_KC_I2]        = {0x1,  0x75,   2,  0},
+  [DVBT_CR_THD_SET2]      = {0x1,  0x76,   7,  6},
+  [DVBT_PSET_IFFREQ]     = {0x1,  0x19,   21,  0},
+  [DVBT_SPEC_INV]        = {0x1,  0x15,   0,  0},
+  [DVBT_RSAMP_RATIO]     = {0x1,  0x9f,   27,  2},
+  [DVBT_CFREQ_OFF_RATIO] = {0x1,  0x9d,   23,  4},
+  [DVBT_FSM_STAGE]       = {0x3,  0x51,   6,  3},
+  [DVBT_RX_CONSTEL]      = {0x3,  0x3c,   3,  2},
+  [DVBT_RX_HIER]         = {0x3,  0x3c,   6,  4},
+  [DVBT_RX_C_RATE_LP]    = {0x3,  0x3d,   2,  0},
+  [DVBT_RX_C_RATE_HP]    = {0x3,  0x3d,   5,  3},
+  [DVBT_GI_IDX]          = {0x3,  0x51,   1,  0},
+  [DVBT_FFT_MODE_IDX]    = {0x3,  0x51,   2,  2},
+  [DVBT_RSD_BER_EST]     = {0x3,  0x4e,   15,  0},
+  [DVBT_CE_EST_EVM]      = {0x4,  0xc,   15,  0},
+  [DVBT_RF_AGC_VAL]      = {0x3,  0x5b,   13,  0},
+  [DVBT_IF_AGC_VAL]      = {0x3,  0x59,   13,  0},
+  [DVBT_DAGC_VAL]        = {0x3,  0x5,   7,  0},
+  [DVBT_SFREQ_OFF]       = {0x3,  0x18,   13,  0},
+  [DVBT_CFREQ_OFF]       = {0x3,  0x5f,   17,  0},
+  [DVBT_POLAR_RF_AGC]    = {0x0,  0xe,   1,  1},
+  [DVBT_POLAR_IF_AGC]    = {0x0,  0xe,   0,  0},
+  [DVBT_AAGC_HOLD]       = {0x1,  0x4,   5,  5},
+  [DVBT_EN_RF_AGC]       = {0x1,  0x4,   6,  6},
+  [DVBT_EN_IF_AGC]       = {0x1,  0x4,   7,  7},
+  [DVBT_IF_AGC_MIN]      = {0x1,  0x8,   7,  0},
+  [DVBT_IF_AGC_MAX]      = {0x1,  0x9,   7,  0},
+  [DVBT_RF_AGC_MIN]      = {0x1,  0xa,   7,  0},
+  [DVBT_RF_AGC_MAX]      = {0x1,  0xb,   7,  0},
+  [DVBT_IF_AGC_MAN]      = {0x1,  0xc,   6,  6},
+  [DVBT_IF_AGC_MAN_VAL]  = {0x1,  0xc,   13,  0},
+  [DVBT_RF_AGC_MAN]      = {0x1,  0xe,   6,  6},
+  [DVBT_RF_AGC_MAN_VAL]  = {0x1,  0xe,   13,  0},
+  [DVBT_DAGC_TRG_VAL]    = {0x1,  0x12,   7,  0},
+  [DVBT_AGC_TARG_VAL_0]  = {0x1,  0x2,   0,  0},
+  [DVBT_AGC_TARG_VAL_8_1] = {0x1,  0x3,   7,  0},
+  [DVBT_AAGC_LOOP_GAIN]  = {0x1,  0xc7,   5,  1},
+  [DVBT_LOOP_GAIN2_3_0]  = {0x1,  0x4,   4,  1},
+  [DVBT_LOOP_GAIN2_4]    = {0x1,  0x5,   7,  7},
+  [DVBT_LOOP_GAIN3]      = {0x1,  0xc8,   4,  0},
+  [DVBT_VTOP1]           = {0x1,  0x6,   5,  0},
+  [DVBT_VTOP2]           = {0x1,  0xc9,   5,  0},
+  [DVBT_VTOP3]           = {0x1,  0xca,   5,  0},
+  [DVBT_KRF1]            = {0x1,  0xcb,   7,  0},
+  [DVBT_KRF2]            = {0x1,  0x7,   7,  0},
+  [DVBT_KRF3]            = {0x1,  0xcd,   7,  0},
+  [DVBT_KRF4]            = {0x1,  0xce,   7,  0},
+  [DVBT_EN_GI_PGA]       = {0x1,  0xe5,   0,  0},
+  [DVBT_THD_LOCK_UP]     = {0x1,  0xd9,   8,  0},
+  [DVBT_THD_LOCK_DW]     = {0x1,  0xdb,   8,  0},
+  [DVBT_THD_UP1]         = {0x1,  0xdd,   7,  0},
+  [DVBT_THD_DW1]         = {0x1,  0xde,   7,  0},
+  [DVBT_INTER_CNT_LEN]   = {0x1,  0xd8,   3,  0},
+  [DVBT_GI_PGA_STATE]    = {0x1,  0xe6,   3,  3},
+  [DVBT_EN_AGC_PGA]      = {0x1,  0xd7,   0,  0},
+  [DVBT_CKOUTPAR]        = {0x1,  0x7b,   5,  5},
+  [DVBT_CKOUT_PWR]       = {0x1,  0x7b,   6,  6},
+  [DVBT_SYNC_DUR]        = {0x1,  0x7b,   7,  7},
+  [DVBT_ERR_DUR]         = {0x1,  0x7c,   0,  0},
+  [DVBT_SYNC_LVL]        = {0x1,  0x7c,   1,  1},
+  [DVBT_ERR_LVL]         = {0x1,  0x7c,   2,  2},
+  [DVBT_VAL_LVL]         = {0x1,  0x7c,   3,  3},
+  [DVBT_SERIAL]          = {0x1,  0x7c,   4,  4},
+  [DVBT_SER_LSB]         = {0x1,  0x7c,   5,  5},
+  [DVBT_CDIV_PH0]        = {0x1,  0x7d,   3,  0},
+  [DVBT_CDIV_PH1]        = {0x1,  0x7d,   7,  4},
+  [DVBT_MPEG_IO_OPT_2_2] = {0x0,  0x6,   7,  7},
+  [DVBT_MPEG_IO_OPT_1_0] = {0x0,  0x7,   7,  6},
+  [DVBT_CKOUTPAR_PIP]    = {0x0,  0xb7,   4,  4},
+  [DVBT_CKOUT_PWR_PIP]   = {0x0,  0xb7,   3,  3},
+  [DVBT_SYNC_LVL_PIP]    = {0x0,  0xb7,   2,  2},
+  [DVBT_ERR_LVL_PIP]     = {0x0,  0xb7,   1,  1},
+  [DVBT_VAL_LVL_PIP]     = {0x0,  0xb7,   0,  0},
+  [DVBT_CKOUTPAR_PID]    = {0x0,  0xb9,   4,  4},
+  [DVBT_CKOUT_PWR_PID]   = {0x0,  0xb9,   3,  3},
+  [DVBT_SYNC_LVL_PID]    = {0x0,  0xb9,   2,  2},
+  [DVBT_ERR_LVL_PID]     = {0x0,  0xb9,   1,  1},
+  [DVBT_VAL_LVL_PID]     = {0x0,  0xb9,   0,  0},
+  [DVBT_SM_PASS]         = {0x1,  0x93,   11,  0},
+  [DVBT_AD7_SETTING]     = {0x0,  0x11,   15,  0},
+  [DVBT_RSSI_R]          = {0x3,  0x1,   6,  0},
+  [DVBT_ACI_DET_IND]     = {0x3,  0x12,   0,  0},
+  [DVBT_REG_MON]        = {0x0,  0xd,   1,  0},
+  [DVBT_REG_MONSEL]     = {0x0,  0xd,   2,  2},
+  [DVBT_REG_GPE]        = {0x0,  0xd,   7,  7},
+  [DVBT_REG_GPO]        = {0x0,  0x10,   0,  0},
+  [DVBT_REG_4MSEL]      = {0x0,  0x13,   0,  0},
+};
+
+
+
+/* write multiple hardware registers */
+static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[1+len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1+len,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* write multiple registers */
+static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8
page, u8 *val, int len)
+{
+	int ret;
+
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2832_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2832_wr(priv, reg, val, len);
+}
+
+/* read multiple registers */
+static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8
page, u8 *val, int len)
+{
+	int ret;
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2832_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2832_rd(priv, reg, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
+{
+	return rtl2832_wr_regs(priv, reg, page, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
+{
+	return rtl2832_rd_regs(priv, reg, page, val, 1);
+}
+
+int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val){
+	int ret;
+
+	u8 reg_start_addr;
+	u8 msb, lsb;
+	u8 page;
+	u8 reading[4];
+	u32 reading_tmp;
+	int i;
+
+	u8 len;
+	u32 mask;
+
+	reg_start_addr = registers[reg].start_address;
+	msb = registers[reg].msb;
+	lsb = registers[reg].lsb;
+	page = registers[reg].page;
+
+	len = (msb >> 3) + 1;
+	mask = reg_mask[msb-lsb];
+
+
+	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	if (ret)
+		goto err;
+
+	reading_tmp = 0;
+	for(i = 0; i < len; i++){
+		reading_tmp |= reading[i] << ((len-1-i)*8);
+	}
+
+	*val = (reading_tmp >> lsb) & mask;
+
+	return ret;
+
+err:
+	return ret;
+
+}
+
+int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
+{
+	int ret, i;
+	u8 len;
+	u8 reg_start_addr;
+	u8 msb, lsb;
+	u8 page;
+	u32 mask;
+
+
+	u8 reading[4];
+	u8 writing[4];
+	u32 reading_tmp;
+	u32 writing_tmp;
+
+
+	reg_start_addr = registers[reg].start_address;
+	msb = registers[reg].msb;
+	lsb = registers[reg].lsb;
+	page = registers[reg].page;
+
+	len = (msb >> 3) + 1;
+	mask = reg_mask[msb-lsb];
+
+
+	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	if (ret)
+		goto err;
+
+	reading_tmp = 0;
+	for (i = 0; i < len; i++) {
+		reading_tmp |= reading[i] << ((len-1-i)*8);
+	}
+
+	writing_tmp = reading_tmp & ~(mask << lsb);
+	writing_tmp |= ((val & mask) << lsb);
+
+
+	for (i = 0; i < len; i++) {
+		writing[i] = (writing_tmp >> ((len-1-i)*8)) & 0xff;
+	}
+
+	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
+	if(ret)
+		goto err;
+
+	return ret;
+
+err:
+	return ret;
+
+}
+
+
+static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	int ret;
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	dbg("%s: enable=%d", __func__, enable);
+
+	/* gate already open or close */
+	if (priv->i2c_gate_state == enable)
+		return 0;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable?0x1:0x0));
+
+	if (ret)
+		goto err;
+
+	priv->i2c_gate_state = enable;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+
+
+static int rtl2832_init(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int i, ret;
+
+	u8 en_bbin;
+	u64 pset_iffreq;
+
+	/* initialization values for the demodulator registers */
+	static rtl2832_reg_value rtl2832_initial_regs_1[] = {
+			{DVBT_AD_EN_REG,			0x1		},
+			{DVBT_AD_EN_REG1,			0x1		},
+			{DVBT_RSD_BER_FAIL_VAL,		0x2800	},
+			{DVBT_MGD_THD0,				0x10	},
+			{DVBT_MGD_THD1,				0x20	},
+			{DVBT_MGD_THD2,				0x20	},
+			{DVBT_MGD_THD3,				0x40	},
+			{DVBT_MGD_THD4,				0x22	},
+			{DVBT_MGD_THD5,				0x32	},
+			{DVBT_MGD_THD6,				0x37	},
+			{DVBT_MGD_THD7,				0x39	},
+			{DVBT_EN_BK_TRK,			0x0		},
+			{DVBT_EN_CACQ_NOTCH,		0x0		},
+			{DVBT_AD_AV_REF,			0x2a	},
+			{DVBT_REG_PI,				0x6		},
+			{DVBT_PIP_ON,				0x0		},
+			{DVBT_CDIV_PH0,				0x8		},
+			{DVBT_CDIV_PH1,				0x8		},
+			{DVBT_SCALE1_B92,			0x4		},
+			{DVBT_SCALE1_B93,			0xb0	},
+			{DVBT_SCALE1_BA7,			0x78	},
+			{DVBT_SCALE1_BA9,			0x28	},
+			{DVBT_SCALE1_BAA,			0x59	},
+			{DVBT_SCALE1_BAB,			0x83	},
+			{DVBT_SCALE1_BAC,			0xd4	},
+			{DVBT_SCALE1_BB0,			0x65	},
+			{DVBT_SCALE1_BB1,			0x43	},
+			{DVBT_KB_P1,				0x1		},
+			{DVBT_KB_P2,				0x4		},
+			{DVBT_KB_P3,				0x7		},
+			{DVBT_K1_CR_STEP12,			0xa		},
+			{DVBT_REG_GPE,				0x1		},
+			{DVBT_SERIAL,				0x0},
+			{DVBT_CDIV_PH0,				0x9},
+			{DVBT_CDIV_PH1,				0x9},
+			{DVBT_MPEG_IO_OPT_2_2,		0x0},
+			{DVBT_MPEG_IO_OPT_1_0,		0x0},
+			{DVBT_TRK_KS_P2,			0x4},
+			{DVBT_TRK_KS_I2,			0x7},
+			{DVBT_TR_THD_SET2,			0x6},
+			{DVBT_TRK_KC_I2,			0x5},
+			{DVBT_CR_THD_SET2,			0x1},
+
+
+		};
+
+	static rtl2832_reg_value rtl2832_initial_regs_2[] = {
+			{DVBT_SPEC_INV,				0x0},
+			{DVBT_DAGC_TRG_VAL,			0x5a	},
+			{DVBT_AGC_TARG_VAL_0,		0x0		},
+			{DVBT_AGC_TARG_VAL_8_1,		0x5a	},
+			{DVBT_AAGC_LOOP_GAIN,		0x16    },
+			{DVBT_LOOP_GAIN2_3_0,		0x6		},
+			{DVBT_LOOP_GAIN2_4,			0x1		},
+			{DVBT_LOOP_GAIN3,			0x16	},
+			{DVBT_VTOP1,				0x35	},
+			{DVBT_VTOP2,				0x21	},
+			{DVBT_VTOP3,				0x21	},
+			{DVBT_KRF1,					0x0		},
+			{DVBT_KRF2,					0x40	},
+			{DVBT_KRF3,					0x10	},
+			{DVBT_KRF4,					0x10	},
+			{DVBT_IF_AGC_MIN,			0x80	},
+			{DVBT_IF_AGC_MAX,			0x7f	},
+			{DVBT_RF_AGC_MIN,			0x80	},
+			{DVBT_RF_AGC_MAX,			0x7f	},
+			{DVBT_POLAR_RF_AGC,			0x0		},
+			{DVBT_POLAR_IF_AGC,			0x0		},
+			{DVBT_AD7_SETTING,			0xe9bf	},
+			{DVBT_EN_GI_PGA,			0x0		},
+			{DVBT_THD_LOCK_UP,			0x0		},
+			{DVBT_THD_LOCK_DW,			0x0		},
+			{DVBT_THD_UP1,				0x11	},
+			{DVBT_THD_DW1,				0xef	},
+			{DVBT_INTER_CNT_LEN,		0xc		},
+			{DVBT_GI_PGA_STATE,			0x0		},
+			{DVBT_EN_AGC_PGA,			0x1		},
+			{DVBT_IF_AGC_MAN,			0x0		},
+		};
+
+
+	info("%s", __func__);
+
+	en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
+
+	/* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) /
CrystalFreqHz) */
+	pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
+	pset_iffreq *= 0x400000;
+	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+	pset_iffreq = pset_iffreq & 0x3fffff;
+
+
+
+	for (i = 0; i < 42; i++) {
+		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_1[i].reg,
rtl2832_initial_regs_1[i].value);
+		if (ret)
+			goto err;
+	}
+
+	/* if frequency settings */
+	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+		if (ret)
+			goto err;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+		if(ret)
+			goto err;
+
+	for (i = 0; i < 31; i++) {
+		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_2[i].reg,
rtl2832_initial_regs_2[i].value);
+		if (ret)
+			goto err;
+	}
+
+	priv->sleeping = false;
+
+	return ret;
+
+err:
+	return ret;
+}
+
+static int rtl2832_sleep(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	info("%s", __func__);
+	priv->sleeping = true;
+	return 0;
+}
+
+int rtl2832_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	info("%s", __func__);
+	s->min_delay_ms = 1000;
+	s->step_size = fe->ops.info.frequency_stepsize * 2;
+	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+	return 0;
+}
+
+static int rtl2832_set_frontend(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, j;
+	u64 bw_mode, num, num2;
+	u32 resamp_ratio, cfreq_off_ratio;
+
+
+	static u8 bw_params[3][32] = {
+		/* 6 MHz bandwidth */
+		{
+			0xf5,	0xff,	0x15,	0x38,	0x5d,	0x6d,	0x52,	0x07,	0xfa,	0x2f,
+			0x53,	0xf5,	0x3f,	0xca,	0x0b,	0x91,	0xea,	0x30,	0x63,	0xb2,
+			0x13,	0xda,	0x0b,	0xc4,	0x18,	0x7e,	0x16,	0x66,	0x08,	0x67,
+			0x19,	0xe0,
+		},
+
+		/*  7 MHz bandwidth */
+		{
+			0xe7,	0xcc,	0xb5,	0xba,	0xe8,	0x2f,	0x67,	0x61,	0x00,	0xaf,
+			0x86,	0xf2,	0xbf,	0x59,	0x04,	0x11,	0xb6,	0x33,	0xa4,	0x30,
+			0x15,	0x10,	0x0a,	0x42,	0x18,	0xf8,	0x17,	0xd9,	0x07,	0x22,
+			0x19,	0x10,
+		},
+
+		/*  8 MHz bandwidth */
+		{
+			0x09,	0xf6,	0xd2,	0xa7,	0x9a,	0xc9,	0x27,	0x77,	0x06,	0xbf,
+			0xec,	0xf4,	0x4f,	0x0b,	0xfc,	0x01,	0x63,	0x35,	0x54,	0xa7,
+			0x16,	0x66,	0x08,	0xb4,	0x19,	0x6e,	0x19,	0x65,	0x05,	0xc8,
+			0x19,	0xe0,
+		},
+	};
+
+
+	info("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
+			c->frequency, c->bandwidth_hz, c->inversion);
+
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+
+	switch (c->bandwidth_hz) {
+		case 6000000:
+			i = 0;
+			bw_mode = 48000000;
+			break;
+		case 7000000:
+			i = 1;
+			bw_mode = 56000000;
+			break;
+		case 8000000:
+			i = 2;
+			bw_mode = 64000000;
+			break;
+		default:
+			dbg("invalid bandwidth");
+			return -EINVAL;
+		}
+
+	for (j = 0; j < 32; j++){
+		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
+		if (ret)
+			goto err;
+	}
+
+	/* calculate and set resample ratio */
+	/* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) /
ConstWithBandwidthMode) */
+	num = priv->cfg.xtal * 7;
+	num *= 0x400000;
+	num = div_u64(num, bw_mode);
+	resamp_ratio =  num & 0x3ffffff;
+	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
+	if (ret)
+		goto err;
+
+	/* calculate and set cfreq off ratio */
+	/* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20) /
(CrystalFreqHz * 7)) */
+	num = bw_mode << 20;
+	num2 = priv->cfg.xtal * 7;
+	num = div_u64(num, num2);
+	num = -num;
+	cfreq_off_ratio = num & 0xfffff;
+	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
+	if (ret)
+		goto err;
+
+
+	/* soft reset */
+	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+	if (ret)
+		goto err;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int ret;
+	u32 tmp;
+	*status = 0;
+
+
+	info("%s", __func__);
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
+	if (ret)
+		goto err;
+
+	if (tmp == 11) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	}
+	/* TODO find out if this is also true */
+	/*else if (tmp == 10) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI;
+	}*/
+
+	return ret;
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	info("%s", __func__);
+	*snr = 0;
+	return 0;
+}
+
+static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	info("%s", __func__);
+	*ber = 0;
+	return 0;
+}
+
+static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	info("%s", __func__);
+	*ucblocks = 0;
+	return 0;
+}
+
+static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	info("%s", __func__);
+	*strength = 0;
+	return 0;
+}
+
+static struct dvb_frontend_ops rtl2832_ops;
+
+static void rtl2832_release(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	info("%s", __func__);
+	kfree(priv);
+}
+
+struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
+	struct i2c_adapter *i2c, u8 tuner)
+{
+	struct rtl2832_priv *priv = NULL;
+	int ret = 0;
+	u8 tmp;
+
+	info("%s", __func__);
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
+	if (priv == NULL)
+		goto err;
+
+	/* setup the priv */
+	priv->i2c = i2c;
+	priv->tuner = tuner;
+	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
+
+	/* check if the demod is there */
+	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
+	if (ret)
+		goto err;
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+
+	/* TODO implement sleep mode depending on RC */
+	priv->sleeping = true;
+
+	return &priv->fe;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(rtl2832_attach);
+
+static struct dvb_frontend_ops rtl2832_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Realtek RTL2832 (DVB-T)",
+		.type               = FE_OFDM,
+		.frequency_min      = 50000000,
+		.frequency_max      = 862000000,
+		.frequency_stepsize = 166667,
+		.caps = FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = rtl2832_release,
+
+	.init = rtl2832_init,
+	.sleep = rtl2832_sleep,
+
+	.get_tune_settings = rtl2832_get_tune_settings,
+
+	.set_frontend = rtl2832_set_frontend,
+
+	.read_status = rtl2832_read_status,
+	.read_snr = rtl2832_read_snr,
+	.read_ber = rtl2832_read_ber,
+	.read_ucblocks = rtl2832_read_ucblocks,
+	.read_signal_strength = rtl2832_read_signal_strength,
+	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
+MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
diff --git a/drivers/media/dvb/frontends/rtl2832.h
b/drivers/media/dvb/frontends/rtl2832.h
new file mode 100644
index 0000000..b16631a
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2832.h
@@ -0,0 +1,300 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_H
+#define RTL2832_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2832_config {
+	/*
+	 * Demodulator I2C address.
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * Xtal frequency.
+	 * Hz
+	 * 4000000, 16000000, 25000000, 28800000
+	 */
+	u32 xtal;
+
+	/*
+	 * IFs for all used modes.
+	 * Hz
+	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+	 */
+	u32 if_dvbt;
+
+	/*
+	 */
+	u8 tuner;
+};
+
+
+#if defined(CONFIG_DVB_RTL2832) || \
+	(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2832_attach(
+	const struct rtl2832_config *cfg,
+	struct i2c_adapter *i2c,
+	u8 tuner
+);
+
+extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2832_attach(
+	const struct rtl2832_config *config,
+	struct i2c_adapter *i2c
+)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+)
+{
+	return NULL;
+}
+#endif
+
+
+/* Demod register bit names */
+enum DVBT_REG_BIT_NAME
+{
+	DVBT_SOFT_RST,
+	DVBT_IIC_REPEAT,
+	DVBT_TR_WAIT_MIN_8K,
+	DVBT_RSD_BER_FAIL_VAL,
+	DVBT_EN_BK_TRK,
+	DVBT_REG_PI,
+	DVBT_REG_PFREQ_1_0,
+	DVBT_PD_DA8,
+	DVBT_LOCK_TH,
+	DVBT_BER_PASS_SCAL,
+	DVBT_CE_FFSM_BYPASS,
+	DVBT_ALPHAIIR_N,
+	DVBT_ALPHAIIR_DIF,
+	DVBT_EN_TRK_SPAN,
+	DVBT_LOCK_TH_LEN,
+	DVBT_CCI_THRE,
+	DVBT_CCI_MON_SCAL,
+	DVBT_CCI_M0,
+	DVBT_CCI_M1,
+	DVBT_CCI_M2,
+	DVBT_CCI_M3,
+	DVBT_SPEC_INIT_0,
+	DVBT_SPEC_INIT_1,
+	DVBT_SPEC_INIT_2,
+	DVBT_AD_EN_REG,
+	DVBT_AD_EN_REG1,
+	DVBT_EN_BBIN,
+	DVBT_MGD_THD0,
+	DVBT_MGD_THD1,
+	DVBT_MGD_THD2,
+	DVBT_MGD_THD3,
+	DVBT_MGD_THD4,
+	DVBT_MGD_THD5,
+	DVBT_MGD_THD6,
+	DVBT_MGD_THD7,
+	DVBT_EN_CACQ_NOTCH,
+	DVBT_AD_AV_REF,	
+	DVBT_PIP_ON,
+	DVBT_SCALE1_B92,
+	DVBT_SCALE1_B93,
+	DVBT_SCALE1_BA7,
+	DVBT_SCALE1_BA9,
+	DVBT_SCALE1_BAA,
+	DVBT_SCALE1_BAB,
+	DVBT_SCALE1_BAC,
+	DVBT_SCALE1_BB0,
+	DVBT_SCALE1_BB1,
+	DVBT_KB_P1,
+	DVBT_KB_P2,
+	DVBT_KB_P3,
+	DVBT_OPT_AD
+	DVBT_AD_AVI
+	DVBT_AD_AVQ
+	DVBT_K1_CR_STEP12,
+	DVBT_TRK_KS_P2,
+	DVBT_TRK_KS_I2,
+	DVBT_TR_THD_SET2,
+	DVBT_TRK_KC_P2,
+	DVBT_TRK_KC_I2,
+	DVBT_CR_THD_SET2,
+	DVBT_PSET_IFFREQ,
+	DVBT_SPEC_INV,
+	DVBT_BW_INDEX,
+	DVBT_RSAMP_RATIO,
+	DVBT_CFREQ_OFF_RATIO,
+	DVBT_FSM_STAGE,
+	DVBT_RX_CONSTEL,
+	DVBT_RX_HIER,
+	DVBT_RX_C_RATE_LP,
+	DVBT_RX_C_RATE_HP,
+	DVBT_GI_IDX,
+	DVBT_FFT_MODE_IDX,
+	DVBT_RSD_BER_EST,
+	DVBT_CE_EST_EVM,
+	DVBT_RF_AGC_VAL,
+	DVBT_IF_AGC_VAL,
+	DVBT_DAGC_VAL,
+	DVBT_SFREQ_OFF,
+	DVBT_CFREQ_OFF,
+	DVBT_POLAR_RF_AGC,
+	DVBT_POLAR_IF_AGC,
+	DVBT_AAGC_HOLD,
+	DVBT_EN_RF_AGC,
+	DVBT_EN_IF_AGC,
+	DVBT_IF_AGC_MIN,
+	DVBT_IF_AGC_MAX,
+	DVBT_RF_AGC_MIN,
+	DVBT_RF_AGC_MAX,
+	DVBT_IF_AGC_MAN,
+	DVBT_IF_AGC_MAN_VAL,
+	DVBT_RF_AGC_MAN,
+	DVBT_RF_AGC_MAN_VAL,
+	DVBT_DAGC_TRG_VAL,
+	DVBT_AGC_TARG_VAL,
+	DVBT_LOOP_GAIN_3_0,
+	DVBT_LOOP_GAIN_4,
+	DVBT_VTOP,	
+	DVBT_KRF,
+	DVBT_AGC_TARG_VAL_0,
+	DVBT_AGC_TARG_VAL_8_1,
+	DVBT_AAGC_LOOP_GAIN,
+	DVBT_LOOP_GAIN2_3_0,
+	DVBT_LOOP_GAIN2_4,
+	DVBT_LOOP_GAIN3,
+	DVBT_VTOP1,
+	DVBT_VTOP2,
+	DVBT_VTOP3,
+	DVBT_KRF1,
+	DVBT_KRF2,
+	DVBT_KRF3,
+	DVBT_KRF4,
+	DVBT_EN_GI_PGA,
+	DVBT_THD_LOCK_UP,
+	DVBT_THD_LOCK_DW,
+	DVBT_THD_UP1,
+	DVBT_THD_DW1,
+	DVBT_INTER_CNT_LEN,
+	DVBT_GI_PGA_STATE,
+	DVBT_EN_AGC_PGA,
+	DVBT_CKOUTPAR,
+	DVBT_CKOUT_PWR,
+	DVBT_SYNC_DUR,
+	DVBT_ERR_DUR,
+	DVBT_SYNC_LVL,
+	DVBT_ERR_LVL,
+	DVBT_VAL_LVL,
+	DVBT_SERIAL,
+	DVBT_SER_LSB,
+	DVBT_CDIV_PH0,
+	DVBT_CDIV_PH1,
+	DVBT_MPEG_IO_OPT_2_2,
+	DVBT_MPEG_IO_OPT_1_0,
+	DVBT_CKOUTPAR_PIP,
+	DVBT_CKOUT_PWR_PIP,
+	DVBT_SYNC_LVL_PIP,
+	DVBT_ERR_LVL_PIP,
+	DVBT_VAL_LVL_PIP,
+	DVBT_CKOUTPAR_PID,
+	DVBT_CKOUT_PWR_PID,
+	DVBT_SYNC_LVL_PID,
+	DVBT_ERR_LVL_PID,
+	DVBT_VAL_LVL_PID,
+	DVBT_SM_PASS,
+	DVBT_UPDATE_REG_2,
+	DVBT_BTHD_P3,
+	DVBT_BTHD_D3,
+	DVBT_FUNC4_REG0,
+	DVBT_FUNC4_REG1,
+	DVBT_FUNC4_REG2,
+	DVBT_FUNC4_REG3,
+	DVBT_FUNC4_REG4,
+	DVBT_FUNC4_REG5,
+	DVBT_FUNC4_REG6,
+	DVBT_FUNC4_REG7,
+	DVBT_FUNC4_REG8,
+	DVBT_FUNC4_REG9,
+	DVBT_FUNC4_REG10,
+	DVBT_FUNC5_REG0,
+	DVBT_FUNC5_REG1,
+	DVBT_FUNC5_REG2,
+	DVBT_FUNC5_REG3,
+	DVBT_FUNC5_REG4,
+	DVBT_FUNC5_REG5,
+	DVBT_FUNC5_REG6,
+	DVBT_FUNC5_REG7,
+	DVBT_FUNC5_REG8,
+	DVBT_FUNC5_REG9,
+	DVBT_FUNC5_REG10,
+	DVBT_FUNC5_REG11,
+	DVBT_FUNC5_REG12,
+	DVBT_FUNC5_REG13,
+	DVBT_FUNC5_REG14,
+	DVBT_FUNC5_REG15,
+	DVBT_FUNC5_REG16,
+	DVBT_FUNC5_REG17,
+	DVBT_FUNC5_REG18,
+	DVBT_AD7_SETTING,
+	DVBT_RSSI_R,
+	DVBT_ACI_DET_IND,
+	DVBT_REG_MON,
+	DVBT_REG_MONSEL,
+	DVBT_REG_GPE,
+	DVBT_REG_GPO,
+	DVBT_REG_4MSEL,
+	DVBT_TEST_REG_1,
+	DVBT_TEST_REG_2,
+	DVBT_TEST_REG_3,
+	DVBT_TEST_REG_4,
+	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
+};
+
+
+/* Register table length */
+#define RTL2832_REG_TABLE_LEN	DVBT_REG_BIT_NAME_ITEM_TERMINATOR
+
+typedef struct
+{
+	u8 page;
+	u8 start_address;
+	u8 msb;
+	u8 lsb;
+}
+rtl2832_reg_entry;
+
+typedef struct
+{
+	int reg;
+	u32 value;
+}
+rtl2832_reg_value;
+
+
+
+
+
+#endif /* RTL2832_H */
diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h
b/drivers/media/dvb/frontends/rtl2832_priv.h
new file mode 100644
index 0000000..2f591c6
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2832_priv.h
@@ -0,0 +1,60 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_PRIV_H
+#define RTL2832_PRIV_H
+
+#include "dvb_frontend.h"
+#include "rtl2832.h"
+
+#define LOG_PREFIX "rtl2832"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (rtl2832_debug) \
+		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct rtl2832_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct rtl2832_config cfg;
+
+	bool i2c_gate_state;
+	bool sleeping;
+
+	u32 xtal;
+
+	u8 tuner;
+	u8 page; /* active register page */
+};
+
+struct rtl2832_reg_val_mask {
+	u16 reg;
+	u8  val;
+	u8  mask;
+};
+
+#endif /* RTL2832_PRIV_H */
-- 
1.7.7.6

^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH] Driver for RTL2832 demodulator chip
  2012-04-29 21:42 [PATCH] Driver for RTL2832 demodulator chip Thomas Mair
@ 2012-04-30  9:38 ` poma
  2012-04-30 15:39   ` [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744 Thomas Mair
  0 siblings, 1 reply; 16+ messages in thread
From: poma @ 2012-04-30  9:38 UTC (permalink / raw)
  To: linux-media

[-- Attachment #1: Type: text/plain, Size: 75583 bytes --]

On 04/29/2012 11:42 PM, Thomas Mair wrote:
> Hello,
> 
> I just finished the driver for the RTL2832 demodulator chip. The patch
> contais modifications of Antti's rtl28xxu driver and a modified
> version of the fc0012 driver from Hans-Frieder Vogt posted recently on
> this list.
> 
> The driver as of now just implements the bare minimum to be working.
> The features I plan to add next are:
> - Remote control
> - Signal quality readings
> - Hardware PID filtering
> 
> I tested the driver with the Terratec Cinergy T Stick Black, which is
> the only device supported so far.
> 
> Regrads
> Thomas
> 
> From f6f653264cdd440bcbd09323e5a3445a7bcab96a Mon Sep 17 00:00:00 2001
> From: Thomas Mair <thomas.mair86@googlemail.com>
> Date: Sun, 29 Apr 2012 22:51:26 +0200
> Subject: [PATCH] First version of RTL2832 demod driver
> Cc: Linux Media Mailing List <linux-media@vger.kernel.org>
> 
> Signed-off-by: Thomas Mair <thomas.mair86@googlemail.com>
> ---
>  drivers/media/common/tuners/Kconfig        |    7 +
>  drivers/media/common/tuners/Makefile       |    1 +
>  drivers/media/common/tuners/fc0012-priv.h  |   42 ++
>  drivers/media/common/tuners/fc0012.c       |  384 +++++++++++++
>  drivers/media/common/tuners/fc0012.h       |   60 ++
>  drivers/media/dvb/dvb-usb/Kconfig          |    2 +
>  drivers/media/dvb/dvb-usb/dvb-usb-ids.h    |    1 +
>  drivers/media/dvb/dvb-usb/rtl28xxu.c       |  430 ++++++++++++---
>  drivers/media/dvb/frontends/Kconfig        |    7 +
>  drivers/media/dvb/frontends/Makefile       |    2 +-
>  drivers/media/dvb/frontends/rtl2832.c      |  832 ++++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/rtl2832.h      |  300 ++++++++++
>  drivers/media/dvb/frontends/rtl2832_priv.h |   60 ++
>  13 files changed, 2060 insertions(+), 68 deletions(-)
>  create mode 100644 drivers/media/common/tuners/fc0012-priv.h
>  create mode 100644 drivers/media/common/tuners/fc0012.c
>  create mode 100644 drivers/media/common/tuners/fc0012.h
>  create mode 100644 drivers/media/dvb/frontends/rtl2832.c
>  create mode 100644 drivers/media/dvb/frontends/rtl2832.h
>  create mode 100644 drivers/media/dvb/frontends/rtl2832_priv.h
> 
> diff --git a/drivers/media/common/tuners/Kconfig
> b/drivers/media/common/tuners/Kconfig
> index 0fd15d9..8518251 100644
> --- a/drivers/media/common/tuners/Kconfig
> +++ b/drivers/media/common/tuners/Kconfig
> @@ -211,6 +211,13 @@ config MEDIA_TUNER_FC0011
>  	help
>  	  Fitipower FC0011 silicon tuner driver.
> 
> +config MEDIA_TUNER_FC0012
> +	tristate "Fitipower FC0012 silicon tuner"
> +	depends on VIDEO_MEDIA && I2C
> +	default m if MEDIA_TUNER_CUSTOMISE
> +	help
> +	  Fitipower FC0012 silicon tuner driver.
> +
>  config MEDIA_TUNER_TDA18212
>  	tristate "NXP TDA18212 silicon tuner"
>  	depends on VIDEO_MEDIA && I2C
> diff --git a/drivers/media/common/tuners/Makefile
> b/drivers/media/common/tuners/Makefile
> index 64ee06f..f046106 100644
> --- a/drivers/media/common/tuners/Makefile
> +++ b/drivers/media/common/tuners/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
>  obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
>  obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
>  obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
> +obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
> 
>  ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
>  ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
> diff --git a/drivers/media/common/tuners/fc0012-priv.h
> b/drivers/media/common/tuners/fc0012-priv.h
> new file mode 100644
> index 0000000..c2c3c47
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012-priv.h
> @@ -0,0 +1,42 @@
> +/*
> + * Fitipower FC0012 tuner driver - private includes
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _FC0012_PRIV_H_
> +#define _FC0012_PRIV_H_
> +
> +#define LOG_PREFIX "fc0012"
> +
> +#undef err
> +#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
> +#undef info
> +#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
> +#undef warn
> +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
> +
> +struct fc0012_priv {
> +       struct i2c_adapter *i2c;
> +       u8 addr;
> +       u8 xtal_freq;
> +
> +       u32 frequency;
> +       u32 bandwidth;
> +};
> +
> +#endif
> diff --git a/drivers/media/common/tuners/fc0012.c
> b/drivers/media/common/tuners/fc0012.c
> new file mode 100644
> index 0000000..bb9f008
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012.c
> @@ -0,0 +1,384 @@
> +/*
> + * Fitipower FC0012 tuner driver
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include "fc0012.h"
> +#include "fc0012-priv.h"
> +
> +static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
> +{
> +	u8 buf[2] = {reg, val};
> +	struct i2c_msg msg = { .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 };
> +
> +	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
> +		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
> +	return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
> +{
> +	struct i2c_msg msg[2] = {
> +		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
> +		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
> +	};
> +
> +	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
> +		err("I2C read failed, reg: %02x", reg);
> +		return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int fc0012_release(struct dvb_frontend *fe)
> +{
> +	kfree(fe->tuner_priv);
> +	fe->tuner_priv = NULL;
> +	return 0;
> +}
> +
> +static int fc0012_init(struct dvb_frontend *fe)
> +{
> +	struct fc0012_priv *priv = fe->tuner_priv;
> +	int i, ret = 0;
> +	unsigned char reg[] = {
> +		0x00,   /* dummy reg. 0 */
> +		0x05,   /* reg. 0x01 */
> +		0x10,   /* reg. 0x02 */
> +		0x00,   /* reg. 0x03 */
> +		0x00,   /* reg. 0x04 */
> +		0x0f,   /* reg. 0x05 CHECK: correct? */ /* this is 0x0f in RTL (CNR test) */
> +		0x00,   /* reg. 0x06: divider 2, VCO slow */
> +		0x00,   /* reg. 0x07 */ /* this is also different in RTL code */
> +		0xff,   /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
> +			   Loop Bw 1/8 */
> +		0x6e,   /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
> +		0xb8,   /* reg. 0x0a: Disable LO Test Buffer */
> +		0x82,   /* reg. 0x0b: Output Clock is same as clock frequency */ /*
> also different in RTL*/
> +		0xfc,   /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8
> */ /* RTL */
> +		0x02,   /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
> +		0x00,   /* reg. 0x0e */
> +		0x00,   /* reg. 0x0f */
> +		0x00,   /* reg. 0x10 */ /* RTL */
> +		0x00,   /* reg. 0x11 */
> +		0x1f,   /* reg. 0x12: Set to maximum gain */
> +		0x08,   /* reg. 0x13: Enable IX2, Set to Middle Gain: 0x08,
> +			   Low Gain: 0x00, High Gain: 0x10 */
> +		0x00,   /* reg. 0x14 */
> +		0x04,   /* reg. 0x15: Enable LNA COMPS */
> +	};
> +
> +	info("%s", __func__);
> +
> +	switch (priv->xtal_freq) {
> +	case FC_XTAL_27_MHZ:
> +	case FC_XTAL_28_8_MHZ:
> +		reg[0x07] |= 0x20;
> +		break;
> +	case FC_XTAL_36_MHZ:
> +	default:
> +		break;
> +	}
> +	
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
> +	
> +	for (i = 1; i < sizeof(reg); i++) {
> +		ret = fc0012_writereg(priv, i, reg[i]);
> +	if (ret)
> +		break;
> +	}
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
> +
> +	if (ret)
> +		warn("%s: failed: %d", __func__, ret);
> +	return ret;
> +}
> +
> +static int fc0012_sleep(struct dvb_frontend *fe)
> +{
> +	/* nothing to do here */
> +	return 0;
> +}
> +
> +static int fc0012_set_params(struct dvb_frontend *fe)
> +{
> +	struct fc0012_priv *priv = fe->tuner_priv;
> +	int i, ret = 0;
> +	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
> +	u32 freq = p->frequency / 1000;
> +	u32 delsys = p->delivery_system;
> +	unsigned char reg[0x16], am, pm, multi;
> +	unsigned long fVCO;
> +	unsigned short xtal_freq_khz_2, xin, xdiv;
> +	int vco_select = false;
> +
> +	info("%s", __func__);
> +
> +	if(fe->callback){
> +		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER,
> FC0012_FE_CALLBACK_UHF_ENABLE, (freq > 300000 ? 0 : 1));
> +		if (ret)
> +			goto exit;
> +	}
> +	
> +	switch (priv->xtal_freq) {
> +	case FC_XTAL_27_MHZ:
> +		xtal_freq_khz_2 = 27000 / 2;
> +		break;
> +	case FC_XTAL_36_MHZ:
> +		xtal_freq_khz_2 = 36000 / 2;
> +		break;
> +	case FC_XTAL_28_8_MHZ:
> +	default:
> +		xtal_freq_khz_2 = 28800 / 2;
> +		break;
> +	}
> +
> +	/* select frequency divider and the frequency of VCO */
> +	if (freq * 96 < 3560000) {
> +		multi = 96;
> +		reg[5] = 0x82;
> +		reg[6] = 0x00;
> +	} else if (freq * 64 < 3560000) {
> +		multi = 64;
> +		reg[5] = 0x82;
> +		reg[6] = 0x02;
> +	} else if (freq * 48 < 3560000) {
> +		multi = 48;
> +		reg[5] = 0x42;
> +		reg[6] = 0x00;
> +	} else if (freq * 32 < 3560000) {
> +		multi = 32;
> +		reg[5] = 0x42;
> +		reg[6] = 0x02;
> +	} else if (freq * 24 < 3560000) {
> +		multi = 24;
> +		reg[5] = 0x22;
> +		reg[6] = 0x00;
> +	} else if (freq * 16 < 3560000) {
> +		multi = 16;
> +		reg[5] = 0x22;
> +		reg[6] = 0x02;
> +	} else if (freq * 12 < 3560000) {
> +		multi = 12;
> +		reg[5] = 0x12;
> +		reg[6] = 0x00;
> +	} else if (freq * 8 < 3560000) {
> +		multi = 8;
> +		reg[5] = 0x12;
> +		reg[6] = 0x02;
> +	} else if (freq * 6 < 3560000) {
> +		multi = 6;
> +		reg[5] = 0x0a;
> +		reg[6] = 0x00;
> +	} else {
> +		multi = 4;
> +		reg[5] = 0x0a;
> +		reg[6] = 0x02;
> +	}
> +
> +	fVCO = freq * multi;
> +	
> +	reg[6] |= 0x08;
> +	vco_select = true;
> +
> +	/* From divided value (XDIV) determined the FA and FP value */
> +	xdiv = (unsigned short)(fVCO / xtal_freq_khz_2);
> +	if ((fVCO - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
> +		xdiv++;
> +	
> +	pm = (unsigned char)(xdiv / 8);
> +	am = (unsigned char)(xdiv - (8 * pm));
> +	
> +	if (am < 2) {
> +		reg[1] = am + 8;
> +		reg[2] = pm - 1;
> +	} else {
> +		reg[1] = am;
> +		reg[2] = pm;
> +	}
> +
> +
> +	/* From VCO frequency determines the XIN ( fractional part of Delta
> +	Sigma PLL) and divided value (XDIV) */
> + 	xin = (unsigned short)(fVCO - (fVCO / xtal_freq_khz_2) * xtal_freq_khz_2);
> +	xin = (xin << 15) / xtal_freq_khz_2;
> +	if (xin >= 16384)
> +		xin += 32768;
> +
> +	reg[3] = xin >> 8;      /* xin with 9 bit resolution */
> +	reg[4] = xin & 0xff;
> +
> +	if (delsys == SYS_DVBT) {
> +		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
> +		switch (p->bandwidth_hz) {
> +		case 6000000:
> +			reg[6] |= 0x80;
> +			break;
> +		case 7000000:
> +			reg[6] &= ~0x80;
> +			reg[6] |= 0x40;
> +			break;
> +		case 8000000:
> +		default:
> +			reg[6] &= ~0xc0;
> +			break;
> +	}
> +	} else {
> +		err("%s: modulation type not supported!", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* modified for Realtek demod */
> +	reg[5] |= 0x07;
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
> +
> +	for (i = 1; i <= 6; i++) {
> +		ret = fc0012_writereg(priv, i, reg[i]);
> +		if (ret)
> +			goto exit;
> +       }
> +
> +	/* VCO Calibration */
> +	ret = fc0012_writereg(priv, 0x0e, 0x80);
> +	if (!ret)
> +		ret = fc0012_writereg(priv, 0x0e, 0x00);
> +
> +	/* VCO Re-Calibration if needed */
> +	if (!ret)
> +		ret = fc0012_writereg(priv, 0x0e, 0x00);
> +
> +	if (!ret) {
> +		msleep(10);
> +		ret = fc0012_readreg(priv, 0x0e, &reg[0x0e]);
> +	}
> +	if (ret)
> +		goto exit;
> +
> +	/* vco selection */
> +	reg[0x0e] &= 0x3f;
> +
> +	if (vco_select) {
> +		if (reg[0x0e] > 0x3c) {
> +		reg[6] &= ~0x08;
> +			ret = fc0012_writereg(priv, 0x06, reg[6]);
> +		if (!ret)
> +			ret = fc0012_writereg(priv, 0x0e, 0x80);
> +		if (!ret)
> +			ret = fc0012_writereg(priv, 0x0e, 0x00);
> +	       }
> +	} else {
> +		if (reg[0x0e] < 0x02) {
> +			reg[6] |= 0x08;
> +			ret = fc0012_writereg(priv, 0x06, reg[6]);
> +			if (!ret)
> +				ret = fc0012_writereg(priv, 0x0e, 0x80);
> +			if (!ret)
> +				ret = fc0012_writereg(priv, 0x0e, 0x00);
> +		}
> +	}
> +
> +	priv->frequency = p->frequency;
> +	priv->bandwidth = p->bandwidth_hz;
> +
> +exit:
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
> +	if (ret)
> +		pr_debug("%s: failed: %d", __func__, ret);
> +	return ret;
> +}
> +
> +static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
> +{
> +       struct fc0012_priv *priv = fe->tuner_priv;
> +       *frequency = priv->frequency;
> +       return 0;
> +}
> +
> +static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
> +{
> +       /* CHECK: always ? */
> +       *frequency = 0;
> +       return 0;
> +}
> +
> +static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
> +{
> +       struct fc0012_priv *priv = fe->tuner_priv;
> +       *bandwidth = priv->bandwidth;
> +       return 0;
> +}
> +
> +
> +static const struct dvb_tuner_ops fc0012_tuner_ops = {
> +       .info = {
> +	       .name		= "Fitipower FC0012",
> +
> +	       .frequency_min	= 170000000,
> +	       .frequency_max	= 860000000,
> +	       .frequency_step	= 0,
> +       },
> +
> +       .release	= fc0012_release,
> +
> +       .init = fc0012_init,
> +       .sleep = fc0012_sleep,
> +
> +       .set_params = fc0012_set_params,
> +
> +       .get_frequency = fc0012_get_frequency,
> +       .get_if_frequency = fc0012_get_if_frequency,
> +       .get_bandwidth = fc0012_get_bandwidth,
> +};
> +
> +struct dvb_frontend * fc0012_attach(struct dvb_frontend *fe,
> +       struct i2c_adapter *i2c, u8 i2c_address,
> +       enum fc0012_xtal_freq xtal_freq)
> +{
> +       struct fc0012_priv *priv = NULL;
> +
> +       priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
> +       if (priv == NULL)
> +	       return NULL;
> +
> +       priv->i2c = i2c;
> +       priv->addr = i2c_address;
> +       priv->xtal_freq = xtal_freq;
> +
> +       info("Fitipower FC0012 successfully attached.");
> +
> +       fe->tuner_priv = priv;
> +
> +       memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
> +	       sizeof(struct dvb_tuner_ops));
> +
> +       return fe;
> +}
> +EXPORT_SYMBOL(fc0012_attach);
> +
> +MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
> +MODULE_AUTHOR("Hans-Frieder Vogt <hfv...@gmx.net>");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("0.4");
> diff --git a/drivers/media/common/tuners/fc0012.h
> b/drivers/media/common/tuners/fc0012.h
> new file mode 100644
> index 0000000..1406e58
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012.h
> @@ -0,0 +1,60 @@
> +/*
> + * Fitipower FC0012 tuner driver - include
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _FC0012_H_
> +#define _FC0012_H_
> +
> +#include "dvb_frontend.h"
> +
> +enum fc0012_xtal_freq {
> +       FC_XTAL_27_MHZ,         /* 27000000 */
> +       FC_XTAL_28_8_MHZ,       /* 28800000 */
> +       FC_XTAL_36_MHZ,         /* 36000000 */
> +};
> +
> +
> +/** enum fc0011_fe_callback_commands - Frontend callbacks
> + *
> + * @FC0012_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
> + */
> +enum fc0012_fe_callback_commands {
> +	FC0012_FE_CALLBACK_UHF_ENABLE,
> +};
> +
> +#define CONFIG_MEDIA_TUNER_FC0012
> +
> +#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
> +        (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
> +                                       struct i2c_adapter *i2c,
> +                                       u8 i2c_address,
> +                                       enum fc0012_xtal_freq xtal_freq);
> +#else
> +static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
> +                                               struct i2c_adapter *i2c,
> +                                               u8 i2c_address,
> +                                               enum fc0012_xtal_freq xtal_freq)
> +{
> +       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +       return NULL;
> +}
> +#endif
> +
> +#endif
> diff --git a/drivers/media/dvb/dvb-usb/Kconfig
> b/drivers/media/dvb/dvb-usb/Kconfig
> index be1db75..a24bbc1 100644
> --- a/drivers/media/dvb/dvb-usb/Kconfig
> +++ b/drivers/media/dvb/dvb-usb/Kconfig
> @@ -417,9 +417,11 @@ config DVB_USB_RTL28XXU
>  	tristate "Realtek RTL28xxU DVB USB support"
>  	depends on DVB_USB && EXPERIMENTAL
>  	select DVB_RTL2830
> +	select DVB_RTL2832
>  	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
>  	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
>  	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
> +	select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
>  	help
>  	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
> 
> diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> index 2418e41..19e942e 100644
> --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> @@ -238,6 +238,7 @@
>  #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
>  #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
>  #define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
> +#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK		0x00a9
>  #define USB_PID_TERRATEC_H7				0x10b4
>  #define USB_PID_TERRATEC_H7_2				0x10a3
>  #define USB_PID_TERRATEC_T3				0x10a0
> diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c
> b/drivers/media/dvb/dvb-usb/rtl28xxu.c
> index 8f4736a..bc9f966 100644
> --- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
> +++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
> @@ -3,6 +3,7 @@
>   *
>   * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
>   * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
>   *
>   *    This program is free software; you can redistribute it and/or modify
>   *    it under the terms of the GNU General Public License as published by
> @@ -22,10 +23,12 @@
>  #include "rtl28xxu.h"
> 
>  #include "rtl2830.h"
> +#include "rtl2832.h"
> 
>  #include "qt1010.h"
>  #include "mt2060.h"
>  #include "mxl5005s.h"
> +#include "fc0012.h"
> 
>  /* debug */
>  static int dvb_usb_rtl28xxu_debug;
> @@ -76,7 +79,7 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device
> *d, struct rtl28xxu_req *req)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -297,7 +300,7 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	/* for QT1010 tuner probe */
>  	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
> 
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
> 
>  	/*
>  	 * RTL2831U GPIOs
> @@ -312,6 +315,7 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret)
>  		goto err;
> 
> +
>  	/* enable as output GPIO0, GPIO2, GPIO4 */
>  	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
>  	if (ret)
> @@ -332,10 +336,10 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret == 0 && buf[0] == 0x2c) {
>  		priv->tuner = TUNER_RTL2830_QT1010;
>  		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
> -		deb_info("%s: QT1010\n", __func__);
> +		deb_info("%s: QT1010", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: QT1010 probe failed=%d - %02x\n",
> +		deb_info("%s: QT1010 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
> 
> @@ -349,10 +353,10 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret == 0 && buf[0] == 0x63) {
>  		priv->tuner = TUNER_RTL2830_MT2060;
>  		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
> -		deb_info("%s: MT2060\n", __func__);
> +		deb_info("%s: MT2060", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: MT2060 probe failed=%d - %02x\n",
> +		deb_info("%s: MT2060 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
> 
> @@ -360,7 +364,7 @@ static int rtl2831u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	ret = 0;
>  	priv->tuner = TUNER_RTL2830_MXL5005S;
>  	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
> -	deb_info("%s: MXL5005S\n", __func__);
> +	deb_info("%s: MXL5005S", __func__);
>  	goto found;
> 
>  found:
> @@ -374,37 +378,130 @@ found:
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
> +	.i2c_addr = 0x10, /* 0x20 */
> +	.xtal = 28800000,
> +	.ts_mode = 0,
> +	.spec_inv = 1,
> +	.if_dvbt = 0,
> +	.vtop = 0x20,
> +	.krf = 0x04,
> +	.agc_targ_val = 0x2d,
> +	.tuner = TUNER_RTL2832_FC0012
> +};
> +
> +
> +static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
> +		int cmd, int arg)
> +{
> +	int ret;
> +	u8 val;
> +
> +	info("%s cmd=%d arg=%d", __func__, cmd, arg);
> +	switch (cmd) {
> +	case FC0012_FE_CALLBACK_UHF_ENABLE:
> +		/* set output values */
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_DIR, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0xbf;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_DIR, val);
> +		if (ret)
> +			goto err;
> +
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x40;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
> +		if (ret)
> +			goto err;
> +
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +			goto err;
> +
> +		if (arg)
> +			val &= 0xbf; /* set GPIO6 low */
> +		else
> +			val |= 0x40; /* set GPIO6 high */
> +		
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +	return 0;
> +
> +err:
> +	err("%s: failed=%d", __func__, ret);
> +
>  	return ret;
>  }
> 
> +static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
> +{
> +	struct rtl28xxu_priv *priv = d->priv;
> +
> +	switch (priv->tuner) {
> +	case TUNER_RTL2832_FC0012:
> +		return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
> +	default:
> +		break;
> +	}
> +
> +	return -ENODEV;
> +}
> +
> +static int rtl2832u_frontend_callback(void *adapter_priv, int component,
> +				    int cmd, int arg)
> +{
> +	struct i2c_adapter *adap = adapter_priv;
> +	struct dvb_usb_device *d = i2c_get_adapdata(adap);
> +
> +	switch (component) {
> +	case DVB_FRONTEND_COMPONENT_TUNER:
> +		return rtl2832u_tuner_callback(d, cmd, arg);
> +	default:
> +		break;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +
> +
> +
>  static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
>  {
>  	int ret;
>  	struct rtl28xxu_priv *priv = adap->dev->priv;
> +	struct rtl2832_config *rtl2832_config;
> +
>  	u8 buf[1];
>  	/* open RTL2832U/RTL2832 I2C gate */
>  	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
>  	/* close RTL2832U/RTL2832 I2C gate */
>  	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
> -	/* for FC2580 tuner probe */
> -	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
> +	/* for FC0012 tuner probe */
> +	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
> 
> -	deb_info("%s:\n", __func__);
> -
> -	/* GPIO direction */
> -	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
> -	if (ret)
> -		goto err;
> -
> -	/* enable as output GPIO0, GPIO2, GPIO4 */
> -	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
> -	if (ret)
> -		goto err;
> -
> -	ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
> -	if (ret)
> -		goto err;
> +	deb_info("%s:", __func__);
> 
>  	/*
>  	 * Probe used tuner. We need to know used tuner before demod attach
> @@ -416,17 +513,20 @@ static int rtl2832u_frontend_attach(struct
> dvb_usb_adapter *adap)
>  	if (ret)
>  		goto err;
> 
> -	/* check FC2580 ID register; reg=01 val=56 */
> -	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
> -	if (ret == 0 && buf[0] == 0x56) {
> -		priv->tuner = TUNER_RTL2832_FC2580;
> -		deb_info("%s: FC2580\n", __func__);
> +
> +	/* check FC0012 ID register; reg=00 val=a1 */
> +	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
> +	if (ret == 0 && buf[0] == 0xa1) {
> +		priv->tuner = TUNER_RTL2832_FC0012;
> +		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
> +		deb_info("%s: FC0012", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: FC2580 probe failed=%d - %02x\n",
> +		deb_info("%s: FC0012 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
> 
> +
>  	/* close demod I2C gate */
>  	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
>  	if (ret)
> @@ -443,11 +543,19 @@ found:
>  		goto err;
> 
>  	/* attach demodulator */
> -	/* TODO: */
> +	adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
> +		&adap->dev->i2c_adap, priv->tuner);
> +		if (adap->fe_adap[0].fe == NULL) {
> +			ret = -ENODEV;
> +			goto err;
> +		}
> +
> +	/* set fe callbacks */
> +	adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -484,7 +592,7 @@ static int rtl2831u_tuner_attach(struct
> dvb_usb_adapter *adap)
>  	struct i2c_adapter *rtl2830_tuner_i2c;
>  	struct dvb_frontend *fe;
> 
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
> 
>  	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
>  	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
> @@ -515,7 +623,7 @@ static int rtl2831u_tuner_attach(struct
> dvb_usb_adapter *adap)
> 
>  	return 0;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -525,12 +633,13 @@ static int rtl2832u_tuner_attach(struct
> dvb_usb_adapter *adap)
>  	struct rtl28xxu_priv *priv = adap->dev->priv;
>  	struct dvb_frontend *fe;
> 
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
> 
>  	switch (priv->tuner) {
> -	case TUNER_RTL2832_FC2580:
> -		/* TODO: */
> -		fe = NULL;
> +	case TUNER_RTL2832_FC0012:
> +		fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
> +			&adap->dev->i2c_adap, 0xc6>>1, FC_XTAL_28_8_MHZ);
> +		return 0;
>  		break;
>  	default:
>  		fe = NULL;
> @@ -544,16 +653,16 @@ static int rtl2832u_tuner_attach(struct
> dvb_usb_adapter *adap)
> 
>  	return 0;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> -static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
> +static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
>  {
>  	int ret;
>  	u8 buf[2], gpio;
> 
> -	deb_info("%s: onoff=%d\n", __func__, onoff);
> +	deb_info("%s: onoff=%d", __func__, onoff);
> 
>  	ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
>  	if (ret)
> @@ -579,16 +688,186 @@ static int rtl28xxu_streaming_ctrl(struct
> dvb_usb_adapter *adap , int onoff)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
> +{
> +	int ret;
> +	u8 buf[2];
> +
> +	deb_info("%s: onoff=%d", __func__, onoff);
> +
> +
> +	if (onoff) {
> +		buf[0] = 0x00;
> +		buf[1] = 0x00;
> +	} else {
> +		buf[0] = 0x10; /* stall EPA */
> +		buf[1] = 0x02; /* reset EPA */
> +	}
> +
> +	ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
> +	if (ret)
> +		goto err;
> +
> +	return ret;
> +err:
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> -static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
> +
> +static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) {
> +
> +	int ret;
> +	struct rtl28xxu_req req;
> +	u8 val;
> +
> +	deb_info("%s: onoff=%d", __func__, onoff);
> +
> +	if(onoff){
> +		/* set output values */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x08;
> +		val &= 0xef;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* enable as output GPIO3 */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x08;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod_ctl_1 */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0xef;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod control */
> +		/* PLL enable */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		/* bit 7 to 1 */
> +		val |= 0x80;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod HW reset */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +		/* bit 5 to 0 */
> +		val &= 0xdf;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x20;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* set page cache to 0 */
> +		req.index = 0x0;
> +		req.value = 0x20 + (1<<8);
> +		req.data = &val;
> +		req.size = 1;
> +		ret = rtl28xxu_ctrl_msg(d, &req);
> +		if (ret)
> +			goto err;
> +
> +
> +		mdelay(5);
> +
> +		/*enable ADC_Q and ADC_I */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x48;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +
> +	} else {
> +		/* demod_ctl_1 */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x0c;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
> +		if (ret)
> +			goto err;
> +
> +		/* set output values */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +				goto err;
> +
> +		val |= 0x10;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod control */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0x37;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +	}
> +
> +	return ret;
> +err:
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
>  {
>  	int ret;
>  	u8 gpio, sys0;
> 
> -	deb_info("%s: onoff=%d\n", __func__, onoff);
> +	deb_info("%s: onoff=%d", __func__, onoff);
> 
>  	/* demod adc */
>  	ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
> @@ -600,12 +879,12 @@ static int rtl28xxu_power_ctrl(struct
> dvb_usb_device *d, int onoff)
>  	if (ret)
>  		goto err;
> 
> -	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
> +	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
> 
>  	if (onoff) {
>  		gpio |= 0x01; /* GPIO0 = 1 */
>  		gpio &= (~0x10); /* GPIO4 = 0 */
> -		sys0 = sys0 & 0x0f;
> +		sys0 = sys0 & 0x0f; /* enable demod adc */
>  		sys0 |= 0xe0;
>  	} else {
>  		gpio &= (~0x01); /* GPIO0 = 0 */
> @@ -613,7 +892,7 @@ static int rtl28xxu_power_ctrl(struct
> dvb_usb_device *d, int onoff)
>  		sys0 = sys0 & (~0xc0);
>  	}
> 
> -	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
> +	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
> 
>  	/* demod adc */
>  	ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
> @@ -627,7 +906,7 @@ static int rtl28xxu_power_ctrl(struct
> dvb_usb_device *d, int onoff)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -699,10 +978,12 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> +/* unused for now */
> +#if 0
>  static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  {
>  	int ret, i;
> @@ -760,14 +1041,16 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  exit:
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> +#endif
> 
>  enum rtl28xxu_usb_table_entry {
>  	RTL2831U_0BDA_2831,
>  	RTL2831U_14AA_0160,
>  	RTL2831U_14AA_0161,
> +	RTL2832U_0CCD_00A9,
>  };
> 
>  static struct usb_device_id rtl28xxu_table[] = {
> @@ -780,6 +1063,8 @@ static struct usb_device_id rtl28xxu_table[] = {
>  		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
> 
>  	/* RTL2832U */
> +	[RTL2832U_0CCD_00A9] = {
> +		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
>  	{} /* terminating entry */
>  };
> 
> @@ -802,7 +1087,7 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  					{
>  						.frontend_attach = rtl2831u_frontend_attach,
>  						.tuner_attach    = rtl2831u_tuner_attach,
> -						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
> +						.streaming_ctrl  = rtl2831u_streaming_ctrl,
>  						.stream = {
>  							.type = USB_BULK,
>  							.count = 6,
> @@ -818,7 +1103,7 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  			}
>  		},
> 
> -		.power_ctrl = rtl28xxu_power_ctrl,
> +		.power_ctrl = rtl2831u_power_ctrl,
> 
>  		.rc.core = {
>  			.protocol       = RC_TYPE_NEC,
> @@ -864,11 +1149,11 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  					{
>  						.frontend_attach = rtl2832u_frontend_attach,
>  						.tuner_attach    = rtl2832u_tuner_attach,
> -						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
> +						.streaming_ctrl  = rtl2832u_streaming_ctrl,
>  						.stream = {
>  							.type = USB_BULK,
> -							.count = 6,
> -							.endpoint = 0x81,
> +							.count = 10,
> +							.endpoint = 0x01,
>  							.u = {
>  								.bulk = {
>  									.buffersize = 8*512,
> @@ -880,23 +1165,26 @@ static struct dvb_usb_device_properties
> rtl28xxu_properties[] = {
>  			}
>  		},
> 
> -		.power_ctrl = rtl28xxu_power_ctrl,
> +		.power_ctrl = rtl2832u_power_ctrl,
> 
> -		.rc.core = {
> +		/*.rc.core = {
>  			.protocol       = RC_TYPE_NEC,
>  			.module_name    = "rtl28xxu",
>  			.rc_query       = rtl2832u_rc_query,
>  			.rc_interval    = 400,
>  			.allowed_protos = RC_TYPE_NEC,
>  			.rc_codes       = RC_MAP_EMPTY,
> -		},
> +		},*/
> 
>  		.i2c_algo = &rtl28xxu_i2c_algo,
> 
> -		.num_device_descs = 0, /* disabled as no support for RTL2832 */
> +		.num_device_descs = 1,
>  		.devices = {
>  			{
> -				.name = "Realtek RTL2832U reference design",
> +				.name = "Terratec Cinergy T Stick Black",
> +				.warm_ids = {
> +					&rtl28xxu_table[RTL2832U_0CCD_00A9],
> +				},
>  			},
>  		}
>  	},
> @@ -907,10 +1195,11 @@ static int rtl28xxu_probe(struct usb_interface *intf,
>  		const struct usb_device_id *id)
>  {
>  	int ret, i;
> +	u8 val;
>  	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
>  	struct dvb_usb_device *d;
> 
> -	deb_info("%s: interface=%d\n", __func__,
> +	deb_info("%s: interface=%d", __func__,
>  		intf->cur_altsetting->desc.bInterfaceNumber);
> 
>  	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
> @@ -926,22 +1215,31 @@ static int rtl28xxu_probe(struct usb_interface *intf,
>  	if (ret)
>  		goto err;
> 
> +
>  	/* init USB endpoints */
> -	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
> +	ret = rtl2831_rd_reg(d, USB_SYSCTL_0, &val);
> +	if (ret)
> +			goto err;
> +
> +	/* enable DMA and Full Packet Mode*/
> +	val |= 0x09;
> +	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, val);
>  	if (ret)
>  		goto err;
> 
> +	/* set EPA maximum packet size to 0x0200 */
>  	ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
>  	if (ret)
>  		goto err;
> 
> +	/* change EPA FIFO length */
>  	ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
>  	if (ret)
>  		goto err;
> 
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> 
> @@ -957,8 +1255,6 @@ static int __init rtl28xxu_module_init(void)
>  {
>  	int ret;
> 
> -	deb_info("%s:\n", __func__);
> -
>  	ret = usb_register(&rtl28xxu_driver);
>  	if (ret)
>  		err("usb_register failed=%d", ret);
> @@ -968,7 +1264,6 @@ static int __init rtl28xxu_module_init(void)
> 
>  static void __exit rtl28xxu_module_exit(void)
>  {
> -	deb_info("%s:\n", __func__);
> 
>  	/* deregister this driver from the USB subsystem */
>  	usb_deregister(&rtl28xxu_driver);
> @@ -979,4 +1274,5 @@ module_exit(rtl28xxu_module_exit);
> 
>  MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
>  MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
> +MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
>  MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/Kconfig
> b/drivers/media/dvb/frontends/Kconfig
> index f479834..f7d67d7 100644
> --- a/drivers/media/dvb/frontends/Kconfig
> +++ b/drivers/media/dvb/frontends/Kconfig
> @@ -432,6 +432,13 @@ config DVB_RTL2830
>  	help
>  	  Say Y when you want to support this frontend.
> 
> +config DVB_RTL2832
> +	tristate "Realtek RTL2832 DVB-T"
> +	depends on DVB_CORE && I2C
> +	default m if DVB_FE_CUSTOMISE
> +	help
> +	  Say Y when you want to support this frontend.
> +
>  comment "DVB-C (cable) frontends"
>  	depends on DVB_CORE
> 
> diff --git a/drivers/media/dvb/frontends/Makefile
> b/drivers/media/dvb/frontends/Makefile
> index b0381dc..a109aae 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -100,4 +100,4 @@ obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
>  obj-$(CONFIG_DVB_AF9033) += af9033.o
> -
> +obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
> diff --git a/drivers/media/dvb/frontends/rtl2832.c
> b/drivers/media/dvb/frontends/rtl2832.c
> new file mode 100644
> index 0000000..920b068
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832.c
> @@ -0,0 +1,832 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    This program is free software; you can redistribute it and/or modify
> + *    it under the terms of the GNU General Public License as published by
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License along
> + *    with this program; if not, write to the Free Software Foundation, Inc.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include "rtl2832_priv.h"
> +
> +
> +
> +int rtl2832_debug = 1;
> +module_param_named(debug, rtl2832_debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
> +
> +
> +static int reg_mask[32] = {
> +    0x00000001,
> +    0x00000003,
> +    0x00000007,
> +    0x0000000f,
> +    0x0000001f,
> +    0x0000003f,
> +    0x0000007f,
> +    0x000000ff,
> +    0x000001ff,
> +    0x000003ff,
> +    0x000007ff,
> +    0x00000fff,
> +    0x00001fff,
> +    0x00003fff,
> +    0x00007fff,
> +    0x0000ffff,
> +    0x0001ffff,
> +    0x0003ffff,
> +    0x0007ffff,
> +    0x000fffff,
> +    0x001fffff,
> +    0x003fffff,
> +    0x007fffff,
> +    0x00ffffff,
> +    0x01ffffff,
> +    0x03ffffff,
> +    0x07ffffff,
> +    0x0fffffff,
> +    0x1fffffff,
> +    0x3fffffff,
> +    0x7fffffff,
> +    0xffffffff
> +};
> +
> +static const rtl2832_reg_entry registers[] = {
> +  [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2},
> +  [DVBT_IIC_REPEAT] = {0x1,  0x1,   3,  3},
> +  [DVBT_TR_WAIT_MIN_8K]   = {0x1,  0x88,   11,  2},
> +  [DVBT_RSD_BER_FAIL_VAL] = {0x1,  0x8f,   15,  0},
> +  [DVBT_EN_BK_TRK]        = {0x1,  0xa6,   7,  7},
> +  [DVBT_AD_EN_REG]        = {0x0,  0x8,   7,  7},
> +  [DVBT_AD_EN_REG1]       = {0x0,  0x8,   6,  6},
> +  [DVBT_EN_BBIN]          = {0x1,  0xb1,   0,  0},
> +  [DVBT_MGD_THD0]         = {0x1,  0x95,   7,  0},
> +  [DVBT_MGD_THD1]         = {0x1,  0x96,   7,  0},
> +  [DVBT_MGD_THD2]         = {0x1,  0x97,   7,  0},
> +  [DVBT_MGD_THD3]         = {0x1,  0x98,   7,  0},
> +  [DVBT_MGD_THD4]         = {0x1,  0x99,   7,  0},
> +  [DVBT_MGD_THD5]         = {0x1,  0x9a,   7,  0},
> +  [DVBT_MGD_THD6]         = {0x1,  0x9b,   7,  0},
> +  [DVBT_MGD_THD7]         = {0x1,  0x9c,   7,  0},
> +  [DVBT_EN_CACQ_NOTCH]    = {0x1,  0x61,   4,  4},
> +  [DVBT_AD_AV_REF]        = {0x0,  0x9,   6,  0},
> +  [DVBT_REG_PI]           = {0x0,  0xa,   2,  0},
> +  [DVBT_PIP_ON]           = {0x0,  0x21,   3,  3},
> +  [DVBT_SCALE1_B92]       = {0x2,  0x92,   7,  0},
> +  [DVBT_SCALE1_B93]       = {0x2,  0x93,   7,  0},
> +  [DVBT_SCALE1_BA7]       = {0x2,  0xa7,   7,  0},
> +  [DVBT_SCALE1_BA9]       = {0x2,  0xa9,   7,  0},
> +  [DVBT_SCALE1_BAA]       = {0x2,  0xaa,   7,  0},
> +  [DVBT_SCALE1_BAB]       = {0x2,  0xab,   7,  0},
> +  [DVBT_SCALE1_BAC]       = {0x2,  0xac,   7,  0},
> +  [DVBT_SCALE1_BB0]       = {0x2,  0xb0,   7,  0},
> +  [DVBT_SCALE1_BB1]       = {0x2,  0xb1,   7,  0},
> +  [DVBT_KB_P1]            = {0x1,  0x64,   3,  1},
> +  [DVBT_KB_P2]            = {0x1,  0x64,   6,  4},
> +  [DVBT_KB_P3]            = {0x1,  0x65,   2,  0},
> +  [DVBT_OPT_ADC_IQ]       = {0x0,  0x6,   5,  4},
> +  [DVBT_AD_AVI]           = {0x0,  0x9,   1,  0},
> +  [DVBT_AD_AVQ]           = {0x0,  0x9,   3,  2},
> +  [DVBT_K1_CR_STEP12]     = {0x2,  0xad,   9,  4},
> +  [DVBT_TRK_KS_P2]        = {0x1,  0x6f,   2,  0},
> +  [DVBT_TRK_KS_I2]        = {0x1,  0x70,   5,  3},
> +  [DVBT_TR_THD_SET2]      = {0x1,  0x72,   3,  0},
> +  [DVBT_TRK_KC_P2]        = {0x1,  0x73,   5,  3},
> +  [DVBT_TRK_KC_I2]        = {0x1,  0x75,   2,  0},
> +  [DVBT_CR_THD_SET2]      = {0x1,  0x76,   7,  6},
> +  [DVBT_PSET_IFFREQ]     = {0x1,  0x19,   21,  0},
> +  [DVBT_SPEC_INV]        = {0x1,  0x15,   0,  0},
> +  [DVBT_RSAMP_RATIO]     = {0x1,  0x9f,   27,  2},
> +  [DVBT_CFREQ_OFF_RATIO] = {0x1,  0x9d,   23,  4},
> +  [DVBT_FSM_STAGE]       = {0x3,  0x51,   6,  3},
> +  [DVBT_RX_CONSTEL]      = {0x3,  0x3c,   3,  2},
> +  [DVBT_RX_HIER]         = {0x3,  0x3c,   6,  4},
> +  [DVBT_RX_C_RATE_LP]    = {0x3,  0x3d,   2,  0},
> +  [DVBT_RX_C_RATE_HP]    = {0x3,  0x3d,   5,  3},
> +  [DVBT_GI_IDX]          = {0x3,  0x51,   1,  0},
> +  [DVBT_FFT_MODE_IDX]    = {0x3,  0x51,   2,  2},
> +  [DVBT_RSD_BER_EST]     = {0x3,  0x4e,   15,  0},
> +  [DVBT_CE_EST_EVM]      = {0x4,  0xc,   15,  0},
> +  [DVBT_RF_AGC_VAL]      = {0x3,  0x5b,   13,  0},
> +  [DVBT_IF_AGC_VAL]      = {0x3,  0x59,   13,  0},
> +  [DVBT_DAGC_VAL]        = {0x3,  0x5,   7,  0},
> +  [DVBT_SFREQ_OFF]       = {0x3,  0x18,   13,  0},
> +  [DVBT_CFREQ_OFF]       = {0x3,  0x5f,   17,  0},
> +  [DVBT_POLAR_RF_AGC]    = {0x0,  0xe,   1,  1},
> +  [DVBT_POLAR_IF_AGC]    = {0x0,  0xe,   0,  0},
> +  [DVBT_AAGC_HOLD]       = {0x1,  0x4,   5,  5},
> +  [DVBT_EN_RF_AGC]       = {0x1,  0x4,   6,  6},
> +  [DVBT_EN_IF_AGC]       = {0x1,  0x4,   7,  7},
> +  [DVBT_IF_AGC_MIN]      = {0x1,  0x8,   7,  0},
> +  [DVBT_IF_AGC_MAX]      = {0x1,  0x9,   7,  0},
> +  [DVBT_RF_AGC_MIN]      = {0x1,  0xa,   7,  0},
> +  [DVBT_RF_AGC_MAX]      = {0x1,  0xb,   7,  0},
> +  [DVBT_IF_AGC_MAN]      = {0x1,  0xc,   6,  6},
> +  [DVBT_IF_AGC_MAN_VAL]  = {0x1,  0xc,   13,  0},
> +  [DVBT_RF_AGC_MAN]      = {0x1,  0xe,   6,  6},
> +  [DVBT_RF_AGC_MAN_VAL]  = {0x1,  0xe,   13,  0},
> +  [DVBT_DAGC_TRG_VAL]    = {0x1,  0x12,   7,  0},
> +  [DVBT_AGC_TARG_VAL_0]  = {0x1,  0x2,   0,  0},
> +  [DVBT_AGC_TARG_VAL_8_1] = {0x1,  0x3,   7,  0},
> +  [DVBT_AAGC_LOOP_GAIN]  = {0x1,  0xc7,   5,  1},
> +  [DVBT_LOOP_GAIN2_3_0]  = {0x1,  0x4,   4,  1},
> +  [DVBT_LOOP_GAIN2_4]    = {0x1,  0x5,   7,  7},
> +  [DVBT_LOOP_GAIN3]      = {0x1,  0xc8,   4,  0},
> +  [DVBT_VTOP1]           = {0x1,  0x6,   5,  0},
> +  [DVBT_VTOP2]           = {0x1,  0xc9,   5,  0},
> +  [DVBT_VTOP3]           = {0x1,  0xca,   5,  0},
> +  [DVBT_KRF1]            = {0x1,  0xcb,   7,  0},
> +  [DVBT_KRF2]            = {0x1,  0x7,   7,  0},
> +  [DVBT_KRF3]            = {0x1,  0xcd,   7,  0},
> +  [DVBT_KRF4]            = {0x1,  0xce,   7,  0},
> +  [DVBT_EN_GI_PGA]       = {0x1,  0xe5,   0,  0},
> +  [DVBT_THD_LOCK_UP]     = {0x1,  0xd9,   8,  0},
> +  [DVBT_THD_LOCK_DW]     = {0x1,  0xdb,   8,  0},
> +  [DVBT_THD_UP1]         = {0x1,  0xdd,   7,  0},
> +  [DVBT_THD_DW1]         = {0x1,  0xde,   7,  0},
> +  [DVBT_INTER_CNT_LEN]   = {0x1,  0xd8,   3,  0},
> +  [DVBT_GI_PGA_STATE]    = {0x1,  0xe6,   3,  3},
> +  [DVBT_EN_AGC_PGA]      = {0x1,  0xd7,   0,  0},
> +  [DVBT_CKOUTPAR]        = {0x1,  0x7b,   5,  5},
> +  [DVBT_CKOUT_PWR]       = {0x1,  0x7b,   6,  6},
> +  [DVBT_SYNC_DUR]        = {0x1,  0x7b,   7,  7},
> +  [DVBT_ERR_DUR]         = {0x1,  0x7c,   0,  0},
> +  [DVBT_SYNC_LVL]        = {0x1,  0x7c,   1,  1},
> +  [DVBT_ERR_LVL]         = {0x1,  0x7c,   2,  2},
> +  [DVBT_VAL_LVL]         = {0x1,  0x7c,   3,  3},
> +  [DVBT_SERIAL]          = {0x1,  0x7c,   4,  4},
> +  [DVBT_SER_LSB]         = {0x1,  0x7c,   5,  5},
> +  [DVBT_CDIV_PH0]        = {0x1,  0x7d,   3,  0},
> +  [DVBT_CDIV_PH1]        = {0x1,  0x7d,   7,  4},
> +  [DVBT_MPEG_IO_OPT_2_2] = {0x0,  0x6,   7,  7},
> +  [DVBT_MPEG_IO_OPT_1_0] = {0x0,  0x7,   7,  6},
> +  [DVBT_CKOUTPAR_PIP]    = {0x0,  0xb7,   4,  4},
> +  [DVBT_CKOUT_PWR_PIP]   = {0x0,  0xb7,   3,  3},
> +  [DVBT_SYNC_LVL_PIP]    = {0x0,  0xb7,   2,  2},
> +  [DVBT_ERR_LVL_PIP]     = {0x0,  0xb7,   1,  1},
> +  [DVBT_VAL_LVL_PIP]     = {0x0,  0xb7,   0,  0},
> +  [DVBT_CKOUTPAR_PID]    = {0x0,  0xb9,   4,  4},
> +  [DVBT_CKOUT_PWR_PID]   = {0x0,  0xb9,   3,  3},
> +  [DVBT_SYNC_LVL_PID]    = {0x0,  0xb9,   2,  2},
> +  [DVBT_ERR_LVL_PID]     = {0x0,  0xb9,   1,  1},
> +  [DVBT_VAL_LVL_PID]     = {0x0,  0xb9,   0,  0},
> +  [DVBT_SM_PASS]         = {0x1,  0x93,   11,  0},
> +  [DVBT_AD7_SETTING]     = {0x0,  0x11,   15,  0},
> +  [DVBT_RSSI_R]          = {0x3,  0x1,   6,  0},
> +  [DVBT_ACI_DET_IND]     = {0x3,  0x12,   0,  0},
> +  [DVBT_REG_MON]        = {0x0,  0xd,   1,  0},
> +  [DVBT_REG_MONSEL]     = {0x0,  0xd,   2,  2},
> +  [DVBT_REG_GPE]        = {0x0,  0xd,   7,  7},
> +  [DVBT_REG_GPO]        = {0x0,  0x10,   0,  0},
> +  [DVBT_REG_4MSEL]      = {0x0,  0x13,   0,  0},
> +};
> +
> +
> +
> +/* write multiple hardware registers */
> +static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
> +{
> +	int ret;
> +	u8 buf[1+len];
> +	struct i2c_msg msg[1] = {
> +		{
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = 0,
> +			.len = 1+len,
> +			.buf = buf,
> +		}
> +	};
> +
> +	buf[0] = reg;
> +	memcpy(&buf[1], val, len);
> +
> +	ret = i2c_transfer(priv->i2c, msg, 1);
> +	if (ret == 1) {
> +		ret = 0;
> +	} else {
> +		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
> +		ret = -EREMOTEIO;
> +	}
> +	return ret;
> +}
> +
> +/* read multiple hardware registers */
> +static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
> +{
> +	int ret;
> +	struct i2c_msg msg[2] = {
> +		{
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = 0,
> +			.len = 1,
> +			.buf = &reg,
> +		}, {
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = I2C_M_RD,
> +			.len = len,
> +			.buf = val,
> +		}
> +	};
> +
> +	ret = i2c_transfer(priv->i2c, msg, 2);
> +	if (ret == 2) {
> +		ret = 0;
> +	} else {
> +		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
> +		ret = -EREMOTEIO;
> +	}
> +	return ret;
> +}
> +
> +/* write multiple registers */
> +static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8
> page, u8 *val, int len)
> +{
> +	int ret;
> +
> +
> +	/* switch bank if needed */
> +	if (page != priv->page) {
> +		ret = rtl2832_wr(priv, 0x00, &page, 1);
> +		if (ret)
> +			return ret;
> +
> +		priv->page = page;
> +	}
> +
> +	return rtl2832_wr(priv, reg, val, len);
> +}
> +
> +/* read multiple registers */
> +static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8
> page, u8 *val, int len)
> +{
> +	int ret;
> +
> +	/* switch bank if needed */
> +	if (page != priv->page) {
> +		ret = rtl2832_wr(priv, 0x00, &page, 1);
> +		if (ret)
> +			return ret;
> +
> +		priv->page = page;
> +	}
> +
> +	return rtl2832_rd(priv, reg, val, len);
> +}
> +
> +#if 0 /* currently not used */
> +/* write single register */
> +static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
> +{
> +	return rtl2832_wr_regs(priv, reg, page, &val, 1);
> +}
> +#endif
> +
> +/* read single register */
> +static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
> +{
> +	return rtl2832_rd_regs(priv, reg, page, val, 1);
> +}
> +
> +int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val){
> +	int ret;
> +
> +	u8 reg_start_addr;
> +	u8 msb, lsb;
> +	u8 page;
> +	u8 reading[4];
> +	u32 reading_tmp;
> +	int i;
> +
> +	u8 len;
> +	u32 mask;
> +
> +	reg_start_addr = registers[reg].start_address;
> +	msb = registers[reg].msb;
> +	lsb = registers[reg].lsb;
> +	page = registers[reg].page;
> +
> +	len = (msb >> 3) + 1;
> +	mask = reg_mask[msb-lsb];
> +
> +
> +	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
> +	if (ret)
> +		goto err;
> +
> +	reading_tmp = 0;
> +	for(i = 0; i < len; i++){
> +		reading_tmp |= reading[i] << ((len-1-i)*8);
> +	}
> +
> +	*val = (reading_tmp >> lsb) & mask;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +
> +}
> +
> +int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
> +{
> +	int ret, i;
> +	u8 len;
> +	u8 reg_start_addr;
> +	u8 msb, lsb;
> +	u8 page;
> +	u32 mask;
> +
> +
> +	u8 reading[4];
> +	u8 writing[4];
> +	u32 reading_tmp;
> +	u32 writing_tmp;
> +
> +
> +	reg_start_addr = registers[reg].start_address;
> +	msb = registers[reg].msb;
> +	lsb = registers[reg].lsb;
> +	page = registers[reg].page;
> +
> +	len = (msb >> 3) + 1;
> +	mask = reg_mask[msb-lsb];
> +
> +
> +	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
> +	if (ret)
> +		goto err;
> +
> +	reading_tmp = 0;
> +	for (i = 0; i < len; i++) {
> +		reading_tmp |= reading[i] << ((len-1-i)*8);
> +	}
> +
> +	writing_tmp = reading_tmp & ~(mask << lsb);
> +	writing_tmp |= ((val & mask) << lsb);
> +
> +
> +	for (i = 0; i < len; i++) {
> +		writing[i] = (writing_tmp >> ((len-1-i)*8)) & 0xff;
> +	}
> +
> +	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
> +	if(ret)
> +		goto err;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +
> +}
> +
> +
> +static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
> +{
> +	int ret;
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	dbg("%s: enable=%d", __func__, enable);
> +
> +	/* gate already open or close */
> +	if (priv->i2c_gate_state == enable)
> +		return 0;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable?0x1:0x0));
> +
> +	if (ret)
> +		goto err;
> +
> +	priv->i2c_gate_state = enable;
> +
> +	return ret;
> +err:
> +	dbg("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +
> +
> +static int rtl2832_init(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	int i, ret;
> +
> +	u8 en_bbin;
> +	u64 pset_iffreq;
> +
> +	/* initialization values for the demodulator registers */
> +	static rtl2832_reg_value rtl2832_initial_regs_1[] = {
> +			{DVBT_AD_EN_REG,			0x1		},
> +			{DVBT_AD_EN_REG1,			0x1		},
> +			{DVBT_RSD_BER_FAIL_VAL,		0x2800	},
> +			{DVBT_MGD_THD0,				0x10	},
> +			{DVBT_MGD_THD1,				0x20	},
> +			{DVBT_MGD_THD2,				0x20	},
> +			{DVBT_MGD_THD3,				0x40	},
> +			{DVBT_MGD_THD4,				0x22	},
> +			{DVBT_MGD_THD5,				0x32	},
> +			{DVBT_MGD_THD6,				0x37	},
> +			{DVBT_MGD_THD7,				0x39	},
> +			{DVBT_EN_BK_TRK,			0x0		},
> +			{DVBT_EN_CACQ_NOTCH,		0x0		},
> +			{DVBT_AD_AV_REF,			0x2a	},
> +			{DVBT_REG_PI,				0x6		},
> +			{DVBT_PIP_ON,				0x0		},
> +			{DVBT_CDIV_PH0,				0x8		},
> +			{DVBT_CDIV_PH1,				0x8		},
> +			{DVBT_SCALE1_B92,			0x4		},
> +			{DVBT_SCALE1_B93,			0xb0	},
> +			{DVBT_SCALE1_BA7,			0x78	},
> +			{DVBT_SCALE1_BA9,			0x28	},
> +			{DVBT_SCALE1_BAA,			0x59	},
> +			{DVBT_SCALE1_BAB,			0x83	},
> +			{DVBT_SCALE1_BAC,			0xd4	},
> +			{DVBT_SCALE1_BB0,			0x65	},
> +			{DVBT_SCALE1_BB1,			0x43	},
> +			{DVBT_KB_P1,				0x1		},
> +			{DVBT_KB_P2,				0x4		},
> +			{DVBT_KB_P3,				0x7		},
> +			{DVBT_K1_CR_STEP12,			0xa		},
> +			{DVBT_REG_GPE,				0x1		},
> +			{DVBT_SERIAL,				0x0},
> +			{DVBT_CDIV_PH0,				0x9},
> +			{DVBT_CDIV_PH1,				0x9},
> +			{DVBT_MPEG_IO_OPT_2_2,		0x0},
> +			{DVBT_MPEG_IO_OPT_1_0,		0x0},
> +			{DVBT_TRK_KS_P2,			0x4},
> +			{DVBT_TRK_KS_I2,			0x7},
> +			{DVBT_TR_THD_SET2,			0x6},
> +			{DVBT_TRK_KC_I2,			0x5},
> +			{DVBT_CR_THD_SET2,			0x1},
> +
> +
> +		};
> +
> +	static rtl2832_reg_value rtl2832_initial_regs_2[] = {
> +			{DVBT_SPEC_INV,				0x0},
> +			{DVBT_DAGC_TRG_VAL,			0x5a	},
> +			{DVBT_AGC_TARG_VAL_0,		0x0		},
> +			{DVBT_AGC_TARG_VAL_8_1,		0x5a	},
> +			{DVBT_AAGC_LOOP_GAIN,		0x16    },
> +			{DVBT_LOOP_GAIN2_3_0,		0x6		},
> +			{DVBT_LOOP_GAIN2_4,			0x1		},
> +			{DVBT_LOOP_GAIN3,			0x16	},
> +			{DVBT_VTOP1,				0x35	},
> +			{DVBT_VTOP2,				0x21	},
> +			{DVBT_VTOP3,				0x21	},
> +			{DVBT_KRF1,					0x0		},
> +			{DVBT_KRF2,					0x40	},
> +			{DVBT_KRF3,					0x10	},
> +			{DVBT_KRF4,					0x10	},
> +			{DVBT_IF_AGC_MIN,			0x80	},
> +			{DVBT_IF_AGC_MAX,			0x7f	},
> +			{DVBT_RF_AGC_MIN,			0x80	},
> +			{DVBT_RF_AGC_MAX,			0x7f	},
> +			{DVBT_POLAR_RF_AGC,			0x0		},
> +			{DVBT_POLAR_IF_AGC,			0x0		},
> +			{DVBT_AD7_SETTING,			0xe9bf	},
> +			{DVBT_EN_GI_PGA,			0x0		},
> +			{DVBT_THD_LOCK_UP,			0x0		},
> +			{DVBT_THD_LOCK_DW,			0x0		},
> +			{DVBT_THD_UP1,				0x11	},
> +			{DVBT_THD_DW1,				0xef	},
> +			{DVBT_INTER_CNT_LEN,		0xc		},
> +			{DVBT_GI_PGA_STATE,			0x0		},
> +			{DVBT_EN_AGC_PGA,			0x1		},
> +			{DVBT_IF_AGC_MAN,			0x0		},
> +		};
> +
> +
> +	info("%s", __func__);
> +
> +	en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
> +
> +	/* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) /
> CrystalFreqHz) */
> +	pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
> +	pset_iffreq *= 0x400000;
> +	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
> +	pset_iffreq = pset_iffreq & 0x3fffff;
> +
> +
> +
> +	for (i = 0; i < 42; i++) {
> +		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_1[i].reg,
> rtl2832_initial_regs_1[i].value);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	/* if frequency settings */
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
> +		if (ret)
> +			goto err;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
> +		if(ret)
> +			goto err;
> +
> +	for (i = 0; i < 31; i++) {
> +		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_2[i].reg,
> rtl2832_initial_regs_2[i].value);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	priv->sleeping = false;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +}
> +
> +static int rtl2832_sleep(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	info("%s", __func__);
> +	priv->sleeping = true;
> +	return 0;
> +}
> +
> +int rtl2832_get_tune_settings(struct dvb_frontend *fe,
> +	struct dvb_frontend_tune_settings *s)
> +{
> +	info("%s", __func__);
> +	s->min_delay_ms = 1000;
> +	s->step_size = fe->ops.info.frequency_stepsize * 2;
> +	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
> +	return 0;
> +}
> +
> +static int rtl2832_set_frontend(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +	int ret, i, j;
> +	u64 bw_mode, num, num2;
> +	u32 resamp_ratio, cfreq_off_ratio;
> +
> +
> +	static u8 bw_params[3][32] = {
> +		/* 6 MHz bandwidth */
> +		{
> +			0xf5,	0xff,	0x15,	0x38,	0x5d,	0x6d,	0x52,	0x07,	0xfa,	0x2f,
> +			0x53,	0xf5,	0x3f,	0xca,	0x0b,	0x91,	0xea,	0x30,	0x63,	0xb2,
> +			0x13,	0xda,	0x0b,	0xc4,	0x18,	0x7e,	0x16,	0x66,	0x08,	0x67,
> +			0x19,	0xe0,
> +		},
> +
> +		/*  7 MHz bandwidth */
> +		{
> +			0xe7,	0xcc,	0xb5,	0xba,	0xe8,	0x2f,	0x67,	0x61,	0x00,	0xaf,
> +			0x86,	0xf2,	0xbf,	0x59,	0x04,	0x11,	0xb6,	0x33,	0xa4,	0x30,
> +			0x15,	0x10,	0x0a,	0x42,	0x18,	0xf8,	0x17,	0xd9,	0x07,	0x22,
> +			0x19,	0x10,
> +		},
> +
> +		/*  8 MHz bandwidth */
> +		{
> +			0x09,	0xf6,	0xd2,	0xa7,	0x9a,	0xc9,	0x27,	0x77,	0x06,	0xbf,
> +			0xec,	0xf4,	0x4f,	0x0b,	0xfc,	0x01,	0x63,	0x35,	0x54,	0xa7,
> +			0x16,	0x66,	0x08,	0xb4,	0x19,	0x6e,	0x19,	0x65,	0x05,	0xc8,
> +			0x19,	0xe0,
> +		},
> +	};
> +
> +
> +	info("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
> +			c->frequency, c->bandwidth_hz, c->inversion);
> +
> +
> +	/* program tuner */
> +	if (fe->ops.tuner_ops.set_params)
> +		fe->ops.tuner_ops.set_params(fe);
> +
> +
> +	switch (c->bandwidth_hz) {
> +		case 6000000:
> +			i = 0;
> +			bw_mode = 48000000;
> +			break;
> +		case 7000000:
> +			i = 1;
> +			bw_mode = 56000000;
> +			break;
> +		case 8000000:
> +			i = 2;
> +			bw_mode = 64000000;
> +			break;
> +		default:
> +			dbg("invalid bandwidth");
> +			return -EINVAL;
> +		}
> +
> +	for (j = 0; j < 32; j++){
> +		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	/* calculate and set resample ratio */
> +	/* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) /
> ConstWithBandwidthMode) */
> +	num = priv->cfg.xtal * 7;
> +	num *= 0x400000;
> +	num = div_u64(num, bw_mode);
> +	resamp_ratio =  num & 0x3ffffff;
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
> +	if (ret)
> +		goto err;
> +
> +	/* calculate and set cfreq off ratio */
> +	/* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20) /
> (CrystalFreqHz * 7)) */
> +	num = bw_mode << 20;
> +	num2 = priv->cfg.xtal * 7;
> +	num = div_u64(num, num2);
> +	num = -num;
> +	cfreq_off_ratio = num & 0xfffff;
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
> +	if (ret)
> +		goto err;
> +
> +
> +	/* soft reset */
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
> +	if (ret)
> +		goto err;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
> +	if (ret)
> +		goto err;
> +
> +	return ret;
> +err:
> +	info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	int ret;
> +	u32 tmp;
> +	*status = 0;
> +
> +
> +	info("%s", __func__);
> +	if (priv->sleeping)
> +		return 0;
> +
> +	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
> +	if (ret)
> +		goto err;
> +
> +	if (tmp == 11) {
> +		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
> +			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +	}
> +	/* TODO find out if this is also true */
> +	/*else if (tmp == 10) {
> +		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
> +			FE_HAS_VITERBI;
> +	}*/
> +
> +	return ret;
> +err:
> +	info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
> +{
> +	info("%s", __func__);
> +	*snr = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
> +{
> +	info("%s", __func__);
> +	*ber = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +	info("%s", __func__);
> +	*ucblocks = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
> +{
> +	info("%s", __func__);
> +	*strength = 0;
> +	return 0;
> +}
> +
> +static struct dvb_frontend_ops rtl2832_ops;
> +
> +static void rtl2832_release(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	info("%s", __func__);
> +	kfree(priv);
> +}
> +
> +struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
> +	struct i2c_adapter *i2c, u8 tuner)
> +{
> +	struct rtl2832_priv *priv = NULL;
> +	int ret = 0;
> +	u8 tmp;
> +
> +	info("%s", __func__);
> +
> +	/* allocate memory for the internal state */
> +	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
> +	if (priv == NULL)
> +		goto err;
> +
> +	/* setup the priv */
> +	priv->i2c = i2c;
> +	priv->tuner = tuner;
> +	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
> +
> +	/* check if the demod is there */
> +	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
> +	if (ret)
> +		goto err;
> +
> +	/* create dvb_frontend */
> +	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
> +	priv->fe.demodulator_priv = priv;
> +
> +	/* TODO implement sleep mode depending on RC */
> +	priv->sleeping = true;
> +
> +	return &priv->fe;
> +err:
> +	dbg("%s: failed=%d", __func__, ret);
> +	kfree(priv);
> +	return NULL;
> +}
> +EXPORT_SYMBOL(rtl2832_attach);
> +
> +static struct dvb_frontend_ops rtl2832_ops = {
> +	.delsys = { SYS_DVBT },
> +	.info = {
> +		.name = "Realtek RTL2832 (DVB-T)",
> +		.type               = FE_OFDM,
> +		.frequency_min      = 50000000,
> +		.frequency_max      = 862000000,
> +		.frequency_stepsize = 166667,
> +		.caps = FE_CAN_FEC_1_2 |
> +			FE_CAN_FEC_2_3 |
> +			FE_CAN_FEC_3_4 |
> +			FE_CAN_FEC_5_6 |
> +			FE_CAN_FEC_7_8 |
> +			FE_CAN_FEC_AUTO |
> +			FE_CAN_QPSK |
> +			FE_CAN_QAM_16 |
> +			FE_CAN_QAM_64 |
> +			FE_CAN_QAM_AUTO |
> +			FE_CAN_TRANSMISSION_MODE_AUTO |
> +			FE_CAN_GUARD_INTERVAL_AUTO |
> +			FE_CAN_HIERARCHY_AUTO |
> +			FE_CAN_RECOVER |
> +			FE_CAN_MUTE_TS
> +	},
> +
> +	.release = rtl2832_release,
> +
> +	.init = rtl2832_init,
> +	.sleep = rtl2832_sleep,
> +
> +	.get_tune_settings = rtl2832_get_tune_settings,
> +
> +	.set_frontend = rtl2832_set_frontend,
> +
> +	.read_status = rtl2832_read_status,
> +	.read_snr = rtl2832_read_snr,
> +	.read_ber = rtl2832_read_ber,
> +	.read_ucblocks = rtl2832_read_ucblocks,
> +	.read_signal_strength = rtl2832_read_signal_strength,
> +	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
> +};
> +
> +MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
> +MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("0.1");
> diff --git a/drivers/media/dvb/frontends/rtl2832.h
> b/drivers/media/dvb/frontends/rtl2832.h
> new file mode 100644
> index 0000000..b16631a
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832.h
> @@ -0,0 +1,300 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    This program is free software; you can redistribute it and/or modify
> + *    it under the terms of the GNU General Public License as published by
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License along
> + *    with this program; if not, write to the Free Software Foundation, Inc.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#ifndef RTL2832_H
> +#define RTL2832_H
> +
> +#include <linux/dvb/frontend.h>
> +
> +struct rtl2832_config {
> +	/*
> +	 * Demodulator I2C address.
> +	 */
> +	u8 i2c_addr;
> +
> +	/*
> +	 * Xtal frequency.
> +	 * Hz
> +	 * 4000000, 16000000, 25000000, 28800000
> +	 */
> +	u32 xtal;
> +
> +	/*
> +	 * IFs for all used modes.
> +	 * Hz
> +	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
> +	 */
> +	u32 if_dvbt;
> +
> +	/*
> +	 */
> +	u8 tuner;
> +};
> +
> +
> +#if defined(CONFIG_DVB_RTL2832) || \
> +	(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *rtl2832_attach(
> +	const struct rtl2832_config *cfg,
> +	struct i2c_adapter *i2c,
> +	u8 tuner
> +);
> +
> +extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
> +	struct dvb_frontend *fe
> +);
> +#else
> +static inline struct dvb_frontend *rtl2832_attach(
> +	const struct rtl2832_config *config,
> +	struct i2c_adapter *i2c
> +)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +
> +static inline struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
> +	struct dvb_frontend *fe
> +)
> +{
> +	return NULL;
> +}
> +#endif
> +
> +
> +/* Demod register bit names */
> +enum DVBT_REG_BIT_NAME
> +{
> +	DVBT_SOFT_RST,
> +	DVBT_IIC_REPEAT,
> +	DVBT_TR_WAIT_MIN_8K,
> +	DVBT_RSD_BER_FAIL_VAL,
> +	DVBT_EN_BK_TRK,
> +	DVBT_REG_PI,
> +	DVBT_REG_PFREQ_1_0,
> +	DVBT_PD_DA8,
> +	DVBT_LOCK_TH,
> +	DVBT_BER_PASS_SCAL,
> +	DVBT_CE_FFSM_BYPASS,
> +	DVBT_ALPHAIIR_N,
> +	DVBT_ALPHAIIR_DIF,
> +	DVBT_EN_TRK_SPAN,
> +	DVBT_LOCK_TH_LEN,
> +	DVBT_CCI_THRE,
> +	DVBT_CCI_MON_SCAL,
> +	DVBT_CCI_M0,
> +	DVBT_CCI_M1,
> +	DVBT_CCI_M2,
> +	DVBT_CCI_M3,
> +	DVBT_SPEC_INIT_0,
> +	DVBT_SPEC_INIT_1,
> +	DVBT_SPEC_INIT_2,
> +	DVBT_AD_EN_REG,
> +	DVBT_AD_EN_REG1,
> +	DVBT_EN_BBIN,
> +	DVBT_MGD_THD0,
> +	DVBT_MGD_THD1,
> +	DVBT_MGD_THD2,
> +	DVBT_MGD_THD3,
> +	DVBT_MGD_THD4,
> +	DVBT_MGD_THD5,
> +	DVBT_MGD_THD6,
> +	DVBT_MGD_THD7,
> +	DVBT_EN_CACQ_NOTCH,
> +	DVBT_AD_AV_REF,	
> +	DVBT_PIP_ON,
> +	DVBT_SCALE1_B92,
> +	DVBT_SCALE1_B93,
> +	DVBT_SCALE1_BA7,
> +	DVBT_SCALE1_BA9,
> +	DVBT_SCALE1_BAA,
> +	DVBT_SCALE1_BAB,
> +	DVBT_SCALE1_BAC,
> +	DVBT_SCALE1_BB0,
> +	DVBT_SCALE1_BB1,
> +	DVBT_KB_P1,
> +	DVBT_KB_P2,
> +	DVBT_KB_P3,
> +	DVBT_OPT_AD
> +	DVBT_AD_AVI
> +	DVBT_AD_AVQ
> +	DVBT_K1_CR_STEP12,
> +	DVBT_TRK_KS_P2,
> +	DVBT_TRK_KS_I2,
> +	DVBT_TR_THD_SET2,
> +	DVBT_TRK_KC_P2,
> +	DVBT_TRK_KC_I2,
> +	DVBT_CR_THD_SET2,
> +	DVBT_PSET_IFFREQ,
> +	DVBT_SPEC_INV,
> +	DVBT_BW_INDEX,
> +	DVBT_RSAMP_RATIO,
> +	DVBT_CFREQ_OFF_RATIO,
> +	DVBT_FSM_STAGE,
> +	DVBT_RX_CONSTEL,
> +	DVBT_RX_HIER,
> +	DVBT_RX_C_RATE_LP,
> +	DVBT_RX_C_RATE_HP,
> +	DVBT_GI_IDX,
> +	DVBT_FFT_MODE_IDX,
> +	DVBT_RSD_BER_EST,
> +	DVBT_CE_EST_EVM,
> +	DVBT_RF_AGC_VAL,
> +	DVBT_IF_AGC_VAL,
> +	DVBT_DAGC_VAL,
> +	DVBT_SFREQ_OFF,
> +	DVBT_CFREQ_OFF,
> +	DVBT_POLAR_RF_AGC,
> +	DVBT_POLAR_IF_AGC,
> +	DVBT_AAGC_HOLD,
> +	DVBT_EN_RF_AGC,
> +	DVBT_EN_IF_AGC,
> +	DVBT_IF_AGC_MIN,
> +	DVBT_IF_AGC_MAX,
> +	DVBT_RF_AGC_MIN,
> +	DVBT_RF_AGC_MAX,
> +	DVBT_IF_AGC_MAN,
> +	DVBT_IF_AGC_MAN_VAL,
> +	DVBT_RF_AGC_MAN,
> +	DVBT_RF_AGC_MAN_VAL,
> +	DVBT_DAGC_TRG_VAL,
> +	DVBT_AGC_TARG_VAL,
> +	DVBT_LOOP_GAIN_3_0,
> +	DVBT_LOOP_GAIN_4,
> +	DVBT_VTOP,	
> +	DVBT_KRF,
> +	DVBT_AGC_TARG_VAL_0,
> +	DVBT_AGC_TARG_VAL_8_1,
> +	DVBT_AAGC_LOOP_GAIN,
> +	DVBT_LOOP_GAIN2_3_0,
> +	DVBT_LOOP_GAIN2_4,
> +	DVBT_LOOP_GAIN3,
> +	DVBT_VTOP1,
> +	DVBT_VTOP2,
> +	DVBT_VTOP3,
> +	DVBT_KRF1,
> +	DVBT_KRF2,
> +	DVBT_KRF3,
> +	DVBT_KRF4,
> +	DVBT_EN_GI_PGA,
> +	DVBT_THD_LOCK_UP,
> +	DVBT_THD_LOCK_DW,
> +	DVBT_THD_UP1,
> +	DVBT_THD_DW1,
> +	DVBT_INTER_CNT_LEN,
> +	DVBT_GI_PGA_STATE,
> +	DVBT_EN_AGC_PGA,
> +	DVBT_CKOUTPAR,
> +	DVBT_CKOUT_PWR,
> +	DVBT_SYNC_DUR,
> +	DVBT_ERR_DUR,
> +	DVBT_SYNC_LVL,
> +	DVBT_ERR_LVL,
> +	DVBT_VAL_LVL,
> +	DVBT_SERIAL,
> +	DVBT_SER_LSB,
> +	DVBT_CDIV_PH0,
> +	DVBT_CDIV_PH1,
> +	DVBT_MPEG_IO_OPT_2_2,
> +	DVBT_MPEG_IO_OPT_1_0,
> +	DVBT_CKOUTPAR_PIP,
> +	DVBT_CKOUT_PWR_PIP,
> +	DVBT_SYNC_LVL_PIP,
> +	DVBT_ERR_LVL_PIP,
> +	DVBT_VAL_LVL_PIP,
> +	DVBT_CKOUTPAR_PID,
> +	DVBT_CKOUT_PWR_PID,
> +	DVBT_SYNC_LVL_PID,
> +	DVBT_ERR_LVL_PID,
> +	DVBT_VAL_LVL_PID,
> +	DVBT_SM_PASS,
> +	DVBT_UPDATE_REG_2,
> +	DVBT_BTHD_P3,
> +	DVBT_BTHD_D3,
> +	DVBT_FUNC4_REG0,
> +	DVBT_FUNC4_REG1,
> +	DVBT_FUNC4_REG2,
> +	DVBT_FUNC4_REG3,
> +	DVBT_FUNC4_REG4,
> +	DVBT_FUNC4_REG5,
> +	DVBT_FUNC4_REG6,
> +	DVBT_FUNC4_REG7,
> +	DVBT_FUNC4_REG8,
> +	DVBT_FUNC4_REG9,
> +	DVBT_FUNC4_REG10,
> +	DVBT_FUNC5_REG0,
> +	DVBT_FUNC5_REG1,
> +	DVBT_FUNC5_REG2,
> +	DVBT_FUNC5_REG3,
> +	DVBT_FUNC5_REG4,
> +	DVBT_FUNC5_REG5,
> +	DVBT_FUNC5_REG6,
> +	DVBT_FUNC5_REG7,
> +	DVBT_FUNC5_REG8,
> +	DVBT_FUNC5_REG9,
> +	DVBT_FUNC5_REG10,
> +	DVBT_FUNC5_REG11,
> +	DVBT_FUNC5_REG12,
> +	DVBT_FUNC5_REG13,
> +	DVBT_FUNC5_REG14,
> +	DVBT_FUNC5_REG15,
> +	DVBT_FUNC5_REG16,
> +	DVBT_FUNC5_REG17,
> +	DVBT_FUNC5_REG18,
> +	DVBT_AD7_SETTING,
> +	DVBT_RSSI_R,
> +	DVBT_ACI_DET_IND,
> +	DVBT_REG_MON,
> +	DVBT_REG_MONSEL,
> +	DVBT_REG_GPE,
> +	DVBT_REG_GPO,
> +	DVBT_REG_4MSEL,
> +	DVBT_TEST_REG_1,
> +	DVBT_TEST_REG_2,
> +	DVBT_TEST_REG_3,
> +	DVBT_TEST_REG_4,
> +	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
> +};
> +
> +
> +/* Register table length */
> +#define RTL2832_REG_TABLE_LEN	DVBT_REG_BIT_NAME_ITEM_TERMINATOR
> +
> +typedef struct
> +{
> +	u8 page;
> +	u8 start_address;
> +	u8 msb;
> +	u8 lsb;
> +}
> +rtl2832_reg_entry;
> +
> +typedef struct
> +{
> +	int reg;
> +	u32 value;
> +}
> +rtl2832_reg_value;
> +
> +
> +
> +
> +
> +#endif /* RTL2832_H */
> diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h
> b/drivers/media/dvb/frontends/rtl2832_priv.h
> new file mode 100644
> index 0000000..2f591c6
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832_priv.h
> @@ -0,0 +1,60 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    This program is free software; you can redistribute it and/or modify
> + *    it under the terms of the GNU General Public License as published by
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License along
> + *    with this program; if not, write to the Free Software Foundation, Inc.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#ifndef RTL2832_PRIV_H
> +#define RTL2832_PRIV_H
> +
> +#include "dvb_frontend.h"
> +#include "rtl2832.h"
> +
> +#define LOG_PREFIX "rtl2832"
> +
> +#undef dbg
> +#define dbg(f, arg...) \
> +	if (rtl2832_debug) \
> +		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
> +#undef err
> +#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
> +#undef info
> +#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
> +#undef warn
> +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
> +
> +struct rtl2832_priv {
> +	struct i2c_adapter *i2c;
> +	struct dvb_frontend fe;
> +	struct rtl2832_config cfg;
> +
> +	bool i2c_gate_state;
> +	bool sleeping;
> +
> +	u32 xtal;
> +
> +	u8 tuner;
> +	u8 page; /* active register page */
> +};
> +
> +struct rtl2832_reg_val_mask {
> +	u16 reg;
> +	u8  val;
> +	u8  mask;
> +};
> +
> +#endif /* RTL2832_PRIV_H */

Antti, Thomas - thanks!

Please merge these two patches for device:
-DeLOCK USB 2.0 DVB-T Receiver 61744
http://www.delock.com/produkte/gruppen/Multimedia/Delock_USB_20_DVB-T_Receiver_61744.html

lsusb:
..
Bus 002 Device 005: ID 1f4d:b803 G-Tek Electronics Group Lifeview
LV5TDLX DVB-T [RTL2832U]
..

modinfo dvb_usb_rtl28xxu:
filename:
/lib/modules/3.3.2-6.fc16.x86_64/kernel/drivers/media/dvb/dvb-usb/dvb-usb-rtl28xxu.ko
license:        GPL
author:         Thomas Mair <thomas.mair86@googlemail.com>
author:         Antti Palosaari <crope@iki.fi>
description:    Realtek RTL28xxU DVB USB driver
alias:          usb:v1F4DpB803d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0CCDp00A9d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v14AAp0161d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v14AAp0160d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0BDAp2831d*dc*dsc*dp*ic*isc*ip*
depends:        dvb-usb,rtl2830,rc-core
vermagic:       3.3.2-6.fc16.x86_64 SMP mod_unload
parm:           debug:set debugging level (int)
parm:           adapter_nr:DVB adapter numbers (array of short)

dmesg:
..
usb 2-3: new high-speed USB device number 5 using ehci_hcd
usb 2-3: New USB device found, idVendor=1f4d, idProduct=b803
usb 2-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
usb 2-3: Product: RTL2838UHIDIR
usb 2-3: Manufacturer: Realtek
usb 2-3: SerialNumber: 00000041
dvb-usb: found a 'G-Tek Electronics Group Lifeview LV5TDLX DVB-T
[RTL2832U]' in warm state.
dvb-usb: will pass the complete MPEG2 transport stream to the software
demuxer.
DVB: registering new adapter (G-Tek Electronics Group Lifeview LV5TDLX
DVB-T [RTL2832U])
rtl2832: rtl2832_attach
DVB: registering adapter 2 frontend 0 (Realtek RTL2832 (DVB-T))...
fc0012: Fitipower FC0012 successfully attached.
dvb-usb: G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]
successfully initialized and connected.
..

lsdvb:

		lsdvb: Simple utility to list PCI/PCIe DVB devices
		Version: 0.0.4
		Copyright (C) Manu Abraham

usb (1:0 -1186842560:58) on PCI Domain:-7907219 Bus:0 Device:-1189043773
Function:58
	..
	DEVICE:0 ADAPTER:2 FRONTEND:0 (Realtek RTL2832 (DVB-T))
		 FE_OFDM Fmin=170MHz Fmax=860MHz


rgds,
poma

[-- Attachment #2: dvb-usb-ids-1f4d_b803.patch --]
[-- Type: text/x-patch, Size: 526 bytes --]

--- media_build/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	2012-04-30 10:40:01.848792922 +0200
+++ media_build-gtek/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h	2012-04-30 09:44:51.353128972 +0200
@@ -135,6 +135,7 @@
 #define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
+#define USB_PID_GTEK					0xb803
 #define USB_PID_INTEL_CE9500				0x9500
 #define USB_PID_ITETECH_IT9135				0x9135
 #define USB_PID_ITETECH_IT9135_9005			0x9005

[-- Attachment #3: rtl28xxu-1f4d_b803.patch --]
[-- Type: text/x-patch, Size: 1039 bytes --]

--- media_build/linux/drivers/media/dvb/dvb-usb/rtl28xxu.c	2012-04-30 10:40:01.891790279 +0200
+++ media_build-gtek/linux/drivers/media/dvb/dvb-usb/rtl28xxu.c	2012-04-30 11:00:16.701619034 +0200
@@ -1051,6 +1051,7 @@
 	RTL2831U_14AA_0160,
 	RTL2831U_14AA_0161,
 	RTL2832U_0CCD_00A9,
+	RTL2832U_1F4D_B803,
 };
 
 static struct usb_device_id rtl28xxu_table[] = {
@@ -1065,6 +1066,8 @@
 	/* RTL2832U */
 	[RTL2832U_0CCD_00A9] = {
 		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
+	[RTL2832U_1F4D_B803] = {
+		USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
 	{} /* terminating entry */
 };
 
@@ -1178,7 +1181,7 @@
 
 		.i2c_algo = &rtl28xxu_i2c_algo,
 
-		.num_device_descs = 1,
+		.num_device_descs = 2,
 		.devices = {
 			{
 				.name = "Terratec Cinergy T Stick Black",
@@ -1186,6 +1189,12 @@
 					&rtl28xxu_table[RTL2832U_0CCD_00A9],
 				},
 			},
+			{
+				.name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1F4D_B803],
+				},
+			},
 		}
 	},
 

^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-04-30  9:38 ` poma
@ 2012-04-30 15:39   ` Thomas Mair
  2012-05-01  6:48     ` poma
  0 siblings, 1 reply; 16+ messages in thread
From: Thomas Mair @ 2012-04-30 15:39 UTC (permalink / raw)
  To: pomidorabelisima; +Cc: Thomas Mair, Linux Media Mailing List

Signed-off-by: Thomas Mair <thomas.mair86@googlemail.com>
---
 drivers/media/common/tuners/Kconfig        |    7 +
 drivers/media/common/tuners/Makefile       |    1 +
 drivers/media/common/tuners/fc0012-priv.h  |   42 ++
 drivers/media/common/tuners/fc0012.c       |  384 +++++++++++++
 drivers/media/common/tuners/fc0012.h       |   60 ++
 drivers/media/dvb/dvb-usb/Kconfig          |    2 +
 drivers/media/dvb/dvb-usb/dvb-usb-ids.h    |    2 +
 drivers/media/dvb/dvb-usb/rtl28xxu.c       |  439 +++++++++++++---
 drivers/media/dvb/frontends/Kconfig        |    7 +
 drivers/media/dvb/frontends/Makefile       |    2 +-
 drivers/media/dvb/frontends/rtl2832.c      |  832 ++++++++++++++++++++++++++++
 drivers/media/dvb/frontends/rtl2832.h      |  300 ++++++++++
 drivers/media/dvb/frontends/rtl2832_priv.h |   60 ++
 13 files changed, 2070 insertions(+), 68 deletions(-)
 create mode 100644 drivers/media/common/tuners/fc0012-priv.h
 create mode 100644 drivers/media/common/tuners/fc0012.c
 create mode 100644 drivers/media/common/tuners/fc0012.h
 create mode 100644 drivers/media/dvb/frontends/rtl2832.c
 create mode 100644 drivers/media/dvb/frontends/rtl2832.h
 create mode 100644 drivers/media/dvb/frontends/rtl2832_priv.h

diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 0fd15d9..8518251 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -211,6 +211,13 @@ config MEDIA_TUNER_FC0011
 	help
 	  Fitipower FC0011 silicon tuner driver.
 
+config MEDIA_TUNER_FC0012
+	tristate "Fitipower FC0012 silicon tuner"
+	depends on VIDEO_MEDIA && I2C
+	default m if MEDIA_TUNER_CUSTOMISE
+	help
+	  Fitipower FC0012 silicon tuner driver.
+
 config MEDIA_TUNER_TDA18212
 	tristate "NXP TDA18212 silicon tuner"
 	depends on VIDEO_MEDIA && I2C
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index 64ee06f..f046106 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
 obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
 obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
 obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
+obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
 
 ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
 ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/fc0012-priv.h b/drivers/media/common/tuners/fc0012-priv.h
new file mode 100644
index 0000000..c2c3c47
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012-priv.h
@@ -0,0 +1,42 @@
+/*
+ * Fitipower FC0012 tuner driver - private includes
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_PRIV_H_
+#define _FC0012_PRIV_H_
+
+#define LOG_PREFIX "fc0012"
+
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct fc0012_priv {
+       struct i2c_adapter *i2c;
+       u8 addr;
+       u8 xtal_freq;
+
+       u32 frequency;
+       u32 bandwidth;
+};
+
+#endif
diff --git a/drivers/media/common/tuners/fc0012.c b/drivers/media/common/tuners/fc0012.c
new file mode 100644
index 0000000..bb9f008
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.c
@@ -0,0 +1,384 @@
+/*
+ * Fitipower FC0012 tuner driver
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "fc0012.h"
+#include "fc0012-priv.h"
+
+static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
+{
+	u8 buf[2] = {reg, val};
+	struct i2c_msg msg = { .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 };
+
+	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
+		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
+	return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
+{
+	struct i2c_msg msg[2] = {
+		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
+		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
+	};
+
+	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
+		err("I2C read failed, reg: %02x", reg);
+		return -EREMOTEIO;
+	}
+	return 0;
+}
+
+static int fc0012_release(struct dvb_frontend *fe)
+{
+	kfree(fe->tuner_priv);
+	fe->tuner_priv = NULL;
+	return 0;
+}
+
+static int fc0012_init(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	unsigned char reg[] = {
+		0x00,   /* dummy reg. 0 */
+		0x05,   /* reg. 0x01 */
+		0x10,   /* reg. 0x02 */
+		0x00,   /* reg. 0x03 */
+		0x00,   /* reg. 0x04 */
+		0x0f,   /* reg. 0x05 CHECK: correct? */ /* this is 0x0f in RTL (CNR test) */
+		0x00,   /* reg. 0x06: divider 2, VCO slow */
+		0x00,   /* reg. 0x07 */ /* this is also different in RTL code */
+		0xff,   /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
+			   Loop Bw 1/8 */
+		0x6e,   /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
+		0xb8,   /* reg. 0x0a: Disable LO Test Buffer */
+		0x82,   /* reg. 0x0b: Output Clock is same as clock frequency */ /* also different in RTL*/
+		0xfc,   /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ /* RTL */
+		0x02,   /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
+		0x00,   /* reg. 0x0e */
+		0x00,   /* reg. 0x0f */
+		0x00,   /* reg. 0x10 */ /* RTL */
+		0x00,   /* reg. 0x11 */
+		0x1f,   /* reg. 0x12: Set to maximum gain */
+		0x08,   /* reg. 0x13: Enable IX2, Set to Middle Gain: 0x08,
+			   Low Gain: 0x00, High Gain: 0x10 */
+		0x00,   /* reg. 0x14 */
+		0x04,   /* reg. 0x15: Enable LNA COMPS */
+	};
+
+	info("%s", __func__);
+
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+	case FC_XTAL_28_8_MHZ:
+		reg[0x07] |= 0x20;
+		break;
+	case FC_XTAL_36_MHZ:
+	default:
+		break;
+	}
+	
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+	
+	for (i = 1; i < sizeof(reg); i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+	if (ret)
+		break;
+	}
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+	if (ret)
+		warn("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0012_sleep(struct dvb_frontend *fe)
+{
+	/* nothing to do here */
+	return 0;
+}
+
+static int fc0012_set_params(struct dvb_frontend *fe)
+{
+	struct fc0012_priv *priv = fe->tuner_priv;
+	int i, ret = 0;
+	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+	u32 freq = p->frequency / 1000;
+	u32 delsys = p->delivery_system;
+	unsigned char reg[0x16], am, pm, multi;
+	unsigned long fVCO;
+	unsigned short xtal_freq_khz_2, xin, xdiv;
+	int vco_select = false;
+
+	info("%s", __func__);
+
+	if(fe->callback){
+		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, FC0012_FE_CALLBACK_UHF_ENABLE, (freq > 300000 ? 0 : 1));
+		if (ret)
+			goto exit;
+	}
+	
+	switch (priv->xtal_freq) {
+	case FC_XTAL_27_MHZ:
+		xtal_freq_khz_2 = 27000 / 2;
+		break;
+	case FC_XTAL_36_MHZ:
+		xtal_freq_khz_2 = 36000 / 2;
+		break;
+	case FC_XTAL_28_8_MHZ:
+	default:
+		xtal_freq_khz_2 = 28800 / 2;
+		break;
+	}
+
+	/* select frequency divider and the frequency of VCO */
+	if (freq * 96 < 3560000) {
+		multi = 96;
+		reg[5] = 0x82;
+		reg[6] = 0x00;
+	} else if (freq * 64 < 3560000) {
+		multi = 64;
+		reg[5] = 0x82;
+		reg[6] = 0x02;
+	} else if (freq * 48 < 3560000) {
+		multi = 48;
+		reg[5] = 0x42;
+		reg[6] = 0x00;
+	} else if (freq * 32 < 3560000) {
+		multi = 32;
+		reg[5] = 0x42;
+		reg[6] = 0x02;
+	} else if (freq * 24 < 3560000) {
+		multi = 24;
+		reg[5] = 0x22;
+		reg[6] = 0x00;
+	} else if (freq * 16 < 3560000) {
+		multi = 16;
+		reg[5] = 0x22;
+		reg[6] = 0x02;
+	} else if (freq * 12 < 3560000) {
+		multi = 12;
+		reg[5] = 0x12;
+		reg[6] = 0x00;
+	} else if (freq * 8 < 3560000) {
+		multi = 8;
+		reg[5] = 0x12;
+		reg[6] = 0x02;
+	} else if (freq * 6 < 3560000) {
+		multi = 6;
+		reg[5] = 0x0a;
+		reg[6] = 0x00;
+	} else {
+		multi = 4;
+		reg[5] = 0x0a;
+		reg[6] = 0x02;
+	}
+
+	fVCO = freq * multi;
+	
+	reg[6] |= 0x08;
+	vco_select = true;
+
+	/* From divided value (XDIV) determined the FA and FP value */
+	xdiv = (unsigned short)(fVCO / xtal_freq_khz_2);
+	if ((fVCO - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
+		xdiv++;
+	
+	pm = (unsigned char)(xdiv / 8);
+	am = (unsigned char)(xdiv - (8 * pm));
+	
+	if (am < 2) {
+		reg[1] = am + 8;
+		reg[2] = pm - 1;
+	} else {
+		reg[1] = am;
+		reg[2] = pm;
+	}
+
+
+	/* From VCO frequency determines the XIN ( fractional part of Delta
+	Sigma PLL) and divided value (XDIV) */
+ 	xin = (unsigned short)(fVCO - (fVCO / xtal_freq_khz_2) * xtal_freq_khz_2);
+	xin = (xin << 15) / xtal_freq_khz_2;
+	if (xin >= 16384)
+		xin += 32768;
+
+	reg[3] = xin >> 8;      /* xin with 9 bit resolution */
+	reg[4] = xin & 0xff;
+
+	if (delsys == SYS_DVBT) {
+		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
+		switch (p->bandwidth_hz) {
+		case 6000000:
+			reg[6] |= 0x80;
+			break;
+		case 7000000:
+			reg[6] &= ~0x80;
+			reg[6] |= 0x40;
+			break;
+		case 8000000:
+		default:
+			reg[6] &= ~0xc0;
+			break;
+	}
+	} else {
+		err("%s: modulation type not supported!", __func__);
+		return -EINVAL;
+	}
+
+	/* modified for Realtek demod */
+	reg[5] |= 0x07;
+
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+	for (i = 1; i <= 6; i++) {
+		ret = fc0012_writereg(priv, i, reg[i]);
+		if (ret)
+			goto exit;
+       }
+
+	/* VCO Calibration */
+	ret = fc0012_writereg(priv, 0x0e, 0x80);
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	/* VCO Re-Calibration if needed */
+	if (!ret)
+		ret = fc0012_writereg(priv, 0x0e, 0x00);
+
+	if (!ret) {
+		msleep(10);
+		ret = fc0012_readreg(priv, 0x0e, &reg[0x0e]);
+	}
+	if (ret)
+		goto exit;
+
+	/* vco selection */
+	reg[0x0e] &= 0x3f;
+
+	if (vco_select) {
+		if (reg[0x0e] > 0x3c) {
+		reg[6] &= ~0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+		if (!ret)
+			ret = fc0012_writereg(priv, 0x0e, 0x80);
+		if (!ret)
+			ret = fc0012_writereg(priv, 0x0e, 0x00);
+	       }
+	} else {
+		if (reg[0x0e] < 0x02) {
+			reg[6] |= 0x08;
+			ret = fc0012_writereg(priv, 0x06, reg[6]);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x80);
+			if (!ret)
+				ret = fc0012_writereg(priv, 0x0e, 0x00);
+		}
+	}
+
+	priv->frequency = p->frequency;
+	priv->bandwidth = p->bandwidth_hz;
+
+exit:
+	if (fe->ops.i2c_gate_ctrl)
+		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+	if (ret)
+		pr_debug("%s: failed: %d", __func__, ret);
+	return ret;
+}
+
+static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       struct fc0012_priv *priv = fe->tuner_priv;
+       *frequency = priv->frequency;
+       return 0;
+}
+
+static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+       /* CHECK: always ? */
+       *frequency = 0;
+       return 0;
+}
+
+static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+       struct fc0012_priv *priv = fe->tuner_priv;
+       *bandwidth = priv->bandwidth;
+       return 0;
+}
+
+
+static const struct dvb_tuner_ops fc0012_tuner_ops = {
+       .info = {
+	       .name		= "Fitipower FC0012",
+
+	       .frequency_min	= 170000000,
+	       .frequency_max	= 860000000,
+	       .frequency_step	= 0,
+       },
+
+       .release	= fc0012_release,
+
+       .init = fc0012_init,
+       .sleep = fc0012_sleep,
+
+       .set_params = fc0012_set_params,
+
+       .get_frequency = fc0012_get_frequency,
+       .get_if_frequency = fc0012_get_if_frequency,
+       .get_bandwidth = fc0012_get_bandwidth,
+};
+
+struct dvb_frontend * fc0012_attach(struct dvb_frontend *fe,
+       struct i2c_adapter *i2c, u8 i2c_address,
+       enum fc0012_xtal_freq xtal_freq)
+{
+       struct fc0012_priv *priv = NULL;
+
+       priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
+       if (priv == NULL)
+	       return NULL;
+
+       priv->i2c = i2c;
+       priv->addr = i2c_address;
+       priv->xtal_freq = xtal_freq;
+
+       info("Fitipower FC0012 successfully attached.");
+
+       fe->tuner_priv = priv;
+
+       memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
+	       sizeof(struct dvb_tuner_ops));
+
+       return fe;
+}
+EXPORT_SYMBOL(fc0012_attach);
+
+MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
+MODULE_AUTHOR("Hans-Frieder Vogt <hfv...@gmx.net>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.4");
diff --git a/drivers/media/common/tuners/fc0012.h b/drivers/media/common/tuners/fc0012.h
new file mode 100644
index 0000000..1406e58
--- /dev/null
+++ b/drivers/media/common/tuners/fc0012.h
@@ -0,0 +1,60 @@
+/*
+ * Fitipower FC0012 tuner driver - include
+ *
+ * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _FC0012_H_
+#define _FC0012_H_
+
+#include "dvb_frontend.h"
+
+enum fc0012_xtal_freq {
+       FC_XTAL_27_MHZ,         /* 27000000 */
+       FC_XTAL_28_8_MHZ,       /* 28800000 */
+       FC_XTAL_36_MHZ,         /* 36000000 */
+};
+
+
+/** enum fc0011_fe_callback_commands - Frontend callbacks
+ *
+ * @FC0012_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
+ */
+enum fc0012_fe_callback_commands {
+	FC0012_FE_CALLBACK_UHF_ENABLE,
+};
+
+#define CONFIG_MEDIA_TUNER_FC0012
+
+#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
+        (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
+extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+                                       struct i2c_adapter *i2c,
+                                       u8 i2c_address,
+                                       enum fc0012_xtal_freq xtal_freq);
+#else
+static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
+                                               struct i2c_adapter *i2c,
+                                               u8 i2c_address,
+                                               enum fc0012_xtal_freq xtal_freq)
+{
+       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index be1db75..a24bbc1 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -417,9 +417,11 @@ config DVB_USB_RTL28XXU
 	tristate "Realtek RTL28xxU DVB USB support"
 	depends on DVB_USB && EXPERIMENTAL
 	select DVB_RTL2830
+	select DVB_RTL2832
 	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
 	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
+	select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
 	help
 	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
 
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 2418e41..1ffee60 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -135,6 +135,7 @@
 #define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
+#define USB_PID_GTEK					0xb803
 #define USB_PID_INTEL_CE9500				0x9500
 #define USB_PID_ITETECH_IT9135				0x9135
 #define USB_PID_ITETECH_IT9135_9005			0x9005
@@ -238,6 +239,7 @@
 #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
 #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
 #define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
+#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK		0x00a9
 #define USB_PID_TERRATEC_H7				0x10b4
 #define USB_PID_TERRATEC_H7_2				0x10a3
 #define USB_PID_TERRATEC_T3				0x10a0
diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
index 8f4736a..1999c17 100644
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
  * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
  *
  *    This program is free software; you can redistribute it and/or modify
  *    it under the terms of the GNU General Public License as published by
@@ -22,10 +23,12 @@
 #include "rtl28xxu.h"
 
 #include "rtl2830.h"
+#include "rtl2832.h"
 
 #include "qt1010.h"
 #include "mt2060.h"
 #include "mxl5005s.h"
+#include "fc0012.h"
 
 /* debug */
 static int dvb_usb_rtl28xxu_debug;
@@ -76,7 +79,7 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
 
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
@@ -297,7 +300,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
 	/* for QT1010 tuner probe */
 	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
 
-	deb_info("%s:\n", __func__);
+	deb_info("%s:", __func__);
 
 	/*
 	 * RTL2831U GPIOs
@@ -312,6 +315,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
 	if (ret)
 		goto err;
 
+
 	/* enable as output GPIO0, GPIO2, GPIO4 */
 	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
 	if (ret)
@@ -332,10 +336,10 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
 	if (ret == 0 && buf[0] == 0x2c) {
 		priv->tuner = TUNER_RTL2830_QT1010;
 		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
-		deb_info("%s: QT1010\n", __func__);
+		deb_info("%s: QT1010", __func__);
 		goto found;
 	} else {
-		deb_info("%s: QT1010 probe failed=%d - %02x\n",
+		deb_info("%s: QT1010 probe failed=%d - %02x",
 			__func__, ret, buf[0]);
 	}
 
@@ -349,10 +353,10 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
 	if (ret == 0 && buf[0] == 0x63) {
 		priv->tuner = TUNER_RTL2830_MT2060;
 		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
-		deb_info("%s: MT2060\n", __func__);
+		deb_info("%s: MT2060", __func__);
 		goto found;
 	} else {
-		deb_info("%s: MT2060 probe failed=%d - %02x\n",
+		deb_info("%s: MT2060 probe failed=%d - %02x",
 			__func__, ret, buf[0]);
 	}
 
@@ -360,7 +364,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
 	ret = 0;
 	priv->tuner = TUNER_RTL2830_MXL5005S;
 	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
-	deb_info("%s: MXL5005S\n", __func__);
+	deb_info("%s: MXL5005S", __func__);
 	goto found;
 
 found:
@@ -374,37 +378,130 @@ found:
 
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
+static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
+	.i2c_addr = 0x10, /* 0x20 */
+	.xtal = 28800000,
+	.ts_mode = 0,
+	.spec_inv = 1,
+	.if_dvbt = 0,
+	.vtop = 0x20,
+	.krf = 0x04,
+	.agc_targ_val = 0x2d,
+	.tuner = TUNER_RTL2832_FC0012
+};
+
+
+static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
+		int cmd, int arg)
+{
+	int ret;
+	u8 val;
+
+	info("%s cmd=%d arg=%d", __func__, cmd, arg);
+	switch (cmd) {
+	case FC0012_FE_CALLBACK_UHF_ENABLE:
+		/* set output values */
+
+		ret = rtl2831_rd_reg(d, SYS_GPIO_DIR, &val);
+		if (ret)
+			goto err;
+
+		val &= 0xbf;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_DIR, val);
+		if (ret)
+			goto err;
+
+
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x40;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
+		if (ret)
+			goto err;
+
+
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+			goto err;
+
+		if (arg)
+			val &= 0xbf; /* set GPIO6 low */
+		else
+			val |= 0x40; /* set GPIO6 high */
+		
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+		break;
+	default:
+		ret = -EINVAL;
+		goto err;
+	}
+	return 0;
+
+err:
+	err("%s: failed=%d", __func__, ret);
+
+	return ret;
+}
+
+static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
+{
+	struct rtl28xxu_priv *priv = d->priv;
+
+	switch (priv->tuner) {
+	case TUNER_RTL2832_FC0012:
+		return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -ENODEV;
+}
+
+static int rtl2832u_frontend_callback(void *adapter_priv, int component,
+				    int cmd, int arg)
+{
+	struct i2c_adapter *adap = adapter_priv;
+	struct dvb_usb_device *d = i2c_get_adapdata(adap);
+
+	switch (component) {
+	case DVB_FRONTEND_COMPONENT_TUNER:
+		return rtl2832u_tuner_callback(d, cmd, arg);
+	default:
+		break;
+	}
+
+	return -EINVAL;
+}
+
+
+
+
 static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	int ret;
 	struct rtl28xxu_priv *priv = adap->dev->priv;
+	struct rtl2832_config *rtl2832_config;
+
 	u8 buf[1];
 	/* open RTL2832U/RTL2832 I2C gate */
 	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
 	/* close RTL2832U/RTL2832 I2C gate */
 	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
-	/* for FC2580 tuner probe */
-	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
-
-	deb_info("%s:\n", __func__);
-
-	/* GPIO direction */
-	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
-	if (ret)
-		goto err;
+	/* for FC0012 tuner probe */
+	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
 
-	/* enable as output GPIO0, GPIO2, GPIO4 */
-	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
-	if (ret)
-		goto err;
-
-	ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
-	if (ret)
-		goto err;
+	deb_info("%s:", __func__);
 
 	/*
 	 * Probe used tuner. We need to know used tuner before demod attach
@@ -416,17 +513,20 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
 	if (ret)
 		goto err;
 
-	/* check FC2580 ID register; reg=01 val=56 */
-	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
-	if (ret == 0 && buf[0] == 0x56) {
-		priv->tuner = TUNER_RTL2832_FC2580;
-		deb_info("%s: FC2580\n", __func__);
+
+	/* check FC0012 ID register; reg=00 val=a1 */
+	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
+	if (ret == 0 && buf[0] == 0xa1) {
+		priv->tuner = TUNER_RTL2832_FC0012;
+		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
+		deb_info("%s: FC0012", __func__);
 		goto found;
 	} else {
-		deb_info("%s: FC2580 probe failed=%d - %02x\n",
+		deb_info("%s: FC0012 probe failed=%d - %02x",
 			__func__, ret, buf[0]);
 	}
 
+
 	/* close demod I2C gate */
 	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
 	if (ret)
@@ -443,11 +543,19 @@ found:
 		goto err;
 
 	/* attach demodulator */
-	/* TODO: */
+	adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
+		&adap->dev->i2c_adap, priv->tuner);
+		if (adap->fe_adap[0].fe == NULL) {
+			ret = -ENODEV;
+			goto err;
+		}
+
+	/* set fe callbacks */
+	adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;
 
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
@@ -484,7 +592,7 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
 	struct i2c_adapter *rtl2830_tuner_i2c;
 	struct dvb_frontend *fe;
 
-	deb_info("%s:\n", __func__);
+	deb_info("%s:", __func__);
 
 	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
 	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
@@ -515,7 +623,7 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
 
 	return 0;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
@@ -525,12 +633,13 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
 	struct rtl28xxu_priv *priv = adap->dev->priv;
 	struct dvb_frontend *fe;
 
-	deb_info("%s:\n", __func__);
+	deb_info("%s:", __func__);
 
 	switch (priv->tuner) {
-	case TUNER_RTL2832_FC2580:
-		/* TODO: */
-		fe = NULL;
+	case TUNER_RTL2832_FC0012:
+		fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
+			&adap->dev->i2c_adap, 0xc6>>1, FC_XTAL_28_8_MHZ);
+		return 0;
 		break;
 	default:
 		fe = NULL;
@@ -544,16 +653,16 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
 
 	return 0;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
-static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
 {
 	int ret;
 	u8 buf[2], gpio;
 
-	deb_info("%s: onoff=%d\n", __func__, onoff);
+	deb_info("%s: onoff=%d", __func__, onoff);
 
 	ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
 	if (ret)
@@ -579,16 +688,186 @@ static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
 
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
-static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
+{
+	int ret;
+	u8 buf[2];
+
+	deb_info("%s: onoff=%d", __func__, onoff);
+
+
+	if (onoff) {
+		buf[0] = 0x00;
+		buf[1] = 0x00;
+	} else {
+		buf[0] = 0x10; /* stall EPA */
+		buf[1] = 0x02; /* reset EPA */
+	}
+
+	ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	deb_info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+
+static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) {
+
+	int ret;
+	struct rtl28xxu_req req;
+	u8 val;
+
+	deb_info("%s: onoff=%d", __func__, onoff);
+
+	if(onoff){
+		/* set output values */
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x08;
+		val &= 0xef;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+
+		/* enable as output GPIO3 */
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x08;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
+		if (ret)
+			goto err;
+
+		/* demod_ctl_1 */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
+		if (ret)
+			goto err;
+
+		val &= 0xef;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
+		if (ret)
+			goto err;
+
+		/* demod control */
+		/* PLL enable */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		/* bit 7 to 1 */
+		val |= 0x80;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		/* demod HW reset */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+		/* bit 5 to 0 */
+		val &= 0xdf;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x20;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+		/* set page cache to 0 */
+		req.index = 0x0;
+		req.value = 0x20 + (1<<8);
+		req.data = &val;
+		req.size = 1;
+		ret = rtl28xxu_ctrl_msg(d, &req);
+		if (ret)
+			goto err;
+
+
+		mdelay(5);
+
+		/*enable ADC_Q and ADC_I */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x48;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+
+	} else {
+		/* demod_ctl_1 */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
+		if (ret)
+			goto err;
+
+		val |= 0x0c;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
+		if (ret)
+			goto err;
+
+		/* set output values */
+		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+		if (ret)
+				goto err;
+
+		val |= 0x10;
+
+		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+		if (ret)
+			goto err;
+
+		/* demod control */
+		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
+		if (ret)
+			goto err;
+
+		val &= 0x37;
+
+		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
+		if (ret)
+			goto err;
+
+	}
+
+	return ret;
+err:
+	deb_info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
 {
 	int ret;
 	u8 gpio, sys0;
 
-	deb_info("%s: onoff=%d\n", __func__, onoff);
+	deb_info("%s: onoff=%d", __func__, onoff);
 
 	/* demod adc */
 	ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
@@ -600,12 +879,12 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
 	if (ret)
 		goto err;
 
-	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
 
 	if (onoff) {
 		gpio |= 0x01; /* GPIO0 = 1 */
 		gpio &= (~0x10); /* GPIO4 = 0 */
-		sys0 = sys0 & 0x0f;
+		sys0 = sys0 & 0x0f; /* enable demod adc */
 		sys0 |= 0xe0;
 	} else {
 		gpio &= (~0x01); /* GPIO0 = 0 */
@@ -613,7 +892,7 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
 		sys0 = sys0 & (~0xc0);
 	}
 
-	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
+	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
 
 	/* demod adc */
 	ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
@@ -627,7 +906,7 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
 
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
@@ -699,10 +978,12 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
 
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
+/* unused for now */
+#if 0
 static int rtl2832u_rc_query(struct dvb_usb_device *d)
 {
 	int ret, i;
@@ -760,14 +1041,17 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
 exit:
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
+#endif
 
 enum rtl28xxu_usb_table_entry {
 	RTL2831U_0BDA_2831,
 	RTL2831U_14AA_0160,
 	RTL2831U_14AA_0161,
+	RTL2832U_0CCD_00A9,
+	RTL2832U_1F4D_B803,
 };
 
 static struct usb_device_id rtl28xxu_table[] = {
@@ -780,6 +1064,10 @@ static struct usb_device_id rtl28xxu_table[] = {
 		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
 
 	/* RTL2832U */
+	[RTL2832U_0CCD_00A9] = {
+		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
+	[RTL2832U_1F4D_B803] = {
+		USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
 	{} /* terminating entry */
 };
 
@@ -802,7 +1090,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
 					{
 						.frontend_attach = rtl2831u_frontend_attach,
 						.tuner_attach    = rtl2831u_tuner_attach,
-						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
+						.streaming_ctrl  = rtl2831u_streaming_ctrl,
 						.stream = {
 							.type = USB_BULK,
 							.count = 6,
@@ -818,7 +1106,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
 			}
 		},
 
-		.power_ctrl = rtl28xxu_power_ctrl,
+		.power_ctrl = rtl2831u_power_ctrl,
 
 		.rc.core = {
 			.protocol       = RC_TYPE_NEC,
@@ -864,11 +1152,11 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
 					{
 						.frontend_attach = rtl2832u_frontend_attach,
 						.tuner_attach    = rtl2832u_tuner_attach,
-						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
+						.streaming_ctrl  = rtl2832u_streaming_ctrl,
 						.stream = {
 							.type = USB_BULK,
-							.count = 6,
-							.endpoint = 0x81,
+							.count = 10,
+							.endpoint = 0x01,
 							.u = {
 								.bulk = {
 									.buffersize = 8*512,
@@ -880,23 +1168,32 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
 			}
 		},
 
-		.power_ctrl = rtl28xxu_power_ctrl,
+		.power_ctrl = rtl2832u_power_ctrl,
 
-		.rc.core = {
+		/*.rc.core = {
 			.protocol       = RC_TYPE_NEC,
 			.module_name    = "rtl28xxu",
 			.rc_query       = rtl2832u_rc_query,
 			.rc_interval    = 400,
 			.allowed_protos = RC_TYPE_NEC,
 			.rc_codes       = RC_MAP_EMPTY,
-		},
+		},*/
 
 		.i2c_algo = &rtl28xxu_i2c_algo,
 
-		.num_device_descs = 0, /* disabled as no support for RTL2832 */
+		.num_device_descs = 2,
 		.devices = {
 			{
-				.name = "Realtek RTL2832U reference design",
+				.name = "Terratec Cinergy T Stick Black",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_0CCD_00A9],
+				},
+			},
+			{
+				.name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1F4D_B803],
+				},
 			},
 		}
 	},
@@ -907,10 +1204,11 @@ static int rtl28xxu_probe(struct usb_interface *intf,
 		const struct usb_device_id *id)
 {
 	int ret, i;
+	u8 val;
 	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
 	struct dvb_usb_device *d;
 
-	deb_info("%s: interface=%d\n", __func__,
+	deb_info("%s: interface=%d", __func__,
 		intf->cur_altsetting->desc.bInterfaceNumber);
 
 	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
@@ -926,22 +1224,31 @@ static int rtl28xxu_probe(struct usb_interface *intf,
 	if (ret)
 		goto err;
 
+
 	/* init USB endpoints */
-	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
+	ret = rtl2831_rd_reg(d, USB_SYSCTL_0, &val);
+	if (ret)
+			goto err;
+
+	/* enable DMA and Full Packet Mode*/
+	val |= 0x09;
+	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, val);
 	if (ret)
 		goto err;
 
+	/* set EPA maximum packet size to 0x0200 */
 	ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
 	if (ret)
 		goto err;
 
+	/* change EPA FIFO length */
 	ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
 	if (ret)
 		goto err;
 
 	return ret;
 err:
-	deb_info("%s: failed=%d\n", __func__, ret);
+	deb_info("%s: failed=%d", __func__, ret);
 	return ret;
 }
 
@@ -957,8 +1264,6 @@ static int __init rtl28xxu_module_init(void)
 {
 	int ret;
 
-	deb_info("%s:\n", __func__);
-
 	ret = usb_register(&rtl28xxu_driver);
 	if (ret)
 		err("usb_register failed=%d", ret);
@@ -968,7 +1273,6 @@ static int __init rtl28xxu_module_init(void)
 
 static void __exit rtl28xxu_module_exit(void)
 {
-	deb_info("%s:\n", __func__);
 
 	/* deregister this driver from the USB subsystem */
 	usb_deregister(&rtl28xxu_driver);
@@ -979,4 +1283,5 @@ module_exit(rtl28xxu_module_exit);
 
 MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
 MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
 MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index f479834..f7d67d7 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -432,6 +432,13 @@ config DVB_RTL2830
 	help
 	  Say Y when you want to support this frontend.
 
+config DVB_RTL2832
+	tristate "Realtek RTL2832 DVB-T"
+	depends on DVB_CORE && I2C
+	default m if DVB_FE_CUSTOMISE
+	help
+	  Say Y when you want to support this frontend.
+
 comment "DVB-C (cable) frontends"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index b0381dc..a109aae 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -100,4 +100,4 @@ obj-$(CONFIG_DVB_TDA10071) += tda10071.o
 obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
 obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
 obj-$(CONFIG_DVB_AF9033) += af9033.o
-
+obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
diff --git a/drivers/media/dvb/frontends/rtl2832.c b/drivers/media/dvb/frontends/rtl2832.c
new file mode 100644
index 0000000..920b068
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2832.c
@@ -0,0 +1,832 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "rtl2832_priv.h"
+
+
+
+int rtl2832_debug = 1;
+module_param_named(debug, rtl2832_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+
+
+static int reg_mask[32] = {
+    0x00000001,
+    0x00000003,
+    0x00000007,
+    0x0000000f,
+    0x0000001f,
+    0x0000003f,
+    0x0000007f,
+    0x000000ff,
+    0x000001ff,
+    0x000003ff,
+    0x000007ff,
+    0x00000fff,
+    0x00001fff,
+    0x00003fff,
+    0x00007fff,
+    0x0000ffff,
+    0x0001ffff,
+    0x0003ffff,
+    0x0007ffff,
+    0x000fffff,
+    0x001fffff,
+    0x003fffff,
+    0x007fffff,
+    0x00ffffff,
+    0x01ffffff,
+    0x03ffffff,
+    0x07ffffff,
+    0x0fffffff,
+    0x1fffffff,
+    0x3fffffff,
+    0x7fffffff,
+    0xffffffff
+};
+
+static const rtl2832_reg_entry registers[] = {
+  [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2},
+  [DVBT_IIC_REPEAT] = {0x1,  0x1,   3,  3},
+  [DVBT_TR_WAIT_MIN_8K]   = {0x1,  0x88,   11,  2},
+  [DVBT_RSD_BER_FAIL_VAL] = {0x1,  0x8f,   15,  0},
+  [DVBT_EN_BK_TRK]        = {0x1,  0xa6,   7,  7},
+  [DVBT_AD_EN_REG]        = {0x0,  0x8,   7,  7},
+  [DVBT_AD_EN_REG1]       = {0x0,  0x8,   6,  6},
+  [DVBT_EN_BBIN]          = {0x1,  0xb1,   0,  0},
+  [DVBT_MGD_THD0]         = {0x1,  0x95,   7,  0},
+  [DVBT_MGD_THD1]         = {0x1,  0x96,   7,  0},
+  [DVBT_MGD_THD2]         = {0x1,  0x97,   7,  0},
+  [DVBT_MGD_THD3]         = {0x1,  0x98,   7,  0},
+  [DVBT_MGD_THD4]         = {0x1,  0x99,   7,  0},
+  [DVBT_MGD_THD5]         = {0x1,  0x9a,   7,  0},
+  [DVBT_MGD_THD6]         = {0x1,  0x9b,   7,  0},
+  [DVBT_MGD_THD7]         = {0x1,  0x9c,   7,  0},
+  [DVBT_EN_CACQ_NOTCH]    = {0x1,  0x61,   4,  4},
+  [DVBT_AD_AV_REF]        = {0x0,  0x9,   6,  0},
+  [DVBT_REG_PI]           = {0x0,  0xa,   2,  0},
+  [DVBT_PIP_ON]           = {0x0,  0x21,   3,  3},
+  [DVBT_SCALE1_B92]       = {0x2,  0x92,   7,  0},
+  [DVBT_SCALE1_B93]       = {0x2,  0x93,   7,  0},
+  [DVBT_SCALE1_BA7]       = {0x2,  0xa7,   7,  0},
+  [DVBT_SCALE1_BA9]       = {0x2,  0xa9,   7,  0},
+  [DVBT_SCALE1_BAA]       = {0x2,  0xaa,   7,  0},
+  [DVBT_SCALE1_BAB]       = {0x2,  0xab,   7,  0},
+  [DVBT_SCALE1_BAC]       = {0x2,  0xac,   7,  0},
+  [DVBT_SCALE1_BB0]       = {0x2,  0xb0,   7,  0},
+  [DVBT_SCALE1_BB1]       = {0x2,  0xb1,   7,  0},
+  [DVBT_KB_P1]            = {0x1,  0x64,   3,  1},
+  [DVBT_KB_P2]            = {0x1,  0x64,   6,  4},
+  [DVBT_KB_P3]            = {0x1,  0x65,   2,  0},
+  [DVBT_OPT_ADC_IQ]       = {0x0,  0x6,   5,  4},
+  [DVBT_AD_AVI]           = {0x0,  0x9,   1,  0},
+  [DVBT_AD_AVQ]           = {0x0,  0x9,   3,  2},
+  [DVBT_K1_CR_STEP12]     = {0x2,  0xad,   9,  4},
+  [DVBT_TRK_KS_P2]        = {0x1,  0x6f,   2,  0},
+  [DVBT_TRK_KS_I2]        = {0x1,  0x70,   5,  3},
+  [DVBT_TR_THD_SET2]      = {0x1,  0x72,   3,  0},
+  [DVBT_TRK_KC_P2]        = {0x1,  0x73,   5,  3},
+  [DVBT_TRK_KC_I2]        = {0x1,  0x75,   2,  0},
+  [DVBT_CR_THD_SET2]      = {0x1,  0x76,   7,  6},
+  [DVBT_PSET_IFFREQ]     = {0x1,  0x19,   21,  0},
+  [DVBT_SPEC_INV]        = {0x1,  0x15,   0,  0},
+  [DVBT_RSAMP_RATIO]     = {0x1,  0x9f,   27,  2},
+  [DVBT_CFREQ_OFF_RATIO] = {0x1,  0x9d,   23,  4},
+  [DVBT_FSM_STAGE]       = {0x3,  0x51,   6,  3},
+  [DVBT_RX_CONSTEL]      = {0x3,  0x3c,   3,  2},
+  [DVBT_RX_HIER]         = {0x3,  0x3c,   6,  4},
+  [DVBT_RX_C_RATE_LP]    = {0x3,  0x3d,   2,  0},
+  [DVBT_RX_C_RATE_HP]    = {0x3,  0x3d,   5,  3},
+  [DVBT_GI_IDX]          = {0x3,  0x51,   1,  0},
+  [DVBT_FFT_MODE_IDX]    = {0x3,  0x51,   2,  2},
+  [DVBT_RSD_BER_EST]     = {0x3,  0x4e,   15,  0},
+  [DVBT_CE_EST_EVM]      = {0x4,  0xc,   15,  0},
+  [DVBT_RF_AGC_VAL]      = {0x3,  0x5b,   13,  0},
+  [DVBT_IF_AGC_VAL]      = {0x3,  0x59,   13,  0},
+  [DVBT_DAGC_VAL]        = {0x3,  0x5,   7,  0},
+  [DVBT_SFREQ_OFF]       = {0x3,  0x18,   13,  0},
+  [DVBT_CFREQ_OFF]       = {0x3,  0x5f,   17,  0},
+  [DVBT_POLAR_RF_AGC]    = {0x0,  0xe,   1,  1},
+  [DVBT_POLAR_IF_AGC]    = {0x0,  0xe,   0,  0},
+  [DVBT_AAGC_HOLD]       = {0x1,  0x4,   5,  5},
+  [DVBT_EN_RF_AGC]       = {0x1,  0x4,   6,  6},
+  [DVBT_EN_IF_AGC]       = {0x1,  0x4,   7,  7},
+  [DVBT_IF_AGC_MIN]      = {0x1,  0x8,   7,  0},
+  [DVBT_IF_AGC_MAX]      = {0x1,  0x9,   7,  0},
+  [DVBT_RF_AGC_MIN]      = {0x1,  0xa,   7,  0},
+  [DVBT_RF_AGC_MAX]      = {0x1,  0xb,   7,  0},
+  [DVBT_IF_AGC_MAN]      = {0x1,  0xc,   6,  6},
+  [DVBT_IF_AGC_MAN_VAL]  = {0x1,  0xc,   13,  0},
+  [DVBT_RF_AGC_MAN]      = {0x1,  0xe,   6,  6},
+  [DVBT_RF_AGC_MAN_VAL]  = {0x1,  0xe,   13,  0},
+  [DVBT_DAGC_TRG_VAL]    = {0x1,  0x12,   7,  0},
+  [DVBT_AGC_TARG_VAL_0]  = {0x1,  0x2,   0,  0},
+  [DVBT_AGC_TARG_VAL_8_1] = {0x1,  0x3,   7,  0},
+  [DVBT_AAGC_LOOP_GAIN]  = {0x1,  0xc7,   5,  1},
+  [DVBT_LOOP_GAIN2_3_0]  = {0x1,  0x4,   4,  1},
+  [DVBT_LOOP_GAIN2_4]    = {0x1,  0x5,   7,  7},
+  [DVBT_LOOP_GAIN3]      = {0x1,  0xc8,   4,  0},
+  [DVBT_VTOP1]           = {0x1,  0x6,   5,  0},
+  [DVBT_VTOP2]           = {0x1,  0xc9,   5,  0},
+  [DVBT_VTOP3]           = {0x1,  0xca,   5,  0},
+  [DVBT_KRF1]            = {0x1,  0xcb,   7,  0},
+  [DVBT_KRF2]            = {0x1,  0x7,   7,  0},
+  [DVBT_KRF3]            = {0x1,  0xcd,   7,  0},
+  [DVBT_KRF4]            = {0x1,  0xce,   7,  0},
+  [DVBT_EN_GI_PGA]       = {0x1,  0xe5,   0,  0},
+  [DVBT_THD_LOCK_UP]     = {0x1,  0xd9,   8,  0},
+  [DVBT_THD_LOCK_DW]     = {0x1,  0xdb,   8,  0},
+  [DVBT_THD_UP1]         = {0x1,  0xdd,   7,  0},
+  [DVBT_THD_DW1]         = {0x1,  0xde,   7,  0},
+  [DVBT_INTER_CNT_LEN]   = {0x1,  0xd8,   3,  0},
+  [DVBT_GI_PGA_STATE]    = {0x1,  0xe6,   3,  3},
+  [DVBT_EN_AGC_PGA]      = {0x1,  0xd7,   0,  0},
+  [DVBT_CKOUTPAR]        = {0x1,  0x7b,   5,  5},
+  [DVBT_CKOUT_PWR]       = {0x1,  0x7b,   6,  6},
+  [DVBT_SYNC_DUR]        = {0x1,  0x7b,   7,  7},
+  [DVBT_ERR_DUR]         = {0x1,  0x7c,   0,  0},
+  [DVBT_SYNC_LVL]        = {0x1,  0x7c,   1,  1},
+  [DVBT_ERR_LVL]         = {0x1,  0x7c,   2,  2},
+  [DVBT_VAL_LVL]         = {0x1,  0x7c,   3,  3},
+  [DVBT_SERIAL]          = {0x1,  0x7c,   4,  4},
+  [DVBT_SER_LSB]         = {0x1,  0x7c,   5,  5},
+  [DVBT_CDIV_PH0]        = {0x1,  0x7d,   3,  0},
+  [DVBT_CDIV_PH1]        = {0x1,  0x7d,   7,  4},
+  [DVBT_MPEG_IO_OPT_2_2] = {0x0,  0x6,   7,  7},
+  [DVBT_MPEG_IO_OPT_1_0] = {0x0,  0x7,   7,  6},
+  [DVBT_CKOUTPAR_PIP]    = {0x0,  0xb7,   4,  4},
+  [DVBT_CKOUT_PWR_PIP]   = {0x0,  0xb7,   3,  3},
+  [DVBT_SYNC_LVL_PIP]    = {0x0,  0xb7,   2,  2},
+  [DVBT_ERR_LVL_PIP]     = {0x0,  0xb7,   1,  1},
+  [DVBT_VAL_LVL_PIP]     = {0x0,  0xb7,   0,  0},
+  [DVBT_CKOUTPAR_PID]    = {0x0,  0xb9,   4,  4},
+  [DVBT_CKOUT_PWR_PID]   = {0x0,  0xb9,   3,  3},
+  [DVBT_SYNC_LVL_PID]    = {0x0,  0xb9,   2,  2},
+  [DVBT_ERR_LVL_PID]     = {0x0,  0xb9,   1,  1},
+  [DVBT_VAL_LVL_PID]     = {0x0,  0xb9,   0,  0},
+  [DVBT_SM_PASS]         = {0x1,  0x93,   11,  0},
+  [DVBT_AD7_SETTING]     = {0x0,  0x11,   15,  0},
+  [DVBT_RSSI_R]          = {0x3,  0x1,   6,  0},
+  [DVBT_ACI_DET_IND]     = {0x3,  0x12,   0,  0},
+  [DVBT_REG_MON]        = {0x0,  0xd,   1,  0},
+  [DVBT_REG_MONSEL]     = {0x0,  0xd,   2,  2},
+  [DVBT_REG_GPE]        = {0x0,  0xd,   7,  7},
+  [DVBT_REG_GPO]        = {0x0,  0x10,   0,  0},
+  [DVBT_REG_4MSEL]      = {0x0,  0x13,   0,  0},
+};
+
+
+
+/* write multiple hardware registers */
+static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[1+len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1+len,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* read multiple hardware registers */
+static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+{
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = priv->cfg.i2c_addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = priv->cfg.i2c_addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+/* write multiple registers */
+static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, int len)
+{
+	int ret;
+
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2832_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2832_wr(priv, reg, val, len);
+}
+
+/* read multiple registers */
+static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, int len)
+{
+	int ret;
+
+	/* switch bank if needed */
+	if (page != priv->page) {
+		ret = rtl2832_wr(priv, 0x00, &page, 1);
+		if (ret)
+			return ret;
+
+		priv->page = page;
+	}
+
+	return rtl2832_rd(priv, reg, val, len);
+}
+
+#if 0 /* currently not used */
+/* write single register */
+static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
+{
+	return rtl2832_wr_regs(priv, reg, page, &val, 1);
+}
+#endif
+
+/* read single register */
+static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
+{
+	return rtl2832_rd_regs(priv, reg, page, val, 1);
+}
+
+int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val){
+	int ret;
+
+	u8 reg_start_addr;
+	u8 msb, lsb;
+	u8 page;
+	u8 reading[4];
+	u32 reading_tmp;
+	int i;
+
+	u8 len;
+	u32 mask;
+
+	reg_start_addr = registers[reg].start_address;
+	msb = registers[reg].msb;
+	lsb = registers[reg].lsb;
+	page = registers[reg].page;
+
+	len = (msb >> 3) + 1;
+	mask = reg_mask[msb-lsb];
+
+
+	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	if (ret)
+		goto err;
+
+	reading_tmp = 0;
+	for(i = 0; i < len; i++){
+		reading_tmp |= reading[i] << ((len-1-i)*8);
+	}
+
+	*val = (reading_tmp >> lsb) & mask;
+
+	return ret;
+
+err:
+	return ret;
+
+}
+
+int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
+{
+	int ret, i;
+	u8 len;
+	u8 reg_start_addr;
+	u8 msb, lsb;
+	u8 page;
+	u32 mask;
+
+
+	u8 reading[4];
+	u8 writing[4];
+	u32 reading_tmp;
+	u32 writing_tmp;
+
+
+	reg_start_addr = registers[reg].start_address;
+	msb = registers[reg].msb;
+	lsb = registers[reg].lsb;
+	page = registers[reg].page;
+
+	len = (msb >> 3) + 1;
+	mask = reg_mask[msb-lsb];
+
+
+	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+	if (ret)
+		goto err;
+
+	reading_tmp = 0;
+	for (i = 0; i < len; i++) {
+		reading_tmp |= reading[i] << ((len-1-i)*8);
+	}
+
+	writing_tmp = reading_tmp & ~(mask << lsb);
+	writing_tmp |= ((val & mask) << lsb);
+
+
+	for (i = 0; i < len; i++) {
+		writing[i] = (writing_tmp >> ((len-1-i)*8)) & 0xff;
+	}
+
+	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
+	if(ret)
+		goto err;
+
+	return ret;
+
+err:
+	return ret;
+
+}
+
+
+static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+	int ret;
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	dbg("%s: enable=%d", __func__, enable);
+
+	/* gate already open or close */
+	if (priv->i2c_gate_state == enable)
+		return 0;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable?0x1:0x0));
+
+	if (ret)
+		goto err;
+
+	priv->i2c_gate_state = enable;
+
+	return ret;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+
+
+static int rtl2832_init(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int i, ret;
+
+	u8 en_bbin;
+	u64 pset_iffreq;
+
+	/* initialization values for the demodulator registers */
+	static rtl2832_reg_value rtl2832_initial_regs_1[] = {
+			{DVBT_AD_EN_REG,			0x1		},
+			{DVBT_AD_EN_REG1,			0x1		},
+			{DVBT_RSD_BER_FAIL_VAL,		0x2800	},
+			{DVBT_MGD_THD0,				0x10	},
+			{DVBT_MGD_THD1,				0x20	},
+			{DVBT_MGD_THD2,				0x20	},
+			{DVBT_MGD_THD3,				0x40	},
+			{DVBT_MGD_THD4,				0x22	},
+			{DVBT_MGD_THD5,				0x32	},
+			{DVBT_MGD_THD6,				0x37	},
+			{DVBT_MGD_THD7,				0x39	},
+			{DVBT_EN_BK_TRK,			0x0		},
+			{DVBT_EN_CACQ_NOTCH,		0x0		},
+			{DVBT_AD_AV_REF,			0x2a	},
+			{DVBT_REG_PI,				0x6		},
+			{DVBT_PIP_ON,				0x0		},
+			{DVBT_CDIV_PH0,				0x8		},
+			{DVBT_CDIV_PH1,				0x8		},
+			{DVBT_SCALE1_B92,			0x4		},
+			{DVBT_SCALE1_B93,			0xb0	},
+			{DVBT_SCALE1_BA7,			0x78	},
+			{DVBT_SCALE1_BA9,			0x28	},
+			{DVBT_SCALE1_BAA,			0x59	},
+			{DVBT_SCALE1_BAB,			0x83	},
+			{DVBT_SCALE1_BAC,			0xd4	},
+			{DVBT_SCALE1_BB0,			0x65	},
+			{DVBT_SCALE1_BB1,			0x43	},
+			{DVBT_KB_P1,				0x1		},
+			{DVBT_KB_P2,				0x4		},
+			{DVBT_KB_P3,				0x7		},
+			{DVBT_K1_CR_STEP12,			0xa		},
+			{DVBT_REG_GPE,				0x1		},
+			{DVBT_SERIAL,				0x0},
+			{DVBT_CDIV_PH0,				0x9},
+			{DVBT_CDIV_PH1,				0x9},
+			{DVBT_MPEG_IO_OPT_2_2,		0x0},
+			{DVBT_MPEG_IO_OPT_1_0,		0x0},
+			{DVBT_TRK_KS_P2,			0x4},
+			{DVBT_TRK_KS_I2,			0x7},
+			{DVBT_TR_THD_SET2,			0x6},
+			{DVBT_TRK_KC_I2,			0x5},
+			{DVBT_CR_THD_SET2,			0x1},
+
+
+		};
+
+	static rtl2832_reg_value rtl2832_initial_regs_2[] = {
+			{DVBT_SPEC_INV,				0x0},
+			{DVBT_DAGC_TRG_VAL,			0x5a	},
+			{DVBT_AGC_TARG_VAL_0,		0x0		},
+			{DVBT_AGC_TARG_VAL_8_1,		0x5a	},
+			{DVBT_AAGC_LOOP_GAIN,		0x16    },
+			{DVBT_LOOP_GAIN2_3_0,		0x6		},
+			{DVBT_LOOP_GAIN2_4,			0x1		},
+			{DVBT_LOOP_GAIN3,			0x16	},
+			{DVBT_VTOP1,				0x35	},
+			{DVBT_VTOP2,				0x21	},
+			{DVBT_VTOP3,				0x21	},
+			{DVBT_KRF1,					0x0		},
+			{DVBT_KRF2,					0x40	},
+			{DVBT_KRF3,					0x10	},
+			{DVBT_KRF4,					0x10	},
+			{DVBT_IF_AGC_MIN,			0x80	},
+			{DVBT_IF_AGC_MAX,			0x7f	},
+			{DVBT_RF_AGC_MIN,			0x80	},
+			{DVBT_RF_AGC_MAX,			0x7f	},
+			{DVBT_POLAR_RF_AGC,			0x0		},
+			{DVBT_POLAR_IF_AGC,			0x0		},
+			{DVBT_AD7_SETTING,			0xe9bf	},
+			{DVBT_EN_GI_PGA,			0x0		},
+			{DVBT_THD_LOCK_UP,			0x0		},
+			{DVBT_THD_LOCK_DW,			0x0		},
+			{DVBT_THD_UP1,				0x11	},
+			{DVBT_THD_DW1,				0xef	},
+			{DVBT_INTER_CNT_LEN,		0xc		},
+			{DVBT_GI_PGA_STATE,			0x0		},
+			{DVBT_EN_AGC_PGA,			0x1		},
+			{DVBT_IF_AGC_MAN,			0x0		},
+		};
+
+
+	info("%s", __func__);
+
+	en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
+
+	/* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) / CrystalFreqHz) */
+	pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
+	pset_iffreq *= 0x400000;
+	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+	pset_iffreq = pset_iffreq & 0x3fffff;
+
+
+
+	for (i = 0; i < 42; i++) {
+		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_1[i].reg, rtl2832_initial_regs_1[i].value);
+		if (ret)
+			goto err;
+	}
+
+	/* if frequency settings */
+	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+		if (ret)
+			goto err;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+		if(ret)
+			goto err;
+
+	for (i = 0; i < 31; i++) {
+		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_2[i].reg, rtl2832_initial_regs_2[i].value);
+		if (ret)
+			goto err;
+	}
+
+	priv->sleeping = false;
+
+	return ret;
+
+err:
+	return ret;
+}
+
+static int rtl2832_sleep(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	info("%s", __func__);
+	priv->sleeping = true;
+	return 0;
+}
+
+int rtl2832_get_tune_settings(struct dvb_frontend *fe,
+	struct dvb_frontend_tune_settings *s)
+{
+	info("%s", __func__);
+	s->min_delay_ms = 1000;
+	s->step_size = fe->ops.info.frequency_stepsize * 2;
+	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
+	return 0;
+}
+
+static int rtl2832_set_frontend(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	int ret, i, j;
+	u64 bw_mode, num, num2;
+	u32 resamp_ratio, cfreq_off_ratio;
+
+
+	static u8 bw_params[3][32] = {
+		/* 6 MHz bandwidth */
+		{
+			0xf5,	0xff,	0x15,	0x38,	0x5d,	0x6d,	0x52,	0x07,	0xfa,	0x2f,
+			0x53,	0xf5,	0x3f,	0xca,	0x0b,	0x91,	0xea,	0x30,	0x63,	0xb2,
+			0x13,	0xda,	0x0b,	0xc4,	0x18,	0x7e,	0x16,	0x66,	0x08,	0x67,
+			0x19,	0xe0,
+		},
+
+		/*  7 MHz bandwidth */
+		{
+			0xe7,	0xcc,	0xb5,	0xba,	0xe8,	0x2f,	0x67,	0x61,	0x00,	0xaf,
+			0x86,	0xf2,	0xbf,	0x59,	0x04,	0x11,	0xb6,	0x33,	0xa4,	0x30,
+			0x15,	0x10,	0x0a,	0x42,	0x18,	0xf8,	0x17,	0xd9,	0x07,	0x22,
+			0x19,	0x10,
+		},
+
+		/*  8 MHz bandwidth */
+		{
+			0x09,	0xf6,	0xd2,	0xa7,	0x9a,	0xc9,	0x27,	0x77,	0x06,	0xbf,
+			0xec,	0xf4,	0x4f,	0x0b,	0xfc,	0x01,	0x63,	0x35,	0x54,	0xa7,
+			0x16,	0x66,	0x08,	0xb4,	0x19,	0x6e,	0x19,	0x65,	0x05,	0xc8,
+			0x19,	0xe0,
+		},
+	};
+
+
+	info("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
+			c->frequency, c->bandwidth_hz, c->inversion);
+
+
+	/* program tuner */
+	if (fe->ops.tuner_ops.set_params)
+		fe->ops.tuner_ops.set_params(fe);
+
+
+	switch (c->bandwidth_hz) {
+		case 6000000:
+			i = 0;
+			bw_mode = 48000000;
+			break;
+		case 7000000:
+			i = 1;
+			bw_mode = 56000000;
+			break;
+		case 8000000:
+			i = 2;
+			bw_mode = 64000000;
+			break;
+		default:
+			dbg("invalid bandwidth");
+			return -EINVAL;
+		}
+
+	for (j = 0; j < 32; j++){
+		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
+		if (ret)
+			goto err;
+	}
+
+	/* calculate and set resample ratio */
+	/* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) / ConstWithBandwidthMode) */
+	num = priv->cfg.xtal * 7;
+	num *= 0x400000;
+	num = div_u64(num, bw_mode);
+	resamp_ratio =  num & 0x3ffffff;
+	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
+	if (ret)
+		goto err;
+
+	/* calculate and set cfreq off ratio */
+	/* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20) / (CrystalFreqHz * 7)) */
+	num = bw_mode << 20;
+	num2 = priv->cfg.xtal * 7;
+	num = div_u64(num, num2);
+	num = -num;
+	cfreq_off_ratio = num & 0xfffff;
+	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
+	if (ret)
+		goto err;
+
+
+	/* soft reset */
+	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+	if (ret)
+		goto err;
+
+	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+	if (ret)
+		goto err;
+
+	return ret;
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int ret;
+	u32 tmp;
+	*status = 0;
+
+
+	info("%s", __func__);
+	if (priv->sleeping)
+		return 0;
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
+	if (ret)
+		goto err;
+
+	if (tmp == 11) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	}
+	/* TODO find out if this is also true */
+	/*else if (tmp == 10) {
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+			FE_HAS_VITERBI;
+	}*/
+
+	return ret;
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
+}
+
+static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+	info("%s", __func__);
+	*snr = 0;
+	return 0;
+}
+
+static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+	info("%s", __func__);
+	*ber = 0;
+	return 0;
+}
+
+static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+	info("%s", __func__);
+	*ucblocks = 0;
+	return 0;
+}
+
+static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	info("%s", __func__);
+	*strength = 0;
+	return 0;
+}
+
+static struct dvb_frontend_ops rtl2832_ops;
+
+static void rtl2832_release(struct dvb_frontend *fe)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+
+	info("%s", __func__);
+	kfree(priv);
+}
+
+struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
+	struct i2c_adapter *i2c, u8 tuner)
+{
+	struct rtl2832_priv *priv = NULL;
+	int ret = 0;
+	u8 tmp;
+
+	info("%s", __func__);
+
+	/* allocate memory for the internal state */
+	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
+	if (priv == NULL)
+		goto err;
+
+	/* setup the priv */
+	priv->i2c = i2c;
+	priv->tuner = tuner;
+	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
+
+	/* check if the demod is there */
+	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
+	if (ret)
+		goto err;
+
+	/* create dvb_frontend */
+	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
+	priv->fe.demodulator_priv = priv;
+
+	/* TODO implement sleep mode depending on RC */
+	priv->sleeping = true;
+
+	return &priv->fe;
+err:
+	dbg("%s: failed=%d", __func__, ret);
+	kfree(priv);
+	return NULL;
+}
+EXPORT_SYMBOL(rtl2832_attach);
+
+static struct dvb_frontend_ops rtl2832_ops = {
+	.delsys = { SYS_DVBT },
+	.info = {
+		.name = "Realtek RTL2832 (DVB-T)",
+		.type               = FE_OFDM,
+		.frequency_min      = 50000000,
+		.frequency_max      = 862000000,
+		.frequency_stepsize = 166667,
+		.caps = FE_CAN_FEC_1_2 |
+			FE_CAN_FEC_2_3 |
+			FE_CAN_FEC_3_4 |
+			FE_CAN_FEC_5_6 |
+			FE_CAN_FEC_7_8 |
+			FE_CAN_FEC_AUTO |
+			FE_CAN_QPSK |
+			FE_CAN_QAM_16 |
+			FE_CAN_QAM_64 |
+			FE_CAN_QAM_AUTO |
+			FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO |
+			FE_CAN_HIERARCHY_AUTO |
+			FE_CAN_RECOVER |
+			FE_CAN_MUTE_TS
+	},
+
+	.release = rtl2832_release,
+
+	.init = rtl2832_init,
+	.sleep = rtl2832_sleep,
+
+	.get_tune_settings = rtl2832_get_tune_settings,
+
+	.set_frontend = rtl2832_set_frontend,
+
+	.read_status = rtl2832_read_status,
+	.read_snr = rtl2832_read_snr,
+	.read_ber = rtl2832_read_ber,
+	.read_ucblocks = rtl2832_read_ucblocks,
+	.read_signal_strength = rtl2832_read_signal_strength,
+	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
+};
+
+MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
+MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION("0.1");
diff --git a/drivers/media/dvb/frontends/rtl2832.h b/drivers/media/dvb/frontends/rtl2832.h
new file mode 100644
index 0000000..b16631a
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2832.h
@@ -0,0 +1,300 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_H
+#define RTL2832_H
+
+#include <linux/dvb/frontend.h>
+
+struct rtl2832_config {
+	/*
+	 * Demodulator I2C address.
+	 */
+	u8 i2c_addr;
+
+	/*
+	 * Xtal frequency.
+	 * Hz
+	 * 4000000, 16000000, 25000000, 28800000
+	 */
+	u32 xtal;
+
+	/*
+	 * IFs for all used modes.
+	 * Hz
+	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
+	 */
+	u32 if_dvbt;
+
+	/*
+	 */
+	u8 tuner;
+};
+
+
+#if defined(CONFIG_DVB_RTL2832) || \
+	(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
+extern struct dvb_frontend *rtl2832_attach(
+	const struct rtl2832_config *cfg,
+	struct i2c_adapter *i2c,
+	u8 tuner
+);
+
+extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+);
+#else
+static inline struct dvb_frontend *rtl2832_attach(
+	const struct rtl2832_config *config,
+	struct i2c_adapter *i2c
+)
+{
+	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+	return NULL;
+}
+
+static inline struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
+	struct dvb_frontend *fe
+)
+{
+	return NULL;
+}
+#endif
+
+
+/* Demod register bit names */
+enum DVBT_REG_BIT_NAME
+{
+	DVBT_SOFT_RST,
+	DVBT_IIC_REPEAT,
+	DVBT_TR_WAIT_MIN_8K,
+	DVBT_RSD_BER_FAIL_VAL,
+	DVBT_EN_BK_TRK,
+	DVBT_REG_PI,
+	DVBT_REG_PFREQ_1_0,
+	DVBT_PD_DA8,
+	DVBT_LOCK_TH,
+	DVBT_BER_PASS_SCAL,
+	DVBT_CE_FFSM_BYPASS,
+	DVBT_ALPHAIIR_N,
+	DVBT_ALPHAIIR_DIF,
+	DVBT_EN_TRK_SPAN,
+	DVBT_LOCK_TH_LEN,
+	DVBT_CCI_THRE,
+	DVBT_CCI_MON_SCAL,
+	DVBT_CCI_M0,
+	DVBT_CCI_M1,
+	DVBT_CCI_M2,
+	DVBT_CCI_M3,
+	DVBT_SPEC_INIT_0,
+	DVBT_SPEC_INIT_1,
+	DVBT_SPEC_INIT_2,
+	DVBT_AD_EN_REG,
+	DVBT_AD_EN_REG1,
+	DVBT_EN_BBIN,
+	DVBT_MGD_THD0,
+	DVBT_MGD_THD1,
+	DVBT_MGD_THD2,
+	DVBT_MGD_THD3,
+	DVBT_MGD_THD4,
+	DVBT_MGD_THD5,
+	DVBT_MGD_THD6,
+	DVBT_MGD_THD7,
+	DVBT_EN_CACQ_NOTCH,
+	DVBT_AD_AV_REF,	
+	DVBT_PIP_ON,
+	DVBT_SCALE1_B92,
+	DVBT_SCALE1_B93,
+	DVBT_SCALE1_BA7,
+	DVBT_SCALE1_BA9,
+	DVBT_SCALE1_BAA,
+	DVBT_SCALE1_BAB,
+	DVBT_SCALE1_BAC,
+	DVBT_SCALE1_BB0,
+	DVBT_SCALE1_BB1,
+	DVBT_KB_P1,
+	DVBT_KB_P2,
+	DVBT_KB_P3,
+	DVBT_OPT_AD
+	DVBT_AD_AVI
+	DVBT_AD_AVQ
+	DVBT_K1_CR_STEP12,
+	DVBT_TRK_KS_P2,
+	DVBT_TRK_KS_I2,
+	DVBT_TR_THD_SET2,
+	DVBT_TRK_KC_P2,
+	DVBT_TRK_KC_I2,
+	DVBT_CR_THD_SET2,
+	DVBT_PSET_IFFREQ,
+	DVBT_SPEC_INV,
+	DVBT_BW_INDEX,
+	DVBT_RSAMP_RATIO,
+	DVBT_CFREQ_OFF_RATIO,
+	DVBT_FSM_STAGE,
+	DVBT_RX_CONSTEL,
+	DVBT_RX_HIER,
+	DVBT_RX_C_RATE_LP,
+	DVBT_RX_C_RATE_HP,
+	DVBT_GI_IDX,
+	DVBT_FFT_MODE_IDX,
+	DVBT_RSD_BER_EST,
+	DVBT_CE_EST_EVM,
+	DVBT_RF_AGC_VAL,
+	DVBT_IF_AGC_VAL,
+	DVBT_DAGC_VAL,
+	DVBT_SFREQ_OFF,
+	DVBT_CFREQ_OFF,
+	DVBT_POLAR_RF_AGC,
+	DVBT_POLAR_IF_AGC,
+	DVBT_AAGC_HOLD,
+	DVBT_EN_RF_AGC,
+	DVBT_EN_IF_AGC,
+	DVBT_IF_AGC_MIN,
+	DVBT_IF_AGC_MAX,
+	DVBT_RF_AGC_MIN,
+	DVBT_RF_AGC_MAX,
+	DVBT_IF_AGC_MAN,
+	DVBT_IF_AGC_MAN_VAL,
+	DVBT_RF_AGC_MAN,
+	DVBT_RF_AGC_MAN_VAL,
+	DVBT_DAGC_TRG_VAL,
+	DVBT_AGC_TARG_VAL,
+	DVBT_LOOP_GAIN_3_0,
+	DVBT_LOOP_GAIN_4,
+	DVBT_VTOP,	
+	DVBT_KRF,
+	DVBT_AGC_TARG_VAL_0,
+	DVBT_AGC_TARG_VAL_8_1,
+	DVBT_AAGC_LOOP_GAIN,
+	DVBT_LOOP_GAIN2_3_0,
+	DVBT_LOOP_GAIN2_4,
+	DVBT_LOOP_GAIN3,
+	DVBT_VTOP1,
+	DVBT_VTOP2,
+	DVBT_VTOP3,
+	DVBT_KRF1,
+	DVBT_KRF2,
+	DVBT_KRF3,
+	DVBT_KRF4,
+	DVBT_EN_GI_PGA,
+	DVBT_THD_LOCK_UP,
+	DVBT_THD_LOCK_DW,
+	DVBT_THD_UP1,
+	DVBT_THD_DW1,
+	DVBT_INTER_CNT_LEN,
+	DVBT_GI_PGA_STATE,
+	DVBT_EN_AGC_PGA,
+	DVBT_CKOUTPAR,
+	DVBT_CKOUT_PWR,
+	DVBT_SYNC_DUR,
+	DVBT_ERR_DUR,
+	DVBT_SYNC_LVL,
+	DVBT_ERR_LVL,
+	DVBT_VAL_LVL,
+	DVBT_SERIAL,
+	DVBT_SER_LSB,
+	DVBT_CDIV_PH0,
+	DVBT_CDIV_PH1,
+	DVBT_MPEG_IO_OPT_2_2,
+	DVBT_MPEG_IO_OPT_1_0,
+	DVBT_CKOUTPAR_PIP,
+	DVBT_CKOUT_PWR_PIP,
+	DVBT_SYNC_LVL_PIP,
+	DVBT_ERR_LVL_PIP,
+	DVBT_VAL_LVL_PIP,
+	DVBT_CKOUTPAR_PID,
+	DVBT_CKOUT_PWR_PID,
+	DVBT_SYNC_LVL_PID,
+	DVBT_ERR_LVL_PID,
+	DVBT_VAL_LVL_PID,
+	DVBT_SM_PASS,
+	DVBT_UPDATE_REG_2,
+	DVBT_BTHD_P3,
+	DVBT_BTHD_D3,
+	DVBT_FUNC4_REG0,
+	DVBT_FUNC4_REG1,
+	DVBT_FUNC4_REG2,
+	DVBT_FUNC4_REG3,
+	DVBT_FUNC4_REG4,
+	DVBT_FUNC4_REG5,
+	DVBT_FUNC4_REG6,
+	DVBT_FUNC4_REG7,
+	DVBT_FUNC4_REG8,
+	DVBT_FUNC4_REG9,
+	DVBT_FUNC4_REG10,
+	DVBT_FUNC5_REG0,
+	DVBT_FUNC5_REG1,
+	DVBT_FUNC5_REG2,
+	DVBT_FUNC5_REG3,
+	DVBT_FUNC5_REG4,
+	DVBT_FUNC5_REG5,
+	DVBT_FUNC5_REG6,
+	DVBT_FUNC5_REG7,
+	DVBT_FUNC5_REG8,
+	DVBT_FUNC5_REG9,
+	DVBT_FUNC5_REG10,
+	DVBT_FUNC5_REG11,
+	DVBT_FUNC5_REG12,
+	DVBT_FUNC5_REG13,
+	DVBT_FUNC5_REG14,
+	DVBT_FUNC5_REG15,
+	DVBT_FUNC5_REG16,
+	DVBT_FUNC5_REG17,
+	DVBT_FUNC5_REG18,
+	DVBT_AD7_SETTING,
+	DVBT_RSSI_R,
+	DVBT_ACI_DET_IND,
+	DVBT_REG_MON,
+	DVBT_REG_MONSEL,
+	DVBT_REG_GPE,
+	DVBT_REG_GPO,
+	DVBT_REG_4MSEL,
+	DVBT_TEST_REG_1,
+	DVBT_TEST_REG_2,
+	DVBT_TEST_REG_3,
+	DVBT_TEST_REG_4,
+	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
+};
+
+
+/* Register table length */
+#define RTL2832_REG_TABLE_LEN	DVBT_REG_BIT_NAME_ITEM_TERMINATOR
+
+typedef struct
+{
+	u8 page;
+	u8 start_address;
+	u8 msb;
+	u8 lsb;
+}
+rtl2832_reg_entry;
+
+typedef struct
+{
+	int reg;
+	u32 value;
+}
+rtl2832_reg_value;
+
+
+
+
+
+#endif /* RTL2832_H */
diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h b/drivers/media/dvb/frontends/rtl2832_priv.h
new file mode 100644
index 0000000..2f591c6
--- /dev/null
+++ b/drivers/media/dvb/frontends/rtl2832_priv.h
@@ -0,0 +1,60 @@
+/*
+ * Realtek RTL2832 DVB-T demodulator driver
+ *
+ * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL2832_PRIV_H
+#define RTL2832_PRIV_H
+
+#include "dvb_frontend.h"
+#include "rtl2832.h"
+
+#define LOG_PREFIX "rtl2832"
+
+#undef dbg
+#define dbg(f, arg...) \
+	if (rtl2832_debug) \
+		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+struct rtl2832_priv {
+	struct i2c_adapter *i2c;
+	struct dvb_frontend fe;
+	struct rtl2832_config cfg;
+
+	bool i2c_gate_state;
+	bool sleeping;
+
+	u32 xtal;
+
+	u8 tuner;
+	u8 page; /* active register page */
+};
+
+struct rtl2832_reg_val_mask {
+	u16 reg;
+	u8  val;
+	u8  mask;
+};
+
+#endif /* RTL2832_PRIV_H */
-- 
1.7.7.6


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-04-30 15:39   ` [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744 Thomas Mair
@ 2012-05-01  6:48     ` poma
  2012-05-03  7:25       ` poma
  0 siblings, 1 reply; 16+ messages in thread
From: poma @ 2012-05-01  6:48 UTC (permalink / raw)
  To: linux-media

[-- Attachment #1: Type: text/plain, Size: 74707 bytes --]

On 04/30/2012 05:39 PM, Thomas Mair wrote:
> Signed-off-by: Thomas Mair <thomas.mair86@googlemail.com>
> ---
>  drivers/media/common/tuners/Kconfig        |    7 +
>  drivers/media/common/tuners/Makefile       |    1 +
>  drivers/media/common/tuners/fc0012-priv.h  |   42 ++
>  drivers/media/common/tuners/fc0012.c       |  384 +++++++++++++
>  drivers/media/common/tuners/fc0012.h       |   60 ++
>  drivers/media/dvb/dvb-usb/Kconfig          |    2 +
>  drivers/media/dvb/dvb-usb/dvb-usb-ids.h    |    2 +
>  drivers/media/dvb/dvb-usb/rtl28xxu.c       |  439 +++++++++++++---
>  drivers/media/dvb/frontends/Kconfig        |    7 +
>  drivers/media/dvb/frontends/Makefile       |    2 +-
>  drivers/media/dvb/frontends/rtl2832.c      |  832 ++++++++++++++++++++++++++++
>  drivers/media/dvb/frontends/rtl2832.h      |  300 ++++++++++
>  drivers/media/dvb/frontends/rtl2832_priv.h |   60 ++
>  13 files changed, 2070 insertions(+), 68 deletions(-)
>  create mode 100644 drivers/media/common/tuners/fc0012-priv.h
>  create mode 100644 drivers/media/common/tuners/fc0012.c
>  create mode 100644 drivers/media/common/tuners/fc0012.h
>  create mode 100644 drivers/media/dvb/frontends/rtl2832.c
>  create mode 100644 drivers/media/dvb/frontends/rtl2832.h
>  create mode 100644 drivers/media/dvb/frontends/rtl2832_priv.h
> 
> diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
> index 0fd15d9..8518251 100644
> --- a/drivers/media/common/tuners/Kconfig
> +++ b/drivers/media/common/tuners/Kconfig
> @@ -211,6 +211,13 @@ config MEDIA_TUNER_FC0011
>  	help
>  	  Fitipower FC0011 silicon tuner driver.
>  
> +config MEDIA_TUNER_FC0012
> +	tristate "Fitipower FC0012 silicon tuner"
> +	depends on VIDEO_MEDIA && I2C
> +	default m if MEDIA_TUNER_CUSTOMISE
> +	help
> +	  Fitipower FC0012 silicon tuner driver.
> +
>  config MEDIA_TUNER_TDA18212
>  	tristate "NXP TDA18212 silicon tuner"
>  	depends on VIDEO_MEDIA && I2C
> diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
> index 64ee06f..f046106 100644
> --- a/drivers/media/common/tuners/Makefile
> +++ b/drivers/media/common/tuners/Makefile
> @@ -30,6 +30,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
>  obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
>  obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
>  obj-$(CONFIG_MEDIA_TUNER_FC0011) += fc0011.o
> +obj-$(CONFIG_MEDIA_TUNER_FC0012) += fc0012.o
>  
>  ccflags-y += -I$(srctree)/drivers/media/dvb/dvb-core
>  ccflags-y += -I$(srctree)/drivers/media/dvb/frontends
> diff --git a/drivers/media/common/tuners/fc0012-priv.h b/drivers/media/common/tuners/fc0012-priv.h
> new file mode 100644
> index 0000000..c2c3c47
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012-priv.h
> @@ -0,0 +1,42 @@
> +/*
> + * Fitipower FC0012 tuner driver - private includes
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _FC0012_PRIV_H_
> +#define _FC0012_PRIV_H_
> +
> +#define LOG_PREFIX "fc0012"
> +
> +#undef err
> +#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
> +#undef info
> +#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
> +#undef warn
> +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
> +
> +struct fc0012_priv {
> +       struct i2c_adapter *i2c;
> +       u8 addr;
> +       u8 xtal_freq;
> +
> +       u32 frequency;
> +       u32 bandwidth;
> +};
> +
> +#endif
> diff --git a/drivers/media/common/tuners/fc0012.c b/drivers/media/common/tuners/fc0012.c
> new file mode 100644
> index 0000000..bb9f008
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012.c
> @@ -0,0 +1,384 @@
> +/*
> + * Fitipower FC0012 tuner driver
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#include "fc0012.h"
> +#include "fc0012-priv.h"
> +
> +static int fc0012_writereg(struct fc0012_priv *priv, u8 reg, u8 val)
> +{
> +	u8 buf[2] = {reg, val};
> +	struct i2c_msg msg = { .addr = priv->addr, .flags = 0, .buf = buf, .len = 2 };
> +
> +	if (i2c_transfer(priv->i2c, &msg, 1) != 1) {
> +		err("I2C write reg failed, reg: %02x, val: %02x", reg, val);
> +	return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int fc0012_readreg(struct fc0012_priv *priv, u8 reg, u8 *val)
> +{
> +	struct i2c_msg msg[2] = {
> +		{ .addr = priv->addr, .flags = 0, .buf = &reg, .len = 1 },
> +		{ .addr = priv->addr, .flags = I2C_M_RD, .buf = val, .len = 1 },
> +	};
> +
> +	if (i2c_transfer(priv->i2c, msg, 2) != 2) {
> +		err("I2C read failed, reg: %02x", reg);
> +		return -EREMOTEIO;
> +	}
> +	return 0;
> +}
> +
> +static int fc0012_release(struct dvb_frontend *fe)
> +{
> +	kfree(fe->tuner_priv);
> +	fe->tuner_priv = NULL;
> +	return 0;
> +}
> +
> +static int fc0012_init(struct dvb_frontend *fe)
> +{
> +	struct fc0012_priv *priv = fe->tuner_priv;
> +	int i, ret = 0;
> +	unsigned char reg[] = {
> +		0x00,   /* dummy reg. 0 */
> +		0x05,   /* reg. 0x01 */
> +		0x10,   /* reg. 0x02 */
> +		0x00,   /* reg. 0x03 */
> +		0x00,   /* reg. 0x04 */
> +		0x0f,   /* reg. 0x05 CHECK: correct? */ /* this is 0x0f in RTL (CNR test) */
> +		0x00,   /* reg. 0x06: divider 2, VCO slow */
> +		0x00,   /* reg. 0x07 */ /* this is also different in RTL code */
> +		0xff,   /* reg. 0x08: AGC Clock divide by 256, AGC gain 1/256,
> +			   Loop Bw 1/8 */
> +		0x6e,   /* reg. 0x09: Disable LoopThrough, Enable LoopThrough: 0x6f */
> +		0xb8,   /* reg. 0x0a: Disable LO Test Buffer */
> +		0x82,   /* reg. 0x0b: Output Clock is same as clock frequency */ /* also different in RTL*/
> +		0xfc,   /* reg. 0x0c: depending on AGC Up-Down mode, may need 0xf8 */ /* RTL */
> +		0x02,   /* reg. 0x0d: AGC Not Forcing & LNA Forcing, 0x02 for DVB-T */
> +		0x00,   /* reg. 0x0e */
> +		0x00,   /* reg. 0x0f */
> +		0x00,   /* reg. 0x10 */ /* RTL */
> +		0x00,   /* reg. 0x11 */
> +		0x1f,   /* reg. 0x12: Set to maximum gain */
> +		0x08,   /* reg. 0x13: Enable IX2, Set to Middle Gain: 0x08,
> +			   Low Gain: 0x00, High Gain: 0x10 */
> +		0x00,   /* reg. 0x14 */
> +		0x04,   /* reg. 0x15: Enable LNA COMPS */
> +	};
> +
> +	info("%s", __func__);
> +
> +	switch (priv->xtal_freq) {
> +	case FC_XTAL_27_MHZ:
> +	case FC_XTAL_28_8_MHZ:
> +		reg[0x07] |= 0x20;
> +		break;
> +	case FC_XTAL_36_MHZ:
> +	default:
> +		break;
> +	}
> +	
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
> +	
> +	for (i = 1; i < sizeof(reg); i++) {
> +		ret = fc0012_writereg(priv, i, reg[i]);
> +	if (ret)
> +		break;
> +	}
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
> +
> +	if (ret)
> +		warn("%s: failed: %d", __func__, ret);
> +	return ret;
> +}
> +
> +static int fc0012_sleep(struct dvb_frontend *fe)
> +{
> +	/* nothing to do here */
> +	return 0;
> +}
> +
> +static int fc0012_set_params(struct dvb_frontend *fe)
> +{
> +	struct fc0012_priv *priv = fe->tuner_priv;
> +	int i, ret = 0;
> +	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
> +	u32 freq = p->frequency / 1000;
> +	u32 delsys = p->delivery_system;
> +	unsigned char reg[0x16], am, pm, multi;
> +	unsigned long fVCO;
> +	unsigned short xtal_freq_khz_2, xin, xdiv;
> +	int vco_select = false;
> +
> +	info("%s", __func__);
> +
> +	if(fe->callback){
> +		ret = fe->callback(priv->i2c, DVB_FRONTEND_COMPONENT_TUNER, FC0012_FE_CALLBACK_UHF_ENABLE, (freq > 300000 ? 0 : 1));
> +		if (ret)
> +			goto exit;
> +	}
> +	
> +	switch (priv->xtal_freq) {
> +	case FC_XTAL_27_MHZ:
> +		xtal_freq_khz_2 = 27000 / 2;
> +		break;
> +	case FC_XTAL_36_MHZ:
> +		xtal_freq_khz_2 = 36000 / 2;
> +		break;
> +	case FC_XTAL_28_8_MHZ:
> +	default:
> +		xtal_freq_khz_2 = 28800 / 2;
> +		break;
> +	}
> +
> +	/* select frequency divider and the frequency of VCO */
> +	if (freq * 96 < 3560000) {
> +		multi = 96;
> +		reg[5] = 0x82;
> +		reg[6] = 0x00;
> +	} else if (freq * 64 < 3560000) {
> +		multi = 64;
> +		reg[5] = 0x82;
> +		reg[6] = 0x02;
> +	} else if (freq * 48 < 3560000) {
> +		multi = 48;
> +		reg[5] = 0x42;
> +		reg[6] = 0x00;
> +	} else if (freq * 32 < 3560000) {
> +		multi = 32;
> +		reg[5] = 0x42;
> +		reg[6] = 0x02;
> +	} else if (freq * 24 < 3560000) {
> +		multi = 24;
> +		reg[5] = 0x22;
> +		reg[6] = 0x00;
> +	} else if (freq * 16 < 3560000) {
> +		multi = 16;
> +		reg[5] = 0x22;
> +		reg[6] = 0x02;
> +	} else if (freq * 12 < 3560000) {
> +		multi = 12;
> +		reg[5] = 0x12;
> +		reg[6] = 0x00;
> +	} else if (freq * 8 < 3560000) {
> +		multi = 8;
> +		reg[5] = 0x12;
> +		reg[6] = 0x02;
> +	} else if (freq * 6 < 3560000) {
> +		multi = 6;
> +		reg[5] = 0x0a;
> +		reg[6] = 0x00;
> +	} else {
> +		multi = 4;
> +		reg[5] = 0x0a;
> +		reg[6] = 0x02;
> +	}
> +
> +	fVCO = freq * multi;
> +	
> +	reg[6] |= 0x08;
> +	vco_select = true;
> +
> +	/* From divided value (XDIV) determined the FA and FP value */
> +	xdiv = (unsigned short)(fVCO / xtal_freq_khz_2);
> +	if ((fVCO - xdiv * xtal_freq_khz_2) >= (xtal_freq_khz_2 / 2))
> +		xdiv++;
> +	
> +	pm = (unsigned char)(xdiv / 8);
> +	am = (unsigned char)(xdiv - (8 * pm));
> +	
> +	if (am < 2) {
> +		reg[1] = am + 8;
> +		reg[2] = pm - 1;
> +	} else {
> +		reg[1] = am;
> +		reg[2] = pm;
> +	}
> +
> +
> +	/* From VCO frequency determines the XIN ( fractional part of Delta
> +	Sigma PLL) and divided value (XDIV) */
> + 	xin = (unsigned short)(fVCO - (fVCO / xtal_freq_khz_2) * xtal_freq_khz_2);
> +	xin = (xin << 15) / xtal_freq_khz_2;
> +	if (xin >= 16384)
> +		xin += 32768;
> +
> +	reg[3] = xin >> 8;      /* xin with 9 bit resolution */
> +	reg[4] = xin & 0xff;
> +
> +	if (delsys == SYS_DVBT) {
> +		reg[6] &= 0x3f; /* bits 6 and 7 describe the bandwidth */
> +		switch (p->bandwidth_hz) {
> +		case 6000000:
> +			reg[6] |= 0x80;
> +			break;
> +		case 7000000:
> +			reg[6] &= ~0x80;
> +			reg[6] |= 0x40;
> +			break;
> +		case 8000000:
> +		default:
> +			reg[6] &= ~0xc0;
> +			break;
> +	}
> +	} else {
> +		err("%s: modulation type not supported!", __func__);
> +		return -EINVAL;
> +	}
> +
> +	/* modified for Realtek demod */
> +	reg[5] |= 0x07;
> +
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
> +
> +	for (i = 1; i <= 6; i++) {
> +		ret = fc0012_writereg(priv, i, reg[i]);
> +		if (ret)
> +			goto exit;
> +       }
> +
> +	/* VCO Calibration */
> +	ret = fc0012_writereg(priv, 0x0e, 0x80);
> +	if (!ret)
> +		ret = fc0012_writereg(priv, 0x0e, 0x00);
> +
> +	/* VCO Re-Calibration if needed */
> +	if (!ret)
> +		ret = fc0012_writereg(priv, 0x0e, 0x00);
> +
> +	if (!ret) {
> +		msleep(10);
> +		ret = fc0012_readreg(priv, 0x0e, &reg[0x0e]);
> +	}
> +	if (ret)
> +		goto exit;
> +
> +	/* vco selection */
> +	reg[0x0e] &= 0x3f;
> +
> +	if (vco_select) {
> +		if (reg[0x0e] > 0x3c) {
> +		reg[6] &= ~0x08;
> +			ret = fc0012_writereg(priv, 0x06, reg[6]);
> +		if (!ret)
> +			ret = fc0012_writereg(priv, 0x0e, 0x80);
> +		if (!ret)
> +			ret = fc0012_writereg(priv, 0x0e, 0x00);
> +	       }
> +	} else {
> +		if (reg[0x0e] < 0x02) {
> +			reg[6] |= 0x08;
> +			ret = fc0012_writereg(priv, 0x06, reg[6]);
> +			if (!ret)
> +				ret = fc0012_writereg(priv, 0x0e, 0x80);
> +			if (!ret)
> +				ret = fc0012_writereg(priv, 0x0e, 0x00);
> +		}
> +	}
> +
> +	priv->frequency = p->frequency;
> +	priv->bandwidth = p->bandwidth_hz;
> +
> +exit:
> +	if (fe->ops.i2c_gate_ctrl)
> +		fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
> +	if (ret)
> +		pr_debug("%s: failed: %d", __func__, ret);
> +	return ret;
> +}
> +
> +static int fc0012_get_frequency(struct dvb_frontend *fe, u32 *frequency)
> +{
> +       struct fc0012_priv *priv = fe->tuner_priv;
> +       *frequency = priv->frequency;
> +       return 0;
> +}
> +
> +static int fc0012_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
> +{
> +       /* CHECK: always ? */
> +       *frequency = 0;
> +       return 0;
> +}
> +
> +static int fc0012_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
> +{
> +       struct fc0012_priv *priv = fe->tuner_priv;
> +       *bandwidth = priv->bandwidth;
> +       return 0;
> +}
> +
> +
> +static const struct dvb_tuner_ops fc0012_tuner_ops = {
> +       .info = {
> +	       .name		= "Fitipower FC0012",
> +
> +	       .frequency_min	= 170000000,
> +	       .frequency_max	= 860000000,
> +	       .frequency_step	= 0,
> +       },
> +
> +       .release	= fc0012_release,
> +
> +       .init = fc0012_init,
> +       .sleep = fc0012_sleep,
> +
> +       .set_params = fc0012_set_params,
> +
> +       .get_frequency = fc0012_get_frequency,
> +       .get_if_frequency = fc0012_get_if_frequency,
> +       .get_bandwidth = fc0012_get_bandwidth,
> +};
> +
> +struct dvb_frontend * fc0012_attach(struct dvb_frontend *fe,
> +       struct i2c_adapter *i2c, u8 i2c_address,
> +       enum fc0012_xtal_freq xtal_freq)
> +{
> +       struct fc0012_priv *priv = NULL;
> +
> +       priv = kzalloc(sizeof(struct fc0012_priv), GFP_KERNEL);
> +       if (priv == NULL)
> +	       return NULL;
> +
> +       priv->i2c = i2c;
> +       priv->addr = i2c_address;
> +       priv->xtal_freq = xtal_freq;
> +
> +       info("Fitipower FC0012 successfully attached.");
> +
> +       fe->tuner_priv = priv;
> +
> +       memcpy(&fe->ops.tuner_ops, &fc0012_tuner_ops,
> +	       sizeof(struct dvb_tuner_ops));
> +
> +       return fe;
> +}
> +EXPORT_SYMBOL(fc0012_attach);
> +
> +MODULE_DESCRIPTION("Fitipower FC0012 silicon tuner driver");
> +MODULE_AUTHOR("Hans-Frieder Vogt <hfv...@gmx.net>");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("0.4");
> diff --git a/drivers/media/common/tuners/fc0012.h b/drivers/media/common/tuners/fc0012.h
> new file mode 100644
> index 0000000..1406e58
> --- /dev/null
> +++ b/drivers/media/common/tuners/fc0012.h
> @@ -0,0 +1,60 @@
> +/*
> + * Fitipower FC0012 tuner driver - include
> + *
> + * Copyright (C) 2012 Hans-Frieder Vogt <hfv...@gmx.net>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _FC0012_H_
> +#define _FC0012_H_
> +
> +#include "dvb_frontend.h"
> +
> +enum fc0012_xtal_freq {
> +       FC_XTAL_27_MHZ,         /* 27000000 */
> +       FC_XTAL_28_8_MHZ,       /* 28800000 */
> +       FC_XTAL_36_MHZ,         /* 36000000 */
> +};
> +
> +
> +/** enum fc0011_fe_callback_commands - Frontend callbacks
> + *
> + * @FC0012_FE_CALLBACK_VHF_ENABLE: enable VHF or UHF
> + */
> +enum fc0012_fe_callback_commands {
> +	FC0012_FE_CALLBACK_UHF_ENABLE,
> +};
> +
> +#define CONFIG_MEDIA_TUNER_FC0012
> +
> +#if defined(CONFIG_MEDIA_TUNER_FC0012) || \
> +        (defined(CONFIG_MEDIA_TUNER_FC0012_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
> +                                       struct i2c_adapter *i2c,
> +                                       u8 i2c_address,
> +                                       enum fc0012_xtal_freq xtal_freq);
> +#else
> +static inline struct dvb_frontend *fc0012_attach(struct dvb_frontend *fe,
> +                                               struct i2c_adapter *i2c,
> +                                               u8 i2c_address,
> +                                               enum fc0012_xtal_freq xtal_freq)
> +{
> +       printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +       return NULL;
> +}
> +#endif
> +
> +#endif
> diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
> index be1db75..a24bbc1 100644
> --- a/drivers/media/dvb/dvb-usb/Kconfig
> +++ b/drivers/media/dvb/dvb-usb/Kconfig
> @@ -417,9 +417,11 @@ config DVB_USB_RTL28XXU
>  	tristate "Realtek RTL28xxU DVB USB support"
>  	depends on DVB_USB && EXPERIMENTAL
>  	select DVB_RTL2830
> +	select DVB_RTL2832
>  	select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
>  	select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
>  	select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
> +	select MEDIA_TUNER_FC0012 if !MEDIA_TUNER_CUSTOMISE
>  	help
>  	  Say Y here to support the Realtek RTL28xxU DVB USB receiver.
>  
> diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> index 2418e41..1ffee60 100644
> --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
> @@ -135,6 +135,7 @@
>  #define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
>  #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
>  #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
> +#define USB_PID_GTEK					0xb803
>  #define USB_PID_INTEL_CE9500				0x9500
>  #define USB_PID_ITETECH_IT9135				0x9135
>  #define USB_PID_ITETECH_IT9135_9005			0x9005
> @@ -238,6 +239,7 @@
>  #define USB_PID_TERRATEC_CINERGY_T_EXPRESS		0x0062
>  #define USB_PID_TERRATEC_CINERGY_T_XXS			0x0078
>  #define USB_PID_TERRATEC_CINERGY_T_XXS_2		0x00ab
> +#define USB_PID_TERRATEC_CINERGY_T_STICK_BLACK		0x00a9
>  #define USB_PID_TERRATEC_H7				0x10b4
>  #define USB_PID_TERRATEC_H7_2				0x10a3
>  #define USB_PID_TERRATEC_T3				0x10a0
> diff --git a/drivers/media/dvb/dvb-usb/rtl28xxu.c b/drivers/media/dvb/dvb-usb/rtl28xxu.c
> index 8f4736a..1999c17 100644
> --- a/drivers/media/dvb/dvb-usb/rtl28xxu.c
> +++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c
> @@ -3,6 +3,7 @@
>   *
>   * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
>   * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@googlemail.com>
>   *
>   *    This program is free software; you can redistribute it and/or modify
>   *    it under the terms of the GNU General Public License as published by
> @@ -22,10 +23,12 @@
>  #include "rtl28xxu.h"
>  
>  #include "rtl2830.h"
> +#include "rtl2832.h"
>  
>  #include "qt1010.h"
>  #include "mt2060.h"
>  #include "mxl5005s.h"
> +#include "fc0012.h"
>  
>  /* debug */
>  static int dvb_usb_rtl28xxu_debug;
> @@ -76,7 +79,7 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
>  
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> @@ -297,7 +300,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
>  	/* for QT1010 tuner probe */
>  	struct rtl28xxu_req req_qt1010 = { 0x0fc4, CMD_I2C_RD, 1, buf };
>  
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
>  
>  	/*
>  	 * RTL2831U GPIOs
> @@ -312,6 +315,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
>  	if (ret)
>  		goto err;
>  
> +
>  	/* enable as output GPIO0, GPIO2, GPIO4 */
>  	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
>  	if (ret)
> @@ -332,10 +336,10 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
>  	if (ret == 0 && buf[0] == 0x2c) {
>  		priv->tuner = TUNER_RTL2830_QT1010;
>  		rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
> -		deb_info("%s: QT1010\n", __func__);
> +		deb_info("%s: QT1010", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: QT1010 probe failed=%d - %02x\n",
> +		deb_info("%s: QT1010 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
>  
> @@ -349,10 +353,10 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
>  	if (ret == 0 && buf[0] == 0x63) {
>  		priv->tuner = TUNER_RTL2830_MT2060;
>  		rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
> -		deb_info("%s: MT2060\n", __func__);
> +		deb_info("%s: MT2060", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: MT2060 probe failed=%d - %02x\n",
> +		deb_info("%s: MT2060 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
>  
> @@ -360,7 +364,7 @@ static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
>  	ret = 0;
>  	priv->tuner = TUNER_RTL2830_MXL5005S;
>  	rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
> -	deb_info("%s: MXL5005S\n", __func__);
> +	deb_info("%s: MXL5005S", __func__);
>  	goto found;
>  
>  found:
> @@ -374,37 +378,130 @@ found:
>  
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> +static struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
> +	.i2c_addr = 0x10, /* 0x20 */
> +	.xtal = 28800000,
> +	.ts_mode = 0,
> +	.spec_inv = 1,
> +	.if_dvbt = 0,
> +	.vtop = 0x20,
> +	.krf = 0x04,
> +	.agc_targ_val = 0x2d,
> +	.tuner = TUNER_RTL2832_FC0012
> +};
> +
> +
> +static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
> +		int cmd, int arg)
> +{
> +	int ret;
> +	u8 val;
> +
> +	info("%s cmd=%d arg=%d", __func__, cmd, arg);
> +	switch (cmd) {
> +	case FC0012_FE_CALLBACK_UHF_ENABLE:
> +		/* set output values */
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_DIR, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0xbf;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_DIR, val);
> +		if (ret)
> +			goto err;
> +
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x40;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
> +		if (ret)
> +			goto err;
> +
> +
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +			goto err;
> +
> +		if (arg)
> +			val &= 0xbf; /* set GPIO6 low */
> +		else
> +			val |= 0x40; /* set GPIO6 high */
> +		
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +		break;
> +	default:
> +		ret = -EINVAL;
> +		goto err;
> +	}
> +	return 0;
> +
> +err:
> +	err("%s: failed=%d", __func__, ret);
> +
> +	return ret;
> +}
> +
> +static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
> +{
> +	struct rtl28xxu_priv *priv = d->priv;
> +
> +	switch (priv->tuner) {
> +	case TUNER_RTL2832_FC0012:
> +		return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
> +	default:
> +		break;
> +	}
> +
> +	return -ENODEV;
> +}
> +
> +static int rtl2832u_frontend_callback(void *adapter_priv, int component,
> +				    int cmd, int arg)
> +{
> +	struct i2c_adapter *adap = adapter_priv;
> +	struct dvb_usb_device *d = i2c_get_adapdata(adap);
> +
> +	switch (component) {
> +	case DVB_FRONTEND_COMPONENT_TUNER:
> +		return rtl2832u_tuner_callback(d, cmd, arg);
> +	default:
> +		break;
> +	}
> +
> +	return -EINVAL;
> +}
> +
> +
> +
> +
>  static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
>  {
>  	int ret;
>  	struct rtl28xxu_priv *priv = adap->dev->priv;
> +	struct rtl2832_config *rtl2832_config;
> +
>  	u8 buf[1];
>  	/* open RTL2832U/RTL2832 I2C gate */
>  	struct rtl28xxu_req req_gate_open = {0x0120, 0x0011, 0x0001, "\x18"};
>  	/* close RTL2832U/RTL2832 I2C gate */
>  	struct rtl28xxu_req req_gate_close = {0x0120, 0x0011, 0x0001, "\x10"};
> -	/* for FC2580 tuner probe */
> -	struct rtl28xxu_req req_fc2580 = {0x01ac, CMD_I2C_RD, 1, buf};
> -
> -	deb_info("%s:\n", __func__);
> -
> -	/* GPIO direction */
> -	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_DIR, 0x0a);
> -	if (ret)
> -		goto err;
> +	/* for FC0012 tuner probe */
> +	struct rtl28xxu_req req_fc0012 = {0x00c6, CMD_I2C_RD, 1, buf};
>  
> -	/* enable as output GPIO0, GPIO2, GPIO4 */
> -	ret = rtl2831_wr_reg(adap->dev, SYS_GPIO_OUT_EN, 0x15);
> -	if (ret)
> -		goto err;
> -
> -	ret = rtl2831_wr_reg(adap->dev, SYS_DEMOD_CTL, 0xe8);
> -	if (ret)
> -		goto err;
> +	deb_info("%s:", __func__);
>  
>  	/*
>  	 * Probe used tuner. We need to know used tuner before demod attach
> @@ -416,17 +513,20 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
>  	if (ret)
>  		goto err;
>  
> -	/* check FC2580 ID register; reg=01 val=56 */
> -	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc2580);
> -	if (ret == 0 && buf[0] == 0x56) {
> -		priv->tuner = TUNER_RTL2832_FC2580;
> -		deb_info("%s: FC2580\n", __func__);
> +
> +	/* check FC0012 ID register; reg=00 val=a1 */
> +	ret = rtl28xxu_ctrl_msg(adap->dev, &req_fc0012);
> +	if (ret == 0 && buf[0] == 0xa1) {
> +		priv->tuner = TUNER_RTL2832_FC0012;
> +		rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
> +		deb_info("%s: FC0012", __func__);
>  		goto found;
>  	} else {
> -		deb_info("%s: FC2580 probe failed=%d - %02x\n",
> +		deb_info("%s: FC0012 probe failed=%d - %02x",
>  			__func__, ret, buf[0]);
>  	}
>  
> +
>  	/* close demod I2C gate */
>  	ret = rtl28xxu_ctrl_msg(adap->dev, &req_gate_close);
>  	if (ret)
> @@ -443,11 +543,19 @@ found:
>  		goto err;
>  
>  	/* attach demodulator */
> -	/* TODO: */
> +	adap->fe_adap[0].fe = dvb_attach(rtl2832_attach, rtl2832_config,
> +		&adap->dev->i2c_adap, priv->tuner);
> +		if (adap->fe_adap[0].fe == NULL) {
> +			ret = -ENODEV;
> +			goto err;
> +		}
> +
> +	/* set fe callbacks */
> +	adap->fe_adap[0].fe->callback = rtl2832u_frontend_callback;
>  
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> @@ -484,7 +592,7 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
>  	struct i2c_adapter *rtl2830_tuner_i2c;
>  	struct dvb_frontend *fe;
>  
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
>  
>  	/* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
>  	rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe_adap[0].fe);
> @@ -515,7 +623,7 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
>  
>  	return 0;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> @@ -525,12 +633,13 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
>  	struct rtl28xxu_priv *priv = adap->dev->priv;
>  	struct dvb_frontend *fe;
>  
> -	deb_info("%s:\n", __func__);
> +	deb_info("%s:", __func__);
>  
>  	switch (priv->tuner) {
> -	case TUNER_RTL2832_FC2580:
> -		/* TODO: */
> -		fe = NULL;
> +	case TUNER_RTL2832_FC0012:
> +		fe = dvb_attach(fc0012_attach, adap->fe_adap[0].fe,
> +			&adap->dev->i2c_adap, 0xc6>>1, FC_XTAL_28_8_MHZ);
> +		return 0;
>  		break;
>  	default:
>  		fe = NULL;
> @@ -544,16 +653,16 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
>  
>  	return 0;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> -static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
> +static int rtl2831u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
>  {
>  	int ret;
>  	u8 buf[2], gpio;
>  
> -	deb_info("%s: onoff=%d\n", __func__, onoff);
> +	deb_info("%s: onoff=%d", __func__, onoff);
>  
>  	ret = rtl2831_rd_reg(adap->dev, SYS_GPIO_OUT_VAL, &gpio);
>  	if (ret)
> @@ -579,16 +688,186 @@ static int rtl28xxu_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
>  
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> -static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
> +static int rtl2832u_streaming_ctrl(struct dvb_usb_adapter *adap , int onoff)
> +{
> +	int ret;
> +	u8 buf[2];
> +
> +	deb_info("%s: onoff=%d", __func__, onoff);
> +
> +
> +	if (onoff) {
> +		buf[0] = 0x00;
> +		buf[1] = 0x00;
> +	} else {
> +		buf[0] = 0x10; /* stall EPA */
> +		buf[1] = 0x02; /* reset EPA */
> +	}
> +
> +	ret = rtl2831_wr_regs(adap->dev, USB_EPA_CTL, buf, 2);
> +	if (ret)
> +		goto err;
> +
> +	return ret;
> +err:
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +
> +static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff) {
> +
> +	int ret;
> +	struct rtl28xxu_req req;
> +	u8 val;
> +
> +	deb_info("%s: onoff=%d", __func__, onoff);
> +
> +	if(onoff){
> +		/* set output values */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x08;
> +		val &= 0xef;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* enable as output GPIO3 */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_EN, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x08;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_EN, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod_ctl_1 */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0xef;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod control */
> +		/* PLL enable */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		/* bit 7 to 1 */
> +		val |= 0x80;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod HW reset */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +		/* bit 5 to 0 */
> +		val &= 0xdf;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x20;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* set page cache to 0 */
> +		req.index = 0x0;
> +		req.value = 0x20 + (1<<8);
> +		req.data = &val;
> +		req.size = 1;
> +		ret = rtl28xxu_ctrl_msg(d, &req);
> +		if (ret)
> +			goto err;
> +
> +
> +		mdelay(5);
> +
> +		/*enable ADC_Q and ADC_I */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x48;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +
> +	} else {
> +		/* demod_ctl_1 */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL1, &val);
> +		if (ret)
> +			goto err;
> +
> +		val |= 0x0c;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL1, val);
> +		if (ret)
> +			goto err;
> +
> +		/* set output values */
> +		ret = rtl2831_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
> +		if (ret)
> +				goto err;
> +
> +		val |= 0x10;
> +
> +		ret = rtl2831_wr_reg(d, SYS_GPIO_OUT_VAL, val);
> +		if (ret)
> +			goto err;
> +
> +		/* demod control */
> +		ret = rtl2831_rd_reg(d, SYS_DEMOD_CTL, &val);
> +		if (ret)
> +			goto err;
> +
> +		val &= 0x37;
> +
> +		ret = rtl2831_wr_reg(d, SYS_DEMOD_CTL, val);
> +		if (ret)
> +			goto err;
> +
> +	}
> +
> +	return ret;
> +err:
> +	deb_info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
>  {
>  	int ret;
>  	u8 gpio, sys0;
>  
> -	deb_info("%s: onoff=%d\n", __func__, onoff);
> +	deb_info("%s: onoff=%d", __func__, onoff);
>  
>  	/* demod adc */
>  	ret = rtl2831_rd_reg(d, SYS_SYS0, &sys0);
> @@ -600,12 +879,12 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
>  	if (ret)
>  		goto err;
>  
> -	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
> +	deb_info("%s: RD SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
>  
>  	if (onoff) {
>  		gpio |= 0x01; /* GPIO0 = 1 */
>  		gpio &= (~0x10); /* GPIO4 = 0 */
> -		sys0 = sys0 & 0x0f;
> +		sys0 = sys0 & 0x0f; /* enable demod adc */
>  		sys0 |= 0xe0;
>  	} else {
>  		gpio &= (~0x01); /* GPIO0 = 0 */
> @@ -613,7 +892,7 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
>  		sys0 = sys0 & (~0xc0);
>  	}
>  
> -	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__, sys0, gpio);
> +	deb_info("%s: WR SYS0=%02x GPIO_OUT_VAL=%02x", __func__, sys0, gpio);
>  
>  	/* demod adc */
>  	ret = rtl2831_wr_reg(d, SYS_SYS0, sys0);
> @@ -627,7 +906,7 @@ static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
>  
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> @@ -699,10 +978,12 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
>  
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> +/* unused for now */
> +#if 0
>  static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  {
>  	int ret, i;
> @@ -760,14 +1041,17 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
>  exit:
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
> +#endif
>  
>  enum rtl28xxu_usb_table_entry {
>  	RTL2831U_0BDA_2831,
>  	RTL2831U_14AA_0160,
>  	RTL2831U_14AA_0161,
> +	RTL2832U_0CCD_00A9,
> +	RTL2832U_1F4D_B803,
>  };
>  
>  static struct usb_device_id rtl28xxu_table[] = {
> @@ -780,6 +1064,10 @@ static struct usb_device_id rtl28xxu_table[] = {
>  		USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2)},
>  
>  	/* RTL2832U */
> +	[RTL2832U_0CCD_00A9] = {
> +		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
> +	[RTL2832U_1F4D_B803] = {
> +		USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
>  	{} /* terminating entry */
>  };
>  
> @@ -802,7 +1090,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
>  					{
>  						.frontend_attach = rtl2831u_frontend_attach,
>  						.tuner_attach    = rtl2831u_tuner_attach,
> -						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
> +						.streaming_ctrl  = rtl2831u_streaming_ctrl,
>  						.stream = {
>  							.type = USB_BULK,
>  							.count = 6,
> @@ -818,7 +1106,7 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
>  			}
>  		},
>  
> -		.power_ctrl = rtl28xxu_power_ctrl,
> +		.power_ctrl = rtl2831u_power_ctrl,
>  
>  		.rc.core = {
>  			.protocol       = RC_TYPE_NEC,
> @@ -864,11 +1152,11 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
>  					{
>  						.frontend_attach = rtl2832u_frontend_attach,
>  						.tuner_attach    = rtl2832u_tuner_attach,
> -						.streaming_ctrl  = rtl28xxu_streaming_ctrl,
> +						.streaming_ctrl  = rtl2832u_streaming_ctrl,
>  						.stream = {
>  							.type = USB_BULK,
> -							.count = 6,
> -							.endpoint = 0x81,
> +							.count = 10,
> +							.endpoint = 0x01,
>  							.u = {
>  								.bulk = {
>  									.buffersize = 8*512,
> @@ -880,23 +1168,32 @@ static struct dvb_usb_device_properties rtl28xxu_properties[] = {
>  			}
>  		},
>  
> -		.power_ctrl = rtl28xxu_power_ctrl,
> +		.power_ctrl = rtl2832u_power_ctrl,
>  
> -		.rc.core = {
> +		/*.rc.core = {
>  			.protocol       = RC_TYPE_NEC,
>  			.module_name    = "rtl28xxu",
>  			.rc_query       = rtl2832u_rc_query,
>  			.rc_interval    = 400,
>  			.allowed_protos = RC_TYPE_NEC,
>  			.rc_codes       = RC_MAP_EMPTY,
> -		},
> +		},*/
>  
>  		.i2c_algo = &rtl28xxu_i2c_algo,
>  
> -		.num_device_descs = 0, /* disabled as no support for RTL2832 */
> +		.num_device_descs = 2,
>  		.devices = {
>  			{
> -				.name = "Realtek RTL2832U reference design",
> +				.name = "Terratec Cinergy T Stick Black",
> +				.warm_ids = {
> +					&rtl28xxu_table[RTL2832U_0CCD_00A9],
> +				},
> +			},
> +			{
> +				.name = "G-Tek Electronics Group Lifeview LV5TDLX DVB-T [RTL2832U]",
> +				.warm_ids = {
> +					&rtl28xxu_table[RTL2832U_1F4D_B803],
> +				},
>  			},
>  		}
>  	},
> @@ -907,10 +1204,11 @@ static int rtl28xxu_probe(struct usb_interface *intf,
>  		const struct usb_device_id *id)
>  {
>  	int ret, i;
> +	u8 val;
>  	int properties_count = ARRAY_SIZE(rtl28xxu_properties);
>  	struct dvb_usb_device *d;
>  
> -	deb_info("%s: interface=%d\n", __func__,
> +	deb_info("%s: interface=%d", __func__,
>  		intf->cur_altsetting->desc.bInterfaceNumber);
>  
>  	if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
> @@ -926,22 +1224,31 @@ static int rtl28xxu_probe(struct usb_interface *intf,
>  	if (ret)
>  		goto err;
>  
> +
>  	/* init USB endpoints */
> -	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, 0x09);
> +	ret = rtl2831_rd_reg(d, USB_SYSCTL_0, &val);
> +	if (ret)
> +			goto err;
> +
> +	/* enable DMA and Full Packet Mode*/
> +	val |= 0x09;
> +	ret = rtl2831_wr_reg(d, USB_SYSCTL_0, val);
>  	if (ret)
>  		goto err;
>  
> +	/* set EPA maximum packet size to 0x0200 */
>  	ret = rtl2831_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
>  	if (ret)
>  		goto err;
>  
> +	/* change EPA FIFO length */
>  	ret = rtl2831_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
>  	if (ret)
>  		goto err;
>  
>  	return ret;
>  err:
> -	deb_info("%s: failed=%d\n", __func__, ret);
> +	deb_info("%s: failed=%d", __func__, ret);
>  	return ret;
>  }
>  
> @@ -957,8 +1264,6 @@ static int __init rtl28xxu_module_init(void)
>  {
>  	int ret;
>  
> -	deb_info("%s:\n", __func__);
> -
>  	ret = usb_register(&rtl28xxu_driver);
>  	if (ret)
>  		err("usb_register failed=%d", ret);
> @@ -968,7 +1273,6 @@ static int __init rtl28xxu_module_init(void)
>  
>  static void __exit rtl28xxu_module_exit(void)
>  {
> -	deb_info("%s:\n", __func__);
>  
>  	/* deregister this driver from the USB subsystem */
>  	usb_deregister(&rtl28xxu_driver);
> @@ -979,4 +1283,5 @@ module_exit(rtl28xxu_module_exit);
>  
>  MODULE_DESCRIPTION("Realtek RTL28xxU DVB USB driver");
>  MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
> +MODULE_AUTHOR("Thomas Mair <thomas.mair86@googlemail.com>");
>  MODULE_LICENSE("GPL");
> diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
> index f479834..f7d67d7 100644
> --- a/drivers/media/dvb/frontends/Kconfig
> +++ b/drivers/media/dvb/frontends/Kconfig
> @@ -432,6 +432,13 @@ config DVB_RTL2830
>  	help
>  	  Say Y when you want to support this frontend.
>  
> +config DVB_RTL2832
> +	tristate "Realtek RTL2832 DVB-T"
> +	depends on DVB_CORE && I2C
> +	default m if DVB_FE_CUSTOMISE
> +	help
> +	  Say Y when you want to support this frontend.
> +
>  comment "DVB-C (cable) frontends"
>  	depends on DVB_CORE
>  
> diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
> index b0381dc..a109aae 100644
> --- a/drivers/media/dvb/frontends/Makefile
> +++ b/drivers/media/dvb/frontends/Makefile
> @@ -100,4 +100,4 @@ obj-$(CONFIG_DVB_TDA10071) += tda10071.o
>  obj-$(CONFIG_DVB_RTL2830) += rtl2830.o
>  obj-$(CONFIG_DVB_M88RS2000) += m88rs2000.o
>  obj-$(CONFIG_DVB_AF9033) += af9033.o
> -
> +obj-$(CONFIG_DVB_RTL2832) += rtl2832.o
> diff --git a/drivers/media/dvb/frontends/rtl2832.c b/drivers/media/dvb/frontends/rtl2832.c
> new file mode 100644
> index 0000000..920b068
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832.c
> @@ -0,0 +1,832 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    This program is free software; you can redistribute it and/or modify
> + *    it under the terms of the GNU General Public License as published by
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License along
> + *    with this program; if not, write to the Free Software Foundation, Inc.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#include "rtl2832_priv.h"
> +
> +
> +
> +int rtl2832_debug = 1;
> +module_param_named(debug, rtl2832_debug, int, 0644);
> +MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
> +
> +
> +static int reg_mask[32] = {
> +    0x00000001,
> +    0x00000003,
> +    0x00000007,
> +    0x0000000f,
> +    0x0000001f,
> +    0x0000003f,
> +    0x0000007f,
> +    0x000000ff,
> +    0x000001ff,
> +    0x000003ff,
> +    0x000007ff,
> +    0x00000fff,
> +    0x00001fff,
> +    0x00003fff,
> +    0x00007fff,
> +    0x0000ffff,
> +    0x0001ffff,
> +    0x0003ffff,
> +    0x0007ffff,
> +    0x000fffff,
> +    0x001fffff,
> +    0x003fffff,
> +    0x007fffff,
> +    0x00ffffff,
> +    0x01ffffff,
> +    0x03ffffff,
> +    0x07ffffff,
> +    0x0fffffff,
> +    0x1fffffff,
> +    0x3fffffff,
> +    0x7fffffff,
> +    0xffffffff
> +};
> +
> +static const rtl2832_reg_entry registers[] = {
> +  [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2},
> +  [DVBT_IIC_REPEAT] = {0x1,  0x1,   3,  3},
> +  [DVBT_TR_WAIT_MIN_8K]   = {0x1,  0x88,   11,  2},
> +  [DVBT_RSD_BER_FAIL_VAL] = {0x1,  0x8f,   15,  0},
> +  [DVBT_EN_BK_TRK]        = {0x1,  0xa6,   7,  7},
> +  [DVBT_AD_EN_REG]        = {0x0,  0x8,   7,  7},
> +  [DVBT_AD_EN_REG1]       = {0x0,  0x8,   6,  6},
> +  [DVBT_EN_BBIN]          = {0x1,  0xb1,   0,  0},
> +  [DVBT_MGD_THD0]         = {0x1,  0x95,   7,  0},
> +  [DVBT_MGD_THD1]         = {0x1,  0x96,   7,  0},
> +  [DVBT_MGD_THD2]         = {0x1,  0x97,   7,  0},
> +  [DVBT_MGD_THD3]         = {0x1,  0x98,   7,  0},
> +  [DVBT_MGD_THD4]         = {0x1,  0x99,   7,  0},
> +  [DVBT_MGD_THD5]         = {0x1,  0x9a,   7,  0},
> +  [DVBT_MGD_THD6]         = {0x1,  0x9b,   7,  0},
> +  [DVBT_MGD_THD7]         = {0x1,  0x9c,   7,  0},
> +  [DVBT_EN_CACQ_NOTCH]    = {0x1,  0x61,   4,  4},
> +  [DVBT_AD_AV_REF]        = {0x0,  0x9,   6,  0},
> +  [DVBT_REG_PI]           = {0x0,  0xa,   2,  0},
> +  [DVBT_PIP_ON]           = {0x0,  0x21,   3,  3},
> +  [DVBT_SCALE1_B92]       = {0x2,  0x92,   7,  0},
> +  [DVBT_SCALE1_B93]       = {0x2,  0x93,   7,  0},
> +  [DVBT_SCALE1_BA7]       = {0x2,  0xa7,   7,  0},
> +  [DVBT_SCALE1_BA9]       = {0x2,  0xa9,   7,  0},
> +  [DVBT_SCALE1_BAA]       = {0x2,  0xaa,   7,  0},
> +  [DVBT_SCALE1_BAB]       = {0x2,  0xab,   7,  0},
> +  [DVBT_SCALE1_BAC]       = {0x2,  0xac,   7,  0},
> +  [DVBT_SCALE1_BB0]       = {0x2,  0xb0,   7,  0},
> +  [DVBT_SCALE1_BB1]       = {0x2,  0xb1,   7,  0},
> +  [DVBT_KB_P1]            = {0x1,  0x64,   3,  1},
> +  [DVBT_KB_P2]            = {0x1,  0x64,   6,  4},
> +  [DVBT_KB_P3]            = {0x1,  0x65,   2,  0},
> +  [DVBT_OPT_ADC_IQ]       = {0x0,  0x6,   5,  4},
> +  [DVBT_AD_AVI]           = {0x0,  0x9,   1,  0},
> +  [DVBT_AD_AVQ]           = {0x0,  0x9,   3,  2},
> +  [DVBT_K1_CR_STEP12]     = {0x2,  0xad,   9,  4},
> +  [DVBT_TRK_KS_P2]        = {0x1,  0x6f,   2,  0},
> +  [DVBT_TRK_KS_I2]        = {0x1,  0x70,   5,  3},
> +  [DVBT_TR_THD_SET2]      = {0x1,  0x72,   3,  0},
> +  [DVBT_TRK_KC_P2]        = {0x1,  0x73,   5,  3},
> +  [DVBT_TRK_KC_I2]        = {0x1,  0x75,   2,  0},
> +  [DVBT_CR_THD_SET2]      = {0x1,  0x76,   7,  6},
> +  [DVBT_PSET_IFFREQ]     = {0x1,  0x19,   21,  0},
> +  [DVBT_SPEC_INV]        = {0x1,  0x15,   0,  0},
> +  [DVBT_RSAMP_RATIO]     = {0x1,  0x9f,   27,  2},
> +  [DVBT_CFREQ_OFF_RATIO] = {0x1,  0x9d,   23,  4},
> +  [DVBT_FSM_STAGE]       = {0x3,  0x51,   6,  3},
> +  [DVBT_RX_CONSTEL]      = {0x3,  0x3c,   3,  2},
> +  [DVBT_RX_HIER]         = {0x3,  0x3c,   6,  4},
> +  [DVBT_RX_C_RATE_LP]    = {0x3,  0x3d,   2,  0},
> +  [DVBT_RX_C_RATE_HP]    = {0x3,  0x3d,   5,  3},
> +  [DVBT_GI_IDX]          = {0x3,  0x51,   1,  0},
> +  [DVBT_FFT_MODE_IDX]    = {0x3,  0x51,   2,  2},
> +  [DVBT_RSD_BER_EST]     = {0x3,  0x4e,   15,  0},
> +  [DVBT_CE_EST_EVM]      = {0x4,  0xc,   15,  0},
> +  [DVBT_RF_AGC_VAL]      = {0x3,  0x5b,   13,  0},
> +  [DVBT_IF_AGC_VAL]      = {0x3,  0x59,   13,  0},
> +  [DVBT_DAGC_VAL]        = {0x3,  0x5,   7,  0},
> +  [DVBT_SFREQ_OFF]       = {0x3,  0x18,   13,  0},
> +  [DVBT_CFREQ_OFF]       = {0x3,  0x5f,   17,  0},
> +  [DVBT_POLAR_RF_AGC]    = {0x0,  0xe,   1,  1},
> +  [DVBT_POLAR_IF_AGC]    = {0x0,  0xe,   0,  0},
> +  [DVBT_AAGC_HOLD]       = {0x1,  0x4,   5,  5},
> +  [DVBT_EN_RF_AGC]       = {0x1,  0x4,   6,  6},
> +  [DVBT_EN_IF_AGC]       = {0x1,  0x4,   7,  7},
> +  [DVBT_IF_AGC_MIN]      = {0x1,  0x8,   7,  0},
> +  [DVBT_IF_AGC_MAX]      = {0x1,  0x9,   7,  0},
> +  [DVBT_RF_AGC_MIN]      = {0x1,  0xa,   7,  0},
> +  [DVBT_RF_AGC_MAX]      = {0x1,  0xb,   7,  0},
> +  [DVBT_IF_AGC_MAN]      = {0x1,  0xc,   6,  6},
> +  [DVBT_IF_AGC_MAN_VAL]  = {0x1,  0xc,   13,  0},
> +  [DVBT_RF_AGC_MAN]      = {0x1,  0xe,   6,  6},
> +  [DVBT_RF_AGC_MAN_VAL]  = {0x1,  0xe,   13,  0},
> +  [DVBT_DAGC_TRG_VAL]    = {0x1,  0x12,   7,  0},
> +  [DVBT_AGC_TARG_VAL_0]  = {0x1,  0x2,   0,  0},
> +  [DVBT_AGC_TARG_VAL_8_1] = {0x1,  0x3,   7,  0},
> +  [DVBT_AAGC_LOOP_GAIN]  = {0x1,  0xc7,   5,  1},
> +  [DVBT_LOOP_GAIN2_3_0]  = {0x1,  0x4,   4,  1},
> +  [DVBT_LOOP_GAIN2_4]    = {0x1,  0x5,   7,  7},
> +  [DVBT_LOOP_GAIN3]      = {0x1,  0xc8,   4,  0},
> +  [DVBT_VTOP1]           = {0x1,  0x6,   5,  0},
> +  [DVBT_VTOP2]           = {0x1,  0xc9,   5,  0},
> +  [DVBT_VTOP3]           = {0x1,  0xca,   5,  0},
> +  [DVBT_KRF1]            = {0x1,  0xcb,   7,  0},
> +  [DVBT_KRF2]            = {0x1,  0x7,   7,  0},
> +  [DVBT_KRF3]            = {0x1,  0xcd,   7,  0},
> +  [DVBT_KRF4]            = {0x1,  0xce,   7,  0},
> +  [DVBT_EN_GI_PGA]       = {0x1,  0xe5,   0,  0},
> +  [DVBT_THD_LOCK_UP]     = {0x1,  0xd9,   8,  0},
> +  [DVBT_THD_LOCK_DW]     = {0x1,  0xdb,   8,  0},
> +  [DVBT_THD_UP1]         = {0x1,  0xdd,   7,  0},
> +  [DVBT_THD_DW1]         = {0x1,  0xde,   7,  0},
> +  [DVBT_INTER_CNT_LEN]   = {0x1,  0xd8,   3,  0},
> +  [DVBT_GI_PGA_STATE]    = {0x1,  0xe6,   3,  3},
> +  [DVBT_EN_AGC_PGA]      = {0x1,  0xd7,   0,  0},
> +  [DVBT_CKOUTPAR]        = {0x1,  0x7b,   5,  5},
> +  [DVBT_CKOUT_PWR]       = {0x1,  0x7b,   6,  6},
> +  [DVBT_SYNC_DUR]        = {0x1,  0x7b,   7,  7},
> +  [DVBT_ERR_DUR]         = {0x1,  0x7c,   0,  0},
> +  [DVBT_SYNC_LVL]        = {0x1,  0x7c,   1,  1},
> +  [DVBT_ERR_LVL]         = {0x1,  0x7c,   2,  2},
> +  [DVBT_VAL_LVL]         = {0x1,  0x7c,   3,  3},
> +  [DVBT_SERIAL]          = {0x1,  0x7c,   4,  4},
> +  [DVBT_SER_LSB]         = {0x1,  0x7c,   5,  5},
> +  [DVBT_CDIV_PH0]        = {0x1,  0x7d,   3,  0},
> +  [DVBT_CDIV_PH1]        = {0x1,  0x7d,   7,  4},
> +  [DVBT_MPEG_IO_OPT_2_2] = {0x0,  0x6,   7,  7},
> +  [DVBT_MPEG_IO_OPT_1_0] = {0x0,  0x7,   7,  6},
> +  [DVBT_CKOUTPAR_PIP]    = {0x0,  0xb7,   4,  4},
> +  [DVBT_CKOUT_PWR_PIP]   = {0x0,  0xb7,   3,  3},
> +  [DVBT_SYNC_LVL_PIP]    = {0x0,  0xb7,   2,  2},
> +  [DVBT_ERR_LVL_PIP]     = {0x0,  0xb7,   1,  1},
> +  [DVBT_VAL_LVL_PIP]     = {0x0,  0xb7,   0,  0},
> +  [DVBT_CKOUTPAR_PID]    = {0x0,  0xb9,   4,  4},
> +  [DVBT_CKOUT_PWR_PID]   = {0x0,  0xb9,   3,  3},
> +  [DVBT_SYNC_LVL_PID]    = {0x0,  0xb9,   2,  2},
> +  [DVBT_ERR_LVL_PID]     = {0x0,  0xb9,   1,  1},
> +  [DVBT_VAL_LVL_PID]     = {0x0,  0xb9,   0,  0},
> +  [DVBT_SM_PASS]         = {0x1,  0x93,   11,  0},
> +  [DVBT_AD7_SETTING]     = {0x0,  0x11,   15,  0},
> +  [DVBT_RSSI_R]          = {0x3,  0x1,   6,  0},
> +  [DVBT_ACI_DET_IND]     = {0x3,  0x12,   0,  0},
> +  [DVBT_REG_MON]        = {0x0,  0xd,   1,  0},
> +  [DVBT_REG_MONSEL]     = {0x0,  0xd,   2,  2},
> +  [DVBT_REG_GPE]        = {0x0,  0xd,   7,  7},
> +  [DVBT_REG_GPO]        = {0x0,  0x10,   0,  0},
> +  [DVBT_REG_4MSEL]      = {0x0,  0x13,   0,  0},
> +};
> +
> +
> +
> +/* write multiple hardware registers */
> +static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
> +{
> +	int ret;
> +	u8 buf[1+len];
> +	struct i2c_msg msg[1] = {
> +		{
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = 0,
> +			.len = 1+len,
> +			.buf = buf,
> +		}
> +	};
> +
> +	buf[0] = reg;
> +	memcpy(&buf[1], val, len);
> +
> +	ret = i2c_transfer(priv->i2c, msg, 1);
> +	if (ret == 1) {
> +		ret = 0;
> +	} else {
> +		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
> +		ret = -EREMOTEIO;
> +	}
> +	return ret;
> +}
> +
> +/* read multiple hardware registers */
> +static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
> +{
> +	int ret;
> +	struct i2c_msg msg[2] = {
> +		{
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = 0,
> +			.len = 1,
> +			.buf = &reg,
> +		}, {
> +			.addr = priv->cfg.i2c_addr,
> +			.flags = I2C_M_RD,
> +			.len = len,
> +			.buf = val,
> +		}
> +	};
> +
> +	ret = i2c_transfer(priv->i2c, msg, 2);
> +	if (ret == 2) {
> +		ret = 0;
> +	} else {
> +		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
> +		ret = -EREMOTEIO;
> +	}
> +	return ret;
> +}
> +
> +/* write multiple registers */
> +static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, int len)
> +{
> +	int ret;
> +
> +
> +	/* switch bank if needed */
> +	if (page != priv->page) {
> +		ret = rtl2832_wr(priv, 0x00, &page, 1);
> +		if (ret)
> +			return ret;
> +
> +		priv->page = page;
> +	}
> +
> +	return rtl2832_wr(priv, reg, val, len);
> +}
> +
> +/* read multiple registers */
> +static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val, int len)
> +{
> +	int ret;
> +
> +	/* switch bank if needed */
> +	if (page != priv->page) {
> +		ret = rtl2832_wr(priv, 0x00, &page, 1);
> +		if (ret)
> +			return ret;
> +
> +		priv->page = page;
> +	}
> +
> +	return rtl2832_rd(priv, reg, val, len);
> +}
> +
> +#if 0 /* currently not used */
> +/* write single register */
> +static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
> +{
> +	return rtl2832_wr_regs(priv, reg, page, &val, 1);
> +}
> +#endif
> +
> +/* read single register */
> +static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
> +{
> +	return rtl2832_rd_regs(priv, reg, page, val, 1);
> +}
> +
> +int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val){
> +	int ret;
> +
> +	u8 reg_start_addr;
> +	u8 msb, lsb;
> +	u8 page;
> +	u8 reading[4];
> +	u32 reading_tmp;
> +	int i;
> +
> +	u8 len;
> +	u32 mask;
> +
> +	reg_start_addr = registers[reg].start_address;
> +	msb = registers[reg].msb;
> +	lsb = registers[reg].lsb;
> +	page = registers[reg].page;
> +
> +	len = (msb >> 3) + 1;
> +	mask = reg_mask[msb-lsb];
> +
> +
> +	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
> +	if (ret)
> +		goto err;
> +
> +	reading_tmp = 0;
> +	for(i = 0; i < len; i++){
> +		reading_tmp |= reading[i] << ((len-1-i)*8);
> +	}
> +
> +	*val = (reading_tmp >> lsb) & mask;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +
> +}
> +
> +int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
> +{
> +	int ret, i;
> +	u8 len;
> +	u8 reg_start_addr;
> +	u8 msb, lsb;
> +	u8 page;
> +	u32 mask;
> +
> +
> +	u8 reading[4];
> +	u8 writing[4];
> +	u32 reading_tmp;
> +	u32 writing_tmp;
> +
> +
> +	reg_start_addr = registers[reg].start_address;
> +	msb = registers[reg].msb;
> +	lsb = registers[reg].lsb;
> +	page = registers[reg].page;
> +
> +	len = (msb >> 3) + 1;
> +	mask = reg_mask[msb-lsb];
> +
> +
> +	ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
> +	if (ret)
> +		goto err;
> +
> +	reading_tmp = 0;
> +	for (i = 0; i < len; i++) {
> +		reading_tmp |= reading[i] << ((len-1-i)*8);
> +	}
> +
> +	writing_tmp = reading_tmp & ~(mask << lsb);
> +	writing_tmp |= ((val & mask) << lsb);
> +
> +
> +	for (i = 0; i < len; i++) {
> +		writing[i] = (writing_tmp >> ((len-1-i)*8)) & 0xff;
> +	}
> +
> +	ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
> +	if(ret)
> +		goto err;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +
> +}
> +
> +
> +static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
> +{
> +	int ret;
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	dbg("%s: enable=%d", __func__, enable);
> +
> +	/* gate already open or close */
> +	if (priv->i2c_gate_state == enable)
> +		return 0;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable?0x1:0x0));
> +
> +	if (ret)
> +		goto err;
> +
> +	priv->i2c_gate_state = enable;
> +
> +	return ret;
> +err:
> +	dbg("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +
> +
> +static int rtl2832_init(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	int i, ret;
> +
> +	u8 en_bbin;
> +	u64 pset_iffreq;
> +
> +	/* initialization values for the demodulator registers */
> +	static rtl2832_reg_value rtl2832_initial_regs_1[] = {
> +			{DVBT_AD_EN_REG,			0x1		},
> +			{DVBT_AD_EN_REG1,			0x1		},
> +			{DVBT_RSD_BER_FAIL_VAL,		0x2800	},
> +			{DVBT_MGD_THD0,				0x10	},
> +			{DVBT_MGD_THD1,				0x20	},
> +			{DVBT_MGD_THD2,				0x20	},
> +			{DVBT_MGD_THD3,				0x40	},
> +			{DVBT_MGD_THD4,				0x22	},
> +			{DVBT_MGD_THD5,				0x32	},
> +			{DVBT_MGD_THD6,				0x37	},
> +			{DVBT_MGD_THD7,				0x39	},
> +			{DVBT_EN_BK_TRK,			0x0		},
> +			{DVBT_EN_CACQ_NOTCH,		0x0		},
> +			{DVBT_AD_AV_REF,			0x2a	},
> +			{DVBT_REG_PI,				0x6		},
> +			{DVBT_PIP_ON,				0x0		},
> +			{DVBT_CDIV_PH0,				0x8		},
> +			{DVBT_CDIV_PH1,				0x8		},
> +			{DVBT_SCALE1_B92,			0x4		},
> +			{DVBT_SCALE1_B93,			0xb0	},
> +			{DVBT_SCALE1_BA7,			0x78	},
> +			{DVBT_SCALE1_BA9,			0x28	},
> +			{DVBT_SCALE1_BAA,			0x59	},
> +			{DVBT_SCALE1_BAB,			0x83	},
> +			{DVBT_SCALE1_BAC,			0xd4	},
> +			{DVBT_SCALE1_BB0,			0x65	},
> +			{DVBT_SCALE1_BB1,			0x43	},
> +			{DVBT_KB_P1,				0x1		},
> +			{DVBT_KB_P2,				0x4		},
> +			{DVBT_KB_P3,				0x7		},
> +			{DVBT_K1_CR_STEP12,			0xa		},
> +			{DVBT_REG_GPE,				0x1		},
> +			{DVBT_SERIAL,				0x0},
> +			{DVBT_CDIV_PH0,				0x9},
> +			{DVBT_CDIV_PH1,				0x9},
> +			{DVBT_MPEG_IO_OPT_2_2,		0x0},
> +			{DVBT_MPEG_IO_OPT_1_0,		0x0},
> +			{DVBT_TRK_KS_P2,			0x4},
> +			{DVBT_TRK_KS_I2,			0x7},
> +			{DVBT_TR_THD_SET2,			0x6},
> +			{DVBT_TRK_KC_I2,			0x5},
> +			{DVBT_CR_THD_SET2,			0x1},
> +
> +
> +		};
> +
> +	static rtl2832_reg_value rtl2832_initial_regs_2[] = {
> +			{DVBT_SPEC_INV,				0x0},
> +			{DVBT_DAGC_TRG_VAL,			0x5a	},
> +			{DVBT_AGC_TARG_VAL_0,		0x0		},
> +			{DVBT_AGC_TARG_VAL_8_1,		0x5a	},
> +			{DVBT_AAGC_LOOP_GAIN,		0x16    },
> +			{DVBT_LOOP_GAIN2_3_0,		0x6		},
> +			{DVBT_LOOP_GAIN2_4,			0x1		},
> +			{DVBT_LOOP_GAIN3,			0x16	},
> +			{DVBT_VTOP1,				0x35	},
> +			{DVBT_VTOP2,				0x21	},
> +			{DVBT_VTOP3,				0x21	},
> +			{DVBT_KRF1,					0x0		},
> +			{DVBT_KRF2,					0x40	},
> +			{DVBT_KRF3,					0x10	},
> +			{DVBT_KRF4,					0x10	},
> +			{DVBT_IF_AGC_MIN,			0x80	},
> +			{DVBT_IF_AGC_MAX,			0x7f	},
> +			{DVBT_RF_AGC_MIN,			0x80	},
> +			{DVBT_RF_AGC_MAX,			0x7f	},
> +			{DVBT_POLAR_RF_AGC,			0x0		},
> +			{DVBT_POLAR_IF_AGC,			0x0		},
> +			{DVBT_AD7_SETTING,			0xe9bf	},
> +			{DVBT_EN_GI_PGA,			0x0		},
> +			{DVBT_THD_LOCK_UP,			0x0		},
> +			{DVBT_THD_LOCK_DW,			0x0		},
> +			{DVBT_THD_UP1,				0x11	},
> +			{DVBT_THD_DW1,				0xef	},
> +			{DVBT_INTER_CNT_LEN,		0xc		},
> +			{DVBT_GI_PGA_STATE,			0x0		},
> +			{DVBT_EN_AGC_PGA,			0x1		},
> +			{DVBT_IF_AGC_MAN,			0x0		},
> +		};
> +
> +
> +	info("%s", __func__);
> +
> +	en_bbin = (priv->cfg.if_dvbt == 0 ? 0x1 : 0x0);
> +
> +	/* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22) / CrystalFreqHz) */
> +	pset_iffreq = priv->cfg.if_dvbt % priv->cfg.xtal;
> +	pset_iffreq *= 0x400000;
> +	pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
> +	pset_iffreq = pset_iffreq & 0x3fffff;
> +
> +
> +
> +	for (i = 0; i < 42; i++) {
> +		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_1[i].reg, rtl2832_initial_regs_1[i].value);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	/* if frequency settings */
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
> +		if (ret)
> +			goto err;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
> +		if(ret)
> +			goto err;
> +
> +	for (i = 0; i < 31; i++) {
> +		ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs_2[i].reg, rtl2832_initial_regs_2[i].value);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	priv->sleeping = false;
> +
> +	return ret;
> +
> +err:
> +	return ret;
> +}
> +
> +static int rtl2832_sleep(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	info("%s", __func__);
> +	priv->sleeping = true;
> +	return 0;
> +}
> +
> +int rtl2832_get_tune_settings(struct dvb_frontend *fe,
> +	struct dvb_frontend_tune_settings *s)
> +{
> +	info("%s", __func__);
> +	s->min_delay_ms = 1000;
> +	s->step_size = fe->ops.info.frequency_stepsize * 2;
> +	s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
> +	return 0;
> +}
> +
> +static int rtl2832_set_frontend(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
> +	int ret, i, j;
> +	u64 bw_mode, num, num2;
> +	u32 resamp_ratio, cfreq_off_ratio;
> +
> +
> +	static u8 bw_params[3][32] = {
> +		/* 6 MHz bandwidth */
> +		{
> +			0xf5,	0xff,	0x15,	0x38,	0x5d,	0x6d,	0x52,	0x07,	0xfa,	0x2f,
> +			0x53,	0xf5,	0x3f,	0xca,	0x0b,	0x91,	0xea,	0x30,	0x63,	0xb2,
> +			0x13,	0xda,	0x0b,	0xc4,	0x18,	0x7e,	0x16,	0x66,	0x08,	0x67,
> +			0x19,	0xe0,
> +		},
> +
> +		/*  7 MHz bandwidth */
> +		{
> +			0xe7,	0xcc,	0xb5,	0xba,	0xe8,	0x2f,	0x67,	0x61,	0x00,	0xaf,
> +			0x86,	0xf2,	0xbf,	0x59,	0x04,	0x11,	0xb6,	0x33,	0xa4,	0x30,
> +			0x15,	0x10,	0x0a,	0x42,	0x18,	0xf8,	0x17,	0xd9,	0x07,	0x22,
> +			0x19,	0x10,
> +		},
> +
> +		/*  8 MHz bandwidth */
> +		{
> +			0x09,	0xf6,	0xd2,	0xa7,	0x9a,	0xc9,	0x27,	0x77,	0x06,	0xbf,
> +			0xec,	0xf4,	0x4f,	0x0b,	0xfc,	0x01,	0x63,	0x35,	0x54,	0xa7,
> +			0x16,	0x66,	0x08,	0xb4,	0x19,	0x6e,	0x19,	0x65,	0x05,	0xc8,
> +			0x19,	0xe0,
> +		},
> +	};
> +
> +
> +	info("%s: frequency=%d bandwidth_hz=%d inversion=%d", __func__,
> +			c->frequency, c->bandwidth_hz, c->inversion);
> +
> +
> +	/* program tuner */
> +	if (fe->ops.tuner_ops.set_params)
> +		fe->ops.tuner_ops.set_params(fe);
> +
> +
> +	switch (c->bandwidth_hz) {
> +		case 6000000:
> +			i = 0;
> +			bw_mode = 48000000;
> +			break;
> +		case 7000000:
> +			i = 1;
> +			bw_mode = 56000000;
> +			break;
> +		case 8000000:
> +			i = 2;
> +			bw_mode = 64000000;
> +			break;
> +		default:
> +			dbg("invalid bandwidth");
> +			return -EINVAL;
> +		}
> +
> +	for (j = 0; j < 32; j++){
> +		ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
> +		if (ret)
> +			goto err;
> +	}
> +
> +	/* calculate and set resample ratio */
> +	/* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22) / ConstWithBandwidthMode) */
> +	num = priv->cfg.xtal * 7;
> +	num *= 0x400000;
> +	num = div_u64(num, bw_mode);
> +	resamp_ratio =  num & 0x3ffffff;
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
> +	if (ret)
> +		goto err;
> +
> +	/* calculate and set cfreq off ratio */
> +	/* CFREQ_OFF_RATIO = - floor(ConstWithBandwidthMode * pow(2, 20) / (CrystalFreqHz * 7)) */
> +	num = bw_mode << 20;
> +	num2 = priv->cfg.xtal * 7;
> +	num = div_u64(num, num2);
> +	num = -num;
> +	cfreq_off_ratio = num & 0xfffff;
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
> +	if (ret)
> +		goto err;
> +
> +
> +	/* soft reset */
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
> +	if (ret)
> +		goto err;
> +
> +	ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
> +	if (ret)
> +		goto err;
> +
> +	return ret;
> +err:
> +	info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +	int ret;
> +	u32 tmp;
> +	*status = 0;
> +
> +
> +	info("%s", __func__);
> +	if (priv->sleeping)
> +		return 0;
> +
> +	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
> +	if (ret)
> +		goto err;
> +
> +	if (tmp == 11) {
> +		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
> +			FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
> +	}
> +	/* TODO find out if this is also true */
> +	/*else if (tmp == 10) {
> +		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
> +			FE_HAS_VITERBI;
> +	}*/
> +
> +	return ret;
> +err:
> +	info("%s: failed=%d", __func__, ret);
> +	return ret;
> +}
> +
> +static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
> +{
> +	info("%s", __func__);
> +	*snr = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
> +{
> +	info("%s", __func__);
> +	*ber = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
> +{
> +	info("%s", __func__);
> +	*ucblocks = 0;
> +	return 0;
> +}
> +
> +static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
> +{
> +	info("%s", __func__);
> +	*strength = 0;
> +	return 0;
> +}
> +
> +static struct dvb_frontend_ops rtl2832_ops;
> +
> +static void rtl2832_release(struct dvb_frontend *fe)
> +{
> +	struct rtl2832_priv *priv = fe->demodulator_priv;
> +
> +	info("%s", __func__);
> +	kfree(priv);
> +}
> +
> +struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
> +	struct i2c_adapter *i2c, u8 tuner)
> +{
> +	struct rtl2832_priv *priv = NULL;
> +	int ret = 0;
> +	u8 tmp;
> +
> +	info("%s", __func__);
> +
> +	/* allocate memory for the internal state */
> +	priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
> +	if (priv == NULL)
> +		goto err;
> +
> +	/* setup the priv */
> +	priv->i2c = i2c;
> +	priv->tuner = tuner;
> +	memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
> +
> +	/* check if the demod is there */
> +	ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
> +	if (ret)
> +		goto err;
> +
> +	/* create dvb_frontend */
> +	memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
> +	priv->fe.demodulator_priv = priv;
> +
> +	/* TODO implement sleep mode depending on RC */
> +	priv->sleeping = true;
> +
> +	return &priv->fe;
> +err:
> +	dbg("%s: failed=%d", __func__, ret);
> +	kfree(priv);
> +	return NULL;
> +}
> +EXPORT_SYMBOL(rtl2832_attach);
> +
> +static struct dvb_frontend_ops rtl2832_ops = {
> +	.delsys = { SYS_DVBT },
> +	.info = {
> +		.name = "Realtek RTL2832 (DVB-T)",
> +		.type               = FE_OFDM,
> +		.frequency_min      = 50000000,
> +		.frequency_max      = 862000000,
> +		.frequency_stepsize = 166667,
> +		.caps = FE_CAN_FEC_1_2 |
> +			FE_CAN_FEC_2_3 |
> +			FE_CAN_FEC_3_4 |
> +			FE_CAN_FEC_5_6 |
> +			FE_CAN_FEC_7_8 |
> +			FE_CAN_FEC_AUTO |
> +			FE_CAN_QPSK |
> +			FE_CAN_QAM_16 |
> +			FE_CAN_QAM_64 |
> +			FE_CAN_QAM_AUTO |
> +			FE_CAN_TRANSMISSION_MODE_AUTO |
> +			FE_CAN_GUARD_INTERVAL_AUTO |
> +			FE_CAN_HIERARCHY_AUTO |
> +			FE_CAN_RECOVER |
> +			FE_CAN_MUTE_TS
> +	},
> +
> +	.release = rtl2832_release,
> +
> +	.init = rtl2832_init,
> +	.sleep = rtl2832_sleep,
> +
> +	.get_tune_settings = rtl2832_get_tune_settings,
> +
> +	.set_frontend = rtl2832_set_frontend,
> +
> +	.read_status = rtl2832_read_status,
> +	.read_snr = rtl2832_read_snr,
> +	.read_ber = rtl2832_read_ber,
> +	.read_ucblocks = rtl2832_read_ucblocks,
> +	.read_signal_strength = rtl2832_read_signal_strength,
> +	.i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
> +};
> +
> +MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
> +MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
> +MODULE_LICENSE("GPL");
> +MODULE_VERSION("0.1");
> diff --git a/drivers/media/dvb/frontends/rtl2832.h b/drivers/media/dvb/frontends/rtl2832.h
> new file mode 100644
> index 0000000..b16631a
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832.h
> @@ -0,0 +1,300 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    This program is free software; you can redistribute it and/or modify
> + *    it under the terms of the GNU General Public License as published by
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License along
> + *    with this program; if not, write to the Free Software Foundation, Inc.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#ifndef RTL2832_H
> +#define RTL2832_H
> +
> +#include <linux/dvb/frontend.h>
> +
> +struct rtl2832_config {
> +	/*
> +	 * Demodulator I2C address.
> +	 */
> +	u8 i2c_addr;
> +
> +	/*
> +	 * Xtal frequency.
> +	 * Hz
> +	 * 4000000, 16000000, 25000000, 28800000
> +	 */
> +	u32 xtal;
> +
> +	/*
> +	 * IFs for all used modes.
> +	 * Hz
> +	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
> +	 */
> +	u32 if_dvbt;
> +
> +	/*
> +	 */
> +	u8 tuner;
> +};
> +
> +
> +#if defined(CONFIG_DVB_RTL2832) || \
> +	(defined(CONFIG_DVB_RTL2832_MODULE) && defined(MODULE))
> +extern struct dvb_frontend *rtl2832_attach(
> +	const struct rtl2832_config *cfg,
> +	struct i2c_adapter *i2c,
> +	u8 tuner
> +);
> +
> +extern struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
> +	struct dvb_frontend *fe
> +);
> +#else
> +static inline struct dvb_frontend *rtl2832_attach(
> +	const struct rtl2832_config *config,
> +	struct i2c_adapter *i2c
> +)
> +{
> +	printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
> +	return NULL;
> +}
> +
> +static inline struct i2c_adapter *rtl2832_get_tuner_i2c_adapter(
> +	struct dvb_frontend *fe
> +)
> +{
> +	return NULL;
> +}
> +#endif
> +
> +
> +/* Demod register bit names */
> +enum DVBT_REG_BIT_NAME
> +{
> +	DVBT_SOFT_RST,
> +	DVBT_IIC_REPEAT,
> +	DVBT_TR_WAIT_MIN_8K,
> +	DVBT_RSD_BER_FAIL_VAL,
> +	DVBT_EN_BK_TRK,
> +	DVBT_REG_PI,
> +	DVBT_REG_PFREQ_1_0,
> +	DVBT_PD_DA8,
> +	DVBT_LOCK_TH,
> +	DVBT_BER_PASS_SCAL,
> +	DVBT_CE_FFSM_BYPASS,
> +	DVBT_ALPHAIIR_N,
> +	DVBT_ALPHAIIR_DIF,
> +	DVBT_EN_TRK_SPAN,
> +	DVBT_LOCK_TH_LEN,
> +	DVBT_CCI_THRE,
> +	DVBT_CCI_MON_SCAL,
> +	DVBT_CCI_M0,
> +	DVBT_CCI_M1,
> +	DVBT_CCI_M2,
> +	DVBT_CCI_M3,
> +	DVBT_SPEC_INIT_0,
> +	DVBT_SPEC_INIT_1,
> +	DVBT_SPEC_INIT_2,
> +	DVBT_AD_EN_REG,
> +	DVBT_AD_EN_REG1,
> +	DVBT_EN_BBIN,
> +	DVBT_MGD_THD0,
> +	DVBT_MGD_THD1,
> +	DVBT_MGD_THD2,
> +	DVBT_MGD_THD3,
> +	DVBT_MGD_THD4,
> +	DVBT_MGD_THD5,
> +	DVBT_MGD_THD6,
> +	DVBT_MGD_THD7,
> +	DVBT_EN_CACQ_NOTCH,
> +	DVBT_AD_AV_REF,	
> +	DVBT_PIP_ON,
> +	DVBT_SCALE1_B92,
> +	DVBT_SCALE1_B93,
> +	DVBT_SCALE1_BA7,
> +	DVBT_SCALE1_BA9,
> +	DVBT_SCALE1_BAA,
> +	DVBT_SCALE1_BAB,
> +	DVBT_SCALE1_BAC,
> +	DVBT_SCALE1_BB0,
> +	DVBT_SCALE1_BB1,
> +	DVBT_KB_P1,
> +	DVBT_KB_P2,
> +	DVBT_KB_P3,
> +	DVBT_OPT_AD
> +	DVBT_AD_AVI
> +	DVBT_AD_AVQ
> +	DVBT_K1_CR_STEP12,
> +	DVBT_TRK_KS_P2,
> +	DVBT_TRK_KS_I2,
> +	DVBT_TR_THD_SET2,
> +	DVBT_TRK_KC_P2,
> +	DVBT_TRK_KC_I2,
> +	DVBT_CR_THD_SET2,
> +	DVBT_PSET_IFFREQ,
> +	DVBT_SPEC_INV,
> +	DVBT_BW_INDEX,
> +	DVBT_RSAMP_RATIO,
> +	DVBT_CFREQ_OFF_RATIO,
> +	DVBT_FSM_STAGE,
> +	DVBT_RX_CONSTEL,
> +	DVBT_RX_HIER,
> +	DVBT_RX_C_RATE_LP,
> +	DVBT_RX_C_RATE_HP,
> +	DVBT_GI_IDX,
> +	DVBT_FFT_MODE_IDX,
> +	DVBT_RSD_BER_EST,
> +	DVBT_CE_EST_EVM,
> +	DVBT_RF_AGC_VAL,
> +	DVBT_IF_AGC_VAL,
> +	DVBT_DAGC_VAL,
> +	DVBT_SFREQ_OFF,
> +	DVBT_CFREQ_OFF,
> +	DVBT_POLAR_RF_AGC,
> +	DVBT_POLAR_IF_AGC,
> +	DVBT_AAGC_HOLD,
> +	DVBT_EN_RF_AGC,
> +	DVBT_EN_IF_AGC,
> +	DVBT_IF_AGC_MIN,
> +	DVBT_IF_AGC_MAX,
> +	DVBT_RF_AGC_MIN,
> +	DVBT_RF_AGC_MAX,
> +	DVBT_IF_AGC_MAN,
> +	DVBT_IF_AGC_MAN_VAL,
> +	DVBT_RF_AGC_MAN,
> +	DVBT_RF_AGC_MAN_VAL,
> +	DVBT_DAGC_TRG_VAL,
> +	DVBT_AGC_TARG_VAL,
> +	DVBT_LOOP_GAIN_3_0,
> +	DVBT_LOOP_GAIN_4,
> +	DVBT_VTOP,	
> +	DVBT_KRF,
> +	DVBT_AGC_TARG_VAL_0,
> +	DVBT_AGC_TARG_VAL_8_1,
> +	DVBT_AAGC_LOOP_GAIN,
> +	DVBT_LOOP_GAIN2_3_0,
> +	DVBT_LOOP_GAIN2_4,
> +	DVBT_LOOP_GAIN3,
> +	DVBT_VTOP1,
> +	DVBT_VTOP2,
> +	DVBT_VTOP3,
> +	DVBT_KRF1,
> +	DVBT_KRF2,
> +	DVBT_KRF3,
> +	DVBT_KRF4,
> +	DVBT_EN_GI_PGA,
> +	DVBT_THD_LOCK_UP,
> +	DVBT_THD_LOCK_DW,
> +	DVBT_THD_UP1,
> +	DVBT_THD_DW1,
> +	DVBT_INTER_CNT_LEN,
> +	DVBT_GI_PGA_STATE,
> +	DVBT_EN_AGC_PGA,
> +	DVBT_CKOUTPAR,
> +	DVBT_CKOUT_PWR,
> +	DVBT_SYNC_DUR,
> +	DVBT_ERR_DUR,
> +	DVBT_SYNC_LVL,
> +	DVBT_ERR_LVL,
> +	DVBT_VAL_LVL,
> +	DVBT_SERIAL,
> +	DVBT_SER_LSB,
> +	DVBT_CDIV_PH0,
> +	DVBT_CDIV_PH1,
> +	DVBT_MPEG_IO_OPT_2_2,
> +	DVBT_MPEG_IO_OPT_1_0,
> +	DVBT_CKOUTPAR_PIP,
> +	DVBT_CKOUT_PWR_PIP,
> +	DVBT_SYNC_LVL_PIP,
> +	DVBT_ERR_LVL_PIP,
> +	DVBT_VAL_LVL_PIP,
> +	DVBT_CKOUTPAR_PID,
> +	DVBT_CKOUT_PWR_PID,
> +	DVBT_SYNC_LVL_PID,
> +	DVBT_ERR_LVL_PID,
> +	DVBT_VAL_LVL_PID,
> +	DVBT_SM_PASS,
> +	DVBT_UPDATE_REG_2,
> +	DVBT_BTHD_P3,
> +	DVBT_BTHD_D3,
> +	DVBT_FUNC4_REG0,
> +	DVBT_FUNC4_REG1,
> +	DVBT_FUNC4_REG2,
> +	DVBT_FUNC4_REG3,
> +	DVBT_FUNC4_REG4,
> +	DVBT_FUNC4_REG5,
> +	DVBT_FUNC4_REG6,
> +	DVBT_FUNC4_REG7,
> +	DVBT_FUNC4_REG8,
> +	DVBT_FUNC4_REG9,
> +	DVBT_FUNC4_REG10,
> +	DVBT_FUNC5_REG0,
> +	DVBT_FUNC5_REG1,
> +	DVBT_FUNC5_REG2,
> +	DVBT_FUNC5_REG3,
> +	DVBT_FUNC5_REG4,
> +	DVBT_FUNC5_REG5,
> +	DVBT_FUNC5_REG6,
> +	DVBT_FUNC5_REG7,
> +	DVBT_FUNC5_REG8,
> +	DVBT_FUNC5_REG9,
> +	DVBT_FUNC5_REG10,
> +	DVBT_FUNC5_REG11,
> +	DVBT_FUNC5_REG12,
> +	DVBT_FUNC5_REG13,
> +	DVBT_FUNC5_REG14,
> +	DVBT_FUNC5_REG15,
> +	DVBT_FUNC5_REG16,
> +	DVBT_FUNC5_REG17,
> +	DVBT_FUNC5_REG18,
> +	DVBT_AD7_SETTING,
> +	DVBT_RSSI_R,
> +	DVBT_ACI_DET_IND,
> +	DVBT_REG_MON,
> +	DVBT_REG_MONSEL,
> +	DVBT_REG_GPE,
> +	DVBT_REG_GPO,
> +	DVBT_REG_4MSEL,
> +	DVBT_TEST_REG_1,
> +	DVBT_TEST_REG_2,
> +	DVBT_TEST_REG_3,
> +	DVBT_TEST_REG_4,
> +	DVBT_REG_BIT_NAME_ITEM_TERMINATOR,
> +};
> +
> +
> +/* Register table length */
> +#define RTL2832_REG_TABLE_LEN	DVBT_REG_BIT_NAME_ITEM_TERMINATOR
> +
> +typedef struct
> +{
> +	u8 page;
> +	u8 start_address;
> +	u8 msb;
> +	u8 lsb;
> +}
> +rtl2832_reg_entry;
> +
> +typedef struct
> +{
> +	int reg;
> +	u32 value;
> +}
> +rtl2832_reg_value;
> +
> +
> +
> +
> +
> +#endif /* RTL2832_H */
> diff --git a/drivers/media/dvb/frontends/rtl2832_priv.h b/drivers/media/dvb/frontends/rtl2832_priv.h
> new file mode 100644
> index 0000000..2f591c6
> --- /dev/null
> +++ b/drivers/media/dvb/frontends/rtl2832_priv.h
> @@ -0,0 +1,60 @@
> +/*
> + * Realtek RTL2832 DVB-T demodulator driver
> + *
> + * Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
> + *
> + *    This program is free software; you can redistribute it and/or modify
> + *    it under the terms of the GNU General Public License as published by
> + *    the Free Software Foundation; either version 2 of the License, or
> + *    (at your option) any later version.
> + *
> + *    This program is distributed in the hope that it will be useful,
> + *    but WITHOUT ANY WARRANTY; without even the implied warranty of
> + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + *    GNU General Public License for more details.
> + *
> + *    You should have received a copy of the GNU General Public License along
> + *    with this program; if not, write to the Free Software Foundation, Inc.,
> + *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
> + */
> +
> +#ifndef RTL2832_PRIV_H
> +#define RTL2832_PRIV_H
> +
> +#include "dvb_frontend.h"
> +#include "rtl2832.h"
> +
> +#define LOG_PREFIX "rtl2832"
> +
> +#undef dbg
> +#define dbg(f, arg...) \
> +	if (rtl2832_debug) \
> +		printk(KERN_INFO            LOG_PREFIX": " f "\n" , ## arg)
> +#undef err
> +#define err(f, arg...)  printk(KERN_ERR     LOG_PREFIX": " f "\n" , ## arg)
> +#undef info
> +#define info(f, arg...) printk(KERN_INFO    LOG_PREFIX": " f "\n" , ## arg)
> +#undef warn
> +#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
> +
> +struct rtl2832_priv {
> +	struct i2c_adapter *i2c;
> +	struct dvb_frontend fe;
> +	struct rtl2832_config cfg;
> +
> +	bool i2c_gate_state;
> +	bool sleeping;
> +
> +	u32 xtal;
> +
> +	u8 tuner;
> +	u8 page; /* active register page */
> +};
> +
> +struct rtl2832_reg_val_mask {
> +	u16 reg;
> +	u8  val;
> +	u8  mask;
> +};
> +
> +#endif /* RTL2832_PRIV_H */

OK, thanks!

This patch, 'v2-rtl2832-h.patch' correct make errors:
..
  CC [M]  /tmp/media_build/v4l/dvb-usb-remote.o
In file included from /tmp/media_build/v4l/rtl28xxu.c:26:0:
/tmp/media_build/v4l/rtl2832.h:136:2: error: expected ',' or '}' before
'DVBT_AD_AVI'
/tmp/media_build/v4l/rtl28xxu.c:388:2: error: unknown field 'ts_mode'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:389:2: error: unknown field 'spec_inv'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:391:2: error: unknown field 'vtop'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:392:2: error: unknown field 'krf'
specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:392:2: warning: excess elements in
struct initializer [enabled by default]
/tmp/media_build/v4l/rtl28xxu.c:392:2: warning: (near initialization for
'rtl28xxu_rtl2832_fc0012_config') [enabled by default]
/tmp/media_build/v4l/rtl28xxu.c:393:2: error: unknown field
'agc_targ_val' specified in initializer
/tmp/media_build/v4l/rtl28xxu.c:393:2: warning: excess elements in
struct initializer [enabled by default]
/tmp/media_build/v4l/rtl28xxu.c:393:2: warning: (near initialization for
'rtl28xxu_rtl2832_fc0012_config') [enabled by default]
make[3]: *** [/tmp/media_build/v4l/rtl28xxu.o] Error 1
make[3]: *** Waiting for unfinished jobs....
make[2]: *** [_module_/tmp/media_build/v4l] Error 2
make[2]: Leaving directory `/usr/src/kernels/3.3.2-6.fc16.x86_64'
make[1]: *** [default] Error 2
make[1]: Leaving directory `/tmp/media_build/v4l'
make: *** [all] Error 2


rgds,
poma

[-- Attachment #2: v2-rtl2832-h.patch --]
[-- Type: text/x-patch, Size: 1042 bytes --]

--- v2-add-support-for-DeLOCK-USB-2.0-DVB-T-Receiver-61744.patch	2012-05-01 08:10:33.000000000 +0200
+++ v2-add-support-for-DeLOCK-USB-2.0-DVB-T-Receiver-61744-corr.patch	2012-05-01 08:08:03.000000000 +0200
@@ -2187,7 +2187,7 @@
 index 0000000..b16631a
 --- /dev/null
 +++ b/drivers/media/dvb/frontends/rtl2832.h
-@@ -0,0 +1,300 @@
+@@ -0,0 +1,322 @@
 +/*
 + * Realtek RTL2832 DVB-T demodulator driver
 + *
@@ -2227,6 +2227,16 @@
 +	u32 xtal;
 +
 +	/*
++	 * TS output mode.
++	 */
++	u8 ts_mode;
++
++	/*
++	 * Spectrum inversion.
++	 */
++	bool spec_inv;
++
++	/*
 +	 * IFs for all used modes.
 +	 * Hz
 +	 * 4570000, 4571429, 36000000, 36125000, 36166667, 44000000
@@ -2235,6 +2245,18 @@
 +
 +	/*
 +	 */
++	u8 vtop;
++
++	/*
++	 */
++	u8 krf;
++
++	/*
++	 */
++	u8 agc_targ_val;
++
++	/*
++	 */
 +	u8 tuner;
 +};
 +
@@ -2322,9 +2344,9 @@
 +	DVBT_KB_P1,
 +	DVBT_KB_P2,
 +	DVBT_KB_P3,
-+	DVBT_OPT_AD
-+	DVBT_AD_AVI
-+	DVBT_AD_AVQ
++	DVBT_OPT_ADC_IQ,
++	DVBT_AD_AVI,
++	DVBT_AD_AVQ,
 +	DVBT_K1_CR_STEP12,
 +	DVBT_TRK_KS_P2,
 +	DVBT_TRK_KS_I2,

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-01  6:48     ` poma
@ 2012-05-03  7:25       ` poma
  2012-05-03  9:03         ` Gianluca Gennari
  2012-05-03 18:17         ` Zdenek Styblik
  0 siblings, 2 replies; 16+ messages in thread
From: poma @ 2012-05-03  7:25 UTC (permalink / raw)
  To: linux-media
  Cc: gennarone, Zdenek Styblik, fermio.kll, julianjm, thomas.mair86,
	Antti Palosaari

[-- Attachment #1: Type: text/plain, Size: 1715 bytes --]


[
…]

Hi there,

These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and
'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on FC0012
tuner, altogether eleven.
Gianluca, please inform forum fellows to test&reply.
Zdenek, fermio - there is a note on
http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at
"Other DVB-T Sticks" regarding 'af4d:a803' device.
Is it based on RTL2832 with FC0012 tuner?

Julian, Thomas, Antii
cheers mates!
;)
poma

ps.
modinfo dvb_usb_rtl28xxu
filename:
/lib/modules/3.3.2-6.fc16.x86_64/kernel/drivers/media/dvb/dvb-usb/dvb-usb-rtl28xxu.ko
license:        GPL
author:         Thomas Mair <thomas.mair86@googlemail.com>
author:         Antti Palosaari <crope@iki.fi>
description:    Realtek RTL28xxU DVB USB driver
alias:          usb:v1F4DpD803d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v1F4DpB803d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0CCDp00A9d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v14AAp0161d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v14AAp0160d*dc*dsc*dp*ic*isc*ip*
alias:          usb:v0BDAp2831d*dc*dsc*dp*ic*isc*ip*
depends:        dvb-usb,rtl2830,rc-core
vermagic:       3.3.2-6.fc16.x86_64 SMP mod_unload
parm:           debug:set debugging level (int)
parm:           adapter_nr:DVB adapter numbers (array of short)


[-- Attachment #2: dvb-usb-ids-v2-rtl2832-fc0012.patch --]
[-- Type: text/x-patch, Size: 2280 bytes --]

--- dvb-usb-ids.h.bcp	2012-05-03 05:28:38.261673063 +0200
+++ dvb-usb-ids.h	2012-05-03 07:07:41.510306992 +0200
@@ -129,10 +129,12 @@
 #define USB_PID_E3C_EC168_3				0xfffb
 #define USB_PID_E3C_EC168_4				0x1001
 #define USB_PID_E3C_EC168_5				0x1002
+#define USB_PID_EZCAP_EZTV646				0x2838
 #define USB_PID_FREECOM_DVBT				0x0160
 #define USB_PID_FREECOM_DVBT_2				0x0161
 #define USB_PID_UNIWILL_STK7700P			0x6003
 #define USB_PID_GENIUS_TVGO_DVB_T03			0x4012
+#define USB_PID_GENIUS_TVGO_DVB_T03_2			0x707f
 #define USB_PID_GRANDTEC_DVBT_USB_COLD			0x0fa0
 #define USB_PID_GRANDTEC_DVBT_USB_WARM			0x0fa1
 #define USB_PID_GTEK					0xb803
@@ -146,6 +148,9 @@
 #define USB_PID_KWORLD_395U_2				0xe39b
 #define USB_PID_KWORLD_395U_3				0xe395
 #define USB_PID_KWORLD_395U_4				0xe39a
+#define USB_PID_KWORLD_D393				0xd393
+#define USB_PID_KWORLD_D395				0xd395
+#define USB_PID_KWORLD_D399				0xd399
 #define USB_PID_KWORLD_MC810				0xc810
 #define USB_PID_KWORLD_PC160_2T				0xc160
 #define USB_PID_KWORLD_PC160_T				0xc161
@@ -209,6 +214,7 @@
 #define USB_PID_HAUPPAUGE_NOVA_TD_STICK_52009		0x5200
 #define USB_PID_HAUPPAUGE_TIGER_ATSC			0xb200
 #define USB_PID_HAUPPAUGE_TIGER_ATSC_B210		0xb210
+#define USB_PID_HU394					0xd394
 #define USB_PID_AVERMEDIA_EXPRESS			0xb568
 #define USB_PID_AVERMEDIA_VOLAR				0xa807
 #define USB_PID_AVERMEDIA_VOLAR_2			0xb808
@@ -265,11 +271,13 @@
 #define USB_PID_PCTV_400E				0x020f
 #define USB_PID_PCTV_450E				0x0222
 #define USB_PID_PCTV_452E				0x021f
+#define USB_PID_PROLECTRIX_DV107669			0xd803
 #define USB_PID_REALTEK_RTL2831U			0x2831
 #define USB_PID_REALTEK_RTL2832U			0x2832
 #define USB_PID_TECHNOTREND_CONNECT_S2_3600		0x3007
 #define USB_PID_TECHNOTREND_CONNECT_S2_3650_CI		0x300a
 #define USB_PID_NEBULA_DIGITV				0x0201
+#define USB_PID_NOT_ONLY_LV5TDELUXE			0xc803
 #define USB_PID_DVICO_BLUEBIRD_LGDT			0xd820
 #define USB_PID_DVICO_BLUEBIRD_LG064F_COLD		0xd500
 #define USB_PID_DVICO_BLUEBIRD_LG064F_WARM		0xd501
@@ -345,6 +353,7 @@
 #define USB_PID_FRIIO_WHITE				0x0001
 #define USB_PID_TVWAY_PLUS				0x0002
 #define USB_PID_SVEON_STV20				0xe39d
+#define USB_PID_SVEON_STV20_2				0xd39d
 #define USB_PID_SVEON_STV22				0xe401
 #define USB_PID_SVEON_STV22_IT9137			0xe411
 #define USB_PID_AZUREWAVE_AZ6027			0x3275

[-- Attachment #3: rtl28xxu-v2-rtl2832-fc0012.patch --]
[-- Type: text/x-patch, Size: 2786 bytes --]

--- rtl28xxu.c.bcp	2012-05-03 06:44:32.958461395 +0200
+++ rtl28xxu.c	2012-05-03 08:11:57.463559065 +0200
@@ -1052,6 +1052,15 @@
 	RTL2831U_14AA_0161,
 	RTL2832U_0CCD_00A9,
 	RTL2832U_1F4D_B803,
+	RTL2832U_0BDA_2838,
+	RTL2832U_0458_707F,
+	RTL2832U_1B80_D39D,
+	RTL2832U_1B80_D393,
+	RTL2832U_1B80_D394,
+	RTL2832U_1B80_D395,
+	RTL2832U_1B80_D399,
+	RTL2832U_1F4D_C803,
+	RTL2832U_1F4D_D803,
 };
 
 static struct usb_device_id rtl28xxu_table[] = {
@@ -1068,6 +1077,24 @@
 		USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK)},
 	[RTL2832U_1F4D_B803] = {
 		USB_DEVICE(USB_VID_GTEK, USB_PID_GTEK)},
+	[RTL2832U_0BDA_2838] = {
+		USB_DEVICE(USB_VID_REALTEK, USB_PID_EZCAP_EZTV646)},
+	[RTL2832U_0458_707F] = {
+		USB_DEVICE(USB_VID_KYE, USB_PID_GENIUS_TVGO_DVB_T03_2)},
+	[RTL2832U_1B80_D39D] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_2)},
+	[RTL2832U_1B80_D393] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_D393)},
+	[RTL2832U_1B80_D394] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_HU394)},
+	[RTL2832U_1B80_D395] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_D395)},
+	[RTL2832U_1B80_D399] = {
+		USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_D399)},
+	[RTL2832U_1F4D_C803] = {
+		USB_DEVICE(USB_VID_GTEK, USB_PID_NOT_ONLY_LV5TDELUXE)},
+	[RTL2832U_1F4D_D803] = {
+		USB_DEVICE(USB_VID_GTEK, USB_PID_PROLECTRIX_DV107669)},
 	{} /* terminating entry */
 };
 
@@ -1181,7 +1208,7 @@
 
 		.i2c_algo = &rtl28xxu_i2c_algo,
 
-		.num_device_descs = 2,
+		.num_device_descs = 11,
 		.devices = {
 			{
 				.name = "Terratec Cinergy T Stick Black",
@@ -1195,6 +1222,60 @@
 					&rtl28xxu_table[RTL2832U_1F4D_B803],
 				},
 			},
+			{
+				.name = "EzCAP EzTV646",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_0BDA_2838],
+				},
+			},
+			{
+				.name = "Genius TVGo DVB-T03 2",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_0458_707F],
+				},
+			},
+			{
+				.name = "Sveon STV20 2",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1B80_D39D],
+				},
+			},
+			{
+				.name = "DVB-T TV Stick D393",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1B80_D393],
+				},
+			},
+			{
+				.name = "DIKOM USB-DVBT HD - HU394",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1B80_D394],
+				},
+			},
+			{
+				.name = "DVB-T TV Stick D395",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1B80_D395],
+				},
+			},
+			{
+				.name = "DVB-T TV Stick D399",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1B80_D399],
+				},
+			},
+			{
+				.name = "Not Only TV DVB-T USB DELUXE LV5TDELUXE",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1F4D_C803],
+				},
+			},
+			{
+				.name = "PROlectrix USB DVB-T & DAB Dongle DV107669",
+				.warm_ids = {
+					&rtl28xxu_table[RTL2832U_1F4D_D803],
+				},
+			},
 		}
 	},
 

[-- Attachment #4: vid-pid-rtl2832-fc0012.txt --]
[-- Type: text/plain, Size: 2972 bytes --]


0bda:2838
*USB_VID_REALTEK	0x0bda
USB_PID_EZCAP_EZTV646	0x2838
EzCAP EzTV646
http://www.szforwardvideo.com/product/Pro_18_7.html
http://ubuntuforums.org/showthread.php?t=1532934
RTL2832U_0BDA_2838


0ccd:00a9
*USB_VID_TERRATEC			0x0ccd
*USB_PID_TERRATEC_CINERGY_T_STICK_BLACK	0x00a9
TERRATEC Cinergy T Stick Black - "Rev.1"
http://linux.terratec.de/tv_en.html
http://www.terratec.net/en/products/Cinergy_T_Stick_Black_107611.html
*RTL2832U_0CCD_00A9

0458:707f
*USB_VID_KYE			0x0458
USB_PID_GENIUS_TVGO_DVB_T03_2	0x707f
Genius TVGo DVB-T03 - "Ver.B"
http://www.linuxtv.org/wiki/index.php/Genius_TVGo_DVB-T03
http://www.abclinuxu.cz/hardware/pridavne-karty/televizni-karty/dvb-t/usb/genius-tvgo-dvb-t03-hw-z-2011
RTL2832U_0458_707F


1b80:d39d
*USB_VID_KWORLD_2	0x1b80
USB_PID_SVEON_STV20_2	0xd39d
Sveon STV20
http://www.sveon.com/fichaSTV20.html
https://github.com/ambrosa/DVB-Realtek-RTL2832U-2.2.2-10tuner-mod_kernel-3.0.0/issues/4
RTL2832U_1B80_D39D


1b80:d393
*USB_VID_KWORLD_2	0x1b80
USB_PID_KWORLD_D393	0xd393
Ardata MyVision DVB-T TV
http://www.ardata.pl/tuner-telewizyjny-ardata-myvision-dvb-t-tv
Gigabyte U7300 USB DVB-T
http://www.gigabyte.com/products/product-page.aspx?pid=3493#sp
http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:gigabyte-u7300-usb-dvb-t-tuner
NILOX DVB-T Stick N15
http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:nilox-dvb-t_stick_n15
Twintech UT-30 USB2.0 DVB-T Stick with FM Radio
http://www.twintech3d.com/products_features.asp?num=300
RTL2832U_1B80_D393


1b80:d394
*USB_VID_KWORLD_2	0x1b80
USB_PID_HU394		0xd394
DIKOM USB-DVBT HD
http://twitter.com/#!/spin877/status/188265508401979392
http://xgazza.altervista.org/Linux/DVB/dikom_dvbt.JPG
RTL2832U_1B80_D394


1b80:d395
*USB_VID_KWORLD_2	0x1b80
USB_PID_KWORLD_D395	0xd395
MaxMedia HU394-T USB DVB-T Multi (FM, DAB, DAB+)
http://www.maxmediatek.com/pd-page/DVB-T_USB.htm
PEAK Hardware 102569AGPK DVB-T Digital TV USB Stick
http://ubuntuforums.org/showthread.php?t=1678094
RTL2832U_1B80_D395


1b80:d399
DVB-T TV Stick D399
*USB_VID_KWORLD_2	0x1b80
USB_PID_KWORLD_D399	0xd399
http://ubuntuforums.org/showthread.php?t=1678094&page=2
RTL2832U_1B80_D399


1f4d:b803
*USB_VID_GTEK	0x1f4d
*USB_PID_GTEK	0xb803
DeLOCK USB 2.0 DVB-T Receiver 61744
http://www.delock.com/produkte/gruppen/Multimedia/Delock_USB_20_DVB-T_Receiver_61744.html
G-Tek T803 
MyGica T803 DVB-T USB TV Stick
http://www.mygica.com/product.asp?id=149
*RTL2832U_1F4D_B803


1f4d:c803
*USB_VID_GTEK			0x1f4d
USB_PID_NOT_ONLY_LV5TDELUXE	0xc803
LifeView/Not Only TV DVB-T USB DELUXE LV5TDELUXE
http://notonlytv.net/p_lv5tdeluxe.html
RTL2832U_1F4D_C803


1f4d:d803
*USB_VID_GTEK			0x1f4d
USB_PID_PROLECTRIX_DV107669	0xd803
PROlectrix USB DVB-T & DAB Dongle DV107669
http://www.reddit.com/user/GrahamM242
RTL2832U_1F4D_D803


https://github.com/tmair/DVB-Realtek-RTL2832U-2.2.2-10tuner-mod_kernel-3.0.0/blob/master/README
http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/



^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-03  7:25       ` poma
@ 2012-05-03  9:03         ` Gianluca Gennari
  2012-05-04  1:27           ` poma
  2012-05-03 18:17         ` Zdenek Styblik
  1 sibling, 1 reply; 16+ messages in thread
From: Gianluca Gennari @ 2012-05-03  9:03 UTC (permalink / raw)
  To: poma
  Cc: linux-media, Zdenek Styblik, fermio.kll, julianjm, thomas.mair86,
	Antti Palosaari

Hi poma,
I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
mini DVB-T stick) and both are based on the E4000 tuner, which is not
supported in the kernel at the moment.
I have no idea if there are sticks with the same USB PID and the fc0012
tuner.

Regards,
Gianluca

Il 03/05/2012 09:25, poma ha scritto:
> 
> [
…]
> 
> Hi there,
> 
> These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and
> 'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on FC0012
> tuner, altogether eleven.
> Gianluca, please inform forum fellows to test&reply.
> Zdenek, fermio - there is a note on
> http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at
> "Other DVB-T Sticks" regarding 'af4d:a803' device.
> Is it based on RTL2832 with FC0012 tuner?
> 
> Julian, Thomas, Antii
> cheers mates!
> ;)
> poma
> 
> ps.
> modinfo dvb_usb_rtl28xxu
> filename:
> /lib/modules/3.3.2-6.fc16.x86_64/kernel/drivers/media/dvb/dvb-usb/dvb-usb-rtl28xxu.ko
> license:        GPL
> author:         Thomas Mair <thomas.mair86@googlemail.com>
> author:         Antti Palosaari <crope@iki.fi>
> description:    Realtek RTL28xxU DVB USB driver
> alias:          usb:v1F4DpD803d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v1F4DpB803d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v0CCDp00A9d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v14AAp0161d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v14AAp0160d*dc*dsc*dp*ic*isc*ip*
> alias:          usb:v0BDAp2831d*dc*dsc*dp*ic*isc*ip*
> depends:        dvb-usb,rtl2830,rc-core
> vermagic:       3.3.2-6.fc16.x86_64 SMP mod_unload
> parm:           debug:set debugging level (int)
> parm:           adapter_nr:DVB adapter numbers (array of short)
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-03  7:25       ` poma
  2012-05-03  9:03         ` Gianluca Gennari
@ 2012-05-03 18:17         ` Zdenek Styblik
  2012-05-04  1:34           ` poma
  1 sibling, 1 reply; 16+ messages in thread
From: Zdenek Styblik @ 2012-05-03 18:17 UTC (permalink / raw)
  To: poma
  Cc: linux-media, gennarone, fermio.kll, julianjm, thomas.mair86,
	Antti Palosaari

Hello poma,

I'm sorry, but that's all info I've been "given". :-\

Best regards,
Z.

On 05/03/12 09:25, poma wrote:
> 
> [
…]
> 
> Hi there,
> 
> These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and 
> 'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on
> FC0012 tuner, altogether eleven. Gianluca, please inform forum
> fellows to test&reply. Zdenek, fermio - there is a note on 
> http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at 
> "Other DVB-T Sticks" regarding 'af4d:a803' device. Is it based on
> RTL2832 with FC0012 tuner?
> 
> Julian, Thomas, Antii cheers mates! ;) poma
> 
> ps. modinfo dvb_usb_rtl28xxu filename: 
> /lib/modules/3.3.2-6.fc16.x86_64/kernel/drivers/media/dvb/dvb-usb/dvb-usb-rtl28xxu.ko
>
> 
license:        GPL
> author:         Thomas Mair <thomas.mair86@googlemail.com> author:
> Antti Palosaari <crope@iki.fi> description:    Realtek RTL28xxU DVB
> USB driver alias:          usb:v1F4DpD803d*dc*dsc*dp*ic*isc*ip* 
> alias:          usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip* alias:
> usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip* alias:
> usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v1F4DpB803d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v0CCDp00A9d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v14AAp0161d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v14AAp0160d*dc*dsc*dp*ic*isc*ip* alias:
> usb:v0BDAp2831d*dc*dsc*dp*ic*isc*ip* depends:
> dvb-usb,rtl2830,rc-core vermagic:       3.3.2-6.fc16.x86_64 SMP
> mod_unload parm:           debug:set debugging level (int) parm:
> adapter_nr:DVB adapter numbers (array of short)
> 


-- 
Zdenek Styblik
email: stybla@turnovfree.net
jabber: stybla@jabber.turnovfree.net

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-03  9:03         ` Gianluca Gennari
@ 2012-05-04  1:27           ` poma
  2012-05-04 13:49             ` Gianluca Gennari
                               ` (2 more replies)
  0 siblings, 3 replies; 16+ messages in thread
From: poma @ 2012-05-04  1:27 UTC (permalink / raw)
  To: linux-media, gennarone

On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
> Hi poma,
> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
> mini DVB-T stick) and both are based on the E4000 tuner, which is not
> supported in the kernel at the moment.
> I have no idea if there are sticks with the same USB PID and the fc0012
> tuner.

OK, second one - no name device is "Realtek RTL2832U reference design"**.

First one:
Once upon a time there was a "EasyCAP"…
"After while crocodile!"
…and "EzCAP" was born.
http://szforwardvideo.en.alibaba.com/aboutus.html
Obviously Easycap EZTV646 != EzCAP EzTV646
http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
ezcap EzTV646	0BDA:2838	RTL2832U/FC0012		Some revisions may have the E4000*
http://i.imgur.com/mFD1X.jpg
(Generic)	0BDa:2838	RTL2832U/E4000*
…
And, in addition:
http://sdr.osmocom.org/trac/wiki/rtl-sdr
0x0bda	0x2832	all of them	Generic RTL2832U (e.g. hama nano)**
0x0bda	0x2838	E4000	ezcap USB 2.0 DVB-T/DAB/FM dongle
…
Maybe?
https://sites.google.com/site/myrtlsdr/
"EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
to force FC0012 tuner because it has the same PID as EZTV668 (PID:
0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
Works, not so good at filtering."
…
Conclusion:
At least two devices share same vid/pid with different tuners - fc0012
vs e4000.
How to resolve this from a drivers perspective in a proper way?

Beside,
there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
E4000)
by Harald Welte
http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
http://sdr.osmocom.org/trac/
http://sdr.osmocom.org/trac/wiki/rtl-sdr
http://wiki.spench.net/wiki/RTL2832U***

regards,
poma

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-03 18:17         ` Zdenek Styblik
@ 2012-05-04  1:34           ` poma
  0 siblings, 0 replies; 16+ messages in thread
From: poma @ 2012-05-04  1:34 UTC (permalink / raw)
  To: Zdenek Styblik, linux-media

On 05/03/2012 08:17 PM, Zdenek Styblik wrote:
> Hello poma,
> 
> I'm sorry, but that's all info I've been "given". :-\

It is as it is.
;)

regards,
poma

> On 05/03/12 09:25, poma wrote:
>>
>> [
…]
>>
>> Hi there,
>>
>> These two patches - 'dvb-usb-ids-v2-rtl2832-fc0012.patch' and 
>> 'rtl28xxu-v2-rtl2832-fc0012.patch' adds nine devices based on
>> FC0012 tuner, altogether eleven. Gianluca, please inform forum
>> fellows to test&reply. Zdenek, fermio - there is a note on 
>> http://wiki.zeratul.org/doku.php?id=linux:v4l:realtek:start at 
>> "Other DVB-T Sticks" regarding 'af4d:a803' device. Is it based on
>> RTL2832 with FC0012 tuner?
>>
>> Julian, Thomas, Antii cheers mates! ;) poma
>>
>> ps. modinfo dvb_usb_rtl28xxu filename: 
>> /lib/modules/3.3.2-6.fc16.x86_64/kernel/drivers/media/dvb/dvb-usb/dvb-usb-rtl28xxu.ko
>>
>>
> license:        GPL
>> author:         Thomas Mair <thomas.mair86@googlemail.com> author:
>> Antti Palosaari <crope@iki.fi> description:    Realtek RTL28xxU DVB
>> USB driver alias:          usb:v1F4DpD803d*dc*dsc*dp*ic*isc*ip* 
>> alias:          usb:v1F4DpC803d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD399d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD395d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD394d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD393d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1B80pD39Dd*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v0458p707Fd*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v0BDAp2838d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v1F4DpB803d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v0CCDp00A9d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v14AAp0161d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v14AAp0160d*dc*dsc*dp*ic*isc*ip* alias:
>> usb:v0BDAp2831d*dc*dsc*dp*ic*isc*ip* depends:
>> dvb-usb,rtl2830,rc-core vermagic:       3.3.2-6.fc16.x86_64 SMP
>> mod_unload parm:           debug:set debugging level (int) parm:
>> adapter_nr:DVB adapter numbers (array of short)
>>
> 
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-04  1:27           ` poma
@ 2012-05-04 13:49             ` Gianluca Gennari
  2012-05-05  0:33               ` poma
  2012-05-04 13:57             ` Gianluca Gennari
       [not found]             ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
  2 siblings, 1 reply; 16+ messages in thread
From: Gianluca Gennari @ 2012-05-04 13:49 UTC (permalink / raw)
  To: poma; +Cc: linux-media

Hi poma,
thanks for the very interesting links.

Il 04/05/2012 03:27, poma ha scritto:
> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>> Hi poma,
>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>> supported in the kernel at the moment.
>> I have no idea if there are sticks with the same USB PID and the fc0012
>> tuner.
> 
> OK, second one - no name device is "Realtek RTL2832U reference design"**.
> 
> First one:
> Once upon a time there was a "EasyCAP"�
> "After while crocodile!"
> �and "EzCAP" was born.
> http://szforwardvideo.en.alibaba.com/aboutus.html
> Obviously Easycap EZTV646 != EzCAP EzTV646
> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
> ezcap EzTV646	0BDA:2838	RTL2832U/FC0012		Some revisions may have the E4000*
> http://i.imgur.com/mFD1X.jpg
> (Generic)	0BDa:2838	RTL2832U/E4000*
> �
> And, in addition:
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> 0x0bda	0x2832	all of them	Generic RTL2832U (e.g. hama nano)**
> 0x0bda	0x2838	E4000	ezcap USB 2.0 DVB-T/DAB/FM dongle
> �
> Maybe?
> https://sites.google.com/site/myrtlsdr/

That's it. Opening the device enclosure, I can read this on the PCB:
"EzTV668 1.0"
and it looks identical to the picture posted there.

> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
> Works, not so good at filtering."
> �
> Conclusion:
> At least two devices share same vid/pid with different tuners - fc0012
> vs e4000.
> How to resolve this from a drivers perspective in a proper way?

This is not a big problem: the rtl2832 driver should read the tuner type
from an internal register and load the proper module (or exit with an
error message if the tuner is unsupported).

> Beside,
> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
> E4000)
> by Harald Welte
> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
> http://sdr.osmocom.org/trac/
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> http://wiki.spench.net/wiki/RTL2832U***

Very nice. So we should ask Harald Welte if he is willing to have his
driver merged in the kernel.

> regards,
> poma
> 

Regards,
Gianluca

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-04  1:27           ` poma
  2012-05-04 13:49             ` Gianluca Gennari
@ 2012-05-04 13:57             ` Gianluca Gennari
       [not found]             ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
  2 siblings, 0 replies; 16+ messages in thread
From: Gianluca Gennari @ 2012-05-04 13:57 UTC (permalink / raw)
  To: poma; +Cc: linux-media

Il 04/05/2012 03:27, poma ha scritto:
> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>> Hi poma,
>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>> supported in the kernel at the moment.
>> I have no idea if there are sticks with the same USB PID and the fc0012
>> tuner.
> 
> OK, second one - no name device is "Realtek RTL2832U reference design"**.

Just for reference, the "no name device" I bought on ebay is exactly
this one:

http://i01.i.aliimg.com/photo/v0/513925059/Mini_notebook_USB_DVB_T_Stick_receiver.jpg

Tuner: E4000
USB PID: 0BDA:2832

It is listed as "Unikoo UK001T (P160)" on the RTL SDR compatibility list:
http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/

Best regards,
Gianluca

> 
> First one:
> Once upon a time there was a "EasyCAP"�
> "After while crocodile!"
> �and "EzCAP" was born.
> http://szforwardvideo.en.alibaba.com/aboutus.html
> Obviously Easycap EZTV646 != EzCAP EzTV646
> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
> ezcap EzTV646	0BDA:2838	RTL2832U/FC0012		Some revisions may have the E4000*
> http://i.imgur.com/mFD1X.jpg
> (Generic)	0BDa:2838	RTL2832U/E4000*
> �
> And, in addition:
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> 0x0bda	0x2832	all of them	Generic RTL2832U (e.g. hama nano)**
> 0x0bda	0x2838	E4000	ezcap USB 2.0 DVB-T/DAB/FM dongle
> �
> Maybe?
> https://sites.google.com/site/myrtlsdr/
> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
> Works, not so good at filtering."
> �
> Conclusion:
> At least two devices share same vid/pid with different tuners - fc0012
> vs e4000.
> How to resolve this from a drivers perspective in a proper way?
> 
> Beside,
> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
> E4000)
> by Harald Welte
> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
> http://sdr.osmocom.org/trac/
> http://sdr.osmocom.org/trac/wiki/rtl-sdr
> http://wiki.spench.net/wiki/RTL2832U***
> 
> regards,
> poma
> 


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
       [not found]             ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
@ 2012-05-05  0:18               ` poma
  0 siblings, 0 replies; 16+ messages in thread
From: poma @ 2012-05-05  0:18 UTC (permalink / raw)
  To: Thomas Mair, linux-media

On 05/04/2012 08:50 AM, Thomas Mair wrote:
> Am 04.05.2012 03:27 schrieb "poma" <pomidorabelisima@gmail.com>:
>>
>> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>>> Hi poma,
>>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>>> supported in the kernel at the moment.
>>> I have no idea if there are sticks with the same USB PID and the fc0012
>>> tuner.
>>
>> OK, second one - no name device is "Realtek RTL2832U reference design"**.
>>
>> First one:
>> Once upon a time there was a "EasyCAP"…
>> "After while crocodile!"
>> …and "EzCAP" was born.
>> http://szforwardvideo.en.alibaba.com/aboutus.html
>> Obviously Easycap EZTV646 != EzCAP EzTV646
>>
> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
>> ezcap EzTV646   0BDA:2838       RTL2832U/FC0012         Some revisions
> may have the E4000*
>> http://i.imgur.com/mFD1X.jpg
>> (Generic)       0BDa:2838       RTL2832U/E4000*
>> …
>> And, in addition:
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> 0x0bda  0x2832  all of them     Generic RTL2832U (e.g. hama nano)**
>> 0x0bda  0x2838  E4000   ezcap USB 2.0 DVB-T/DAB/FM dongle
>> …
>> Maybe?
>> https://sites.google.com/site/myrtlsdr/
>> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
>> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
>> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
>> Works, not so good at filtering."
>> …
>> Conclusion:
>> At least two devices share same vid/pid with different tuners - fc0012
>> vs e4000.
>> How to resolve this from a drivers perspective in a proper way?
> The handling of the different tuners of devices with the same vid/pid
> should not be a problem, because rtl28xxu driver probes for the tuner when
> the device is initialized.
> 
Thanks for clarifying!
rtl28xxu.c:
…
* Probe used tuner. We need to know used tuner before demod attach
* since there is some demod params needed to set according to tuner.
…
/* check FC0012 ID register; reg=00 val=a1 */
…

>> Beside,
>> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
>> E4000)
>> by Harald Welte
>> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
>> http://sdr.osmocom.org/trac/
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> http://wiki.spench.net/wiki/RTL2832U***
> So what is missing is the e4000 tuner driver.
> 
True.

> Btw i do have a list of devices that include the Rtl2832 demod. I will send
> that list on the weekend.
> 
Groovy!

> Regards
> Thomas
> 

regards,
poma


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-04 13:49             ` Gianluca Gennari
@ 2012-05-05  0:33               ` poma
  2012-05-05 16:01                 ` Thomas Mair
  0 siblings, 1 reply; 16+ messages in thread
From: poma @ 2012-05-05  0:33 UTC (permalink / raw)
  To: gennarone, linux-media

On 05/04/2012 03:49 PM, Gianluca Gennari wrote:
> Hi poma,
> thanks for the very interesting links.
> 
;)

> Il 04/05/2012 03:27, poma ha scritto:
>> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>>> Hi poma,
>>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>>> supported in the kernel at the moment.
>>> I have no idea if there are sticks with the same USB PID and the fc0012
>>> tuner.
>>
>> OK, second one - no name device is "Realtek RTL2832U reference design"**.
>>
>> First one:
>> Once upon a time there was a "EasyCAP"�
>> "After while crocodile!"
>> �and "EzCAP" was born.
>> http://szforwardvideo.en.alibaba.com/aboutus.html
>> Obviously Easycap EZTV646 != EzCAP EzTV646
>> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
>> ezcap EzTV646	0BDA:2838	RTL2832U/FC0012		Some revisions may have the E4000*
>> http://i.imgur.com/mFD1X.jpg
>> (Generic)	0BDa:2838	RTL2832U/E4000*
>> �
>> And, in addition:
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> 0x0bda	0x2832	all of them	Generic RTL2832U (e.g. hama nano)**
>> 0x0bda	0x2838	E4000	ezcap USB 2.0 DVB-T/DAB/FM dongle
>> �
>> Maybe?
>> https://sites.google.com/site/myrtlsdr/
> 
> That's it. Opening the device enclosure, I can read this on the PCB:
> "EzTV668 1.0"
> and it looks identical to the picture posted there.
> 
Groovy!

>> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
>> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
>> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
>> Works, not so good at filtering."
>> �
>> Conclusion:
>> At least two devices share same vid/pid with different tuners - fc0012
>> vs e4000.
>> How to resolve this from a drivers perspective in a proper way?
> 
> This is not a big problem: the rtl2832 driver should read the tuner type
> from an internal register and load the proper module (or exit with an
> error message if the tuner is unsupported).
> 
Ack, thanks!

>> Beside,
>> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
>> E4000)
>> by Harald Welte
>> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
>> http://sdr.osmocom.org/trac/
>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>> http://wiki.spench.net/wiki/RTL2832U***
> 
> Very nice. So we should ask Harald Welte if he is willing to have his
> driver merged in the kernel.
>
Undoubtedly!
Please ping Thomas and Antti, accordingly.

>> regards,
>> poma
>>
> 
> Regards,
> Gianluca

regards,
poma

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-05  0:33               ` poma
@ 2012-05-05 16:01                 ` Thomas Mair
  2012-05-05 16:54                   ` Hans-Frieder Vogt
  2012-05-05 17:02                   ` Antti Palosaari
  0 siblings, 2 replies; 16+ messages in thread
From: Thomas Mair @ 2012-05-05 16:01 UTC (permalink / raw)
  To: poma; +Cc: gennarone, linux-media, Antti Palosaari

I am currently finishing up the work at the demod driver and will
probably send a new version to the list tomorrow.

As I don't own a device with a different tuner than the fc0012 I will
include an error message about the unsupported tuner and print its
type. So It is easier to get the information about the tuners.

Right now I am writing the signal_strength callback and stumbled upon
the following problem:
The signal strength is read from the fc0012 tuner (only for fc0012).
How should the driver implement this situation. Is there a callback I
could implement within the tuner or should I just read the tuner
registers from the demodulator?

Regards
Thomas

2012/5/5 poma <pomidorabelisima@gmail.com>:
> On 05/04/2012 03:49 PM, Gianluca Gennari wrote:
>> Hi poma,
>> thanks for the very interesting links.
>>
> ;)
>
>> Il 04/05/2012 03:27, poma ha scritto:
>>> On 05/03/2012 11:03 AM, Gianluca Gennari wrote:
>>>> Hi poma,
>>>> I have a 0BDA:2838 (Easycap EZTV646) and a 0BDA:2832 (no name 20x20mm
>>>> mini DVB-T stick) and both are based on the E4000 tuner, which is not
>>>> supported in the kernel at the moment.
>>>> I have no idea if there are sticks with the same USB PID and the fc0012
>>>> tuner.
>>>
>>> OK, second one - no name device is "Realtek RTL2832U reference design"**.
>>>
>>> First one:
>>> Once upon a time there was a "EasyCAP"�
>>> "After while crocodile!"
>>> �and "EzCAP" was born.
>>> http://szforwardvideo.en.alibaba.com/aboutus.html
>>> Obviously Easycap EZTV646 != EzCAP EzTV646
>>> http://www.reddit.com/r/RTLSDR/comments/s6ddo/rtlsdr_compatibility_list_v2_work_in_progress/
>>> ezcap EzTV646        0BDA:2838       RTL2832U/FC0012         Some revisions may have the E4000*
>>> http://i.imgur.com/mFD1X.jpg
>>> (Generic)    0BDa:2838       RTL2832U/E4000*
>>> �
>>> And, in addition:
>>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>>> 0x0bda       0x2832  all of them     Generic RTL2832U (e.g. hama nano)**
>>> 0x0bda       0x2838  E4000   ezcap USB 2.0 DVB-T/DAB/FM dongle
>>> �
>>> Maybe?
>>> https://sites.google.com/site/myrtlsdr/
>>
>> That's it. Opening the device enclosure, I can read this on the PCB:
>> "EzTV668 1.0"
>> and it looks identical to the picture posted there.
>>
> Groovy!
>
>>> "EzCap EZTV646 has got RTL2832U/FC0012. However rtl-sdr must be tweaked
>>> to force FC0012 tuner because it has the same PID as EZTV668 (PID:
>>> 0x2838) so running it whithout a tweak will select Elonics E4000 tuner.
>>> Works, not so good at filtering."
>>> �
>>> Conclusion:
>>> At least two devices share same vid/pid with different tuners - fc0012
>>> vs e4000.
>>> How to resolve this from a drivers perspective in a proper way?
>>
>> This is not a big problem: the rtl2832 driver should read the tuner type
>> from an internal register and load the proper module (or exit with an
>> error message if the tuner is unsupported).
>>
> Ack, thanks!
>
>>> Beside,
>>> there is GPL'ed 'e4k' tuner source code aka 'e4000 improved'*** (Elonics
>>> E4000)
>>> by Harald Welte
>>> http://cgit.osmocom.org/cgit/osmo-sdr/tree/firmware/src/tuner_e4k.c
>>> http://sdr.osmocom.org/trac/
>>> http://sdr.osmocom.org/trac/wiki/rtl-sdr
>>> http://wiki.spench.net/wiki/RTL2832U***
>>
>> Very nice. So we should ask Harald Welte if he is willing to have his
>> driver merged in the kernel.
>>
> Undoubtedly!
> Please ping Thomas and Antti, accordingly.
>
>>> regards,
>>> poma
>>>
>>
>> Regards,
>> Gianluca
>
> regards,
> poma
> --
> To unsubscribe from this list: send the line "unsubscribe linux-media" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-05 16:01                 ` Thomas Mair
@ 2012-05-05 16:54                   ` Hans-Frieder Vogt
  2012-05-05 17:02                   ` Antti Palosaari
  1 sibling, 0 replies; 16+ messages in thread
From: Hans-Frieder Vogt @ 2012-05-05 16:54 UTC (permalink / raw)
  To: Thomas Mair; +Cc: linux-media

Am Samstag, 5. Mai 2012 schrieben Sie:
> I am currently finishing up the work at the demod driver and will
> probably send a new version to the list tomorrow.
> 
> As I don't own a device with a different tuner than the fc0012 I will
> include an error message about the unsupported tuner and print its
> type. So It is easier to get the information about the tuners.
> 
> Right now I am writing the signal_strength callback and stumbled upon
> the following problem:
> The signal strength is read from the fc0012 tuner (only for fc0012).
> How should the driver implement this situation. Is there a callback I
> could implement within the tuner or should I just read the tuner
> registers from the demodulator?

I would recommend implementing the function into the demod driver. Please see an example implementation 
attached. To be able to decide which tuner is in use, I had to move the definition of enum rtl28xxu_tuner out of 
rtl28xxu.h into an own file. By the way, what is the sense behind naming the tuners after the demodulator? I 
think a more appropriate naming would be TUNER_RTL28XX_...

p.s.: I have written a tuner driver for the fc0013, which I hope to be able to send to the mailing list later this 
weekend.

Cheers,
Hans-Frieder

> [...]

and here is the patch:
--- a/drivers/media/dvb/frontends/rtl2832.c	2012-05-01 12:28:26.407776103 +0200
+++ b/drivers/media/dvb/frontends/rtl2832.c	2012-05-05 18:35:28.778377211 +0200
@@ -19,10 +19,11 @@
  */
 
 #include "rtl2832_priv.h"
+#include "rtl28xxu_tuners.h"
 
 
 
-int rtl2832_debug = 1;
+int rtl2832_debug;
 module_param_named(debug, rtl2832_debug, int, 0644);
 MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
 
@@ -391,6 +392,58 @@ err:
 
 }
 
+static int rtl2832_wr_i2c(struct rtl2832_priv *priv, u8 addr, u8 reg, u8 *val, int len)
+{
+	int ret;
+	u8 buf[1+len];
+	struct i2c_msg msg[1] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.len = 1+len,
+			.buf = buf,
+		}
+	};
+
+	buf[0] = reg;
+	memcpy(&buf[1], val, len);
+
+	ret = i2c_transfer(priv->i2c, msg, 1);
+	if (ret == 1) {
+		ret = 0;
+	} else {
+		warn("i2c wr failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+static int rtl2832_rd_i2c(struct rtl2832_priv *priv, u8 addr, u8 reg, u8 *val, int len)
+{
+	int ret;
+	struct i2c_msg msg[2] = {
+		{
+			.addr = addr,
+			.flags = 0,
+			.len = 1,
+			.buf = &reg,
+		}, {
+			.addr = addr,
+			.flags = I2C_M_RD,
+			.len = len,
+			.buf = val,
+		}
+	};
+
+	ret = i2c_transfer(priv->i2c, msg, 2);
+	if (ret == 2) {
+		ret = 0;
+	} else {
+		warn("i2c rd failed=%d reg=%02x len=%d", ret, reg, len);
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
 
 static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
@@ -683,7 +736,9 @@ static int rtl2832_read_status(struct dv
 	*status = 0;
 
 
+#if 0
 	info("%s", __func__);
+#endif
 	if (priv->sleeping)
 		return 0;
 
@@ -707,32 +762,198 @@ err:
 	return ret;
 }
 
+#define RTL2832_CE_EST_EVM_MAX_VALUE 65535
+#define RTL2832_SNR_FRAC_BIT_NUM 10
+#define RTL2832_SNR_DB_DEN 3402
+
 static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-	info("%s", __func__);
-	*snr = 0;
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int ret;
+	u32 fsm_stage, ce_est_evm, constellation, hierarchy;
+	int num;
+	static const int snr_db_num_const[3][4] =
+	{
+		{122880,        122880,         122880,         122880,   },
+		{146657,        146657,         156897,         171013,   },
+		{167857,        167857,         173127,         181810,   },
+	};
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &fsm_stage);
+	if (ret)
+		goto err;
+
+	if (fsm_stage < 10)
+		ce_est_evm = RTL2832_CE_EST_EVM_MAX_VALUE;
+	else {
+		ret = rtl2832_rd_demod_reg(priv, DVBT_CE_EST_EVM, &ce_est_evm);
+		if (ret)
+			goto err;
+	}
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_RX_CONSTEL, &constellation);
+	if (ret)
+		goto err;
+	if (constellation > 2)
+		goto err;
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_RX_HIER, &hierarchy);
+	if (ret)
+		goto err;
+	if (hierarchy > 3)
+		goto err;
+
+	num = snr_db_num_const[constellation][hierarchy] -
+		10*ilog2(ce_est_evm*ce_est_evm)*0x200;
+	if (num < 0)
+		*snr = 0;
+	else
+		*snr = 256 * num / RTL2832_SNR_DB_DEN;
 	return 0;
+
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
 }
 
 static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-	info("%s", __func__);
-	*ber = 0;
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	u32 tmp;
+	int ret;
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_RSD_BER_EST, &tmp);
+	if (ret)
+		goto err;
+	*ber = tmp;
 	return 0;
+
+err:
+	info("%s: failed=%d", __func__, ret);
+	*ber = 0;
+	return ret;
 }
 
 static int rtl2832_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-	info("%s", __func__);
 	*ucblocks = 0;
 	return 0;
 }
 
-static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+#define INPUT_ADC_LEVEL   -8
+
+const int fc001x_lna_gain_table[] = {
+	/* low gain */
+	-63, -58, -99, -73,
+	-63, -65, -54, -60,
+	/* middle gain */
+	 71,  70,  68,  67,
+	 65,  63,  61,  58,
+	/* high gain */
+	197, 191, 188, 186,
+	184, 182, 181, 179,
+};
+
+static int rtl2832_fc001x_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
-	info("%s", __func__);
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int ret;
+	u8 val, reg;
+	int int_temp, lna_gain, int_lna, tot_agc_gain, power;
+
+	if (priv->tuner == TUNER_RTL2832_FC0013)
+		reg = 0x13;
+	else
+		reg = 0x12;
+
+	ret = rtl2832_i2c_gate_ctrl(fe, true);
+	if (ret)
+		goto err;
+
+	val = 0x00;
+	ret = rtl2832_wr_i2c(priv, 0xc6 >> 1, reg, &val, 1);
+	if (ret) {
+		err("%s: rtl2832_wr_i2c failed, ret=%d", __func__, ret);
+		goto err_gate;
+	} else {
+		ret = rtl2832_rd_i2c(priv, 0xc6 >> 1, reg, &val, 1);
+		if (ret)
+			err("%s: rtl2832_rd_i2c failed, ret=%d", __func__, ret);
+//		info("fc001x read 0x12: 0x%02x", val);
+		int_temp = val;
+
+		ret = rtl2832_rd_i2c(priv, 0xc6 >> 1, reg + 1, &val, 1);
+		if (ret)
+			err("%s: rtl2832_rd_i2c failed, ret=%d", __func__, ret);
+//		info("fc001x read 0x13: 0x%02x", val);
+		lna_gain = val & 0x1f;
+	}
+
+	ret = rtl2832_i2c_gate_ctrl(fe, false);
+	if (ret)
+		goto err;
+
+	if (lna_gain < ARRAY_SIZE(fc001x_lna_gain_table)) {
+		int_lna = fc001x_lna_gain_table[lna_gain];
+		tot_agc_gain = (abs((int_temp >> 5) - 7) -2) * 2 +
+			(int_temp & 0x1f) * 2;
+		power = INPUT_ADC_LEVEL - tot_agc_gain - int_lna / 10;
+		
+		if (power >= 45)
+			*strength = 255;	/* 100% */
+		else if (power < -95)
+			*strength = 0;
+		else
+			*strength = (power + 95) * 255 / 140;
+		*strength |= *strength << 8;
+	} else {
+		ret = -1;
+		goto err;
+	}
+
+	return 0;
+
+err_gate:
+	ret = rtl2832_i2c_gate_ctrl(fe, false);
+err:
 	*strength = 0;
+	return ret;
+}
+
+static int rtl2832_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+	struct rtl2832_priv *priv = fe->demodulator_priv;
+	int ret, if_agc;
+	u32 fsm_stage, if_agc_raw;
+
+	if ((priv->tuner == TUNER_RTL2832_FC0012) ||
+	    (priv->tuner == TUNER_RTL2832_FC0013))
+		return rtl2832_fc001x_read_signal_strength(fe, strength);
+
+	ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &fsm_stage);
+	if (ret)
+		goto err;
+	if (fsm_stage < 10)
+		*strength = 0;
+	else {
+		/* if_agc is read as a 10bit binary */
+		ret = rtl2832_rd_demod_reg(priv, DVBT_IF_AGC_VAL, &if_agc_raw);
+		if (ret)
+			goto err;
+	info("%s: if_agc_raw: 0x%04x", __func__, if_agc_raw);
+		if (if_agc_raw < (1 << 9))
+			if_agc = if_agc_raw;
+		else {
+			if_agc = -(~(if_agc_raw-1) & 0x1ff);
+		}
+		*strength = 55 - if_agc / 182;
+		*strength |= *strength << 8;
+	}
+
 	return 0;
+err:
+	info("%s: failed=%d", __func__, ret);
+	return ret;
 }
 
 static struct dvb_frontend_ops rtl2832_ops;
--- /dev/null	2012-05-05 09:43:48.063333275 +0200
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu_tuners.h	2012-05-02 22:43:24.446371878 +0200
@@ -0,0 +1,44 @@
+/*
+ * Realtek RTL28xxU DVB USB driver
+ *
+ * Copyright (C) 2009 Antti Palosaari <crope@iki.fi>
+ * Copyright (C) 2011 Antti Palosaari <crope@iki.fi>
+ *
+ *    This program is free software; you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation; either version 2 of the License, or
+ *    (at your option) any later version.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *    You should have received a copy of the GNU General Public License along
+ *    with this program; if not, write to the Free Software Foundation, Inc.,
+ *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef RTL28XXU_TUNERS_H
+#define RTL28XXU_TUNERS_H
+
+enum rtl28xxu_tuner {
+	TUNER_NONE,
+
+	TUNER_RTL2830_QT1010,
+	TUNER_RTL2830_MT2060,
+	TUNER_RTL2830_MXL5005S,
+
+	TUNER_RTL2832_MT2266,
+	TUNER_RTL2832_FC2580,
+	TUNER_RTL2832_MT2063,
+	TUNER_RTL2832_MAX3543,
+	TUNER_RTL2832_TUA9001,
+	TUNER_RTL2832_MXL5007T,
+	TUNER_RTL2832_FC0012,
+	TUNER_RTL2832_E4000,
+	TUNER_RTL2832_TDA18272,
+	TUNER_RTL2832_FC0013,
+};
+
+#endif
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.h	2012-02-29 05:45:38.000000000 +0100
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.h	2012-05-02 22:43:53.002893237 +0200
@@ -84,25 +84,6 @@ enum rtl28xxu_chip_id {
 	CHIP_ID_RTL2832U,
 };
 
-enum rtl28xxu_tuner {
-	TUNER_NONE,
-
-	TUNER_RTL2830_QT1010,
-	TUNER_RTL2830_MT2060,
-	TUNER_RTL2830_MXL5005S,
-
-	TUNER_RTL2832_MT2266,
-	TUNER_RTL2832_FC2580,
-	TUNER_RTL2832_MT2063,
-	TUNER_RTL2832_MAX3543,
-	TUNER_RTL2832_TUA9001,
-	TUNER_RTL2832_MXL5007T,
-	TUNER_RTL2832_FC0012,
-	TUNER_RTL2832_E4000,
-	TUNER_RTL2832_TDA18272,
-	TUNER_RTL2832_FC0013,
-};
-
 struct rtl28xxu_req {
 	u16 value;
 	u16 index;
--- a/drivers/media/dvb/dvb-usb/rtl28xxu.c      2012-05-01 12:28:26.407776103 +0200
+++ b/drivers/media/dvb/dvb-usb/rtl28xxu.c  2012-05-05 14:25:04.212866649 +0200
@@ -21,6 +21,7 @@
  */
 
 #include "rtl28xxu.h"
+#include "rtl28xxu_tuners.h"
 
 #include "rtl2830.h"
 #include "rtl2832.h"



Hans-Frieder Vogt                       e-mail: hfvogt <at> gmx .dot. net

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744
  2012-05-05 16:01                 ` Thomas Mair
  2012-05-05 16:54                   ` Hans-Frieder Vogt
@ 2012-05-05 17:02                   ` Antti Palosaari
  1 sibling, 0 replies; 16+ messages in thread
From: Antti Palosaari @ 2012-05-05 17:02 UTC (permalink / raw)
  To: Thomas Mair; +Cc: poma, gennarone, linux-media, Antti Palosaari

la 5.5.2012 19:01 Thomas Mair kirjoitti:
> I am currently finishing up the work at the demod driver and will
> probably send a new version to the list tomorrow.

Nice! I will try to review it on Monday...
I looked quickly your old patch last week and tuner driver was done by
Hans-Frieder Vogt. I think he should send tuner patch first and then your
rtl2832 applied top of that.

> As I don't own a device with a different tuner than the fc0012 I will
> include an error message about the unsupported tuner and print its
> type. So It is easier to get the information about the tuners.

Sounds good.

> Right now I am writing the signal_strength callback and stumbled upon
> the following problem:
> The signal strength is read from the fc0012 tuner (only for fc0012).
> How should the driver implement this situation. Is there a callback I
> could implement within the tuner or should I just read the tuner
> registers from the demodulator?

Demod should report signal strength, normally based IF AGC. But that
estimation is very poor, tuner could report it more accurate.

On optimal situation you should implement demod callback for signal
strength and if there is tuner callback then override demod callback in
order to get better reports. IMHO that override should be done in DVB-USB
driver, in that case dvb-usb-rtl2832u. So when you attach rtl2832u just
after that override demod callback with tuner.

regards
Antti


^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2012-05-05 17:02 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-04-29 21:42 [PATCH] Driver for RTL2832 demodulator chip Thomas Mair
2012-04-30  9:38 ` poma
2012-04-30 15:39   ` [PATCH v2] add support for DeLOCK-USB-2.0-DVB-T-Receiver-61744 Thomas Mair
2012-05-01  6:48     ` poma
2012-05-03  7:25       ` poma
2012-05-03  9:03         ` Gianluca Gennari
2012-05-04  1:27           ` poma
2012-05-04 13:49             ` Gianluca Gennari
2012-05-05  0:33               ` poma
2012-05-05 16:01                 ` Thomas Mair
2012-05-05 16:54                   ` Hans-Frieder Vogt
2012-05-05 17:02                   ` Antti Palosaari
2012-05-04 13:57             ` Gianluca Gennari
     [not found]             ` <CAKZ=SG8SjH1C0E38iGjQfJvzi+uTy=dL_9jOxAetgOhkUp5t7g@mail.gmail.com>
2012-05-05  0:18               ` poma
2012-05-03 18:17         ` Zdenek Styblik
2012-05-04  1:34           ` poma

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.